@highfivve/ad-tag 5.7.2 → 5.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/ads/googleAdManager.js +1 -1
- package/lib/ads/modules/custom/index.js +58 -0
- package/lib/ads/moli.js +6 -7
- package/lib/bundle/custom.js +2 -0
- package/lib/console/components/globalConfig.js +9 -7
- package/lib/console/debug.js +36 -15
- package/lib/console/util/calculateAdDensity.js +1 -1
- package/lib/gen/packageJson.js +1 -1
- package/lib/util/browserStorageKeys.js +2 -1
- package/lib/util/environmentOverride.js +25 -2
- package/lib/util/queryParameters.js +2 -1
- package/package.json +1 -1
|
@@ -341,7 +341,7 @@ export const gptDefineSlots = () => (context, slots) => {
|
|
|
341
341
|
const checkAndSwitchToWebInterstitial = (slotsToRefresh, context) => {
|
|
342
342
|
const interstitialSlot = slotsToRefresh.find(({ moliSlot }) => moliSlot.position === 'interstitial');
|
|
343
343
|
if (interstitialSlot && context.auction__.interstitialChannel() === 'gam') {
|
|
344
|
-
const targeting = { ...interstitialSlot.adSlot.getConfig('targeting') };
|
|
344
|
+
const targeting = { ...interstitialSlot.adSlot.getConfig('targeting').targeting };
|
|
345
345
|
context.window__.googletag.destroySlots([interstitialSlot.adSlot]);
|
|
346
346
|
const gamWebInterstitial = context.window__.googletag.defineOutOfPageSlot(resolveAdUnitPath(interstitialSlot.moliSlot.adUnitPath, context.adUnitPathVariables__), context.window__.googletag.enums.OutOfPageFormat.INTERSTITIAL);
|
|
347
347
|
if (gamWebInterstitial) {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { mkInitStep } from 'ad-tag/ads/adPipeline';
|
|
2
|
+
const name = 'custom';
|
|
3
|
+
export const customModule = () => {
|
|
4
|
+
let customConfig = null;
|
|
5
|
+
const injectInlineJs = (context, config) => {
|
|
6
|
+
if (config.inlineJs && config.inlineJs.code) {
|
|
7
|
+
try {
|
|
8
|
+
const script = context.window__.document.createElement('script');
|
|
9
|
+
script.type = 'text/javascript';
|
|
10
|
+
script.innerHTML = config.inlineJs.code;
|
|
11
|
+
context.window__.document.head.appendChild(script);
|
|
12
|
+
context.logger__?.info(name, 'Injected inline JS');
|
|
13
|
+
}
|
|
14
|
+
catch (e) {
|
|
15
|
+
context.logger__?.error(name, 'Failed to inject inline JS', e);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
if (config.scripts) {
|
|
19
|
+
config.scripts
|
|
20
|
+
.filter(scriptConfig => context.labelConfigService__.filterSlot(scriptConfig))
|
|
21
|
+
.forEach(scriptConfig => {
|
|
22
|
+
try {
|
|
23
|
+
const script = context.window__.document.createElement('script');
|
|
24
|
+
script.type = 'text/javascript';
|
|
25
|
+
script.src = scriptConfig.src;
|
|
26
|
+
if (scriptConfig.attributes) {
|
|
27
|
+
Object.entries(scriptConfig.attributes).forEach(([key, value]) => {
|
|
28
|
+
script.setAttribute(key, value);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
context.window__.document.head.appendChild(script);
|
|
32
|
+
context.logger__?.info(name, `Injected script from URL: ${scriptConfig.src}`);
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
context.logger__?.error(name, 'Failed to inject script from config', scriptConfig, e);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return Promise.resolve();
|
|
40
|
+
};
|
|
41
|
+
return {
|
|
42
|
+
name,
|
|
43
|
+
description: 'Injects custom inline JavaScript code',
|
|
44
|
+
moduleType: 'custom',
|
|
45
|
+
config__: () => null,
|
|
46
|
+
configure__: (moduleConfig) => {
|
|
47
|
+
if (moduleConfig?.custom?.enabled) {
|
|
48
|
+
customConfig = moduleConfig.custom;
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
initSteps__: () => {
|
|
52
|
+
const config = customConfig;
|
|
53
|
+
return config ? [mkInitStep('custom-init', ctx => injectInlineJs(ctx, config))] : [];
|
|
54
|
+
},
|
|
55
|
+
configureSteps__: () => [],
|
|
56
|
+
prepareRequestAdsSteps__: () => []
|
|
57
|
+
};
|
|
58
|
+
};
|
package/lib/ads/moli.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { parseQueryString } from '../util/query';
|
|
2
1
|
import { AssetLoadMethod, createAssetLoaderService } from '../util/assetLoaderService';
|
|
3
2
|
import { getLogger } from '../util/logging';
|
|
4
3
|
import { addNewInfiniteSlotToConfig } from '../util/addNewInfiniteSlotToConfig';
|
|
5
4
|
import { AdService } from './adService';
|
|
6
5
|
import { createEventService } from './eventService';
|
|
7
|
-
import { getActiveEnvironmentOverride, setEnvironmentOverrideInStorage } from '../util/environmentOverride';
|
|
6
|
+
import { getAbTestValues, getActiveEnvironmentOverride, setEnvironmentOverrideInStorage } from '../util/environmentOverride';
|
|
8
7
|
import { packageJson } from '../gen/packageJson';
|
|
9
8
|
import * as adUnitPath from './adUnitPath';
|
|
10
9
|
import { extractTopPrivateDomainFromHostname } from '../util/extractTopPrivateDomainFromHostname';
|
|
11
10
|
import { createLabelConfigService } from './labelConfigService';
|
|
12
11
|
import { allowRefreshAdSlot, allowRequestAds } from './spa';
|
|
12
|
+
import { QueryParameters } from 'ad-tag/util/queryParameters';
|
|
13
|
+
import { BrowserStorageKeys } from 'ad-tag/util/browserStorageKeys';
|
|
13
14
|
export const createMoliTag = (window) => {
|
|
14
15
|
const assetLoaderService = createAssetLoaderService(window);
|
|
15
16
|
const eventService = createEventService();
|
|
@@ -577,11 +578,9 @@ export const createMoliTag = (window) => {
|
|
|
577
578
|
}
|
|
578
579
|
}
|
|
579
580
|
function setABtestTargeting() {
|
|
580
|
-
const
|
|
581
|
-
const
|
|
582
|
-
|
|
583
|
-
const abTest = param ? Number(param) : Math.floor(Math.random() * 100) + 1;
|
|
584
|
-
setTargeting(key, abTest.toString());
|
|
581
|
+
const abTestValues = getAbTestValues(window, QueryParameters.abTest, BrowserStorageKeys.abTest);
|
|
582
|
+
const abTestValue = abTestValues.length > 0 ? Number(abTestValues[0].value) : Math.floor(Math.random() * 100) + 1;
|
|
583
|
+
setTargeting(QueryParameters.abTest, abTestValue.toString());
|
|
585
584
|
}
|
|
586
585
|
function addDomainLabel(domainFromConfig) {
|
|
587
586
|
const domain = domainFromConfig || extractTopPrivateDomainFromHostname(window.location.hostname);
|
|
@@ -374,7 +374,8 @@ export class GlobalConfig extends Component {
|
|
|
374
374
|
React.createElement("div", { className: "MoliDebug-tagContainer" },
|
|
375
375
|
React.createElement(TagLabel, null, "Overall Mode"),
|
|
376
376
|
runtimeConfig.environment === 'test' ? (React.createElement(Tag, { variant: "yellow" }, "Test")) : (React.createElement(Tag, { variant: "green" }, "Production")),
|
|
377
|
-
isEnvironmentOverridden ? (React.createElement("button", { className: "MoliDebug-button MoliDebug-button--green", onClick: this.resetEnvironmentOverrides }, "\u25C0 Reset override")) : (React.createElement("button", { className: "MoliDebug-button MoliDebug-button--yellow MoliDebug-button--greyText", onClick: this.overrideEnvironmentToTest }, "\u25B6 Override to test"))
|
|
377
|
+
isEnvironmentOverridden ? (React.createElement("button", { className: "MoliDebug-button MoliDebug-button--green", onClick: this.resetEnvironmentOverrides }, "\u25C0 Reset override")) : (React.createElement("button", { className: "MoliDebug-button MoliDebug-button--yellow MoliDebug-button--greyText", onClick: this.overrideEnvironmentToTest }, "\u25B6 Override to test")),
|
|
378
|
+
React.createElement("button", { className: "MoliDebug-button MoliDebug-button--blue", onClick: () => this.props.onShowOverlaysChange(!this.props.showOverlays) }, this.props.showOverlays ? '◀ Hide overlays' : '▶ Show overlays')),
|
|
378
379
|
interstitialSlot && (React.createElement("div", { className: "MoliDebug-tagContainer" },
|
|
379
380
|
React.createElement(TagLabel, null, "Interstitital Test Mode"),
|
|
380
381
|
isInterstitialTestEnabled ? (React.createElement("button", { className: "MoliDebug-button MoliDebug-button--green", onClick: () => {
|
|
@@ -438,12 +439,13 @@ export class GlobalConfig extends Component {
|
|
|
438
439
|
showOnlyRenderedSlots: e.target.checked
|
|
439
440
|
}) }),
|
|
440
441
|
"Show only rendered slots")),
|
|
441
|
-
|
|
442
|
-
React.createElement("
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
442
|
+
this.props.showOverlays &&
|
|
443
|
+
config.slots.map((slot, index) => this.isSlotRendered(slot) || !showOnlyRenderedSlots ? (React.createElement("div", { key: index },
|
|
444
|
+
React.createElement("strong", null, slot.behaviour.loaded),
|
|
445
|
+
" slot with DOM ID",
|
|
446
|
+
' ',
|
|
447
|
+
React.createElement("strong", null, slot.domId),
|
|
448
|
+
React.createElement(AdSlotConfig, { labelConfigService: labelConfigService, slot: slot }))) : null)))),
|
|
447
449
|
React.createElement("div", { className: "MoliDebug-sidebarSection MoliDebug-sidebarSection--targeting" },
|
|
448
450
|
React.createElement("h4", null,
|
|
449
451
|
this.collapseToggle('targeting'),
|
package/lib/console/debug.js
CHANGED
|
@@ -15,23 +15,44 @@ if (moliConfig) {
|
|
|
15
15
|
let container = document.createElement('div');
|
|
16
16
|
container.classList.add('moli-console-container');
|
|
17
17
|
const shadowRoot = container.attachShadow({ mode: 'open' });
|
|
18
|
-
const
|
|
18
|
+
const DebugConsole = () => {
|
|
19
|
+
const [showOverlays, setShowOverlays] = React.useState(false);
|
|
20
|
+
const slotRoots = React.useRef(new Map());
|
|
21
|
+
React.useEffect(() => {
|
|
22
|
+
setTimeout(() => {
|
|
23
|
+
const globalConfigComponentRoot = shadowRoot.getElementById('moli-console-global-config');
|
|
24
|
+
themingService.setRootElement(globalConfigComponentRoot);
|
|
25
|
+
themingService.applyTheme();
|
|
26
|
+
themingService.enableSystemThemeListener();
|
|
27
|
+
}, 200);
|
|
28
|
+
}, []);
|
|
29
|
+
React.useEffect(() => {
|
|
30
|
+
if (showOverlays) {
|
|
31
|
+
moliConfig.slots.forEach(slot => {
|
|
32
|
+
const slotDomElement = document.getElementById(slot.domId);
|
|
33
|
+
if (slotDomElement && labelConfigService.filterSlot(slot)) {
|
|
34
|
+
let slotConfigRoot = slotRoots.current.get(slot.domId);
|
|
35
|
+
if (!slotConfigRoot) {
|
|
36
|
+
slotConfigRoot = createRoot(slotDomElement);
|
|
37
|
+
slotRoots.current.set(slot.domId, slotConfigRoot);
|
|
38
|
+
}
|
|
39
|
+
slotConfigRoot.render(React.createElement(AdSlotConfig, { labelConfigService: labelConfigService, slot: slot, parentElement: slotDomElement }));
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
slotRoots.current.forEach(root => {
|
|
45
|
+
root.unmount();
|
|
46
|
+
});
|
|
47
|
+
slotRoots.current.clear();
|
|
48
|
+
}
|
|
49
|
+
}, [showOverlays]);
|
|
50
|
+
return (React.createElement(React.Fragment, null,
|
|
51
|
+
React.createElement(GlobalConfig, { config: moliConfig, runtimeConfig: window.moli.getRuntimeConfig(), modules: window.moli.getConfig()?.modules || {}, labelConfigService: labelConfigService, windowResizeService: new WindowResizeService(), themingService: themingService, showOverlays: showOverlays, onShowOverlaysChange: setShowOverlays })));
|
|
52
|
+
};
|
|
19
53
|
window.document.body.append(container);
|
|
20
54
|
const root = createRoot(shadowRoot);
|
|
21
|
-
root.render(
|
|
22
|
-
setTimeout(() => {
|
|
23
|
-
const globalConfigComponentRoot = shadowRoot.getElementById('moli-console-global-config');
|
|
24
|
-
themingService.setRootElement(globalConfigComponentRoot);
|
|
25
|
-
themingService.applyTheme();
|
|
26
|
-
themingService.enableSystemThemeListener();
|
|
27
|
-
}, 200);
|
|
28
|
-
moliConfig.slots.forEach(slot => {
|
|
29
|
-
const slotDomElement = document.getElementById(slot.domId);
|
|
30
|
-
if (slotDomElement && labelConfigService.filterSlot(slot)) {
|
|
31
|
-
const slotConfigRoot = createRoot(slotDomElement);
|
|
32
|
-
slotConfigRoot.render(React.createElement(AdSlotConfig, { labelConfigService: labelConfigService, slot: slot, parentElement: slotDomElement }));
|
|
33
|
-
}
|
|
34
|
-
});
|
|
55
|
+
root.render(React.createElement(DebugConsole, null));
|
|
35
56
|
}
|
|
36
57
|
else {
|
|
37
58
|
window.alert('No moli config found. The console cannot be displayed');
|
|
@@ -29,7 +29,7 @@ export function calculateAdDensity(contentSelector, adSelectorOverride) {
|
|
|
29
29
|
console.warn('Content area is zero');
|
|
30
30
|
return { totalAdDensity: 0, totalAdArea: 0, adAreaPerSlot: [] };
|
|
31
31
|
}
|
|
32
|
-
const totalAdDensity = (totalAdArea / pageArea) * 100;
|
|
32
|
+
const totalAdDensity = Math.round((totalAdArea / pageArea) * 100);
|
|
33
33
|
logMessages.push(`Total ad area: ${totalAdArea}px², Page area: ${pageArea}px², Ad density: ${totalAdDensity.toFixed(2)}%`);
|
|
34
34
|
console.log(logMessages.join('\n'));
|
|
35
35
|
return { totalAdDensity, totalAdArea, adAreaPerSlot };
|
package/lib/gen/packageJson.js
CHANGED
|
@@ -1,13 +1,36 @@
|
|
|
1
1
|
import { BrowserStorageKeys } from './browserStorageKeys';
|
|
2
|
-
import { removeBrowserStorageValue, setBrowserStorageValue } from './localStorage';
|
|
3
|
-
import { updateQueryString } from './query';
|
|
2
|
+
import { getBrowserStorageValue, removeBrowserStorageValue, setBrowserStorageValue } from './localStorage';
|
|
3
|
+
import { parseQueryString, updateQueryString } from './query';
|
|
4
4
|
import { QueryParameters } from './queryParameters';
|
|
5
5
|
import { resolveOverrides } from './resolveOverrides';
|
|
6
|
+
import { isNotNull } from 'ad-tag/util/arrayUtils';
|
|
6
7
|
const isEnvironmentString = (environment) => {
|
|
7
8
|
const validValues = ['production', 'test'];
|
|
8
9
|
return !!validValues.find(value => value === environment);
|
|
9
10
|
};
|
|
11
|
+
const isValidAbTestValue = (value) => {
|
|
12
|
+
const num = Number(value);
|
|
13
|
+
return !isNaN(num) && num >= 1 && num <= 100;
|
|
14
|
+
};
|
|
10
15
|
export const getActiveEnvironmentOverride = (window) => resolveOverrides(window, QueryParameters.moliEnv, BrowserStorageKeys.moliEnv, isEnvironmentString)[0] || undefined;
|
|
16
|
+
export const getAbTestValues = (window, abTestQueryParam, abTestBrowserStorageKey) => {
|
|
17
|
+
return [
|
|
18
|
+
{
|
|
19
|
+
source: 'queryParam',
|
|
20
|
+
value: parseQueryString(window.location.search).get(abTestQueryParam)
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
source: 'sessionStorage',
|
|
24
|
+
value: getBrowserStorageValue(abTestBrowserStorageKey, window.sessionStorage)
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
source: 'localStorage',
|
|
28
|
+
value: getBrowserStorageValue(abTestBrowserStorageKey, window.localStorage)
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
.map(({ source, value }) => !!value && isValidAbTestValue(value) ? { source, value } : undefined)
|
|
32
|
+
.filter(isNotNull);
|
|
33
|
+
};
|
|
11
34
|
export const setEnvironmentOverrideInStorage = (value, storage) => setBrowserStorageValue(BrowserStorageKeys.moliEnv, value, storage);
|
|
12
35
|
export const resetEnvironmentOverrides = (window) => {
|
|
13
36
|
removeBrowserStorageValue(BrowserStorageKeys.moliEnv, window.sessionStorage);
|