Scriptlets icon indicating copy to clipboard operation
Scriptlets copied to clipboard

Fix `googletagservices-gpt` — broken website - bloomberg.com

Open AdamWr opened this issue 3 years ago • 0 comments

Steps to reproduce:

  1. Add this rule:
||securepubads.g.doubleclick.net/tag/js/gpt.js$script,redirect=googletagservices-gpt,important,domain=bloomberg.com
  1. Go to - https://www.bloomberg.com/quote/SX5E:IND

Stock list below header is not displayed.

Screenshot

image

It seems that this works fine - https://searchfox.org/mozilla-central/source/browser/extensions/webcompat/shims/google-publisher-tags.js

Basing on mentioned script something like this:

Code
function GoogleTagServicesGpt() {

    const noopFunc = function () { };
    const noopThis = function () { return this; };
    const noopNull = function () { return null; };
    const noopArray = function () { return []; };
    const noopStr = function () { return ""; };
    const trueFunc = function () { return true; };

    const slots = new Map();
    const slotsById = new Map();
    const eventCallbacks = new Map();


    const addEventListener = function(name, listener) {
        if (!eventCallbacks.has(name)) {
          eventCallbacks.set(name, new Set());
        }
        eventCallbacks.get(name).add(listener);
        return this;
      };
    
      const removeEventListener = function(name, listener) {
        if (eventCallbacks.has(name)) {
          return eventCallbacks.get(name).delete(listener);
        }
        return false;
      };

    const fireSlotEvent = (name, slot) => {
        return new Promise(resolve => {
            requestAnimationFrame(() => {
                const size = [0, 0];
                for (const cb of eventCallbacks.get(name) || []) {
                    cb({ isEmpty: true, size, slot });
                }
                resolve();
            });
        });
    };

    const displaySlot = async slot => {
        if (!slot) {
            return;
        }
        const id = slot.getSlotElementId();
        if (!document.getElementById(id)) {
            return;
        }

        const parent = document.getElementById(id);
        if (parent) {
            parent.appendChild(document.createElement("div"));
        }

        await fireSlotEvent("slotRenderEnded", slot);
        await fireSlotEvent("slotRequested", slot);
        await fireSlotEvent("slotResponseReceived", slot);
        await fireSlotEvent("slotOnload", slot);
        await fireSlotEvent("impressionViewable", slot);
    };

    const companionAdsService = {
        addEventListener: addEventListener,
        removeEventListener: removeEventListener,
        enableSyncLoading: noopFunc,
        setRefreshUnfilledSlots: noopFunc,
        getSlots: noopArray,
    };
    const contentService = {
        addEventListener: addEventListener,
        removeEventListener: removeEventListener,
        setContent: noopFunc,
    };
    function PassbackSlot() { } // constructor

    PassbackSlot.prototype.display = noopFunc;
    PassbackSlot.prototype.get = noopNull;
    PassbackSlot.prototype.set = noopThis;
    PassbackSlot.prototype.setClickUrl = noopThis;
    PassbackSlot.prototype.setTagForChildDirectedTreatment = noopThis;
    PassbackSlot.prototype.setTargeting = noopThis;
    PassbackSlot.prototype.updateTargetingFromMap = noopThis;

    function SizeMappingBuilder() { } // constructor
    SizeMappingBuilder.prototype.addSize = noopThis;
    SizeMappingBuilder.prototype.build = noopNull;

    function Slot(adUnitPath, creatives, opt_div) {
        this.adUnitPath = adUnitPath;
        this.creatives = creatives;
        this.opt_div = opt_div;

        if (slotsById.has(opt_div)) {
            document.getElementById(opt_div)?.remove();
            return slotsById.get(opt_div);
        }
        slotsById.set(opt_div, this);
    } // constructor
    Slot.prototype.addService = noopThis;
    Slot.prototype.clearCategoryExclusions = noopThis;
    Slot.prototype.clearTargeting = noopThis;
    Slot.prototype.defineSizeMapping = noopThis;
    Slot.prototype.get = noopNull;
    Slot.prototype.getAdUnitPath = noopStr;
    Slot.prototype.getAttributeKeys = noopArray;
    Slot.prototype.getCategoryExclusions = noopArray;
    Slot.prototype.getDomId = function () {
        return this.opt_div;
    };
    Slot.prototype.getSlotElementId = function () {
        return this.opt_div;
    };
    Slot.prototype.getSlotId = noopThis;
    Slot.prototype.getSizes = noopArray;
    Slot.prototype.getTargeting = noopArray;
    Slot.prototype.getTargetingKeys = noopArray;
    Slot.prototype.set = noopThis;
    Slot.prototype.setCategoryExclusion = noopThis;
    Slot.prototype.setClickUrl = noopThis;
    Slot.prototype.setCollapseEmptyDiv = noopThis;
    Slot.prototype.setTargeting = noopThis;

    const pubAdsService = {
        addEventListener: addEventListener,
        removeEventListener: removeEventListener,
        clear: noopFunc,
        clearCategoryExclusions: noopThis,
        clearTagForChildDirectedTreatment: noopThis,
        clearTargeting: noopThis,
        collapseEmptyDivs: noopFunc,
        defineOutOfPagePassback() { return new PassbackSlot(); },
        definePassback() { return new PassbackSlot(); },
        disableInitialLoad: noopFunc,
        display: noopFunc,
        enableAsyncRendering: noopFunc,
        enableLazyLoad: noopFunc,
        enableSingleRequest: noopFunc,
        enableSyncRendering: noopFunc,
        enableVideoAds: noopFunc,
        get: noopNull,
        getAttributeKeys: noopArray,
        getTargeting: noopArray,
        getTargetingKeys: noopArray,
        getSlots: noopArray,
        isInitialLoadDisabled: trueFunc,
        refresh: noopFunc,
        set: noopThis,
        setCategoryExclusion: noopThis,
        setCentering: noopFunc,
        setCookieOptions: noopThis,
        setForceSafeFrame: noopThis,
        setLocation: noopThis,
        setPublisherProvidedId: noopThis,
        setRequestNonPersonalizedAds: noopThis,
        setSafeFrameConfig: noopThis,
        setTagForChildDirectedTreatment: noopThis,
        setTargeting: noopThis,
        setVideoContent: noopThis,
        updateCorrelator: noopFunc,
    };

    const { googletag = {} } = window;
    const { cmd = [] } = googletag;

    googletag.apiReady = true;
    googletag.cmd = [];
    googletag.cmd.push = (a) => {
        try {
            a();
            // eslint-disable-next-line no-empty
        } catch (ex) { }
        return 1;
    };
    googletag.companionAds = () => companionAdsService;
    googletag.content = () => contentService;
    googletag.defineOutOfPageSlot = (adUnitPath, creatives, opt_div) => new Slot(adUnitPath, creatives, opt_div);
    googletag.defineSlot = (adUnitPath, creatives, opt_div) => new Slot(adUnitPath, creatives, opt_div);
    googletag.destroySlots = function () {
        slots.clear();
        slotsById.clear();
    };
    googletag.disablePublisherConsole = noopFunc;
    googletag.display = function (arg) {
        let id;
        if (arg?.getSlotElementId) {
            id = arg.getSlotElementId();
        } else if (arg?.nodeType) {
            id = arg.id;
        } else {
            id = String(arg);
        }
        displaySlot(slotsById.get(id));
    };
    googletag.enableServices = noopFunc;
    googletag.getVersion = noopStr;
    googletag.pubads = () => pubAdsService;
    googletag.pubadsReady = true;
    googletag.setAdIframeTitle = noopFunc;
    googletag.sizeMapping = () => new SizeMappingBuilder();

    window.googletag = googletag;
    while (cmd.length !== 0) {
        googletag.cmd.push(cmd.shift());
    }

} GoogleTagServicesGpt()

seems to fixes issue, but it just example and requires more tweaks.

AdamWr avatar Aug 11 '22 10:08 AdamWr