<div id="oms_gpt_skyscraper" class="c-ad js-ad-stroeer c-ad--sky"></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 %}
{
"text": "Werbung: sky",
"additionalClass": "js-ad-stroeer c-ad--sky",
"id": "oms_gpt_skyscraper"
}
/**
* @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;
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;
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;
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;
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);
});
});
});
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;
.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;
}
}
There are no notes for this item.