Show placeholders when no prior consent exists

The activate() method was only called when consent existed (from
cookie or API). When there was no prior consent, observeAndActivate()
never ran, so visual elements with data-cookie-consent were left
without placeholders. Build default consent data from the config's
consent_mode and always call activate() at the end of load().

Also consolidate activateElements/addPlaceholders into
observeAndActivate to avoid duplicate DOM traversals.

Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
Émile Ré
2026-04-30 17:10:35 +04:00
parent 15ff6131e1
commit 42a6a2f8bd
2 changed files with 18 additions and 27 deletions

View File

@@ -383,29 +383,6 @@ export function deactivateElements(
}
}
export function activateElements(
consentData: Record<string, boolean>,
): void {
const elements = document.querySelectorAll(`[${ATTR_CATEGORY}]`);
for (const el of elements) {
tryActivate(el, consentData);
}
}
export function addPlaceholders(
consentData: Record<string, boolean>,
categoryLabels: Record<string, string>,
texts?: BannerTexts,
): void {
const elements = document.querySelectorAll(`[${ATTR_CATEGORY}]`);
for (const el of elements) {
const category = el.getAttribute(ATTR_CATEGORY);
if (!category || consentData[category]) continue;
if (!VISUAL_TAGS.has(el.tagName)) continue;
createPlaceholder(el, category, categoryLabels[category], texts);
}
}
function tryPlaceholder(
el: Element,
consentData: Record<string, boolean>,
@@ -423,6 +400,12 @@ export function observeAndActivate(
categoryLabels: Record<string, string>,
texts?: BannerTexts,
): MutationObserver {
const existing = document.querySelectorAll(`[${ATTR_CATEGORY}]`);
for (const el of existing) {
tryActivate(el, consentData);
tryPlaceholder(el, consentData, categoryLabels, texts);
}
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
for (const node of mutation.addedNodes) {

View File

@@ -13,8 +13,6 @@
// PERFORMANCE OF THIS SOFTWARE.
import {
activateElements,
addPlaceholders,
deactivateElements,
observeAndActivate,
} from "./activation";
@@ -180,6 +178,8 @@ export class CookieBannerClient {
if (!this.consent && this.gpcDetected) {
this.gpc();
this._gpcApplied = true;
} else if (!this.consent) {
this.activate(this.buildDefaultConsentData());
}
void flush(this.bannerId);
@@ -294,6 +294,16 @@ export class CookieBannerClient {
.catch(() => enqueue(this.bannerId, url.href, body));
}
private buildDefaultConsentData(): Record<string, boolean> {
const cfg = this.config;
const consentData: Record<string, boolean> = {};
for (const cat of cfg.categories) {
consentData[cat.slug] =
cfg.consent_mode === "OPT_OUT" || cat.kind === "NECESSARY";
}
return consentData;
}
private activate(consentData: Record<string, boolean>): void {
for (const integration of this.integrations) {
integration.update(this.config.categories, consentData);
@@ -308,8 +318,6 @@ export class CookieBannerClient {
const texts = this.config.texts;
deactivateElements(consentData, categoryCookies, categoryLabels, texts);
activateElements(consentData);
addPlaceholders(consentData, categoryLabels, texts);
if (this.observer) {
this.observer.disconnect();
}