import type {JsonObject, Wnd} from './types'; import {doNotTrack, buildWarn, isBot} from './utils'; import {version} from '../package.json'; export {Wnd}; const run = () => { if (!window) return; const isDnt = doNotTrack(); const { // @ts-ignore screen: {width, height}, // @ts-ignore navigator: {language, userAgent}, location: {hostname, pathname, search, origin}, document, history, } = window; const script = document.querySelector('script[data-site]'); if (!script) return console.error('script.js not found'); // @ts-ignore const url = new URL(document.currentScript.src).origin; const attr = (key: string) => script && (script.getAttribute(key) || script.getAttribute(`data-${key}`)); const shortcode = attr('site'); // shortcode const dnt0ff = attr('dnt-off'); // shoud we send dnt=0? const spa = attr('spa'); // is it spa const warn = buildWarn(); const parsedHosthName = attr('hostname') || hostname; // @ts-ignore const canonical = attr('canonical'); // should we monitor canonical urls if (!shortcode) return warn('site not found'); if (isBot(userAgent)) return warn('bot detected'); if (dnt0ff && isDnt) return warn('dnt-off and dnt=1'); if ( 'visibilityState' in document && // @ts-ignore 'prerender' === document.visibilityState ) { return warn('Prerendering'); } const historyAttached = () => { const pushState = history.pushState; if (void 0 !== history) { history.pushState = function () { var output = pushState.apply(history, arguments as any); return ( window.dispatchEvent(new Event('pushstate')), window.dispatchEvent(new Event('prxm')), output ); }; window.addEventListener('popstate', function () { window.dispatchEvent(new Event('prxm')); }); window.addEventListener('prxm', monitor); } }; const hashAttached = () => { window.addEventListener('hashchange', monitor); }; const init = () => { warn('init'); if (spa) { switch (spa) { case 'history': historyAttached(); break; case 'hash': hashAttached(); break; default: void 0 !== history ? historyAttached() : hashAttached(); } } else { window.addEventListener('load', monitor); } }; const pxl = (p: string, e: JsonObject) => { const element = document.createElement('img') as HTMLImageElement; element.setAttribute('aria-hidden', 'true'); element.setAttribute('alt', ''); element.src = url + e.toString(); element.style.position = 'absolute'; // @ts-ignore element.src = url + p + '/pixel?' + new URLSearchParams(e).toString(); element.addEventListener('load', function () { element.parentNode && element.parentNode.removeChild(element); }); element.addEventListener('error', function () { element.parentNode && element.parentNode.removeChild(element); }); document.body.appendChild(element); }; // @ts-ignore const event = (e: JsonObject) => {}; const send = (p: string, data: JsonObject) => { const xhr = new XMLHttpRequest(); xhr.open('POST', url + p, true); xhr.setRequestHeader('Content-Type', 'text/plain'); xhr.addEventListener('error', function () { pxl(p, data); }); xhr.send(JSON.stringify(data)); }; const monitor = () => { const data = { p: origin + pathname + search, v: version, s: shortcode, h: parsedHosthName, r: document.referrer, cid: Date.now().toString(32), // @ts-ignore l: navigator.userLanguage || navigator.language || '', // performance metrics }; send('/hit/torch', data); }; // @ts-ignore const monitorEvent = () => {}; if (!(window as Wnd).proxima) { const proxima = { monitor: monitor, event: monitor, }; (window as Wnd).proxima = proxima; init(); } }; run();