Ad

100%
<!-- Sky -->
<div class="c-ad"></div>

<!-- Skyscraper -->
<div id="oms_gpt_skyscraper" class="c-ad js-ad-stroeer c-ad--sky"></div>

<!-- Billboard -->
<div class="show-for-medium">
    <div id="oms_gpt_billboard" class="c-ad js-ad-stroeer c-ad--billboard"></div>
</div>

<!-- Superbanner -->
<div id="oms_gpt_superbanner" class="c-ad js-ad-stroeer c-ad--banner"></div>

<!-- Rectangle -->
<div id="oms_gpt_standard" class="c-ad js-ad-stroeer c-ad--rectangle"></div>

<!-- Rectangle 2 -->
<div id="oms_gpt_standard2" class="c-ad js-ad-stroeer c-ad--rectangle2"></div>

<!-- Topmobile 2 -->
<div class="show-for-small-only">
    <div id="oms_gpt_topmobile2" class="c-ad js-ad-stroeer c-ad--topmobile2"></div>
</div>

<!-- Seeding -->
<div class="c-ad js-ad-seeding"></div>

<!-- Taboola -->
<div id="taboola-below-article-thumbnails" class="c-ad js-ad-taboola"></div>

<!-- Ivw -->
<div class="c-ad js-ivw"></div>

{% if viewport %}
<div class="show-for-{{ viewport }}">
{% endif %}
    <div{% if id %} id="{{ id }}"{% endif %} class="c-ad{% if additionalClass %} {{ additionalClass }}{% endif %}"></div>
{% if viewport %}
</div>
{% endif %}
/* Sky */
{
  "text": "skyscraper",
  "additionalClass": ""
}

/* Skyscraper */
{
  "text": "Werbung: sky",
  "additionalClass": "js-ad-stroeer c-ad--sky",
  "id": "oms_gpt_skyscraper"
}

/* Billboard */
{
  "text": "Werbung: billboard",
  "additionalClass": "js-ad-stroeer c-ad--billboard",
  "viewport": "medium",
  "id": "oms_gpt_billboard"
}

/* Superbanner */
{
  "text": "Werbung: banner",
  "additionalClass": "js-ad-stroeer c-ad--banner",
  "id": "oms_gpt_superbanner"
}

/* Rectangle */
{
  "text": "Werbung: rectangle",
  "additionalClass": "js-ad-stroeer c-ad--rectangle",
  "id": "oms_gpt_standard"
}

/* Rectangle 2 */
{
  "text": "Werbung: rectangle2",
  "additionalClass": "js-ad-stroeer c-ad--rectangle2",
  "id": "oms_gpt_standard2"
}

/* Topmobile 2 */
{
  "text": "Werbung: topmobile2",
  "additionalClass": "js-ad-stroeer c-ad--topmobile2",
  "viewport": "small-only",
  "id": "oms_gpt_topmobile2"
}

/* Seeding */
{
  "text": "Werbung: seeding",
  "additionalClass": "js-ad-seeding"
}

/* Taboola */
{
  "text": "Werbung: taboola",
  "additionalClass": "js-ad-taboola",
  "id": "taboola-below-article-thumbnails"
}

