analytics-utils
Version:
Analytics utility functions used by 'analytics' module
1 lines • 19.9 kB
Source Map (JSON)
{"version":3,"file":"analytics-utils.cjs","sources":["../src/decodeUri.js","../src/isExternalReferrer.js","../src/paramsClean.js","../src/paramsParse.js","../src/url.js","../src/parseReferrer.js","../src/getBrowserLocale.js","../src/getTimeZone.js","../src/isScriptLoaded.js","../src/paramsGet.js","../src/paramsRemove.js","../src/throttle.js","../src/uuid.js"],"sourcesContent":["/**\n * Decode URI string\n *\n * @param {String} s string to decode\n * @returns {String} decoded string\n * @example\n * decode(\"Bought%20keyword)\n * => \"Bought keyword\"\n */\nexport function decodeUri(s) {\n try {\n return decodeURIComponent(s.replace(/\\+/g, ' '))\n } catch (e) {\n return null\n }\n}\n","import { isBrowser } from '@analytics/type-utils'\n\n/**\n * @param {string | null | undefined} ref\n * @returns {boolean | undefined}\n */\nexport function isExternalReferrer(ref) {\n if (!isBrowser) return false\n const referrer = ref || document.referrer\n if (referrer) {\n const port = window.document.location.port\n let ref = referrer.split('/')[2]\n if (port) {\n ref = ref.replace(`:${port}`, '')\n }\n return ref !== window.location.hostname\n }\n return false\n}\n","\n/**\n * Strip a query parameter from a url string\n * @param {string} url - url with query parameters\n * @param {string} param - parameter to strip\n * @return {string} cleaned url\n */\nexport function paramsClean(url, param) {\n const search = (url.split('?') || [ , ])[1] // eslint-disable-line\n if (!search || search.indexOf(param) === -1) {\n return url\n }\n // remove all utm params from URL search\n const regex = new RegExp(`(\\\\&|\\\\?)${param}([_A-Za-z0-9\"+=.\\\\/\\\\-@%]+)`, 'g')\n const cleanSearch = `?${search}`.replace(regex, '').replace(/^&/, '?')\n // replace search params with clean params\n const cleanURL = url.replace(`?${search}`, cleanSearch)\n // use browser history API to clean the params\n return cleanURL\n}\n","import { isBrowser } from '@analytics/type-utils'\nimport { decodeUri } from './decodeUri.js'\n\n/**\n * Get search string from given url\n * @param {string} [url] - optional url string. If no url, window.location.search will be used\n * @return {string} url search string\n */\nfunction getSearchString(url) {\n if (url) {\n const p = url.match(/\\?(.*)/)\n return (p && p[1]) ? p[1].split('#')[0] : ''\n }\n return isBrowser && window.location.search.substring(1)\n}\n\n/**\n * Parse url parameters into javascript object\n * @param {string} [url] - URI to parse. If no url supplied window.location will be used\n * @return {object} parsed url parameters\n */\nexport function paramsParse(url) {\n return getParamsAsObject(getSearchString(url))\n}\n\n/*\n?first=abc&a[]=123&a[]=false&b[]=str&c[]=3.5&a[]=last\nhttps://random.url.com?Target=Report&Method=getStats&fields%5B%5D=Offer.name&fields%5B%5D=Advertiser.company&fields%5B%5D=Stat.clicks&fields%5B%5D=Stat.conversions&fields%5B%5D=Stat.cpa&fields%5B%5D=Stat.payout&fields%5B%5D=Stat.date&fields%5B%5D=Stat.offer_id&fields%5B%5D=Affiliate.company&groups%5B%5D=Stat.offer_id&groups%5B%5D=Stat.date&filters%5BStat.affiliate_id%5D%5Bconditional%5D=EQUAL_TO&filters%5BStat.affiliate_id%5D%5Bvalues%5D=1831&limit=9999\nhttps://random.url.com?Target=Offer&Method=findAll&filters%5Bhas_goals_enabled%5D%5BTRUE%5D=1&filters%5Bstatus%5D=active&fields%5B%5D=id&fields%5B%5D=name&fields%5B%5D=default_goal_name\nhttp://localhost:3000/?Target=Offer&Method=findAll&filters[has_goals_enabled][TRUE]=1&filters[status]=active&filters[wow]arr[]=yaz&filters[wow]arr[]=naz&fields[]=id&fields[]=name&fields[]=default_goal_name */\n\n\nfunction getParamsAsObject(query) {\n let params = Object.create(null)\n let temp\n const re = /([^&=]+)=?([^&]*)/g\n\n while (temp = re.exec(query)) {\n var k = decodeUri(temp[1])\n var v = decodeUri(temp[2])\n if (!k) continue\n if (k.substring(k.length - 2) === '[]') {\n k = k.substring(0, k.length - 2);\n var arrVal = params[k] || (params[k] = [])\n params[k] = Array.isArray(arrVal) ? arrVal : []\n params[k].push(v)\n } else {\n params[k] = (v === '') ? true : v\n }\n }\n\n for (var prop in params) {\n var arr = prop.split('[')\n if (arr.length > 1) {\n assign(params, arr.map((x) => x.replace(/[?[\\]\\\\ ]/g, '')), params[prop])\n delete params[prop]\n }\n }\n return params\n}\n\nfunction assign(obj, keyPath, value) {\n var lastKeyIndex = keyPath.length - 1\n for (var i = 0; i < lastKeyIndex; ++i) {\n var key = keyPath[i]\n if (key === '__proto__' || key === 'constructor') {\n break;\n }\n if (!(key in obj)) { \n obj[key] = {} \n }\n obj = obj[key]\n }\n obj[keyPath[lastKeyIndex]] = value\n}\n\n\n/*\nhttps://github.com/choojs/nanoquery/blob/791cbdfe49cc380f0b2f93477572128946171b46/browser.js\nvar reg = /([^?=&]+)(=([^&]*))?/g\n\nfunction qs (url) {\n var obj = {}\n url.replace(/^.*\\?/, '').replace(reg, function (a0, a1, a2, a3) {\n var value = decodeURIComponent(a3)\n var key = decodeURIComponent(a1)\n if (obj.hasOwnProperty(key)) {\n if (Array.isArray(obj[key])) obj[key].push(value)\n else obj[key] = [obj[key], value]\n } else {\n obj[key] = value\n }\n })\n return obj\n}\n*/","import { isBrowser } from '@analytics/type-utils'\n\n/**\n * Get host domain of url\n * @param {String} url - href of page\n * @return {String} hostname of page\n *\n * @example\n * getDomainHost('https://subdomain.my-site.com/')\n * > subdomain.my-site.com\n */\nexport function getDomainHost(url) {\n if (!isBrowser) return null\n const a = document.createElement('a')\n a.setAttribute('href', url)\n return a.hostname\n}\n\n/**\n * Get host domain of url\n * @param {String} url - href of page\n * @return {String} base hostname of page\n *\n * @example\n * getDomainBase('https://subdomain.my-site.com/')\n * > my-site.com\n */\nexport function getDomainBase(url) {\n const host = getDomainHost(url) || ''\n return host.split('.').slice(-2).join('.')\n}\n\n/**\n * Remove TLD from domain string\n * @param {String} baseDomain - host name of site\n * @return {String}\n * @example\n * trimTld('google.com')\n * > google\n */\nexport function trimTld(baseDomain) {\n const arr = baseDomain.split('.')\n return (arr.length > 1) ? arr.slice(0, -1).join('.') : baseDomain\n}\n\nexport default {\n trimTld,\n getDomainBase,\n getDomainHost\n}\n","import { isBrowser } from '@analytics/type-utils'\nimport { paramsParse } from './paramsParse.js'\nimport { isExternalReferrer } from './isExternalReferrer.js'\nimport { trimTld, getDomainBase } from './url.js'\n\nconst googleKey = 'google'\n\n/**\n * @typedef {{\n * campaign: string,\n * referrer?: string,\n * } & DomainObject & Object.<string, any>} ReferrerObject\n */\n\n/**\n * Checks a given url and parses referrer data\n * @param {String} [referrer] - (optional) referring URL\n * @param {String} [currentUrl] - (optional) the current url\n * @return {ReferrerObject} [description]\n */\nexport function parseReferrer(referrer, currentUrl) {\n if (!isBrowser) return false\n // default referral data\n let refData = {\n 'source': '(direct)',\n 'medium': '(none)',\n 'campaign': '(not set)'\n }\n // Add raw ref url if external\n if (referrer && isExternalReferrer(referrer)) {\n refData.referrer = referrer\n }\n\n const domainInfo = parseDomain(referrer)\n // Read referrer URI and infer source\n if (domainInfo && Object.keys(domainInfo).length) {\n refData = Object.assign({}, refData, domainInfo)\n }\n\n // Read URI params and use set utm params\n const params = paramsParse(currentUrl)\n const paramKeys = Object.keys(params)\n if (!paramKeys.length) {\n return refData\n }\n\n // set campaign params off GA matches\n const gaParams = paramKeys.reduce((acc, key) => {\n // match utm params & dclid (display) & gclid (cpc)\n if (key.match(/^utm_/)) {\n acc[`${key.replace(/^utm_/, '')}`] = params[key]\n }\n // https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters\n // dclid - cpc Cost-Per-Thousand Impressions\n // gclid - cpc Cost per Click\n if (key.match(/^(d|g)clid/)) {\n acc['source'] = googleKey\n acc['medium'] = (params.gclid) ? 'cpc' : 'cpm'\n acc[key] = params[key]\n }\n return acc\n }, {})\n\n return Object.assign({}, refData, gaParams)\n}\n\n/**\n * @typedef {{\n * source: string,\n * medium: string,\n * term?: string\n * }} DomainObject\n */\n\n/**\n * Client side domain parser for determining marketing data.\n * @param {String} referrer - ref url\n * @return {DomainObject | boolean}\n */\nfunction parseDomain(referrer) {\n if (!referrer || !isBrowser) return false\n\n let referringDomain = getDomainBase(referrer)\n const a = document.createElement('a')\n a.href = referrer\n\n // Shim for the billion google search engines\n if (a.hostname.indexOf(googleKey) > -1) {\n referringDomain = googleKey\n }\n\n // If is search engine\n if (searchEngines[referringDomain]) {\n const searchEngine = searchEngines[referringDomain]\n const queryParam = (typeof searchEngine === 'string') ? searchEngine : searchEngine.p\n const termRegex = new RegExp(queryParam + '=.*?([^&#]*|$)', 'gi')\n const term = a.search.match(termRegex)\n\n return {\n source: searchEngine.n || trimTld(referringDomain),\n medium: 'organic',\n term: (term ? term[0].split('=')[1] : '') || '(not provided)'\n }\n }\n\n // Default\n const medium = (!isExternalReferrer(referrer)) ? 'internal' : 'referral'\n return {\n source: a.hostname,\n medium: medium\n }\n}\n\n/**\n * Search engine query string data\n * @type {Object}\n */\nconst Q = 'q'\nconst QUERY = 'query'\nconst searchEngines = {\n 'daum.net': Q,\n 'eniro.se': 'search_word',\n 'naver.com': QUERY,\n 'yahoo.com': 'p',\n 'msn.com': Q,\n 'aol.com': Q,\n 'ask.com': Q,\n 'baidu.com': 'wd',\n 'yandex.com': 'text',\n 'rambler.ru': 'words',\n 'google': Q,\n 'bing.com': {\n 'p': Q,\n 'n': 'live'\n },\n}\n","import { isBrowser } from '@analytics/type-utils'\n\n/**\n * @returns {string | undefined}\n */\nexport function getBrowserLocale() {\n if (!isBrowser) return\n const { language, languages, userLanguage } = navigator\n if (userLanguage) return userLanguage // IE only\n return (languages && languages.length) ? languages[0] : language\n}\n","\n/**\n * @returns {string | undefined}\n */\nexport function getTimeZone() {\n try {\n return Intl.DateTimeFormat().resolvedOptions().timeZone\n } catch (error) {}\n}\n","import { isBrowser, isString, isRegex } from '@analytics/type-utils'\n\n/**\n * Check if a script is loaded\n * @param {String|RegExp} script - Script src as string or regex\n * @return {Boolean} is script loaded\n */\nexport function isScriptLoaded(script) {\n if (!isBrowser) return true\n const scripts = document.getElementsByTagName('script')\n return !!Object.keys(scripts).filter((key) => {\n const { src } = scripts[key]\n if (isString(script)) {\n return src.indexOf(script) !== -1\n } else if (isRegex(script)) {\n return src.match(script)\n }\n return false\n }).length\n}\n","import {decodeUri} from './decodeUri.js'\n\n/**\n * Get a given query parameter value\n * @param {string} param - Key of parameter to find\n * @param {string} url - url to search\n * @return {string} match\n */\nexport function paramsGet(param, url) {\n return decodeUri((RegExp(`${param}=(.+?)(&|$)`).exec(url) || [, ''])[1])\n}\n","import { isBrowser } from '@analytics/type-utils'\nimport { paramsClean } from './paramsClean.js'\n\n/**\n * Removes params from url in browser\n * @param {string} param - param key to remove from current URL\n * @param {() => void} [callback] - callback function to run. Only runs in browser\n * @return {PromiseLike<void>}\n */\nexport function paramsRemove(param, callback) {\n if (!isBrowser) return Promise.resolve()\n\n return new Promise((resolve, reject) => {\n if (window.history && window.history.replaceState) {\n const url = window.location.href\n const cleanUrl = paramsClean(url, param)\n if (url !== cleanUrl) {\n /* replace URL with history API */\n // eslint-disable-next-line no-restricted-globals\n history.replaceState({}, '', cleanUrl)\n }\n }\n\n if (callback) callback()\n\n return resolve()\n })\n}\n","/**\n * @template {Function} F;\n * @param {F} func;\n * @param {number} wait;\n * @return {F};\n */\nexport function throttle(func, wait) {\n var context, args, result\n var timeout = null\n var previous = 0\n var later = function () {\n previous = new Date()\n timeout = null\n result = func.apply(context, args)\n };\n return function () {\n var now = new Date()\n if (!previous) {\n previous = now\n }\n var remaining = wait - (now - previous)\n context = this\n args = arguments\n if (remaining <= 0) {\n clearTimeout(timeout)\n timeout = null\n previous = now\n result = func.apply(context, args)\n } else if (!timeout) {\n timeout = setTimeout(later, remaining)\n }\n return result\n }\n}\n","/* ref: http://bit.ly/2daP79j */\n/**\n * @return {string}\n */\nexport function uuid() {\n var u = '',\n m = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx',\n i = 0,\n rb = Math.random() * 0xffffffff|0;\n\n while (i++<36) {\n var c = m [i-1],\n r = rb&0xf,\n v = c=='x' ? r : (r&0x3|0x8);\n\n u += (c=='-' || c=='4') ? c : v.toString(16);\n rb = i%8==0 ? Math.random() * 0xffffffff|0 : rb>>4\n }\n return u\n}\n"],"names":["decodeUri","s","decodeURIComponent","replace","e","isExternalReferrer","ref","isBrowser","referrer","document","port","window","location","split","hostname","paramsClean","url","param","search","indexOf","regex","RegExp","cleanSearch","paramsParse","query","temp","params","Object","create","re","exec","k","v","substring","length","arrVal","Array","isArray","push","prop","arr","assign","map","x","getParamsAsObject","p","match","getSearchString","obj","keyPath","value","lastKeyIndex","i","key","getDomainHost","a","createElement","setAttribute","getDomainBase","slice","join","trimTld","baseDomain","googleKey","Q","searchEngines","google","n","_navigator","navigator","languages","userLanguage","language","Intl","DateTimeFormat","resolvedOptions","timeZone","error","script","scripts","getElementsByTagName","keys","filter","src","isString","isRegex","callback","Promise","resolve","reject","history","replaceState","href","cleanUrl","currentUrl","refData","source","medium","campaign","domainInfo","referringDomain","searchEngine","termRegex","term","parseDomain","paramKeys","gaParams","reduce","acc","gclid","func","wait","context","args","result","timeout","previous","later","Date","apply","now","remaining","this","arguments","clearTimeout","setTimeout","u","rb","Math","random","c","r","toString"],"mappings":"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"}