@guardian/commercial-core 3.5.0 → 4.0.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/dist/cjs/ad-sizes.d.ts +4 -4
- package/dist/cjs/ad-sizes.js +3 -3
- package/dist/cjs/create-ad-slot.d.ts +9 -0
- package/dist/cjs/create-ad-slot.js +229 -0
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js +2 -2
- package/dist/cjs/types.d.ts +1 -0
- package/dist/esm/ad-sizes.d.ts +4 -4
- package/dist/esm/ad-sizes.js +2 -2
- package/dist/esm/create-ad-slot.d.ts +9 -0
- package/dist/esm/create-ad-slot.js +225 -0
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/types.d.ts +1 -0
- package/package.json +1 -1
package/dist/cjs/ad-sizes.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ interface SizeMapping {
|
|
|
11
11
|
phablet?: AdSize[];
|
|
12
12
|
tablet?: AdSize[];
|
|
13
13
|
}
|
|
14
|
-
interface
|
|
14
|
+
interface SlotSizeMappings {
|
|
15
15
|
right: SizeMapping;
|
|
16
16
|
comments: SizeMapping;
|
|
17
17
|
'top-above-nav': SizeMapping;
|
|
@@ -21,10 +21,10 @@ interface SizeMappings {
|
|
|
21
21
|
survey: SizeMapping;
|
|
22
22
|
}
|
|
23
23
|
declare const adSizes: Record<SizeKeys, AdSize>;
|
|
24
|
-
declare const
|
|
24
|
+
declare const slotSizeMappings: SlotSizeMappings;
|
|
25
25
|
declare const getAdSize: (size: SizeKeys) => AdSize;
|
|
26
26
|
export declare const _: {
|
|
27
27
|
createAdSize: (width: number, height: number) => AdSize;
|
|
28
28
|
};
|
|
29
|
-
export type { AdSizeString, AdSize, SizeKeys };
|
|
30
|
-
export { adSizes, getAdSize,
|
|
29
|
+
export type { AdSizeString, AdSize, SizeKeys, SizeMapping };
|
|
30
|
+
export { adSizes, getAdSize, slotSizeMappings };
|
package/dist/cjs/ad-sizes.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.slotSizeMappings = exports.getAdSize = exports.adSizes = exports._ = void 0;
|
|
4
4
|
const createAdSize = (width, height) => {
|
|
5
5
|
const toString = () => width === 0 && height === 0 ? 'fluid' : `${width},${height}`;
|
|
6
6
|
return Object.freeze({
|
|
@@ -43,7 +43,7 @@ const adSizes = {
|
|
|
43
43
|
'160x600': adSizesPartial.skyscraper,
|
|
44
44
|
};
|
|
45
45
|
exports.adSizes = adSizes;
|
|
46
|
-
const
|
|
46
|
+
const slotSizeMappings = {
|
|
47
47
|
right: {
|
|
48
48
|
mobile: [
|
|
49
49
|
adSizes.outOfPage,
|
|
@@ -156,7 +156,7 @@ const sizeMappings = {
|
|
|
156
156
|
desktop: [adSizes.outOfPage],
|
|
157
157
|
},
|
|
158
158
|
};
|
|
159
|
-
exports.
|
|
159
|
+
exports.slotSizeMappings = slotSizeMappings;
|
|
160
160
|
const getAdSize = (size) => adSizes[size];
|
|
161
161
|
exports.getAdSize = getAdSize;
|
|
162
162
|
// Export for testing
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AdSize } from './ad-sizes';
|
|
2
|
+
declare type SlotName = 'im' | 'high-merch' | 'high-merch-lucky' | 'high-merch-paid' | 'inline' | 'mostpop' | 'comments' | 'top-above-nav' | 'carrot' | 'epic' | 'mobile-sticky';
|
|
3
|
+
declare type CreateSlotOptions = {
|
|
4
|
+
classes?: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
sizes?: Record<string, AdSize[]>;
|
|
7
|
+
};
|
|
8
|
+
export declare const createAdSlot: (name: SlotName, options?: CreateSlotOptions) => HTMLElement;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createAdSlot = void 0;
|
|
4
|
+
const ad_sizes_1 = require("./ad-sizes");
|
|
5
|
+
const adSlotIdPrefix = 'dfp-ad--';
|
|
6
|
+
const commonSizeMappings = {
|
|
7
|
+
mobile: [
|
|
8
|
+
ad_sizes_1.adSizes.outOfPage,
|
|
9
|
+
ad_sizes_1.adSizes.empty,
|
|
10
|
+
ad_sizes_1.adSizes.outstreamMobile,
|
|
11
|
+
ad_sizes_1.adSizes.mpu,
|
|
12
|
+
ad_sizes_1.adSizes.googleCard,
|
|
13
|
+
ad_sizes_1.adSizes.fluid,
|
|
14
|
+
],
|
|
15
|
+
phablet: [
|
|
16
|
+
ad_sizes_1.adSizes.outOfPage,
|
|
17
|
+
ad_sizes_1.adSizes.empty,
|
|
18
|
+
ad_sizes_1.adSizes.outstreamMobile,
|
|
19
|
+
ad_sizes_1.adSizes.mpu,
|
|
20
|
+
ad_sizes_1.adSizes.googleCard,
|
|
21
|
+
ad_sizes_1.adSizes.fluid,
|
|
22
|
+
],
|
|
23
|
+
desktop: [
|
|
24
|
+
ad_sizes_1.adSizes.outOfPage,
|
|
25
|
+
ad_sizes_1.adSizes.empty,
|
|
26
|
+
ad_sizes_1.adSizes.mpu,
|
|
27
|
+
ad_sizes_1.adSizes.googleCard,
|
|
28
|
+
ad_sizes_1.adSizes.fluid,
|
|
29
|
+
],
|
|
30
|
+
};
|
|
31
|
+
/*
|
|
32
|
+
|
|
33
|
+
mark: 432b3a46-90c1-4573-90d3-2400b51af8d0
|
|
34
|
+
|
|
35
|
+
The ad sizes which are hardcoded here are also hardcoded in the source code of
|
|
36
|
+
dotcom-rendering.
|
|
37
|
+
|
|
38
|
+
If/when this file is modified, please make sure that updates, if any, are reported to DCR.
|
|
39
|
+
|
|
40
|
+
TODO use a map type??
|
|
41
|
+
want to assert that values are of type AdSlotConfig
|
|
42
|
+
*/
|
|
43
|
+
const adSlotConfigs = {
|
|
44
|
+
im: {
|
|
45
|
+
label: false,
|
|
46
|
+
refresh: false,
|
|
47
|
+
sizeMappings: {
|
|
48
|
+
mobile: [
|
|
49
|
+
ad_sizes_1.adSizes.outOfPage,
|
|
50
|
+
ad_sizes_1.adSizes.empty,
|
|
51
|
+
ad_sizes_1.adSizes.inlineMerchandising,
|
|
52
|
+
ad_sizes_1.adSizes.fluid,
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
'high-merch': {
|
|
57
|
+
label: false,
|
|
58
|
+
refresh: false,
|
|
59
|
+
name: 'merchandising-high',
|
|
60
|
+
sizeMappings: {
|
|
61
|
+
mobile: [
|
|
62
|
+
ad_sizes_1.adSizes.outOfPage,
|
|
63
|
+
ad_sizes_1.adSizes.empty,
|
|
64
|
+
ad_sizes_1.adSizes.merchandisingHigh,
|
|
65
|
+
ad_sizes_1.adSizes.fluid,
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
'high-merch-lucky': {
|
|
70
|
+
label: false,
|
|
71
|
+
refresh: false,
|
|
72
|
+
name: 'merchandising-high-lucky',
|
|
73
|
+
sizeMappings: {
|
|
74
|
+
mobile: [ad_sizes_1.adSizes.outOfPage, ad_sizes_1.adSizes.empty, ad_sizes_1.adSizes.fluid],
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
'high-merch-paid': {
|
|
78
|
+
label: false,
|
|
79
|
+
refresh: false,
|
|
80
|
+
name: 'merchandising-high',
|
|
81
|
+
sizeMappings: {
|
|
82
|
+
mobile: [
|
|
83
|
+
ad_sizes_1.adSizes.outOfPage,
|
|
84
|
+
ad_sizes_1.adSizes.empty,
|
|
85
|
+
ad_sizes_1.adSizes.merchandisingHighAdFeature,
|
|
86
|
+
ad_sizes_1.adSizes.fluid,
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
inline: {
|
|
91
|
+
sizeMappings: commonSizeMappings,
|
|
92
|
+
},
|
|
93
|
+
mostpop: {
|
|
94
|
+
sizeMappings: commonSizeMappings,
|
|
95
|
+
},
|
|
96
|
+
comments: {
|
|
97
|
+
sizeMappings: commonSizeMappings,
|
|
98
|
+
},
|
|
99
|
+
'top-above-nav': {
|
|
100
|
+
sizeMappings: {
|
|
101
|
+
mobile: [
|
|
102
|
+
ad_sizes_1.adSizes.outOfPage,
|
|
103
|
+
ad_sizes_1.adSizes.empty,
|
|
104
|
+
ad_sizes_1.adSizes.fabric,
|
|
105
|
+
ad_sizes_1.adSizes.outstreamMobile,
|
|
106
|
+
ad_sizes_1.adSizes.mpu,
|
|
107
|
+
ad_sizes_1.adSizes.fluid,
|
|
108
|
+
],
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
carrot: {
|
|
112
|
+
label: false,
|
|
113
|
+
refresh: false,
|
|
114
|
+
name: 'carrot',
|
|
115
|
+
sizeMappings: {
|
|
116
|
+
mobile: [ad_sizes_1.adSizes.fluid],
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
epic: {
|
|
120
|
+
label: false,
|
|
121
|
+
refresh: false,
|
|
122
|
+
name: 'epic',
|
|
123
|
+
sizeMappings: {
|
|
124
|
+
mobile: [ad_sizes_1.adSizes.fluid],
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
'mobile-sticky': {
|
|
128
|
+
label: true,
|
|
129
|
+
refresh: true,
|
|
130
|
+
name: 'mobile-sticky',
|
|
131
|
+
sizeMappings: {
|
|
132
|
+
mobile: [ad_sizes_1.adSizes.mobilesticky],
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
Returns an adSlot HTMLElement which is the main DFP slot.
|
|
138
|
+
|
|
139
|
+
Insert that element as siblings at the place you want adverts to appear.
|
|
140
|
+
|
|
141
|
+
Note that for the DFP slot to be filled by GTP, you'll have to
|
|
142
|
+
use addSlot from add-slot.js
|
|
143
|
+
*/
|
|
144
|
+
const createAdSlotElement = (name, attrs, classes) => {
|
|
145
|
+
const id = `${adSlotIdPrefix}${name}`;
|
|
146
|
+
// 3562dc07-78e9-4507-b922-78b979d4c5cb
|
|
147
|
+
if (window.guardian.config?.isDotcomRendering && name === 'top-above-nav') {
|
|
148
|
+
// This is to prevent a problem that appeared with DCR.
|
|
149
|
+
// We are simply making sure that if we are about to
|
|
150
|
+
// introduce dfp-ad--top-above-nav then there isn't already one.
|
|
151
|
+
const node = document.getElementById(id);
|
|
152
|
+
if (node?.parentNode) {
|
|
153
|
+
const pnode = node.parentNode;
|
|
154
|
+
console.log(`warning: cleaning up dom node id: dfp-ad--${name}`);
|
|
155
|
+
pnode.removeChild(node);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// The 'main' adSlot
|
|
159
|
+
const adSlot = document.createElement('div');
|
|
160
|
+
adSlot.id = id;
|
|
161
|
+
adSlot.className = `js-ad-slot ad-slot ${classes.join(' ')}`;
|
|
162
|
+
adSlot.setAttribute('data-link-name', `ad slot ${name}`);
|
|
163
|
+
adSlot.setAttribute('data-name', name);
|
|
164
|
+
adSlot.setAttribute('aria-hidden', 'true');
|
|
165
|
+
Object.entries(attrs).forEach(([k, v]) => adSlot.setAttribute(k, v));
|
|
166
|
+
return adSlot;
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* Split class names and prefix all with ad-slot--${className}
|
|
170
|
+
*/
|
|
171
|
+
const createClasses = (slotName, classes) => [...(classes?.split(' ') ?? []), slotName].map((className) => `ad-slot--${className}`);
|
|
172
|
+
/**
|
|
173
|
+
* Given default size mappings and additional size mappings from
|
|
174
|
+
* the createAdSlot options parameter.
|
|
175
|
+
*
|
|
176
|
+
* 1. Check that the options size mappings use known device names
|
|
177
|
+
* 2. If so concat the size mappings
|
|
178
|
+
*
|
|
179
|
+
*/
|
|
180
|
+
const concatSizeMappings = (defaultSizeMappings, optionSizeMappings) => {
|
|
181
|
+
if (!optionSizeMappings)
|
|
182
|
+
return defaultSizeMappings;
|
|
183
|
+
const concatenatedSizeMappings = { ...defaultSizeMappings };
|
|
184
|
+
const optionDevices = Object.keys(optionSizeMappings); // ['mobile', 'desktop']
|
|
185
|
+
for (let i = 0; i < optionDevices.length; i++) {
|
|
186
|
+
const device = optionDevices[i];
|
|
187
|
+
if (optionSizeMappings[device] && defaultSizeMappings[device]) {
|
|
188
|
+
const optionSizeMappingsForDevice = optionSizeMappings[device];
|
|
189
|
+
const defaultSizeMappingsForDevice = defaultSizeMappings[device];
|
|
190
|
+
if (defaultSizeMappingsForDevice && optionSizeMappingsForDevice) {
|
|
191
|
+
// TODO can we do concatenatedSizeMappings[device]?.concat ?
|
|
192
|
+
concatenatedSizeMappings[device] = (concatenatedSizeMappings[device] ?? []).concat(optionSizeMappingsForDevice);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return concatenatedSizeMappings;
|
|
197
|
+
};
|
|
198
|
+
/**
|
|
199
|
+
* Convert size mappings to a string that will be added to the ad slot
|
|
200
|
+
* data attributes.
|
|
201
|
+
*
|
|
202
|
+
* e.g. { desktop: [[320,250], [320, 280]] } => { desktop: '320,250|320,280' }
|
|
203
|
+
*
|
|
204
|
+
*/
|
|
205
|
+
const covertSizeMappingsToStrings = (sizeMappings) => Object.entries(sizeMappings).reduce((result, [device, sizes]) => {
|
|
206
|
+
result[device] = sizes.join('|');
|
|
207
|
+
return result;
|
|
208
|
+
}, {});
|
|
209
|
+
/**
|
|
210
|
+
* Prefix all object keys with data-${key}
|
|
211
|
+
*/
|
|
212
|
+
const createDataAttributes = (attrs) => Object.entries(attrs).reduce((result, [key, value]) => {
|
|
213
|
+
result[`data-${key}`] = value;
|
|
214
|
+
return result;
|
|
215
|
+
}, {});
|
|
216
|
+
const createAdSlot = (name, options = {}) => {
|
|
217
|
+
const adSlotConfig = adSlotConfigs[name];
|
|
218
|
+
const slotName = options.name ?? adSlotConfig.name ?? name;
|
|
219
|
+
const sizeMappings = concatSizeMappings(adSlotConfig.sizeMappings, options.sizes);
|
|
220
|
+
const attributes = covertSizeMappingsToStrings(sizeMappings);
|
|
221
|
+
if (adSlotConfig.label === false) {
|
|
222
|
+
attributes.label = 'false';
|
|
223
|
+
}
|
|
224
|
+
if (adSlotConfig.refresh === false) {
|
|
225
|
+
attributes.refresh = 'false';
|
|
226
|
+
}
|
|
227
|
+
return createAdSlotElement(slotName, createDataAttributes(attributes), createClasses(slotName, options.classes));
|
|
228
|
+
};
|
|
229
|
+
exports.createAdSlot = createAdSlot;
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export { remarketing } from './third-party-tags/remarketing';
|
|
|
7
7
|
export { EventTimer } from './event-timer';
|
|
8
8
|
export { bypassCommercialMetricsSampling, initCommercialMetrics, } from './send-commercial-metrics';
|
|
9
9
|
export type { ThirdPartyTag } from './types';
|
|
10
|
-
export { adSizes, getAdSize,
|
|
10
|
+
export { adSizes, getAdSize, slotSizeMappings } from './ad-sizes';
|
|
11
11
|
export type { SizeKeys, AdSizeString, AdSize } from './ad-sizes';
|
|
12
12
|
export { isAdBlockInUse } from './detect-ad-blocker';
|
|
13
13
|
export { clearPermutiveSegments, getPermutiveSegments, getPermutivePFPSegments, } from './permutive';
|
package/dist/cjs/index.js
CHANGED
|
@@ -24,7 +24,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
24
24
|
return result;
|
|
25
25
|
};
|
|
26
26
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
-
exports.pickTargetingValues = exports.getViewportTargeting = exports.getSharedTargeting = exports.getSessionTargeting = exports.getPersonalisedTargeting = exports.getContentTargeting = exports.constants = exports.disabledAds = exports.buildAdsConfigWithConsent = exports.initTrackGpcSignal = exports.initTrackScrollDepth = exports.getPermutivePFPSegments = exports.getPermutiveSegments = exports.clearPermutiveSegments = exports.isAdBlockInUse = exports.
|
|
27
|
+
exports.pickTargetingValues = exports.getViewportTargeting = exports.getSharedTargeting = exports.getSessionTargeting = exports.getPersonalisedTargeting = exports.getContentTargeting = exports.constants = exports.disabledAds = exports.buildAdsConfigWithConsent = exports.initTrackGpcSignal = exports.initTrackScrollDepth = exports.getPermutivePFPSegments = exports.getPermutiveSegments = exports.clearPermutiveSegments = exports.isAdBlockInUse = exports.slotSizeMappings = exports.getAdSize = exports.adSizes = exports.initCommercialMetrics = exports.bypassCommercialMetricsSampling = exports.EventTimer = exports.remarketing = exports.inizio = exports.twitter = exports.fbPixel = exports.permutive = exports.ias = void 0;
|
|
28
28
|
var ias_1 = require("./third-party-tags/ias");
|
|
29
29
|
Object.defineProperty(exports, "ias", { enumerable: true, get: function () { return ias_1.ias; } });
|
|
30
30
|
var permutive_1 = require("./third-party-tags/permutive");
|
|
@@ -45,7 +45,7 @@ Object.defineProperty(exports, "initCommercialMetrics", { enumerable: true, get:
|
|
|
45
45
|
var ad_sizes_1 = require("./ad-sizes");
|
|
46
46
|
Object.defineProperty(exports, "adSizes", { enumerable: true, get: function () { return ad_sizes_1.adSizes; } });
|
|
47
47
|
Object.defineProperty(exports, "getAdSize", { enumerable: true, get: function () { return ad_sizes_1.getAdSize; } });
|
|
48
|
-
Object.defineProperty(exports, "
|
|
48
|
+
Object.defineProperty(exports, "slotSizeMappings", { enumerable: true, get: function () { return ad_sizes_1.slotSizeMappings; } });
|
|
49
49
|
var detect_ad_blocker_1 = require("./detect-ad-blocker");
|
|
50
50
|
Object.defineProperty(exports, "isAdBlockInUse", { enumerable: true, get: function () { return detect_ad_blocker_1.isAdBlockInUse; } });
|
|
51
51
|
var permutive_2 = require("./permutive");
|
package/dist/cjs/types.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export declare type GuardianAnalyticsConfig = {
|
|
|
23
23
|
};
|
|
24
24
|
export declare type GuardianWindowConfig = {
|
|
25
25
|
googleAnalytics?: GuardianAnalyticsConfig;
|
|
26
|
+
isDotcomRendering?: boolean;
|
|
26
27
|
};
|
|
27
28
|
export declare type GoogleTagParams = unknown;
|
|
28
29
|
export declare type GoogleTrackConversionObject = {
|
package/dist/esm/ad-sizes.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ interface SizeMapping {
|
|
|
11
11
|
phablet?: AdSize[];
|
|
12
12
|
tablet?: AdSize[];
|
|
13
13
|
}
|
|
14
|
-
interface
|
|
14
|
+
interface SlotSizeMappings {
|
|
15
15
|
right: SizeMapping;
|
|
16
16
|
comments: SizeMapping;
|
|
17
17
|
'top-above-nav': SizeMapping;
|
|
@@ -21,10 +21,10 @@ interface SizeMappings {
|
|
|
21
21
|
survey: SizeMapping;
|
|
22
22
|
}
|
|
23
23
|
declare const adSizes: Record<SizeKeys, AdSize>;
|
|
24
|
-
declare const
|
|
24
|
+
declare const slotSizeMappings: SlotSizeMappings;
|
|
25
25
|
declare const getAdSize: (size: SizeKeys) => AdSize;
|
|
26
26
|
export declare const _: {
|
|
27
27
|
createAdSize: (width: number, height: number) => AdSize;
|
|
28
28
|
};
|
|
29
|
-
export type { AdSizeString, AdSize, SizeKeys };
|
|
30
|
-
export { adSizes, getAdSize,
|
|
29
|
+
export type { AdSizeString, AdSize, SizeKeys, SizeMapping };
|
|
30
|
+
export { adSizes, getAdSize, slotSizeMappings };
|
package/dist/esm/ad-sizes.js
CHANGED
|
@@ -39,7 +39,7 @@ const adSizes = {
|
|
|
39
39
|
'300x1050': adSizesPartial.portrait,
|
|
40
40
|
'160x600': adSizesPartial.skyscraper,
|
|
41
41
|
};
|
|
42
|
-
const
|
|
42
|
+
const slotSizeMappings = {
|
|
43
43
|
right: {
|
|
44
44
|
mobile: [
|
|
45
45
|
adSizes.outOfPage,
|
|
@@ -155,4 +155,4 @@ const sizeMappings = {
|
|
|
155
155
|
const getAdSize = (size) => adSizes[size];
|
|
156
156
|
// Export for testing
|
|
157
157
|
export const _ = { createAdSize };
|
|
158
|
-
export { adSizes, getAdSize,
|
|
158
|
+
export { adSizes, getAdSize, slotSizeMappings };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AdSize } from './ad-sizes';
|
|
2
|
+
declare type SlotName = 'im' | 'high-merch' | 'high-merch-lucky' | 'high-merch-paid' | 'inline' | 'mostpop' | 'comments' | 'top-above-nav' | 'carrot' | 'epic' | 'mobile-sticky';
|
|
3
|
+
declare type CreateSlotOptions = {
|
|
4
|
+
classes?: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
sizes?: Record<string, AdSize[]>;
|
|
7
|
+
};
|
|
8
|
+
export declare const createAdSlot: (name: SlotName, options?: CreateSlotOptions) => HTMLElement;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { adSizes } from './ad-sizes';
|
|
2
|
+
const adSlotIdPrefix = 'dfp-ad--';
|
|
3
|
+
const commonSizeMappings = {
|
|
4
|
+
mobile: [
|
|
5
|
+
adSizes.outOfPage,
|
|
6
|
+
adSizes.empty,
|
|
7
|
+
adSizes.outstreamMobile,
|
|
8
|
+
adSizes.mpu,
|
|
9
|
+
adSizes.googleCard,
|
|
10
|
+
adSizes.fluid,
|
|
11
|
+
],
|
|
12
|
+
phablet: [
|
|
13
|
+
adSizes.outOfPage,
|
|
14
|
+
adSizes.empty,
|
|
15
|
+
adSizes.outstreamMobile,
|
|
16
|
+
adSizes.mpu,
|
|
17
|
+
adSizes.googleCard,
|
|
18
|
+
adSizes.fluid,
|
|
19
|
+
],
|
|
20
|
+
desktop: [
|
|
21
|
+
adSizes.outOfPage,
|
|
22
|
+
adSizes.empty,
|
|
23
|
+
adSizes.mpu,
|
|
24
|
+
adSizes.googleCard,
|
|
25
|
+
adSizes.fluid,
|
|
26
|
+
],
|
|
27
|
+
};
|
|
28
|
+
/*
|
|
29
|
+
|
|
30
|
+
mark: 432b3a46-90c1-4573-90d3-2400b51af8d0
|
|
31
|
+
|
|
32
|
+
The ad sizes which are hardcoded here are also hardcoded in the source code of
|
|
33
|
+
dotcom-rendering.
|
|
34
|
+
|
|
35
|
+
If/when this file is modified, please make sure that updates, if any, are reported to DCR.
|
|
36
|
+
|
|
37
|
+
TODO use a map type??
|
|
38
|
+
want to assert that values are of type AdSlotConfig
|
|
39
|
+
*/
|
|
40
|
+
const adSlotConfigs = {
|
|
41
|
+
im: {
|
|
42
|
+
label: false,
|
|
43
|
+
refresh: false,
|
|
44
|
+
sizeMappings: {
|
|
45
|
+
mobile: [
|
|
46
|
+
adSizes.outOfPage,
|
|
47
|
+
adSizes.empty,
|
|
48
|
+
adSizes.inlineMerchandising,
|
|
49
|
+
adSizes.fluid,
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
'high-merch': {
|
|
54
|
+
label: false,
|
|
55
|
+
refresh: false,
|
|
56
|
+
name: 'merchandising-high',
|
|
57
|
+
sizeMappings: {
|
|
58
|
+
mobile: [
|
|
59
|
+
adSizes.outOfPage,
|
|
60
|
+
adSizes.empty,
|
|
61
|
+
adSizes.merchandisingHigh,
|
|
62
|
+
adSizes.fluid,
|
|
63
|
+
],
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
'high-merch-lucky': {
|
|
67
|
+
label: false,
|
|
68
|
+
refresh: false,
|
|
69
|
+
name: 'merchandising-high-lucky',
|
|
70
|
+
sizeMappings: {
|
|
71
|
+
mobile: [adSizes.outOfPage, adSizes.empty, adSizes.fluid],
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
'high-merch-paid': {
|
|
75
|
+
label: false,
|
|
76
|
+
refresh: false,
|
|
77
|
+
name: 'merchandising-high',
|
|
78
|
+
sizeMappings: {
|
|
79
|
+
mobile: [
|
|
80
|
+
adSizes.outOfPage,
|
|
81
|
+
adSizes.empty,
|
|
82
|
+
adSizes.merchandisingHighAdFeature,
|
|
83
|
+
adSizes.fluid,
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
inline: {
|
|
88
|
+
sizeMappings: commonSizeMappings,
|
|
89
|
+
},
|
|
90
|
+
mostpop: {
|
|
91
|
+
sizeMappings: commonSizeMappings,
|
|
92
|
+
},
|
|
93
|
+
comments: {
|
|
94
|
+
sizeMappings: commonSizeMappings,
|
|
95
|
+
},
|
|
96
|
+
'top-above-nav': {
|
|
97
|
+
sizeMappings: {
|
|
98
|
+
mobile: [
|
|
99
|
+
adSizes.outOfPage,
|
|
100
|
+
adSizes.empty,
|
|
101
|
+
adSizes.fabric,
|
|
102
|
+
adSizes.outstreamMobile,
|
|
103
|
+
adSizes.mpu,
|
|
104
|
+
adSizes.fluid,
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
carrot: {
|
|
109
|
+
label: false,
|
|
110
|
+
refresh: false,
|
|
111
|
+
name: 'carrot',
|
|
112
|
+
sizeMappings: {
|
|
113
|
+
mobile: [adSizes.fluid],
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
epic: {
|
|
117
|
+
label: false,
|
|
118
|
+
refresh: false,
|
|
119
|
+
name: 'epic',
|
|
120
|
+
sizeMappings: {
|
|
121
|
+
mobile: [adSizes.fluid],
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
'mobile-sticky': {
|
|
125
|
+
label: true,
|
|
126
|
+
refresh: true,
|
|
127
|
+
name: 'mobile-sticky',
|
|
128
|
+
sizeMappings: {
|
|
129
|
+
mobile: [adSizes.mobilesticky],
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
Returns an adSlot HTMLElement which is the main DFP slot.
|
|
135
|
+
|
|
136
|
+
Insert that element as siblings at the place you want adverts to appear.
|
|
137
|
+
|
|
138
|
+
Note that for the DFP slot to be filled by GTP, you'll have to
|
|
139
|
+
use addSlot from add-slot.js
|
|
140
|
+
*/
|
|
141
|
+
const createAdSlotElement = (name, attrs, classes) => {
|
|
142
|
+
const id = `${adSlotIdPrefix}${name}`;
|
|
143
|
+
// 3562dc07-78e9-4507-b922-78b979d4c5cb
|
|
144
|
+
if (window.guardian.config?.isDotcomRendering && name === 'top-above-nav') {
|
|
145
|
+
// This is to prevent a problem that appeared with DCR.
|
|
146
|
+
// We are simply making sure that if we are about to
|
|
147
|
+
// introduce dfp-ad--top-above-nav then there isn't already one.
|
|
148
|
+
const node = document.getElementById(id);
|
|
149
|
+
if (node?.parentNode) {
|
|
150
|
+
const pnode = node.parentNode;
|
|
151
|
+
console.log(`warning: cleaning up dom node id: dfp-ad--${name}`);
|
|
152
|
+
pnode.removeChild(node);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// The 'main' adSlot
|
|
156
|
+
const adSlot = document.createElement('div');
|
|
157
|
+
adSlot.id = id;
|
|
158
|
+
adSlot.className = `js-ad-slot ad-slot ${classes.join(' ')}`;
|
|
159
|
+
adSlot.setAttribute('data-link-name', `ad slot ${name}`);
|
|
160
|
+
adSlot.setAttribute('data-name', name);
|
|
161
|
+
adSlot.setAttribute('aria-hidden', 'true');
|
|
162
|
+
Object.entries(attrs).forEach(([k, v]) => adSlot.setAttribute(k, v));
|
|
163
|
+
return adSlot;
|
|
164
|
+
};
|
|
165
|
+
/**
|
|
166
|
+
* Split class names and prefix all with ad-slot--${className}
|
|
167
|
+
*/
|
|
168
|
+
const createClasses = (slotName, classes) => [...(classes?.split(' ') ?? []), slotName].map((className) => `ad-slot--${className}`);
|
|
169
|
+
/**
|
|
170
|
+
* Given default size mappings and additional size mappings from
|
|
171
|
+
* the createAdSlot options parameter.
|
|
172
|
+
*
|
|
173
|
+
* 1. Check that the options size mappings use known device names
|
|
174
|
+
* 2. If so concat the size mappings
|
|
175
|
+
*
|
|
176
|
+
*/
|
|
177
|
+
const concatSizeMappings = (defaultSizeMappings, optionSizeMappings) => {
|
|
178
|
+
if (!optionSizeMappings)
|
|
179
|
+
return defaultSizeMappings;
|
|
180
|
+
const concatenatedSizeMappings = { ...defaultSizeMappings };
|
|
181
|
+
const optionDevices = Object.keys(optionSizeMappings); // ['mobile', 'desktop']
|
|
182
|
+
for (let i = 0; i < optionDevices.length; i++) {
|
|
183
|
+
const device = optionDevices[i];
|
|
184
|
+
if (optionSizeMappings[device] && defaultSizeMappings[device]) {
|
|
185
|
+
const optionSizeMappingsForDevice = optionSizeMappings[device];
|
|
186
|
+
const defaultSizeMappingsForDevice = defaultSizeMappings[device];
|
|
187
|
+
if (defaultSizeMappingsForDevice && optionSizeMappingsForDevice) {
|
|
188
|
+
// TODO can we do concatenatedSizeMappings[device]?.concat ?
|
|
189
|
+
concatenatedSizeMappings[device] = (concatenatedSizeMappings[device] ?? []).concat(optionSizeMappingsForDevice);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return concatenatedSizeMappings;
|
|
194
|
+
};
|
|
195
|
+
/**
|
|
196
|
+
* Convert size mappings to a string that will be added to the ad slot
|
|
197
|
+
* data attributes.
|
|
198
|
+
*
|
|
199
|
+
* e.g. { desktop: [[320,250], [320, 280]] } => { desktop: '320,250|320,280' }
|
|
200
|
+
*
|
|
201
|
+
*/
|
|
202
|
+
const covertSizeMappingsToStrings = (sizeMappings) => Object.entries(sizeMappings).reduce((result, [device, sizes]) => {
|
|
203
|
+
result[device] = sizes.join('|');
|
|
204
|
+
return result;
|
|
205
|
+
}, {});
|
|
206
|
+
/**
|
|
207
|
+
* Prefix all object keys with data-${key}
|
|
208
|
+
*/
|
|
209
|
+
const createDataAttributes = (attrs) => Object.entries(attrs).reduce((result, [key, value]) => {
|
|
210
|
+
result[`data-${key}`] = value;
|
|
211
|
+
return result;
|
|
212
|
+
}, {});
|
|
213
|
+
export const createAdSlot = (name, options = {}) => {
|
|
214
|
+
const adSlotConfig = adSlotConfigs[name];
|
|
215
|
+
const slotName = options.name ?? adSlotConfig.name ?? name;
|
|
216
|
+
const sizeMappings = concatSizeMappings(adSlotConfig.sizeMappings, options.sizes);
|
|
217
|
+
const attributes = covertSizeMappingsToStrings(sizeMappings);
|
|
218
|
+
if (adSlotConfig.label === false) {
|
|
219
|
+
attributes.label = 'false';
|
|
220
|
+
}
|
|
221
|
+
if (adSlotConfig.refresh === false) {
|
|
222
|
+
attributes.refresh = 'false';
|
|
223
|
+
}
|
|
224
|
+
return createAdSlotElement(slotName, createDataAttributes(attributes), createClasses(slotName, options.classes));
|
|
225
|
+
};
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export { remarketing } from './third-party-tags/remarketing';
|
|
|
7
7
|
export { EventTimer } from './event-timer';
|
|
8
8
|
export { bypassCommercialMetricsSampling, initCommercialMetrics, } from './send-commercial-metrics';
|
|
9
9
|
export type { ThirdPartyTag } from './types';
|
|
10
|
-
export { adSizes, getAdSize,
|
|
10
|
+
export { adSizes, getAdSize, slotSizeMappings } from './ad-sizes';
|
|
11
11
|
export type { SizeKeys, AdSizeString, AdSize } from './ad-sizes';
|
|
12
12
|
export { isAdBlockInUse } from './detect-ad-blocker';
|
|
13
13
|
export { clearPermutiveSegments, getPermutiveSegments, getPermutivePFPSegments, } from './permutive';
|
package/dist/esm/index.js
CHANGED
|
@@ -7,7 +7,7 @@ export { inizio } from './third-party-tags/inizio';
|
|
|
7
7
|
export { remarketing } from './third-party-tags/remarketing';
|
|
8
8
|
export { EventTimer } from './event-timer';
|
|
9
9
|
export { bypassCommercialMetricsSampling, initCommercialMetrics, } from './send-commercial-metrics';
|
|
10
|
-
export { adSizes, getAdSize,
|
|
10
|
+
export { adSizes, getAdSize, slotSizeMappings } from './ad-sizes';
|
|
11
11
|
export { isAdBlockInUse } from './detect-ad-blocker';
|
|
12
12
|
export { clearPermutiveSegments, getPermutiveSegments, getPermutivePFPSegments, } from './permutive';
|
|
13
13
|
export { initTrackScrollDepth } from './track-scroll-depth';
|
package/dist/esm/types.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export declare type GuardianAnalyticsConfig = {
|
|
|
23
23
|
};
|
|
24
24
|
export declare type GuardianWindowConfig = {
|
|
25
25
|
googleAnalytics?: GuardianAnalyticsConfig;
|
|
26
|
+
isDotcomRendering?: boolean;
|
|
26
27
|
};
|
|
27
28
|
export declare type GoogleTagParams = unknown;
|
|
28
29
|
export declare type GoogleTrackConversionObject = {
|