@guardian/ophan-tracker-js 2.1.1 → 2.1.2-next.0

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.
@@ -1,71 +0,0 @@
1
- import transmit from './transmit.js';
2
-
3
- /*
4
- TO-DO:
5
- This function could probably be simplified with an async function.
6
- 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).
7
- */
8
- const privateBrowsingMode = (callback) => {
9
- const reportNormalMode = () => callback(false);
10
- const reportPrivateMode = () => callback(true);
11
-
12
- const tryLocalStorage = () => {
13
- try {
14
- if (localStorage.length) {
15
- reportNormalMode();
16
- } else {
17
- localStorage.x = 1;
18
- localStorage.removeItem('x');
19
- reportNormalMode();
20
- }
21
- } catch (error) {
22
- reportPrivateMode();
23
- }
24
- };
25
-
26
- const tryIndexedDB = () => {
27
- try {
28
- const db = indexedDB.open('test');
29
- db.onsuccess = reportNormalMode;
30
- db.onerror = reportPrivateMode;
31
- } catch (error) {
32
- reportPrivateMode();
33
- }
34
- };
35
-
36
- // Blink
37
- if (window.webkitRequestFileSystem) {
38
- window.webkitRequestFileSystem(
39
- window.TEMPORARY,
40
- 1,
41
- reportNormalMode,
42
- reportPrivateMode,
43
- );
44
- // Firefox
45
- } else if ('MozAppearance' in document.documentElement.style) {
46
- tryIndexedDB();
47
- // Safari
48
- } else if (/constructor/i.test(window.HTMLElement)) {
49
- tryLocalStorage();
50
- } else if (
51
- !window.indexedDB &&
52
- (window.PointerEvent || window.MSPointerEvent)
53
- ) {
54
- reportPrivateMode();
55
- } else {
56
- // Rest
57
- reportNormalMode();
58
- }
59
- };
60
-
61
- export default {
62
- init() {
63
- privateBrowsingMode((value) => {
64
- const report = {
65
- inPrivateBrowsingMode: value,
66
- };
67
- transmit.sendMore(report);
68
- });
69
- },
70
- privateBrowsingMode,
71
- };
package/assets/r2.js DELETED
@@ -1,24 +0,0 @@
1
- // Generated by CoffeeScript 2.7.0
2
- import core from './core.js';
3
-
4
- import transmit from './transmit.js';
5
-
6
- import attention from './attention.js';
7
-
8
- import visibility from './visibility.js';
9
-
10
- import './click-path-capture.js';
11
-
12
- import './perf.js';
13
-
14
- import './campaign.js';
15
-
16
- core.init('r2');
17
-
18
- if (window.addEventListener != null) {
19
- attention.init(visibility);
20
- }
21
-
22
- export default {
23
- viewId: transmit.viewId,
24
- };
@@ -1,19 +0,0 @@
1
- // Generated by CoffeeScript 2.7.0
2
- import core from './core.js';
3
-
4
- import transmit from './transmit.js';
5
-
6
- import attention from './attention.js';
7
-
8
- import visibility from './visibility.js';
9
-
10
- core.init('smart-news');
11
-
12
- if (window.addEventListener != null) {
13
- attention.init(visibility);
14
- }
15
-
16
- export default {
17
- record: transmit.sendMore,
18
- viewId: transmit.viewId,
19
- };
package/assets/support.js DELETED
@@ -1,34 +0,0 @@
1
- import core from './core.js';
2
- import transmit from './transmit.js';
3
- import attention from './attention.js';
4
- import visibility from './visibility.js';
5
-
6
- import './click-path-capture.js';
7
- import './perf.js';
8
- import './campaign.js';
9
-
10
- const init = () => {
11
- core.init('support');
12
- if (window.addEventListener) {
13
- attention.init(visibility);
14
- }
15
- };
16
-
17
- const sendInitialEvent = (
18
- url = location.href,
19
- referrer = document.referrer,
20
- ) => {
21
- try {
22
- transmit.bumpViewId();
23
- core.sendInitialEvent(null, url, referrer);
24
- } catch (error) {
25
- console.log(error);
26
- }
27
- };
28
-
29
- export default {
30
- init,
31
- sendInitialEvent,
32
- record: transmit.sendMore,
33
- viewId: transmit.viewId,
34
- };
@@ -1,143 +0,0 @@
1
- const ophanRemoteHost = window?.ophanRemoteHost || 'https://ophan.theguardian.com';
2
-
3
- /**
4
- * @returns {string}
5
- */
6
- const generatePageViewId = () => {
7
- return `${new Date().getTime().toString(36)}${'xxxxxxxxxxxx'.replace(
8
- /x/g,
9
- () => Math.floor(Math.random() * 36).toString(36),
10
- )}`;
11
- };
12
-
13
- // guardian.config.ophan.pageViewId is now pregenerated in
14
- // the Guardian Frontend Project (https://github.com/guardian/frontend)
15
- // frontend/common/app/templates/inlineJS/blocking/config.scala.js
16
- // If you're going to change the generation method, please update that one too
17
- let viewId;
18
- if (typeof guardian !== 'undefined') {
19
- viewId = guardian.config?.ophan?.pageViewId ?? generatePageViewId();
20
- } else {
21
- viewId = generatePageViewId();
22
- }
23
-
24
- const bumpViewId = () => {
25
- viewId = generatePageViewId();
26
- };
27
-
28
- /**
29
- * send the initial event associated with this page view
30
- * store the resulting page view id
31
- * this must only ever be called *once* subsequent calls will
32
- * be ignored
33
- * @param {Object} obj - The data to be sent.
34
- */
35
- const sendInitial = (obj) => {
36
- send(`${ophanRemoteHost}/img/1?${buildQueryString(obj)}`);
37
- };
38
-
39
- /**
40
- * Encodes a value for URL transmission.
41
- * @param {(string|number)} value - The value to encode.
42
- * @returns {string} The encoded value.
43
- */
44
- const smartEncode = (value) => {
45
- if (typeof value === 'string' || typeof value === 'number') {
46
- return encodeURIComponent(value);
47
- } else {
48
- return encodeURIComponent(JSON.stringify(value));
49
- }
50
- };
51
-
52
- /**
53
- * Used for sending additional events after the initial PageView event has been sent, such as attention events.
54
- * @param {Object} obj - The data object to be sent.
55
- * @param {Function} [f] - An optional callback function. This is used by consumers of this library.
56
- */
57
- const sendMore = (obj, f) => {
58
- if (!JSON) return;
59
-
60
- const values = [];
61
- for (const prop in obj) {
62
- if (obj.hasOwnProperty(prop) && isDefined(obj[prop])) {
63
- values.push(`${encodeURIComponent(prop)}=${smartEncode(obj[prop])}`);
64
- }
65
- }
66
-
67
- if (values.length === 0) {
68
- return;
69
- }
70
-
71
- const url = `${ophanRemoteHost}/img/2?viewId=${viewId}&${values.join('&')}`;
72
- send(url, f);
73
- };
74
-
75
- /**
76
- * Checks if a value is defined and not null.
77
- * @param {*} v - The value to check.
78
- * @returns {boolean} True if the value is defined, false otherwise.
79
- */
80
- const isDefined = (v) => {
81
- if (Array.isArray(v)) {
82
- return !!v.length;
83
- } else {
84
- return v != null;
85
- }
86
- };
87
-
88
- /**
89
- * Builds a query string from an object.
90
- * @param {Object} obj - The object to convert to a query string.
91
- * @returns {string} The resulting query string.
92
- */
93
- const buildQueryString = (obj) => {
94
- obj.viewId = viewId;
95
-
96
- const values = [];
97
- for (const prop in obj) {
98
- if (obj.hasOwnProperty(prop) && obj[prop] != null) {
99
- values.push(`${encodeURIComponent(prop)}=${encodeURIComponent(obj[prop])}`);
100
- }
101
- }
102
-
103
- return values.join('&');
104
- };
105
-
106
- /**
107
- * Sends data to a specified URL, i.e.: the Ophan Tracker backend service.
108
- * @param {string} url - The URL to send data to.
109
- * @param {() => void} [f] - An optional callback function.
110
- */
111
- const send = (url, f) => {
112
- if (typeof fetch === 'function') {
113
- return fetch(url, { method: 'GET', mode: 'no-cors', keepalive: true, credentials: "include" }).then(() => f?.());
114
- } else {
115
- const image = new Image();
116
- const checker = setInterval(() => {
117
- if (image.complete) {
118
- if (typeof f === 'function') {
119
- f();
120
- }
121
- clearInterval(checker);
122
- }
123
- }, 10);
124
- image.src = url;
125
- }
126
- };
127
-
128
- export default {
129
- sendInitial,
130
- sendMore,
131
- viewId,
132
- bumpViewId,
133
- };
134
-
135
- /**
136
- * Exports for testing purposes.
137
- */
138
- export const _testExports = {
139
- generatePageViewId,
140
- smartEncode,
141
- isDefined,
142
- buildQueryString,
143
- };
@@ -1,366 +0,0 @@
1
- // Generated by CoffeeScript 2.7.0
2
- // TLDR; This is stripped down from the IAB ad block detection library.
3
- // https://github.com/InteractiveAdvertisingBureau/AdBlockDetection
4
- // The aforementioned library is not well maintained
5
- // and had work in progress network adblocking detection
6
-
7
- var init = function () {
8
- var ofs = 'offset',
9
- cl = 'client';
10
- var noop = function () {};
11
-
12
- var testedOnce = false;
13
- var testExecuting = false;
14
-
15
- var isOldIEevents = window.addEventListener === undefined;
16
-
17
- /**
18
- * Options set with default options initialized
19
- *
20
- */
21
- var _options = {
22
- loopDelay: 50,
23
- maxLoop: 5,
24
- debug: false,
25
- found: noop,
26
- notfound: noop,
27
- complete: noop,
28
- };
29
-
30
- var listeners = []; // event response listeners
31
- var baitNode = null;
32
- var quickBait = {
33
- cssClass:
34
- 'ad-slot pub_300x250 pub_300x250m pub_728x90 text-ad textAd text_ad text_ads text-ads text-ad-links',
35
- };
36
- var baitTriggers = {
37
- nullProps: [ofs + 'Parent'],
38
- zeroProps: [],
39
- };
40
-
41
- baitTriggers.zeroProps = [
42
- ofs + 'Height',
43
- ofs + 'Left',
44
- ofs + 'Top',
45
- ofs + 'Width',
46
- ofs + 'Height',
47
- cl + 'Height',
48
- cl + 'Width',
49
- ];
50
-
51
- // result object
52
- var exeResult = {
53
- quick: null,
54
- remote: null,
55
- };
56
-
57
- var findResult = null; // result of test for ad blocker
58
-
59
- var timerIds = {
60
- test: 0,
61
- download: 0,
62
- };
63
-
64
- function isFunc(fn) {
65
- return typeof fn == 'function';
66
- }
67
-
68
- /**
69
- * Make a DOM element
70
- */
71
- function makeEl(tag, attributes) {
72
- var k,
73
- v,
74
- el,
75
- attr = attributes;
76
- var d = document;
77
-
78
- el = d.createElement(tag);
79
-
80
- if (attr) {
81
- for (k in attr) {
82
- if (attr.hasOwnProperty(k)) {
83
- el.setAttribute(k, attr[k]);
84
- }
85
- }
86
- }
87
-
88
- return el;
89
- }
90
-
91
- function attachEventListener(dom, eventName, handler) {
92
- if (isOldIEevents) {
93
- dom.attachEvent('on' + eventName, handler);
94
- } else {
95
- dom.addEventListener(eventName, handler, false);
96
- }
97
- }
98
-
99
- function log(message, isError) {
100
- if (!_options.debug && !isError) {
101
- return;
102
- }
103
- if (window.console && window.console.log) {
104
- if (isError) {
105
- console.error('[ABD] ' + message);
106
- } else {
107
- console.log('[ABD] ' + message);
108
- }
109
- }
110
- }
111
-
112
- function beginTest(bait) {
113
- log('start beginTest');
114
- if (findResult == true) {
115
- return;
116
- }
117
- testExecuting = true;
118
- castBait(bait);
119
-
120
- exeResult.quick = 'testing';
121
-
122
- timerIds.test = setTimeout(function () {
123
- reelIn(bait, 1);
124
- }, 5);
125
- }
126
-
127
- /**
128
- * Create the bait node to see how the browser page reacts
129
- */
130
- function castBait(bait) {
131
- var i,
132
- d = document,
133
- b = d.body;
134
- var t;
135
- var baitStyle =
136
- 'width: 1px !important; height: 1px !important; position: absolute !important; left: -10000px !important; top: -1000px !important;';
137
-
138
- if (bait == null || typeof bait == 'string') {
139
- log('invalid bait being cast');
140
- return;
141
- }
142
-
143
- if (bait.style != null) {
144
- baitStyle += bait.style;
145
- }
146
-
147
- baitNode = makeEl('div', {
148
- class: bait.cssClass,
149
- style: baitStyle,
150
- });
151
-
152
- log('adding bait node to DOM');
153
-
154
- b.appendChild(baitNode);
155
-
156
- // touch these properties
157
- for (i = 0; i < baitTriggers.nullProps.length; i++) {
158
- t = baitNode[baitTriggers.nullProps[i]];
159
- }
160
- for (i = 0; i < baitTriggers.zeroProps.length; i++) {
161
- t = baitNode[baitTriggers.zeroProps[i]];
162
- }
163
- }
164
-
165
- /**
166
- * Run tests to see if browser has taken the bait and blocked the bait element
167
- */
168
- function reelIn(bait, attemptNum) {
169
- var i, k, v;
170
- var body = document.body;
171
- var found = false;
172
-
173
- if (baitNode == null) {
174
- log('recast bait');
175
- castBait(bait || quickBait);
176
- }
177
-
178
- if (typeof bait == 'string') {
179
- log('invalid bait used', true);
180
- if (clearBaitNode()) {
181
- setTimeout(function () {
182
- testExecuting = false;
183
- }, 5);
184
- }
185
-
186
- return;
187
- }
188
-
189
- if (timerIds.test > 0) {
190
- clearTimeout(timerIds.test);
191
- timerIds.test = 0;
192
- }
193
-
194
- // test for issues
195
-
196
- if (body.getAttribute('abp') !== null) {
197
- log('found adblock body attribute');
198
- found = true;
199
- }
200
-
201
- for (i = 0; i < baitTriggers.nullProps.length; i++) {
202
- if (baitNode[baitTriggers.nullProps[i]] == null) {
203
- if (attemptNum > 4) found = true;
204
- log('found adblock null attr: ' + baitTriggers.nullProps[i]);
205
- break;
206
- }
207
- if (found == true) {
208
- break;
209
- }
210
- }
211
-
212
- for (i = 0; i < baitTriggers.zeroProps.length; i++) {
213
- if (found == true) {
214
- break;
215
- }
216
- if (baitNode[baitTriggers.zeroProps[i]] == 0) {
217
- if (attemptNum > 4) found = true;
218
- log('found adblock zero attr: ' + baitTriggers.zeroProps[i]);
219
- }
220
- }
221
-
222
- if (window.getComputedStyle !== undefined) {
223
- var baitTemp = window.getComputedStyle(baitNode, null);
224
- if (
225
- baitTemp.getPropertyValue('display') == 'none' ||
226
- baitTemp.getPropertyValue('visibility') == 'hidden'
227
- ) {
228
- if (attemptNum > 4) found = true;
229
- log('found adblock computedStyle indicator');
230
- }
231
- }
232
-
233
- testedOnce = true;
234
-
235
- if (found || attemptNum++ >= _options.maxLoop) {
236
- findResult = found;
237
- log('exiting test loop - value: ' + findResult);
238
- notifyListeners();
239
- if (clearBaitNode()) {
240
- setTimeout(function () {
241
- testExecuting = false;
242
- }, 5);
243
- }
244
- } else {
245
- timerIds.test = setTimeout(function () {
246
- reelIn(bait, attemptNum);
247
- }, _options.loopDelay);
248
- }
249
- }
250
-
251
- function clearBaitNode() {
252
- if (baitNode === null) {
253
- return true;
254
- }
255
-
256
- try {
257
- if (isFunc(baitNode.remove)) {
258
- baitNode.remove();
259
- }
260
- document.body.removeChild(baitNode);
261
- } catch (ex) {}
262
- baitNode = null;
263
-
264
- return true;
265
- }
266
-
267
- /**
268
- * Halt the test and any pending timeouts
269
- */
270
- function stopFishing() {
271
- if (timerIds.test > 0) {
272
- clearTimeout(timerIds.test);
273
- }
274
- if (timerIds.download > 0) {
275
- clearTimeout(timerIds.download);
276
- }
277
-
278
- clearBaitNode();
279
- }
280
-
281
- /**
282
- * Fire all registered listeners
283
- */
284
- function notifyListeners() {
285
- var i, funcs;
286
- if (findResult === null) {
287
- return;
288
- }
289
- for (i = 0; i < listeners.length; i++) {
290
- funcs = listeners[i];
291
- try {
292
- if (funcs != null) {
293
- if (isFunc(funcs['complete'])) {
294
- funcs['complete'](findResult);
295
- }
296
-
297
- if (findResult && isFunc(funcs['found'])) {
298
- funcs['found']();
299
- } else if (findResult === false && isFunc(funcs['notfound'])) {
300
- funcs['notfound']();
301
- }
302
- }
303
- } catch (ex) {
304
- log('Failure in notify listeners ' + ex.Message, true);
305
- }
306
- }
307
- }
308
-
309
- /**
310
- * Attaches event listener or fires if events have already passed.
311
- */
312
- function attachOrFire() {
313
- var fireNow = false;
314
- var fn;
315
-
316
- if (document.readyState) {
317
- if (document.readyState == 'complete') {
318
- fireNow = true;
319
- }
320
- }
321
-
322
- fn = function () {
323
- beginTest(quickBait, false);
324
- };
325
-
326
- if (fireNow) {
327
- fn();
328
- } else {
329
- attachEventListener(window, 'load', fn);
330
- }
331
- }
332
-
333
- /**
334
- * Public interface of adblock detector
335
- */
336
- return function (options) {
337
- var k, v, funcs;
338
-
339
- if (!options) {
340
- return;
341
- }
342
-
343
- funcs = {
344
- complete: noop,
345
- found: noop,
346
- notfound: noop,
347
- };
348
-
349
- for (k in options) {
350
- if (options.hasOwnProperty(k)) {
351
- if (k == 'complete' || k == 'found' || k == 'notFound') {
352
- funcs[k.toLowerCase()] = options[k];
353
- } else {
354
- _options[k] = options[k];
355
- }
356
- }
357
- }
358
-
359
- listeners.push(funcs);
360
-
361
- attachOrFire();
362
- };
363
- };
364
- export default {
365
- init: init(),
366
- };
@@ -1,23 +0,0 @@
1
- export default {
2
- state: () =>
3
- document.visibilityState ||
4
- document.webkitVisibilityState ||
5
- document.mozVisibilityState ||
6
- document.msVisibilityState,
7
-
8
- changeEvent: getChangeEvent(),
9
-
10
- };
11
-
12
- function getChangeEvent() {
13
- if (document.visibilityState) {
14
- return 'visibilitychange';
15
- } else if (document.webkitVisibilityState) {
16
- return 'webkitvisibilitychange';
17
- } else if (document.mozVisibilityState) {
18
- return 'mozvisibilitychange';
19
- } else if (document.msVisibilityState) {
20
- return 'msvisibilitychange';
21
- }
22
- return undefined;
23
- }
package/assets/witness.js DELETED
@@ -1,11 +0,0 @@
1
- // Generated by CoffeeScript 2.7.0
2
- import core from './core.js';
3
-
4
- import transmit from './transmit.js';
5
-
6
- core.init('witness');
7
-
8
- export default {
9
- record: transmit.sendMore,
10
- viewId: transmit.viewId,
11
- };