@highfivve/ad-tag 5.11.7 → 5.11.9

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.
@@ -5,6 +5,7 @@ var TCPurpose = tcfapi.responses.TCPurpose;
5
5
  import { generateAdUnitPathVariables } from './adUnitPath';
6
6
  import { createAssetLoaderService } from '../util/assetLoaderService';
7
7
  import { uuidV4 } from '../util/uuid';
8
+ import { getMoliLabelsFromQueryParam, getMoliLabelsFromStorage } from '../util/debugLabels';
8
9
  export const HIGH_PRIORITY = 100;
9
10
  export const LOW_PRIORITY = 10;
10
11
  export const mkInitStep = (name, fn) => {
@@ -83,7 +84,12 @@ export class AdPipeline {
83
84
  ? this.tcData
84
85
  : consentReady(consentConfig, this.window, this.logger, runtimeConfig.environment);
85
86
  return this.tcData.then(consentData => {
86
- const extraLabels = [...(config.targeting?.labels || []), ...runtimeConfig.labels];
87
+ const extraLabels = [
88
+ ...(config.targeting?.labels || []),
89
+ ...runtimeConfig.labels,
90
+ ...getMoliLabelsFromQueryParam(this.window),
91
+ ...getMoliLabelsFromStorage(this.window)
92
+ ];
87
93
  if (consentData.gdprApplies &&
88
94
  consentData.purpose.consents[TCPurpose.STORE_INFORMATION_ON_DEVICE]) {
89
95
  extraLabels.push('purpose-1');
@@ -1,21 +1,29 @@
1
- const extractDeviceIdParam = (context, advertiserIdKey) => {
2
- const deviceId = context.config__.targeting?.keyValues[advertiserIdKey];
1
+ const extractDeviceIdParam = (targeting, advertiserIdKey) => {
2
+ const deviceId = targeting[advertiserIdKey];
3
3
  if (deviceId) {
4
4
  return `&device_id=${typeof deviceId === 'string' ? deviceId : deviceId[0]}`;
5
5
  }
6
6
  return '';
7
7
  };
8
+ const extractKeywordsParam = (targeting, keywordsKey) => {
9
+ const keywords = keywordsKey ? targeting[keywordsKey] : undefined;
10
+ if (keywords) {
11
+ const value = typeof keywords === 'string' ? keywords : keywords.join(',');
12
+ return `&keywords=${encodeURIComponent(value)}`;
13
+ }
14
+ return '';
15
+ };
8
16
  export const trackInApp = (context, appConfig, additionalIdentifier, additionalCustomParams, document) => {
9
- const deviceIdParam = extractDeviceIdParam(context, appConfig.advertiserIdKey);
17
+ const targeting = {
18
+ ...context.config__.targeting?.keyValues,
19
+ ...context.runtimeConfig__.keyValues
20
+ };
21
+ const deviceIdParam = extractDeviceIdParam(targeting, appConfig.advertiserIdKey);
10
22
  const consentString = context.tcData__.gdprApplies
11
23
  ? `gdpr=1&gdpr_consent=${context.tcData__.tcString}`
12
24
  : 'gdpr=0';
13
- const linkParam = appConfig.linkOrKeyword.link
14
- ? `&link=${encodeURIComponent(appConfig.linkOrKeyword.link)}`
15
- : '';
16
- const keywordsParam = appConfig.linkOrKeyword.keywords
17
- ? `&keywords=${encodeURIComponent(appConfig.linkOrKeyword.keywords)}`
18
- : '';
25
+ const linkParam = `&link=${encodeURIComponent(context.window__.location.href)}`;
26
+ const keywordsParam = extractKeywordsParam(targeting, appConfig.keywordsKey);
19
27
  let additionalIdsParam = '';
20
28
  const identifiers = { ...appConfig.additionalIdentifier, ...additionalIdentifier };
21
29
  Object.entries(identifiers).forEach(([key, value]) => {
package/lib/ads/moli.js CHANGED
@@ -231,6 +231,16 @@ export const createMoliTag = (window) => {
231
231
  }
232
232
  return Promise.resolve(null);
233
233
  }
234
+ function refreshQueuedInfiniteSlots(config, runtimeConfig) {
235
+ const { refreshInfiniteSlots } = runtimeConfig;
236
+ if (refreshInfiniteSlots.length === 0) {
237
+ return config;
238
+ }
239
+ const log = getLogger(runtimeConfig, window);
240
+ const configWithInfiniteSlots = refreshInfiniteSlots.reduce((currentConfig, slot) => addNewInfiniteSlotToConfig(currentConfig, slot.idOfConfiguredSlot, slot.artificialDomId, log), config);
241
+ adService.refreshAdSlots(refreshInfiniteSlots.map(slot => slot.artificialDomId), configWithInfiniteSlots, runtimeConfig);
242
+ return configWithInfiniteSlots;
243
+ }
234
244
  function requestAds() {
235
245
  switch (state.state) {
236
246
  case 'configurable': {
@@ -324,7 +334,8 @@ export const createMoliTag = (window) => {
324
334
  const validateLocation = config.spa?.validateLocation ?? 'href';
325
335
  if (state.state === 'spa-requestAds' &&
326
336
  allowRefreshAdSlot(validateLocation, state.href, window.location)) {
327
- const { config, runtimeConfig } = state;
337
+ const { runtimeConfig } = state;
338
+ const config = refreshQueuedInfiniteSlots(state.config, runtimeConfig);
328
339
  if (state.runtimeConfig.refreshSlots.length > 0) {
329
340
  adService.refreshAdSlots(runtimeConfig.refreshSlots, config, runtimeConfig);
330
341
  }
@@ -336,6 +347,7 @@ export const createMoliTag = (window) => {
336
347
  afterRequestAds.forEach(hook => hook('spa-finished'));
337
348
  const finishedState = {
338
349
  ...state,
350
+ config,
339
351
  state: 'spa-finished',
340
352
  nextRuntimeConfig: newEmptyRuntimeConfig(state.runtimeConfig),
341
353
  runtimeConfig: newEmptyRuntimeConfig(state.runtimeConfig, { keepTargeting: true })
@@ -432,8 +444,9 @@ export const createMoliTag = (window) => {
432
444
  }
433
445
  return adService.requestAds(config, nextRuntimeConfig).then(() => config);
434
446
  })
435
- .then(config => {
447
+ .then(requestedConfig => {
436
448
  const runtimeConfig = state.runtimeConfig;
449
+ const config = refreshQueuedInfiniteSlots(requestedConfig, runtimeConfig);
437
450
  if (state.runtimeConfig.refreshSlots.length > 0) {
438
451
  adService.refreshAdSlots(state.runtimeConfig.refreshSlots, config, state.runtimeConfig);
439
452
  }
@@ -21,6 +21,7 @@ import { BrowserStorageKeys } from 'ad-tag/util/browserStorageKeys';
21
21
  import { calculateAdDensity } from 'ad-tag/console/util/calculateAdDensity';
22
22
  import { extractPositionFromPath } from 'ad-tag/console/util/extractPositionFromPath';
23
23
  import { getBrowserStorageValue, removeBrowserStorageValue, setBrowserStorageValue } from 'ad-tag/util/localStorage';
24
+ import { addMoliLabelToStorage, clearMoliLabelsFromStorage, getMoliLabelsFromStorage, removeMoliLabelFromStorage } from 'ad-tag/util/debugLabels';
24
25
  const debugSidebarSelector = 'moli-debug-sidebar';
25
26
  export class GlobalConfig extends Component {
26
27
  constructor(props) {
@@ -75,6 +76,7 @@ export class GlobalConfig extends Component {
75
76
  React.createElement(TagLabel, null, "Test mode"),
76
77
  React.createElement(Toggle, { checked: isTestMode, title: isTestMode ? 'Switch back to production mode' : 'Override environment to test', onChange: checked => checked ? this.overrideEnvironmentToTest() : this.resetEnvironmentOverrides() }),
77
78
  isTestMode && !isEnvironmentOverridden && (React.createElement(Tag, { variant: "yellow" }, "test environment set in config")))),
79
+ React.createElement(Block, { title: "Debug Labels", color: "debugLabels" }, this.renderDebugLabels()),
78
80
  React.createElement(Block, { title: "Targeting", color: "targeting" },
79
81
  config.targeting && (React.createElement("div", null,
80
82
  React.createElement(SubHeadline, null, "Key/value pairs"),
@@ -100,6 +102,34 @@ export class GlobalConfig extends Component {
100
102
  React.createElement("div", { className: "text-xs font-semibold opacity-60" }, this.requestedSizesLabel(slot))),
101
103
  React.createElement("button", { className: "d-btn d-btn-ghost d-btn-sm font-normal normal-case", title: "Open in Ad Setup", onClick: () => this.openSlotInAdSetup(slot.domId) }, "details")))))))));
102
104
  };
105
+ this.renderDebugLabels = () => {
106
+ const debugLabels = getMoliLabelsFromStorage(window);
107
+ return (React.createElement("div", null,
108
+ this.labels(debugLabels, {
109
+ onRemove: this.removeDebugLabel,
110
+ emptyMessage: 'No debug labels set.'
111
+ }),
112
+ React.createElement(TagContainer, null,
113
+ React.createElement(TextInput, { placeholder: "label", value: this.state.newDebugLabel, onChange: e => this.setState({ newDebugLabel: e.currentTarget.value }) }),
114
+ React.createElement(Btn, { onClick: () => this.addDebugLabel(this.state.newDebugLabel) }, "add"),
115
+ React.createElement(Btn, { variant: "red", onClick: this.clearDebugLabels, disabled: debugLabels.length === 0 }, "clear all"))));
116
+ };
117
+ this.addDebugLabel = (label) => {
118
+ const trimmed = label.trim();
119
+ if (trimmed.length === 0) {
120
+ return;
121
+ }
122
+ addMoliLabelToStorage(window, trimmed);
123
+ window.location.reload();
124
+ };
125
+ this.removeDebugLabel = (label) => {
126
+ removeMoliLabelFromStorage(window, label);
127
+ window.location.reload();
128
+ };
129
+ this.clearDebugLabels = () => {
130
+ clearMoliLabelsFromStorage(window);
131
+ window.location.reload();
132
+ };
103
133
  this.renderAdSetup = (config) => {
104
134
  const { modules, labelConfigService } = this.props;
105
135
  const { showOnlyRenderedSlots, selectedSlotDomId } = this.state;
@@ -374,11 +404,13 @@ export class GlobalConfig extends Component {
374
404
  : this.standardTagFromString(value))));
375
405
  })))) : (React.createElement("span", null, "No key/values config present."));
376
406
  };
377
- this.labels = (labels) => {
407
+ this.labels = (labels, options) => {
378
408
  return (React.createElement("div", { className: "mt-2 flex flex-wrap items-center gap-y-1" },
379
409
  labels &&
380
- labels.map((label, index) => (React.createElement(Tag, { key: index, variant: "grey", spacing: "medium" }, label))),
381
- (!labels || labels.length === 0) && React.createElement("span", null, "No labels present.")));
410
+ labels.map((label, index) => (React.createElement(Tag, { key: index, variant: "grey", spacing: "medium" },
411
+ label,
412
+ options?.onRemove && (React.createElement("button", { className: "ml-1 border-0 bg-transparent p-0 font-bold", title: `Remove ${label}`, onClick: () => options.onRemove(label) }, "\u2715"))))),
413
+ (!labels || labels.length === 0) && (React.createElement("span", null, options?.emptyMessage ?? 'No labels present.'))));
382
414
  };
383
415
  this.filterSetting = (name, filterSetting) => {
384
416
  return (React.createElement("div", null,
@@ -505,7 +537,8 @@ export class GlobalConfig extends Component {
505
537
  totalAdDensity: undefined,
506
538
  percentagePerSlot: []
507
539
  },
508
- configVersion: 'not available'
540
+ configVersion: 'not available',
541
+ newDebugLabel: ''
509
542
  };
510
543
  if (!props.config) {
511
544
  this.reportMissingConfig(this.state.messages);
@@ -4,6 +4,7 @@ const sectionAccent = {
4
4
  moli: 'border-l-[#998fc7]',
5
5
  slots: 'border-l-[#506684]',
6
6
  targeting: 'border-l-[#998fc7]',
7
+ debugLabels: 'border-l-[#b6e388]',
7
8
  sizeConfig: 'border-l-[#d4c2fc]',
8
9
  modules: 'border-l-[#8a7de0]',
9
10
  prebid: 'border-l-[#76949f]',
@@ -1,3 +1,3 @@
1
1
  export const packageJson = {
2
- version: '5.11.7'
2
+ version: '5.11.9'
3
3
  };
@@ -6,5 +6,6 @@ export const BrowserStorageKeys = {
6
6
  moliConsoleTheme: 'moli-console-theme',
7
7
  testSlotSize: (id) => `moli-test-slot-size-${id}`,
8
8
  debugDelay: 'moli-debug-delay',
9
- abTest: 'moli-ab-test'
9
+ abTest: 'moli-ab-test',
10
+ moliLabels: 'moli-labels'
10
11
  };
@@ -0,0 +1,40 @@
1
+ import { parseQueryString } from './query';
2
+ import { getBrowserStorageValue, removeBrowserStorageValue, setBrowserStorageValue } from './localStorage';
3
+ import { QueryParameters } from './queryParameters';
4
+ import { BrowserStorageKeys } from './browserStorageKeys';
5
+ export const getMoliLabelsFromQueryParam = (window) => {
6
+ try {
7
+ return (parseQueryString(window.location.search).get(QueryParameters.moliLabels) ?? '')
8
+ .split(',')
9
+ .map(label => label.trim())
10
+ .filter(label => label.length > 0);
11
+ }
12
+ catch (e) {
13
+ return [];
14
+ }
15
+ };
16
+ const isStringArray = (value) => Array.isArray(value) && value.every(entry => typeof entry === 'string');
17
+ export const getMoliLabelsFromStorage = (window) => {
18
+ try {
19
+ const raw = getBrowserStorageValue(BrowserStorageKeys.moliLabels, window.localStorage);
20
+ if (!raw) {
21
+ return [];
22
+ }
23
+ const parsed = JSON.parse(raw);
24
+ return isStringArray(parsed) ? parsed : [];
25
+ }
26
+ catch (e) {
27
+ return [];
28
+ }
29
+ };
30
+ export const addMoliLabelToStorage = (window, label) => {
31
+ const labels = [...getMoliLabelsFromStorage(window), label];
32
+ setBrowserStorageValue(BrowserStorageKeys.moliLabels, JSON.stringify(labels), window.localStorage);
33
+ };
34
+ export const removeMoliLabelFromStorage = (window, label) => {
35
+ const labels = getMoliLabelsFromStorage(window).filter(entry => entry !== label);
36
+ setBrowserStorageValue(BrowserStorageKeys.moliLabels, JSON.stringify(labels), window.localStorage);
37
+ };
38
+ export const clearMoliLabelsFromStorage = (window) => {
39
+ removeBrowserStorageValue(BrowserStorageKeys.moliLabels, window.localStorage);
40
+ };
@@ -2,5 +2,6 @@ export const QueryParameters = {
2
2
  moliEnv: 'moliEnv',
3
3
  moliPubCode: 'moliPubCode',
4
4
  moliVersion: 'moliVersion',
5
- abTest: 'ABtest'
5
+ abTest: 'ABtest',
6
+ moliLabels: 'moliLabels'
6
7
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@highfivve/ad-tag",
3
- "version": "5.11.7",
3
+ "version": "5.11.9",
4
4
  "license": "Apache-2.0",
5
5
  "description": "An ad tag implementation called moli",
6
6
  "main": "./lib/index.js",