PluginProbe ʕ •ᴥ•ʔ
Advanced Ads – Ad Manager & AdSense / 2.0.25
Advanced Ads – Ad Manager & AdSense v2.0.25
2.0.25 2.0.24 2.0.23 2.0.22 2.0.21 1.38.0 1.39.0 1.39.1 1.39.2 1.39.3 1.39.4 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.40.0 1.40.1 1.40.2 1.41.0 1.42.0 1.42.1 1.42.2 1.43.0 1.44.0 1.44.1 1.45.0 1.45.1 1.46.0 1.47.0 1.47.1 1.47.2 1.47.3 1.47.4 1.47.5 1.48.0 1.48.1 1.49.0 1.5.0 1.5.0.1 1.5.1 1.5.2 1.5.2.1 1.5.4 1.5.4.1 1.5.5 1.50.0 1.51.0 1.51.1 1.51.2 1.51.3 1.52.0 1.52.1 1.52.2 1.52.3 1.52.4 1.53.0 1.53.1 1.53.2 1.54.0 1.54.1 1.55.0 1.56.0 1.56.1 1.56.2 1.56.3 1.56.4 1.6 1.6.1 1.6.10 1.6.10.1 1.6.10.2 1.6.11 1.6.11.1 1.6.12 1.6.13 1.6.14 1.6.15 1.6.16 1.6.17 1.6.17.1 1.6.17.2 1.6.2 1.6.2.1 1.6.3 1.6.4 1.6.4.1 1.6.5 1.6.6 1.6.6.1 1.6.7 1.6.7.1 1.6.8 1.6.8.1 1.6.8.2 1.6.8.3 1.6.9 1.6.9.1 1.6.9.2 1.6.9.3 1.6.9.4 1.7 1.7.0.1 1.7.0.2 1.7.0.3 1.7.1 1.7.1.1 1.7.1.2 1.7.1.3 1.7.1.4 1.7.1.5 1.7.10 trunk 1.7.11 1.0.1 1.7.12 1.0.2 1.7.13 1.0.3 1.7.14 1.1.0 1.7.15 1.1.1 1.7.16 1.1.2 1.7.17 1.1.3 1.7.18 1.10 1.7.19 1.10.1 1.7.2 1.10.10 1.7.2.1 1.10.11 1.7.20 1.10.12 1.7.21 1.10.2 1.7.22 1.10.3 1.7.23 1.10.4 1.7.24 1.10.5 1.7.25 1.10.6 1.7.3 1.10.7 1.7.4 1.10.8 1.7.4.1 1.10.9 1.7.4.2 1.11 1.7.4.3 1.11.1 1.7.4.4 1.11.2 1.7.4.5 1.12 1.7.5 1.13 1.7.5.1 1.13.1 1.7.6 1.13.2 1.7.7 1.13.3 1.7.8 1.13.4 1.7.9 1.13.5 1.7.9.1 1.13.6 1.7.9.2 1.13.7 1.7.9.3 1.13.8 1.8 1.14 1.8.1 1.14.1 1.8.10 1.14.10 1.8.11 1.14.11 1.8.12 1.14.2 1.8.13 1.14.3 1.8.14 1.14.4 1.8.15 1.14.5 1.8.16 1.14.6 1.8.17 1.14.7 1.8.18 1.14.8 1.8.19 1.14.9 1.8.2 1.15 1.8.20 1.16 1.8.21 1.16.1 1.8.22 1.17 1.8.23 1.17.1 1.8.24 1.17.10 1.8.25 1.17.10-rc.1 1.8.26 1.17.11 1.8.27 1.17.12 1.8.28 1.17.12-rc.1 1.8.29 1.17.2 1.8.3 1.17.3 1.8.30 1.17.4 1.8.4 1.17.5 1.8.5 1.17.6 1.8.6 1.17.7 1.8.7 1.17.8 1.8.8 1.17.9 1.8.9 1.17.9-beta.1 1.9 1.18.0 2.0.0 1.19.0 2.0.1 1.19.1 2.0.10 1.2 2.0.11 1.2.1 2.0.12 1.2.2 2.0.13 1.2.3 2.0.14 1.2.4 2.0.15 1.2.5 2.0.16 1.2.6 2.0.17 1.2.7 2.0.18 1.20.0 2.0.19 1.20.0-rc.1 2.0.2 1.20.0-rc.2 2.0.20 1.20.1 2.0.3 1.20.2 2.0.4 1.20.3 2.0.5 1.21.0 2.0.6 1.21.1 2.0.7 1.22.0 2.0.8 1.22.1 2.0.9 1.22.2 1.23.0 1.23.1 1.23.2 1.24.0 1.24.1 1.24.2 1.25.0 1.25.1 1.26.0 1.27.0 1.28.0 1.29.0 1.29.1 1.3 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.14 1.3.15 1.3.16 1.3.17 1.3.18 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.30.0 1.30.1 1.30.2 1.30.2-rc.1 1.30.3 1.30.4 1.30.4-rc.1 1.30.5 1.31.0 1.31.1 1.32.0 1.32.0-rc.1 1.33.0 1.33.1 1.33.2 1.34.0 1.35.0 1.35.1 1.36.0 1.36.1 1.36.2 1.36.3 1.37.0 1.37.1 1.37.2
advanced-ads / src / public / advanced.js
advanced-ads / src / public Last commit date
advanced.js 3 months ago frontend-picker.js 2 months ago
advanced.js
798 lines
1 /* eslint-disable */
2 /*
3 * advanced ads functions to be used directly within ad codes
4 */
5
6 /**
7 * Polyfills
8 */
9 ( function () {
10 if ( typeof window.CustomEvent !== 'function' ) {
11 /**
12 * CustomEvent polyfill for IE11: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
13 *
14 * @param {string} event Event name.
15 * @param {Object} params Event parameters.
16 * @return {Object} Custom event.
17 */
18 function CustomEvent( event, params ) {
19 params = params || {
20 bubbles: false,
21 cancelable: false,
22 detail: null,
23 };
24 const evt = document.createEvent( 'CustomEvent' );
25 evt.initCustomEvent(
26 event,
27 params.bubbles,
28 params.cancelable,
29 params.detail
30 );
31 return evt;
32 }
33
34 window.CustomEvent = CustomEvent;
35 }
36
37 /**
38 * ReplaceWith polyfill for IE11: https://developer.mozilla.org/en-US/docs/Web/API/ChildNode/replaceWith
39 */
40 function ReplaceWithPolyfill() {
41 'use-strict'; // For safari, and IE > 10
42 let parent = this.parentNode,
43 i = arguments.length,
44 currentNode;
45 if ( ! parent ) {
46 return;
47 }
48 if ( ! i ) {
49 // if there are no arguments
50 parent.removeChild( this );
51 }
52 while ( i-- ) {
53 // i-- decrements i and returns the value of i before the decrement
54 currentNode = arguments[ i ];
55 if ( typeof currentNode !== 'object' ) {
56 currentNode = this.ownerDocument.createTextNode( currentNode );
57 } else if ( currentNode.parentNode ) {
58 currentNode.parentNode.removeChild( currentNode );
59 }
60 // the value of "i" below is after the decrement
61 if ( ! i ) {
62 // if currentNode is the first argument (currentNode === arguments[0])
63 parent.replaceChild( currentNode, this );
64 } else {
65 // if currentNode isn't the first
66 parent.insertBefore( currentNode, this.nextSibling );
67 }
68 }
69 }
70 if ( ! Element.prototype.replaceWith ) {
71 Element.prototype.replaceWith = ReplaceWithPolyfill;
72 }
73 if ( ! CharacterData.prototype.replaceWith ) {
74 CharacterData.prototype.replaceWith = ReplaceWithPolyfill;
75 }
76 if ( ! DocumentType.prototype.replaceWith ) {
77 DocumentType.prototype.replaceWith = ReplaceWithPolyfill;
78 }
79
80 /**
81 * Polyfill for NodeList.foreach() because we need to support IE11: https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach
82 */
83 if ( window.NodeList && ! NodeList.prototype.forEach ) {
84 NodeList.prototype.forEach = function ( callback, thisArg ) {
85 let i;
86 const len = this.length;
87
88 thisArg = thisArg || window;
89
90 for ( i = 0; i < len; i++ ) {
91 callback.call( thisArg, this[ i ], i, this );
92 }
93 };
94 }
95 } )();
96
97 advads = {
98 /**
99 * check if localstorage is supported/enabled by client
100 */
101 supports_localstorage() {
102 'use strict';
103 try {
104 if ( ! window || window.localStorage === undefined ) {
105 return false;
106 }
107 // storage might be full or disabled
108 window.localStorage.setItem( 'x', 'x' );
109 window.localStorage.removeItem( 'x' );
110 return true;
111 } catch ( e ) {
112 return false;
113 }
114 },
115 /**
116 * check if the ad is displayed more than {max} times per session
117 * every check increases the counter
118 *
119 * @param {string} name (no id needed, just any id-formated string)
120 * @param {type} max number of maximum times the ad can be displayed within the period
121 * @return {bool} true if limit is reached
122 */
123 max_per_session( name, max ) {
124 let num = 1;
125 if ( max === undefined || parseInt( max ) === 0 ) {
126 max = 1;
127 }
128
129 // check if cookie exists and get the value
130 if ( this.cookie_exists( name ) ) {
131 if ( this.get_cookie( name ) >= max ) {
132 return true;
133 }
134 num = num + parseInt( this.get_cookie( name ) );
135 }
136 this.set_cookie( name, num );
137 return false;
138 },
139 /**
140 * increase a cookie with an integer value by 1
141 *
142 * @param {str} name of the cookie
143 * @param {int} exdays days until cookie expires
144 */
145 count_up( name, exdays ) {
146 let num = 1;
147
148 // check if cookie exists and get the value
149 if ( this.cookie_exists( name ) ) {
150 num = num + parseInt( this.get_cookie( name ) );
151 }
152 this.set_cookie( name, num );
153 },
154 /**
155 * return true, if cookie exists
156 * return false, if not
157 * if not exists, create it
158 * use case: to check if something already happened in this page impression
159 *
160 * @param {type} name
161 * @return {unresolved}
162 */
163 set_cookie_exists( name ) {
164 if ( get_cookie( name ) ) {
165 return true;
166 }
167 set_cookie( name, '', 0 );
168 return false;
169 },
170 /**
171 * get a cookie value
172 *
173 * @param {string} name of the cookie
174 * @return {string} decoded cookie value
175 */
176 get_cookie( name ) {
177 let i,
178 x,
179 y,
180 ADVcookies = document.cookie.split( ';' );
181 for ( i = 0; i < ADVcookies.length; i++ ) {
182 x = ADVcookies[ i ].substr( 0, ADVcookies[ i ].indexOf( '=' ) );
183 y = ADVcookies[ i ].substr( ADVcookies[ i ].indexOf( '=' ) + 1 );
184 x = x.replace( /^\s+|\s+$/g, '' );
185 if ( x === name ) {
186 return decodeURIComponent( y );
187 }
188 }
189 },
190 /**
191 * set a cookie value
192 *
193 * @param {str} name of the cookie
194 * @param {str} value of the cookie
195 * @param {int} exdays days until cookie expires
196 * set 0 to expire cookie immidiatelly
197 * set null to expire cookie in the current session
198 * @param path
199 * @param domain
200 * @param secure
201 */
202 set_cookie( name, value, exdays, path, domain, secure ) {
203 // days in seconds
204 const expiry = exdays == null ? null : exdays * 24 * 60 * 60;
205 this.set_cookie_sec( name, value, expiry, path, domain, secure );
206 },
207 /**
208 * set a cookie with expiry given in seconds
209 *
210 * @param {str} name of the cookie
211 * @param {str} value of the cookie
212 * @param {int} expiry seconds until cookie expires
213 * set 0 to expire cookie immidiatelly
214 * set null to expire cookie in the current session
215 * @param path
216 * @param domain
217 * @param secure
218 */
219 set_cookie_sec( name, value, expiry, path, domain, secure ) {
220 const exdate = new Date();
221 exdate.setSeconds( exdate.getSeconds() + parseInt( expiry ) );
222 document.cookie =
223 name +
224 '=' +
225 encodeURIComponent( value ) +
226 ( expiry == null ? '' : '; expires=' + exdate.toUTCString() ) +
227 ( path == null ? '; path=/' : '; path=' + path ) +
228 ( domain == null ? '' : '; domain=' + domain ) +
229 ( secure == null ? '' : '; secure' );
230 },
231 /**
232 * check if a cookie is set and contains a value
233 *
234 * @param {str} name of the cookie
235 * @return {bool} true, if cookie is set
236 */
237 cookie_exists( name ) {
238 const c_value = this.get_cookie( name );
239 if ( c_value !== null && c_value !== '' && c_value !== undefined ) {
240 return true;
241 }
242 return false;
243 },
244 /**
245 * move one element into another
246 *
247 * @param {str} element selector of the element that should be moved
248 * @param {str} target selector of the element where to move
249 * @param {arr} options
250 */
251 move( element, target, options ) {
252 const el = jQuery( element );
253 const target_string = target;
254
255 if ( typeof options === 'undefined' ) {
256 options = {};
257 }
258 if ( typeof options.css === 'undefined' ) {
259 options.css = {};
260 }
261 if ( typeof options.method === 'undefined' ) {
262 options.method = 'prependTo';
263 }
264
265 if (
266 typeof options.offset !== 'undefined' &&
267 ( options.offset === 'right' || options.offset === 'left' )
268 ) {
269 options.method = 'insertAfter';
270 }
271
272 // search for abstract target element
273 if ( target === '' && typeof options.target !== 'undefined' ) {
274 switch ( options.target ) {
275 case 'wrapper': // wrapper
276 var offset = 'left';
277 if ( typeof options.offset !== 'undefined' ) {
278 offset = options.offset;
279 }
280 target = this.find_wrapper( element, offset );
281 break;
282 }
283 }
284
285 // use only visible elements
286 if ( typeof options.moveintohidden === 'undefined' ) {
287 target = jQuery( target ).filter( ':visible' );
288 } else {
289 target = jQuery( target );
290 }
291
292 // print warning in console if the element appears multiple times
293 if ( target.length > 1 ) {
294 console.log(
295 "Advanced Ads: element '" +
296 target_string +
297 "' found " +
298 target.length +
299 ' times.'
300 );
301 }
302
303 // switch insert method
304 switch ( options.method ) {
305 case 'insertBefore':
306 el.insertBefore( target );
307 break;
308 case 'insertAfter':
309 el.insertAfter( target );
310 break;
311 case 'appendTo':
312 el.appendTo( target );
313 break;
314 case 'prependTo':
315 el.prependTo( target );
316 break;
317 default:
318 el.prependTo( target );
319 }
320 },
321
322 /**
323 * Set 'relative' position for a parent element.
324 *
325 * @param {str} element selector
326 * @param options
327 */
328 set_parent_relative( element, options ) {
329 var options = typeof options !== 'undefined' ? options : {};
330 const el = jQuery( element );
331 // give "position" style to parent element, if missing
332 let parent = el.parent();
333
334 if ( options.use_grandparent ) {
335 parent = parent.parent();
336 }
337
338 if (
339 parent.css( 'position' ) === 'static' ||
340 parent.css( 'position' ) === ''
341 ) {
342 parent.css( 'position', 'relative' );
343 }
344 },
345
346 /**
347 * make an absolute position element fixed at the current position
348 * hint: use only after DOM is fully loaded in order to fix a wrong position
349 *
350 * @param {str} element selector
351 * @param {obj} options
352 */
353 fix_element( element, options ) {
354 var options = typeof options !== 'undefined' ? options : {};
355
356 const el = jQuery( element );
357
358 if ( options.use_grandparent ) {
359 this.set_parent_relative( el.parent() );
360 } else {
361 this.set_parent_relative( el );
362 }
363
364 // fix element at current position
365 // get position for hidden elements by showing them for a very short time
366 if ( options.is_invisible ) {
367 el.show();
368 }
369 const topoffset = parseInt( el.offset().top );
370 const leftoffset = parseInt( el.offset().left );
371 if ( options.is_invisible ) {
372 el.hide();
373 }
374 if ( 'left' === options.offset ) {
375 // Allow to scale the nested image down when it has `max-width: 100%` and touches the left edge of the viewport.
376 const rightoffset =
377 jQuery( window ).width() - leftoffset - el.outerWidth();
378 el.css( 'position', 'fixed' )
379 .css( 'top', topoffset + 'px' )
380 .css( 'right', rightoffset + 'px' )
381 .css( 'left', '' );
382 } else {
383 // reset "right" to prevent conflicts
384 el.css( 'position', 'fixed' )
385 .css( 'top', topoffset + 'px' )
386 .css( 'left', leftoffset + 'px' )
387 .css( 'right', '' );
388 }
389 },
390
391 /**
392 * find the main wrapper
393 * either id or first of its class
394 *
395 * @param {str} element selector
396 * @param {str} offset which position of the offset to check (left or right)
397 * @return {str} selector
398 */
399 find_wrapper( element, offset ) {
400 // first margin: auto element after body
401 let returnValue;
402
403 const excludes = [
404 'script',
405 '.screen-reader-text',
406 '.skip-link',
407 element,
408 '.' + advancedAds.frontendPrefix + 'entity-placement',
409 ].join( ', ' );
410
411 jQuery( 'body' )
412 .children()
413 .not( excludes )
414 .each( function ( key, value ) {
415 // check offset value
416 const checkedelement = jQuery( value );
417 // check if there is space left or right of the element
418 if (
419 ( offset === 'right' &&
420 checkedelement.offset().left +
421 jQuery( checkedelement ).width() <
422 jQuery( window ).width() ) ||
423 ( offset === 'left' && checkedelement.offset().left > 0 )
424 ) {
425 // fix element
426 if (
427 checkedelement.css( 'position' ) === 'static' ||
428 checkedelement.css( 'position' ) === ''
429 ) {
430 checkedelement.css( 'position', 'relative' );
431 }
432 // set return value
433 returnValue = value;
434 return false;
435 }
436 } );
437 return returnValue;
438 },
439 /**
440 * center fixed element on the screen
441 *
442 * @param {str} element selector
443 */
444 center_fixed_element( element ) {
445 const el = jQuery( element );
446 // half window width minus half element width
447 const left =
448 jQuery( window ).width() / 2 - parseInt( el.css( 'width' ) ) / 2;
449 el.css( 'left', left + 'px' );
450 },
451 /**
452 * center element vertically on the screen
453 *
454 * @param {str} element selector
455 */
456 center_vertically( element ) {
457 const el = jQuery( element );
458 // half window height minus half element height
459 let left =
460 jQuery( window ).height() / 2 - parseInt( el.css( 'height' ) ) / 2;
461
462 // Center correctly when the ad is attached to the element that begins lower.
463 if ( el.css( 'position' ) !== 'fixed' ) {
464 left -= topoffset = parseInt( el.offset().top );
465 }
466 el.css( 'top', left + 'px' );
467 },
468 /**
469 * close an ad and add a cookie
470 *
471 * @param {str} element selector
472 */
473 close( element ) {
474 const wrapper = jQuery( element );
475 // remove the ad
476 wrapper.remove();
477 },
478 /**
479 * Wait until images are ready.
480 *
481 * @param {obj} $el jQuery object.
482 * @param {Function} ready_callback Ready callback.
483 * derrived from https://github.com/alexanderdickson/waitForImages/blob/master/dist/jquery.waitforimages.js
484 */
485 wait_for_images( $el, ready_callback ) {
486 let loaded_count = 0;
487 const srcs = [];
488
489 $el.find( 'img[src][src!=""]' ).each( function () {
490 srcs.push( this.src );
491 } );
492
493 if ( srcs.length === 0 ) {
494 ready_callback.call( $el );
495 }
496
497 jQuery.each( srcs, function ( i, src ) {
498 const image = new Image();
499 image.src = src;
500 const events = 'load error';
501
502 jQuery( image ).one( events, function me( event ) {
503 // Remove remaining handler (either 'load' or 'error').
504 jQuery( this ).off( events, me );
505 loaded_count++;
506
507 if ( loaded_count == srcs.length ) {
508 ready_callback.call( $el[ 0 ] );
509 return false;
510 }
511 } );
512 } );
513 },
514
515 privacy: {
516 state: 'unknown',
517 state_executed: false,
518 /**
519 * Get consent state.
520 * IIFE so the events fire only once per event.
521 *
522 * @return string
523 * 'not_needed' - consent is not needed.
524 * 'accepted' - consent was given.
525 * 'unknown' - consent was not given yet.
526 */
527 get_state: ( function () {
528 return function () {
529 // if we already have a state, return that.
530 if ( window.advads_options.privacy.state !== 'unknown' ) {
531 // make sure this only gets executed once.
532 if ( ! advads.privacy.state_executed ) {
533 advads.privacy.state_executed = true;
534 advads.privacy.dispatch_event(
535 window.advads_options.privacy.state,
536 false
537 );
538 }
539 return advads.privacy.state;
540 }
541
542 // If using the cookie method, fire an initial event, regardless if cookie set or not.
543 if (
544 window.advads_options.privacy[ 'consent-method' ] ===
545 'custom'
546 ) {
547 var cookie_regex = new RegExp(
548 '.*?' +
549 window.advads_options.privacy[
550 'custom-cookie-value'
551 ] +
552 '[^;]*?'
553 );
554 const cookie =
555 advads.get_cookie(
556 window.advads_options.privacy[
557 'custom-cookie-name'
558 ]
559 ) || '';
560
561 // Force the event, if we haven't yet fired one.
562 if ( ! advads.privacy.state_executed ) {
563 advads.privacy.state_executed = true;
564 advads.privacy.dispatch_event(
565 cookie.match( cookie_regex )
566 ? 'accepted'
567 : 'unknown',
568 true
569 );
570 }
571 }
572
573 // make sure this only gets executed once.
574 advads.privacy.state_executed = true;
575
576 // Run this in an interval (every 0.3s) just in case we are still waiting for consent
577 var cnt = 0,
578 consentSetInterval = setInterval( function () {
579 // Bail if we have not gotten a consent response after 60 seconds.
580 if ( ++cnt === 181 ) {
581 clearInterval( consentSetInterval );
582 }
583 switch (
584 window.advads_options.privacy[ 'consent-method' ]
585 ) {
586 case 'custom':
587 const cookie =
588 advads.get_cookie(
589 window.advads_options.privacy[
590 'custom-cookie-name'
591 ]
592 ) || '';
593
594 // check if custom cookie is set and matches value.
595 if ( cookie.match( cookie_regex ) ) {
596 clearInterval( consentSetInterval );
597 if ( advads.privacy.state !== 'accepted' ) {
598 advads.privacy.dispatch_event(
599 'accepted',
600 true
601 );
602 }
603 }
604 break;
605
606 case 'iab_tcf_20':
607 // Check if window.__tcfapi has been set.
608 if ( typeof window.__tcfapi === 'undefined' ) {
609 return;
610 }
611 clearInterval( consentSetInterval );
612
613 window.__tcfapi(
614 'addEventListener',
615 2,
616 function ( TCData, listenerSuccess ) {
617 if ( ! listenerSuccess ) {
618 return;
619 }
620 if (
621 TCData.eventStatus === 'tcloaded' ||
622 TCData.eventStatus ===
623 'useractioncomplete' ||
624 // if this is google funding choices, eventStatus is not set. Check if either gdpr doesn't apply or if there is a purpose object.
625 ( TCData.eventStatus === null &&
626 typeof window.googlefc !==
627 'undefined' &&
628 ( typeof TCData.purpose !==
629 'undefined' ||
630 ! TCData.gdprApplies ) )
631 ) {
632 const userAction =
633 TCData.eventStatus ===
634 'useractioncomplete';
635 if ( ! TCData.gdprApplies ) {
636 if (
637 advads.privacy.state !==
638 'not_needed'
639 ) {
640 advads.privacy.dispatch_event(
641 'not_needed',
642 userAction
643 );
644 }
645 return;
646 }
647
648 if (
649 TCData.purpose.consents[ 1 ]
650 ) {
651 if (
652 advads.privacy.state !==
653 'accepted'
654 ) {
655 advads.privacy.dispatch_event(
656 'accepted',
657 userAction
658 );
659 }
660 return;
661 }
662
663 // fire another event, in case the user revokes the previous consent.
664 if (
665 advads.privacy.state !==
666 'rejected'
667 ) {
668 advads.privacy.dispatch_event(
669 'rejected',
670 userAction
671 );
672 }
673 }
674 }
675 );
676 break;
677 }
678 }, 333 );
679
680 return advads.privacy.state;
681 };
682 } )(),
683 /**
684 * Check if the privacy_method is custom cookie, and non personalized ads are allowed.
685 *
686 * @return {boolean}
687 */
688 is_adsense_npa_enabled() {
689 if ( ! window.advads_options || ! window.advads_options.privacy ) {
690 return true;
691 }
692 return !! (
693 window.advads_options.privacy[
694 'show-non-personalized-adsense'
695 ] &&
696 window.advads_options.privacy[ 'consent-method' ] === 'custom'
697 );
698 },
699 /**
700 * Dispatch a custom event whenever the state changes.
701 *
702 * @param {string} state The current privacy state.
703 * @param {boolean} userAction This is result of action by user.
704 */
705 dispatch_event( state, userAction ) {
706 const previousState = advads.privacy.state,
707 fire_event = function () {
708 document.dispatchEvent(
709 new CustomEvent( 'advanced_ads_privacy', {
710 detail: {
711 state,
712 previousState,
713 userAction,
714 },
715 } )
716 );
717 };
718
719 advads.privacy.state = state;
720
721 console.log( {
722 state,
723 previousState,
724 userAction,
725 } );
726
727 window.advanced_ads_ready_queue.push( fire_event );
728 },
729 /**
730 * Check if ad is decoded.
731 *
732 * @param {integer} id
733 *
734 * @return {boolean}
735 */
736 is_ad_decoded( id ) {
737 return (
738 document.querySelector(
739 'script[data-tcf="waiting-for-consent"][data-id="' +
740 id +
741 '"]'
742 ) === null
743 );
744 },
745 /**
746 * Decode ad content.
747 *
748 * @param {Element} el
749 * @param {boolean} [inject=true]
750 */
751 decode_ad( el, inject ) {
752 // this can also be a number if used in a foreach.
753 inject = typeof inject === 'boolean' ? inject : true;
754 const string = decodeURIComponent(
755 Array.prototype.map
756 .call( atob( el.textContent ), function ( c ) {
757 return (
758 '%' +
759 ( '00' + c.charCodeAt( 0 ).toString( 16 ) ).slice(
760 -2
761 )
762 );
763 } )
764 .join( '' )
765 );
766
767 if ( ! inject ) {
768 return string;
769 }
770
771 el.replaceWith(
772 document.createRange().createContextualFragment( string )
773 );
774 },
775 },
776 };
777
778 window.advanced_ads_ready_queue.push( advads.privacy.get_state );
779
780 document.addEventListener( 'advanced_ads_privacy', function ( event ) {
781 if (
782 ( event.detail.state !== 'accepted' &&
783 event.detail.state !== 'not_needed' ) ||
784 event.detail.userAction ||
785 document.readyState === 'loading'
786 ) {
787 return;
788 }
789
790 // Find all scripts waiting for consent and decode them.
791 document
792 .querySelectorAll(
793 'script[type="text/plain"][data-tcf="waiting-for-consent"]'
794 )
795 .forEach( advads.privacy.decode_ad );
796 } );
797 /* eslint-enable */
798