js/brivembed.js
// ========================================================================
// Brivembed JS
// ========================================================================
document.addEventListener('DOMContentLoaded', () => {
const KEY = 'brivembed_allow';
// Keep preferences in memory to avoid JSON.parse on every click.
let prefs = (() => {
try {
return JSON.parse(localStorage.getItem(KEY)) || {};
} catch {
return {};
}
})();
const savePrefs = () => localStorage.setItem(KEY, JSON.stringify(prefs));
const PROVIDERS = {
codepen: {
label: 'CodePen',
src: ({
code,
user = CODEPEN_USER,
tab = 'result',
editable = 'true'
}) => `https://codepen.io/${encodeURIComponent(user)}/embed/${encodeURIComponent(code)}`
+ `?default-tab=${encodeURIComponent(tab)}`
+ `&editable=${encodeURIComponent(editable)}`
},
dailymotion: {
label: 'Dailymotion',
src: ({ code }) =>
`https://geo.dailymotion.com/player.html?video=${encodeURIComponent(code)}`
},
githubpages: {
label: 'GitHub Pages'
},
youtube: {
label: 'YouTube',
src: ({ code }) =>
`https://www.youtube.com/embed/${encodeURIComponent(code)}`
}
};
const getProvider = (box) => PROVIDERS[box.dataset.provider];
const hasFullscreen = (box) => box.dataset.fullscreen === '1';
const updateRememberUI = (box, active) => {
const icon = box.querySelector('.brivembed-icon');
if (!icon) return;
icon.classList.toggle('fa-square', !active);
icon.classList.toggle('fa-square-check', active);
};
const ensurePlaceholder = (box) => {
if (box.querySelector('.brivembed-placeholder')) return;
const p = getProvider(box);
const label = p?.label || (box.dataset.provider || '');
box.insertAdjacentHTML('afterbegin', `
<div class="brivembed-placeholder">
<h3>External content hosted by <span class="brivembed-provider-name-title">${label}</span></h3>
<p>To respect your privacy, click “Show content” to load it.</p>
<div class="brivembed-actions">
<button type="button" class="brivembed-load">Show content</button>
<div class="brivembed-remember" role="button" tabindex="0">
<span aria-hidden="true" class="brivembed-icon fa-regular fa-square fa-lg"></span>
<span class="brivembed-text">
Always allow the service
<span class="brivembed-provider-name-checkbox">${label}</span>
</span>
</div>
</div>
</div>
`);
};
// The iframe is only created after explicit consent.
const buildIframe = (src, providerLabel) => {
const iframe = document.createElement('iframe');
iframe.src = src;
iframe.title = `Displaying external content hosted by ${providerLabel}`;
iframe.loading = 'lazy';
iframe.setAttribute(
'allow',
'accelerometer; encrypted-media; fullscreen; gyroscope; picture-in-picture'
);
return iframe;
};
const buildSrc = (box) => {
if (box.dataset.src) return box.dataset.src;
const p = getProvider(box);
const code = box.dataset.code;
if (!p || !code) return '';
return p.src({
code,
user: box.dataset.user,
tab: box.dataset.tab,
editable: box.dataset.editable
});
};
const updateFullscreenButtons = () => {
document.querySelectorAll('.brivembed-fullscreen').forEach((btn) => {
const box = btn.closest('.embed-container');
const isFullscreen = document.fullscreenElement === box;
btn.innerHTML = isFullscreen
? '<span class="fa-solid fa-2x fa-compress"></span>'
: '<span class="fa-solid fa-2x fa-expand"></span>';
const label = isFullscreen
? 'Exit fullscreen'
: 'Show fullscreen';
btn.setAttribute('aria-label', label);
btn.setAttribute('title', label);
});
};
const buildFullscreenButton = (box) => {
const btn = document.createElement('button');
btn.type = 'button';
btn.className = 'brivembed-fullscreen';
btn.addEventListener('click', () => {
if (document.fullscreenElement === box) {
document.exitFullscreen?.();
} else {
box.requestFullscreen?.();
}
});
return btn;
};
const loadBox = (box) => {
const p = getProvider(box);
const src = buildSrc(box);
if (!src) return;
box.querySelector('.brivembed-placeholder')?.remove();
box.classList.remove('brivembed');
box.classList.add('embed-container');
const iframe = buildIframe(
src,
p?.label || box.dataset.provider || ''
);
box.appendChild(iframe);
if (hasFullscreen(box)) {
box.appendChild(buildFullscreenButton(box));
}
updateFullscreenButtons();
};
const initBox = (box) => {
const provider = box.dataset.provider;
if (!provider) return;
ensurePlaceholder(box);
const active = prefs[provider] === true;
updateRememberUI(box, active);
if (active) loadBox(box);
};
const initAll = () => {
document.querySelectorAll('.brivembed').forEach(initBox);
};
document.addEventListener(
'fullscreenchange',
updateFullscreenButtons
);
// Initialize placeholders once the DOM is ready.
initAll();
// Handle clicks.
document.addEventListener('click', (e) => {
const loadBtn = e.target.closest('.brivembed-load');
const rememberBtn = e.target.closest('.brivembed-remember');
if (!loadBtn && !rememberBtn) return;
const box = e.target.closest('.brivembed');
if (!box) return;
const provider = box.dataset.provider;
if (!provider) return;
if (rememberBtn) {
prefs[provider] = !prefs[provider];
savePrefs();
updateRememberUI(box, prefs[provider] === true);
return;
}
if (loadBtn) {
loadBox(box);
}
});
// Keyboard support for the "always allow" control.
document.addEventListener('keydown', (e) => {
if (e.key !== 'Enter' && e.key !== ' ') return;
const rememberBtn = e.target.closest?.('.brivembed-remember');
if (!rememberBtn) return;
const box = rememberBtn.closest('.brivembed');
if (!box) return;
e.preventDefault();
const provider = box.dataset.provider;
if (!provider) return;
prefs[provider] = !prefs[provider];
savePrefs();
updateRememberUI(box, prefs[provider] === true);
});
});