@guardian/commercial-core 4.4.0 → 4.7.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,3 +1,4 @@
1
+ import type { Breakpoint } from './lib/breakpoint';
1
2
  declare type AdSizeString = 'fluid' | `${number},${number}`;
2
3
  /**
3
4
  * Store ad sizes in a way that is compatible with google-tag but also accessible via
@@ -24,9 +25,8 @@ declare class AdSize extends Array<number> {
24
25
  get width(): number;
25
26
  get height(): number;
26
27
  }
27
- declare type SizeKeys = '160x600' | '300x1050' | '300x250' | '300x600' | '728x90' | '970x250' | 'billboard' | 'empty' | 'fabric' | 'fluid' | 'googleCard' | 'halfPage' | 'inlineMerchandising' | 'leaderboard' | 'merchandising' | 'merchandisingHigh' | 'merchandisingHighAdFeature' | 'mobilesticky' | 'mpu' | 'outOfPage' | 'outstreamDesktop' | 'outstreamGoogleDesktop' | 'outstreamMobile' | 'portrait' | 'skyscraper';
28
+ declare type SizeKeys = '160x600' | '300x1050' | '300x250' | '300x600' | '728x90' | '970x250' | 'billboard' | 'empty' | 'fabric' | 'fluid' | 'googleCard' | 'halfPage' | 'inlineMerchandising' | 'leaderboard' | 'merchandising' | 'merchandisingHigh' | 'merchandisingHighAdFeature' | 'mobilesticky' | 'mpu' | 'outOfPage' | 'outstreamDesktop' | 'outstreamGoogleDesktop' | 'outstreamMobile' | 'portrait' | 'skyscraper' | 'cascade';
28
29
  declare type SlotName = 'right' | 'comments' | 'top-above-nav' | 'mostpop' | 'merchandising' | 'merchandising-high' | 'merchandising-high-lucky' | 'survey' | 'im' | 'inline' | 'mostpop' | 'comments' | 'top-above-nav' | 'carrot' | 'epic' | 'mobile-sticky' | 'crossword-banner';
29
- declare type Breakpoint = 'mobile' | 'desktop' | 'phablet' | 'tablet';
30
30
  declare type SizeMapping = Partial<Record<Breakpoint, AdSize[]>>;
31
31
  declare type SlotSizeMappings = Record<SlotName, SizeMapping>;
32
32
  declare const createAdSize: (width: number, height: number) => AdSize;
@@ -62,6 +62,7 @@ const adSizesPartial = {
62
62
  outstreamDesktop: createAdSize(620, 350),
63
63
  outstreamGoogleDesktop: createAdSize(550, 310),
64
64
  outstreamMobile: createAdSize(300, 197),
65
+ cascade: createAdSize(940, 230),
65
66
  };
66
67
  const adSizes = {
67
68
  ...adSizesPartial,
@@ -1,9 +1,17 @@
1
- import type { AdSize } from './ad-sizes';
1
+ import type { SizeMapping } from './ad-sizes';
2
2
  declare type SlotName = 'im' | 'high-merch' | 'high-merch-lucky' | 'high-merch-paid' | 'inline' | 'mostpop' | 'comments' | 'top-above-nav' | 'carrot' | 'epic' | 'mobile-sticky';
3
3
  declare type CreateSlotOptions = {
4
4
  classes?: string;
5
5
  name?: string;
6
- sizes?: Record<string, AdSize[]>;
7
6
  };
8
- export declare const createAdSlot: (name: SlotName, options?: CreateSlotOptions) => HTMLElement;
9
- export {};
7
+ /**
8
+ * Given default size mappings and additional size mappings from
9
+ * the createAdSlot options parameter.
10
+ *
11
+ * 1. Check that the options size mappings use known device names
12
+ * 2. If so concat the size mappings
13
+ *
14
+ */
15
+ declare const concatSizeMappings: (defaultSizeMappings: SizeMapping, optionSizeMappings?: SizeMapping) => SizeMapping;
16
+ declare const createAdSlot: (name: SlotName, options?: CreateSlotOptions) => HTMLElement;
17
+ export { createAdSlot, concatSizeMappings };
@@ -1,61 +1,42 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createAdSlot = void 0;
4
- const ad_sizes_1 = require("./ad-sizes");
3
+ exports.concatSizeMappings = exports.createAdSlot = void 0;
4
+ const breakpoint_1 = require("./lib/breakpoint");
5
5
  const adSlotIdPrefix = 'dfp-ad--';
