);
}
+
+export async function getServerSideProps() {
+ return {
+ props: { enabled: !!process.env.ENABLE_TEST_CONSOLE },
+ };
+}
diff --git a/tracker/index.js b/tracker/index.js
index f0584288..17ee467d 100644
--- a/tracker/index.js
+++ b/tracker/index.js
@@ -5,23 +5,25 @@ import { removeTrailingSlash } from '../lib/url';
const {
screen: { width, height },
navigator: { language },
- location: { hostname, pathname, search },
+ location,
localStorage,
document,
history,
} = window;
+ const { hostname, pathname, search } = location;
+ const { currentScript } = document;
- const script = document.querySelector('script[data-website-id]');
+ if (!currentScript) return;
- if (!script) return;
-
- const attr = script.getAttribute.bind(script);
- const website = attr('data-website-id');
- const hostUrl = attr('data-host-url');
- const autoTrack = attr('data-auto-track') !== 'false';
- const dnt = attr('data-do-not-track');
- const cssEvents = attr('data-css-events') !== 'false';
- const domain = attr('data-domains') || '';
+ const _data = 'data-';
+ const _false = 'false';
+ const attr = currentScript.getAttribute.bind(currentScript);
+ const website = attr(_data + 'website-id');
+ const hostUrl = attr(_data + 'host-url');
+ const autoTrack = attr(_data + 'auto-track') !== _false;
+ const dnt = attr(_data + 'do-not-track');
+ const cssEvents = attr(_data + 'css-events') !== _false;
+ const domain = attr(_data + 'domains') || '';
const domains = domain.split(',').map(n => n.trim());
const eventClass = /^umami--([a-z]+)--([\w]+[\w-]*)$/;
@@ -34,7 +36,8 @@ import { removeTrailingSlash } from '../lib/url';
const root = hostUrl
? removeTrailingSlash(hostUrl)
- : script.src.split('/').slice(0, -1).join('/');
+ : currentScript.src.split('/').slice(0, -1).join('/');
+ const endpoint = `${root}/api/collect`;
const screen = `${width}x${height}`;
const listeners = {};
let currentUrl = `${pathname}${search}`;
@@ -43,21 +46,6 @@ import { removeTrailingSlash } from '../lib/url';
/* Collect metrics */
- const post = (url, data, callback) => {
- const req = new XMLHttpRequest();
- req.open('POST', url, true);
- req.setRequestHeader('Content-Type', 'application/json');
- if (cache) req.setRequestHeader('x-umami-cache', cache);
-
- req.onreadystatechange = () => {
- if (req.readyState === 4) {
- callback(req.response);
- }
- };
-
- req.send(JSON.stringify(data));
- };
-
const getPayload = () => ({
website,
hostname,
@@ -68,7 +56,7 @@ import { removeTrailingSlash } from '../lib/url';
const assign = (a, b) => {
Object.keys(b).forEach(key => {
- a[key] = b[key];
+ if (b[key] !== undefined) a[key] = b[key];
});
return a;
};
@@ -76,17 +64,16 @@ import { removeTrailingSlash } from '../lib/url';
const collect = (type, payload) => {
if (trackingDisabled()) return;
- post(
- `${root}/api/collect`,
- {
- type,
- payload,
- },
- res => (cache = res),
- );
+ return fetch(endpoint, {
+ method: 'POST',
+ body: JSON.stringify({ type, payload }),
+ headers: assign({ 'Content-Type': 'application/json' }, { ['x-umami-cache']: cache }),
+ })
+ .then(res => res.text())
+ .then(text => (cache = text));
};
- const trackView = (url = currentUrl, referrer = currentRef, uuid = website) => {
+ const trackView = (url = currentUrl, referrer = currentRef, uuid = website) =>
collect(
'pageview',
assign(getPayload(), {
@@ -95,9 +82,8 @@ import { removeTrailingSlash } from '../lib/url';
referrer,
}),
);
- };
- const trackEvent = (event_name = 'custom', event_data, url = currentUrl, uuid = website) => {
+ const trackEvent = (event_name, event_data, url = currentUrl, uuid = website) =>
collect(
'event',
assign(getPayload(), {
@@ -107,49 +93,45 @@ import { removeTrailingSlash } from '../lib/url';
event_data,
}),
);
- };
/* Handle events */
- const sendEvent = name => {
- const payload = getPayload();
-
- payload.event_name = name;
-
- const data = JSON.stringify({
- type: 'event',
- payload,
- });
-
- fetch(`${root}/api/collect`, {
- method: 'POST',
- body: data,
- keepalive: true,
- });
- };
-
const addEvents = node => {
const elements = node.querySelectorAll(eventSelect);
Array.prototype.forEach.call(elements, addEvent);
};
const addEvent = element => {
- (element.getAttribute('class') || '').split(' ').forEach(className => {
+ const get = element.getAttribute.bind(element);
+ (get('class') || '').split(' ').forEach(className => {
if (!eventClass.test(className)) return;
- const [, type, name] = className.split('--');
+ const [, event, name] = className.split('--');
const listener = listeners[className]
? listeners[className]
- : (listeners[className] = () => {
- if (element.tagName === 'A') {
- sendEvent(name);
+ : (listeners[className] = e => {
+ if (
+ event === 'click' &&
+ element.tagName === 'A' &&
+ !(
+ e.ctrlKey ||
+ e.shiftKey ||
+ e.metaKey ||
+ (e.button && e.button === 1) ||
+ get('target')
+ )
+ ) {
+ e.preventDefault();
+ trackEvent(name).then(() => {
+ location.href = get('href');
+ });
} else {
trackEvent(name);
}
});
- element.addEventListener(type, listener, true);
+ element.addEventListener(event, listener, true);
});
};