@guardian/ophan-tracker-js 2.1.1 → 2.1.2-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NPM-dist/adblock-detection.js +20 -0
- package/NPM-dist/attention.js +126 -0
- package/NPM-dist/campaign.js +23 -0
- package/NPM-dist/click-path-capture.js +68 -0
- package/NPM-dist/components.js +168 -0
- package/{assets → NPM-dist}/contribution.js +4 -13
- package/NPM-dist/core.js +230 -0
- package/{assets → NPM-dist}/embed.js +3 -6
- package/{assets → NPM-dist}/fb-instant.js +2 -5
- package/NPM-dist/heatmap.js +34 -0
- package/{assets → NPM-dist}/holidays.js +3 -6
- package/{assets → NPM-dist}/http-status.js +4 -6
- package/NPM-dist/iframe-tracking.js +80 -0
- package/NPM-dist/interactive.js +17 -0
- package/{assets → NPM-dist}/jobs-courses.js +3 -6
- package/{assets → NPM-dist}/jobs.js +3 -6
- package/NPM-dist/manage-my-account.js +29 -0
- package/{assets → NPM-dist}/membership.js +4 -13
- package/NPM-dist/ng.js +46 -0
- package/NPM-dist/perf.js +36 -0
- package/NPM-dist/privatebrowsing.js +66 -0
- package/{assets → NPM-dist}/r2.js +3 -12
- package/{assets → NPM-dist}/smart-news.js +4 -10
- package/NPM-dist/support.js +28 -0
- package/NPM-dist/tests/click-path-capture.test.js +44 -0
- package/NPM-dist/tests/components.test.js +47 -0
- package/NPM-dist/tests/core.test.js +161 -0
- package/NPM-dist/tests/heatmap.test.js +45 -0
- package/NPM-dist/tests/transmit.test.js +118 -0
- package/NPM-dist/transmit.js +126 -0
- package/NPM-dist/types/abtest.js +1 -0
- package/NPM-dist/types/acquisition.js +1 -0
- package/NPM-dist/types/adblock-detection.d.ts +4 -0
- package/NPM-dist/types/attention.d.ts +9 -0
- package/NPM-dist/types/campaign.d.ts +1 -0
- package/NPM-dist/types/click-path-capture.d.ts +14 -0
- package/NPM-dist/types/component-event.js +1 -0
- package/NPM-dist/types/component-type.js +1 -0
- package/NPM-dist/types/components.d.ts +60 -0
- package/NPM-dist/types/consent.js +1 -0
- package/NPM-dist/types/contribution.d.ts +5 -0
- package/NPM-dist/types/core.d.ts +64 -0
- package/NPM-dist/types/embed.d.ts +5 -0
- package/NPM-dist/types/event.js +1 -0
- package/NPM-dist/types/fb-instant.d.ts +4 -0
- package/NPM-dist/types/heatmap.d.ts +5 -0
- package/NPM-dist/types/holidays.d.ts +5 -0
- package/NPM-dist/types/http-status.d.ts +5 -0
- package/NPM-dist/types/iframe-tracking.d.ts +1 -0
- package/NPM-dist/types/inpageclick.js +1 -0
- package/NPM-dist/types/interaction.js +1 -0
- package/NPM-dist/types/interactive.d.ts +1 -0
- package/NPM-dist/types/jobs-courses.d.ts +5 -0
- package/NPM-dist/types/jobs.d.ts +5 -0
- package/NPM-dist/types/link.js +1 -0
- package/NPM-dist/types/manage-my-account.d.ts +7 -0
- package/NPM-dist/types/media.js +1 -0
- package/NPM-dist/types/membership.d.ts +5 -0
- package/NPM-dist/types/ng.d.ts +26 -0
- package/NPM-dist/types/perf.d.ts +2 -0
- package/NPM-dist/types/platform.js +1 -0
- package/NPM-dist/types/printproduct.js +1 -0
- package/NPM-dist/types/privatebrowsing.d.ts +6 -0
- package/NPM-dist/types/product.js +1 -0
- package/NPM-dist/types/r2.d.ts +4 -0
- package/NPM-dist/types/smart-news.d.ts +5 -0
- package/NPM-dist/types/subscription.js +1 -0
- package/NPM-dist/types/support.d.ts +9 -0
- package/NPM-dist/types/tests/click-path-capture.test.d.ts +1 -0
- package/NPM-dist/types/tests/components.test.d.ts +1 -0
- package/NPM-dist/types/tests/core.test.d.ts +1 -0
- package/NPM-dist/types/tests/heatmap.test.d.ts +1 -0
- package/NPM-dist/types/tests/transmit.test.d.ts +1 -0
- package/NPM-dist/types/transmit.d.ts +17 -0
- package/NPM-dist/types/types/abtest.d.ts +28 -0
- package/NPM-dist/types/types/acquisition.d.ts +116 -0
- package/NPM-dist/types/types/component-event.d.ts +86 -0
- package/NPM-dist/types/types/component-type.d.ts +1 -0
- package/NPM-dist/types/types/consent.d.ts +40 -0
- package/NPM-dist/types/types/event.d.ts +106 -0
- package/NPM-dist/types/types/inpageclick.d.ts +11 -0
- package/NPM-dist/types/types/interaction.d.ts +17 -0
- package/NPM-dist/types/types/link.d.ts +14 -0
- package/NPM-dist/types/types/media.d.ts +98 -0
- package/NPM-dist/types/types/platform.d.ts +10 -0
- package/NPM-dist/types/types/printproduct.d.ts +27 -0
- package/NPM-dist/types/types/product.d.ts +53 -0
- package/NPM-dist/types/types/subscription.d.ts +60 -0
- package/NPM-dist/types/types/utmparameters.d.ts +26 -0
- package/NPM-dist/types/utmparameters.js +1 -0
- package/NPM-dist/types/vendor/adBlockDetectionLib.d.ts +4 -0
- package/NPM-dist/types/visibility.d.ts +5 -0
- package/NPM-dist/types/witness.d.ts +5 -0
- package/NPM-dist/vendor/adBlockDetectionLib.js +312 -0
- package/NPM-dist/visibility.js +22 -0
- package/{assets → NPM-dist}/witness.js +3 -6
- package/package.json +18 -8
- package/readme.md +98 -11
- package/assets/adblock-detection.js +0 -19
- package/assets/attention.js +0 -160
- package/assets/campaign.js +0 -25
- package/assets/click-path-capture.js +0 -80
- package/assets/components.js +0 -199
- package/assets/core.js +0 -282
- package/assets/heatmap.js +0 -53
- package/assets/iframe-tracking.js +0 -88
- package/assets/interactive.js +0 -17
- package/assets/manage-my-account.js +0 -38
- package/assets/ng.js +0 -41
- package/assets/perf.js +0 -40
- package/assets/privatebrowsing.js +0 -71
- package/assets/support.js +0 -34
- package/assets/transmit.js +0 -143
- package/assets/vendor/adBlockDetectionLib.js +0 -366
- package/assets/visibility.js +0 -23
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
// Generated by CoffeeScript 2.7.0
|
|
2
2
|
import core from './core.js';
|
|
3
|
-
|
|
4
|
-
import transmit from './transmit.js';
|
|
5
|
-
|
|
3
|
+
import transmit from './transmit';
|
|
6
4
|
core.init('facebook-instant-article');
|
|
7
|
-
|
|
8
5
|
export default {
|
|
9
|
-
|
|
6
|
+
viewId: transmit.viewId,
|
|
10
7
|
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
let heatmapFired = false;
|
|
2
|
+
const init = () => {
|
|
3
|
+
const addHeatmap = () => {
|
|
4
|
+
let heatmapParam;
|
|
5
|
+
if (typeof localStorage !== 'undefined' &&
|
|
6
|
+
localStorage !== null &&
|
|
7
|
+
!heatmapFired) {
|
|
8
|
+
heatmapFired = true;
|
|
9
|
+
heatmapParam = window.location.search.replace(/^(?:.*[&\?]heatmap(?:\=([^&]*))?)?.*$/, '$1');
|
|
10
|
+
if (heatmapParam === 'experimental') {
|
|
11
|
+
return (document.body.appendChild(document.createElement('script')).src = '//dashboard.ophan.co.uk/assets/js/react/heatphan/index.js');
|
|
12
|
+
}
|
|
13
|
+
if (heatmapParam === 'true' || heatmapParam === 'false') {
|
|
14
|
+
localStorage['ophan_heatmap'] = heatmapParam;
|
|
15
|
+
}
|
|
16
|
+
if (localStorage['ophan_heatmap'] === 'true' || heatmapParam === 'show') {
|
|
17
|
+
return (document.body.appendChild(document.createElement('script')).src = '//dashboard.ophan.co.uk/assets/js/heatmap-bookmarklet.js');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
if (document.readyState === 'complete') {
|
|
22
|
+
return addHeatmap();
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
return typeof window.addEventListener === 'function'
|
|
26
|
+
? window.addEventListener('load', function () {
|
|
27
|
+
return addHeatmap();
|
|
28
|
+
}, false)
|
|
29
|
+
: void 0;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
export default {
|
|
33
|
+
init,
|
|
34
|
+
};
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
// Generated by CoffeeScript 2.7.0
|
|
2
2
|
import core from './core.js';
|
|
3
|
-
|
|
4
|
-
import transmit from './transmit.js';
|
|
5
|
-
|
|
3
|
+
import transmit from './transmit';
|
|
6
4
|
core.init('holidays');
|
|
7
|
-
|
|
8
5
|
export default {
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
record: transmit.sendMore,
|
|
7
|
+
viewId: transmit.viewId,
|
|
11
8
|
};
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import core from './core.js';
|
|
2
|
-
import './transmit.
|
|
2
|
+
import './transmit.ts';
|
|
3
3
|
import './click-path-capture.js';
|
|
4
4
|
import './perf.js';
|
|
5
5
|
import './campaign.js';
|
|
6
|
-
|
|
7
6
|
const reportStatus = (platform, status) => {
|
|
8
|
-
|
|
7
|
+
return core.init(platform, status);
|
|
9
8
|
};
|
|
10
|
-
|
|
11
9
|
export default {
|
|
12
|
-
|
|
13
|
-
};
|
|
10
|
+
reportStatus,
|
|
11
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import clickCapture from './click-path-capture.js';
|
|
2
|
+
const validIframeDomains = [
|
|
3
|
+
'.theguardian.com',
|
|
4
|
+
'.dev-theguardian.com',
|
|
5
|
+
'.thegulocal.com', // NB - leading dot is essential here to avoid matching on non-Guardian-owned domains
|
|
6
|
+
];
|
|
7
|
+
/**
|
|
8
|
+
* Handles messages received from iframes, recording events as necessary.
|
|
9
|
+
* @param {MessageEvent} messageEvent - The message event received from an iframe.
|
|
10
|
+
*/
|
|
11
|
+
const handleIframeMessage = (messageEvent) => {
|
|
12
|
+
const originDomain = retrieveOriginDomain(messageEvent.origin);
|
|
13
|
+
if (originDomain &&
|
|
14
|
+
validIframeDomains.some((domain) => originDomain.endsWith(domain))) {
|
|
15
|
+
if (messageEvent.data.type === 'ophan-iframe-click-event') {
|
|
16
|
+
const eventObject = messageEvent.data.value;
|
|
17
|
+
const iFrame = document.getElementById(messageEvent.data.iframeId);
|
|
18
|
+
recordIframeClickEvent(iFrame, eventObject);
|
|
19
|
+
}
|
|
20
|
+
else if (messageEvent.data.type === 'ophan-iframe-component-event') {
|
|
21
|
+
const eventObject = messageEvent.data.value;
|
|
22
|
+
recordIframeComponentEvent(eventObject);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Retrieves the domain from an event's origin URL.
|
|
28
|
+
* @param {string} eventOrigin - The origin URL of the event.
|
|
29
|
+
* @returns {(string|null)} The domain of the origin URL or null if it cannot be parsed.
|
|
30
|
+
*/
|
|
31
|
+
const retrieveOriginDomain = (eventOrigin) => {
|
|
32
|
+
try {
|
|
33
|
+
const originURL = new URL(eventOrigin);
|
|
34
|
+
return originURL.host;
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
if (error instanceof TypeError) {
|
|
38
|
+
// We failed to parse origin as an URL, we should ignore the event
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Records a click event occurring within an iframe.
|
|
48
|
+
* @param {HTMLElement} iFrame - The iframe element where the click event occurred.
|
|
49
|
+
* @param {Object} clickEvent - The click event object to record.
|
|
50
|
+
*/
|
|
51
|
+
const recordIframeClickEvent = (iFrame, clickEvent) => {
|
|
52
|
+
if (iFrame) {
|
|
53
|
+
clickEvent.clickLinkNames =
|
|
54
|
+
clickCapture.getDataLinkNames(iFrame, clickEvent.clickLinkNames) ||
|
|
55
|
+
clickEvent.clickLinkNames;
|
|
56
|
+
}
|
|
57
|
+
window.guardian.ophan.record(clickEvent);
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Validates if an event object is a valid component event.
|
|
61
|
+
* @param {Object} eventObject - The event object to validate.
|
|
62
|
+
* @returns {boolean} True if the event object is valid, false otherwise.
|
|
63
|
+
*/
|
|
64
|
+
const componentEventIsValid = (eventObject) => {
|
|
65
|
+
return (eventObject &&
|
|
66
|
+
typeof eventObject === 'object' &&
|
|
67
|
+
eventObject.componentEvent &&
|
|
68
|
+
typeof eventObject.componentEvent === 'object');
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Records a component event from an iframe.
|
|
72
|
+
* @param {Object} eventObject - The component event object to record.
|
|
73
|
+
*/
|
|
74
|
+
const recordIframeComponentEvent = (eventObject) => {
|
|
75
|
+
if (!componentEventIsValid(eventObject)) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
window.guardian.ophan.record(eventObject);
|
|
79
|
+
};
|
|
80
|
+
window.addEventListener('message', handleIframeMessage, false);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import core from './core.js';
|
|
2
|
+
import transmit from './transmit';
|
|
3
|
+
import attention from './attention.js';
|
|
4
|
+
import './click-path-capture.js';
|
|
5
|
+
if (window.guardian?.ophan) {
|
|
6
|
+
guardian.ophan;
|
|
7
|
+
}
|
|
8
|
+
else {
|
|
9
|
+
core.init('embed');
|
|
10
|
+
window.guardian = guardian || {};
|
|
11
|
+
guardian.ophan = {
|
|
12
|
+
setEventEmitter: attention.setEventEmitter,
|
|
13
|
+
trackComponentAttention: attention.initComponent,
|
|
14
|
+
record: transmit.sendMore,
|
|
15
|
+
viewId: transmit.viewId,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
// Generated by CoffeeScript 2.7.0
|
|
2
2
|
import core from './core.js';
|
|
3
|
-
|
|
4
|
-
import transmit from './transmit.js';
|
|
5
|
-
|
|
3
|
+
import transmit from './transmit';
|
|
6
4
|
core.init('jobs-courses');
|
|
7
|
-
|
|
8
5
|
export default {
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
record: transmit.sendMore,
|
|
7
|
+
viewId: transmit.viewId,
|
|
11
8
|
};
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
// Generated by CoffeeScript 2.7.0
|
|
2
2
|
import core from './core.js';
|
|
3
|
-
|
|
4
|
-
import transmit from './transmit.js';
|
|
5
|
-
|
|
3
|
+
import transmit from './transmit';
|
|
6
4
|
core.init('jobs');
|
|
7
|
-
|
|
8
5
|
export default {
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
record: transmit.sendMore,
|
|
7
|
+
viewId: transmit.viewId,
|
|
11
8
|
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Generated by CoffeeScript 2.7.0
|
|
2
|
+
import core from './core.js';
|
|
3
|
+
import transmit from './transmit';
|
|
4
|
+
import attention from './attention.js';
|
|
5
|
+
import visibility from './visibility.js';
|
|
6
|
+
import './click-path-capture.js';
|
|
7
|
+
import './perf.js';
|
|
8
|
+
import './campaign.js';
|
|
9
|
+
core.init('manage-my-account');
|
|
10
|
+
if (window.addEventListener) {
|
|
11
|
+
attention.init(visibility);
|
|
12
|
+
}
|
|
13
|
+
const sendInitialEvent = (url = location.href, referrer = document.referrer) => {
|
|
14
|
+
try {
|
|
15
|
+
transmit.bumpViewId();
|
|
16
|
+
core.sendInitialEvent(null, url, referrer);
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
console.log(error);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const exports = {
|
|
23
|
+
sendInitialEvent,
|
|
24
|
+
record: transmit.sendMore,
|
|
25
|
+
viewId: transmit.viewId,
|
|
26
|
+
};
|
|
27
|
+
window.guardian = window.guardian || {};
|
|
28
|
+
window.guardian.ophan = exports;
|
|
29
|
+
export default exports;
|
|
@@ -1,25 +1,16 @@
|
|
|
1
1
|
// Generated by CoffeeScript 2.7.0
|
|
2
2
|
import core from './core.js';
|
|
3
|
-
|
|
4
|
-
import transmit from './transmit.js';
|
|
5
|
-
|
|
3
|
+
import transmit from './transmit';
|
|
6
4
|
import attention from './attention.js';
|
|
7
|
-
|
|
8
5
|
import visibility from './visibility.js';
|
|
9
|
-
|
|
10
6
|
import './click-path-capture.js';
|
|
11
|
-
|
|
12
7
|
import './perf.js';
|
|
13
|
-
|
|
14
8
|
import './campaign.js';
|
|
15
|
-
|
|
16
9
|
core.init('membership');
|
|
17
|
-
|
|
18
10
|
if (window.addEventListener != null) {
|
|
19
|
-
|
|
11
|
+
attention.init(visibility);
|
|
20
12
|
}
|
|
21
|
-
|
|
22
13
|
export default {
|
|
23
|
-
|
|
24
|
-
|
|
14
|
+
record: transmit.sendMore,
|
|
15
|
+
viewId: transmit.viewId,
|
|
25
16
|
};
|
package/NPM-dist/ng.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import core from './core';
|
|
2
|
+
import transmit from './transmit';
|
|
3
|
+
import attention from './attention';
|
|
4
|
+
import visibility from './visibility';
|
|
5
|
+
import privatebrowsing from './privatebrowsing';
|
|
6
|
+
import heatmap from './heatmap';
|
|
7
|
+
import './click-path-capture';
|
|
8
|
+
import './perf';
|
|
9
|
+
import './iframe-tracking';
|
|
10
|
+
export * from './types/abtest';
|
|
11
|
+
export * from './types/acquisition';
|
|
12
|
+
export * from './types/subscription';
|
|
13
|
+
export * from './types/interaction';
|
|
14
|
+
export * from './types/inpageclick';
|
|
15
|
+
export * from './types/printproduct';
|
|
16
|
+
export * from './types/product';
|
|
17
|
+
export * from './types/platform';
|
|
18
|
+
export * from './types/media';
|
|
19
|
+
export * from './types/consent';
|
|
20
|
+
export * from './types/component-type';
|
|
21
|
+
export * from './types/component-event';
|
|
22
|
+
export * from './types/event';
|
|
23
|
+
let ng;
|
|
24
|
+
if (window.guardian && window.guardian.ophan) {
|
|
25
|
+
ng = window.guardian.ophan;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
core.init('next-gen');
|
|
29
|
+
privatebrowsing.init();
|
|
30
|
+
heatmap.init();
|
|
31
|
+
if (window.addEventListener) {
|
|
32
|
+
attention.init(visibility);
|
|
33
|
+
}
|
|
34
|
+
if (!window.guardian) {
|
|
35
|
+
window.guardian = {};
|
|
36
|
+
}
|
|
37
|
+
window.guardian.ophan = {
|
|
38
|
+
setEventEmitter: attention.setEventEmitter,
|
|
39
|
+
trackComponentAttention: attention.initComponent,
|
|
40
|
+
record: transmit.sendMore,
|
|
41
|
+
viewId: transmit.viewId,
|
|
42
|
+
pageViewId: transmit.viewId
|
|
43
|
+
};
|
|
44
|
+
ng = window.guardian.ophan;
|
|
45
|
+
}
|
|
46
|
+
export default ng;
|
package/NPM-dist/perf.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Generated by CoffeeScript 2.7.0
|
|
2
|
+
import core from './core.js';
|
|
3
|
+
const perf = window.performance ||
|
|
4
|
+
window.msPerformance ||
|
|
5
|
+
window.webkitPerformance ||
|
|
6
|
+
window.mozPerformance;
|
|
7
|
+
const sendTimingData = () => {
|
|
8
|
+
const t = perf?.timing;
|
|
9
|
+
if (t) {
|
|
10
|
+
return {
|
|
11
|
+
performance: {
|
|
12
|
+
// Time required for domain lookup.
|
|
13
|
+
dns: t.domainLookupEnd - t.domainLookupStart,
|
|
14
|
+
// Time to establish a connection to server.
|
|
15
|
+
connection: t.connectEnd - t.connectStart,
|
|
16
|
+
// From connection established to first byte of data.
|
|
17
|
+
firstByte: t.responseStart - t.connectEnd,
|
|
18
|
+
// First byte to last byte, or closed, including if from cache.
|
|
19
|
+
lastByte: t.responseEnd - t.responseStart,
|
|
20
|
+
// From last byte of doc to start of domContentLoaded
|
|
21
|
+
domContentLoadedEvent: t.domContentLoadedEventStart - t.responseEnd,
|
|
22
|
+
// domcontentLoaded to start of load event.
|
|
23
|
+
loadEvent: t.loadEventStart - t.domContentLoadedEventStart,
|
|
24
|
+
// click, back/forward, etc...
|
|
25
|
+
navType: perf.navigation.type,
|
|
26
|
+
// No. of redirects on current domain.
|
|
27
|
+
redirectCount: perf.navigation.redirectCount,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
return {};
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
core.onLoadCapture(sendTimingData);
|
|
36
|
+
export default perf;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import transmit from './transmit';
|
|
2
|
+
/*
|
|
3
|
+
TO-DO:
|
|
4
|
+
This function could probably be simplified with an async function.
|
|
5
|
+
It basically returns a `boolean`, but uses a callback to do so... I can only guess it’s because of [`requestFileSystem`’s signature](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestFileSystem).
|
|
6
|
+
*/
|
|
7
|
+
const privateBrowsingMode = (callback) => {
|
|
8
|
+
const reportNormalMode = () => callback(false);
|
|
9
|
+
const reportPrivateMode = () => callback(true);
|
|
10
|
+
const tryLocalStorage = () => {
|
|
11
|
+
try {
|
|
12
|
+
if (localStorage.length) {
|
|
13
|
+
reportNormalMode();
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
localStorage.x = 1;
|
|
17
|
+
localStorage.removeItem('x');
|
|
18
|
+
reportNormalMode();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
reportPrivateMode();
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
const tryIndexedDB = () => {
|
|
26
|
+
try {
|
|
27
|
+
const db = indexedDB.open('test');
|
|
28
|
+
db.onsuccess = reportNormalMode;
|
|
29
|
+
db.onerror = reportPrivateMode;
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
reportPrivateMode();
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
// Blink
|
|
36
|
+
if (window.webkitRequestFileSystem) {
|
|
37
|
+
window.webkitRequestFileSystem(window.TEMPORARY, 1, reportNormalMode, reportPrivateMode);
|
|
38
|
+
// Firefox
|
|
39
|
+
}
|
|
40
|
+
else if ('MozAppearance' in document.documentElement.style) {
|
|
41
|
+
tryIndexedDB();
|
|
42
|
+
// Safari
|
|
43
|
+
}
|
|
44
|
+
else if (/constructor/i.test(window.HTMLElement)) {
|
|
45
|
+
tryLocalStorage();
|
|
46
|
+
}
|
|
47
|
+
else if (!window.indexedDB &&
|
|
48
|
+
(window.PointerEvent || window.MSPointerEvent)) {
|
|
49
|
+
reportPrivateMode();
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
// Rest
|
|
53
|
+
reportNormalMode();
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
export default {
|
|
57
|
+
init() {
|
|
58
|
+
privateBrowsingMode((value) => {
|
|
59
|
+
const report = {
|
|
60
|
+
inPrivateBrowsingMode: value,
|
|
61
|
+
};
|
|
62
|
+
transmit.sendMore(report);
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
privateBrowsingMode,
|
|
66
|
+
};
|
|
@@ -1,24 +1,15 @@
|
|
|
1
1
|
// Generated by CoffeeScript 2.7.0
|
|
2
2
|
import core from './core.js';
|
|
3
|
-
|
|
4
|
-
import transmit from './transmit.js';
|
|
5
|
-
|
|
3
|
+
import transmit from './transmit';
|
|
6
4
|
import attention from './attention.js';
|
|
7
|
-
|
|
8
5
|
import visibility from './visibility.js';
|
|
9
|
-
|
|
10
6
|
import './click-path-capture.js';
|
|
11
|
-
|
|
12
7
|
import './perf.js';
|
|
13
|
-
|
|
14
8
|
import './campaign.js';
|
|
15
|
-
|
|
16
9
|
core.init('r2');
|
|
17
|
-
|
|
18
10
|
if (window.addEventListener != null) {
|
|
19
|
-
|
|
11
|
+
attention.init(visibility);
|
|
20
12
|
}
|
|
21
|
-
|
|
22
13
|
export default {
|
|
23
|
-
|
|
14
|
+
viewId: transmit.viewId,
|
|
24
15
|
};
|
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
// Generated by CoffeeScript 2.7.0
|
|
2
2
|
import core from './core.js';
|
|
3
|
-
|
|
4
|
-
import transmit from './transmit.js';
|
|
5
|
-
|
|
3
|
+
import transmit from './transmit';
|
|
6
4
|
import attention from './attention.js';
|
|
7
|
-
|
|
8
5
|
import visibility from './visibility.js';
|
|
9
|
-
|
|
10
6
|
core.init('smart-news');
|
|
11
|
-
|
|
12
7
|
if (window.addEventListener != null) {
|
|
13
|
-
|
|
8
|
+
attention.init(visibility);
|
|
14
9
|
}
|
|
15
|
-
|
|
16
10
|
export default {
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
record: transmit.sendMore,
|
|
12
|
+
viewId: transmit.viewId,
|
|
19
13
|
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import core from './core.js';
|
|
2
|
+
import transmit from './transmit';
|
|
3
|
+
import attention from './attention.js';
|
|
4
|
+
import visibility from './visibility.js';
|
|
5
|
+
import './click-path-capture.js';
|
|
6
|
+
import './perf.js';
|
|
7
|
+
import './campaign.js';
|
|
8
|
+
const init = () => {
|
|
9
|
+
core.init('support');
|
|
10
|
+
if (window.addEventListener) {
|
|
11
|
+
attention.init(visibility);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const sendInitialEvent = (url = location.href, referrer = document.referrer) => {
|
|
15
|
+
try {
|
|
16
|
+
transmit.bumpViewId();
|
|
17
|
+
core.sendInitialEvent(null, url, referrer);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
console.log(error);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
export default {
|
|
24
|
+
init,
|
|
25
|
+
sendInitialEvent,
|
|
26
|
+
record: transmit.sendMore,
|
|
27
|
+
viewId: transmit.viewId,
|
|
28
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import clickPathCapture, { validAncestorAnchorElement, getContainingComponent } from '../click-path-capture.js';
|
|
2
|
+
const { getDataLinkNames } = clickPathCapture;
|
|
3
|
+
describe('click-path-capture.js', () => {
|
|
4
|
+
beforeAll(() => {
|
|
5
|
+
document.body.innerHTML = `
|
|
6
|
+
<div data-component="component1">
|
|
7
|
+
<a href="#" data-link-name="link1">
|
|
8
|
+
<span id="testElement1"></span>
|
|
9
|
+
</a>
|
|
10
|
+
</div>
|
|
11
|
+
<div id="testElement2" data-component="component2"></div>
|
|
12
|
+
`;
|
|
13
|
+
});
|
|
14
|
+
describe('validAncestorAnchorElement', () => {
|
|
15
|
+
test('should return the ancestor anchor element', () => {
|
|
16
|
+
const element = document.getElementById('testElement1');
|
|
17
|
+
expect(validAncestorAnchorElement(element)).toBe(element.closest('a'));
|
|
18
|
+
});
|
|
19
|
+
test('should return null when no anchor ancestor is present', () => {
|
|
20
|
+
const element = document.getElementById('testElement2');
|
|
21
|
+
expect(validAncestorAnchorElement(element)).toBeNull();
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
describe('getContainingComponent', () => {
|
|
25
|
+
test('should find the parent element with data-component attribute', () => {
|
|
26
|
+
const element = document.getElementById('testElement1');
|
|
27
|
+
expect(getContainingComponent(element)).toBe('component1');
|
|
28
|
+
});
|
|
29
|
+
test('should return null if no data-component parent is found', () => {
|
|
30
|
+
const element = document.createElement('div');
|
|
31
|
+
expect(getContainingComponent(element)).toBeNull();
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
describe('getDataLinkNames', () => {
|
|
35
|
+
test('should collect data-link-name attributes from ancestors', () => {
|
|
36
|
+
const element = document.getElementById('testElement1');
|
|
37
|
+
expect(getDataLinkNames(element)).toEqual(['link1']);
|
|
38
|
+
});
|
|
39
|
+
test('should return an empty array when no data-link-name attributes are present', () => {
|
|
40
|
+
const element = document.getElementById('testElement2');
|
|
41
|
+
expect(getDataLinkNames(element)).toEqual([]);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { default as testExports } from '../components.js';
|
|
2
|
+
import { components } from "../components.js";
|
|
3
|
+
const { startMonitoring, stopMonitoring, getAttentionTimes } = testExports;
|
|
4
|
+
describe('components.js', () => {
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
components.length = 0;
|
|
7
|
+
components.push({
|
|
8
|
+
name: 'comp1',
|
|
9
|
+
isVisible: jest.fn().mockReturnValue(true),
|
|
10
|
+
makeActive: jest.fn(),
|
|
11
|
+
makeInactive: jest.fn(),
|
|
12
|
+
hadAttentionSinceLastGet: jest.fn().mockReturnValue(true),
|
|
13
|
+
getAttentionTime: jest.fn().mockReturnValue(123),
|
|
14
|
+
});
|
|
15
|
+
components.push({
|
|
16
|
+
name: 'comp2',
|
|
17
|
+
isVisible: jest.fn().mockReturnValue(true),
|
|
18
|
+
makeActive: jest.fn(),
|
|
19
|
+
makeInactive: jest.fn(),
|
|
20
|
+
hadAttentionSinceLastGet: jest.fn().mockReturnValue(true),
|
|
21
|
+
getAttentionTime: jest.fn().mockReturnValue(123),
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
test('startMonitoring activates visible components', () => {
|
|
25
|
+
components[0].isVisible.mockReturnValue(true);
|
|
26
|
+
components[1].isVisible.mockReturnValue(false);
|
|
27
|
+
const results = startMonitoring();
|
|
28
|
+
expect(components[0].makeActive).toHaveBeenCalled();
|
|
29
|
+
expect(components[1].makeActive).not.toHaveBeenCalled();
|
|
30
|
+
expect(results).toHaveLength(1);
|
|
31
|
+
});
|
|
32
|
+
test('stopMonitoring deactivates all components', () => {
|
|
33
|
+
const results = stopMonitoring();
|
|
34
|
+
components.forEach((component) => {
|
|
35
|
+
expect(component.makeInactive).toHaveBeenCalled();
|
|
36
|
+
});
|
|
37
|
+
expect(results).toHaveLength(components.length);
|
|
38
|
+
});
|
|
39
|
+
test('getAttentionTimes returns attention times for components with attention', () => {
|
|
40
|
+
components[0].hadAttentionSinceLastGet.mockReturnValue(true);
|
|
41
|
+
components[0].getAttentionTime.mockReturnValue(123);
|
|
42
|
+
components[1].hadAttentionSinceLastGet.mockReturnValue(false);
|
|
43
|
+
const attentionTimes = getAttentionTimes();
|
|
44
|
+
expect(attentionTimes).toEqual({ comp1: 123 });
|
|
45
|
+
expect(components[1].getAttentionTime).not.toHaveBeenCalled();
|
|
46
|
+
});
|
|
47
|
+
});
|