@guardian/commercial-core 0.0.0-beta-20250716121613

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.
Files changed (111) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +45 -0
  3. package/dist/cjs/ad-sizes.d.ts +202 -0
  4. package/dist/cjs/ad-sizes.js +400 -0
  5. package/dist/cjs/breakpoint.d.ts +8 -0
  6. package/dist/cjs/breakpoint.js +10 -0
  7. package/dist/cjs/constants/ad-label-height.d.ts +4 -0
  8. package/dist/cjs/constants/ad-label-height.js +7 -0
  9. package/dist/cjs/constants/index.d.ts +3 -0
  10. package/dist/cjs/constants/index.js +9 -0
  11. package/dist/cjs/constants/prebid-timeout.d.ts +4 -0
  12. package/dist/cjs/constants/prebid-timeout.js +7 -0
  13. package/dist/cjs/constants/top-above-nav-height.d.ts +10 -0
  14. package/dist/cjs/constants/top-above-nav-height.js +48 -0
  15. package/dist/cjs/detect-ad-blocker.d.ts +12 -0
  16. package/dist/cjs/detect-ad-blocker.js +61 -0
  17. package/dist/cjs/event-timer.d.ts +103 -0
  18. package/dist/cjs/event-timer.js +204 -0
  19. package/dist/cjs/geo/country-code.d.ts +3 -0
  20. package/dist/cjs/geo/country-code.js +34 -0
  21. package/dist/cjs/geo/geo-utils.d.ts +11 -0
  22. package/dist/cjs/geo/geo-utils.js +31 -0
  23. package/dist/cjs/geo/get-locale.d.ts +8 -0
  24. package/dist/cjs/geo/get-locale.js +43 -0
  25. package/dist/cjs/global.d.ts +71 -0
  26. package/dist/cjs/global.js +2 -0
  27. package/dist/cjs/index.d.ts +13 -0
  28. package/dist/cjs/index.js +46 -0
  29. package/dist/cjs/messenger/post-message.d.ts +1 -0
  30. package/dist/cjs/messenger/post-message.js +7 -0
  31. package/dist/cjs/permutive.d.ts +9 -0
  32. package/dist/cjs/permutive.js +38 -0
  33. package/dist/cjs/send-commercial-metrics.d.ts +58 -0
  34. package/dist/cjs/send-commercial-metrics.js +209 -0
  35. package/dist/cjs/targeting/build-page-targeting.d.ts +47 -0
  36. package/dist/cjs/targeting/build-page-targeting.js +112 -0
  37. package/dist/cjs/targeting/content.d.ts +87 -0
  38. package/dist/cjs/targeting/content.js +76 -0
  39. package/dist/cjs/targeting/personalised.d.ts +83 -0
  40. package/dist/cjs/targeting/personalised.js +140 -0
  41. package/dist/cjs/targeting/pick-targeting-values.d.ts +25 -0
  42. package/dist/cjs/targeting/pick-targeting-values.js +47 -0
  43. package/dist/cjs/targeting/session.d.ts +111 -0
  44. package/dist/cjs/targeting/session.js +61 -0
  45. package/dist/cjs/targeting/shared.d.ts +156 -0
  46. package/dist/cjs/targeting/shared.js +28 -0
  47. package/dist/cjs/targeting/teads-eligibility.d.ts +2 -0
  48. package/dist/cjs/targeting/teads-eligibility.js +20 -0
  49. package/dist/cjs/targeting/types.d.ts +6 -0
  50. package/dist/cjs/targeting/types.js +2 -0
  51. package/dist/cjs/targeting/viewport.d.ts +48 -0
  52. package/dist/cjs/targeting/viewport.js +22 -0
  53. package/dist/cjs/targeting/youtube-ima.d.ts +12 -0
  54. package/dist/cjs/targeting/youtube-ima.js +76 -0
  55. package/dist/cjs/types.d.ts +426 -0
  56. package/dist/cjs/types.js +12 -0
  57. package/dist/esm/ad-sizes.d.ts +202 -0
  58. package/dist/esm/ad-sizes.js +390 -0
  59. package/dist/esm/breakpoint.d.ts +8 -0
  60. package/dist/esm/breakpoint.js +6 -0
  61. package/dist/esm/constants/ad-label-height.d.ts +4 -0
  62. package/dist/esm/constants/ad-label-height.js +4 -0
  63. package/dist/esm/constants/index.d.ts +3 -0
  64. package/dist/esm/constants/index.js +3 -0
  65. package/dist/esm/constants/prebid-timeout.d.ts +4 -0
  66. package/dist/esm/constants/prebid-timeout.js +4 -0
  67. package/dist/esm/constants/top-above-nav-height.d.ts +10 -0
  68. package/dist/esm/constants/top-above-nav-height.js +45 -0
  69. package/dist/esm/detect-ad-blocker.d.ts +12 -0
  70. package/dist/esm/detect-ad-blocker.js +58 -0
  71. package/dist/esm/event-timer.d.ts +103 -0
  72. package/dist/esm/event-timer.js +199 -0
  73. package/dist/esm/geo/country-code.d.ts +3 -0
  74. package/dist/esm/geo/country-code.js +31 -0
  75. package/dist/esm/geo/geo-utils.d.ts +11 -0
  76. package/dist/esm/geo/geo-utils.js +20 -0
  77. package/dist/esm/geo/get-locale.d.ts +8 -0
  78. package/dist/esm/geo/get-locale.js +38 -0
  79. package/dist/esm/global.d.ts +71 -0
  80. package/dist/esm/global.js +0 -0
  81. package/dist/esm/index.d.ts +13 -0
  82. package/dist/esm/index.js +10 -0
  83. package/dist/esm/messenger/post-message.d.ts +1 -0
  84. package/dist/esm/messenger/post-message.js +3 -0
  85. package/dist/esm/permutive.d.ts +9 -0
  86. package/dist/esm/permutive.js +33 -0
  87. package/dist/esm/send-commercial-metrics.d.ts +58 -0
  88. package/dist/esm/send-commercial-metrics.js +204 -0
  89. package/dist/esm/targeting/build-page-targeting.d.ts +47 -0
  90. package/dist/esm/targeting/build-page-targeting.js +108 -0
  91. package/dist/esm/targeting/content.d.ts +87 -0
  92. package/dist/esm/targeting/content.js +73 -0
  93. package/dist/esm/targeting/personalised.d.ts +83 -0
  94. package/dist/esm/targeting/personalised.js +137 -0
  95. package/dist/esm/targeting/pick-targeting-values.d.ts +25 -0
  96. package/dist/esm/targeting/pick-targeting-values.js +43 -0
  97. package/dist/esm/targeting/session.d.ts +111 -0
  98. package/dist/esm/targeting/session.js +57 -0
  99. package/dist/esm/targeting/shared.d.ts +156 -0
  100. package/dist/esm/targeting/shared.js +25 -0
  101. package/dist/esm/targeting/teads-eligibility.d.ts +2 -0
  102. package/dist/esm/targeting/teads-eligibility.js +17 -0
  103. package/dist/esm/targeting/types.d.ts +6 -0
  104. package/dist/esm/targeting/types.js +0 -0
  105. package/dist/esm/targeting/viewport.d.ts +48 -0
  106. package/dist/esm/targeting/viewport.js +19 -0
  107. package/dist/esm/targeting/youtube-ima.d.ts +12 -0
  108. package/dist/esm/targeting/youtube-ima.js +73 -0
  109. package/dist/esm/types.d.ts +426 -0
  110. package/dist/esm/types.js +10 -0
  111. package/package.json +65 -0
