118 lines
3.9 KiB
JavaScript
118 lines
3.9 KiB
JavaScript
/* =============================================
|
|
HELLION NEWTAB — state.js
|
|
Globaler State, Default-Werte, Hilfsfunktionen
|
|
============================================= */
|
|
|
|
let boards = [];
|
|
|
|
// Papierkorb als EIGENER Store-Key (nicht im boards-Payload), isoliert das Quota-Risiko (CR-04/TRASH-02).
|
|
// Eintrag-Schema: { item, type: 'bookmark'|'board', deletedAt, originBoardId }
|
|
let trash = [];
|
|
|
|
// Papierkorb: Auto-Cleanup-Fenster und harte Obergrenze (Quota-Schutz, TRASH-04).
|
|
// 30 Tage in Millisekunden; ueber dieser Zeit wird ein Eintrag beim Laden auto-geloescht.
|
|
const TRASH_RETENTION_MS = 30 * 24 * 60 * 60 * 1000;
|
|
// Max. Anzahl trash-Eintraege. Bei Ueberlauf werden die aeltesten zuerst verworfen,
|
|
// damit der Papierkorb nicht das 10-MB-Storage-Limit sprengt (kein blindes Wachstum).
|
|
const TRASH_MAX_ENTRIES = 100;
|
|
|
|
let settings = {
|
|
compact: false,
|
|
shortenTitles: false,
|
|
newTab: true,
|
|
showDesc: false,
|
|
hideExtra: false,
|
|
visibleCount: 10,
|
|
bgUrl: '',
|
|
theme: 'nebula',
|
|
showSearch: true,
|
|
searchEngine: 'google',
|
|
toolbarPos: 'right',
|
|
imageRefEnabled: false,
|
|
language: 'auto'
|
|
};
|
|
|
|
// uid() lebt jetzt in quicksave-core.js (globalThis.uid), damit Seite und
|
|
// Background-Worker dieselbe ID-Erzeugung teilen. Hier bewusst KEINE eigene Deklaration.
|
|
|
|
function escHtml(str) {
|
|
return String(str)
|
|
.replace(/&/g, '&')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>')
|
|
.replace(/"/g, '"');
|
|
}
|
|
|
|
function getDefaultBoards() {
|
|
return [
|
|
{
|
|
id: uid(),
|
|
title: 'Getting Started',
|
|
bookmarks: [
|
|
{ id: uid(), title: 'GitHub', url: 'https://github.com', desc: '' },
|
|
{ id: uid(), title: 'MDN Web Docs', url: 'https://developer.mozilla.org', desc: '' },
|
|
{ id: uid(), title: 'Next.js Docs', url: 'https://nextjs.org/docs', desc: '' },
|
|
],
|
|
blurred: false
|
|
}
|
|
];
|
|
}
|
|
|
|
async function saveBoards() {
|
|
await Store.set('boards', boards);
|
|
}
|
|
|
|
async function saveTrash() {
|
|
await Store.set('trash', trash);
|
|
}
|
|
|
|
/**
|
|
* Legt einen Eintrag in den Papierkorb. Klont das Objekt (structuredClone),
|
|
* damit der trash-Eintrag nicht per Referenz an boards[] haengt und nach dem
|
|
* Restore-Loop konsistent bleibt. Setzt deletedAt. Erzwingt die harte Obergrenze
|
|
* TRASH_MAX_ENTRIES (Quota-Schutz, TRASH-04): bei Ueberlauf fallen die aeltesten
|
|
* Eintraege heraus. Speichern uebernimmt der Aufrufer (saveTrash()).
|
|
* @param {{ item: Object, type: 'bookmark'|'board', originBoardId: (string|null) }} entry
|
|
*/
|
|
function pushToTrash({ item, type, originBoardId }) {
|
|
trash.push({
|
|
item: structuredClone(item),
|
|
type,
|
|
originBoardId: originBoardId ?? null,
|
|
deletedAt: Date.now()
|
|
});
|
|
// Aelteste zuerst kappen, falls die Obergrenze ueberschritten ist.
|
|
if (trash.length > TRASH_MAX_ENTRIES) {
|
|
trash.sort((a, b) => a.deletedAt - b.deletedAt);
|
|
trash = trash.slice(trash.length - TRASH_MAX_ENTRIES);
|
|
}
|
|
}
|
|
|
|
// Page-seitiger Wrapper um das DOM-freie ensureInbox() aus quicksave-core.js.
|
|
// ensureInbox() mutiert das globale boards-Array in-place; wir persistieren nur,
|
|
// wenn die Inbox neu angelegt wurde, und geben das Inbox-Board-Objekt zurueck
|
|
// (fuer Quick-Save-/Restore-Pfade).
|
|
async function ensureInboxBoard() {
|
|
const before = boards.length;
|
|
const inbox = ensureInbox(boards); // global aus quicksave-core.js; mutiert boards in-place
|
|
if (boards.length !== before) {
|
|
await saveBoards();
|
|
}
|
|
return inbox;
|
|
}
|
|
|
|
async function saveSettings() {
|
|
await Store.set('settings', settings);
|
|
}
|
|
|
|
// ---- VIEW TRANSITIONS ----
|
|
// Fuehrt eine synchrone DOM-Mutation mit nativem View-Transition-Fade aus.
|
|
// Feature-Detection-Fallback (Firefox < 144): instant. reduced-motion kappt das Fade ueber den ungeschichteten @media-Block.
|
|
function withViewTransition(mutate) {
|
|
if (document.startViewTransition) {
|
|
document.startViewTransition(mutate);
|
|
} else {
|
|
mutate();
|
|
}
|
|
}
|