{"version":3,"file":"js/chunks/util.js","sources":["webpack:///./org_colony/cartridge/js/util.js"],"sourcesContent":["const forEach = require('lodash.foreach');\nconst isString = require('lodash.isstring');\n\nconst smallBreakpoint = 320;\nconst mediumBreakpoint = 480;\nconst largeBreakpoint = 768;\nconst desktopBreakpoint = 1025;\nconst maxBreakpoint = 1280;\nconst mobileMenuBreakpoint = desktopBreakpoint;\n\nconst util = {\n /**\n * @desc Media breakpoints that are used throughout the Javascript\n */\n breakpoints: {\n xs: smallBreakpoint,\n sm: mediumBreakpoint,\n md: largeBreakpoint,\n lg: desktopBreakpoint,\n xl: maxBreakpoint,\n 'mobile-menu': mobileMenuBreakpoint,\n },\n\n /**\n * @function\n * @description Returns either an object with all of the available breakpoints or a specific viewport based on the given size\n * @param {string} size The viewport to return\n * @param {string} breakpoints A custom breakpoints object\n */\n getViewports(size, breakpoints) {\n const bps = typeof breakpoints !== 'undefined' ? breakpoints : this.breakpoints;\n\n if (typeof size !== 'undefined') {\n if (bps[size]) {\n return bps[size];\n }\n window.console.error('Unexpected viewport size given in util.getViewports');\n throw new Error('Unexpected viewport size given in util.getViewports');\n } else {\n return breakpoints;\n }\n },\n\n /**\n * @function\n * @description Returns the current viewport name (ex: 'medium') or 'max' if the current window is larger than any defined viewport width\n */\n getCurrentViewport() {\n const w = window.innerWidth;\n const viewports = util.getViewports();\n let viewportName = 'max';\n // traverse the object from small up to desktop, and return the first match\n forEach(viewports, (value, name) => {\n if (w <= value) {\n viewportName = name;\n return false;\n }\n return true;\n });\n return viewportName;\n },\n\n /**\n * @function\n * @description appends the parameter with the given name and value to the given url and returns the changed url\n * @param {String} url the url to which the parameter will be added\n * @param {String} name the name of the parameter\n * @param {String} value the value of the parameter\n */\n appendParamToURL(url, name, value) {\n // quit if the param already exists\n if (url.indexOf(`${name}=`) !== -1) {\n return url;\n }\n const separator = url.indexOf('?') !== -1 ? '&' : '?';\n return `${url + separator + name}=${encodeURIComponent(value)}`;\n },\n\n /**\n * @function\n * @description remove the parameter and its value from the given url and returns the changed url\n * @param {String} url the url from which the parameter will be removed\n * @param {String} name the name of parameter that will be removed from url\n */\n removeParamFromURL(url, name) {\n if (url.indexOf('?') === -1 || url.indexOf(`${name}=`) === -1) {\n return url;\n }\n const [domain, query] = url.split('?');\n const newParams = [];\n let paramUrl = query;\n let hash = null;\n\n // if there is a hash at the end, store the hash\n if (query.indexOf('#') > -1) {\n [paramUrl, hash] = query.split('#');\n }\n const params = paramUrl.split('&');\n for (let i = 0; i < params.length; i += 1) {\n // put back param to newParams array if it is not the one to be removed\n if (params[i].split('=')[0] !== name) {\n newParams.push(params[i]);\n }\n }\n return `${domain}?${newParams.join('&')}${hash ? `#${hash}` : ''}`;\n },\n\n /**\n * @function\n * @description appends the parameters to the given url and returns the changed url\n * @param {String} url the url to which the parameters will be added\n * @param {Object} params\n */\n appendParamsToUrl(url, params) {\n let newUrl = url;\n forEach(params, (value, name) => {\n newUrl = this.appendParamToURL(newUrl, name, value);\n });\n return newUrl;\n },\n /**\n * @function\n * @description extract the query string from URL\n * @param {String} url the url to extra query string from\n * */\n getQueryString(url) {\n let qs;\n if (!isString(url)) { return null; }\n const a = document.createElement('a');\n a.href = url;\n if (a.search) {\n qs = a.search.substr(1); // remove the leading ?\n }\n return qs;\n },\n /**\n * @function\n * @description\n * @param {String}\n * @param {String}\n */\n elementInViewport(el, offsetToTop) {\n const width = el.offsetWidth;\n const height = el.offsetHeight;\n let top = el.offsetTop;\n let left = el.offsetLeft;\n let currentElement = el;\n\n while (currentElement.offsetParent) {\n currentElement = currentElement.offsetParent;\n top += currentElement.offsetTop;\n left += currentElement.offsetLeft;\n }\n\n if (typeof (offsetToTop) !== 'undefined') {\n top -= offsetToTop;\n }\n\n if (window.pageXOffset !== null) {\n return (\n top < (window.pageYOffset + window.innerHeight)\n && left < (window.pageXOffset + window.innerWidth)\n && (top + height) > window.pageYOffset\n && (left + width) > window.pageXOffset\n );\n }\n\n if (document.compatMode === 'CSS1Compat') {\n return (\n top < (window.document.documentElement.scrollTop + window.document.documentElement.clientHeight)\n && left < (window.document.documentElement.scrollLeft + window.document.documentElement.clientWidth)\n && (top + height) > window.document.documentElement.scrollTop\n && (left + width) > window.document.documentElement.scrollLeft\n );\n }\n return false;\n },\n\n /**\n * @function\n * @description Appends the parameter 'format=ajax' to a given path\n * @param {String} path the relative path\n */\n ajaxUrl(path) {\n return this.appendParamToURL(path, 'format', 'ajax');\n },\n\n /**\n * @function\n * @description\n * @param {String} url\n */\n toAbsoluteUrl(url) {\n return url.indexOf('http') !== 0 && url.charAt(0) !== '/' ? `/${url}` : url;\n },\n /**\n * @function\n * @description Loads css dynamically from given urls\n * @param {Array} urls Array of urls from which css will be dynamically loaded.\n */\n loadDynamicCss(urls) {\n const len = urls.length;\n for (let i = 0; i < len; i += 1) {\n this.loadedCssFiles.push(this.loadCssFile(urls[i]));\n }\n },\n\n /**\n * @function\n * @description Loads css file dynamically from given url\n * @param {String} url The url from which css file will be dynamically loaded.\n */\n loadCssFile(url) {\n return $('').appendTo($('head')).attr({\n type: 'text/css',\n rel: 'stylesheet',\n }).attr('href', url); // for i.e. <9, href must be added after link has been appended to head\n },\n // array to keep track of the dynamically loaded CSS files\n loadedCssFiles: [],\n\n /**\n * @function\n * @description Removes all css files which were dynamically loaded\n */\n clearDynamicCss() {\n const len = this.loadedCssFiles.length;\n for (let i = 0; i < len; i += 1) {\n $(this.loadedCssFiles[i]).remove();\n }\n this.loadedCssFiles = [];\n },\n /**\n * @function\n * @description Loads js dynamically from given urls\n * @param {Array} urls Array of urls from which js will be dynamically loaded.\n */\n loadDynamicJs(urls) {\n const len = urls.length;\n for (let i = 0; i < len; i += 1) {\n this.loadedJsFiles.push(this.loadJsFile(urls[i]));\n }\n },\n\n /**\n * @function\n * @description Loads js file dynamically from given url\n * @param {String} url The url from which js file will be dynamically loaded.\n */\n loadJsFile(url) {\n return $('').appendTo($('body')).attr({\n type: 'text/javascript',\n }).attr('src', url);\n },\n // array to keep track of the dynamically loaded JS files\n loadedJsFiles: [],\n\n /**\n * @function\n * @description Removes all js files which were dynamically loaded\n */\n clearDynamicJs() {\n const len = this.loadedJsFiles.length;\n for (let i = 0; i < len; i += 1) {\n $(this.loadedJsFiles[i]).remove();\n }\n this.loadedJsFiles = [];\n },\n /**\n * @function\n * @description Extracts all parameters from a given query string into an object\n * @param {String} qs The query string from which the parameters will be extracted\n */\n getQueryStringParams(qs) {\n if (!qs || qs.length === 0) { return {}; }\n const url = qs.toString();\n const params = {};\n\n // Use the String::replace method to iterate over each\n // name-value pair in the string.\n url.replace(\n /([^?=&]+)(=([^&]*))?/g,\n ($0, $1, $2, $3) => {\n params[$1] = decodeURIComponent($3);\n },\n );\n return params;\n },\n\n fillAddressFields(address, $form) {\n forEach(address, (value, field) => {\n if (field !== 'ID' && field !== 'UUID' && field !== 'key') {\n // if the key in address object ends with 'Code', remove that suffix\n // keys that ends with 'Code' are postalCode, stateCode and countryCode\n $form.find(`[name$=\"${field.replace('Code', '')}\"]`).val(address[field]);\n // update the state fields\n if (field === 'countryCode') {\n $form.find('[name$=\"country\"]').trigger('change');\n // retrigger state selection after country has changed\n // this results in duplication of the state code, but is a necessary evil\n // for now because sometimes countryCode comes after stateCode\n $form.find('[name$=\"state\"]').val(address.stateCode);\n }\n }\n });\n },\n\n fillAddressDisplay(address, $container) {\n forEach(address, (value, field) => {\n if (field !== 'ID' && field !== 'UUID' && field !== 'key') {\n $container.find(`.${field}`).text(address[field]);\n }\n });\n },\n /**\n * @function\n * @description Updates the number of the remaining character\n * based on the character limit in a text area\n */\n limitCharacters() {\n $('form').find('textarea[data-character-limit], input[data-character-limit]').each((index, element) => {\n const characterLimit = $(element).data('character-limit');\n const charCountHtml = String.format(\n Resources.CHAR_LIMIT_MSG,\n `${characterLimit}`,\n );\n let charCountContainer = $(element).next('div.char-count');\n if (charCountContainer.length === 0) {\n charCountContainer = $('