assets/themes/j1/adapter/js/advertising.js in j1-template-2023.3.0 vs assets/themes/j1/adapter/js/advertising.js in j1-template-2023.3.1

- old
+ new

@@ -4,11 +4,11 @@ {% capture cache %} {% comment %} # ----------------------------------------------------------------------------- - # ~/assets/themes/j1/adapter/js/advertising.js + # ~/assets/theFdames/j1/adapter/js/advertising.js # Liquid template to adapt advertising plugin # # Product/Info: # https://jekyll.one # Copyright (C) 2023 Juergen Adams @@ -53,10 +53,11 @@ {% comment %} Variables -------------------------------------------------------------------------------- {% endcomment %} {% assign advertising = advertising_options.enabled %} {% assign advertising_provider = advertising_options.provider %} +{% assign layout = page.layout %} {% comment %} Detect prod mode -------------------------------------------------------------------------------- {% endcomment %} {% assign production = false %} {% if environment == 'prod' or environment == 'production' %} @@ -88,19 +89,23 @@ 'use strict'; j1.adapter.advertising = (function (j1, window) { {% comment %} Set global variables -------------------------------------------------------------------------------- {% endcomment %} -var environment = '{{environment}}'; -var date = new Date(); -var timestamp_now = date.toISOString(); -var gasScript = document.createElement('script'); -var gasDiv = document.createElement('div'); -var gasIns = document.createElement('ins'); -var adInitializerScript = document.createElement('script'); +var environment = '{{environment}}'; +var production = (environment.includes('prod') ? true : false); +var development = (environment.includes('dev') ? true : false); +var date = new Date(); +var timestamp_now = date.toISOString(); +var gasScript = document.createElement('script'); +var gasDiv = document.createElement('div'); +var gasIns = document.createElement('ins'); +var adInitializerScript = document.createElement('script'); +var advertisingProvider = 'Google Adsense'; +var layout; var advertisingDefaults; -var aadvertisingSettings; +var advertisingSettings; var advertisingOptions; var frontmatterOptions; var autoHideOnUnfilled; var addBorderOnUnfilled; var checkTrackingProtection; @@ -110,13 +115,12 @@ var url; var baseUrl; var hostname; var cookie_names; var user_consent; -var advertisingProvider; var publisherID; -var validPublisherID; +var validpublisherID; var _this; var logger; var logText; // --------------------------------------------------------------------------- @@ -147,146 +151,193 @@ user_consent = j1.readCookie(cookie_names.user_consent); url = new liteURL(window.location.href); hostname = url.hostname; // create settings object from frontmatter + // frontmatterOptions = options != null ? $.extend({}, options) : {}; + // initialze advertisingOptions + // advertisingDefaults = $.extend({}, {{advertising_defaults | replace: 'nil', 'null' | replace: '=>', ':' }}); - aadvertisingSettings = $.extend({}, {{advertising_settings | replace: 'nil', 'null' | replace: '=>', ':' }}); - advertisingOptions = $.extend(true, {}, advertisingDefaults, aadvertisingSettings); - + advertisingSettings = $.extend({}, {{advertising_settings | replace: 'nil', 'null' | replace: '=>', ':' }}); + advertisingOptions = $.extend(true, {}, advertisingDefaults, advertisingSettings, frontmatterOptions); + layout = advertisingOptions.layout; + publisherID = advertisingOptions.google.publisherID; + validpublisherID = (publisherID.includes('pub-')) ? true : false; autoHideOnUnfilled = advertisingOptions.google.autoHideOnUnfilled; addBorderOnUnfilled = advertisingOptions.google.addBorderOnUnfilled; checkTrackingProtection = advertisingOptions.google.checkTrackingProtection; showErrorPageOnBlocked = advertisingOptions.google.showErrorPageOnBlocked; + // run initialization on 'contentVisible' + // var dependencies_met_page_ready = setInterval (function (options) { - var pageState = $('#no_flicker').css("display"); - var pageVisible = (pageState == 'block') ? true: false; - var atticFinished = (j1.adapter.attic.getState() == 'finished') ? true: false; + var contentState = $('#content').css("display"); + var contentVisible = (contentState == 'block') ? true: false; -// if (j1.getState() === 'finished' && pageVisible && atticFinished) { - if (j1.getState() === 'finished' && pageVisible) { + if (j1.getState() === 'finished' && contentVisible) { + + {% comment %} detect|load code if 'advertising' is 'enabled' + ------------------------------------------------------------------------ {% endcomment %} {% if advertising %} - var advertisingProvider = 'Google Adsense'; - var providerID = '{{advertising_options.google.publisherID}}'; - var validProviderID = (providerID.includes('pub-')) ? true : false; - if (!validProviderID) { - logger.warn('\n' + 'invalid publisher id: ' + providerID); - logger.info('\n' + 'module disabled' ); + _this.ad_initializer(); + + if (!validpublisherID) { + if (development) { + logger.warn('\n' + 'invalid publisher id: ' + publisherID); + logger.info('\n' + 'module disabled' ); + } clearInterval(dependencies_met_page_ready); return false; } {% case advertising_provider %} {% when "google" %} - // [INFO ] [j1.adapter.advertising ] [ place provider: Google Adsense ] + // [INFO ] [j1.adapter.advertising ] [ place provider: Google Adsense ] // initialize state flag + // _this.setState('started'); - logger.debug('\n' + 'state: ' + _this.getState()); + if (development) { + logger.debug('\n' + 'state: ' + _this.getState()); + } if (user_consent.personalization) { - logger.info('\n' + 'adsense api is being initialized'); + if (development) { + logger.info('\n' + 'adsense api is being initialized'); + } - publisherID = advertisingOptions.google.publisherID; - advertisingProvider = 'Google Adsense'; - validPublisherID = (publisherID.includes('your')) ? false : true; - - if (!validPublisherID) { - logger.debug('\n' + 'invalid publisherID detected for Google Adsense (GAS): ' + publisherID); - logger.info('\n' + 'skip initialization for provider: ' + advertisingProvider); - // return false; + if (!validpublisherID) { + if (development) { + logger.debug('\n' + 'invalid publisherID detected for Google Adsense: ' + publisherID); + logger.info('\n' + 'skip initialization for provider: ' + advertisingProvider); + } + return false; } else { - logger.info('\n' + 'use publisherID for Google Adsense (GAS): ' + publisherID); + if (development) { + logger.info('\n' + 'use publisherID for Google Adsense: ' + publisherID); + } } - // add GAS API (Google Adsense) dynamically in head section - // loaded async - // ----------------------------------------------------------------- - logger.info('\n' + 'add Google Adsense (GAS) API in section: head'); + // add Google Adsense API dynamically in head section loaded async + // + if (development) { + logger.info('\n' + 'add Google AdsenseAPI in section: head'); + } + gasScript.async = true; gasScript.id = 'gas-api'; gasScript.src = '//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js'; gasScript.setAttribute('data-ad-client', publisherID); document.head.appendChild(gasScript); - logger.info('\n' + 'adsense api initialized'); + if (development) { + logger.info('\n' + 'adsense api initialized'); + } + // setup monitor for state changes on all ads configured - // ----------------------------------------------------------------- - logger.info('\n' + 'setup ad monitoring'); - _this.ad_monitor(); + // + setTimeout(function () { + var ads_found = (document.getElementsByClassName('adsbygoogle').length > 0) ? true : false; + if (ads_found > 0) { + if (development) { + logger.info('\n' + 'setup Google Ad monitoring'); + } + _this.ad_monitor(); + } else { + if (development) { + logger.warn('\n' + 'no initialized Google Ads found in page'); + } + } + }, 1000); // run protection check - // ----------------------------------------------------------------- + // if (checkTrackingProtection) { - logger.debug('\n' + 'run checks for tracking protection'); + if (development) { + logger.debug('\n' + 'run checks for tracking protection'); + } _this.check_tracking_protection(); var dependencies_met_tracking_check_ready = setInterval (function (options) { if (typeof tracking_protection !== 'undefined' ) { var browser_tracking_feature = navigator.DoNotTrack; if (!tracking_protection && !browser_tracking_feature) { - logText = '\n' + 'tracking protection: disabled'; - logger.info(logText); + if (development) { + logText = '\n' + 'tracking protection: disabled'; + logger.info(logText); + } } else { - logText = '\n' + 'tracking protection: enabled'; - logger.debug(logText); + if (development) { + logText = '\n' + 'tracking protection: enabled'; + logger.debug(logText); + } if (showErrorPageOnBlocked) { - logger.error('\n' + 'redirect to error page (blocked content): HTML-447'); + if (development) { + logger.error('\n' + 'redirect to error page (blocked content): HTML-447'); + } // redirect to error page: blocked content window.location.href = '/447.html'; } } } + clearInterval(dependencies_met_tracking_check_ready); }, 10); } else { // no protection check enabled _this.setState('finished'); - logger.debug('\n' + 'state: ' + _this.getState()); - logger.info('\n' + 'module initialized successfully'); + + if (development) { + logger.debug('\n' + 'state: ' + _this.getState()); + logger.info('\n' + 'module initialized successfully'); + } + clearInterval(dependencies_met_tracking_check_ready); } } else { // user consent on personalization "false" // - logger.warn('\n' + 'user consent on personalization: ' + user_consent.personalization); - logger.warn('\n' + 'initializing module: skipped'); + if (production) { + console.debug('cookies for personalization rejected'); + console.debug('initialization of module advertising skipped'); + } else { + logger.warn('\n' + 'user consent on personalization: ' + user_consent.personalization); + logger.warn('\n' + 'initializing module: skipped'); + } - // manage GAD cookies if no consent is given|rejected - // ----------------------------------------------------------------- - var gasCookies = j1.findCookie('__ga'); - logger.debug('\n' + 'consent on cookies disabled for personalization'); - logger.debug('\n' + 'initialization of module advertising skipped'); - - // remove cookies on invalid GAS config or left from a previous - // session/page view if they exists - // ------------------------------------------------------------------ + // if consent is rejected, detect and remove Adsense cookies + // + var gasCookies = j1.findCookie('__g'); gasCookies.forEach(function (item) { - // Remove cookies from Google Ads + // remove Google Ad cookies + // if (hostname == 'localhost') { j1.removeCookie({ name: item, domain: false, secure: false }); } else { j1.removeCookie({ name: item, domain: '.' + hostname, secure: false }); } }); // manage tracking protection - // ----------------------------------------------------------------- + // if (checkTrackingProtection) { if (!user_consent.personalization) { - logText = '\n' + 'consent on cookies disabled for personalization'; - logger.debug(logText); + if (development) { + logText = '\n' + 'consent on cookies disabled for personalization'; + logger.debug(logText); + } if (showErrorPageOnBlocked) { - logger.error('\n' + 'redirect to error page (blocked content): HTML-447'); + if (development) { + logger.error('\n' + 'redirect to error page (blocked content): HTML-447'); + } // redirect to error page: blocked content window.location.href = '/448.html'; } } } @@ -297,52 +348,199 @@ // [INFO ] [j1.adapter.advertising ] [ place provider: Custom Provider ] {% endcase %} // [INFO ] [j1.adapter.advertising ] [ end processing ] {% else %} var ads_found = document.getElementsByClassName('adsbygoogle').length; - logger = log4javascript.getLogger('j1.adapter.advertising'); - logger.debug('\n' + 'found ads in page: #' + ads_found); - logger.debug('\n' + 'no ads initialized, advertising disabled'); - {% endif %} + if (development) { + logger = log4javascript.getLogger('j1.adapter.advertising'); + logger.debug('\n' + 'found ads in page: #' + ads_found); + logger.debug('\n' + 'no ads initialized, advertising disabled'); + } + {% endif %} // END if 'advertising' clearInterval(dependencies_met_page_ready); } }, 10); }, // END init // ------------------------------------------------------------------------- + // ad_initializer() + // initialze all ad units in a page (ins elements) + // ------------------------------------------------------------------------- + ad_initializer: function () { + + var dependencies_met_page_visible = setInterval (function (options) { + var contentState = $('#content').css("display"); + var contentVisible = (contentState == 'block') ? true: false; + var ads_found = (document.getElementsByClassName('adsbygoogle').length > 0) ? true : false; + var ads_initialized = 0; + var ad_containers; + + if (j1.getState() === 'finished' && contentVisible && ads_found) { + if (!validpublisherID) { + // skip setup processes + // + clearInterval(dependencies_met_page_visible); + return false; + } + + // create|loading adverting for containers enabled + // + ad_containers = advertisingOptions.google.ads; + ad_containers.forEach(function (ad) { + if (user_consent.personalization) { + var currentDiv = document.getElementById(ad.id); + + if (ad.enabled && ad.layout == layout) { + var ins = document.createElement('ins'); + + currentDiv.appendChild(ins); + var insID = 'ins_' + ad.id; + ins.setAttribute('id', insID); + ins.className = "adsbygoogle"; + + document.getElementById(insID).setAttribute('style', ad.styles); + document.getElementById(insID).setAttribute('data-ad-test', ad.test) + document.getElementById(insID).setAttribute('data-ad-client', ad.publisherID); + document.getElementById(insID).setAttribute('data-ad-slot', ad.slot); + document.getElementById(insID).setAttribute('data-ad-format', ad.ad_format); + + if (ad.ad_layout == 'display') { + document.getElementById(insID).setAttribute('data-full-width-responsive', ad.ad_responsive); + } + + // if (ad.ad_layout == 'in-article') { + // document.getElementById(insID).setAttribute('data-ad-format', ad.ad_format); + // } + + if (ad.ad_layout == 'multiplex') { + document.getElementById(insID).setAttribute('data-matched-content-ui-typ', ad.ui_type); + document.getElementById(insID).setAttribute('data-matched-content-columns-num', ad.ui_columns); + document.getElementById(insID).setAttribute('data-matched-content-rows-num', ad.ui_rows); + } + + ads_initialized ++; + } else { + if (ad.layout == layout) { + if (development) { + logger.warn('\n' + 'ad disabled on id ' + ad.id + ' for slot: ' + ad.slot); + } + } + } + } else { + if (development) { + logger.warn('\n' + 'skipped add settings on all ad containers'); + } + } // END if user_consent.personalization + + }); + // END loading adverting containers + + if (ads_initialized > 0) { + if (development) { + logger.info('\n' + 'ads enabled found in page (total): ' + ads_initialized); + } + + var google_ads = document.getElementsByClassName('adsbygoogle'); + var counter = document.getElementsByClassName('adsbygoogle').length; + + // jadams, 2023-06-22: + // skip last element in google_ads (adsbygoogle-noablate) + // TODO: clarify for what reason an 'ins' element with + // class 'adsbygoogle-noablate' is added by Googgle Adsense + // Possible reason: publisherID is 'wrong|fake' or NOT 'verified' + // + counter--; + + [].forEach.call(google_ads, function() { + // skip last element in google_ads (adsbygoogle-noablate) + if (counter > 0) { + (adsbygoogle = window.adsbygoogle || []).push({}); + } + counter --; + }); + } else { + if (development) { + logger.warn('\n' + 'no ads found in page for layout: ' + layout); + } + } // END if ads_initialized + + clearInterval(dependencies_met_page_visible); + } // END contentVisible|ads_found + + }, 10); // END dependencies_met_page_visible + + }, // END ad_initializer + + // ------------------------------------------------------------------------- // ad_monitor() // monitor for state changes on the ad placed in pages (if any) // // NOTE: Check visibility state of the adSlot to prevent multiple // processing of the same slot + // + // NOTE: Skip ad containers with class 'adsbygoogle-noablate' + // // ------------------------------------------------------------------------- ad_monitor: function () { - // logger.info('\n' + 'setup ad monitoring'); $('.adsbygoogle').attrchange({ trackValues: true, callback: function (event) { - if (event.newValue === 'unfilled') { - var elm = event.target.dataset; - var adSlotIsVisible = $('.adsbygoogle').is(":visible"); - if (adSlotIsVisible) { - logger.warn('\n' + 'detected ad on slot ' + elm.adSlot + ' in state: ' + event.newValue); + var elm = event.target.dataset; + var elm_classes = event.target.className; + var validAdContainer = (elm_classes.includes('adsbygoogle-noablate')) ? false : true; + var environment = '{{environment}}'; + var production = (environment.includes('prod') ? true : false); + var adSlotIsVisible = $('.adsbygoogle').is(":visible"); + + if (adSlotIsVisible && validAdContainer && event.newValue !== event.oldValue) { + if (event.newValue === 'unfilled') { + if (production) { + console.debug('detected ad blocks in state: unfilled'); + } else { + logger.warn('\n' + 'detected ad on slot ' + elm.adSlot + ' in state: ' + event.newValue); + } if (addBorderOnUnfilled) { $('.adsbygoogle').addClass('border--dotted'); } - if (autoHideOnUnfilled) { - logger.info('\n' + ' hide ad on slot: ' + elm.adSlot); + if (development) { + logger.info('\n' + ' hide ad on slot: ' + elm.adSlot); + } $('.adsbygoogle').hide(); } - } - } else { - // logger.info('\n' + 'found ad in state ' + event.newValue + ' on slot: ' + elm.adSlot); - } - } - }); - }, + } else if (event.newValue === 'filled') { + if (development) { + logger.info('\n' + 'detected ad on slot ' + elm.adSlot + ' in state: ' + event.newValue); + } + } else { + var filled = (event.newValue.includes('display') ? true : false); + var unfilled = (event.newValue.includes('dotted') ? true : false); + if (filled) { + if (production) { + console.info('detected ad blocks in state: filled'); + } else { + logger.info('\n' + 'detected ad block on slot ' + elm.adSlot + ' in state: filled'); + } + } else if (unfilled) { + if (production) { + console.info('detected ad blocks in state: unfilled'); + } else { + logger.info('\n' + 'detected ad block on slot ' + elm.adSlot + ' in state: unfilled'); + } + } else { + if (production) { + console.warn('unknown ad state detected: ' + event.newValue); + } else { + logger.warn('\n' + 'unknown ad state detected on slot ' + elm.adSlot + ' : ' + event.newValue); + } + } + } // END if 'event.newValue' + } // END if 'adSlotIsVisible' + } // END 'callback' + }); // END 'attrchange' + }, // END ad_monitor // ------------------------------------------------------------------------- // check_tracking_protection() // detect if a user is using tracking protection // NOTE: @@ -355,12 +553,14 @@ // https://stackoverflow.com/questions/33959324/how-to-detect-if-a-user-is-using-tracking-protection-in-firefox-42 // ------------------------------------------------------------------------- check_tracking_protection: function () { var logger = log4javascript.getLogger('j1.adapter.advertising.monitor.tracking'); - logText = '\n' + 'check for trackingprotection'; - logger.info(logText); + if (development) { + logText = '\n' + 'check for trackingprotection'; + logger.info(logText); + } function checkTrackingProtection() { if (!checkTrackingProtection.promise) { checkTrackingProtection.promise = new Promise(function(resolve, reject) { @@ -377,11 +577,13 @@ img.src = '//www.facebook.com/tr/'; }).then((result) => { tracking_protection = false; }).catch(e => { tracking_protection = true; - logger.debug('\n' + 'detection details: ' + e); + if (development) { + logger.debug('\n' + 'detection details: ' + e); + } }); } } checkTrackingProtection(); @@ -392,20 +594,24 @@ // manage messages send from other J1 modules // ------------------------------------------------------------------------- messageHandler: function (sender, message) { var json_message = JSON.stringify(message, undefined, 2); - logText = '\n' + 'received message from ' + sender + ': ' + json_message; - logger.debug(logText); + if (development) { + logText = '\n' + 'received message from ' + sender + ': ' + json_message; + logger.debug(logText); + } // ----------------------------------------------------------------------- // Process commands|actions // ----------------------------------------------------------------------- if (message.type === 'command' && message.action === 'module_initialized') { // // Place handling of command|action here // - logger.info('\n' + message.text); + if (development) { + logger.info('\n' + message.text); + } } // // Place handling of other command|action here //