UNPKG

begrowth-analytics-utils

Version:

Analytics utility functions used by 'analytics' module

536 lines (439 loc) 13.4 kB
export { default as dotProp } from 'dlv'; export { getCookie, globalContext, removeCookie, setCookie, default as storage } from 'begrowth-analytics-storage-utils'; function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function (obj) { return typeof obj; }; } else { _typeof = function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function isFunction(x) { return typeof x === 'function'; } /** * @param x * @return {x is string} */ function isString(x) { return typeof x === 'string'; } /** * @param x * @return {x is undefined} */ function isUndefined(x) { return typeof x === 'undefined'; } /** * @param x * @return {x is boolean} */ function isBoolean(x) { return typeof x === 'boolean'; } /** * @template T * @param x * @return {x is Array<T>} */ function isArray(x) { return Array.isArray(x); } /** * @param obj * @return {obj is Object} */ function isObject(obj) { if (_typeof(obj) !== 'object' || obj === null) return false; var proto = obj; while (Object.getPrototypeOf(proto) !== null) { proto = Object.getPrototypeOf(proto); } return Object.getPrototypeOf(obj) === proto; } function decode(s) { try { return decodeURIComponent(s.replace(/\+/g, ' ')); } catch (e) { return null; } } var inBrowser = typeof document !== 'undefined'; /** * @returns {string | undefined} */ function getBrowserLocale() { if (!inBrowser) return; var _navigator = navigator, language = _navigator.language, languages = _navigator.languages, userLanguage = _navigator.userLanguage; if (userLanguage) return userLanguage; // IE only return languages && languages.length ? languages[0] : language; } function getTimeZone() { try { return Intl.DateTimeFormat().resolvedOptions().timeZone; } catch (error) {} } /** * @param {string | null | undefined} ref * @returns {boolean | undefined} */ function isExternalReferrer(ref) { if (!inBrowser) return false; var referrer = ref || document.referrer; if (referrer) { var port = window.document.location.port; var _ref = referrer.split('/')[2]; if (port) { _ref = _ref.replace(":".concat(port), ''); } return _ref !== window.location.hostname; } return false; } /** * Check if a script is loaded * @param {String|RegExp} script - Script src as string or regex * @return {Boolean} is script loaded */ function isScriptLoaded(script) { if (!inBrowser) return true; var scripts = document.getElementsByTagName('script'); return !!Object.keys(scripts).filter(function (key) { var src = scripts[key].src; if (typeof script === 'string') { return src.indexOf(script) !== -1; } else if (script instanceof RegExp) { return src.match(script); } return false; }).length; } function noOp() {} function paramsClean(url, param) { var search = (url.split('?') || [,])[1]; // eslint-disable-line if (!search || search.indexOf(param) === -1) { return url; } // remove all utm params from URL search var regex = new RegExp("(\\&|\\?)".concat(param, "([_A-Za-z0-9\"+=.\\/\\-@%]+)"), 'g'); var cleanSearch = "?".concat(search).replace(regex, '').replace(/^&/, '?'); // replace search params with clean params var cleanURL = url.replace("?".concat(search), cleanSearch); // use browser history API to clean the params return cleanURL; } /** * Get a given query parameter value * @param {string} param - Key of parameter to find * @param {string} url - url to search * @return {string} match */ function getValueParamValue(param, url) { return decode((RegExp("".concat(param, "=(.+?)(&|$)")).exec(url) || [, ''])[1]); } /** * Get search string from given url * @param {string} [url] - optional url string. If no url, window.location.search will be used * @return {string} url search string */ function getSearchString(url) { if (url) { var p = url.match(/\?(.*)/); return p && p[1] ? p[1].split('#')[0] : ''; } return inBrowser && window.location.search.substring(1); } /** * Parse url parameters into javascript object * @param {string} [url] - URI to parse. If no url supplied window.location will be used * @return {object} parsed url parameters */ function paramsParse(url) { return getParamsAsObject(getSearchString(url)); } /* ?first=abc&a[]=123&a[]=false&b[]=str&c[]=3.5&a[]=last https://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 https://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 http://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 */ function getParamsAsObject(query) { var params = {}; var temp; var re = /([^&=]+)=?([^&]*)/g; while (temp = re.exec(query)) { var k = decode(temp[1]); var v = decode(temp[2]); if (k.substring(k.length - 2) === '[]') { k = k.substring(0, k.length - 2); (params[k] || (params[k] = [])).push(v); } else { params[k] = v === '' ? true : v; } } for (var prop in params) { var arr = prop.split('['); if (arr.length > 1) { assign(params, arr.map(function (x) { return x.replace(/[?[\]\\ ]/g, ''); }), params[prop]); delete params[prop]; } } return params; } function assign(obj, keyPath, value) { var lastKeyIndex = keyPath.length - 1; for (var i = 0; i < lastKeyIndex; ++i) { var key = keyPath[i]; if (!(key in obj)) { obj[key] = {}; } obj = obj[key]; } obj[keyPath[lastKeyIndex]] = value; } /* https://github.com/choojs/nanoquery/blob/791cbdfe49cc380f0b2f93477572128946171b46/browser.js var reg = /([^?=&]+)(=([^&]*))?/g function qs (url) { var obj = {} url.replace(/^.*\?/, '').replace(reg, function (a0, a1, a2, a3) { var value = decodeURIComponent(a3) var key = decodeURIComponent(a1) if (obj.hasOwnProperty(key)) { if (Array.isArray(obj[key])) obj[key].push(value) else obj[key] = [obj[key], value] } else { obj[key] = value } }) return obj } */ /** * Removes params from url in browser * @param {string} param - param key to remove from current URL * @param {() => void} [callback] - callback function to run. Only runs in browser * @return {PromiseLike<void>} */ function paramsRemove(param, callback) { if (!inBrowser) return Promise.resolve(); return new Promise(function (resolve, reject) { if (window.history && window.history.replaceState) { var url = window.location.href; var cleanUrl = paramsClean(url, param); if (url !== cleanUrl) { /* replace URL with history API */ // eslint-disable-next-line no-restricted-globals history.replaceState({}, '', cleanUrl); } } if (callback) callback(); return resolve(); }); } /** * Get host domain of url * @param {String} url - href of page * @return {String} hostname of page * * @example * getDomainHost('https://subdomain.my-site.com/') * > subdomain.my-site.com */ function getDomainHost(url) { if (!inBrowser) return null; var a = document.createElement('a'); a.setAttribute('href', url); return a.hostname; } /** * Get host domain of url * @param {String} url - href of page * @return {String} base hostname of page * * @example * getDomainBase('https://subdomain.my-site.com/') * > my-site.com */ function getDomainBase(url) { var host = getDomainHost(url) || ''; return host.split('.').slice(-2).join('.'); } /** * Remove TLD from domain string * @param {String} baseDomain - host name of site * @return {String} * @example * trimTld('google.com') * > google */ function trimTld(baseDomain) { var arr = baseDomain.split('.'); return arr.length > 1 ? arr.slice(0, -1).join('.') : baseDomain; } var url = { trimTld: trimTld, getDomainBase: getDomainBase, getDomainHost: getDomainHost }; var googleKey = 'google'; /** * @typedef {{ * campaign: string, * referrer?: string, * } & DomainObject & Object.<string, any>} ReferrerObject */ /** * Checks a given url and parses referrer data * @param {String} [referrer] - (optional) referring URL * @param {String} [currentUrl] - (optional) the current url * @return {ReferrerObject} [description] */ function parseReferrer(referrer, currentUrl) { if (!inBrowser) return false; // default referral data var refData = { 'source': '(direct)', 'medium': '(direct)', 'campaign': '(direct)' }; // Add raw ref url if external if (referrer && isExternalReferrer(referrer)) { refData.referrer = referrer; } var domainInfo = parseDomain(referrer); // Read referrer URI and infer source if (domainInfo && Object.keys(domainInfo).length) { refData = Object.assign({}, refData, domainInfo); } // Read URI params and use set utm params var params = paramsParse(currentUrl); var paramKeys = Object.keys(params); if (!paramKeys.length) { return refData; } // set campaign params off GA matches var gaParams = paramKeys.reduce(function (acc, key) { // match utm params & dclid (display) & gclid (cpc) if (key.match(/^utm_/)) { acc["".concat(key.replace(/^utm_/, ''))] = params[key]; } // https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters // dclid - cpc Cost-Per-Thousand Impressions // gclid - cpc Cost per Click if (key.match(/^(d|g)clid/)) { acc['source'] = googleKey; acc['medium'] = params.gclid ? 'cpc' : 'cpm'; acc[key] = params[key]; } return acc; }, {}); return Object.assign({}, refData, gaParams); } /** * @typedef {{ * source: string, * medium: string, * term?: string * }} DomainObject */ /** * Client side domain parser for determining marketing data. * @param {String} referrer - ref url * @return {DomainObject | boolean} */ function parseDomain(referrer) { if (!referrer || !inBrowser) return false; var referringDomain = getDomainBase(referrer); var a = document.createElement('a'); a.href = referrer; // Shim for the billion google search engines if (a.hostname.indexOf(googleKey) > -1) { referringDomain = googleKey; } // If is search engine if (searchEngines[referringDomain]) { var searchEngine = searchEngines[referringDomain]; var queryParam = typeof searchEngine === 'string' ? searchEngine : searchEngine.p; var termRegex = new RegExp(queryParam + '=.*?([^&#]*|$)', 'gi'); var term = a.search.match(termRegex); return { source: searchEngine.n || trimTld(referringDomain), medium: 'direct', term: (term ? term[0].split('=')[1] : '') || '(not provided)' }; } // Default var medium = !isExternalReferrer(referrer) ? 'direct' : 'referral'; return { source: a.hostname, medium: medium }; } /** * Search engine query string data * @type {Object} */ var Q = 'q'; var QUERY = 'query'; var searchEngines = { 'daum.net': Q, 'eniro.se': 'search_word', 'naver.com': QUERY, 'yahoo.com': 'p', 'msn.com': Q, 'aol.com': Q, 'ask.com': Q, 'baidu.com': 'wd', 'yandex.com': 'text', 'rambler.ru': 'words', 'google': Q, 'bing.com': { 'p': Q, 'n': 'live' } }; /** * @return {string} */ function uuid() { var u = '', m = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx', i = 0, rb = Math.random() * 0xffffffff | 0; while (i++ < 36) { var c = m[i - 1], r = rb & 0xf, v = c == 'x' ? r : r & 0x3 | 0x8; u += c == '-' || c == '4' ? c : v.toString(16); rb = i % 8 == 0 ? Math.random() * 0xffffffff | 0 : rb >> 4; } return u; } function throttle(func, wait) { var context, args, result; var timeout = null; var previous = 0; var later = function later() { previous = new Date(); timeout = null; result = func.apply(context, args); }; return function () { var now = new Date(); if (!previous) { previous = now; } var remaining = wait - (now - previous); context = this; args = arguments; if (remaining <= 0) { clearTimeout(timeout); timeout = null; previous = now; result = func.apply(context, args); } else if (!timeout) { timeout = setTimeout(later, remaining); } return result; }; } export { decode as decodeUri, getBrowserLocale, getTimeZone, inBrowser, isArray, isBoolean, isExternalReferrer, isFunction, isObject, isScriptLoaded, isString, isUndefined, noOp, paramsClean, getValueParamValue as paramsGet, paramsParse, paramsRemove, parseReferrer, throttle, url, uuid };