@highfivve/ad-tag 5.7.2 → 5.8.0

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.
@@ -0,0 +1,39 @@
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
+ context.logger__?.warn(name, 'No inline JS code provided');
8
+ return Promise.resolve();
9
+ }
10
+ try {
11
+ const script = context.window__.document.createElement('script');
12
+ script.type = 'text/javascript';
13
+ script.innerHTML = config.inlineJs.code;
14
+ context.window__.document.head.appendChild(script);
15
+ context.logger__?.info(name, 'Injected inline JS');
16
+ }
17
+ catch (e) {
18
+ context.logger__?.error(name, 'Failed to inject inline JS', e);
19
+ }
20
+ return Promise.resolve();
21
+ };
22
+ return {
23
+ name,
24
+ description: 'Injects custom inline JavaScript code',
25
+ moduleType: 'custom',
26
+ config__: () => null,
27
+ configure__: (moduleConfig) => {
28
+ if (moduleConfig?.custom?.enabled) {
29
+ customConfig = moduleConfig.custom;
30
+ }
31
+ },
32
+ initSteps__: () => {
33
+ const config = customConfig;
34
+ return config ? [mkInitStep('custom-init', ctx => injectInlineJs(ctx, config))] : [];
35
+ },
36
+ configureSteps__: () => [],
37
+ prepareRequestAdsSteps__: () => []
38
+ };
39
+ };
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 key = 'ABtest';
581
- const params = parseQueryString(window.location.search);
582
- const param = params.get(key);
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);
@@ -0,0 +1,2 @@
1
+ import { customModule } from 'ad-tag/ads/modules/custom';
2
+ window.moli.registerModule(customModule());
@@ -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
- config.slots.map((slot, index) => this.isSlotRendered(slot) || !showOnlyRenderedSlots ? (React.createElement("div", { key: index },
442
- React.createElement("strong", null, slot.behaviour.loaded),
443
- " slot with DOM ID",
444
- ' ',
445
- React.createElement("strong", null, slot.domId),
446
- React.createElement(AdSlotConfig, { labelConfigService: labelConfigService, slot: slot }))) : null)))),
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'),
@@ -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 globalConfigComponent = (React.createElement(GlobalConfig, { config: moliConfig, runtimeConfig: window.moli.getRuntimeConfig(), modules: window.moli.getConfig()?.modules || {}, labelConfigService: labelConfigService, windowResizeService: new WindowResizeService(), themingService: themingService }));
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(globalConfigComponent);
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 };
@@ -1,3 +1,3 @@
1
1
  export const packageJson = {
2
- version: '5.7.2'
2
+ version: '5.8.0'
3
3
  };
@@ -3,5 +3,6 @@ export const BrowserStorageKeys = {
3
3
  moliPubCode: 'moli-pub-code',
4
4
  moliVersion: 'moli-version',
5
5
  testSlotSize: (id) => `moli-test-slot-size-${id}`,
6
- debugDelay: 'moli-debug-delay'
6
+ debugDelay: 'moli-debug-delay',
7
+ abTest: 'moli-ab-test'
7
8
  };
@@ -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);
@@ -1,5 +1,6 @@
1
1
  export const QueryParameters = {
2
2
  moliEnv: 'moliEnv',
3
3
  moliPubCode: 'moliPubCode',
4
- moliVersion: 'moliVersion'
4
+ moliVersion: 'moliVersion',
5
+ abTest: 'ABtest'
5
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@highfivve/ad-tag",
3
- "version": "5.7.2",
3
+ "version": "5.8.0",
4
4
  "license": "Apache-2.0",
5
5
  "description": "An ad tag implementation called moli",
6
6
  "main": "./lib/index.js",