www.openair.com
Open in
urlscan Pro
129.159.101.111
Public Scan
Submitted URL: http://coupa.app.openair.com/version/cb83.42bf/js/OA.lib.lang.js
Effective URL: https://www.openair.com/js/OA.lib.lang.js
Submission: On April 22 via manual from CH — Scanned from DE
Effective URL: https://www.openair.com/js/OA.lib.lang.js
Submission: On April 22 via manual from CH — Scanned from DE
Form analysis
0 forms found in the DOMText Content
/*eslint no-unused-vars: 0*/ /*eslint oa-require-jsdoc: [0] */ /** * Defined namespaces: * OA.lib.lang */ /* use ECMAScript 5 Strict mode */ (function() { "use strict"; }()); /** * This namespace defines JS language extensions. * All function like generating object ID, array * extensions and other are stored here. */ /* define namespace */ OA.namespace('OA.lib.lang'); /* stores general object ID */ OA.lib.lang.oid = 0; OA.lib.lang.escapeEntities = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; OA.lib.lang.tagWhitelist = [ 'BR', 'I', 'B', 'U' ]; OA.lib.lang.XSSLevels = { AGGRESSIVE: 1, HIGH: 5, MODERATE: 10, LOW: 20, NONE: 100 }; /* object with currency format definition */ OA.lib.lang.currency = { // supported formats formats: { // $25.5 '%symbol%value': ['USD', 'CAD', 'AUD', 'HKD', 'ZAR', 'KRW', 'NAD', 'SGD', 'NZD', 'GBP', 'JPY', 'CNY', 'RMB', 'EUR'], // 25.5 $ '%value%separator%symbol': ['FRF', 'RUP', 'INR', 'ESP', 'DEM', 'SEK', 'FIM', 'DKK'], // $ 25.5 '%symbol%separator%value': ['CHF', 'ITL', 'NLG', 'AWG', 'PHP', 'NOK'] }, // default format (USD 25.5) defaultFormat: '%currency%separator%value', // separator between currency and value separator: ' ', // cached currency formats, see OA.lib.lang.formatCurrency cache: undefined }; /** * Generates specific ID for object that * needs that behavior (calls this function). */ OA.lib.lang.generateId = function() { return OA.lib.lang.oid++; }; /** * Sugarize JS language * This function runs couple of functions that * extend JS internal objects like Function, * Object, Image ... */ OA.lib.lang.sugar = function() { /** * Extend every object with oid function * Objects are then able to retrieve * their specific id within whole OA app * * TODO: for some reason this extension causes jQuery crashes * we need to test it! */ //Object.prototype.oid = function () { // var newOid = OA.lib.lang.generateId(); // // /* * // * Rewrite instance of oid function for // * object that called oid() function // * to always return it's specific oid // */ // this.oid = function () { // return newOid; // }; // // /* return specific object id (oid) */ // return newOid; //}; (function() { $.fn.bounds = function() { var bounds = { left: Number.POSITIVE_INFINITY, top: Number.POSITIVE_INFINITY, right: Number.NEGATIVE_INFINITY, bottom: Number.NEGATIVE_INFINITY, width: Number.NaN, height: Number.NaN }; this.each(function(i, el) { var elQ, off; elQ = $(el); off = elQ.offset(); off.right = off.left + $(elQ).width(); off.bottom = off.top + $(elQ).height(); if (off.left < bounds.left) { bounds.left = off.left; } if (off.top < bounds.top) { bounds.top = off.top; } if (off.right > bounds.right) { bounds.right = off.right; } if (off.bottom > bounds.bottom) { bounds.bottom = off.bottom; } }); bounds.width = bounds.right - bounds.left; bounds.height = bounds.bottom - bounds.top; return bounds; }; })(); (function() { $.fn.getNonColSpanIndex = function() { var allCells, normalIndex, nonColSpanIndex; if (!$(this).is('td') && !$(this).is('th')) { return -1; } allCells = this.parent('tr').children(); normalIndex = allCells.index(this); nonColSpanIndex = 0; allCells.each(function(i) { var colspan = $(this).attr('colspan'); if (parseInt(i, 10) === parseInt(normalIndex, 10)) { return false; } colspan = colspan ? parseInt(colspan, 10) : 1; nonColSpanIndex += colspan; }); return nonColSpanIndex; }; })(); /* Adds scrollstart and scrollstop event */ (function() { var special = $.event.special, uid1 = 'D' + (+new Date()), uid2 = 'D' + (+new Date() + 1); special.scrollstart = { setup: function() { var timer, handler = function(evt) { var _self = this, _args = arguments; if (timer) { clearTimeout(timer); } else { evt.type = 'scrollstart'; $.event.handle.apply(_self, _args); } timer = setTimeout(function() { timer = null; }, special.scrollstop.latency); }; $(this).on('scroll', handler).data(uid1, handler); }, teardown: function() { $(this).off('scroll', $(this).data(uid1)); } }; special.scrollstop = { latency: 300, setup: function() { var timer, handler = function(evt) { var _self = this, _args = arguments; if (timer) { clearTimeout(timer); } timer = setTimeout(function() { timer = null; evt.type = 'scrollstop'; $.event.handle.apply(_self, _args); }, special.scrollstop.latency); }; $(this).on('scroll', handler).data(uid2, handler); }, teardown: function() { $(this).off('scroll', $(this).data(uid2)); } }; })(); }; OA.lib.lang.sameStructure = function(objA, objB) { var aKeys, bKeys; if (typeof objA === 'object' && typeof objB === 'object') { aKeys = Object.keys(objA).sort(); bKeys = Object.keys(objB).sort(); return JSON.stringify(aKeys) === JSON.stringify(bKeys); } else { return objA === objB; } }; /** * JSON method to clone any object * @param {Object} obj template object * @return {Object} cloned object */ OA.lib.lang.cloneObject = function(obj) { return JSON.parse(JSON.stringify(obj)); }; OA.lib.lang.collect = function() { var ret = {}, len = arguments.lenght, i = 0, p; for (i = 0; i < len; i++) { for (p in arguments[i]) { if (arguments[i].hasOwnProperty(p)) { ret[p] = arguments[i][p]; } } } return ret; }; /** * Convert value to JSON string */ OA.lib.lang.stringify = function(value, replacer, space) { return (JSON.stringify(value, replacer, space)); }; /** * Convert json string to object */ OA.lib.lang.destringify = function(text, reviver) { return (JSON.parse(text, reviver)); }; OA.lib.lang.capitaliseFirstLetter = function(string) { return string.charAt(0).toUpperCase() + string.slice(1); }; /** * Return value with 'px' suffix * * @param {String} value value as string * * @return {String} value + 'px' */ OA.lib.lang.inPx = function(value) { return value + 'px'; }; /** * Returns string prefixed with '.' * * @param {String} string class name * * @example OA.lib.lang.stringAsClassSelector('hover') => '.hover' * * @return {String} '.' + class name */ OA.lib.lang.stringAsClassSelector = function(string) { return '.' + string; }; /** * Get array of classes of passed element * * @param {object} element DOM node * @return {Array} array of strings of classnames */ OA.lib.lang.getClassList = function(element) { return (element && element.className) ? element.className.split(/\s+/) : []; }; /** * fillprop - overwrite @defparams properties in object by same property values from @params * * var def = OA.fillprop({ test : true }, { test : false, foo : "" } ) ; * console.log(def) * { test : false } * * @defparams {Object} default values * @params {Object} values to overwrite default values * @return {Object} */ OA.fillprop = function(defparams, params) { var attr, retval = {}; if (params === undefined) { params = {}; } //Join parameters for (attr in defparams) { if (params[attr] !== undefined) { retval[attr] = params[attr]; } else { retval[attr] = defparams[attr]; } } return retval; }; /** * cleanPage get body of page from full html page * @return String */ OA.cleanPage = function(msg) { var patt; msg = msg.slice(msg.search('<body'), msg.search('</body')); patt = new RegExp("<body[^>]*>", ""); msg = msg.replace(patt, ""); return (msg); }; /** * Escapes a string for insertion into HTML * * OA.escape('James, Eric & Tony'); * result: "James, Eric & Tony" * * @param {string} str string to escape * @return {string} */ OA.lib.lang.escape = function(s, forAttribute) { return s.toString().replace(forAttribute ? /[&<>'"]/g : /[&<>]/g, function(c) { return OA.lib.lang.escapeEntities[c]; }); }; /** * Strips HTML tags like <script> from string. * https://stackoverflow.com/questions/6659351/removing-all-script-tags-from-html-with-js-regular-expression * * @param {String} s * * @return {String} */ OA.lib.lang.stripTags = function(s) { var i; var el; var div = document.createElement('div'); var re; var output; var children; var toRemove = []; // process stripping only for AGGRESSIVE or HIGH level if (!s || OA.core.XSSLevel > OA.lib.lang.XSSLevels.HIGH) { return s; } div.innerHTML = OA.lib.lang.stripAttrs(s); children = div.querySelectorAll('*'); for (i = 0; i < children.length; i++) { el = children[i]; // element should be removed if (OA.lib.lang.tagWhitelist.indexOf(el.tagName) === -1) { // collect elements to be removed (cannot be removed directly in for loop - changing index) toRemove.push(el); // allowed tag, remove all attributes (no need to have any attributes // for 'b', 'i', 'u' and 'br') } else { while (el.attributes.length > 0) { el.removeAttribute(el.attributes[0].name); } } } if (toRemove.length) { for (i = 0; i < toRemove.length; i++) { toRemove[i].parentNode.removeChild(toRemove[i]); } } output = div.innerHTML; // replace entities (created due to using innerHTML) for (i in OA.lib.lang.escapeEntities) { re = new RegExp(OA.lib.lang.escapeEntities[i], 'g'); output = output.replace(re, i); } return output; }; /** * Strips on* HTML attributes from string * e.g. onload, onerror, onfocus ... * * @param {String} s * * @return {String} */ OA.lib.lang.stripAttrs = function(s) { if (!s) { return s; } // onerror attribute must be stripped before adding into element // othwerwise onerror will be triggered (e.g. <img src=x onerror=alert(1)>) // with apos and quotes s = s.replace(new RegExp("on[a-z]+='.*?'", 'ig'), ''); s = s.replace(new RegExp('on[a-z]+=".*?"', 'ig'), ''); // attribute value without quotes s = s.replace(new RegExp('on[a-z]+=[^> ]+([> ])', 'ig'), '$1'); return s; }; /** * Returns the value of s with the first character uppercased. * * OA.ucfirst('james'); * result: "James" * * @param {string} s string to uppercase * @return {string} */ OA.lib.lang.ucfirst = function(s) { return (typeof s === "string" && s.length > 0 ? s.charAt(0).toUpperCase() + s.substr(1) : s); }; /** * Implementation of MurmurHash3 * * @author Gary Court * @see http://github.com/garycourt/murmurhash-js * @author Austin Appleby * @see http://sites.google.com/site/murmurhash/ * * @param {String} key - ASCII only * @param {Number} seed - positive integer only * * @return {Number} 32-bit positive integer hash */ OA.lib.lang.computeHash = function(key, seed) { var remainder, bytes, h1, h1b, c1, c1b, c2, c2b, k1, i; remainder = key.length & 3; bytes = key.length - remainder; h1 = seed; c1 = 0xcc9e2d51; c2 = 0x1b873593; i = 0; while (i < bytes) { k1 = ((key.charCodeAt(i) & 0xff)) | ((key.charCodeAt(++i) & 0xff) << 8) | ((key.charCodeAt(++i) & 0xff) << 16) | ((key.charCodeAt(++i) & 0xff) << 24); ++i; k1 = ((((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16))) & 0xffffffff; k1 = (k1 << 15) | (k1 >>> 17); k1 = ((((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16))) & 0xffffffff; h1 ^= k1; h1 = (h1 << 13) | (h1 >>> 19); h1b = ((((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16))) & 0xffffffff; h1 = (((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16)); } k1 = 0; switch (remainder) { case 3: k1 ^= (key.charCodeAt(i + 2) & 0xff) << 16; /* falls through */ case 2: k1 ^= (key.charCodeAt(i + 1) & 0xff) << 8; /* falls through */ case 1: k1 ^= (key.charCodeAt(i) & 0xff); k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff; k1 = (k1 << 15) | (k1 >>> 17); k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff; h1 ^= k1; } h1 ^= key.length; h1 ^= h1 >>> 16; h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff; h1 ^= h1 >>> 13; h1 = ((((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16))) & 0xffffffff; h1 ^= h1 >>> 16; return h1 >>> 0; }; /** * Return value with currency symbol. * @param {String|Number} value formatted value * @param {String} currency currency abbreviation * @param {String} symbol currency symbol * * @return {String} */ OA.lib.lang.formatCurrency = function(value, currency, symbol) { var format; var i; var currencies; var selectedFormat; var result; if (_.isUndefined(value)) { throw "Value is required."; } if (_.isUndefined(currency)) { throw "Currency is required."; } // fallback symbol is same as currency if (_.isUndefined(symbol)) { symbol = currency; } // cache formats by currencies if (_.isUndefined(OA.lib.lang.currency.cache)) { OA.lib.lang.currency.cache = {}; // process all formats for (format in OA.lib.lang.currency.formats) { currencies = OA.lib.lang.currency.formats[format]; // add format for all currencies for (i = 0; i < currencies.length; i++) { OA.lib.lang.currency.cache[currencies[i]] = format; } } } // try to find format for specified currency if (OA.lib.lang.currency.cache[currency]) { selectedFormat = OA.lib.lang.currency.cache[currency]; } // use default format if specific format for currency not found if (!selectedFormat) { selectedFormat = OA.lib.lang.currency.defaultFormat; } // replace all wildcards result = selectedFormat.replace('%value', value); result = result.replace('%separator', OA.lib.lang.currency.separator); result = result.replace('%symbol', symbol); result = result.replace('%currency', currency); return result; }; /** * Call handler for clearing account translations, provided the URL is defined. * * @return {boolean} */ OA.lib.lang.clearLanguage = function() { var jqXHR; var clearTranslationsURL = OA.core.clearTranslationsURL; if (_.isUndefined(clearTranslationsURL)) { return false; } jqXHR = $.ajax({ type: "GET", url: clearTranslationsURL, dataType: "json" }); jqXHR.done(function(response) { OA.publish('OA.comp.Notification.showTimeout', ['Account translations were successfully cleared: ' + response.rowsDeleted + ' row(s) deleted', 'Success']); }); jqXHR.fail(function() { OA.publish('OA.comp.Notification.showTimeout', ['Could not clear account translations', 'Error']); }); return true; };