@folklore/ads 0.0.124 → 0.0.127

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.js DELETED
@@ -1,1316 +0,0 @@
1
- 'use strict';
2
-
3
- var PropTypes = require('prop-types');
4
- var classNames = require('classnames');
5
- var React = require('react');
6
- var isArray = require('lodash/isArray');
7
- var isObject = require('lodash/isObject');
8
- var sortBy = require('lodash/sortBy');
9
- var uniqBy = require('lodash/uniqBy');
10
- var debounce = require('lodash/debounce');
11
- var createDebug = require('debug');
12
- var EventEmitter = require('wolfy87-eventemitter');
13
- var jsxRuntime = require('react/jsx-runtime');
14
- var utils = require('@folklore/utils');
15
- var hooks = require('@folklore/hooks');
16
- var tracking = require('@folklore/tracking');
17
-
18
- const adPath = PropTypes.string;
19
- const adSize = PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.number), PropTypes.arrayOf(PropTypes.string), PropTypes.string, PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.number), PropTypes.arrayOf(PropTypes.string), PropTypes.string]))]);
20
- const adSizeMapping = PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.number), adSize])));
21
- const adViewports = PropTypes.objectOf(PropTypes.arrayOf(PropTypes.number));
22
- const adSlot = PropTypes.shape({
23
- size: adSize,
24
- sizeMapping: PropTypes.objectOf(adSize)
25
- });
26
- const adSlots = PropTypes.objectOf(adSlot);
27
- const adTargeting = PropTypes.shape({
28
- domain: PropTypes.string
29
- });
30
-
31
- var propTypes = /*#__PURE__*/Object.freeze({
32
- __proto__: null,
33
- adPath: adPath,
34
- adSize: adSize,
35
- adSizeMapping: adSizeMapping,
36
- adSlot: adSlot,
37
- adSlots: adSlots,
38
- adTargeting: adTargeting,
39
- adViewports: adViewports
40
- });
41
-
42
- function normalizeAdSizes(size) {
43
- if (size === null) {
44
- return [];
45
- }
46
- if (isArray(size) && size.length > 0 && isArray(size[0])) {
47
- return size;
48
- }
49
- return [size];
50
- }
51
- function getAdSizes(sizes) {
52
- return uniqBy(sizes, size => isArray(size) ? size.join('x') : size);
53
- }
54
- function getMinimumAdSize(sizes) {
55
- return getAdSizes(sizes).filter(size => size !== 'fluid').reduce((minimumSize, size) => ({
56
- width: Math.min(minimumSize.width, size[0]),
57
- height: Math.min(minimumSize.height, size[1])
58
- }), {
59
- width: Infinity,
60
- height: Infinity
61
- });
62
- }
63
- function sizeFitsInViewport(size, viewport) {
64
- return size === 'fluid' && viewport[0] > 600 || size !== 'fluid' && (viewport[0] === 0 || size[0] <= viewport[0]) && (viewport[1] === 0 || size[1] <= viewport[1]);
65
- }
66
- function getSortedViewports(viewports) {
67
- return sortBy(Object.keys(viewports).map(name => ({
68
- name,
69
- size: viewports[name]
70
- })), [viewport => viewport.size[0]]).reverse();
71
- }
72
- function buildSizeMappingFromViewports(sizeMapping, viewports) {
73
- return isObject(sizeMapping) && !isArray(sizeMapping) ? getSortedViewports(viewports).reduce((newSizeMapping, {
74
- name,
75
- size: viewPortSize
76
- }) => typeof sizeMapping[name] !== 'undefined' ? [...newSizeMapping, [viewPortSize, sizeMapping[name]]] : newSizeMapping, []) : sizeMapping;
77
- }
78
- function buildSizeMappingFromSizes(sizes, viewports) {
79
- return getSortedViewports(viewports).map(({
80
- name,
81
- size: viewPortSize
82
- }) => [viewPortSize, sizes.filter(size => sizeFitsInViewport(size, name === 'default' ? [300, 300] : viewPortSize))]);
83
- }
84
- function getSizeMappingFromSlot({
85
- size: allSizes = [],
86
- sizeMapping = null
87
- }, viewports) {
88
- if (sizeMapping === true) {
89
- return buildSizeMappingFromSizes(allSizes, viewports);
90
- }
91
- return sizeMapping !== null ? buildSizeMappingFromViewports(sizeMapping, viewports) : null;
92
- }
93
- function getSizeFromSizeMapping(sizeMapping) {
94
- if (sizeMapping === null) {
95
- return null;
96
- }
97
- return getAdSizes(sizeMapping.reduce((allSizes, sizeMap) => [...allSizes, ...sizeMap[1]], [])).sort((a, b) => {
98
- if (a === 'fluid') {
99
- return 1;
100
- }
101
- if (b === 'fluid') {
102
- return -1;
103
- }
104
- if (a[0] === b[0]) {
105
- return a[1] > b[1] ? 1 : -1;
106
- }
107
- return a[0] > b[0] ? 1 : -1;
108
- });
109
- }
110
-
111
- class AdSlot extends EventEmitter {
112
- constructor(id, path, size, opts = {}) {
113
- super();
114
- this.options = {
115
- sizeMapping: null,
116
- targeting: {},
117
- categoryExclusions: [],
118
- visible: true,
119
- ...opts
120
- };
121
- const {
122
- visible
123
- } = this.options;
124
- this.elementId = id;
125
- this.adPath = path;
126
- this.adSize = size;
127
- this.adSlot = null;
128
- this.visible = visible;
129
- this.wasVisible = visible;
130
- this.rendered = false;
131
- this.displayed = false;
132
- this.viewable = false;
133
- this.destroyed = false;
134
- this.renderEvent = null;
135
- this.refreshDisabled = false;
136
- }
137
- updateAdSlot() {
138
- const {
139
- adSlot
140
- } = this;
141
- const {
142
- targeting = {},
143
- categoryExclusions = [],
144
- sizeMapping = null
145
- } = this.options;
146
-
147
- // Size mapping
148
- if (sizeMapping !== null) {
149
- adSlot.defineSizeMapping(sizeMapping);
150
- }
151
-
152
- // Targeting
153
- const targetingKeys = targeting !== null ? Object.keys(targeting) : null;
154
- if (targetingKeys !== null && targetingKeys.length > 0) {
155
- targetingKeys.forEach(key => {
156
- adSlot.setTargeting(key, targeting[key]);
157
- });
158
- } else {
159
- adSlot.clearTargeting();
160
- }
161
-
162
- // Category exclusions
163
- if (categoryExclusions !== null && categoryExclusions.length > 0) {
164
- categoryExclusions.forEach(exclusion => {
165
- adSlot.setCategoryExclusion(exclusion);
166
- });
167
- } else {
168
- adSlot.clearCategoryExclusions();
169
- }
170
- }
171
- setAdSlot(slot) {
172
- this.adSlot = slot;
173
- if (slot !== null) {
174
- this.updateAdSlot();
175
- }
176
- return this;
177
- }
178
- setRenderEvent(event) {
179
- this.renderEvent = event;
180
- this.rendered = true;
181
- this.emit('render', event, this);
182
- return this;
183
- }
184
- setViewable(viewable) {
185
- this.viewable = viewable;
186
- }
187
- setDisplayed(displayed) {
188
- this.displayed = displayed;
189
- return this;
190
- }
191
-
192
- // eslint-disable-next-line
193
- setVisible(visible) {
194
- this.visible = visible;
195
- if (!this.wasVisible && visible) {
196
- this.wasVisible = visible;
197
- }
198
- this.emit('visible', visible, this);
199
- return this;
200
- }
201
- setRefreshDisabled() {
202
- this.refreshDisabled = true;
203
- }
204
- setTargeting(targeting) {
205
- if (this.adSlot !== null) {
206
- this.adSlot.updateTargetingFromMap(targeting);
207
- } else {
208
- this.options.targeting = targeting;
209
- }
210
- }
211
- destroy() {
212
- if (this.destroyed) {
213
- return;
214
- }
215
- this.emit('destroy', this);
216
- this.removeAllListeners();
217
- this.adSlot = null;
218
- this.rendered = false;
219
- this.displayed = false;
220
- this.renderEvent = null;
221
- this.destroyed = true;
222
- }
223
- getElementId() {
224
- return this.elementId;
225
- }
226
- getAdSlot() {
227
- return this.adSlot;
228
- }
229
- getAdPath() {
230
- return this.adPath;
231
- }
232
- getAdSize() {
233
- return this.adSize;
234
- }
235
- getTargeting() {
236
- const {
237
- targeting
238
- } = this.options;
239
- return targeting;
240
- }
241
- isVisible() {
242
- return this.visible;
243
- }
244
- isDefined() {
245
- return this.adSlot !== null;
246
- }
247
- isDisplayed() {
248
- return this.displayed;
249
- }
250
- isViewable() {
251
- return this.viewable;
252
- }
253
- isRendered() {
254
- return this.rendered;
255
- }
256
- isRefreshDisabled() {
257
- return this.refreshDisabled;
258
- }
259
- isDestroyed() {
260
- return this.destroyed;
261
- }
262
- isEmpty() {
263
- if (this.renderEvent === null) {
264
- return false;
265
- }
266
- return this.renderEvent.isEmpty;
267
- }
268
- canBeDisplayed() {
269
- return this.isDefined() && !this.isDisplayed();
270
- }
271
- getRenderedSize() {
272
- if (this.renderEvent === null) {
273
- return null;
274
- }
275
- const {
276
- size = null
277
- } = this.renderEvent;
278
- return size !== null ? {
279
- width: size[0],
280
- height: size[1],
281
- isFluid: size[0] === 0 && size[1] === 0
282
- } : null;
283
- }
284
- }
285
-
286
- /* globals refreshDisabledLineItems: [] */
287
- const debug$1 = createDebug('folklore:ads');
288
- class AdsManager extends EventEmitter {
289
- // static index = 0;
290
-
291
- // static createAdId() {
292
- // const newId = `div-gpt-ad-${new Date().getTime()}-${Math.round(
293
- // Math.random() * (Math.random() * 1000),
294
- // )}-${AdsManager.index}`;
295
- // AdsManager.index += 1;
296
- // return newId;
297
- // }
298
-
299
- static ID_PREFIX = 'div-gpt-ad-';
300
- static getArticleTargeting(article) {
301
- if (article === null) {
302
- return null;
303
- }
304
- const {
305
- id,
306
- title,
307
- slug,
308
- metadata: {
309
- categories = [],
310
- authors = [],
311
- sponsors = [],
312
- safeForDistribution = true
313
- }
314
- } = article;
315
- return {
316
- title,
317
- slug,
318
- postID: id,
319
- categories: categories.map(it => it.slug),
320
- authors: authors.map(it => it.slug),
321
- sponsors: sponsors.map(it => it.name),
322
- GoogleSafeTargeting: safeForDistribution
323
- };
324
- }
325
- static getSectionTargeting(section) {
326
- return section !== null ? {
327
- section: section.slug
328
- } : null;
329
- }
330
- static getIndexTargeting(index) {
331
- return index !== null ? {
332
- index: index.slug
333
- } : null;
334
- }
335
- static getIndexItemTargeting(index, item) {
336
- return index !== null && item !== null ? {
337
- [index.id]: [item.slug]
338
- } : null;
339
- }
340
- constructor(opts = {}) {
341
- super();
342
- this.options = {
343
- disabled: false,
344
- disablePersonnalizedAds: false,
345
- disableSingleRequest: false,
346
- disableLazyLoad: false,
347
- disableVideoAds: false,
348
- autoInit: false,
349
- ...opts
350
- };
351
- this.initGpt = this.initGpt.bind(this);
352
- this.onSlotRenderEnded = this.onSlotRenderEnded.bind(this);
353
- this.onSlotImpressionViewable = this.onSlotImpressionViewable.bind(this);
354
- this.onSlotVisibleChange = this.onSlotVisibleChange.bind(this);
355
- this.disabled = this.options.disabled;
356
- this.personnalizedAdsDisabled = this.options.disablePersonnalizedAds;
357
- this.ready = false;
358
- this.enabled = false;
359
- this.googletag = typeof window !== 'undefined' ? window.googletag : {
360
- cmd: []
361
- };
362
- this.slots = [];
363
- this.index = 0;
364
- if (this.options.autoInit && !this.disabled) {
365
- this.init();
366
- }
367
- }
368
- createAdId() {
369
- // const newId = `div-gpt-ad-${new Date().getTime()}-${Math.round(
370
- // Math.random() * (Math.random() * 1000),
371
- // )}-${this.index}`;
372
- const newId = `${AdsManager.ID_PREFIX}${this.index}`;
373
- this.index += 1;
374
- return newId;
375
- }
376
- init() {
377
- const {
378
- googletag
379
- } = this;
380
- googletag.cmd.push(() => {
381
- if (this.disabled) {
382
- return;
383
- }
384
- this.initGpt();
385
- });
386
- }
387
- initGpt() {
388
- const {
389
- googletag
390
- } = this;
391
- if (this.disabled) {
392
- return;
393
- }
394
- debug$1('Initializing GPT...');
395
- const {
396
- disabled,
397
- personnalizedAdsDisabled
398
- } = this;
399
- const {
400
- disableSingleRequest = false,
401
- disableLazyLoad = false,
402
- disableVideoAds = false,
403
- mobileScaling = 1.0,
404
- renderMarginPercent = 100,
405
- fetchMarginPercent = 300
406
- } = this.options;
407
- if (disabled) {
408
- debug$1('Disable initial load');
409
- googletag.pubads().disableInitialLoad();
410
- }
411
- if (!disableSingleRequest) {
412
- debug$1('Enable single request');
413
- googletag.pubads().enableSingleRequest();
414
- }
415
- if (personnalizedAdsDisabled) {
416
- debug$1('Disable personalized ads');
417
- googletag.pubads().setRequestNonPersonalizedAds(1);
418
- }
419
- if (!disableLazyLoad) {
420
- debug$1('Enable lazy loading %o', {
421
- fetchMarginPercent,
422
- renderMarginPercent,
423
- mobileScaling
424
- });
425
- googletag.pubads().enableLazyLoad({
426
- fetchMarginPercent,
427
- renderMarginPercent,
428
- mobileScaling
429
- });
430
- }
431
- if (!disableVideoAds) {
432
- debug$1('Enable video ads');
433
- googletag.pubads().enableVideoAds();
434
- }
435
- googletag.pubads().addEventListener('slotRenderEnded', this.onSlotRenderEnded);
436
- googletag.pubads().addEventListener('impressionViewable', this.onSlotImpressionViewable);
437
- googletag.enableServices();
438
- debug$1('GPT is ready');
439
- this.enabled = true;
440
- this.ready = true;
441
- this.emit('ready');
442
- }
443
- onSlotRenderEnded(event) {
444
- const {
445
- slot: eventSlot,
446
- lineItemId = null,
447
- size = []
448
- } = event;
449
- const renderSlot = this.slots.find(slot => eventSlot === slot.getAdSlot()) || null;
450
- if (renderSlot !== null) {
451
- renderSlot.setRenderEvent(event);
452
- }
453
- const lineItems = typeof window !== 'undefined' ? window.refreshDisabledLineItems || [] : [];
454
- if (isArray(lineItems) && lineItems.indexOf(lineItemId) > -1) {
455
- renderSlot.setRefreshDisabled();
456
- }
457
- if (event.isEmpty) {
458
- debug$1('Render ended for slot #%s(%s). Slot is empty.', eventSlot.getSlotElementId(), eventSlot.getAdUnitPath());
459
- } else {
460
- debug$1('Render ended for slot #%s(%s) with size %s.', eventSlot.getSlotElementId(), eventSlot.getAdUnitPath(), size !== null ? size.join('x') : '-');
461
- }
462
- }
463
- onSlotImpressionViewable(event) {
464
- const {
465
- slot: eventSlot
466
- } = event;
467
- const impressionSlot = this.slots.find(slot => eventSlot === slot.getAdSlot()) || null;
468
- if (impressionSlot !== null) {
469
- impressionSlot.setViewable(true);
470
- }
471
- debug$1('Impression viewable for slot #%s(%s).', eventSlot.getSlotElementId(), eventSlot.getAdUnitPath());
472
- }
473
-
474
- // eslint-disable-next-line class-methods-use-this
475
- onSlotVisibleChange(visible, slot) {
476
- debug$1('Slot #%s(%s) visibility change to %s', slot.getElementId(), slot.getAdPath(), visible ? 'visible' : 'not visible');
477
- }
478
- isReady() {
479
- return this.ready && this.enabled && !this.disabled;
480
- }
481
- isDisabled() {
482
- return this.disabled;
483
- }
484
- setDisabled(disabled) {
485
- // const shouldRefresh = this.disabled && !disabled;
486
- this.disabled = disabled;
487
- if (!this.enabled && !disabled) {
488
- this.init();
489
- }
490
-
491
- // if (shouldRefresh) {
492
- // this.refreshAllSlots();
493
- // }
494
-
495
- // if (this.enabled && !disabled) {
496
- // this.emit('ready');
497
- // }
498
- }
499
- disablePersonnalizedAds(disablePersonnalizedAds) {
500
- const {
501
- googletag
502
- } = this;
503
- this.personnalizedAdsDisabled = disablePersonnalizedAds;
504
- googletag.cmd.push(() => {
505
- googletag.pubads().setRequestNonPersonalizedAds(disablePersonnalizedAds ? 1 : 0);
506
- });
507
- }
508
- createSlot(path, size, opts = {}) {
509
- const {
510
- id: providedId = null
511
- } = opts;
512
- const id = providedId || this.createAdId();
513
- debug$1('Creating slot #%s(%s)...', id, path);
514
- const slot = new AdSlot(id, path, size, {
515
- ...opts
516
- });
517
- slot.on('visible', this.onSlotVisibleChange);
518
- this.slots.push(slot);
519
- return slot;
520
- }
521
- defineSlot(slot) {
522
- const {
523
- googletag
524
- } = this;
525
- googletag.cmd.push(() => {
526
- if (slot.isDestroyed() || slot.isDefined()) {
527
- return;
528
- }
529
- const id = slot.getElementId();
530
- const path = slot.getAdPath();
531
- const size = slot.getAdSize();
532
- debug$1('Defining slot #%s(%s)...', id, path);
533
- const adSlot = googletag.defineSlot(path, size, id).addService(googletag.pubads());
534
- slot.setAdSlot(adSlot);
535
- });
536
- }
537
- displaySlots() {
538
- const slotsToDisplay = this.slots.filter(slot => slot.canBeDisplayed());
539
- const slotsCount = slotsToDisplay.length;
540
- if (slotsCount > 0) {
541
- debug$1('Displaying %i slot(s)...', slotsCount);
542
- slotsToDisplay.forEach(slot => this.callDisplaySlot(slot));
543
- }
544
- return true;
545
- }
546
- displaySlot(slot) {
547
- this.callDisplaySlot(slot);
548
- }
549
-
550
- /* eslint-disable */
551
- callDisplaySlot(slot) {
552
- const {
553
- googletag
554
- } = this;
555
- googletag.cmd.push(() => {
556
- if (!slot.canBeDisplayed()) {
557
- return;
558
- }
559
- const id = slot.getElementId();
560
- const path = slot.getAdPath();
561
- debug$1('Displaying slot #%s(%s)...', id, path);
562
- googletag.display(id);
563
- if (googletag.pubads().isInitialLoadDisabled()) {
564
- googletag.pubads().refresh([id]);
565
- }
566
- slot.setDisplayed(true);
567
- });
568
- }
569
- /* eslint-enable */
570
-
571
- destroySlot(id) {
572
- const {
573
- googletag
574
- } = this;
575
- const slot = isObject(id) ? id : this.slots.find(it => it.getElementId() === id) || null;
576
- if (slot === null || slot.isDestroyed()) {
577
- return;
578
- }
579
- const adSlot = slot.getAdSlot();
580
- slot.destroy();
581
- this.slots = this.slots.filter(it => it !== slot);
582
- if (adSlot !== null) {
583
- debug$1('Destroying slot #%s(%s)...', adSlot.getAdUnitPath(), adSlot.getSlotElementId());
584
- googletag.cmd.push(() => {
585
- googletag.destroySlots([adSlot]);
586
- });
587
- }
588
- this.emit('destroy:slot', slot);
589
- }
590
- refreshSlot(id) {
591
- const {
592
- googletag
593
- } = this;
594
- const slot = isObject(id) ? id : this.slots.find(it => it.getElementId() === id) || null;
595
- if (slot === null || slot.isDestroyed() || slot.isRefreshDisabled()) {
596
- return;
597
- }
598
- const adSlot = slot.getAdSlot();
599
- if (adSlot !== null) {
600
- debug$1('Refreshing slot #%s(%s)...', adSlot.getAdUnitPath(), slot.getElementId());
601
- googletag.cmd.push(() => {
602
- googletag.pubads().refresh([adSlot], {
603
- changeCorrelator: false
604
- });
605
- });
606
- }
607
- }
608
- refreshSlots(ids) {
609
- const {
610
- googletag
611
- } = this;
612
- const slots = ids.map(id => isObject(id) ? id : this.slots.find(it => !it.isDestroyed() && it.getElementId() === id) || null).filter(it => it !== null).map(it => it.getAdSlot());
613
- if (slots.length === 0) {
614
- return;
615
- }
616
- debug$1('Refreshing slots %o...', slots.map(slot => `#${slot.getElementId()}(${slot.getAdUnitPath()})`));
617
- googletag.cmd.push(() => {
618
- googletag.pubads().refresh(slots);
619
- });
620
- }
621
- refreshAllSlots() {
622
- const {
623
- googletag
624
- } = this;
625
- debug$1('Refreshing all slots...');
626
- googletag.cmd.push(() => {
627
- googletag.pubads().refresh();
628
- });
629
- }
630
- }
631
-
632
- const viewports = {
633
- default: [0, 0],
634
- tablet: [728, 0],
635
- desktop: [1024, 0],
636
- laptop: [1400, 700]
637
- };
638
- const slots = {
639
- top: {
640
- sizeMapping: {
641
- default: [[300, 100], [300, 150], [320, 50], [320, 100], [320, 180]],
642
- tablet: [[300, 100], [300, 150], [320, 50], [320, 100], [320, 180], [728, 90]],
643
- desktop: [[640, 350], [728, 90], [970, 90], [970, 250], [1024, 300]],
644
- laptop: [[640, 350], [728, 90], [970, 90], [970, 250], [1024, 300], [1382, 300], [1382, 600]]
645
- }
646
- },
647
- grid: {
648
- size: [[250, 250], [300, 250]]
649
- },
650
- sidebar: {
651
- sizeMapping: {
652
- default: [[300, 250]],
653
- laptop: [[120, 600], [160, 600], [300, 250], [300, 600]]
654
- }
655
- },
656
- fullwidth: {
657
- sizeMapping: {
658
- default: [[250, 250], [300, 100], [300, 150], [300, 250], [320, 50], [320, 100], [320, 180], [336, 280]],
659
- tablet: [[250, 250], [300, 100], [300, 150], [300, 250], [320, 50], [320, 100], [320, 180], [336, 280], [634, 634], [640, 350], [640, 360], [728, 90]],
660
- desktop: [[634, 634], [640, 350], [640, 360], [728, 90], [960, 540], [970, 90], [970, 250], [970, 415], [1024, 300]],
661
- laptop: [[634, 634], [640, 350], [640, 360], [728, 90], [960, 540], [970, 90], [970, 250], [970, 415], [1024, 300], [1382, 300], [1382, 600]]
662
- }
663
- },
664
- content: {
665
- sizeMapping: {
666
- default: [[120, 600], [160, 600], [250, 250], [300, 100], [300, 150], [300, 250], [300, 600], [320, 50], [320, 100], [320, 180], [336, 280]],
667
- tablet: [[120, 600], [160, 600], [250, 250], [300, 100], [300, 150], [300, 250],
668
- // [300, 600],
669
- [320, 50], [320, 100], [320, 180], [336, 280], [634, 634], [640, 350], [640, 360], [728, 90]],
670
- desktop: [[120, 600], [160, 600],
671
- // [300, 600],
672
- [634, 634], [640, 350], [640, 360], [728, 90], [960, 540], [970, 90], [970, 250], [970, 415], [1024, 300]],
673
- laptop: [[120, 600], [160, 600],
674
- // [300, 600],
675
- [634, 634], [640, 350], [640, 360], [728, 90], [960, 540], [970, 90], [970, 250], [970, 415], [1024, 300], [1382, 300], [1382, 600]]
676
- }
677
- }
678
- };
679
-
680
- /* eslint-disable react/jsx-props-no-spreading */
681
- const AdsContext = /*#__PURE__*/React.createContext({
682
- ready: false
683
- });
684
- const useAdsContext = () => React.useContext(AdsContext);
685
- function AdsProvider({
686
- children,
687
- defaultSlotPath = null,
688
- slotsPath = null,
689
- disableSingleRequest = false,
690
- disableVideoAds = false,
691
- disableLazyLoad = false,
692
- autoInit = true,
693
- resizeDebounceDelay = 500,
694
- refreshOnResize = false,
695
- mobileScaling = 1.0,
696
- renderMarginPercent = 100,
697
- fetchMarginPercent = 300,
698
- viewport = null,
699
- viewports: viewports$1 = viewports,
700
- slots: slots$1 = slots,
701
- richAdComponents = null,
702
- disabled = false,
703
- disableTracking = false
704
- }) {
705
- const [ready, setReady] = React.useState(false);
706
- const adsRef = React.useRef(null);
707
- const ads = React.useMemo(() => {
708
- if (adsRef.current === null) {
709
- adsRef.current = new AdsManager({
710
- autoInit,
711
- disabled,
712
- disableSingleRequest,
713
- disableVideoAds,
714
- disableLazyLoad,
715
- mobileScaling,
716
- renderMarginPercent,
717
- fetchMarginPercent
718
- });
719
- } else {
720
- adsRef.current.setDisabled(disabled);
721
- }
722
- return adsRef.current;
723
- }, [autoInit, disabled, disableSingleRequest, disableVideoAds, disableLazyLoad, mobileScaling, renderMarginPercent, fetchMarginPercent]);
724
- React.useEffect(() => {
725
- let onReady = null;
726
- if (!ads.isReady()) {
727
- onReady = () => setReady(true);
728
- ads.on('ready', onReady);
729
- } else {
730
- setReady(true);
731
- }
732
- return () => {
733
- if (onReady != null) {
734
- ads.off('ready', onReady);
735
- }
736
- };
737
- }, [ads, setReady]);
738
- React.useEffect(() => {
739
- if (!autoInit) {
740
- ads.init();
741
- }
742
- }, [ads, autoInit]);
743
- React.useEffect(() => {
744
- const onResize = debounce(() => ads.refreshAllSlots(), resizeDebounceDelay);
745
- if (refreshOnResize) {
746
- window.addEventListener('resize', onResize);
747
- }
748
- return () => {
749
- if (refreshOnResize) {
750
- window.removeEventListener('resize', onResize);
751
- }
752
- onResize.cancel();
753
- };
754
- }, [ads, resizeDebounceDelay, refreshOnResize]);
755
- const slotsWithSizeMapping = React.useMemo(() => Object.keys(slots$1 || {}).reduce((map, key) => {
756
- const slot = slots$1[key];
757
- const {
758
- size
759
- } = slot;
760
- const sizeMapping = getSizeMappingFromSlot(slot, viewports$1);
761
- return {
762
- ...map,
763
- [key]: {
764
- ...slot,
765
- size: size || getSizeFromSizeMapping(sizeMapping || null),
766
- sizeMapping
767
- }
768
- };
769
- }, {}), [slots$1, viewports$1]);
770
- const finalSlotsPath = React.useMemo(() => {
771
- if (defaultSlotPath !== null && slotsPath) {
772
- return {
773
- default: defaultSlotPath,
774
- ...slotsPath
775
- };
776
- }
777
- return slotsPath ? {
778
- ...slotsPath
779
- } : {};
780
- }, [defaultSlotPath, slotsPath]);
781
- const value = React.useMemo(() => ({
782
- ready,
783
- ads,
784
- viewports: viewports$1,
785
- viewport,
786
- slots: slotsWithSizeMapping,
787
- slotsPath: finalSlotsPath,
788
- trackingDisabled: disableTracking,
789
- richAdComponents
790
- }), [ready, ads, viewports$1, viewport, slotsWithSizeMapping, finalSlotsPath, disableTracking, richAdComponents]);
791
- return /*#__PURE__*/jsxRuntime.jsx(AdsContext.Provider, {
792
- value: value,
793
- children: children
794
- });
795
- }
796
-
797
- const defaultTargeting = {
798
- domain: typeof window !== 'undefined' ? `${window.location.protocol}//${window.location.host}` : null
799
- };
800
- const AdsTargetingContext = /*#__PURE__*/React.createContext(defaultTargeting);
801
- const useAdsTargeting = () => React.useContext(AdsTargetingContext);
802
- function AdsTargetingProvider({
803
- children,
804
- targeting = defaultTargeting,
805
- replace = false
806
- }) {
807
- const previousTargeting = useAdsTargeting();
808
- const mergedTargeting = React.useMemo(() => replace ? targeting : {
809
- ...previousTargeting,
810
- ...targeting
811
- }, [replace, previousTargeting, targeting]);
812
- return /*#__PURE__*/jsxRuntime.jsx(AdsTargetingContext.Provider, {
813
- value: mergedTargeting,
814
- children: children
815
- });
816
- }
817
-
818
- /* eslint-disable react/jsx-props-no-spreading */
819
- function RichAd({
820
- richAd,
821
- ...props
822
- }) {
823
- const {
824
- type = null,
825
- ...richAdProps
826
- } = richAd;
827
- const {
828
- richAdComponents = null
829
- } = useAdsContext();
830
- const RichAdComponent = utils.getComponentFromName(richAdComponents, type);
831
- return RichAdComponent !== null ? /*#__PURE__*/jsxRuntime.jsx(RichAdComponent, {
832
- ...props,
833
- ...richAdProps
834
- }) : null;
835
- }
836
-
837
- function useAdsTracking() {
838
- const tracking$1 = tracking.useTracking() || null;
839
- const trackEvent = React.useCallback((action, slot = null, renderEvent = null) => {
840
- if (tracking$1 !== null && typeof tracking$1.trackAd !== 'undefined') {
841
- tracking$1.trackAd(action, slot, renderEvent);
842
- }
843
- }, [tracking$1]);
844
- return trackEvent;
845
- }
846
-
847
- function useAd(path, size, {
848
- id,
849
- sizeMapping = null,
850
- viewport = null,
851
- targeting = null,
852
- categoryExclusions = null,
853
- refreshInterval = null,
854
- alwaysRender = false,
855
- onRender = null,
856
- onDestroy = null,
857
- disabled = false,
858
- disableTracking = false,
859
- rootMargin = '300px'
860
- } = {}) {
861
- const {
862
- ads: adsManager,
863
- viewports,
864
- ready: adsReady,
865
- trackingDisabled: globalTrackingDisabled = false
866
- } = useAdsContext();
867
- const trackAd = useAdsTracking();
868
- const track = React.useCallback((action, slot = null, renderEvent = null) => {
869
- if (!disableTracking && !globalTrackingDisabled) {
870
- trackAd(action, slot, renderEvent);
871
- }
872
- }, [disableTracking, globalTrackingDisabled, trackAd]);
873
-
874
- // Check for visibility
875
- const {
876
- ref: refObserver,
877
- entry: {
878
- isIntersecting = false
879
- }
880
- } = hooks.useIntersectionObserver({
881
- rootMargin,
882
- disabled
883
- });
884
-
885
- // Window blur
886
- const [windowActive, setWindowActive] = React.useState(true); // eslint-disable-line
887
- const onWindowBlur = React.useCallback(() => setWindowActive(false), [setWindowActive]);
888
- const onWindowFocus = React.useCallback(() => setWindowActive(true), [setWindowActive]);
889
- hooks.useWindowEvent('blur', onWindowBlur);
890
- hooks.useWindowEvent('focus', onWindowFocus);
891
- const isVisible = isIntersecting; /* && windowActive */
892
-
893
- // Current render event
894
- const [renderEvent, setRenderEvent] = React.useState(null);
895
-
896
- // Create slot
897
- const slotRef = React.useRef(null);
898
- // const { current: slot } = slotRef;
899
- // const [slot, setSlot] = useState(null);
900
- const slot = React.useMemo(() => {
901
- const {
902
- current: currentSlot = null
903
- } = slotRef;
904
- if (currentSlot !== null) {
905
- adsManager.destroySlot(currentSlot);
906
- }
907
- const viewportSize = viewport !== null ? viewports[viewport] || null : null;
908
- const [, viewportFixedSize = null] = sizeMapping !== null && viewportSize !== null ? sizeMapping.find(([itViewport]) => itViewport.join('x') === viewportSize.join('x')) || [] : [];
909
- const newSlot = path !== null && !disabled ? adsManager.createSlot(path, viewportFixedSize || size, {
910
- id,
911
- visible: isVisible,
912
- sizeMapping: viewportFixedSize === null ? sizeMapping : null,
913
- targeting,
914
- categoryExclusions
915
- }) : null;
916
- slotRef.current = newSlot;
917
- return newSlot;
918
- // // setSlot(newSlot);
919
- // // if (currentSlot.current !== null && adsReady) {
920
- // // adsManager.defineSlot(currentSlot.current);
921
- // // }
922
- // // return currentSlot.current;
923
- // return () => {
924
- // slotRef.current = null;
925
- // if (newSlot !== null) {
926
- // adsManager.destroySlot(newSlot);
927
- // }
928
- // };
929
- }, [adsManager, path, disabled, size, sizeMapping, viewport, categoryExclusions, id]);
930
- React.useEffect(() => {
931
- if (slot !== null) {
932
- slot.setTargeting(targeting);
933
- }
934
- }, [slot, targeting]);
935
-
936
- // Set visibility
937
- React.useEffect(() => {
938
- if (slot !== null) {
939
- slot.setVisible(isVisible);
940
- }
941
- }, [slot, isVisible]);
942
-
943
- // Render ad when visible
944
- React.useEffect(() => {
945
- const slotReady = slot !== null && !slot.isDefined();
946
- if (adsReady && slotReady) {
947
- adsManager.defineSlot(slot);
948
- }
949
- }, [adsManager, adsReady, slot]);
950
- React.useEffect(() => {
951
- const slotReady = slot !== null && !slot.isDisplayed();
952
- if (adsReady && slotReady && (alwaysRender || isVisible)) {
953
- adsManager.displaySlot(slot);
954
- track('Init', slot);
955
- }
956
- }, [adsManager, adsReady, slot, alwaysRender, isVisible, track]);
957
-
958
- // Refresh ads slot
959
- React.useEffect(() => {
960
- let interval = null;
961
- const slotReady = slot !== null && slot.isDefined();
962
- if (adsReady && slotReady && isVisible && refreshInterval !== null) {
963
- interval = setInterval(() => {
964
- adsManager.refreshSlot(slot);
965
- track('Refresh', slot);
966
- }, refreshInterval);
967
- }
968
- return () => {
969
- if (interval !== null) {
970
- clearInterval(interval);
971
- }
972
- };
973
- }, [adsManager, adsReady, slot, isVisible, refreshInterval, track]);
974
-
975
- // Listen to render event
976
- React.useEffect(() => {
977
- if (slot === null) {
978
- if (renderEvent !== null) {
979
- setRenderEvent(null);
980
- }
981
- return () => {};
982
- }
983
- const onSlotRender = event => {
984
- const newRenderEvent = {
985
- ...event,
986
- ...(slot !== null ? slot.getRenderedSize() : null),
987
- slot
988
- };
989
- setRenderEvent(newRenderEvent);
990
- if (onRender !== null) {
991
- onRender(newRenderEvent);
992
- }
993
- const {
994
- isEmpty = true
995
- } = newRenderEvent || {};
996
- if (isEmpty) {
997
- track('Empty', slot);
998
- } else {
999
- track('Render', slot, newRenderEvent);
1000
- }
1001
- };
1002
- slot.on('render', onSlotRender);
1003
- return () => slot.off('render', onSlotRender);
1004
- }, [slot, disabled, setRenderEvent, onRender, track]);
1005
-
1006
- // Listen to destroy event
1007
- React.useEffect(() => {
1008
- if (slot === null) {
1009
- return () => {};
1010
- }
1011
- const onSlotDestroy = destroySlot => {
1012
- if (onDestroy !== null) {
1013
- onDestroy(destroySlot);
1014
- }
1015
- };
1016
- slot.on('destroy', onSlotDestroy);
1017
- return () => slot.off('destroy', onSlotDestroy);
1018
- }, [slot, onDestroy]);
1019
-
1020
- // Destroy slot
1021
- // useEffect(
1022
- // () => () => {
1023
- // if (slot !== null) {
1024
- // // currentSlot.current = null;
1025
- // adsManager.destroySlot(slot);
1026
- // }
1027
- // },
1028
- // [],
1029
- // );
1030
-
1031
- return {
1032
- refObserver,
1033
- slot,
1034
- disabled: adsManager.isDisabled(),
1035
- id: slot !== null ? slot.getElementId() : null,
1036
- isRendered: slot !== null && slot.isRendered(),
1037
- isEmpty: slot !== null ? slot.isEmpty() : true,
1038
- isVisible: slot !== null ? slot.isVisible() : true,
1039
- width: null,
1040
- height: null,
1041
- renderEvent,
1042
- ...(slot !== null ? slot.getRenderedSize() : null)
1043
- };
1044
- }
1045
-
1046
- const debug = createDebug('folklore:ads');
1047
- function parseRichAd(data) {
1048
- let richAd = null;
1049
- try {
1050
- const eventData = JSON.parse(data) || null;
1051
- richAd = eventData !== null ? eventData.richAd || null : null;
1052
- } catch (e) {}
1053
- return richAd;
1054
- }
1055
- function useRichAd(containerRef, id, opts = {}) {
1056
- const [richAd, setRichAd] = React.useState(null);
1057
- const {
1058
- onRichAd = null
1059
- } = opts || {};
1060
- React.useEffect(() => {
1061
- if (id === null) {
1062
- return () => {};
1063
- }
1064
- setRichAd(null);
1065
- function onMessage(event) {
1066
- if (event.origin.match(/safeframe\.googlesyndication\.com/) === null) {
1067
- return;
1068
- }
1069
- const container = containerRef.current || null;
1070
- const iframe = container !== null ? container.querySelector('iframe') || null : null;
1071
- if (iframe === null || iframe.contentWindow !== event.source) {
1072
- return;
1073
- }
1074
- const newRichAd = parseRichAd(event.data);
1075
- if (newRichAd === null) {
1076
- return;
1077
- }
1078
- debug('Received rich ad for %s %O', id, newRichAd);
1079
- setRichAd(newRichAd);
1080
- if (onRichAd !== null) {
1081
- onRichAd(newRichAd);
1082
- }
1083
- }
1084
- window.addEventListener('message', onMessage);
1085
- return () => {
1086
- window.removeEventListener('message', onMessage);
1087
- };
1088
- }, [id, onRichAd]);
1089
- return richAd;
1090
- }
1091
-
1092
- /* eslint-disable react/require-default-props */
1093
- function Ad({
1094
- slot: slotName,
1095
- path: providedPath = null,
1096
- size: providedSize = null,
1097
- sizeMapping: providedSizeMapping = null,
1098
- viewport: providedViewport = null,
1099
- targeting: providedTargeting = null,
1100
- refreshInterval: providedRefreshInterval = null,
1101
- alwaysRender = true,
1102
- disabled: providedDisabled = false,
1103
- disableTracking = false,
1104
- shouldKeepSize = false,
1105
- withoutStyle = false,
1106
- withoutMinimumSize = false,
1107
- withReactId = false,
1108
- className = null,
1109
- emptyClassName = null,
1110
- adClassName = null,
1111
- richAdClassName = null,
1112
- richAdIframeClassName = null,
1113
- onRender = null,
1114
- onDestroy = null,
1115
- onRichAd = null,
1116
- slotRef = null
1117
- }) {
1118
- const {
1119
- slots = null,
1120
- slotsPath = null,
1121
- viewport: contextViewport = null,
1122
- ads
1123
- } = useAdsContext();
1124
- const {
1125
- default: defaultSlotPath = null
1126
- } = slotsPath || {};
1127
- const slot = slotName && slots !== null ? slots[slotName] || null : null;
1128
- const {
1129
- sizeMapping: slotSizeMapping = null,
1130
- size: slotSize = null,
1131
- path: slotPath = null
1132
- } = slot || {};
1133
- const path = providedPath || slotPath || (slotName !== null && slotsPath !== null ? slotsPath[slotName] : null) || defaultSlotPath || null;
1134
-
1135
- // Size
1136
- const size = providedSize || slotSize;
1137
- const sizeMapping = providedSizeMapping || slotSizeMapping;
1138
- const minimumSize = React.useMemo(() => getMinimumAdSize([...(getSizeFromSizeMapping(sizeMapping) || []), ...normalizeAdSizes(size)]), [sizeMapping, size]);
1139
-
1140
- // Targeting
1141
- const contextTargeting = useAdsTargeting();
1142
- const {
1143
- targeting,
1144
- refreshInterval,
1145
- disabled,
1146
- viewport
1147
- } = React.useMemo(() => {
1148
- const allTargeting = {
1149
- ...(slotName !== null ? {
1150
- slot: slotName
1151
- } : null),
1152
- ...contextTargeting,
1153
- ...providedTargeting
1154
- };
1155
- const {
1156
- refreshAds = null,
1157
- disabled: targetingDisabled = false,
1158
- viewport: targetingViewport = null,
1159
- ...otherProps
1160
- } = allTargeting || {};
1161
- return {
1162
- refreshInterval: refreshAds !== null && refreshAds === 'inactive' ? null : providedRefreshInterval,
1163
- disabled: providedDisabled || targetingDisabled || ads.isDisabled(),
1164
- viewport: providedViewport || contextViewport || targetingViewport,
1165
- targeting: otherProps || {}
1166
- };
1167
- }, [slotName, contextTargeting, providedTargeting, ads, providedRefreshInterval, providedDisabled, providedViewport, contextViewport]);
1168
- const [lastRenderedSize, setLastRenderedSize] = React.useState(null);
1169
- const onAdRender = React.useCallback(event => {
1170
- const {
1171
- isEmpty: newIsEmpty = true,
1172
- width: newWidth,
1173
- height: newHeight
1174
- } = event || {};
1175
- const isRendered = !newIsEmpty;
1176
- setLastRenderedSize(isRendered ? {
1177
- width: newWidth,
1178
- height: newHeight
1179
- } : null);
1180
- if (onRender !== null) {
1181
- onRender(event);
1182
- }
1183
- }, [onRender, shouldKeepSize, disabled]);
1184
-
1185
- // useEffect(() => {
1186
- // if (!disabled) {
1187
- // return;
1188
- // }
1189
- // const keepSize = shouldKeepSize && lastRenderedSize.current !== null;
1190
- // if (onRender !== null) {
1191
- // onRender({
1192
- // isEmpty: true,
1193
- // keepSize,
1194
- // });
1195
- // }
1196
- // }, [disabled]);
1197
-
1198
- const reactId = React.useId();
1199
-
1200
- // Create ad
1201
- const {
1202
- id,
1203
- width,
1204
- height,
1205
- isFluid = false,
1206
- isEmpty,
1207
- isRendered,
1208
- refObserver,
1209
- slot: slotObject = null
1210
- } = useAd(path, size, {
1211
- id: withReactId ? `ad-${reactId}` : null,
1212
- viewport,
1213
- sizeMapping,
1214
- targeting,
1215
- refreshInterval,
1216
- alwaysRender,
1217
- onRender: onAdRender,
1218
- onDestroy,
1219
- disabled,
1220
- disableTracking
1221
- });
1222
- const adContainerRef = React.useRef(null);
1223
- const richAd = useRichAd(adContainerRef, id, {
1224
- onRichAd
1225
- });
1226
- if (slotRef !== null && typeof slotRef === 'function') {
1227
- slotRef(slotObject);
1228
- } else if (slotRef !== null && typeof slotRef === 'object') {
1229
- // eslint-disable-next-line no-param-reassign
1230
- slotRef.current = slotObject;
1231
- }
1232
- const keepSize = shouldKeepSize && lastRenderedSize !== null && !isRendered;
1233
- if (id === null && !keepSize) {
1234
- return null;
1235
- }
1236
- let adStyle = null;
1237
- if (isRendered) {
1238
- adStyle = !isFluid ? {
1239
- width,
1240
- height
1241
- } : null;
1242
- } else if (keepSize) {
1243
- adStyle = lastRenderedSize;
1244
- } else if (!withoutMinimumSize) {
1245
- adStyle = minimumSize;
1246
- }
1247
- let containerStyle = null;
1248
- if (disabled && !keepSize) {
1249
- containerStyle = {
1250
- display: 'none',
1251
- visibility: 'hidden'
1252
- };
1253
- } else if (isEmpty && !keepSize) {
1254
- containerStyle = {
1255
- height: 0,
1256
- paddingBottom: 0,
1257
- overflow: 'hidden',
1258
- opacity: 0
1259
- };
1260
- }
1261
- return /*#__PURE__*/jsxRuntime.jsx("div", {
1262
- id: id !== null ? `${id}-container` : null,
1263
- className: classNames([className, {
1264
- [emptyClassName]: emptyClassName !== null && isEmpty && !keepSize
1265
- }]),
1266
- style: !withoutStyle ? containerStyle : null,
1267
- suppressHydrationWarning: true,
1268
- ref: refObserver,
1269
- children: /*#__PURE__*/jsxRuntime.jsxs("div", {
1270
- className: adClassName,
1271
- style: {
1272
- position: 'relative',
1273
- ...adStyle
1274
- },
1275
- ref: adContainerRef,
1276
- suppressHydrationWarning: true,
1277
- children: [/*#__PURE__*/jsxRuntime.jsx("div", {
1278
- id: id,
1279
- className: classNames([{
1280
- [richAdIframeClassName]: richAdIframeClassName !== null && isRendered && richAd !== null
1281
- }]),
1282
- suppressHydrationWarning: true
1283
- }), isRendered && richAd !== null ? /*#__PURE__*/jsxRuntime.jsx(RichAd, {
1284
- richAd: richAd,
1285
- isFluid: isFluid,
1286
- width: width,
1287
- height: height,
1288
- className: richAdClassName
1289
- }) : null]
1290
- })
1291
- });
1292
- }
1293
-
1294
- exports.Ad = Ad;
1295
- exports.AdSlot = AdSlot;
1296
- exports.AdsManager = AdsManager;
1297
- exports.AdsProvider = AdsProvider;
1298
- exports.AdsTargetingProvider = AdsTargetingProvider;
1299
- exports.PropTypes = propTypes;
1300
- exports.RichAd = RichAd;
1301
- exports.buildSizeMappingFromSizes = buildSizeMappingFromSizes;
1302
- exports.buildSizeMappingFromViewports = buildSizeMappingFromViewports;
1303
- exports.getAdSizes = getAdSizes;
1304
- exports.getMinimumAdSize = getMinimumAdSize;
1305
- exports.getSizeFromSizeMapping = getSizeFromSizeMapping;
1306
- exports.getSizeMappingFromSlot = getSizeMappingFromSlot;
1307
- exports.getSortedViewports = getSortedViewports;
1308
- exports.normalizeAdSizes = normalizeAdSizes;
1309
- exports.sizeFitsInViewport = sizeFitsInViewport;
1310
- exports.slots = slots;
1311
- exports.useAd = useAd;
1312
- exports.useAdsContext = useAdsContext;
1313
- exports.useAdsTargeting = useAdsTargeting;
1314
- exports.useAdsTracking = useAdsTracking;
1315
- exports.useRichAd = useRichAd;
1316
- exports.viewports = viewports;