6
6
  const adSlotConfigs = {
7
7
  im: {
8
8
  label: false,
9
9
  refresh: false,
10
- sizeMappings: ad_sizes_1.slotSizeMappings['im'],
11
10
  },
12
11
  'high-merch': {
13
12
  label: false,
14
13
  refresh: false,
15
14
  name: 'merchandising-high',
16
- sizeMappings: ad_sizes_1.slotSizeMappings['merchandising-high'],
17
15
  },
18
16
  'high-merch-lucky': {
19
17
  label: false,
20
18
  refresh: false,
21
19
  name: 'merchandising-high-lucky',
22
- sizeMappings: ad_sizes_1.slotSizeMappings['merchandising-high-lucky'],
23
20
  },
24
21
  'high-merch-paid': {
25
22
  label: false,
26
23
  refresh: false,
27
24
  name: 'merchandising-high',
28
- sizeMappings: ad_sizes_1.slotSizeMappings['merchandising-high'],
29
- },
30
- inline: {
31
- sizeMappings: ad_sizes_1.slotSizeMappings['inline'],
32
- },
33
- mostpop: {
34
- sizeMappings: ad_sizes_1.slotSizeMappings['mostpop'],
35
- },
36
- comments: {
37
- sizeMappings: ad_sizes_1.slotSizeMappings['comments'],
38
- },
39
- 'top-above-nav': {
40
- sizeMappings: ad_sizes_1.slotSizeMappings['top-above-nav'],
41
25
  },
42
26
  carrot: {
43
27
  label: false,
44
28
  refresh: false,
45
29
  name: 'carrot',
46
- sizeMappings: ad_sizes_1.slotSizeMappings['merchandising-high'],
47
30
  },
48
31
  epic: {
49
32
  label: false,
50
33
  refresh: false,
51
34
  name: 'epic',
52
- sizeMappings: ad_sizes_1.slotSizeMappings['epic'],
53
35
  },
54
36
  'mobile-sticky': {
55
37
  label: true,
56
38
  refresh: true,
57
39
  name: 'mobile-sticky',
58
- sizeMappings: ad_sizes_1.slotSizeMappings['mobile-sticky'],
59
40
  },
60
41
  };
61
42
  /**
@@ -84,10 +65,10 @@ const createAdSlotElement = (name, attrs, classes) => {
84
65
  const adSlot = document.createElement('div');
85
66
  adSlot.id = id;
86
67
  adSlot.className = `js-ad-slot ad-slot ${classes.join(' ')}`;
87
- adSlot.setAttribute('data-link-name', `ad slot ${name}`);
88
- adSlot.setAttribute('data-name', name);
68
+ adSlot.dataset.linkName = `ad slot ${name}`;
69
+ adSlot.dataset.name = name;
89
70
  adSlot.setAttribute('aria-hidden', 'true');
90
- Object.entries(attrs).forEach(([k, v]) => adSlot.setAttribute(k, v));
71
+ Object.entries(attrs).forEach(([k, v]) => (adSlot.dataset[k] = v));
91
72
  return adSlot;
92
73
  };
93
74
  /**
@@ -102,53 +83,25 @@ const createClasses = (slotName, classes) => [...(classes?.split(' ') ?? []), sl
102
83
  * 2. If so concat the size mappings
103
84
  *
104
85
  */