@@ -0,0 +1,400 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.findAppliedSizesForBreakpoint = exports.createAdSize = exports.slotSizeMappings = exports.getAdSize = exports.outstreamSizes = exports.standardAdSizes = exports.adSizes = exports.AdSize = exports._ = void 0;
4
+ const breakpoint_1 = require("./breakpoint");
5
+ /**
6
+ * Store ad sizes in a way that is compatible with google-tag but also accessible via
7
+ * more semantic `width`/`height` properties and keep things readonly.
8
+ *
9
+ * example:
10
+ * const size = new AdSize([300, 250]);
11
+ *
12
+ * size.width === 300; // true
13
+ * size[0] === 300; // true
14
+ *
15
+ * size.height === 250; // true
16
+ * size[1] === 250; // true
17
+ *
18
+ * size[0] = 200; // throws error
19
+ * size.width = 200; // throws error
20
+ *
21
+ */
22
+ class AdSize extends Array {
23
+ [0];
24
+ [1];
25
+ constructor([width, height]) {
26
+ super();
27
+ this[0] = width;
28
+ this[1] = height;
29
+ }
30
+ toString() {
31
+ return this.width === 0 && this.height === 0
32
+ ? 'fluid'
33
+ : `${this.width},${this.height}`;
34
+ }
35
+ toArray() {
36
+ return [this[0], this[1]];
37
+ }
38
+ // The advert size is not reflective of the actual size of the advert.
39
+ // For example, fluid ads and Guardian merch ads are larger than the dimensions
40
+ isProxy() {
41
+ const isOutOfPage = this.width === 1 && this.height === 1;
42
+ const isEmpty = this.width === 2 && this.height === 2;
43
+ const isFluid = this.toString() === 'fluid';
44
+ const isMerch = this.width === 88;
45
+ const isSponsorLogo = this.width === 3 && this.height === 3;
46
+ return isOutOfPage || isEmpty || isFluid || isMerch || isSponsorLogo;
47
+ }
48
+ get width() {
49
+ return this[0];
50
+ }
51
+ get height() {
52
+ return this[1];
53
+ }
54
+ }
55
+ exports.AdSize = AdSize;
56
+ const createAdSize = (width, height) => {
57
+ return new AdSize([width, height]);
58
+ };
59
+ exports.createAdSize = createAdSize;
60
+ const namedStandardAdSizes = {
61
+ billboard: createAdSize(970, 250),
62
+ halfPage: createAdSize(300, 600),
63
+ leaderboard: createAdSize(728, 90),
64
+ mobilesticky: createAdSize(320, 50),
65
+ mpu: createAdSize(300, 250),
66
+ portrait: createAdSize(300, 1050),
67
+ skyscraper: createAdSize(160, 600),
68
+ cascade: createAdSize(940, 230),
69
+ portraitInterstitial: createAdSize(320, 480),
70
+ };
71
+ const standardAdSizes = {
72
+ '970x250': namedStandardAdSizes.billboard,
73
+ '300x600': namedStandardAdSizes.halfPage,
74
+ '728x90': namedStandardAdSizes.leaderboard,
75
+ '300x250': namedStandardAdSizes.mpu,
76
+ '300x1050': namedStandardAdSizes.portrait,
77
+ '160x600': namedStandardAdSizes.skyscraper,
78
+ };
79
+ exports.standardAdSizes = standardAdSizes;
80
+ const outstreamSizes = {
81
+ outstreamDesktop: createAdSize(620, 350),
82
+ outstreamGoogleDesktop: createAdSize(550, 310),
83
+ outstreamMobile: createAdSize(300, 197),
84
+ };
85
+ exports.outstreamSizes = outstreamSizes;
86
+ /**
87
+ * Ad sizes commonly associated with third parties
88
+ */
89
+ const proprietaryAdSizes = {
90
+ fluid: createAdSize(0, 0),
91
+ googleCard: createAdSize(300, 274),
92
+ outOfPage: createAdSize(1, 1),
93
+ pubmaticInterscroller: createAdSize(371, 660), // pubmatic only mobile size
94
+ };
95
+ /**
96
+ * Ad sizes associated with in-house formats
97
+ */
98
+ const guardianProprietaryAdSizes = {
99
+ empty: createAdSize(2, 2),
100
+ fabric: createAdSize(88, 71),
101
+ merchandising: createAdSize(88, 88),
102
+ merchandisingHigh: createAdSize(88, 87),
103
+ merchandisingHighAdFeature: createAdSize(88, 89),
104
+ /**
105
+ * This is a proxy size (not the true size of the rendered creative)
106
+ * that can be used to ensure that no other high priority line items
107
+ * fill a certain slot.
108
+ */
109
+ sponsorLogo: createAdSize(3, 3),
110
+ };
111
+ const adSizes = {
112
+ ...namedStandardAdSizes,
113
+ ...standardAdSizes,
114
+ ...outstreamSizes,
115
+ ...proprietaryAdSizes,
116
+ ...guardianProprietaryAdSizes,
117
+ };
118
+ exports.adSizes = adSizes;
119
+ /**
120
+ * mark: 432b3a46-90c1-4573-90d3-2400b51af8d0
121
+ * Some of these may or may not need to be synced for with the sizes in ./create-ad-slot.ts
122
+ * these were originally from DCR, create-ad-slot.ts ones were in frontend.
123
+ *
124
+ * Note:
125
+ * If a breakpoint is not defined in a size mapping for a slot, that breakpoint will use the sizes
126
+ * of the next breakpoint down that has a size mapping. For example, if only "mobile" and "phablet" sizes
127
+ * are defined for a slot, all breakpoints larger than "phablet" will use the mapping for "phablet".
128
+ *
129
+ * In another example, if a slot has only "tablet" as a size mapping defined,
130
+ * then "desktop" will use the size mapping for "tablet". "mobile" and "phablet"
131
+ * will have no size mapping. This type of example may be used in cases where
132
+ * we only want the slot to appear on the "tablet" size or greater.
133
+ **/
134
+ const slotSizeMappings = {
135
+ inline: {
136
+ mobile: [
137
+ adSizes.outOfPage,
138
+ adSizes.empty,
139
+ adSizes.outstreamMobile,
140
+ adSizes.mpu,
141
+ adSizes.googleCard,
142
+ adSizes.fluid,
143
+ ],
144
+ desktop: [
145
+ adSizes.outOfPage,
146
+ adSizes.empty,
147
+ adSizes.mpu,
148
+ adSizes.googleCard,
149
+ adSizes.fluid,
150
+ ],
151
+ },
152
+ right: {
153
+ mobile: [
154
+ adSizes.outOfPage,
155
+ adSizes.empty,
156
+ adSizes.mpu,
157
+ adSizes.googleCard,
158
+ adSizes.halfPage,
159
+ adSizes.fluid,
160
+ ],
161
+ },
162
+ comments: {
163
+ mobile: [
164
+ adSizes.outOfPage,
165
+ adSizes.empty,
166
+ adSizes.outstreamMobile,
167
+ adSizes.mpu,
168
+ adSizes.googleCard,
169
+ adSizes.fluid,
170
+ ],
171
+ desktop: [
172
+ adSizes.outOfPage,
173
+ adSizes.empty,
174
+ adSizes.mpu,
175
+ adSizes.googleCard,
176
+ adSizes.fluid,
177
+ ],
178
+ },
179
+ 'comments-expanded': {
180
+ mobile: [adSizes.mpu, adSizes.empty],
181
+ desktop: [
182
+ adSizes.outOfPage,
183
+ adSizes.empty,
184
+ adSizes.mpu,
185
+ adSizes.googleCard,
186
+ adSizes.fluid,
187
+ adSizes.skyscraper,
188
+ adSizes.halfPage,
189
+ ],
190
+ },
191
+ 'top-above-nav': {
192
+ mobile: [
193
+ adSizes.outOfPage,
194
+ adSizes.empty,
195
+ adSizes.fabric,
196
+ adSizes.outstreamMobile,
197
+ adSizes.mpu,
198
+ adSizes.fluid,
199
+ ],
200
+ tablet: [
201
+ adSizes.outOfPage,
202
+ adSizes.empty,
203
+ adSizes.fabric,
204
+ adSizes.fluid,
205
+ adSizes.leaderboard,
206
+ ],
207
+ desktop: [
208
+ adSizes.outOfPage,
209
+ adSizes.empty,
210
+ adSizes.leaderboard,
211
+ createAdSize(940, 230),
212
+ createAdSize(900, 250),
213
+ adSizes.billboard,
214
+ adSizes.fabric,
215
+ adSizes.fluid,
216
+ ],
217
+ },
218
+ 'fronts-banner': {
219
+ tablet: [adSizes.empty, adSizes.leaderboard],
220
+ desktop: [
221
+ adSizes.outOfPage,
222
+ adSizes.empty,
223
+ adSizes.billboard,
224
+ adSizes.merchandisingHigh,
225
+ adSizes.fluid,
226
+ ],
227
+ },
228
+ mostpop: {
229
+ mobile: [
230
+ adSizes.outOfPage,
231
+ adSizes.empty,
232
+ adSizes.mpu,
233
+ adSizes.googleCard,
234
+ adSizes.fluid,
235
+ ],
236
+ phablet: [
237
+ adSizes.outOfPage,
238
+ adSizes.empty,
239
+ adSizes.outstreamMobile,
240
+ adSizes.mpu,
241
+ adSizes.googleCard,
242
+ adSizes.halfPage,
243
+ adSizes.fluid,
244
+ ],
245
+ tablet: [
246
+ adSizes.outOfPage,
247
+ adSizes.empty,
248
+ adSizes.mpu,
249
+ adSizes.googleCard,
250
+ adSizes.halfPage,
251
+ adSizes.fluid,
252
+ ],
253
+ desktop: [
254
+ adSizes.outOfPage,
255
+ adSizes.empty,
256
+ adSizes.mpu,
257
+ adSizes.googleCard,
258
+ adSizes.halfPage,
259
+ adSizes.fluid,
260
+ ],
261
+ },
262
+ 'liveblog-top': {
263
+ mobile: [adSizes.outOfPage, adSizes.empty, adSizes.mpu, adSizes.fluid],
264
+ tablet: [],
265
+ desktop: [],
266
+ },
267
+ 'merchandising-high': {
268
+ mobile: [
269
+ adSizes.outOfPage,
270
+ adSizes.empty,
271
+ adSizes.merchandisingHigh,
272
+ adSizes.fluid,
273
+ adSizes.mpu,
274
+ ],
275
+ tablet: [
276
+ adSizes.outOfPage,
277
+ adSizes.empty,
278
+ adSizes.merchandisingHigh,
279
+ adSizes.fluid,
280
+ ],
281
+ desktop: [
282
+ adSizes.outOfPage,
283
+ adSizes.empty,
284
+ adSizes.merchandisingHigh,
285
+ adSizes.fluid,
286
+ adSizes.billboard,
287
+ ],
288
+ },
289
+ merchandising: {
290
+ mobile: [
291
+ adSizes.outOfPage,
292
+ adSizes.empty,
293
+ adSizes.merchandising,
294
+ adSizes.fluid,
295
+ adSizes.mpu,
296
+ ],
297
+ tablet: [
298
+ adSizes.outOfPage,
299
+ adSizes.empty,
300
+ adSizes.merchandising,
301
+ adSizes.fluid,
302
+ ],
303
+ desktop: [
304
+ adSizes.outOfPage,
305
+ adSizes.empty,
306
+ adSizes.merchandising,
307
+ adSizes.fluid,
308
+ adSizes.billboard,
309
+ ],
310
+ },
311
+ survey: {
312
+ desktop: [adSizes.outOfPage],
313
+ },
314
+ carrot: {
315
+ mobile: [adSizes.fluid],
316
+ },
317
+ 'mobile-sticky': {
318
+ mobile: [adSizes.mobilesticky, adSizes.empty, createAdSize(300, 50)],
319
+ },
320
+ 'crossword-banner-mobile': {
321
+ mobile: [adSizes.mobilesticky],
322
+ },
323
+ 'football-right': {
324
+ desktop: [
325
+ adSizes.empty,
326
+ adSizes.mpu,
327
+ adSizes.skyscraper,
328
+ adSizes.halfPage,
329
+ ],
330
+ },
331
+ 'article-end': {
332
+ mobile: [], // Mappings are dynamically added for this slot using additionalSizes
333
+ },
334
+ exclusion: {
335
+ mobile: [adSizes.empty],
336
+ },
337
+ /**
338
+ * @deprecated Use `slotSizeMappings['sponsor-logo']` instead
339
+ */
340
+ external: {
341
+ mobile: [adSizes.outOfPage, adSizes.empty, adSizes.fluid, adSizes.mpu],
342
+ },
343
+ 'sponsor-logo': {
344
+ mobile: [
345
+ adSizes.outOfPage,
346
+ adSizes.empty,
347
+ adSizes.fluid,
348
+ adSizes.sponsorLogo,
349
+ ],
350
+ },
351
+ interactive: {
352
+ // Mappings are dynamically added for this slot using data attributes
353
+ mobile: [adSizes.outOfPage, adSizes.empty],
354
+ tablet: [adSizes.outOfPage, adSizes.empty],
355
+ desktop: [adSizes.outOfPage, adSizes.empty],
356
+ },
357
+ };
358
+ exports.slotSizeMappings = slotSizeMappings;
359
+ const getAdSize = (size) => adSizes[size];
360
+ exports.getAdSize = getAdSize;
361
+ /**
362
+ * Finds the ad sizes that will be used for a breakpoint given a size mapping
363
+ *
364
+ * If ad sizes are defined in the size mapping for the specified breakpoint, we use that.
365
+ * If no sizes are defined for the breakpoint, use the next smallest breakpoint with defined ad sizes.
366
+ * If no smaller breakpoints have defined ad sizes, return an empty array
367
+ *
368
+ * Example:
369
+ * For the following slotSizeMappings:
370
+ * inline: {
371
+ * phablet: [adSizes.mpu],
372
+ * desktop: [adSizes.billboard]
373
+ * }
374
+ * the applied sizes for each breakpoint for the "inline" slot will be:
375
+ * mobile: []
376
+ * phablet: [adSizes.mpu]
377
+ * tablet: [adSizes.mpu]
378
+ * desktop: [adSizes.billboard]
379
+ *
380
+ * See ad-sizes.test.ts for more examples
381
+ */
382
+ const findAppliedSizesForBreakpoint = (sizeMappings, breakpoint) => {
383
+ if (!(0, breakpoint_1.isBreakpoint)(breakpoint)) {
384
+ return [];
385
+ }
386
+ let breakpointIndex = breakpoint_1.breakpoints.findIndex((b) => b === breakpoint);
387
+ while (breakpointIndex >= 0) {
388
+ const breakpointToTry = breakpoint_1.breakpoints[breakpointIndex];
389
+ const sizeMapping = sizeMappings[breakpointToTry];
390
+ if (sizeMapping?.length) {
391
+ return sizeMapping;
392
+ }
393
+ breakpointIndex--;
394
+ }
395
+ // There are no size mappings defined for any size smaller than the breakpoint
396
+ return [];
397
+ };
398
+ exports.findAppliedSizesForBreakpoint = findAppliedSizesForBreakpoint;
399
+ // Export for testing
400
+ exports._ = { createAdSize };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Breakpoints ordered from smallest to largest
3
+ */
4
+ declare const breakpoints: readonly ["mobile", "phablet", "tablet", "desktop", "wide"];
5
+ type Breakpoint = (typeof breakpoints)[number];
6
+ declare const isBreakpoint: (s: string) => s is Breakpoint;
7
+ export type { Breakpoint };
8
+ export { breakpoints, isBreakpoint };
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isBreakpoint = exports.breakpoints = void 0;
4
+ /**
5
+ * Breakpoints ordered from smallest to largest
6
+ */
7
+ const breakpoints = ['mobile', 'phablet', 'tablet', 'desktop', 'wide'];
8
+ exports.breakpoints = breakpoints;
9
+ const isBreakpoint = (s) => breakpoints.includes(s);
10
+ exports.isBreakpoint = isBreakpoint;
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Unit: pixels
3
+ */
4
+ export declare const AD_LABEL_HEIGHT = 24;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AD_LABEL_HEIGHT = void 0;
4
+ /**
5
+ * Unit: pixels
6
+ */
7
+ exports.AD_LABEL_HEIGHT = 24;
@@ -0,0 +1,3 @@
1
+ export { AD_LABEL_HEIGHT } from './ad-label-height';
2
+ export { PREBID_TIMEOUT } from './prebid-timeout';
3
+ export { TOP_ABOVE_NAV_HEIGHT } from './top-above-nav-height';
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TOP_ABOVE_NAV_HEIGHT = exports.PREBID_TIMEOUT = exports.AD_LABEL_HEIGHT = void 0;
4
+ var ad_label_height_1 = require("./ad-label-height");
5
+ Object.defineProperty(exports, "AD_LABEL_HEIGHT", { enumerable: true, get: function () { return ad_label_height_1.AD_LABEL_HEIGHT; } });
6
+ var prebid_timeout_1 = require("./prebid-timeout");
7
+ Object.defineProperty(exports, "PREBID_TIMEOUT", { enumerable: true, get: function () { return prebid_timeout_1.PREBID_TIMEOUT; } });
8
+ var top_above_nav_height_1 = require("./top-above-nav-height");
9
+ Object.defineProperty(exports, "TOP_ABOVE_NAV_HEIGHT", { enumerable: true, get: function () { return top_above_nav_height_1.TOP_ABOVE_NAV_HEIGHT; } });
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Unit: milliseconds
3
+ */
4
+ export declare const PREBID_TIMEOUT = 1500;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PREBID_TIMEOUT = void 0;
4
+ /**
5
+ * Unit: milliseconds
6
+ */
7
+ exports.PREBID_TIMEOUT = 1500;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Unit: pixels.
3
+ *
4
+ * The majority of ads in the top banner are 250px high. We ran an experiment
5
+ * in October 2021 to set the minimum height to 250, and let smaller ads be
6
+ * centred in the space. We did not process with this option, as it had a
7
+ * negative impact on viewability and revenue.
8
+ *
9
+ */
10
+ export declare const TOP_ABOVE_NAV_HEIGHT = 90;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TOP_ABOVE_NAV_HEIGHT = void 0;
4
+ /**
5
+ * Unit: pixels.
6
+ *
7
+ * The majority of ads in the top banner are 250px high. We ran an experiment
8
+ * in October 2021 to set the minimum height to 250, and let smaller ads be
9
+ * centred in the space. We did not process with this option, as it had a
10
+ * negative impact on viewability and revenue.
11
+ *
12
+ */
13
+ exports.TOP_ABOVE_NAV_HEIGHT = 90;
14
+ /*
15
+ Further Notes
16
+ =============
17
+
18
+ There was a very positive impact on CLS (Cumulative Layout Shift), which is good
19
+ for UX. However, the negative commercial impact meant we kept a height of 90px.
20
+
21
+ We ran a 1% server-side experiment to measure CLS when dedicating 250px for the
22
+ topAboveNav. The experiment showed this change has a significant positive impact
23
+ on CLS, and moves average CLS for the page from 0.09 to 0.07 (a 26% improvement
24
+ from this one change). The other way we sliced the data was to look at the
25
+ percent of pages that Google categorised as having 'good', 'needs improvement'
26
+ or 'poor' CLS scores. The viewability for the page dropped by about 1%, and for
27
+ that specific slot, by 4-6%.
28
+
29
+ When the experiment ran, the breakdown was as follows:
30
+
31
+ - 74% of our pages have a “good” CLS score
32
+ - 12% have a “poor” CLS score.
33
+ - 70% viewability for top-above-nav
34
+
35
+ This change resulted in:
36
+
37
+ - 84% “good”
38
+ - 4% “poor”
39
+ - 64% viewability for top-above-nav
40
+
41
+ Relevant Pull Requests
42
+ ----------------------
43
+
44
+ - https://github.com/guardian/frontend/pull/24095
45
+ - https://github.com/guardian/dotcom-rendering/pull/3497
46
+ - https://github.com/guardian/dotcom-rendering/pull/3340
47
+
48
+ */
@@ -0,0 +1,12 @@
1
+ /**
2
+ Detect whether or not the user has an ad blocking extension enabled.
3
+ A few ad blockers are not detectable with this approach e.g. Safari / Adblock
4
+ Code inspired by just-detect-adblock's:
5
+ https://github.com/wmcmurray/just-detect-adblock/blob/master/src/helpers.js
6
+ */
7
+ /**
8
+ * Determines whether or not the user has an ad blocking extension enabled.
9
+ * Note: positive results can be considered reliable while negative ones may not be.
10
+ * @returns Promise
11
+ */
12
+ export declare function isAdBlockInUse(): Promise<boolean>;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ /**
3
+ Detect whether or not the user has an ad blocking extension enabled.
4
+ A few ad blockers are not detectable with this approach e.g. Safari / Adblock
5
+ Code inspired by just-detect-adblock's:
6
+ https://github.com/wmcmurray/just-detect-adblock/blob/master/src/helpers.js
7
+ */
8
+ /*istanbul ignore file -- adElementBlocked can't be tested without patching each of the properties of
9
+ HTMLElement.prototype that it accesses, defeating the purpose of the test! */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.isAdBlockInUse = isAdBlockInUse;
12
+ let adBlockInUse = undefined;
13
+ function adElementBlocked(ad) {
14
+ if (ad.offsetParent === null ||
15
+ ad.offsetHeight === 0 ||
16
+ ad.offsetLeft === 0 ||
17
+ ad.offsetTop === 0 ||
18
+ ad.offsetWidth === 0 ||
19
+ ad.clientHeight === 0 ||
20
+ ad.clientWidth === 0) {
21
+ return true;
22
+ }
23
+ const adStyles = window.getComputedStyle(ad);
24
+ if (adStyles.getPropertyValue('display') === 'none')
25
+ return true;
26
+ if (adStyles.getPropertyValue('visibility') === 'hidden')
27
+ return true;
28
+ const mozBindingProp = adStyles.getPropertyValue('-moz-binding');
29
+ if (mozBindingProp.includes('about:'))
30
+ return true;
31
+ return false;
32
+ }
33
+ /**
34
+ * Determines whether or not the user has an ad blocking extension enabled.
35
+ * Note: positive results can be considered reliable while negative ones may not be.
36
+ * @returns Promise
37
+ */
38
+ function isAdBlockInUse() {
39
+ if (adBlockInUse !== undefined) {
40
+ return Promise.resolve(adBlockInUse);
41
+ }
42
+ if (typeof window.getComputedStyle !== 'function') {
43
+ // Old browsers not supporting getComputedStyle most likely won't have adBlockers
44
+ adBlockInUse = false;
45
+ return Promise.resolve(adBlockInUse);
46
+ }
47
+ return new Promise((resolve) => {
48
+ window.requestAnimationFrame(() => {
49
+ // create a fake ad element and append it to the document
50
+ const ad = document.createElement('div');
51
+ ad.setAttribute('class', 'ad_unit pub_300x250 pub_300x250m pub_728x90 text-ad textAd text_ad text_ads text-ads text-ad-links ad-text adSense adBlock adContent adBanner');
52
+ ad.setAttribute('style', 'width: 1px !important; height: 1px !important; position: absolute !important; left: -10000px !important; top: -1000px !important;');
53
+ document.body.appendChild(ad);
54
+ // avoid a forced layout
55
+ window.requestAnimationFrame(() => {
56
+ // if the ad element has been hidden, an ad blocker is enabled.
57
+ resolve(adElementBlocked(ad));
58
+ });
59
+ });
60
+ });
61
+ }