UNPKG

vtex-utils

Version:

A collection of utilities methods for Vtex stores

1,414 lines (1,250 loc) 162 kB
/*!! * VtexUtils.js v1.18.1 * https://github.com/zeindelf/vtex-utils * * Copyright (c) 2017-2018 Zeindelf * Released under the MIT license * * Date: 2018-09-17T18:32:03.664Z */ var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; function createCommonjsModule(fn, module) { return module = { exports: {} }, fn(module, module.exports), module.exports; } var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; var createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var defineProperty = function (obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }; /* eslint-disable */ if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object') { commonjsGlobal.window = commonjsGlobal; commonjsGlobal.window.navigator = {}; } if ('jQuery' in window || '$' in window) { /* * jquery.ajax-retry * https://github.com/johnkpaul/jquery-ajax-retry * * Copyright (c) 2012 John Paul * Licensed under the MIT license. */ (function ($) { // enhance all ajax requests with our retry API $.ajaxPrefilter(function (options, originalOptions, jqXHR) { jqXHR.retry = function (opts) { if (opts.timeout) { this.timeout = opts.timeout; } if (opts.statusCodes) { this.statusCodes = opts.statusCodes; } return this.pipe(null, pipeFailRetry(this, opts)); }; }); // generates a fail pipe function that will retry `jqXHR` `times` more times function pipeFailRetry(jqXHR, opts) { var times = opts.times; var timeout = jqXHR.timeout; // takes failure data as input, returns a new deferred return function (input, status, msg) { var ajaxOptions = this; var output = new $.Deferred(); var retryAfter = jqXHR.getResponseHeader('Retry-After'); // whenever we do make this request, pipe its output to our deferred function nextRequest() { $.ajax(ajaxOptions).retry({ times: times - 1, timeout: opts.timeout, statusCodes: opts.statusCodes }).pipe(output.resolve, output.reject); } if (times > 1 && (!jqXHR.statusCodes || $.inArray(input.status, jqXHR.statusCodes) > -1)) { // implement Retry-After rfc // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.37 if (retryAfter) { // it must be a date if (isNaN(retryAfter)) { timeout = new Date(retryAfter).getTime() - $.now(); // its a number in seconds } else { timeout = parseInt(retryAfter, 10) * 1000; } // ensure timeout is a positive number if (isNaN(timeout) || timeout < 0) { timeout = jqXHR.timeout; } } if (timeout !== undefined) { setTimeout(nextRequest, timeout); } else { nextRequest(); } } else { // no times left, reject our deferred with the current arguments output.rejectWith(this, arguments); } return output; }; } })(jQuery); /*! * jquery.requestanimationframe - 0.2.3-pre * https://github.com/gnarf37/jquery-requestAnimationFrame * Requires jQuery 1.8+ * * Copyright (c) 2016 Corey Frang * Licensed under the MIT license. */ // UMD factory https://github.com/umdjs/umd/blob/master/jqueryPlugin.js (function ($) { if (Number(jQuery.fn.jquery.split('.')[0]) >= 3) { if (window.console && window.console.warn) { window.console.warn('The jquery.requestanimationframe plugin is not needed ' + 'in jQuery 3.0 or newer as they handle it natively.'); } return false; } var animating; function raf() { if (animating) { window.requestAnimationFrame(raf); jQuery.fx.tick(); } } if (window.requestAnimationFrame) { jQuery.fx.timer = function (timer) { if (timer() && jQuery.timers.push(timer) && !animating) { animating = true; raf(); } }; jQuery.fx.stop = function () { animating = false; }; } })(jQuery); } var utilify = createCommonjsModule(function (module, exports) { /*@preserve * Utilify.js v0.10.1 * https://github.com/zeindelf/utilify-js * * Copyright (c) 2017-2018 Zeindelf * Released under the MIT license * * Date: 2018-09-17T18:11:50.467Z */ (function (global, factory) { module.exports = factory(); }(commonjsGlobal, (function () { /** * JavaScript Cookie v2.2.0 * https://github.com/js-cookie/js-cookie * * Copyright 2006, 2015 Klaus Hartl & Fagner Brack * Released under the MIT license */ /* eslint-disable */ function extend() { var i = 0; var result = {}; for (; i < arguments.length; i++) { var attributes = arguments[i]; for (var key in attributes) { result[key] = attributes[key]; } } return result; } function decode(s) { return s.replace(/(%[0-9A-Z]{2})+/g, decodeURIComponent); } var initCookies = function initCookies(converter) { function api() {} function set(key, value, attributes) { if (typeof document === 'undefined') { return; } attributes = extend({ path: '/' }, api.defaults, attributes); if (typeof attributes.expires === 'number') { attributes.expires = new Date(new Date() * 1 + attributes.expires * 864e+5); } // We're using "expires" because "max-age" is not supported by IE attributes.expires = attributes.expires ? attributes.expires.toUTCString() : ''; try { var result = JSON.stringify(value); if (/^[\{\[]/.test(result)) { value = result; } } catch (e) {} value = converter.write ? converter.write(value, key) : encodeURIComponent(String(value)).replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent); key = encodeURIComponent(String(key)).replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent).replace(/[\(\)]/g, escape); var stringifiedAttributes = ''; for (var attributeName in attributes) { if (!attributes[attributeName]) { continue; } stringifiedAttributes += '; ' + attributeName; if (attributes[attributeName] === true) { continue; } // Considers RFC 6265 section 5.2: // ... // 3. If the remaining unparsed-attributes contains a %x3B (";") // character: // Consume the characters of the unparsed-attributes up to, // not including, the first %x3B (";") character. // ... stringifiedAttributes += '=' + attributes[attributeName].split(';')[0]; } return document.cookie = key + '=' + value + stringifiedAttributes; } function get(key, json) { if (typeof document === 'undefined') { return; } var jar = {}; // To prevent the for loop in the first place assign an empty array // in case there are no cookies at all. var cookies = document.cookie ? document.cookie.split('; ') : []; var i = 0; for (; i < cookies.length; i++) { var parts = cookies[i].split('='); var cookie = parts.slice(1).join('='); if (!json && cookie.charAt(0) === '"') { cookie = cookie.slice(1, -1); } try { var name = decode(parts[0]); cookie = (converter.read || converter)(cookie, name) || decode(cookie); if (json) { try { cookie = JSON.parse(cookie); } catch (e) {} } jar[name] = cookie; if (key === name) { break; } } catch (e) {} } return key ? jar[key] : jar; } api.set = set; api.get = function (key) { return get(key, false /* read as raw */); }; api.getJSON = function (key) { return get(key, true /* read as json */); }; api.remove = function (key, attributes) { set(key, '', extend(attributes, { expires: -1 })); }; api.defaults = {}; api.withConverter = initCookies; return api; }; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; var createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var defineProperty = function (obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var toConsumableArray = function (arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } }; /* ! store2 - v2.7.0 - 2018-02-08 * Copyright (c) 2018 Nathan Bubna; Licensed (MIT OR GPL-3.0) */ /* eslint-disable */ var _ = { version: "2.7.0", areas: {}, apis: {}, // utilities inherit: function inherit(api, o) { for (var p in api) { if (!o.hasOwnProperty(p)) { o[p] = api[p]; } } return o; }, stringify: function stringify(d) { return d === undefined || typeof d === "function" ? d + '' : JSON.stringify(d); }, parse: function parse(s) { // if it doesn't parse, return as is try { return JSON.parse(s); } catch (e) { return s; } }, // extension hooks fn: function fn(name, _fn) { _.storeAPI[name] = _fn; for (var api in _.apis) { _.apis[api][name] = _fn; } }, get: function get$$1(area, key) { return area.getItem(key); }, set: function set$$1(area, key, string) { area.setItem(key, string); }, remove: function remove(area, key) { area.removeItem(key); }, key: function key(area, i) { return area.key(i); }, length: function length(area) { return area.length; }, clear: function clear(area) { area.clear(); }, // core functions Store: function Store(id, area, namespace) { var store = _.inherit(_.storeAPI, function (key, data, overwrite) { if (arguments.length === 0) { return store.getAll(); } if (typeof data === "function") { return store.transact(key, data, overwrite); } // fn=data, alt=overwrite if (data !== undefined) { return store.set(key, data, overwrite); } if (typeof key === "string" || typeof key === "number") { return store.get(key); } if (!key) { return store.clear(); } return store.setAll(key, data); // overwrite=data, data=key }); store._id = id; try { var testKey = '_safariPrivate_'; area.setItem(testKey, 'sucks'); store._area = area; area.removeItem(testKey); } catch (e) {} if (!store._area) { store._area = _.inherit(_.storageAPI, { items: {}, name: 'fake' }); } store._ns = namespace || ''; if (!_.areas[id]) { _.areas[id] = store._area; } if (!_.apis[store._ns + store._id]) { _.apis[store._ns + store._id] = store; } return store; }, storeAPI: { // admin functions area: function area(id, _area) { var store = this[id]; if (!store || !store.area) { store = _.Store(id, _area, this._ns); //new area-specific api in this namespace if (!this[id]) { this[id] = store; } } return store; }, namespace: function namespace(_namespace, noSession) { if (!_namespace) { return this._ns ? this._ns.substring(0, this._ns.length - 1) : ''; } var ns = _namespace, store = this[ns]; if (!store || !store.namespace) { store = _.Store(this._id, this._area, this._ns + ns + '.'); //new namespaced api if (!this[ns]) { this[ns] = store; } if (!noSession) { store.area('session', _.areas.session); } } return store; }, isFake: function isFake() { return this._area.name === 'fake'; }, toString: function toString() { return 'store' + (this._ns ? '.' + this.namespace() : '') + '[' + this._id + ']'; }, // storage functions has: function has(key) { if (this._area.has) { return this._area.has(this._in(key)); //extension hook } return !!(this._in(key) in this._area); }, size: function size() { return this.keys().length; }, each: function each(fn, value) { // value is used by keys(fillList) and getAll(fillList)) for (var i = 0, m = _.length(this._area); i < m; i++) { var key = this._out(_.key(this._area, i)); if (key !== undefined) { if (fn.call(this, key, value || this.get(key)) === false) { break; } } if (m > _.length(this._area)) { m--;i--; } // in case of removeItem } return value || this; }, keys: function keys(fillList) { return this.each(function (k, list) { list.push(k); }, fillList || []); }, get: function get$$1(key, alt) { var s = _.get(this._area, this._in(key)); return s !== null ? _.parse(s) : alt || s; // support alt for easy default mgmt }, getAll: function getAll(fillObj) { return this.each(function (k, all) { all[k] = this.get(k); }, fillObj || {}); }, transact: function transact(key, fn, alt) { var val = this.get(key, alt), ret = fn(val); this.set(key, ret === undefined ? val : ret); return this; }, set: function set$$1(key, data, overwrite) { var d = this.get(key); if (d != null && overwrite === false) { return data; } return _.set(this._area, this._in(key), _.stringify(data), overwrite) || d; }, setAll: function setAll(data, overwrite) { var changed, val; for (var key in data) { val = data[key]; if (this.set(key, val, overwrite) !== val) { changed = true; } } return changed; }, add: function add(key, data) { var d = this.get(key); if (d instanceof Array) { data = d.concat(data); } else if (d !== null) { var type = typeof d === "undefined" ? "undefined" : _typeof(d); if (type === (typeof data === "undefined" ? "undefined" : _typeof(data)) && type === 'object') { for (var k in data) { d[k] = data[k]; } data = d; } else { data = d + data; } } _.set(this._area, this._in(key), _.stringify(data)); return data; }, remove: function remove(key) { var d = this.get(key); _.remove(this._area, this._in(key)); return d; }, clear: function clear() { if (!this._ns) { _.clear(this._area); } else { this.each(function (k) { _.remove(this._area, this._in(k)); }, 1); } return this; }, clearAll: function clearAll() { var area = this._area; for (var id in _.areas) { if (_.areas.hasOwnProperty(id)) { this._area = _.areas[id]; this.clear(); } } this._area = area; return this; }, // internal use functions _in: function _in(k) { if (typeof k !== "string") { k = _.stringify(k); } return this._ns ? this._ns + k : k; }, _out: function _out(k) { return this._ns ? k && k.indexOf(this._ns) === 0 ? k.substring(this._ns.length) : undefined : // so each() knows to skip it k; } }, // end _.storeAPI storageAPI: { length: 0, has: function has(k) { return this.items.hasOwnProperty(k); }, key: function key(i) { var c = 0; for (var k in this.items) { if (this.has(k) && i === c++) { return k; } } }, setItem: function setItem(k, v) { if (!this.has(k)) { this.length++; } this.items[k] = v; }, removeItem: function removeItem(k) { if (this.has(k)) { delete this.items[k]; this.length--; } }, getItem: function getItem(k) { return this.has(k) ? this.items[k] : null; }, clear: function clear() { for (var k in this.items) { this.removeItem(k); } }, toString: function toString() { return this.length + ' items in ' + this.name + 'Storage'; } // end _.storageAPI } }; // safely set this up (throws error in IE10/32bit mode for local files) var store = _.Store("local", function () { try { return localStorage; } catch (e) {} }()); store.local = store; // for completeness store._ = _; // for extenders and debuggers... // safely setup store.session (throws exception in FF for file:/// urls) store.area("session", function () { try { return sessionStorage; } catch (e) {} }()); (function (store, _) { var _set = _.set, _get = _.get, _remove = _.remove, _key = _.key, _length = _.length, _clear = _.clear; _.overflow = function (area, create) { var name = area === _.areas.local ? '+local+' : area === _.areas.session ? '+session+' : false; if (name) { var overflow = _.areas[name]; if (create && !overflow) { overflow = store.area(name)._area; // area() copies to _.areas } else if (create === false) { delete _.areas[name]; delete store[name]; } return overflow; } }; _.set = function (area, key, string) { try { _set.apply(this, arguments); } catch (e) { if (e.name === 'QUOTA_EXCEEDED_ERR' || e.name === 'NS_ERROR_DOM_QUOTA_REACHED' || e.toString().indexOf("QUOTA_EXCEEDED_ERR") !== -1 || e.toString().indexOf("QuotaExceededError") !== -1) { // the e.toString is needed for IE9 / IE10, cos name is empty there return _.set(_.overflow(area, true), key, string); } throw e; } }; _.get = function (area, key) { var overflow = _.overflow(area); return overflow && _get.call(this, overflow, key) || _get.apply(this, arguments); }; _.remove = function (area, key) { var overflow = _.overflow(area); if (overflow) { _remove.call(this, overflow, key); } _remove.apply(this, arguments); }; _.key = function (area, i) { var overflow = _.overflow(area); if (overflow) { var l = _length.call(this, area); if (i >= l) { i = i - l; // make i overflow-relative for (var j = 0, m = _length.call(this, overflow); j < m; j++) { if (j === i) { // j is overflow index return _key.call(this, overflow, j); } } } } return _key.apply(this, arguments); }; _.length = function (area) { var length = _length(area), overflow = _.overflow(area); return overflow ? length + _length(overflow) : length; }; _.clear = function (area) { _.overflow(area, false); _clear.apply(this, arguments); }; })(store, store._, undefined); (function (store, _) { var prefix = 'exp@', suffix = ';', parse = _.parse, _get = _.get, _set = _.set; _.parse = function (s) { if (s && s.indexOf(prefix) === 0) { s = s.substring(s.indexOf(suffix) + 1); } return parse(s); }; _.expires = function (s) { if (s && s.indexOf(prefix) === 0) { return parseInt(s.substring(prefix.length, s.indexOf(suffix)), 10); } return false; }; _.when = function (min) { // if min, return min->date, else date->min var now = Math.floor(new Date().getTime() / 1000); return min ? new Date((now + min) * 1000) : now; }; _.cache = function (area, key) { var s = _get(area, key), min = _.expires(s); if (min && _.when() >= min) { return area.removeItem(key); } return s; }; _.get = function (area, key) { var s = _.cache(area, key); return s === undefined ? null : s; }; _.set = function (area, key, string, min) { try { if (min) { string = prefix + (_.when() + min) + suffix + string; } _set(area, key, string); } catch (e) { if (e.name === 'QUOTA_EXCEEDED_ERR' || e.name === 'NS_ERROR_DOM_QUOTA_REACHED') { var changed = false; for (var i = 0, m = area.length; i < m; i++) { if (_.cache(area, key) === undefined) { changed = true; } } if (changed) { return _.set.apply(this, arguments); } } throw e; } }; })(store, store._, undefined); var stringHelpers = { /** * Capitalize a string * * @param {string} str - The String * @return {string} The modified string * @example * capitalize('foo bar'); // 'Foo Bar' */ capitalize: function capitalize(str) { return str.replace(/(?:^|\s)\S/g, function (match) { return match.toUpperCase(); }); }, /** * Replace <, >, &, ', " and / with HTML entities. * @param {string} str - The string to check * @return {boolean} */ escape: function escape(str) { return str.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&#x27;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\//g, '&#x2F;').replace(/\\/g, '&#x5C;').replace(/`/g, '&#96;'); }, /** * Normalize text adding first character to upper after punctuations (. ? !) * * @param {String} [str] Text to convert * @return {String} */ normalizeText: function normalizeText(str) { var _this = this; var re = /(^|[.!?]\s+)([a-z])/g; var normalize = function normalize(str) { return str.toLowerCase().replace(re, function (m, $1, $2) { return $1 + $2.toUpperCase(); }); }; var addSpace = function addSpace(str) { return _this.strCompact(str.replace(/[,.!?:;]+(?=\S)/g, '$& ')); }; return normalize(addSpace(str)); }, /** * Zero padding number * * @param {integer} number Number to format * @param {integer} [size=2] Digits limit * @return {string} Formatted num with zero padding */ pad: function pad(number, size) { var stringNum = String(number); while (stringNum.length < (size || 2)) { stringNum = '0' + stringNum; } return stringNum; }, /** * Remove accents from a string * @param {string} str - The string to remove accents * @return {string} The modified string * @example * removeAccent('Olá Mündô!'); // 'Ola Mundo!' */ removeAccent: function removeAccent(str) { var reAccents = /[àáâãäçèéêëìíîïñòóôõöùúûüýÿÀÁÂÃÄÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ]/g; // Prefixed with some char to avoid off-by-one: var replacements = '_aaaaaceeeeiiiinooooouuuuyyAAAAACEEEEIIIINOOOOOUUUUY'; return str.replace(reAccents, function (match) { return replacements[reAccents.source.indexOf(match)]; }); }, /** * Slugify a text, removing/replacing all special characters and spaces with dashes '-' * @param {string} str - The string to sanitize * @return {string} The modified string * @example * slugifyText('Olá Mundo!'); // 'ola-mundo' */ slugifyText: function slugifyText(str) { str = str.replace(/^\s+|\s+$/g, '') // trim .toLowerCase().replace(/\./g, '-') // Replace a dot for a - .replace(/\*/g, '-') // Replace a * for a - .replace(/\+/g, '-'); // Replace a + for a - // Remove accents, swap ñ for n, etc var from = 'àáäâãèéëêìíïîòóöôõùúüûýÿñç·/_,:;'; var to = 'aaaaaeeeeiiiiooooouuuuyync------'; for (var i = 0, len = from.length; i < len; i += 1) { str = str.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i)); } str = str.replace(/[^a-z0-9 -]/g, '') // Remove invalid chars .replace(/\s+/g, '-') // Collapse whitespace and replace by - .replace(/-+/g, '-'); // Collapse dashes if (str.charAt(0) === '-') str = str.substr(1); if (str.charAt(str.length - 1) === '-') str = str.substr(0, str.length - 1); return str; }, /** * Compacts whitespace in the string to a single space and trims the ends. * * @param {String} [str] String to remove spaces * @return {String} * @example * strCompact(' Foo Bar Baz ') // 'Foo Bar Baz' */ strCompact: function strCompact(str) { return this.trim(str).replace(/([\r\n\s])+/g, function (match, whitespace) { return whitespace === ' ' ? whitespace : ' '; }); }, /** * Multiple string replace, PHP str_replace clone * @param {string|Array} search - The value being searched for, otherwise known as the needle. * An array may be used to designate multiple needles. * @param {string|Array} replace - The replacement value that replaces found search values. * An array may be used to designate multiple replacements. * @param {string} subject - The subject of the replacement * @return {string} The modified string * @example * strReplace(['olá', 'mundo'], ['hello', 'world'], 'olá mundo'); // 'hello world' * strReplace(['um', 'dois'], 'olá', 'um dois três'); // Output 'olá olá três' */ strReplace: function strReplace(search, replace, subject) { var regex = void 0; if (validateHelpers.isArray(search)) { for (var i = 0; i < search.length; i++) { search[i] = search[i].replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); regex = new RegExp(search[i], 'g'); subject = subject.replace(regex, validateHelpers.isArray(replace) ? replace[i] : replace); } } else { search = search.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); regex = new RegExp(search, 'g'); subject = subject.replace(regex, validateHelpers.isArray(replace) ? replace[0] : replace); } return subject; }, /** * Remove leading and trailing empty spaces. * * @param {String} str - The string. * @returns {String} The new string. * @example * trim(' Foo ') // 'Foo' */ trim: function trim(str) { if (validateHelpers.isString(str)) { return str.replace(/^\s+|\s+$/gm, ''); } return ''; }, /** * Make a string's first character uppercase * PHP ucfirst clone * * @param {String} str - The string. * @returns {String} The new string. * @example * ucfirst('foo bar foz') // 'Foo bar foz' */ ucfirst: function ucfirst(str) { str += ''; var f = str.charAt(0).toUpperCase(); return f + str.substr(1); }, /** * Converts hyphens and camel casing to underscores. * * @param {String} str String to convert * @return {String} */ underscore: function underscore(str) { return str.replace(/[-\s]+/g, '_').replace(/([A-Z\d]+)([A-Z][a-z])/g, '$1_$2').replace(/([a-z\d])([A-Z])/g, '$1_$2').toLowerCase(); }, /** * Replaces HTML encoded entities with <, >, &, ', " and /. * @param {string} str - The string to check * @return {boolean} */ unescape: function unescape(str) { return str.replace(/&amp;/g, '&').replace(/&quot;/g, '"').replace(/&#x27;/g, '\'').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&#x2F;/g, '/').replace(/&#x5C;/g, '\\').replace(/&#96;/g, '`'); } }; var globalHelpers = { /** * Recursively transform key strings to camelCase if param is an Object. * If param is string, return an camel cased string. * * @param {Object|String} obj Object or string to transform * @returns {Object|String} */ camelize: function camelize(obj) { var _this = this; var _camelize = function _camelize(str) { str = stringHelpers.underscore(str); str = stringHelpers.slugifyText(str); return str.replace(/[_.-\s](\w|$)/g, function (_, x) { return x.toUpperCase(); }); }; if (validateHelpers.isDate(obj) || validateHelpers.isRegExp(obj)) { return obj; } if (validateHelpers.isArray(obj)) { return obj.map(function (item, index) { if (validateHelpers.isObject(item)) { return _this.camelize(item); } return item; }); } if (validateHelpers.isString(obj)) { return _camelize(obj); } return Object.keys(obj).reduce(function (acc, key) { var camel = _camelize(key); acc[camel] = obj[key]; if (validateHelpers.isObject(obj[key])) { acc[camel] = _this.camelize(obj[key]); } return acc; }, {}); }, /** * Check if value contains in an element * * @category Global * @param {String} value - Value to check * @param {String|Array} elem - String or array * @return {Boolean} - Return true if element contains a value */ contains: function contains(value, elem) { if (validateHelpers.isArray(elem)) { for (var i = 0, len = elem.length; i < len; i += 1) { if (elem[i] === value) { return true; } } } if (validateHelpers.isString(elem)) { return elem.indexOf(value) >= 0; } return false; }, /** * Creates a debounced function that delays invoking `func` until after `wait` * milliseconds have elapsed since the last time the debounced function was * invoked, or until the next browser frame is drawn. The debounced function * comes with a `cancel` method to cancel delayed `func` invocations and a * `flush` method to immediately invoke them. Provide `options` to indicate * whether `func` should be invoked on the leading and/or trailing edge of the * `wait` timeout. The `func` is invoked with the last arguments provided to the * debounced function. Subsequent calls to the debounced function return the * result of the last `func` invocation. * * **Note:** If `leading` and `trailing` options are `true`, `func` is * invoked on the trailing edge of the timeout only if the debounced function * is invoked more than once during the `wait` timeout. * * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred * until the next tick, similar to `setTimeout` with a timeout of `0`. * * If `wait` is omitted in an environment with `requestAnimationFrame`, `func` * invocation will be deferred until the next frame is drawn (typically about * 16ms). * * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) * for details over the differences between `debounce` and `throttle`. * * @from Lodash * * @category Global * @param {Function} func The function to debounce. * @param {number} [wait=0] The number of milliseconds to delay; if omitted, `requestAnimationFrame` is used (if available). * @param {Object} [options={}] The options object. * @param {boolean} [options.leading=false] Specify invoking on the leading edge of the timeout. * @param {number} [options.maxWait] The maximum time `func` is allowed to be delayed before it's invoked. * @param {boolean} [options.trailing=true] Specify invoking on the trailing edge of the timeout. * @return {Function} Returns the new debounced function. * @example * // Avoid costly calculations while the window size is in flux. * $(window).on('resize', debounce(calculateLayout, 150)); * * // Invoke `sendMail` when clicked, debouncing subsequent calls. * $(element).on('click', debounce(sendMail, 300, { * 'leading': true, * 'trailing': false, * })); * * // Ensure `batchLog` is invoked once after 1 second of debounced calls. * const debounced = debounce(batchLog, 250, { 'maxWait': 1000 }) * const source = new EventSource('/stream') * $(source).on('message', debounced) * * // Cancel the trailing debounced invocation. * $(window).on('popstate', debounced.cancel) * * // Check for pending invocations. * const status = debounced.pending() ? "Pending..." : "Ready" */ debounce: function debounce(func, wait, options) { var lastArgs = void 0; var lastThis = void 0; var maxWait = void 0; var result = void 0; var timerId = void 0; var lastCallTime = void 0; var lastInvokeTime = 0; var leading = false; var maxing = false; var trailing = true; // Bypass `requestAnimationFrame` by explicitly setting `wait=0`. var useRAF = !wait && wait !== 0 && typeof window.requestAnimationFrame === 'function'; if (typeof func != 'function') { throw new TypeError('Expected a function'); } wait = +wait || 0; if (validateHelpers.isObject(options)) { leading = !!options.leading; maxing = 'maxWait' in options; maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : maxWait; trailing = 'trailing' in options ? !!options.trailing : trailing; } function invokeFunc(time) { var args = lastArgs; var thisArg = lastThis; lastArgs = lastThis = undefined; lastInvokeTime = time; result = func.apply(thisArg, args); return result; } function startTimer(pendingFunc, wait) { if (useRAF) { return window.requestAnimationFrame(pendingFunc); } return setTimeout(pendingFunc, wait); } function cancelTimer(id) { if (useRAF) { return window.cancelAnimationFrame(id); } clearTimeout(id); } function leadingEdge(time) { // Reset any `maxWait` timer. lastInvokeTime = time; // Start the timer for the trailing edge. timerId = startTimer(timerExpired, wait); // Invoke the leading edge. return leading ? invokeFunc(time) : result; } function remainingWait(time) { var timeSinceLastCall = time - lastCallTime; var timeSinceLastInvoke = time - lastInvokeTime; var timeWaiting = wait - timeSinceLastCall; return maxing ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting; } function shouldInvoke(time) { var timeSinceLastCall = time - lastCallTime; var timeSinceLastInvoke = time - lastInvokeTime; // Either this is the first call, activity has stopped and we're at the // trailing edge, the system time has gone backwards and we're treating // it as the trailing edge, or we've hit the `maxWait` limit. return lastCallTime === undefined || timeSinceLastCall >= wait || timeSinceLastCall < 0 || maxing && timeSinceLastInvoke >= maxWait; } function timerExpired() { var time = Date.now(); if (shouldInvoke(time)) { return trailingEdge(time); } // Restart the timer. timerId = startTimer(timerExpired, remainingWait(time)); } function trailingEdge(time) { timerId = undefined; // Only invoke if we have `lastArgs` which means `func` has been // debounced at least once. if (trailing && lastArgs) { return invokeFunc(time); } lastArgs = lastThis = undefined; return result; } function cancel() { if (timerId !== undefined) { cancelTimer(timerId); } lastInvokeTime = 0; lastArgs = lastCallTime = lastThis = timerId = undefined; } function flush() { return timerId === undefined ? result : trailingEdge(Date.now()); } function pending() { return timerId !== undefined; } function debounced() { var time = Date.now(); var isInvoking = shouldInvoke(time); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } lastArgs = args; /* eslint-disable */ lastThis = this; /* eslint-enable */ lastCallTime = time; if (isInvoking) { if (timerId === undefined) { return leadingEdge(lastCallTime); } if (maxing) { // Handle invocations in a tight loop. timerId = startTimer(timerExpired, wait); return invokeFunc(lastCallTime); } } if (timerId === undefined) { timerId = startTimer(timerExpired, wait); } return result; } debounced.cancel = cancel; debounced.flush = flush; debounced.pending = pending; return debounced; }, /** * Get variable type * * @category Global * @param {Mix} variable - Variable to check type * @return {string} Name of variable type * @example * getType(123); // 'number' * getType([]); // 'array' * getType({}); // 'object' * // and so on... */ getType: function getType(variable) { var types = { 'undefined': 'undefined', 'number': 'number', 'boolean': 'boolean', 'string': 'string', '[object Function]': 'function', '[object RegExp]': 'regexp', '[object Array]': 'array', '[object Date]': 'date', '[object Error]': 'error' }; return types[typeof variable === 'undefined' ? 'undefined' : _typeof(variable)] || types[{}.toString.call(variable)] || (variable ? 'object' : 'null'); }, /** * Get url params from a query string * * @category Global * @param {string} name - Param name * @param {string} entryPoint - Full url or query string * @return {string} Value query string param * @example * // URL: https://site.com?param1=foo&param2=bar * getUrlParameter('param1'); // foo * getUrlParameter('param2'); // bar * * // Given entry point * var url = 'http://www.site.com?param1=foo&param2=bar&param3=baz'; * getUrlParameter('param3', url); // baz */ getUrlParameter: function getUrlParameter(name, entryPoint) { entryPoint = !validateHelpers.isString(entryPoint) ? window.location.href : entryPoint.substring(0, 1) === '?' ? entryPoint : '?' + entryPoint; name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]'); var regex = new RegExp('[\\?&]' + name + '=([^&#]*)'); var results = regex.exec(entryPoint); return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' ')); }, parseJwt: function parseJwt(token) { var b64DecodeUnicode = function b64DecodeUnicode(str) { return decodeURIComponent(Array.prototype.map.call(atob(str), function (c) { return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); }).join('')); }; return JSON.parse(b64DecodeUnicode(token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/'))); }, /** * Resize image by aspect ratio * * @category Global * @param {String} type Resize by 'width' or 'height' * @param {Number} newSize New value to resize * @param {Number} aspectRatio Image aspect ratio (calculate by (width / height)) * @return {Object} Object with new 'width' and 'height' */ resizeImageByRatio: function resizeImageByRatio(type, newSiz