@guardian/commercial-core 7.1.0 → 27.1.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.
- package/LICENSE +201 -0
- package/README.md +23 -34
- package/dist/cjs/ad-sizes.d.ts +150 -8
- package/dist/cjs/ad-sizes.js +129 -38
- package/dist/cjs/breakpoint.d.ts +8 -0
- package/dist/cjs/breakpoint.js +10 -0
- package/dist/cjs/constants/index.d.ts +1 -1
- package/dist/cjs/constants/index.js +2 -2
- package/dist/cjs/detect-ad-blocker.js +1 -2
- package/dist/cjs/event-timer.d.ts +60 -48
- package/dist/cjs/event-timer.js +149 -115
- package/dist/cjs/geo/country-code.d.ts +3 -0
- package/dist/cjs/geo/country-code.js +34 -0
- package/dist/cjs/geo/geo-utils.d.ts +11 -0
- package/dist/cjs/geo/geo-utils.js +31 -0
- package/dist/cjs/global.d.ts +58 -10
- package/dist/cjs/index.d.ts +9 -39
- package/dist/cjs/index.js +12 -67
- package/dist/cjs/send-commercial-metrics.d.ts +8 -2
- package/dist/cjs/send-commercial-metrics.js +51 -27
- package/dist/cjs/targeting/build-page-targeting.d.ts +4 -5
- package/dist/cjs/targeting/build-page-targeting.js +35 -7
- package/dist/cjs/targeting/content.d.ts +1 -1
- package/dist/cjs/targeting/content.js +1 -1
- package/dist/cjs/targeting/personalised.d.ts +2 -3
- package/dist/cjs/targeting/personalised.js +3 -3
- package/dist/cjs/targeting/pick-targeting-values.d.ts +1 -1
- package/dist/cjs/targeting/session.d.ts +2 -2
- package/dist/cjs/targeting/shared.d.ts +31 -20
- package/dist/cjs/targeting/shared.js +0 -30
- package/dist/cjs/targeting/teads-eligibility.d.ts +2 -0
- package/dist/cjs/targeting/teads-eligibility.js +20 -0
- package/dist/cjs/targeting/types.d.ts +6 -0
- package/dist/cjs/targeting/types.js +2 -0
- package/dist/cjs/targeting/viewport.d.ts +1 -1
- package/dist/cjs/targeting/youtube-ima.d.ts +4 -3
- package/dist/cjs/targeting/youtube-ima.js +7 -4
- package/dist/cjs/types.d.ts +403 -63
- package/dist/cjs/types.js +11 -0
- package/dist/esm/ad-sizes.d.ts +150 -8
- package/dist/esm/ad-sizes.js +127 -38
- package/dist/esm/breakpoint.d.ts +8 -0
- package/dist/esm/breakpoint.js +6 -0
- package/dist/esm/constants/index.d.ts +1 -1
- package/dist/esm/constants/index.js +1 -1
- package/dist/esm/event-timer.d.ts +60 -48
- package/dist/esm/event-timer.js +147 -115
- package/dist/esm/geo/country-code.d.ts +3 -0
- package/dist/esm/geo/country-code.js +31 -0
- package/dist/esm/geo/geo-utils.d.ts +11 -0
- package/dist/esm/geo/geo-utils.js +20 -0
- package/dist/esm/global.d.ts +58 -10
- package/dist/esm/global.js +0 -1
- package/dist/esm/index.d.ts +9 -39
- package/dist/esm/index.js +6 -31
- package/dist/esm/send-commercial-metrics.d.ts +8 -2
- package/dist/esm/send-commercial-metrics.js +48 -25
- package/dist/esm/targeting/build-page-targeting.d.ts +4 -5
- package/dist/esm/targeting/build-page-targeting.js +35 -7
- package/dist/esm/targeting/content.d.ts +1 -1
- package/dist/esm/targeting/content.js +1 -1
- package/dist/esm/targeting/personalised.d.ts +2 -3
- package/dist/esm/targeting/personalised.js +3 -3
- package/dist/esm/targeting/pick-targeting-values.d.ts +1 -1
- package/dist/esm/targeting/session.d.ts +2 -2
- package/dist/esm/targeting/shared.d.ts +31 -20
- package/dist/esm/targeting/shared.js +0 -30
- package/dist/esm/targeting/teads-eligibility.d.ts +2 -0
- package/dist/esm/targeting/teads-eligibility.js +17 -0
- package/dist/esm/targeting/types.d.ts +6 -0
- package/dist/esm/targeting/types.js +0 -0
- package/dist/esm/targeting/viewport.d.ts +1 -1
- package/dist/esm/targeting/youtube-ima.d.ts +4 -3
- package/dist/esm/targeting/youtube-ima.js +7 -4
- package/dist/esm/types.d.ts +403 -63
- package/dist/esm/types.js +11 -1
- package/package.json +64 -83
- package/dist/cjs/__vendor/a9-apstag.d.ts +0 -1
- package/dist/cjs/__vendor/a9-apstag.js +0 -34
- package/dist/cjs/__vendor/ipsos-mori.d.ts +0 -1
- package/dist/cjs/__vendor/ipsos-mori.js +0 -18
- package/dist/cjs/__vendor/launchpad.d.ts +0 -1
- package/dist/cjs/__vendor/launchpad.js +0 -25
- package/dist/cjs/__vendor/pubmatic.d.ts +0 -1
- package/dist/cjs/__vendor/pubmatic.js +0 -49
- package/dist/cjs/__vendor/twitter-script.d.ts +0 -1
- package/dist/cjs/__vendor/twitter-script.js +0 -26
- package/dist/cjs/create-ad-slot.d.ts +0 -17
- package/dist/cjs/create-ad-slot.js +0 -107
- package/dist/cjs/google-analytics.d.ts +0 -1
- package/dist/cjs/google-analytics.js +0 -14
- package/dist/cjs/lib/ab-localstorage.d.ts +0 -2
- package/dist/cjs/lib/ab-localstorage.js +0 -14
- package/dist/cjs/lib/breakpoint.d.ts +0 -4
- package/dist/cjs/lib/breakpoint.js +0 -5
- package/dist/cjs/lib/can-use-dom.d.ts +0 -2
- package/dist/cjs/lib/can-use-dom.js +0 -9
- package/dist/cjs/lib/construct-query.d.ts +0 -3
- package/dist/cjs/lib/construct-query.js +0 -12
- package/dist/cjs/messenger.d.ts +0 -97
- package/dist/cjs/messenger.js +0 -281
- package/dist/cjs/targeting/build-page-targeting-consentless.d.ts +0 -15
- package/dist/cjs/targeting/build-page-targeting-consentless.js +0 -46
- package/dist/cjs/targeting/youtube.d.ts +0 -13
- package/dist/cjs/targeting/youtube.js +0 -64
- package/dist/cjs/third-party-tags/ias.d.ts +0 -7
- package/dist/cjs/third-party-tags/ias.js +0 -14
- package/dist/cjs/third-party-tags/inizio.d.ts +0 -13
- package/dist/cjs/third-party-tags/inizio.js +0 -39
- package/dist/cjs/third-party-tags/permutive.d.ts +0 -6
- package/dist/cjs/third-party-tags/permutive.js +0 -13
- package/dist/cjs/third-party-tags/remarketing.d.ts +0 -7
- package/dist/cjs/third-party-tags/remarketing.js +0 -22
- package/dist/cjs/third-party-tags/twitter-uwt.d.ts +0 -7
- package/dist/cjs/third-party-tags/twitter-uwt.js +0 -15
- package/dist/cjs/track-gpc-signal.d.ts +0 -7
- package/dist/cjs/track-gpc-signal.js +0 -17
- package/dist/cjs/track-labs-container.d.ts +0 -7
- package/dist/cjs/track-labs-container.js +0 -35
- package/dist/cjs/track-scroll-depth.d.ts +0 -8
- package/dist/cjs/track-scroll-depth.js +0 -41
- package/dist/esm/__vendor/a9-apstag.d.ts +0 -1
- package/dist/esm/__vendor/a9-apstag.js +0 -30
- package/dist/esm/__vendor/ipsos-mori.d.ts +0 -1
- package/dist/esm/__vendor/ipsos-mori.js +0 -14
- package/dist/esm/__vendor/launchpad.d.ts +0 -1
- package/dist/esm/__vendor/launchpad.js +0 -21
- package/dist/esm/__vendor/pubmatic.d.ts +0 -1
- package/dist/esm/__vendor/pubmatic.js +0 -45
- package/dist/esm/__vendor/twitter-script.d.ts +0 -1
- package/dist/esm/__vendor/twitter-script.js +0 -22
- package/dist/esm/create-ad-slot.d.ts +0 -17
- package/dist/esm/create-ad-slot.js +0 -103
- package/dist/esm/google-analytics.d.ts +0 -1
- package/dist/esm/google-analytics.js +0 -10
- package/dist/esm/lib/ab-localstorage.d.ts +0 -2
- package/dist/esm/lib/ab-localstorage.js +0 -10
- package/dist/esm/lib/breakpoint.d.ts +0 -4
- package/dist/esm/lib/breakpoint.js +0 -2
- package/dist/esm/lib/can-use-dom.d.ts +0 -2
- package/dist/esm/lib/can-use-dom.js +0 -6
- package/dist/esm/lib/construct-query.d.ts +0 -3
- package/dist/esm/lib/construct-query.js +0 -9
- package/dist/esm/messenger.d.ts +0 -97
- package/dist/esm/messenger.js +0 -274
- package/dist/esm/targeting/build-page-targeting-consentless.d.ts +0 -15
- package/dist/esm/targeting/build-page-targeting-consentless.js +0 -43
- package/dist/esm/targeting/youtube.d.ts +0 -13
- package/dist/esm/targeting/youtube.js +0 -60
- package/dist/esm/third-party-tags/ias.d.ts +0 -7
- package/dist/esm/third-party-tags/ias.js +0 -10
- package/dist/esm/third-party-tags/inizio.d.ts +0 -13
- package/dist/esm/third-party-tags/inizio.js +0 -35
- package/dist/esm/third-party-tags/permutive.d.ts +0 -6
- package/dist/esm/third-party-tags/permutive.js +0 -9
- package/dist/esm/third-party-tags/remarketing.d.ts +0 -7
- package/dist/esm/third-party-tags/remarketing.js +0 -18
- package/dist/esm/third-party-tags/twitter-uwt.d.ts +0 -7
- package/dist/esm/third-party-tags/twitter-uwt.js +0 -11
- package/dist/esm/track-gpc-signal.d.ts +0 -7
- package/dist/esm/track-gpc-signal.js +0 -14
- package/dist/esm/track-labs-container.d.ts +0 -7
- package/dist/esm/track-labs-container.js +0 -32
- package/dist/esm/track-scroll-depth.d.ts +0 -8
- package/dist/esm/track-scroll-depth.js +0 -38
- /package/dist/cjs/constants/{adLabelHeight.d.ts → ad-label-height.d.ts} +0 -0
- /package/dist/cjs/constants/{adLabelHeight.js → ad-label-height.js} +0 -0
- /package/dist/cjs/{lib → geo}/get-locale.d.ts +0 -0
- /package/dist/cjs/{lib → geo}/get-locale.js +0 -0
- /package/dist/esm/constants/{adLabelHeight.d.ts → ad-label-height.d.ts} +0 -0
- /package/dist/esm/constants/{adLabelHeight.js → ad-label-height.js} +0 -0
- /package/dist/esm/{lib → geo}/get-locale.d.ts +0 -0
- /package/dist/esm/{lib → geo}/get-locale.js +0 -0
package/dist/esm/messenger.js
DELETED
|
@@ -1,274 +0,0 @@
|
|
|
1
|
-
import { postMessage } from './messenger/post-message';
|
|
2
|
-
const LISTENERS = {};
|
|
3
|
-
let REGISTERED_LISTENERS = 0;
|
|
4
|
-
let reportError = () => {
|
|
5
|
-
// not set yet
|
|
6
|
-
};
|
|
7
|
-
const error405 = {
|
|
8
|
-
code: 405,
|
|
9
|
-
message: 'Service %% not implemented',
|
|
10
|
-
};
|
|
11
|
-
const error500 = {
|
|
12
|
-
code: 500,
|
|
13
|
-
message: 'Internal server error\n\n%%',
|
|
14
|
-
};
|
|
15
|
-
/**
|
|
16
|
-
* Determine if an unknown payload has the shape of a programmatic message
|
|
17
|
-
*
|
|
18
|
-
* @param payload The unknown message payload
|
|
19
|
-
*/
|
|
20
|
-
const isProgrammaticMessage = (payload) => {
|
|
21
|
-
const payloadToCheck = payload;
|
|
22
|
-
return (payloadToCheck.type === 'set-ad-height' &&
|
|
23
|
-
('id' in payloadToCheck.value || 'slotId' in payloadToCheck.value) &&
|
|
24
|
-
'height' in payloadToCheck.value);
|
|
25
|
-
};
|
|
26
|
-
/**
|
|
27
|
-
* Convert a legacy programmatic message to a standard message
|
|
28
|
-
*
|
|
29
|
-
* Note that this only applies to specific resize programmatic messages
|
|
30
|
-
* (these include specific width and height values)
|
|
31
|
-
*/
|
|
32
|
-
const toStandardMessage = (payload) => ({
|
|
33
|
-
id: 'aaaa0000-bb11-cc22-dd33-eeeeee444444',
|
|
34
|
-
type: 'resize',
|
|
35
|
-
iframeId: payload.value.id,
|
|
36
|
-
slotId: payload.value.slotId,
|
|
37
|
-
value: {
|
|
38
|
-
height: payload.value.height,
|
|
39
|
-
width: payload.value.width,
|
|
40
|
-
},
|
|
41
|
-
});
|
|
42
|
-
/**
|
|
43
|
-
* Retrieve a reference to the calling iFrame
|
|
44
|
-
*
|
|
45
|
-
* Attempts the following strategies to find the correct iframe:
|
|
46
|
-
* - using the slotId from the incoming message
|
|
47
|
-
* - using the iframeId from the incoming message
|
|
48
|
-
* - checking message event.source (i.e. window) against all page level iframe contentWindows
|
|
49
|
-
*
|
|
50
|
-
* Listeners can then use the iFrame to determine the slot making the postMessage call
|
|
51
|
-
*/
|
|
52
|
-
const getIframe = (message, messageEventSource) => {
|
|
53
|
-
if (message.slotId) {
|
|
54
|
-
const container = document.getElementById(`dfp-ad--${message.slotId}`);
|
|
55
|
-
return container?.querySelector('iframe') ?? undefined;
|
|
56
|
-
}
|
|
57
|
-
else if (message.iframeId) {
|
|
58
|
-
const el = document.getElementById(message.iframeId);
|
|
59
|
-
return el instanceof HTMLIFrameElement ? el : undefined;
|
|
60
|
-
}
|
|
61
|
-
else if (messageEventSource) {
|
|
62
|
-
const iframes = document.querySelectorAll('iframe');
|
|
63
|
-
return Array.from(iframes).find((iframe) => iframe.contentWindow === messageEventSource);
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
// Regex for testing validity of message ids
|
|
67
|
-
const validMessageRegex = /^[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}$/;
|
|
68
|
-
/**
|
|
69
|
-
* Narrow an `unknown` payload to the standard message format
|
|
70
|
-
*
|
|
71
|
-
* Until DFP provides a way for us to identify with 100% certainty our
|
|
72
|
-
* in-house creatives, we are left with doing some basic tests
|
|
73
|
-
* such as validating the anatomy of the payload and whitelisting
|
|
74
|
-
* event type
|
|
75
|
-
*/
|
|
76
|
-
const isValidPayload = (payload) => {
|
|
77
|
-
const payloadToCheck = payload;
|
|
78
|
-
return ('type' in payloadToCheck &&
|
|
79
|
-
'value' in payloadToCheck &&
|
|
80
|
-
'id' in payloadToCheck &&
|
|
81
|
-
payloadToCheck.type in LISTENERS &&
|
|
82
|
-
validMessageRegex.test(payloadToCheck.id));
|
|
83
|
-
};
|
|
84
|
-
/**
|
|
85
|
-
* Cheap string formatting function
|
|
86
|
-
*
|
|
87
|
-
* @param error An object `{ code, message }`. `message` is a string where successive
|
|
88
|
-
* occurrences of %% will be replaced by the following arguments
|
|
89
|
-
* @param args Arguments that will replace %%
|
|
90
|
-
*
|
|
91
|
-
* @example
|
|
92
|
-
* formatError({ message: "%%, you are so %%" }, "Regis", "lovely")
|
|
93
|
-
* => { message: "Regis, you are so lovely" }
|
|
94
|
-
*/
|
|
95
|
-
const formatError = (error, ...args) => args.reduce((e, arg) => {
|
|
96
|
-
e.message = e.message.replace('%%', arg);
|
|
97
|
-
return e;
|
|
98
|
-
}, error);
|
|
99
|
-
/**
|
|
100
|
-
* Convert a posted message to our StandardMessage format
|
|
101
|
-
*
|
|
102
|
-
* @param event The message event received on the window
|
|
103
|
-
* @returns A message with the `StandardMessage` format, or null if the conversion was unsuccessful
|
|
104
|
-
*/
|
|
105
|
-
const eventToStandardMessage = (event) => {
|
|
106
|
-
try {
|
|
107
|
-
// Currently all non-string messages are discarded here since parsing throws an error
|
|
108
|
-
// TODO Review whether this is the desired outcome
|
|
109
|
-
const data = JSON.parse(event.data);
|
|
110
|
-
const message = isProgrammaticMessage(data)
|
|
111
|
-
? toStandardMessage(data)
|
|
112
|
-
: data;
|
|
113
|
-
if (isValidPayload(message)) {
|
|
114
|
-
return message;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
catch (ex) {
|
|
118
|
-
// Do nothing
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
/**
|
|
122
|
-
* Respond to the original iframe with the result of calling the
|
|
123
|
-
* persistent listener / listener chain
|
|
124
|
-
*/
|
|
125
|
-
const respond = (id, target, error, result) => {
|
|
126
|
-
postMessage({
|
|
127
|
-
id,
|
|
128
|
-
error,
|
|
129
|
-
result,
|
|
130
|
-
}, target ?? window);
|
|
131
|
-
};
|
|
132
|
-
/**
|
|
133
|
-
* Callback that is fired when an arbitrary message is received on the window
|
|
134
|
-
*
|
|
135
|
-
* @param event The message event received on the window
|
|
136
|
-
*/
|
|
137
|
-
const onMessage = async (event) => {
|
|
138
|
-
const message = eventToStandardMessage(event);
|
|
139
|
-
if (!message) {
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
const listener = LISTENERS[message.type];
|
|
143
|
-
if (Array.isArray(listener) && listener.length) {
|
|
144
|
-
// Because any listener can have side-effects (by unregistering itself),
|
|
145
|
-
// we run the promise chain on a copy of the `LISTENERS` array.
|
|
146
|
-
// Hat tip @piuccio
|
|
147
|
-
const promise =
|
|
148
|
-
// We offer, but don't impose, the possibility that a listener returns
|
|
149
|
-
// a value that must be sent back to the calling frame. To do this,
|
|
150
|
-
// we pass the cumulated returned value as a second argument to each
|
|
151
|
-
// listener. Notice we don't try some clever way to compose the result
|
|
152
|
-
// value ourselves, this would only make the solution more complex.
|
|
153
|
-
// That means a listener can ignore the cumulated return value and
|
|
154
|
-
// return something else entirely—life is unfair.
|
|
155
|
-
// We don't know what each callack will be made of, we don't want to.
|
|
156
|
-
// And so we wrap each call in a promise chain, in case one drops the
|
|
157
|
-
// occasional fastdom bomb in the middle.
|
|
158
|
-
listener.reduce((func, listener) => func.then((ret) => {
|
|
159
|
-
const thisRet = listener(message.value, ret, getIframe(message, event.source));
|
|
160
|
-
return thisRet === undefined ? ret : thisRet;
|
|
161
|
-
}), Promise.resolve());
|
|
162
|
-
return promise
|
|
163
|
-
.then((response) => {
|
|
164
|
-
respond(message.id, event.source, null, response);
|
|
165
|
-
})
|
|
166
|
-
.catch((ex) => {
|
|
167
|
-
reportError(ex, {
|
|
168
|
-
feature: 'native-ads',
|
|
169
|
-
});
|
|
170
|
-
respond(message.id, event.source, formatError(error500, ex.toString()), null);
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
else if (typeof listener === 'function') {
|
|
174
|
-
// We found a persistent listener, to which we just delegate
|
|
175
|
-
// responsibility to write something. Anything. Really.
|
|
176
|
-
// The listener writes something by being given the `respond` function as the spec
|
|
177
|
-
listener(
|
|
178
|
-
// TODO change the arguments expected by persistent listeners to avoid this
|
|
179
|
-
(error, result) => respond(message.id, event.source, error, result), message.value, getIframe(message, event.source));
|
|
180
|
-
}
|
|
181
|
-
else {
|
|
182
|
-
// If there is no routine attached to this event type, we just answer
|
|
183
|
-
// with an error code
|
|
184
|
-
respond(message.id, event.source, formatError(error405, message.type), null);
|
|
185
|
-
}
|
|
186
|
-
};
|
|
187
|
-
const on = (window) => {
|
|
188
|
-
window.addEventListener('message', (event) => void onMessage(event));
|
|
189
|
-
};
|
|
190
|
-
const off = (window) => {
|
|
191
|
-
window.removeEventListener('message', (event) => void onMessage(event));
|
|
192
|
-
};
|
|
193
|
-
/**
|
|
194
|
-
* Register a listener for a given type of iframe message
|
|
195
|
-
*
|
|
196
|
-
* @param type The `type` of message to register against
|
|
197
|
-
* @param callback The listener callback to register that will receive messages of the given type
|
|
198
|
-
* @param options Options for the target window
|
|
199
|
-
*/
|
|
200
|
-
export const register = (type, callback, options) => {
|
|
201
|
-
if (REGISTERED_LISTENERS === 0) {
|
|
202
|
-
on(options?.window ?? window);
|
|
203
|
-
}
|
|
204
|
-
const listeners = LISTENERS[type] ?? [];
|
|
205
|
-
if (Array.isArray(listeners) && !listeners.includes(callback)) {
|
|
206
|
-
LISTENERS[type] = [...listeners, callback];
|
|
207
|
-
REGISTERED_LISTENERS += 1;
|
|
208
|
-
}
|
|
209
|
-
};
|
|
210
|
-
/**
|
|
211
|
-
* Register a persistent listener for a given type of iframe message
|
|
212
|
-
*
|
|
213
|
-
* @param type The `type` of message to register against
|
|
214
|
-
* @param callback The persistent listener callback to register that will receive messages of the given type
|
|
215
|
-
* @param options Options for the target window and whether the callback is persistent
|
|
216
|
-
*/
|
|
217
|
-
export const registerPersistentListener = (type, callback, options) => {
|
|
218
|
-
if (REGISTERED_LISTENERS === 0) {
|
|
219
|
-
on(options?.window ?? window);
|
|
220
|
-
}
|
|
221
|
-
LISTENERS[type] = callback;
|
|
222
|
-
REGISTERED_LISTENERS += 1;
|
|
223
|
-
};
|
|
224
|
-
/**
|
|
225
|
-
* Unregister a callback for a given type
|
|
226
|
-
*
|
|
227
|
-
* @param type The type of message to unregister against. An iframe will send
|
|
228
|
-
* messages annotated with the type
|
|
229
|
-
* @param callback Optionally include the original callback. If this is included
|
|
230
|
-
* for a persistent callback this function will be unregistered. If it's
|
|
231
|
-
* included for a non-persistent callback only the matching callback is removed,
|
|
232
|
-
* otherwise all callbacks for that type will be unregistered
|
|
233
|
-
* @param options Option for the target window
|
|
234
|
-
*/
|
|
235
|
-
export const unregister = (type, callback, options) => {
|
|
236
|
-
const listeners = LISTENERS[type];
|
|
237
|
-
if (listeners === undefined) {
|
|
238
|
-
throw new Error(formatError(error405, type).message);
|
|
239
|
-
}
|
|
240
|
-
else if (listeners === callback) {
|
|
241
|
-
LISTENERS[type] = undefined;
|
|
242
|
-
REGISTERED_LISTENERS -= 1;
|
|
243
|
-
}
|
|
244
|
-
else if (Array.isArray(listeners)) {
|
|
245
|
-
if (callback === undefined) {
|
|
246
|
-
LISTENERS[type] = [];
|
|
247
|
-
REGISTERED_LISTENERS -= listeners.length;
|
|
248
|
-
}
|
|
249
|
-
else {
|
|
250
|
-
LISTENERS[type] = listeners.filter((cb) => {
|
|
251
|
-
const callbacksEqual = cb === callback;
|
|
252
|
-
if (callbacksEqual) {
|
|
253
|
-
REGISTERED_LISTENERS -= 1;
|
|
254
|
-
}
|
|
255
|
-
return !callbacksEqual;
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
if (REGISTERED_LISTENERS === 0) {
|
|
260
|
-
off(options?.window ?? window);
|
|
261
|
-
}
|
|
262
|
-
};
|
|
263
|
-
/**
|
|
264
|
-
* Initialize an array of listener callbacks in a batch
|
|
265
|
-
*
|
|
266
|
-
* @param listeners The listener registration functions
|
|
267
|
-
* @param persistentListeners The persistent listener registration functions
|
|
268
|
-
*/
|
|
269
|
-
export const init = (listeners, persistentListeners, errorHandler) => {
|
|
270
|
-
reportError = errorHandler;
|
|
271
|
-
listeners.forEach((moduleInit) => moduleInit(register, errorHandler));
|
|
272
|
-
persistentListeners.forEach((moduleInit) => moduleInit(registerPersistentListener, errorHandler));
|
|
273
|
-
};
|
|
274
|
-
export const _ = { onMessage };
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { ConsentState } from '@guardian/consent-management-platform/dist/types';
|
|
2
|
-
import type { PageTargeting } from './build-page-targeting';
|
|
3
|
-
declare const consentlessTargetingKeys: readonly ["ab", "at", "bl", "bp", "br", "cc", "ct", "dcre", "edition", "k", "rc", "rp", "s", "se", "sens", "sh", "si", "skinsize", "su", "tn", "url", "urlkw"];
|
|
4
|
-
type ConsentlessTargetingKeys = (typeof consentlessTargetingKeys)[number];
|
|
5
|
-
type ConsentlessPageTargeting = Partial<Pick<PageTargeting, ConsentlessTargetingKeys>>;
|
|
6
|
-
/**
|
|
7
|
-
* Call buildPageTargeting then filter out the keys that are not needed for
|
|
8
|
-
* consentless targeting.
|
|
9
|
-
*
|
|
10
|
-
* @param {ConsentState} consentState
|
|
11
|
-
* @param {boolean} adFree
|
|
12
|
-
* @returns ConsentlessPageTargeting
|
|
13
|
-
*/
|
|
14
|
-
declare const buildPageTargetingConsentless: (consentState: ConsentState, adFree: boolean) => ConsentlessPageTargeting;
|
|
15
|
-
export { buildPageTargetingConsentless };
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { buildPageTargeting } from './build-page-targeting';
|
|
2
|
-
const consentlessTargetingKeys = [
|
|
3
|
-
'ab',
|
|
4
|
-
'at',
|
|
5
|
-
'bl',
|
|
6
|
-
'bp',
|
|
7
|
-
'br',
|
|
8
|
-
'cc',
|
|
9
|
-
'ct',
|
|
10
|
-
'dcre',
|
|
11
|
-
'edition',
|
|
12
|
-
'k',
|
|
13
|
-
'rc',
|
|
14
|
-
'rp',
|
|
15
|
-
's',
|
|
16
|
-
'se',
|
|
17
|
-
'sens',
|
|
18
|
-
'sh',
|
|
19
|
-
'si',
|
|
20
|
-
'skinsize',
|
|
21
|
-
'su',
|
|
22
|
-
'tn',
|
|
23
|
-
'url',
|
|
24
|
-
'urlkw',
|
|
25
|
-
];
|
|
26
|
-
const isConsentlessKey = (key) => consentlessTargetingKeys.includes(key);
|
|
27
|
-
/**
|
|
28
|
-
* Call buildPageTargeting then filter out the keys that are not needed for
|
|
29
|
-
* consentless targeting.
|
|
30
|
-
*
|
|
31
|
-
* @param {ConsentState} consentState
|
|
32
|
-
* @param {boolean} adFree
|
|
33
|
-
* @returns ConsentlessPageTargeting
|
|
34
|
-
*/
|
|
35
|
-
const buildPageTargetingConsentless = (consentState, adFree) => {
|
|
36
|
-
const consentedPageTargeting = buildPageTargeting({
|
|
37
|
-
adFree,
|
|
38
|
-
consentState,
|
|
39
|
-
clientSideParticipations: {},
|
|
40
|
-
});
|
|
41
|
-
return Object.fromEntries(Object.entries(consentedPageTargeting).filter(([k]) => isConsentlessKey(k)));
|
|
42
|
-
};
|
|
43
|
-
export { buildPageTargetingConsentless };
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { Participations } from '@guardian/ab-core';
|
|
2
|
-
import type { ConsentState } from '@guardian/consent-management-platform/dist/types';
|
|
3
|
-
import type { AdsConfig, AdsConfigDisabled, CustomParams } from '../types';
|
|
4
|
-
declare const disabledAds: AdsConfigDisabled;
|
|
5
|
-
type BuildAdsConfigWithConsent = {
|
|
6
|
-
isAdFreeUser: boolean;
|
|
7
|
-
adUnit: string;
|
|
8
|
-
customParams: CustomParams;
|
|
9
|
-
consentState: ConsentState;
|
|
10
|
-
clientSideParticipations: Participations;
|
|
11
|
-
};
|
|
12
|
-
declare const buildAdsConfigWithConsent: ({ adUnit, clientSideParticipations, consentState, customParams, isAdFreeUser, }: BuildAdsConfigWithConsent) => AdsConfig;
|
|
13
|
-
export { buildAdsConfigWithConsent, disabledAds };
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { constructQuery } from '../lib/construct-query';
|
|
2
|
-
import { buildPageTargeting } from './build-page-targeting';
|
|
3
|
-
const disabledAds = { disableAds: true };
|
|
4
|
-
const buildAdsConfig = (cmpConsent, adUnit, customParams, clientSideParticipations) => {
|
|
5
|
-
const mergedCustomParams = {
|
|
6
|
-
...customParams,
|
|
7
|
-
...buildPageTargeting({
|
|
8
|
-
adFree: false,
|
|
9
|
-
clientSideParticipations,
|
|
10
|
-
consentState: cmpConsent,
|
|
11
|
-
youtube: true,
|
|
12
|
-
}),
|
|
13
|
-
// 19/04/2023 This is a temporary update to assist reporting for a YouTube IMA test
|
|
14
|
-
yt_embed_ima: '0',
|
|
15
|
-
};
|
|
16
|
-
const defaultAdsConfig = {
|
|
17
|
-
adTagParameters: {
|
|
18
|
-
iu: adUnit,
|
|
19
|
-
// TODO: Why are we double encoding? Following Frontend process for now
|
|
20
|
-
cust_params: encodeURIComponent(constructQuery(mergedCustomParams)),
|
|
21
|
-
},
|
|
22
|
-
};
|
|
23
|
-
if (cmpConsent.ccpa) {
|
|
24
|
-
const canTarget = !cmpConsent.ccpa.doNotSell;
|
|
25
|
-
return {
|
|
26
|
-
...defaultAdsConfig,
|
|
27
|
-
restrictedDataProcessor: !canTarget,
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
if (cmpConsent.aus) {
|
|
31
|
-
const canTarget = cmpConsent.aus.personalisedAdvertising;
|
|
32
|
-
return {
|
|
33
|
-
...defaultAdsConfig,
|
|
34
|
-
restrictedDataProcessor: !canTarget,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
if (cmpConsent.tcfv2) {
|
|
38
|
-
const tcfData = cmpConsent.tcfv2;
|
|
39
|
-
const canTarget = Object.values(tcfData.consents).every(Boolean);
|
|
40
|
-
const mergedAdTagParameters = {
|
|
41
|
-
...defaultAdsConfig.adTagParameters,
|
|
42
|
-
cmpGdpr: tcfData.gdprApplies ? 1 : 0,
|
|
43
|
-
cmpGvcd: tcfData.addtlConsent,
|
|
44
|
-
cmpVcd: tcfData.tcString,
|
|
45
|
-
};
|
|
46
|
-
return {
|
|
47
|
-
adTagParameters: mergedAdTagParameters,
|
|
48
|
-
nonPersonalizedAd: !canTarget,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
// Shouldn't happen but handle if no matching framework
|
|
52
|
-
return disabledAds;
|
|
53
|
-
};
|
|
54
|
-
const buildAdsConfigWithConsent = ({ adUnit, clientSideParticipations, consentState, customParams, isAdFreeUser, }) => {
|
|
55
|
-
if (isAdFreeUser) {
|
|
56
|
-
return disabledAds;
|
|
57
|
-
}
|
|
58
|
-
return buildAdsConfig(consentState, adUnit, customParams, clientSideParticipations);
|
|
59
|
-
};
|
|
60
|
-
export { buildAdsConfigWithConsent, disabledAds };
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { GetThirdPartyTag } from '../types';
|
|
2
|
-
/**
|
|
3
|
-
* Allows creatives to show survey
|
|
4
|
-
* https://trello.com/c/wHffHVF1/171-integrate-and-test-inizio
|
|
5
|
-
* @param {} {shouldRun}
|
|
6
|
-
*/
|
|
7
|
-
export declare const inizio: GetThirdPartyTag;
|
|
8
|
-
export declare const _: {
|
|
9
|
-
onLoad: () => void;
|
|
10
|
-
handleQuerySurveyDone: (surveyAvailable: boolean, survey: {
|
|
11
|
-
measurementId: string;
|
|
12
|
-
}) => void;
|
|
13
|
-
};
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
const handleQuerySurveyDone = (surveyAvailable, survey) => {
|
|
2
|
-
if (surveyAvailable) {
|
|
3
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- @types/googletag declares it, but it may be missing
|
|
4
|
-
if (window.googletag) {
|
|
5
|
-
window.googletag.cmd.push(() => {
|
|
6
|
-
window.googletag.pubads().setTargeting('inizio', 't');
|
|
7
|
-
});
|
|
8
|
-
}
|
|
9
|
-
console.log(`surveyAvailable: ${survey.measurementId}`);
|
|
10
|
-
}
|
|
11
|
-
};
|
|
12
|
-
const onLoad = () => {
|
|
13
|
-
window._brandmetrics || (window._brandmetrics = []);
|
|
14
|
-
window._brandmetrics.push({
|
|
15
|
-
cmd: '_querySurvey',
|
|
16
|
-
val: {
|
|
17
|
-
callback: handleQuerySurveyDone,
|
|
18
|
-
},
|
|
19
|
-
});
|
|
20
|
-
};
|
|
21
|
-
/**
|
|
22
|
-
* Allows creatives to show survey
|
|
23
|
-
* https://trello.com/c/wHffHVF1/171-integrate-and-test-inizio
|
|
24
|
-
* @param {} {shouldRun}
|
|
25
|
-
*/
|
|
26
|
-
export const inizio = ({ shouldRun }) => ({
|
|
27
|
-
shouldRun,
|
|
28
|
-
url: '//cdn.brandmetrics.com/survey/script/e96d04c832084488a841a06b49b8fb2d.js',
|
|
29
|
-
name: 'inizio',
|
|
30
|
-
onLoad,
|
|
31
|
-
});
|
|
32
|
-
export const _ = {
|
|
33
|
-
onLoad,
|
|
34
|
-
handleQuerySurveyDone,
|
|
35
|
-
};
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
const onLoad = () => {
|
|
2
|
-
window.google_trackConversion?.({
|
|
3
|
-
google_conversion_id: 971225648,
|
|
4
|
-
google_custom_params: window.google_tag_params,
|
|
5
|
-
google_remarketing_only: true,
|
|
6
|
-
});
|
|
7
|
-
};
|
|
8
|
-
/**
|
|
9
|
-
* Google conversion tracking
|
|
10
|
-
* https://support.google.com/google-ads/answer/6095821
|
|
11
|
-
* @param {} {shouldRun}
|
|
12
|
-
*/
|
|
13
|
-
export const remarketing = ({ shouldRun }) => ({
|
|
14
|
-
shouldRun,
|
|
15
|
-
url: '//www.googleadservices.com/pagead/conversion_async.js',
|
|
16
|
-
name: 'remarketing',
|
|
17
|
-
onLoad,
|
|
18
|
-
});
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { GetThirdPartyTag } from '../types';
|
|
2
|
-
/**
|
|
3
|
-
* tracking pixel
|
|
4
|
-
* https://business.twitter.com/en/help/campaign-measurement-and-analytics/conversion-tracking-for-websites.html
|
|
5
|
-
* @param {} {shouldRun}
|
|
6
|
-
*/
|
|
7
|
-
export declare const twitter: GetThirdPartyTag;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { twitterScript as insertSnippet } from '../__vendor/twitter-script';
|
|
2
|
-
/**
|
|
3
|
-
* tracking pixel
|
|
4
|
-
* https://business.twitter.com/en/help/campaign-measurement-and-analytics/conversion-tracking-for-websites.html
|
|
5
|
-
* @param {} {shouldRun}
|
|
6
|
-
*/
|
|
7
|
-
export const twitter = ({ shouldRun }) => ({
|
|
8
|
-
shouldRun,
|
|
9
|
-
name: 'twitter',
|
|
10
|
-
insertSnippet,
|
|
11
|
-
});
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { ConsentState } from '@guardian/consent-management-platform/dist/types';
|
|
2
|
-
/**
|
|
3
|
-
* Collect metrics on gpcSignal presence and value
|
|
4
|
-
* https://globalprivacycontrol.github.io/gpc-spec/
|
|
5
|
-
*/
|
|
6
|
-
declare const initTrackGpcSignal: (consentState: ConsentState) => void;
|
|
7
|
-
export { initTrackGpcSignal };
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { log } from '@guardian/libs';
|
|
2
|
-
import { EventTimer } from './event-timer';
|
|
3
|
-
/**
|
|
4
|
-
* Collect metrics on gpcSignal presence and value
|
|
5
|
-
* https://globalprivacycontrol.github.io/gpc-spec/
|
|
6
|
-
*/
|
|
7
|
-
const initTrackGpcSignal = (consentState) => {
|
|
8
|
-
// If undefined we set the property value to -1, false is 0, true is 1
|
|
9
|
-
const gpcSignal = consentState.gpcSignal === undefined ? -1 : +consentState.gpcSignal;
|
|
10
|
-
const eventTimer = EventTimer.get();
|
|
11
|
-
log('commercial', `gpcSignal ${gpcSignal}`);
|
|
12
|
-
eventTimer.setProperty('gpcSignal', gpcSignal);
|
|
13
|
-
};
|
|
14
|
-
export { initTrackGpcSignal };
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Collect commercial metrics on:
|
|
3
|
-
* - whether the page contains a Guardian Labs container element (aka 'dumathoin'), and if so
|
|
4
|
-
* - when the element is scrolled into view
|
|
5
|
-
*/
|
|
6
|
-
declare const initTrackLabsContainer: () => void;
|
|
7
|
-
export { initTrackLabsContainer };
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { log } from '@guardian/libs';
|
|
2
|
-
import { EventTimer } from './event-timer';
|
|
3
|
-
/**
|
|
4
|
-
* Collect commercial metrics on:
|
|
5
|
-
* - whether the page contains a Guardian Labs container element (aka 'dumathoin'), and if so
|
|
6
|
-
* - when the element is scrolled into view
|
|
7
|
-
*/
|
|
8
|
-
const initTrackLabsContainer = () => {
|
|
9
|
-
const target = document.querySelector('section.dumathoin');
|
|
10
|
-
if (target === null)
|
|
11
|
-
return;
|
|
12
|
-
const labsUrl = document
|
|
13
|
-
.querySelector('h1.dumathoin__title a')
|
|
14
|
-
?.getAttribute('href');
|
|
15
|
-
if (labsUrl === null)
|
|
16
|
-
return;
|
|
17
|
-
const eventTimer = EventTimer.get();
|
|
18
|
-
log('commercial', 'Page has labs container');
|
|
19
|
-
eventTimer.setProperty('hasLabsContainer', true);
|
|
20
|
-
eventTimer.setProperty('labsUrl', labsUrl);
|
|
21
|
-
const observer = new IntersectionObserver((entries) => {
|
|
22
|
-
entries.map((entry) => {
|
|
23
|
-
if (entry.isIntersecting) {
|
|
24
|
-
log('commercial', 'Labs container in view');
|
|
25
|
-
eventTimer.trigger('labsContainerInView');
|
|
26
|
-
observer.unobserve(entry.target);
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
observer.observe(target);
|
|
31
|
-
};
|
|
32
|
-
export { initTrackLabsContainer };
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Collect commercial metrics on scroll depth
|
|
3
|
-
* Insert hidden elements at intervals of 1 viewport height
|
|
4
|
-
* then use an intersection observer to mark the time when the viewport intersects with these elements.
|
|
5
|
-
* Approach inspired by https://gist.github.com/bgreater/2412517f5a3f9c6fc4cafeb1ca71384f
|
|
6
|
-
*/
|
|
7
|
-
declare const initTrackScrollDepth: () => void;
|
|
8
|
-
export { initTrackScrollDepth };
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { log } from '@guardian/libs';
|
|
2
|
-
import { EventTimer } from './event-timer';
|
|
3
|
-
/**
|
|
4
|
-
* Collect commercial metrics on scroll depth
|
|
5
|
-
* Insert hidden elements at intervals of 1 viewport height
|
|
6
|
-
* then use an intersection observer to mark the time when the viewport intersects with these elements.
|
|
7
|
-
* Approach inspired by https://gist.github.com/bgreater/2412517f5a3f9c6fc4cafeb1ca71384f
|
|
8
|
-
*/
|
|
9
|
-
const initTrackScrollDepth = () => {
|
|
10
|
-
const pageHeight = document.body.offsetHeight;
|
|
11
|
-
const intViewportHeight = window.innerHeight;
|
|
12
|
-
// how many viewports tall is the page?
|
|
13
|
-
const pageHeightVH = Math.floor(pageHeight / intViewportHeight);
|
|
14
|
-
const eventTimer = EventTimer.get();
|
|
15
|
-
eventTimer.setProperty('pageHeightVH', pageHeightVH);
|
|
16
|
-
const observer = new IntersectionObserver(
|
|
17
|
-
/* istanbul ignore next */
|
|
18
|
-
(entries) => {
|
|
19
|
-
entries.forEach((entry) => {
|
|
20
|
-
if (entry.isIntersecting) {
|
|
21
|
-
const currentDepthVH = String(entry.target.getAttribute('data-depth'));
|
|
22
|
-
log('commercial', `current scroll depth ${currentDepthVH}`);
|
|
23
|
-
eventTimer.trigger(`scroll-depth-vh-${currentDepthVH}`);
|
|
24
|
-
observer.unobserve(entry.target);
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
for (let depth = 1; depth <= pageHeightVH; depth++) {
|
|
29
|
-
const div = document.createElement('div');
|
|
30
|
-
div.dataset.depth = String(depth);
|
|
31
|
-
div.style.top = String(100 * depth) + '%';
|
|
32
|
-
div.style.position = 'absolute';
|
|
33
|
-
div.className = 'scroll-depth-marker';
|
|
34
|
-
document.body.appendChild(div);
|
|
35
|
-
observer.observe(div);
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
export { initTrackScrollDepth };
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|