/*! trentpower.fr · /cite.js · generated · signed via /integrity.json */
(function () {
'use strict';
var EDITION = '2026-05-09';
function getLang() {
var t = document.documentElement.lang || 'en';
if (window.I18N && window.I18N[t]) return t;
var nav = (navigator.languages && navigator.languages[0]) || navigator.language || 'en';
return /^fr\b/i.test(nav) ? 'fr' : 'en';
}
function tt(key, fallback) {
var lang = getLang();
var ref = (window.I18N && window.I18N[lang]) || {};
var parts = key.split('.');
for (var i = 0; i < parts.length; i++) {
if (ref == null || typeof ref !== 'object') return fallback || '';
ref = ref[parts[i]];
}
return (typeof ref === 'string') ? ref : (fallback || '');
}
function normalisePath(raw) {
if (!raw) return '/';
raw = String(raw).trim();
if (!raw) return '/';
if (raw.charAt(0) !== '/') raw = '/' + raw;
raw = raw.replace(/\/index\.html$/, '/');
if (raw.indexOf('.') === -1 && raw.charAt(raw.length - 1) !== '/') raw += '/';
return raw;
}
function currentRecord() {
var map = (typeof window !== 'undefined' && window.TP_VERIFICATION_MAP) || {};
var p = normalisePath(location.pathname || '/');
return map[p] || null;
}
function pageTitle() {
var raw = document.title || '';
if (raw.indexOf('|') !== -1) {
return raw.replace(/^[^|]+\|\s*/, '').trim().replace(/\s*&\s*/g, ' and ');
}
return raw.replace(/\s*[—\-]\s*Trent Power$/, '').trim();
}
function canonicalUrl() {
var link = document.querySelector('link[rel="canonical"]');
return link ? link.href : location.href;
}
function fallbackCitation() {
return 'Trent Power. "' + pageTitle() + '." ' +
tt('cite.site_label', 'Personal Site') +
'. Paris, France. ' +
tt('cite.edition_label', 'Edition') + ' ' + EDITION + '. ' +
canonicalUrl();
}
function verifyUrl() {
var p = normalisePath(location.pathname || '/');
return '/verify/?path=' + encodeURIComponent(p);
}
var PRINT_PAGE_SHEET = {
privacy: 1, integrity: 1, security: 1,
source: 1, releases: 1, verify: 1,
forbidden: 1, 'not-found': 1, 'server-error': 1
};
function printLabel() {
var page = (document.body && document.body.dataset && document.body.dataset.page)
|| (document.documentElement.dataset && document.documentElement.dataset.page)
|| '';
if (page === 'home') return tt('cite.overlay.action.print_home', 'Print profile');
if (PRINT_PAGE_SHEET[page]) return tt('cite.overlay.action.print_sheet', 'Print this sheet');
return tt('cite.overlay.action.print_page', 'Print page');
}
function el(tag, attrs, text) {
var n = document.createElement(tag);
if (attrs) for (var k in attrs) {
if (Object.prototype.hasOwnProperty.call(attrs, k) && attrs[k] != null) {
n.setAttribute(k, attrs[k]);
}
}
if (text != null) n.textContent = text;
return n;
}
function safeHref(href) {
if (!href) return '#';
if (href.charAt(0) === '/' || /^https?:\/\//.test(href)) return href;
return '#';
}
var overlay = null;
var copyBtnAction = {};
function resolveTitle(rec) {
var explicit = document.body && document.body.dataset && document.body.dataset.citationTitle;
if (explicit) return explicit;
var page = (document.body && document.body.dataset && document.body.dataset.page) || '';
if (page) {
var key = 'cite.overlay.page_title.' + page;
var translated = tt(key, '');
if (translated) return translated;
}
return (rec && rec.title) || pageTitle() || tt('cite.site_label', 'Personal Site');
}
function buildOverlay() {
var rec = currentRecord();
var citation = (rec && rec.citation) || fallbackCitation();
var title = resolveTitle(rec);
overlay = el('div', {
'class': 'modal-overlay cite-overlay',
'id': 'cite-dialog',
'role': 'dialog',
'aria-modal': 'true',
'aria-labelledby': 'cite-modal-title',
'aria-hidden': 'true',
});
var card = el('div', { 'class': 'modal cite-modal' });
var closeX = el('button', {
type: 'button',
'class': 'cite-modal-close-x',
'data-cite-action': 'close',
'aria-label': tt('cite.overlay.action.close', 'Close'),
}, '\u00d7');
card.appendChild(closeX);
var header = el('header', { 'class': 'cite-modal-header' });
header.appendChild(el('p', { 'class': 'cite-modal-kicker' },
tt('cite.overlay.kicker', 'This page')));
header.appendChild(el('h2', { 'class': 'cite-modal-title', 'id': 'cite-modal-title' },
title));
header.appendChild(el('p', { 'class': 'cite-modal-lede' },
tt('cite.overlay.lede', 'Canonical publication record for this page.')));
card.appendChild(header);
var meta = el('dl', { 'class': 'cite-modal-meta' });
var editionRow = el('div', { 'class': 'cite-modal-meta-row' });
editionRow.appendChild(el('dt', null,
tt('cite.overlay.edition_label', 'Edition')));
var editionDd = el('dd', null);
editionDd.appendChild(el('time', { 'datetime': EDITION }, EDITION));
editionRow.appendChild(editionDd);
meta.appendChild(editionRow);
var releaseRow = el('div', { 'class': 'cite-modal-meta-row' });
releaseRow.appendChild(el('dt', null,
tt('cite.overlay.release_status', 'Signed release')));
meta.appendChild(releaseRow);
card.appendChild(meta);
var actions = el('div', { 'class': 'cite-modal-actions' });
var primary = el('div', { 'class': 'cite-modal-actions-row cite-modal-actions-row--primary' });
primary.appendChild(el('a', {
'href': safeHref(verifyUrl()),
'class': 'cite-modal-action cite-modal-action--primary',
'data-cite-action': 'verify',
}, tt('cite.overlay.action.verify', 'Verify this page')));
var sourceHref = (rec && rec.reader) || (rec && rec.source) || '/source/';
primary.appendChild(el('a', {
'href': safeHref(sourceHref),
'class': 'cite-modal-action cite-modal-action--primary',
'data-cite-action': 'open-source',
}, tt('cite.overlay.action.open_source', 'View source')));
actions.appendChild(primary);
var secondary = el('div', { 'class': 'cite-modal-actions-row cite-modal-actions-row--secondary' });
var copyBtn = el('button', {
type: 'button',
'class': 'cite-modal-action cite-modal-action--secondary',
'data-cite-action': 'copy-citation',
}, tt('cite.overlay.action.copy_citation', 'Copy citation'));
copyBtn.dataset.payload = citation;
secondary.appendChild(copyBtn);
copyBtnAction['copy-citation'] = copyBtn;
var printBtn = el('button', {
type: 'button',
'class': 'cite-modal-action cite-modal-action--secondary',
'data-cite-action': 'print',
}, printLabel());
secondary.appendChild(printBtn);
copyBtnAction['print'] = printBtn;
actions.appendChild(secondary);
card.appendChild(actions);
var liveStatus = el('output', {
'class': 'visually-hidden',
'aria-live': 'polite',
'id': 'cite-copy-status',
});
card.appendChild(liveStatus);
overlay.appendChild(card);
document.body.appendChild(overlay);
overlay.addEventListener('click', function (e) {
if (e.target === overlay) {
if (window.TP_OVERLAY && window.TP_OVERLAY.close) window.TP_OVERLAY.close();
}
});
card.addEventListener('click', handleActionClick);
}
function handleActionClick(e) {
var t = e.target && e.target.closest
? e.target.closest('[data-cite-action]')
: null;
if (!t) return;
var action = t.dataset.citeAction;
if (action === 'close') {
if (window.TP_OVERLAY && window.TP_OVERLAY.close) window.TP_OVERLAY.close();
return;
}
if (action === 'print') {
window.print();
if (window.TP_OVERLAY && window.TP_OVERLAY.close) window.TP_OVERLAY.close();
return;
}
if (action === 'copy-citation') {
e.preventDefault();
var payload = t.dataset.payload || '';
if (!payload) return;
if (!navigator.clipboard) return;
var prev = t.textContent;
var toastKey = 'cite.overlay.toast.citation_copied';
var toastFallback = 'citation copied';
navigator.clipboard.writeText(payload).then(function () {
var toastText = tt(toastKey, toastFallback);
t.textContent = toastText;
t.setAttribute('data-state', 'copied');
var status = document.getElementById('cite-copy-status');
if (status) {
status.textContent = '';
setTimeout(function () { status.textContent = toastText; }, 0);
}
setTimeout(function () {
t.textContent = prev;
t.removeAttribute('data-state');
if (status) status.textContent = '';
}, 1400);
}, function () { });
return;
}
}
function openCite(e, opener) {
if (!opener && e && e.currentTarget) opener = e.currentTarget;
if (!window.TP_OVERLAY || !window.TP_OVERLAY.open) {
if (e && typeof e.preventDefault === 'function') e.preventDefault();
try { console.warn('cite overlay unavailable, falling back to /verify/'); }
catch (_) {}
window.location.href = '/verify/';
return;
}
if (e && typeof e.preventDefault === 'function') e.preventDefault();
if (!overlay) buildOverlay();
window.TP_OVERLAY.open(overlay, opener || null, { hash: '#cite' });
}
function init() {
var triggers = document.querySelectorAll('[data-cite-open]');
if (!triggers.length) return;
Array.prototype.forEach.call(triggers, function (trigger) {
trigger.addEventListener('click', function (e) { openCite(e, trigger); });
});
if (window.location.hash === '#cite') {
setTimeout(function () { openCite(null, triggers[0]); }, 0);
}
window.addEventListener('popstate', function () {
var st = history.state;
if (window.location.hash === '#cite' && st && st.tp_overlay === 'cite' &&
!document.querySelector('.modal-overlay.active')) {
if (!overlay) buildOverlay();
if (window.TP_OVERLAY && window.TP_OVERLAY.open) {
window.TP_OVERLAY.open(overlay, triggers[0], { hash: '#cite', fromPopstate: true });
}
}
});
var observer = new MutationObserver(function (mutations) {
for (var i = 0; i < mutations.length; i++) {
if (mutations[i].attributeName === 'lang') {
if (overlay) {
overlay.parentNode && overlay.parentNode.removeChild(overlay);
overlay = null;
copyBtnAction = {};
}
break;
}
}
});
observer.observe(document.documentElement, { attributes: true });
}
function _scheduleInit() {
if ('requestIdleCallback' in window) {
window.requestIdleCallback(init, { timeout: 1500 });
} else {
window.setTimeout(init, 500);
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', _scheduleInit);
} else {
_scheduleInit();
}
function _wireCopyButtons() {
var copyBtns = document.querySelectorAll('.copy-fingerprint[data-copy-target], .verify-command-copy[data-copy-target]');
copyBtns.forEach(function (b) {
var resting = b.textContent;
var collapse = b.classList.contains('copy-fingerprint');
b.addEventListener('click', function () {
var target = document.getElementById(b.dataset.copyTarget);
if (!target || !navigator.clipboard) return;
var raw = target.textContent || '';
var text = collapse ? raw.replace(/\s+/g, ' ').trim() : raw.replace(/\s+$/, '');
navigator.clipboard.writeText(text).then(function () {
b.textContent = tt('cite.copied', 'Copied');
b.setAttribute('data-state', 'copied');
setTimeout(function () {
b.textContent = resting;
b.removeAttribute('data-state');
}, 1500);
}, function () { });
});
});
}
if ('requestIdleCallback' in window) {
window.requestIdleCallback(_wireCopyButtons, { timeout: 1500 });
} else {
window.setTimeout(_wireCopyButtons, 500);
}
})();