/* Ivw */
{
  "text": "Analyse: IVW",
  "additionalClass": "js-ivw"
}

  • Content:
    /**
     * @desc CMP loader helper.
     */
    class Cmp {
      constructor() {
        this.registeredVendors = [];
      }
    
      /**
       *
       * @param {Element} what The created script element
       * @param {Boolean} vendorAllowed User consent regarding the vendor related to the script
       */
      // eslint-disable-next-line class-methods-use-this
      applyWithConsent(what, vendorAllowed, callback) {
        const firstScriptOnPage = document.getElementsByTagName('script')[0];
        if (vendorAllowed) {
          firstScriptOnPage.parentNode.insertBefore(what, firstScriptOnPage);
          if (callback) callback();
        }
      }
    
      /**
       * Tests for strings in id (which implies a custom vendor). IAB vendor IDs are numeric only.
       * @param {String|Number} id
       * @return {boolean}
       */
      // eslint-disable-next-line class-methods-use-this
      isIABVendor(id) {
        return !Number.isNaN(parseInt(id, 10));
      }
    
      /**
       *
       * @param {Object} consents
       * @param {String|Number} vendorId
       * @return {boolean}
       */
      // eslint-disable-next-line class-methods-use-this
      getConsentState(consents, vendorId) {
        const vendorList = consents.vendorConsents;
    
        return (typeof (consents) === 'object') && 'gdprApplies' in consents
          && (!consents.gdprApplies
            || (vendorId in vendorList && vendorList[vendorId]));
      }
    
      /**
       * Public helper especially used by Stroeer to get consent information for Google Ad Manager
       * (IAB 755). We still use __cmp as API here as __tcfapi delivers different results for certain
       * methods (not here though).
       * @param cmp
       * @param {Number} vendorId Vendor Id.
       * @returns {boolean|*}
       * @see https://stroeerdigitalgroup.atlassian.net/wiki/spaces/SDGPUBLIC/pages/1273004657/Einbau+des+Publisher+eignen+CMPs#EinbaudesPublishereignenCMPs-WeitereDienstleister
       */
      getPublicConsentState(api, vendorId) {
        const status = api('consentStatus');
        if (typeof (status) === 'object' && 'consentExists' in status && status.consentExists) {
          // consent data is present, check if consent for vendor is given
          return this.getConsentState(api('getCMPData'), vendorId); // => true, dann Google hat die Zustimmung
        }
        return false;
      }
    
      /**
       * Wrapper function to ensures availability of data and functions needed to validate user consent.
       * Waits for CMP object to attach "consent" event listener. Applies ad scripts then.
       * This actually is a necessary workaround to implementing CMP via GTM also in regards to the
       * proposed IAB standard. That one states that __cmp should be available asap in order to attach
       * event handlers (init) properly, too.
       * @param what {Element} The created script element
       * @param vendorId {Number} The vendor's id within the CMP tool.
       * @param disregardConsent {Boolean}
       */
      // eslint-disable-next-line class-methods-use-this
      waitForConsent(what, vendorId, disregardConsent, callback) {
        const interval = setInterval(() => {
          // Wait for __cmp to be available, a function and to have a consentStatus
          const cmp = window.__cmp;
          if (typeof cmp === 'function' && typeof cmp('consentStatus') === 'object') {
            const vendorIsAllowed = disregardConsent || this.getConsentState(cmp('getCMPData'), vendorId);
            if (disregardConsent) {
              // eslint-disable-next-line no-console
              console.info(`[CMP] "${vendorId}" doesn't apply to consent and will render: %c${vendorIsAllowed ? 'YES' : 'NO'}`, 'font-weight: 700');
            } else {
              // eslint-disable-next-line no-console
              console.info(`[CMP] "${vendorId}" applies to consent and consent is: %c${vendorIsAllowed ? 'YES' : 'NO'}`, 'font-weight: 700');
            }
    
            clearInterval(interval);
            this.applyWithConsent(what, vendorIsAllowed, callback);
    
            // Attach vendor to event listener check only when it isn't initialized already & always.
            if (!disregardConsent) {
              // NOTE Add event listener for vendors which might not be loaded yet
              if (!this.registeredVendors.length) {
                // add a listener once. Then, iterate over all possible registered vendors
                cmp('addEventListener', ['consent', (e, o) => {
                  this.registeredVendors.forEach((id) => {
                    const eventVendorIsAllowed = this.getConsentState(cmp('getCMPData'), id);
                    // eslint-disable-next-line no-console
                    console.info(`[CMP] updated. Will ${id} (${o.getVendor(id).name || ''}) render? %c${eventVendorIsAllowed ? 'YES' : 'NO'}`, 'font-weight:700');
                    this.applyWithConsent(what, eventVendorIsAllowed, callback);
                  });
                }, false], null);
              }
    
              this.registeredVendors.push(vendorId);
            }
          }
        }, 200);
      }
    }
    
    /* eslint-enable no-undef */
    export default Cmp;
    
  • URL: /components/raw/ad/ad-cmp-loader.js
  • Filesystem Path: src/patterns/20-components/ad/ad-cmp-loader.js
  • Size: 4.8 KB
  • Content:
    import Cmp from './ad-cmp-loader';
    
    class AdPaidTaboola {
      constructor() {
        window._taboola = window._taboola || [];
        window._taboola.push({ article: 'auto' });
    
        // Notes for Consent Manager integration
        // https://www.taboola.com/documents/consent-management-technical-integration-guidelines-publishers.pdf
    
        // eslint-disable-next-line camelcase
        const script = document.createElement('script');
        script.async = true;
        script.id = 'tb_loader_script';
        script.src = '//cdn.taboola.com/libtrc/stroeergamma-hildesheimer/loader.js';
    
        const cmp = new Cmp();
        // eslint-disable-next-line max-len
        // NOTE We don't need the vendorId actually as we disregard it, still we submit it for console output
        cmp.waitForConsent(script, 42);
    
        if (window.performance && typeof window.performance.mark === 'function') {
          window.performance.mark('tbl_ic');
        }
    
        script.onload = () => {
          window._taboola = window._taboola || [];
          window._taboola.push({
            mode: 'thumbnails-a',
            container: 'taboola-widget-plus-article',
            placement: 'Widget Plus Article',
            target_type: 'mix',
          });
        };
      }
    }
    
    export default AdPaidTaboola;
    
  • URL: /components/raw/ad/ad-paid-taboola.js
  • Filesystem Path: src/patterns/20-components/ad/ad-paid-taboola.js
  • Size: 1.2 KB
  • Content:
    import Cmp from './ad-cmp-loader';
    /**
     * Include advertisement seeding on page.
     *
     */
    
    class AdSeeding {
      constructor() {
        // eslint-disable-next-line camelcase
        const script = document.createElement('script');
        script.async = true;
        script.src = '//d.nativendo.de/cds/delivery/init';
    
        const cmp = new Cmp();
        // Seeding Alliance is an IAB compliant vendor, so its id is numeric only
        // eslint-disable-next-line max-len
        // NOTE We don't need the vendorId actually as we disregard it, still we submit it for console output
        // TODO Simplify code if it is really that simple that all IAB vendor may be loaded always as
        //  they stick to the IAB settings stored inside __cmp.
        cmp.waitForConsent(script, 371);
      }
    }
    
    export default AdSeeding;
    
  • URL: /components/raw/ad/ad-seeding.js
  • Filesystem Path: src/patterns/20-components/ad/ad-seeding.js
  • Size: 780 Bytes
  • Content:
    import _debounce from 'lodash/debounce';
    import Cmp from './ad-cmp-loader';
    
    /* eslint-disable no-undef */
    class adStroeer {
      /**
       * @param {Window.haz.ads|{tablet, disabledSlots, desktop, zone, mobile}} configurations
       */
      constructor(configurations) {
        const script = document.createElement('script');
        script.async = true;
        script.src = '//cdn.stroeerdigitalgroup.de/metatag/live/OMS_hildesheim_neu/metaTag.min.js';
    
    
        const cmp = new Cmp();
        cmp.waitForConsent(script, 136);
    
        this.configurations = configurations;
        this.currentViewportName = adStroeer.getViewportName(
          adStroeer.getClientWidth(),
          configurations,
        );
    
        script.onload = () => {
          adStroeer.configureSlots(cmp, configurations.zone);
          adStroeer.registerSlots(this.currentViewportName, configurations);
        };
      }
    
      update(throttleTimeout) {
        return _debounce(() => {
          const newViewPortName = adStroeer.getViewportName(
            adStroeer.getClientWidth(),
            this.configurations,
          );
    
          if (newViewPortName !== this.currentViewportName) {
            adStroeer.registerSlots(newViewPortName, this.configurations);
            this.currentViewportName = newViewPortName;
          }
        }, throttleTimeout);
      }
    
      static registerSlots(viewportName, configurations) {
        SDG.Publisher.unregisterAllSlots(true);
    
        const containers = document.getElementsByClassName('js-ad-stroeer');
        if (!containers.length) {
          return;
        }
    
        const device = configurations[viewportName];
        for (let i = 0; i < device.slots.length; i++) {
          const container = containers[device.slots[i].id];
          const restrictedParent = !!container && container.closest('[class*="show-for-"]');
          const isRestrictedAndVisible = restrictedParent && getComputedStyle(restrictedParent).display !== 'none';
    
          // Only register slots that are not disabled somehow (e.g. for the current page)
          if (
            adStroeer.isSlotEnabled(device.slots[i].adSlotName, configurations)
            && !!container
            && (!restrictedParent || isRestrictedAndVisible)
          ) {
            // eslint-disable-next-line max-len
            adStroeer.loadSlot(device.slots[i], device.targeting);
          }
        }
    
        SDG.Publisher.finalizeSlots();
      }
    
      static isSlotEnabled(slotName, configurations) {
        return !configurations.disabledSlots.includes(slotName);
      }
    
      static loadSlot(configuration, targeting) {
        const slot = SDG.Publisher.registerSlot(configuration.adSlotName, configuration.id);
    
        if (configuration.excludedSizes) {
          slot.removeSizes(configuration.excludedSizes);
        }
    
        slot.setTargeting(targeting);
        slot.load();
      }
    
      static configureSlots(cmp, zone) {
        // eslint-disable-next-line no-console
        console.info(`[CMP] 755 "Google Advertising Products" for Ströer: ${cmp.getPublicConsentState(__cmp, 755)}, %cNotice: Changes are effective on next page load.`, 'font-style: italic;color: #666');
        SDG.Publisher.setAdServerConsent(cmp.getPublicConsentState(__cmp, 755));
        SDG.Publisher.setZone(zone);
        SDG.Publisher.addKeywords([zone]);
        SDG.Publisher.addKeyValue(zone);
        SDG.Publisher.addKeyValues({ interessen: [zone] });
      }
    
      static getClientWidth() {
        return Math.max(document.documentElement.getClientWidth || 0, window.innerWidth || 0);
      }
    
      static getViewportName(clientWidth, configurations) {
        let viewportName = 'desktop';
    
        if (clientWidth <= configurations.mobile.maxWidth) {
          viewportName = 'mobile';
        } else if (clientWidth > configurations.mobile.maxWidth
          && clientWidth <= configurations.tablet.maxWidth) {
          viewportName = 'tablet';
        } else if (clientWidth > configurations.tablet.maxWidth) {
          viewportName = 'desktop';
        }
    
        return viewportName;
      }
    }
    /* eslint-enable no-undef */
    
    export default adStroeer;
    
  • URL: /components/raw/ad/ad-stroeer.js
  • Filesystem Path: src/patterns/20-components/ad/ad-stroeer.js
  • Size: 3.8 KB
  • Content:
    import adStroeer from './ad-stroeer';
    
    const AdStroeer = adStroeer; // Fix linter error :p
    
    describe('The Ströer ad helper', () => {
      it('exists and throws a TypeError without a global document and window.', () => {
        // Since the adStroeer object is so heavily reliant on window and document it is
        // impossible to test with the short amount of time I have left...
        // Everything I can do is test the TypeError :'(
        expect(() => new AdStroeer({}, 0))
          .toThrow(new TypeError('Cannot read property \'maxWidth\' of undefined'));
      });
    
      describe('exposes the static helper to calculate the viewport name', () => {
        const configurations = {
          mobile: { maxWidth: 640 },
          tablet: { maxWidth: 1024 },
        };
    
        it.each([
          [1025, 'desktop'],
          [2048, 'desktop'],
          [768, 'tablet'],
          [320, 'mobile'],
        ])('from %ipx to %s.', (clientWidth, expectedViewPortName) => {
          const name = AdStroeer.getViewportName(clientWidth, configurations);
          expect(name).toBe(expectedViewPortName);
        });
      });
    });
    
  • URL: /components/raw/ad/ad-stroeer.test.js
  • Filesystem Path: src/patterns/20-components/ad/ad-stroeer.test.js
  • Size: 1.1 KB
  • Content:
    import Cmp from './ad-cmp-loader';
    
    class AdTaboola {
      constructor() {
        window._taboola = window._taboola || [];
        window._taboola.push({ article: 'auto' });
    
        // Notes for Consent Manager integration
        // https://www.taboola.com/documents/consent-management-technical-integration-guidelines-publishers.pdf
    
        // eslint-disable-next-line camelcase
        const script = document.createElement('script');
        script.async = true;
        script.id = 'tb_loader_script';
        script.src = '//cdn.taboola.com/libtrc/stroeergamma-hildesheimer/loader.js';
    
        const cmp = new Cmp();
        // eslint-disable-next-line max-len
        // NOTE We don't need the vendorId actually as we disregard it, still we submit it for console output
        cmp.waitForConsent(script, 42);
    
        if (window.performance && typeof window.performance.mark === 'function') {
          window.performance.mark('tbl_ic');
        }
    
        script.onload = () => {
          window._taboola = window._taboola || [];
          window._taboola.push({
            mode: 'alternating-thumbnails-a',
            container: 'taboola-below-article-thumbnails',
            placement: 'Below Article Thumbnails',
            target_type: 'mix',
          });
        };
      }
    }
    
    export default AdTaboola;
    
  • URL: /components/raw/ad/ad-taboola.js
  • Filesystem Path: src/patterns/20-components/ad/ad-taboola.js
  • Size: 1.2 KB
  • Content:
    .c-ad {
        margin-bottom: $spacing;
    
        &--rectangle {
            @include breakpoint(large) {
                float: right;
            }
        }
    }
    
    @include breakpoint(small only) {
        .sdgSlotName-topmobile,
        .sdgSlotName-topmobile2,
        .oms_gpt_standard {
            min-height: 250px; /* https://jira.hdnet.de/browse/HAZ-567 */
            text-align: center;
        }
    }
    
    .c-imagead {
        margin: 1rem 0 1rem;
    
        .c-imagead-content {
            text-align: center;
        }
    }
    
  • URL: /components/raw/ad/ad.scss
  • Filesystem Path: src/patterns/20-components/ad/ad.scss
  • Size: 461 Bytes

There are no notes for this item.