begrowth-analytics-utils
Version:
Analytics utility functions used by 'analytics' module
589 lines (489 loc) • 14.7 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var dlv = _interopDefault(require('dlv'));
var begrowthAnalyticsStorageUtils = require('begrowth-analytics-storage-utils');
var begrowthAnalyticsStorageUtils__default = _interopDefault(begrowthAnalyticsStorageUtils);
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;
};
}
exports.dotProp = dlv;
Object.defineProperty(exports, 'getCookie', {
enumerable: true,
get: function () {
return begrowthAnalyticsStorageUtils.getCookie;
}
});
Object.defineProperty(exports, 'globalContext', {
enumerable: true,
get: function () {
return begrowthAnalyticsStorageUtils.globalContext;
}
});
Object.defineProperty(exports, 'removeCookie', {
enumerable: true,
get: function () {
return begrowthAnalyticsStorageUtils.removeCookie;
}
});
Object.defineProperty(exports, 'setCookie', {
enumerable: true,
get: function () {
return begrowthAnalyticsStorageUtils.setCookie;
}
});
exports.storage = begrowthAnalyticsStorageUtils__default;
exports.decodeUri = decode;
exports.getBrowserLocale = getBrowserLocale;
exports.getTimeZone = getTimeZone;
exports.inBrowser = inBrowser;
exports.isArray = isArray;
exports.isBoolean = isBoolean;
exports.isExternalReferrer = isExternalReferrer;
exports.isFunction = isFunction;
exports.isObject = isObject;
exports.isScriptLoaded = isScriptLoaded;
exports.isString = isString;
exports.isUndefined = isUndefined;
exports.noOp = noOp;
exports.paramsClean = paramsClean;
exports.paramsGet = getValueParamValue;
exports.paramsParse = paramsParse;
exports.paramsRemove = paramsRemove;
exports.parseReferrer = parseReferrer;
exports.throttle = throttle;
exports.url = url;
exports.uuid = uuid;