PageSourceSearch

https://tecnoelectrica.cl/wp-content/plugins/chile-consiente/assets/js/banner.js?ver=1.1.2

js tecnoelectrica.cl collected 2026-10-06 20:42:55 UTC 8,462 bytes, 211 lines download raw bytes

1/**
2 * Chile Consiente — banner de consentimiento (vanilla JS, sin dependencias).
3 *
4 * Cargado como archivo externo (sin inline) para no disparar HDR-CSP-WEAK.
5 * El estado se resuelve en cliente desde la cookie → funciona con caché de página.
6 *
7 * Flujo:
8 *  1. Lee la cookie. Si hay decisión vigente (misma versión de política) →
9 *     aplica el estado (desbloquea scripts, Consent Mode update, wp_set_consent)
10 *     y no muestra el banner.
11 *  2. Si no → muestra el banner. Aceptar/Rechazar/Configurar.
12 *  3. Al decidir → POST al endpoint (cookie autoritativa + log) y aplica el
13 *     estado en memoria sin recargar.
14 */
15( function () {
16	'use strict';
17
18	var cfg = window.chileConsiente;
19	if ( !cfg || !cfg.categories ) { return; }
20
21	// Categoría (nuestra) → señales de Google Consent Mode v2.
22	var SIGNALS = {
23		analiticas:    { analytics_storage: 1, personalization_storage: 1 },
24		publicitarias: { ad_storage: 1, ad_user_data: 1, ad_personalization: 1 },
25		funcionales:   { functionality_storage: 1, personalization_storage: 1 }
26	};
27
28	// ── utilidades ────────────────────────────────────────────────────────────
29	function readCookie( name ) {
30		var m = document.cookie.match( '(?:^|; )' + name.replace( /([.$?*|{}()\[\]\\\/+^])/g, '\\$1' ) + '=([^;]*)' );
31		if ( !m ) { return null; }
32		try { return JSON.parse( decodeURIComponent( m[1] ) ); } catch ( e ) { return null; }
33	}
34
35	function currentDecision() {
36		var c = readCookie( cfg.cookieName );
37		if ( c && String( c.v ) === String( cfg.policyVersion ) && c.cats ) { return c; }
38		return null;
39	}
40
41	function el( tag, attrs, text ) {
42		var n = document.createElement( tag );
43		if ( attrs ) { Object.keys( attrs ).forEach( function ( k ) { n.setAttribute( k, attrs[k] ); } ); }
44		if ( text != null ) { n.textContent = text; }
45		return n;
46	}
47
48	// ── aplicar estado ────────────────────────────────────────────────────────
49	function unblockScripts( cats ) {
50		var nodes = document.querySelectorAll( 'script[type="text/plain"][' + cfg.catAttr + ']' );
51		nodes.forEach( function ( old ) {
52			var cat = old.getAttribute( cfg.catAttr );
53			if ( !cats[cat] ) { return; }
54			var s = document.createElement( 'script' );
55			for ( var i = 0; i < old.attributes.length; i++ ) {
56				var a = old.attributes[i];
57				if ( a.name === 'type' || a.name === cfg.catAttr ) { continue; }
58				s.setAttribute( a.name, a.value );
59			}
60			if ( old.textContent ) { s.textContent = old.textContent; }
61			old.parentNode.replaceChild( s, old );
62		} );
63	}
64
65	function consentModeUpdate( cats ) {
66		if ( typeof window.gtag !== 'function' ) { return; }
67		var upd = {};
68		Object.keys( SIGNALS ).forEach( function ( cat ) {
69			var granted = !!cats[cat];
70			Object.keys( SIGNALS[cat] ).forEach( function ( sig ) {
71				if ( granted ) { upd[sig] = 'granted'; }
72				else if ( !( sig in upd ) ) { upd[sig] = 'denied'; }
73			} );
74		} );
75		window.gtag( 'consent', 'update', upd );
76	}
77
78	function wpConsentApi( cats ) {
79		if ( typeof window.wp_set_consent !== 'function' ) { return; }
80		Object.keys( cfg.catMap ).forEach( function ( cat ) {
81			var mapped = cfg.catMap[cat];
82			var val = ( cat === 'necesarias' || cats[cat] ) ? 'allow' : 'deny';
83			try { window.wp_set_consent( mapped, val ); } catch ( e ) {}
84		} );
85	}
86
87	function applyState( cats ) {
88		consentModeUpdate( cats );
89		wpConsentApi( cats );
90		unblockScripts( cats );
91	}
92
93	// ── persistencia ──────────────────────────────────────────────────────────
94	// Aplica el estado en el acto y guarda la decisión en el servidor (cookie
95	// autoritativa + log). Transporte: REST y, si falla (sitios que restringen
96	// la REST a usuarios autenticados), fallback a admin-ajax.
97	function persist( cats ) {
98		applyState( cats );
99		sendConsent( cats );
100		hideBanner();
101	}
102
103	function postJson( url, body ) {
104		try {
105			return fetch( url, {
106				method: 'POST',
107				credentials: 'same-origin',
108				headers: { 'Content-Type': 'application/json' },
109				body: body
110			} ).then( function ( r ) { return !!( r && r.ok ); } ).catch( function () { return false; } );
111		} catch ( e ) {
112			return Promise.resolve( false );
113		}
114	}
115
116	function sendConsent( cats ) {
117		var body = JSON.stringify( { choices: cats } );
118		postJson( cfg.restUrl, body ).then( function ( ok ) {
119			if ( ok || !cfg.ajaxUrl ) { return; }
120			var sep = cfg.ajaxUrl.indexOf( '?' ) === -1 ? '?' : '&';
121			var url = cfg.ajaxUrl + sep + 'action=' + encodeURIComponent( cfg.ajaxAction || 'chc_consent' );
122			postJson( url, body );
123		} );
124	}
125
126	function allCats( value ) {
127		var c = {};
128		cfg.categories.forEach( function ( cat ) { c[cat.key] = cat.required ? true : value; } );
129		return c;
130	}
131
132	// ── UI ────────────────────────────────────────────────────────────────────
133	var root = document.getElementById( 'chc-root' );
134
135	function hideBanner() { if ( root ) { root.classList.add( 'chc-hidden' ); root.innerHTML = ''; } }
136
137	function buildPanel() {
138		var rows = el( 'div', { 'class': 'chc-cats' } );
139		cfg.categories.forEach( function ( cat ) {
140			var row = el( 'label', { 'class': 'chc-cat' } );
141			var cb  = el( 'input', { type: 'checkbox', value: cat.key } );
142			if ( cat.required ) { cb.checked = true; cb.disabled = true; }
143			row.appendChild( cb );
144			var txt = el( 'span', { 'class': 'chc-cat-txt' } );
145			txt.appendChild( el( 'strong', null, cat.label ) );
146			txt.appendChild( el( 'span', { 'class': 'chc-cat-desc' }, cat.desc ) );
147			row.appendChild( txt );
148			rows.appendChild( row );
149		} );
150		return rows;
151	}
152
153	function showBanner() {
154		if ( !root ) { return; }
155		root.innerHTML = '';
156		var box = el( 'div', { 'class': 'chc-banner', role: 'document' } );
157		box.appendChild( el( 'h2', { 'class': 'chc-title' }, cfg.texts.title ) );
158		var body = el( 'p', { 'class': 'chc-body' }, cfg.texts.body );
159		if ( cfg.policyUrl ) {
160			body.appendChild( document.createTextNode( ' ' ) );
161			body.appendChild( el( 'a', { 'class': 'chc-policy-link', href: cfg.policyUrl }, cfg.texts.policy ) );
162		}
163		box.appendChild( body );
164
165		var panel = buildPanel();
166		panel.classList.add( 'chc-hidden' );
167		box.appendChild( panel );
168
169		var actions = el( 'div', { 'class': 'chc-actions' } );
170		var bReject = el( 'button', { type: 'button', 'class': 'chc-btn chc-btn--reject' }, cfg.texts.reject );
171		var bConfig = el( 'button', { type: 'button', 'class': 'chc-btn chc-btn--config' }, cfg.texts.config );
172		var bAccept = el( 'button', { type: 'button', 'class': 'chc-btn chc-btn--accept' }, cfg.texts.accept );
173		var bSave   = el( 'button', { type: 'button', 'class': 'chc-btn chc-btn--save chc-hidden' }, cfg.texts.save );
174
175		bAccept.addEventListener( 'click', function () { persist( allCats( true ) ); } );
176		bReject.addEventListener( 'click', function () { persist( allCats( false ) ); } );
177		bConfig.addEventListener( 'click', function () {
178			panel.classList.toggle( 'chc-hidden' );
179			bSave.classList.toggle( 'chc-hidden' );
180		} );
181		bSave.addEventListener( 'click', function () {
182			var c = {};
183			cfg.categories.forEach( function ( cat ) {
184				if ( cat.required ) { c[cat.key] = true; return; }
185				var cb = panel.querySelector( 'input[value="' + cat.key + '"]' );
186				c[cat.key] = !!( cb && cb.checked );
187			} );
188			persist( c );
189		} );
190
191		actions.appendChild( bReject );
192		actions.appendChild( bConfig );
193		actions.appendChild( bAccept );
194		actions.appendChild( bSave );
195		box.appendChild( actions );
196
197		root.appendChild( box );
198		root.classList.remove( 'chc-hidden' );
199	}
200
201	// Reabrir desde el shortcode/enlace de footer.
202	document.addEventListener( 'click', function ( e ) {
203		var t = e.target;
204		if ( t && t.closest && t.closest( '[data-chc-reopen]' ) ) { e.preventDefault(); showBanner(); }
205	} );
206
207	// ── arranque ────────────────────────────────────────────────────────────────
208	var decision = currentDecision();
209	if ( decision ) { applyState( decision.cats ); }
210	else { showBanner(); }
211} )();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.