Files

75 lines
2.8 KiB
JavaScript

(() => {
'use strict';
const language = document.documentElement.lang || navigator.language || 'de-DE';
const zone = Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC';
const formatter = new Intl.DateTimeFormat(language, {
dateStyle: 'short',
timeStyle: 'medium'
});
function parseUtc(value) {
if (!value) return null;
let normalized = String(value).trim();
if (!normalized) return null;
// Project database timestamps without an offset are UTC by convention.
if (/^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?$/.test(normalized)) {
normalized = normalized.replace(' ', 'T') + 'Z';
}
const date = new Date(normalized);
return Number.isNaN(date.getTime()) ? null : date;
}
function formatUtc(value, fallback = '') {
const date = parseUtc(value);
return date ? formatter.format(date) : (fallback || value || '');
}
function localizeElement(element) {
const value = element.getAttribute('datetime') || element.dataset.utc;
if (!value) return;
const formatted = formatUtc(value, element.textContent);
element.textContent = formatted;
element.title = `${value} UTC · ${zone}`;
element.dataset.localTimeApplied = 'true';
const cell = element.closest('[data-sort-value]');
if (cell) cell.dataset.sortValue = value;
}
const isoPattern = /(?<!\d)(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?)(?!\d)/g;
function localizeLogText(element) {
if (!element || element.dataset.localizingLog === 'true') return;
const original = element.textContent || '';
const converted = original.replace(isoPattern, match => formatUtc(match, match));
if (converted !== original) {
element.dataset.localizingLog = 'true';
element.textContent = converted;
delete element.dataset.localizingLog;
}
element.title = zone;
}
function scan(root = document) {
if (root.matches?.('time[data-utc], time[datetime].local-time')) localizeElement(root);
root.querySelectorAll?.('time[data-utc], time[datetime].local-time').forEach(localizeElement);
if (root.matches?.('[data-localize-log]')) localizeLogText(root);
root.querySelectorAll?.('[data-localize-log]').forEach(localizeLogText);
}
window.AssetManagerTime = {formatUtc, parseUtc, zone, scan};
scan(document);
const observer = new MutationObserver(mutations => {
for (const mutation of mutations) {
mutation.addedNodes.forEach(node => {
if (node.nodeType === Node.ELEMENT_NODE) scan(node);
});
const owner = mutation.target.nodeType === Node.ELEMENT_NODE
? mutation.target.closest?.('[data-localize-log]')
: mutation.target.parentElement?.closest?.('[data-localize-log]');
if (owner) localizeLogText(owner);
}
});
observer.observe(document.body, {childList: true, subtree: true, characterData: true});
})();