105
- const concatSizeMappings = (defaultSizeMappings, optionSizeMappings) => {
106
- if (!optionSizeMappings)
107
- return defaultSizeMappings;
108
- const concatenatedSizeMappings = { ...defaultSizeMappings };
109
- const optionDevices = Object.keys(optionSizeMappings); // ['mobile', 'desktop']
110
- for (let i = 0; i < optionDevices.length; i++) {
111
- const device = optionDevices[i];
112
- if (optionSizeMappings[device] && defaultSizeMappings[device]) {
113
- const optionSizeMappingsForDevice = optionSizeMappings[device];
114
- const defaultSizeMappingsForDevice = defaultSizeMappings[device];
115
- if (defaultSizeMappingsForDevice && optionSizeMappingsForDevice) {
116
- // TODO can we do concatenatedSizeMappings[device]?.concat ?
117
- concatenatedSizeMappings[device] = (concatenatedSizeMappings[device] ?? []).concat(optionSizeMappingsForDevice);
118
- }
119
- }
86
+ const concatSizeMappings = (defaultSizeMappings, optionSizeMappings = {}) => Object.entries(optionSizeMappings).reduce((sizeMappings, [breakpoint, optionSizes]) => {
87
+ // Only perform concatenation if breakpoint is of the correct type
88
+ if ((0, breakpoint_1.isBreakpoint)(breakpoint)) {
89
+ // Concatenate the option sizes onto any existing sizes present for a given breakpoint
90
+ sizeMappings[breakpoint] = (sizeMappings[breakpoint] ?? []).concat(optionSizes);
120
91
  }
121
- return concatenatedSizeMappings;
122
- };
123
- /**
124
- * Convert size mappings to a string that will be added to the ad slot
125
- * data attributes.
126
- *
127
- * e.g. { desktop: [[320,250], [320, 280]] } => { desktop: '320,250|320,280' }
128
- *
129
- */
130
- const covertSizeMappingsToStrings = (sizeMappings) => Object.entries(sizeMappings).reduce((result, [device, sizes]) => {
131
- result[device] = sizes.join('|');
132
- return result;
133
- }, {});
134
- /**
135
- * Prefix all object keys with data-${key}
136
- */
137
- const createDataAttributes = (attrs) => Object.entries(attrs).reduce((result, [key, value]) => {
138
- result[`data-${key}`] = value;
139
- return result;
140
- }, {});
92
+ return sizeMappings;
93
+ }, { ...defaultSizeMappings });
94
+ exports.concatSizeMappings = concatSizeMappings;
141
95
  const createAdSlot = (name, options = {}) => {
142
- const adSlotConfig = adSlotConfigs[name];
96
+ const adSlotConfig = adSlotConfigs[name] ?? {};
143
97
  const slotName = options.name ?? adSlotConfig.name ?? name;
144
- const sizeMappings = concatSizeMappings(adSlotConfig.sizeMappings, options.sizes);
145
- const attributes = covertSizeMappingsToStrings(sizeMappings);
98
+ const dataAttributes = {};
146
99
  if (adSlotConfig.label === false) {
147
- attributes.label = 'false';
100
+ dataAttributes.label = 'false';
148
101
  }
149
102
  if (adSlotConfig.refresh === false) {
150
- attributes.refresh = 'false';
103
+ dataAttributes.refresh = 'false';
151
104
  }
152
- return createAdSlotElement(slotName, createDataAttributes(attributes), createClasses(slotName, options.classes));
105
+ return createAdSlotElement(slotName, dataAttributes, createClasses(slotName, options.classes));
153
106
  };
154
107
  exports.createAdSlot = createAdSlot;
@@ -8,13 +8,15 @@ export { EventTimer } from './event-timer';
8
8
  export { bypassCommercialMetricsSampling, initCommercialMetrics, } from './send-commercial-metrics';
9
9
  export type { ThirdPartyTag } from './types';
10
10
  export { adSizes, getAdSize, slotSizeMappings, createAdSize } from './ad-sizes';
11
+ export { isBreakpoint } from './lib/breakpoint';
12
+ export type { Breakpoint } from './lib/breakpoint';
11
13
  export type { SizeKeys, AdSizeString, AdSize, SizeMapping, SlotSizeMappings, SlotName, } from './ad-sizes';
12
14
  export { isAdBlockInUse } from './detect-ad-blocker';
13
15
  export { clearPermutiveSegments, getPermutiveSegments, getPermutivePFPSegments, } from './permutive';
14
16
  export { initTrackScrollDepth } from './track-scroll-depth';
15
17
  export { initTrackGpcSignal } from './track-gpc-signal';
16
18
  export { buildAdsConfigWithConsent, disabledAds } from './ad-targeting-youtube';
17
- export { createAdSlot } from './create-ad-slot';
19
+ export { createAdSlot, concatSizeMappings } from './create-ad-slot';
18
20
  export type { AdsConfig, AdsConfigBasic, AdsConfigDisabled, AdTargetingBuilder, CustomParams, } from './types';
19
21
  export * as constants from './constants';
20
22
  export type { ContentTargeting } from './targeting/content';
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.createAdSlot = exports.disabledAds = exports.buildAdsConfigWithConsent = exports.initTrackGpcSignal = exports.initTrackScrollDepth = exports.getPermutivePFPSegments = exports.getPermutiveSegments = exports.clearPermutiveSegments = exports.isAdBlockInUse = exports.createAdSize = 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;
27
+ exports.pickTargetingValues = exports.getViewportTargeting = exports.getSharedTargeting = exports.getSessionTargeting = exports.getPersonalisedTargeting = exports.getContentTargeting = exports.constants = exports.concatSizeMappings = exports.createAdSlot = exports.disabledAds = exports.buildAdsConfigWithConsent = exports.initTrackGpcSignal = exports.initTrackScrollDepth = exports.getPermutivePFPSegments = exports.getPermutiveSegments = exports.clearPermutiveSegments = exports.isAdBlockInUse = exports.isBreakpoint = exports.createAdSize = 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");
@@ -47,6 +47,8 @@ Object.defineProperty(exports, "adSizes", { enumerable: true, get: function () {
47
47
  Object.defineProperty(exports, "getAdSize", { enumerable: true, get: function () { return ad_sizes_1.getAdSize; } });
48
48
  Object.defineProperty(exports, "slotSizeMappings", { enumerable: true, get: function () { return ad_sizes_1.slotSizeMappings; } });
49
49
  Object.defineProperty(exports, "createAdSize", { enumerable: true, get: function () { return ad_sizes_1.createAdSize; } });
50
+ var breakpoint_1 = require("./lib/breakpoint");
51
+ Object.defineProperty(exports, "isBreakpoint", { enumerable: true, get: function () { return breakpoint_1.isBreakpoint; } });
50
52
  var detect_ad_blocker_1 = require("./detect-ad-blocker");
51
53
  Object.defineProperty(exports, "isAdBlockInUse", { enumerable: true, get: function () { return detect_ad_blocker_1.isAdBlockInUse; } });
52
54
  var permutive_2 = require("./permutive");
@@ -62,6 +64,7 @@ Object.defineProperty(exports, "buildAdsConfigWithConsent", { enumerable: true,
62
64
  Object.defineProperty(exports, "disabledAds", { enumerable: true, get: function () { return ad_targeting_youtube_1.disabledAds; } });
63
65
  var create_ad_slot_1 = require("./create-ad-slot");
64
66
  Object.defineProperty(exports, "createAdSlot", { enumerable: true, get: function () { return create_ad_slot_1.createAdSlot; } });
67
+ Object.defineProperty(exports, "concatSizeMappings", { enumerable: true, get: function () { return create_ad_slot_1.concatSizeMappings; } });
65
68
  exports.constants = __importStar(require("./constants"));
66
69
  var content_1 = require("./targeting/content");
67
70
  Object.defineProperty(exports, "getContentTargeting", { enumerable: true, get: function () { return content_1.getContentTargeting; } });
@@ -0,0 +1,4 @@
1
+ declare type Breakpoint = 'mobile' | 'desktop' | 'phablet' | 'tablet';
2
+ declare const isBreakpoint: (s: string) => s is Breakpoint;
3
+ export type { Breakpoint };
4
+ export { isBreakpoint };
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isBreakpoint = void 0;
4
+ const isBreakpoint = (s) => s === 'mobile' || s === 'phablet' || s === 'tablet' || s === 'desktop';
5
+ exports.isBreakpoint = isBreakpoint;
@@ -1,3 +1,4 @@
1
+ import type { Breakpoint } from './lib/breakpoint';
1
2
  declare type AdSizeString = 'fluid' | `${number},${number}`;
2
3
  /**
3
4
  * Store ad sizes in a way that is compatible with google-tag but also accessible via
@@ -24,9 +25,8 @@ declare class AdSize extends Array<number> {
24
25
  get width(): number;
25
26
  get height(): number;
26
27
  }
27
- declare type SizeKeys = '160x600' | '300x1050' | '300x250' | '300x600' | '728x90' | '970x250' | 'billboard' | 'empty' | 'fabric' | 'fluid' | 'googleCard' | 'halfPage' | 'inlineMerchandising' | 'leaderboard' | 'merchandising' | 'merchandisingHigh' | 'merchandisingHighAdFeature' | 'mobilesticky' | 'mpu' | 'outOfPage' | 'outstreamDesktop' | 'outstreamGoogleDesktop' | 'outstreamMobile' | 'portrait' | 'skyscraper';
28
+ declare type SizeKeys = '160x600' | '300x1050' | '300x250' | '300x600' | '728x90' | '970x250' | 'billboard' | 'empty' | 'fabric' | 'fluid' | 'googleCard' | 'halfPage' | 'inlineMerchandising' | 'leaderboard' | 'merchandising' | 'merchandisingHigh' | 'merchandisingHighAdFeature' | 'mobilesticky' | 'mpu' | 'outOfPage' | 'outstreamDesktop' | 'outstreamGoogleDesktop' | 'outstreamMobile' | 'portrait' | 'skyscraper' | 'cascade';
28
29
  declare type SlotName = 'right' | 'comments' | 'top-above-nav' | 'mostpop' | 'merchandising' | 'merchandising-high' | 'merchandising-high-lucky' | 'survey' | 'im' | 'inline' | 'mostpop' | 'comments' | 'top-above-nav' | 'carrot' | 'epic' | 'mobile-sticky' | 'crossword-banner';
29
- declare type Breakpoint = 'mobile' | 'desktop' | 'phablet' | 'tablet';
30
30
  declare type SizeMapping = Partial<Record<Breakpoint, AdSize[]>>;
31
31
  declare type SlotSizeMappings = Record<SlotName, SizeMapping>;
32
32
  declare const createAdSize: (width: number, height: number) => AdSize;
@@ -58,6 +58,7 @@ const adSizesPartial = {
58
58
  outstreamDesktop: createAdSize(620, 350),
59
59
  outstreamGoogleDesktop: createAdSize(550, 310),
60
60
  outstreamMobile: createAdSize(300, 197),
61
+ cascade: createAdSize(940, 230),
61
62
  };
62
63
  const adSizes = {
63
64
  ...adSizesPartial,
@@ -1,9 +1,17 @@
1
- import type { AdSize } from './ad-sizes';
1
+ import type { SizeMapping } from './ad-sizes';
2
2
  declare type SlotName = 'im' | 'high-merch' | 'high-merch-lucky' | 'high-merch-paid' | 'inline' | 'mostpop' | 'comments' | 'top-above-nav' | 'carrot' | 'epic' | 'mobile-sticky';
3
3
  declare type CreateSlotOptions = {
4
4
  classes?: string;
5
5
  name?: string;
6
- sizes?: Record<string, AdSize[]>;
7
6
  };
8
- export declare const createAdSlot: (name: SlotName, options?: CreateSlotOptions) => HTMLElement;
9
- export {};
7
+ /**
8
+ * Given default size mappings and additional size mappings from
9
+ * the createAdSlot options parameter.
10
+ *
11
+ * 1. Check that the options size mappings use known device names
12
+ * 2. If so concat the size mappings
13
+ *
14
+ */
15
+ declare const concatSizeMappings: (defaultSizeMappings: SizeMapping, optionSizeMappings?: SizeMapping) => SizeMapping;
16
+ declare const createAdSlot: (name: SlotName, options?: CreateSlotOptions) => HTMLElement;
17
+ export { createAdSlot, concatSizeMappings };
@@ -1,58 +1,39 @@
1
- import { slotSizeMappings } from './ad-sizes';
1
+ import { isBreakpoint } from './lib/breakpoint';
2
2
  const adSlotIdPrefix = 'dfp-ad--';
3
3
  const adSlotConfigs = {
4
4
  im: {
5
5
  label: false,
6
6
  refresh: false,
7
- sizeMappings: slotSizeMappings['im'],
8
7
  },
9
8
  'high-merch': {
10
9
  label: false,
11
10
  refresh: false,
12
11
  name: 'merchandising-high',
13
- sizeMappings: slotSizeMappings['merchandising-high'],
14
12
  },
15
13
  'high-merch-lucky': {
16
14
  label: false,
17
15
  refresh: false,
18
16
  name: 'merchandising-high-lucky',
19
- sizeMappings: slotSizeMappings['merchandising-high-lucky'],
20
17
  },
21
18
  'high-merch-paid': {
22
19
  label: false,
23
20
  refresh: false,
24
21
  name: 'merchandising-high',
25
- sizeMappings: slotSizeMappings['merchandising-high'],
26
- },
27
- inline: {
28
- sizeMappings: slotSizeMappings['inline'],
29
- },
30
- mostpop: {
31
- sizeMappings: slotSizeMappings['mostpop'],
32
- },
33
- comments: {
34
- sizeMappings: slotSizeMappings['comments'],
35
- },
36
- 'top-above-nav': {
37
- sizeMappings: slotSizeMappings['top-above-nav'],
38
22
  },
39
23
  carrot: {
40
24
  label: false,
41
25
  refresh: false,
42
26
  name: 'carrot',
43
- sizeMappings: slotSizeMappings['merchandising-high'],
44
27
  },
45
28
  epic: {
46
29
  label: false,
47
30
  refresh: false,
48
31
  name: 'epic',
49
- sizeMappings: slotSizeMappings['epic'],
50
32
  },
51
33
  'mobile-sticky': {
52
34
  label: true,
53
35
  refresh: true,
54
36
  name: 'mobile-sticky',
55
- sizeMappings: slotSizeMappings['mobile-sticky'],
56
37
  },
57
38
  };
58
39
  /**
@@ -81,10 +62,10 @@ const createAdSlotElement = (name, attrs, classes) => {
81
62
  const adSlot = document.createElement('div');
82
63
  adSlot.id = id;
83
64
  adSlot.className = `js-ad-slot ad-slot ${classes.join(' ')}`;
84
- adSlot.setAttribute('data-link-name', `ad slot ${name}`);
85
- adSlot.setAttribute('data-name', name);
65
+ adSlot.dataset.linkName = `ad slot ${name}`;
66
+ adSlot.dataset.name = name;
86
67
  adSlot.setAttribute('aria-hidden', 'true');
87
- Object.entries(attrs).forEach(([k, v]) => adSlot.setAttribute(k, v));
68
+ Object.entries(attrs).forEach(([k, v]) => (adSlot.dataset[k] = v));
88
69
  return adSlot;
89
70
  };
90
71
  /**
@@ -99,52 +80,24 @@ const createClasses = (slotName, classes) => [...(classes?.split(' ') ?? []), sl
99
80
  * 2. If so concat the size mappings
100
81
  *
101
82
  */
102
- const concatSizeMappings = (defaultSizeMappings, optionSizeMappings) => {
103
- if (!optionSizeMappings)
104
- return defaultSizeMappings;
105
- const concatenatedSizeMappings = { ...defaultSizeMappings };
106
- const optionDevices = Object.keys(optionSizeMappings); // ['mobile', 'desktop']
107
- for (let i = 0; i < optionDevices.length; i++) {
108
- const device = optionDevices[i];
109
- if (optionSizeMappings[device] && defaultSizeMappings[device]) {
110
- const optionSizeMappingsForDevice = optionSizeMappings[device];
111
- const defaultSizeMappingsForDevice = defaultSizeMappings[device];
112
- if (defaultSizeMappingsForDevice && optionSizeMappingsForDevice) {
113
- // TODO can we do concatenatedSizeMappings[device]?.concat ?
114
- concatenatedSizeMappings[device] = (concatenatedSizeMappings[device] ?? []).concat(optionSizeMappingsForDevice);
115
- }
116
- }
83
+ const concatSizeMappings = (defaultSizeMappings, optionSizeMappings = {}) => Object.entries(optionSizeMappings).reduce((sizeMappings, [breakpoint, optionSizes]) => {
84
+ // Only perform concatenation if breakpoint is of the correct type
85
+ if (isBreakpoint(breakpoint)) {
86
+ // Concatenate the option sizes onto any existing sizes present for a given breakpoint
87
+ sizeMappings[breakpoint] = (sizeMappings[breakpoint] ?? []).concat(optionSizes);
117
88
  }
118
- return concatenatedSizeMappings;
119
- };
120
- /**
121
- * Convert size mappings to a string that will be added to the ad slot
122
- * data attributes.
123
- *
124
- * e.g. { desktop: [[320,250], [320, 280]] } => { desktop: '320,250|320,280' }
125
- *
126
- */
127
- const covertSizeMappingsToStrings = (sizeMappings) => Object.entries(sizeMappings).reduce((result, [device, sizes]) => {
128
- result[device] = sizes.join('|');
129
- return result;
130
- }, {});
131
- /**
132
- * Prefix all object keys with data-${key}
133
- */
134
- const createDataAttributes = (attrs) => Object.entries(attrs).reduce((result, [key, value]) => {
135
- result[`data-${key}`] = value;
136
- return result;
137
- }, {});
138
- export const createAdSlot = (name, options = {}) => {
139
- const adSlotConfig = adSlotConfigs[name];
89
+ return sizeMappings;
90
+ }, { ...defaultSizeMappings });
91
+ const createAdSlot = (name, options = {}) => {
92
+ const adSlotConfig = adSlotConfigs[name] ?? {};
140
93
  const slotName = options.name ?? adSlotConfig.name ?? name;
141
- const sizeMappings = concatSizeMappings(adSlotConfig.sizeMappings, options.sizes);
142
- const attributes = covertSizeMappingsToStrings(sizeMappings);
94
+ const dataAttributes = {};
143
95
  if (adSlotConfig.label === false) {
144
- attributes.label = 'false';
96
+ dataAttributes.label = 'false';
145
97
  }
146
98
  if (adSlotConfig.refresh === false) {
147
- attributes.refresh = 'false';
99
+ dataAttributes.refresh = 'false';
148
100
  }
149
- return createAdSlotElement(slotName, createDataAttributes(attributes), createClasses(slotName, options.classes));
101
+ return createAdSlotElement(slotName, dataAttributes, createClasses(slotName, options.classes));
150
102
  };
103
+ export { createAdSlot, concatSizeMappings };
@@ -8,13 +8,15 @@ export { EventTimer } from './event-timer';
8
8
  export { bypassCommercialMetricsSampling, initCommercialMetrics, } from './send-commercial-metrics';
9
9
  export type { ThirdPartyTag } from './types';
10
10
  export { adSizes, getAdSize, slotSizeMappings, createAdSize } from './ad-sizes';
11
+ export { isBreakpoint } from './lib/breakpoint';
12
+ export type { Breakpoint } from './lib/breakpoint';
11
13
  export type { SizeKeys, AdSizeString, AdSize, SizeMapping, SlotSizeMappings, SlotName, } from './ad-sizes';
12
14
  export { isAdBlockInUse } from './detect-ad-blocker';
13
15
  export { clearPermutiveSegments, getPermutiveSegments, getPermutivePFPSegments, } from './permutive';
14
16
  export { initTrackScrollDepth } from './track-scroll-depth';
15
17
  export { initTrackGpcSignal } from './track-gpc-signal';
16
18
  export { buildAdsConfigWithConsent, disabledAds } from './ad-targeting-youtube';
17
- export { createAdSlot } from './create-ad-slot';
19
+ export { createAdSlot, concatSizeMappings } from './create-ad-slot';
18
20
  export type { AdsConfig, AdsConfigBasic, AdsConfigDisabled, AdTargetingBuilder, CustomParams, } from './types';
19
21
  export * as constants from './constants';
20
22
  export type { ContentTargeting } from './targeting/content';
package/dist/esm/index.js CHANGED
@@ -8,12 +8,13 @@ export { remarketing } from './third-party-tags/remarketing';
8
8
  export { EventTimer } from './event-timer';
9
9
  export { bypassCommercialMetricsSampling, initCommercialMetrics, } from './send-commercial-metrics';
10
10
  export { adSizes, getAdSize, slotSizeMappings, createAdSize } from './ad-sizes';
11
+ export { isBreakpoint } from './lib/breakpoint';
11
12
  export { isAdBlockInUse } from './detect-ad-blocker';
12
13
  export { clearPermutiveSegments, getPermutiveSegments, getPermutivePFPSegments, } from './permutive';
13
14
  export { initTrackScrollDepth } from './track-scroll-depth';
14
15
  export { initTrackGpcSignal } from './track-gpc-signal';
15
16
  export { buildAdsConfigWithConsent, disabledAds } from './ad-targeting-youtube';
16
- export { createAdSlot } from './create-ad-slot';
17
+ export { createAdSlot, concatSizeMappings } from './create-ad-slot';
17
18
  import * as constants_1 from './constants';
18
19
  export { constants_1 as constants };
19
20
  export { getContentTargeting } from './targeting/content';
@@ -0,0 +1,4 @@
1
+ declare type Breakpoint = 'mobile' | 'desktop' | 'phablet' | 'tablet';
2
+ declare const isBreakpoint: (s: string) => s is Breakpoint;
3
+ export type { Breakpoint };
4
+ export { isBreakpoint };
@@ -0,0 +1,2 @@
1
+ const isBreakpoint = (s) => s === 'mobile' || s === 'phablet' || s === 'tablet' || s === 'desktop';
2
+ export { isBreakpoint };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guardian/commercial-core",
3
- "version": "4.4.0",
3
+ "version": "4.7.0",
4
4
  "description": "Guardian advertising business logic",
5
5
  "homepage": "https://github.com/guardian/commercial-core#readme",
6
6
  "bugs": {