var CookieConsent = {
storageKey: 'af_cookie_consent',
init: function() {
var consent = localStorage.getItem(this.storageKey);
if (!consent) {
var banner = document.getElementById('cookie-banner');
if (banner) banner.style.display = 'block';
}
},
accept: function() {
localStorage.setItem(this.storageKey, 'accepted');
var banner = document.getElementById('cookie-banner');
if (banner) banner.style.display = 'none';
},
dismiss: function() {
localStorage.setItem(this.storageKey, 'declined');
var banner = document.getElementById('cookie-banner');
if (banner) banner.style.display = 'none';
}
};
window.CookieConsent = CookieConsent;
CookieConsent.init();
// ─── CSP-safe event delegation (replaces inline on* handlers) ────
(function() {
var H = {
'data-onclick': 'click',
'data-onsubmit': 'submit',
'data-onchange': 'change',
'data-oninput': 'input',
'data-onkeyup': 'keyup',
'data-onkeydown': 'keydown',
'data-onkeypress': 'keypress',
'data-onfocus': 'focusin',
'data-onblur': 'focusout',
};
function _resolveFn(name, ctx) {
// Resolve dotted function names (e.g. "CookieConsent.accept")
// Try ctx first, then fall back to window (global functions)
var parts = name.split('.');
var obj = ctx || window;
for (var i = 0; i < parts.length; i++) {
if (typeof obj[parts[i]] === 'function') {
obj = obj[parts[i]];
} else if (i === 0 && window && typeof window[parts[i]] === 'function') {
// First part not found on ctx — fall back to window
obj = window;
obj = obj[parts[i]];
} else {
return null;
}
}
return obj;
}
function _parseCall(code) {
// Parse "fnName(args)" or "fnName" or "obj.fn(args)" or "return fn(args)"
var s = code.trim();
if (s.startsWith('return ')) s = s.slice(7).trim();
// Match fnName(...) or obj.fn(...)
var m = s.match(/^([\w.$]+)\((.*)\)$/);
if (m) return { fn: m[1], argsStr: m[2] };
// No args
if (/^[\w.$]+$/.test(s)) return { fn: s, argsStr: '' };
return null;
}
function _splitArgs(str) {
if (!str.trim()) return [];
var args = [], current = '', depth = 0, inStr = false, strChar = '';
for (var i = 0; i < str.length; i++) {
var c = str[i];
if (inStr) { if (c === strChar) inStr = false; current += c; continue; }
if (c === '"' || c === "'") { inStr = true; strChar = c; current += c; continue; }
if (c === '(' || c === '[' || c === '{') depth++;
if (c === ')' || c === ']' || c === '}') depth--;
if (c === ',' && depth === 0) { args.push(current.trim()); current = ''; continue; }
current += c;
}
if (current.trim()) args.push(current.trim());
return args;
}
function _invoke(code, el, e) {
var parsed = _parseCall(code);
if (!parsed) return undefined;
var fn = _resolveFn(parsed.fn, el);
if (!fn) { console.warn('CSP delegate: unknown function', parsed.fn); return undefined; }
var args = _splitArgs(parsed.argsStr);
// Replace 'this' references with element, 'event' with e, parse string literals
args = args.map(function(a) {
if (a === 'this') return el;
if (a === 'event' || a === 'e') return e;
if (a === 'this.value') return el.value;
if (a === 'this.form') return el.form;
if (a === 'this.checked') return el.checked;
// Parse string literals (strip surrounding quotes)
if ((a.startsWith("'") && a.endsWith("'")) || (a.startsWith('"') && a.endsWith('"'))) {
return a.slice(1, -1);
}
return a; // pass raw for numbers, booleans, etc.
});
return fn.apply(window, args);
}
for (var attr in H) {
(function(a, ev) {
document.addEventListener(ev, function(e) {
var el = e.target.closest('[' + a + ']');
if (!el) return;
var code = el.getAttribute(a);
if (!code) return;
var result = _invoke(code, el, e);
if (result === false) {
e.preventDefault();
e.stopPropagation();
}
}, ev === 'focusin' || ev === 'focusout');
})(attr, H[attr]);
}
// Handle data-onerror/data-onload for images (non-bubbling)
['error', 'load'].forEach(function(ev) {
document.addEventListener(ev, function(e) {
var code = e.target.getAttribute('data-' + ev);
if (!code) return;
_invoke(code, e.target, e);
}, true);
});
})();