bookmarks restyling
This commit is contained in:
517
web/app.js
517
web/app.js
@@ -101,10 +101,8 @@ const SORT_SETTINGS_LEGACY_KEY = 'trackerSortMode';
|
||||
const FACEBOOK_TRACKING_PARAMS = ['__cft__', '__tn__', '__eep__', 'mibextid', 'set', 'comment_id', 'hoisted_section_header_type'];
|
||||
const VALID_SORT_MODES = new Set(['created', 'deadline', 'smart', 'lastCheck', 'lastChange']);
|
||||
const DEFAULT_SORT_SETTINGS = { mode: 'created', direction: 'desc' };
|
||||
const BOOKMARKS_STORAGE_KEY = 'trackerSearchBookmarks';
|
||||
const BOOKMARKS_BASE_URL = 'https://www.facebook.com/search/top';
|
||||
const BOOKMARK_WINDOW_DAYS = 28;
|
||||
const DEFAULT_BOOKMARKS = [];
|
||||
const BOOKMARK_SUFFIXES = ['Gewinnspiel', 'gewinnen', 'verlosen'];
|
||||
|
||||
function initializeFocusParams() {
|
||||
@@ -279,53 +277,202 @@ function persistSortStorage(storage) {
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeCustomBookmark(entry) {
|
||||
function normalizeServerBookmark(entry) {
|
||||
if (!entry || typeof entry !== 'object') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const id = typeof entry.id === 'string' ? entry.id : null;
|
||||
const query = typeof entry.query === 'string' ? entry.query.trim() : '';
|
||||
if (!query) {
|
||||
if (!id || !query) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const label = typeof entry.label === 'string' && entry.label.trim() ? entry.label.trim() : query;
|
||||
const id = typeof entry.id === 'string' && entry.id ? entry.id : `custom-${Date.now()}-${Math.random().toString(16).slice(2, 8)}`;
|
||||
|
||||
const normalizeDate = (value) => {
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
const date = new Date(value);
|
||||
if (Number.isNaN(date.getTime())) {
|
||||
return null;
|
||||
}
|
||||
return date.toISOString();
|
||||
};
|
||||
|
||||
return {
|
||||
id,
|
||||
label,
|
||||
query,
|
||||
type: 'custom'
|
||||
created_at: normalizeDate(entry.created_at),
|
||||
updated_at: normalizeDate(entry.updated_at),
|
||||
last_clicked_at: normalizeDate(entry.last_clicked_at),
|
||||
deletable: true
|
||||
};
|
||||
}
|
||||
|
||||
function loadCustomBookmarks() {
|
||||
try {
|
||||
const raw = localStorage.getItem(BOOKMARKS_STORAGE_KEY);
|
||||
if (!raw) {
|
||||
return [];
|
||||
function deduplicateBookmarks(list) {
|
||||
const seen = new Set();
|
||||
const deduped = [];
|
||||
|
||||
list.forEach((bookmark) => {
|
||||
if (!bookmark || !bookmark.query) {
|
||||
return;
|
||||
}
|
||||
const parsed = JSON.parse(raw);
|
||||
if (!Array.isArray(parsed)) {
|
||||
return [];
|
||||
const key = bookmark.query.toLowerCase();
|
||||
if (seen.has(key)) {
|
||||
return;
|
||||
}
|
||||
return parsed.map(normalizeCustomBookmark).filter(Boolean);
|
||||
} catch (error) {
|
||||
console.warn('Konnte Bookmarks nicht laden:', error);
|
||||
return [];
|
||||
}
|
||||
seen.add(key);
|
||||
deduped.push(bookmark);
|
||||
});
|
||||
|
||||
return deduped;
|
||||
}
|
||||
|
||||
function saveCustomBookmarks(bookmarks) {
|
||||
try {
|
||||
const sanitized = Array.isArray(bookmarks)
|
||||
? bookmarks.map(normalizeCustomBookmark).filter(Boolean)
|
||||
: [];
|
||||
localStorage.setItem(BOOKMARKS_STORAGE_KEY, JSON.stringify(sanitized));
|
||||
} catch (error) {
|
||||
console.warn('Konnte Bookmarks nicht speichern:', error);
|
||||
function sortBookmarksByRecency(list) {
|
||||
return [...list].sort((a, b) => {
|
||||
const aClick = a.last_clicked_at ? new Date(a.last_clicked_at).getTime() : -Infinity;
|
||||
const bClick = b.last_clicked_at ? new Date(b.last_clicked_at).getTime() : -Infinity;
|
||||
if (aClick !== bClick) {
|
||||
return bClick - aClick;
|
||||
}
|
||||
|
||||
const aCreated = a.created_at ? new Date(a.created_at).getTime() : -Infinity;
|
||||
const bCreated = b.created_at ? new Date(b.created_at).getTime() : -Infinity;
|
||||
if (aCreated !== bCreated) {
|
||||
return bCreated - aCreated;
|
||||
}
|
||||
|
||||
return a.label.localeCompare(b.label, 'de', { sensitivity: 'base' });
|
||||
});
|
||||
}
|
||||
|
||||
const bookmarkState = {
|
||||
items: [],
|
||||
loaded: false,
|
||||
loading: false,
|
||||
error: null
|
||||
};
|
||||
|
||||
let bookmarkFetchPromise = null;
|
||||
|
||||
function formatRelativeTimeFromNow(timestamp) {
|
||||
if (!timestamp) {
|
||||
return 'Noch nie geöffnet';
|
||||
}
|
||||
|
||||
const date = new Date(timestamp);
|
||||
if (Number.isNaN(date.getTime())) {
|
||||
return 'Zuletzt: unbekannt';
|
||||
}
|
||||
|
||||
const diffMs = Date.now() - date.getTime();
|
||||
if (diffMs < 0) {
|
||||
return 'gerade eben';
|
||||
}
|
||||
const diffSeconds = Math.floor(diffMs / 1000);
|
||||
if (diffSeconds < 45) {
|
||||
return 'vor wenigen Sekunden';
|
||||
}
|
||||
const diffMinutes = Math.floor(diffSeconds / 60);
|
||||
if (diffMinutes < 60) {
|
||||
return `vor ${diffMinutes} ${diffMinutes === 1 ? 'Minute' : 'Minuten'}`;
|
||||
}
|
||||
const diffHours = Math.floor(diffMinutes / 60);
|
||||
if (diffHours < 24) {
|
||||
return `vor ${diffHours} ${diffHours === 1 ? 'Stunde' : 'Stunden'}`;
|
||||
}
|
||||
const diffDays = Math.floor(diffHours / 24);
|
||||
if (diffDays < 31) {
|
||||
return `vor ${diffDays} ${diffDays === 1 ? 'Tag' : 'Tagen'}`;
|
||||
}
|
||||
const diffMonths = Math.floor(diffDays / 30);
|
||||
if (diffMonths < 12) {
|
||||
return `vor ${diffMonths} ${diffMonths === 1 ? 'Monat' : 'Monaten'}`;
|
||||
}
|
||||
const diffYears = Math.floor(diffMonths / 12);
|
||||
return `vor ${diffYears} ${diffYears === 1 ? 'Jahr' : 'Jahren'}`;
|
||||
}
|
||||
|
||||
function upsertBookmarkInState(bookmark) {
|
||||
const normalized = normalizeServerBookmark(bookmark);
|
||||
if (!normalized) {
|
||||
return;
|
||||
}
|
||||
|
||||
const lowerQuery = normalized.query.toLowerCase();
|
||||
const existingIndex = bookmarkState.items.findIndex((item) => {
|
||||
if (!item || !item.query) {
|
||||
return false;
|
||||
}
|
||||
return item.id === normalized.id || item.query.toLowerCase() === lowerQuery;
|
||||
});
|
||||
|
||||
if (existingIndex >= 0) {
|
||||
bookmarkState.items[existingIndex] = { ...bookmarkState.items[existingIndex], ...normalized };
|
||||
} else {
|
||||
bookmarkState.items.push(normalized);
|
||||
}
|
||||
|
||||
bookmarkState.items = deduplicateBookmarks(sortBookmarksByRecency(bookmarkState.items));
|
||||
}
|
||||
|
||||
function removeBookmarkFromState(bookmarkId) {
|
||||
if (!bookmarkId) {
|
||||
return;
|
||||
}
|
||||
bookmarkState.items = bookmarkState.items.filter((bookmark) => bookmark.id !== bookmarkId);
|
||||
}
|
||||
|
||||
async function refreshBookmarks(options = {}) {
|
||||
const { force = false } = options;
|
||||
if (bookmarkFetchPromise && !force) {
|
||||
return bookmarkFetchPromise;
|
||||
}
|
||||
|
||||
bookmarkFetchPromise = (async () => {
|
||||
bookmarkState.loading = true;
|
||||
if (!bookmarkState.loaded || force) {
|
||||
renderBookmarks();
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await apiFetch(`${API_URL}/bookmarks`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const normalized = Array.isArray(data)
|
||||
? data.map(normalizeServerBookmark).filter(Boolean)
|
||||
: [];
|
||||
|
||||
const finalList = deduplicateBookmarks(sortBookmarksByRecency(normalized));
|
||||
|
||||
bookmarkState.items = finalList;
|
||||
bookmarkState.loaded = true;
|
||||
bookmarkState.loading = false;
|
||||
bookmarkState.error = null;
|
||||
renderBookmarks();
|
||||
|
||||
return bookmarkState.items;
|
||||
} catch (error) {
|
||||
console.warn('Konnte Bookmarks nicht laden:', error);
|
||||
bookmarkState.error = 'Bookmarks konnten nicht geladen werden.';
|
||||
bookmarkState.loading = false;
|
||||
if (!bookmarkState.loaded) {
|
||||
bookmarkState.items = [];
|
||||
}
|
||||
renderBookmarks();
|
||||
throw error;
|
||||
} finally {
|
||||
bookmarkFetchPromise = null;
|
||||
}
|
||||
})();
|
||||
|
||||
return bookmarkFetchPromise;
|
||||
}
|
||||
|
||||
function formatFacebookDateParts(date) {
|
||||
@@ -457,6 +604,22 @@ function openBookmark(bookmark) {
|
||||
queries.push('');
|
||||
}
|
||||
|
||||
const stateBookmark = bookmarkState.items.find((item) => item.id === bookmark.id) || bookmark;
|
||||
|
||||
if (stateBookmark && stateBookmark.id && stateBookmark.deletable !== false) {
|
||||
const nowIso = new Date().toISOString();
|
||||
upsertBookmarkInState({
|
||||
id: stateBookmark.id,
|
||||
label: stateBookmark.label,
|
||||
query: stateBookmark.query,
|
||||
last_clicked_at: nowIso,
|
||||
created_at: stateBookmark.created_at || nowIso,
|
||||
updated_at: nowIso
|
||||
});
|
||||
renderBookmarks();
|
||||
markBookmarkClick(stateBookmark.id);
|
||||
}
|
||||
|
||||
queries.forEach((searchTerm) => {
|
||||
const url = buildBookmarkSearchUrl(searchTerm);
|
||||
if (url) {
|
||||
@@ -465,18 +628,114 @@ function openBookmark(bookmark) {
|
||||
});
|
||||
}
|
||||
|
||||
function removeBookmark(bookmarkId) {
|
||||
async function markBookmarkClick(bookmarkId) {
|
||||
if (!bookmarkId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const current = loadCustomBookmarks();
|
||||
const next = current.filter((bookmark) => bookmark.id !== bookmarkId);
|
||||
if (next.length === current.length) {
|
||||
try {
|
||||
const response = await apiFetch(`${API_URL}/bookmarks/${encodeURIComponent(bookmarkId)}/click`, {
|
||||
method: 'POST'
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updated = await response.json();
|
||||
upsertBookmarkInState(updated);
|
||||
renderBookmarks();
|
||||
} catch (error) {
|
||||
console.warn('Konnte Bookmark-Klick nicht speichern:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function removeBookmark(bookmarkId) {
|
||||
if (!bookmarkId) {
|
||||
return;
|
||||
}
|
||||
saveCustomBookmarks(next);
|
||||
renderBookmarks();
|
||||
|
||||
try {
|
||||
const response = await apiFetch(`${API_URL}/bookmarks/${encodeURIComponent(bookmarkId)}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
if (response.ok || response.status === 204 || response.status === 404) {
|
||||
removeBookmarkFromState(bookmarkId);
|
||||
bookmarkState.error = null;
|
||||
renderBookmarks();
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error(`HTTP ${response.status}`);
|
||||
} catch (error) {
|
||||
console.warn('Konnte Bookmark nicht löschen:', error);
|
||||
bookmarkState.error = 'Bookmark konnte nicht gelöscht werden.';
|
||||
renderBookmarks();
|
||||
}
|
||||
}
|
||||
|
||||
function createBookmarkRow(bookmark) {
|
||||
const row = document.createElement('div');
|
||||
row.className = 'bookmark-row';
|
||||
row.dataset.query = bookmark.query || '';
|
||||
|
||||
if (!bookmark.last_clicked_at) {
|
||||
row.dataset.state = 'never-used';
|
||||
}
|
||||
if (bookmark.isDefault) {
|
||||
row.dataset.default = '1';
|
||||
}
|
||||
|
||||
const openButton = document.createElement('button');
|
||||
openButton.type = 'button';
|
||||
openButton.className = 'bookmark-row__open';
|
||||
|
||||
const searchVariants = buildBookmarkSearchQueries(bookmark.query);
|
||||
if (searchVariants.length) {
|
||||
openButton.title = searchVariants.map((variant) => `• ${variant}`).join('\n');
|
||||
}
|
||||
|
||||
openButton.addEventListener('click', () => openBookmark(bookmark));
|
||||
|
||||
const label = document.createElement('span');
|
||||
label.className = 'bookmark-row__label';
|
||||
label.textContent = bookmark.label || bookmark.query || 'Bookmark';
|
||||
openButton.appendChild(label);
|
||||
|
||||
const query = document.createElement('span');
|
||||
query.className = 'bookmark-row__query';
|
||||
query.textContent = bookmark.query ? `„${bookmark.query}“` : 'Standard-Keywords';
|
||||
openButton.appendChild(query);
|
||||
|
||||
row.appendChild(openButton);
|
||||
|
||||
const meta = document.createElement('span');
|
||||
meta.className = 'bookmark-row__meta';
|
||||
meta.textContent = formatRelativeTimeFromNow(bookmark.last_clicked_at);
|
||||
if (bookmark.last_clicked_at) {
|
||||
const date = new Date(bookmark.last_clicked_at);
|
||||
if (!Number.isNaN(date.getTime())) {
|
||||
meta.title = date.toLocaleString();
|
||||
}
|
||||
}
|
||||
row.appendChild(meta);
|
||||
|
||||
if (bookmark.deletable !== false) {
|
||||
const removeBtn = document.createElement('button');
|
||||
removeBtn.type = 'button';
|
||||
removeBtn.className = 'bookmark-row__remove';
|
||||
removeBtn.setAttribute('aria-label', `${bookmark.label || bookmark.query} entfernen`);
|
||||
removeBtn.textContent = '×';
|
||||
removeBtn.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
removeBookmark(bookmark.id);
|
||||
});
|
||||
row.appendChild(removeBtn);
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
function renderBookmarks() {
|
||||
@@ -486,62 +745,97 @@ function renderBookmarks() {
|
||||
|
||||
bookmarksList.innerHTML = '';
|
||||
|
||||
const items = [...DEFAULT_BOOKMARKS, ...loadCustomBookmarks()];
|
||||
|
||||
const staticDefault = {
|
||||
id: 'default-empty',
|
||||
label: 'Gewinnspiel / gewinnen / verlosen',
|
||||
query: '',
|
||||
type: 'default'
|
||||
};
|
||||
|
||||
items.unshift(staticDefault);
|
||||
|
||||
if (!items.length) {
|
||||
const empty = document.createElement('div');
|
||||
empty.className = 'bookmark-empty';
|
||||
empty.textContent = 'Noch keine Bookmarks vorhanden.';
|
||||
empty.setAttribute('role', 'listitem');
|
||||
bookmarksList.appendChild(empty);
|
||||
if (bookmarkState.loading && !bookmarkState.loaded) {
|
||||
const loading = document.createElement('div');
|
||||
loading.className = 'bookmark-status bookmark-status--loading';
|
||||
loading.textContent = 'Lade Bookmarks...';
|
||||
bookmarksList.appendChild(loading);
|
||||
return;
|
||||
}
|
||||
|
||||
items.forEach((bookmark) => {
|
||||
const item = document.createElement('div');
|
||||
item.className = 'bookmark-item';
|
||||
item.setAttribute('role', 'listitem');
|
||||
if (bookmarkState.error && !bookmarkState.loaded) {
|
||||
const errorNode = document.createElement('div');
|
||||
errorNode.className = 'bookmark-status bookmark-status--error';
|
||||
errorNode.textContent = bookmarkState.error;
|
||||
bookmarksList.appendChild(errorNode);
|
||||
return;
|
||||
}
|
||||
|
||||
const button = document.createElement('button');
|
||||
button.type = 'button';
|
||||
button.className = 'bookmark-button';
|
||||
const label = bookmark.label || bookmark.query;
|
||||
button.textContent = label;
|
||||
if (bookmarkState.error && bookmarkState.loaded) {
|
||||
const warnNode = document.createElement('div');
|
||||
warnNode.className = 'bookmark-status bookmark-status--error';
|
||||
warnNode.textContent = bookmarkState.error;
|
||||
bookmarksList.appendChild(warnNode);
|
||||
}
|
||||
|
||||
const searchVariants = buildBookmarkSearchQueries(bookmark.query);
|
||||
if (searchVariants.length) {
|
||||
button.title = searchVariants.map((variant) => `• ${variant}`).join('\n');
|
||||
} else {
|
||||
button.title = `Suche nach "${bookmark.query}" (letzte 4 Wochen)`;
|
||||
const dynamicBookmarks = bookmarkState.items;
|
||||
|
||||
const staticDefault = {
|
||||
id: 'default-search',
|
||||
label: 'Gewinnspiel / gewinnen / verlosen',
|
||||
query: '',
|
||||
last_clicked_at: null,
|
||||
deletable: false,
|
||||
isDefault: true
|
||||
};
|
||||
|
||||
const sorted = sortBookmarksByRecency(dynamicBookmarks);
|
||||
const recent = [];
|
||||
const RECENT_LIMIT = 5;
|
||||
|
||||
sorted.forEach((bookmark) => {
|
||||
if (bookmark.last_clicked_at && recent.length < RECENT_LIMIT) {
|
||||
recent.push(bookmark);
|
||||
}
|
||||
button.addEventListener('click', () => openBookmark(bookmark));
|
||||
});
|
||||
|
||||
item.appendChild(button);
|
||||
const alphabeticalAll = [...dynamicBookmarks]
|
||||
.sort((a, b) => a.label.localeCompare(b.label, 'de', { sensitivity: 'base' }));
|
||||
|
||||
if (bookmark.type === 'custom') {
|
||||
const removeBtn = document.createElement('button');
|
||||
removeBtn.type = 'button';
|
||||
removeBtn.className = 'bookmark-remove-btn';
|
||||
removeBtn.setAttribute('aria-label', `${bookmark.label || bookmark.query} entfernen`);
|
||||
removeBtn.textContent = '×';
|
||||
removeBtn.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
removeBookmark(bookmark.id);
|
||||
});
|
||||
item.appendChild(removeBtn);
|
||||
const sections = [];
|
||||
|
||||
if (recent.length) {
|
||||
sections.push({
|
||||
id: 'recent',
|
||||
title: 'Zuletzt verwendet',
|
||||
items: recent
|
||||
});
|
||||
}
|
||||
|
||||
sections.push({
|
||||
id: 'all',
|
||||
title: 'Alle Bookmarks',
|
||||
items: [staticDefault, ...alphabeticalAll]
|
||||
});
|
||||
|
||||
sections.forEach((section) => {
|
||||
if (!section.items.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
bookmarksList.appendChild(item);
|
||||
const sectionElement = document.createElement('section');
|
||||
sectionElement.className = 'bookmark-section';
|
||||
sectionElement.dataset.section = section.id;
|
||||
|
||||
const header = document.createElement('header');
|
||||
header.className = 'bookmark-section__header';
|
||||
|
||||
const title = document.createElement('h3');
|
||||
title.className = 'bookmark-section__title';
|
||||
title.textContent = section.title;
|
||||
header.appendChild(title);
|
||||
|
||||
sectionElement.appendChild(header);
|
||||
|
||||
const list = document.createElement('div');
|
||||
list.className = 'bookmark-section__list';
|
||||
|
||||
section.items.forEach((bookmark) => {
|
||||
list.appendChild(createBookmarkRow(bookmark));
|
||||
});
|
||||
|
||||
sectionElement.appendChild(list);
|
||||
bookmarksList.appendChild(sectionElement);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -604,7 +898,13 @@ function toggleBookmarkPanel(forceVisible) {
|
||||
bookmarkPanelToggle.setAttribute('aria-expanded', bookmarkPanelVisible ? 'true' : 'false');
|
||||
|
||||
if (bookmarkPanelVisible) {
|
||||
renderBookmarks();
|
||||
if (!bookmarkState.loaded && !bookmarkState.loading) {
|
||||
bookmarkState.loading = true;
|
||||
renderBookmarks();
|
||||
refreshBookmarks().catch(() => {});
|
||||
} else {
|
||||
renderBookmarks();
|
||||
}
|
||||
resetBookmarkForm();
|
||||
if (bookmarkQueryInput) {
|
||||
window.requestAnimationFrame(() => {
|
||||
@@ -619,13 +919,14 @@ function toggleBookmarkPanel(forceVisible) {
|
||||
} else {
|
||||
resetBookmarkForm();
|
||||
removeBookmarkOutsideHandler();
|
||||
bookmarkState.error = null;
|
||||
if (bookmarkPanelToggle) {
|
||||
bookmarkPanelToggle.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleBookmarkSubmit(event) {
|
||||
async function handleBookmarkSubmit(event) {
|
||||
event.preventDefault();
|
||||
|
||||
if (!bookmarkForm) {
|
||||
@@ -643,26 +944,44 @@ function handleBookmarkSubmit(event) {
|
||||
return;
|
||||
}
|
||||
|
||||
const customBookmarks = loadCustomBookmarks();
|
||||
const normalizedQuery = query.toLowerCase();
|
||||
const existingIndex = customBookmarks.findIndex((bookmark) => bookmark.query.toLowerCase() === normalizedQuery);
|
||||
bookmarkState.error = null;
|
||||
|
||||
const nextBookmark = {
|
||||
id: existingIndex >= 0 ? customBookmarks[existingIndex].id : `custom-${Date.now()}-${Math.random().toString(16).slice(2, 8)}`,
|
||||
label: name || query,
|
||||
query,
|
||||
type: 'custom'
|
||||
};
|
||||
try {
|
||||
const response = await apiFetch(`${API_URL}/bookmarks`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
label: name,
|
||||
query
|
||||
})
|
||||
});
|
||||
|
||||
if (existingIndex >= 0) {
|
||||
customBookmarks[existingIndex] = nextBookmark;
|
||||
} else {
|
||||
customBookmarks.push(nextBookmark);
|
||||
if (response.status === 409) {
|
||||
bookmarkState.error = 'Bookmark existiert bereits.';
|
||||
renderBookmarks();
|
||||
resetBookmarkForm();
|
||||
if (bookmarkQueryInput) {
|
||||
bookmarkQueryInput.focus();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}`);
|
||||
}
|
||||
|
||||
const created = await response.json();
|
||||
upsertBookmarkInState(created);
|
||||
bookmarkState.error = null;
|
||||
renderBookmarks();
|
||||
resetBookmarkForm();
|
||||
} catch (error) {
|
||||
console.warn('Konnte Bookmark nicht speichern:', error);
|
||||
bookmarkState.error = 'Bookmark konnte nicht gespeichert werden.';
|
||||
renderBookmarks();
|
||||
}
|
||||
|
||||
saveCustomBookmarks(customBookmarks);
|
||||
renderBookmarks();
|
||||
resetBookmarkForm();
|
||||
}
|
||||
|
||||
function initializeBookmarks() {
|
||||
@@ -670,7 +989,7 @@ function initializeBookmarks() {
|
||||
return;
|
||||
}
|
||||
|
||||
renderBookmarks();
|
||||
refreshBookmarks().catch(() => {});
|
||||
|
||||
if (bookmarkPanel) {
|
||||
bookmarkPanel.setAttribute('aria-hidden', 'true');
|
||||
|
||||
Reference in New Issue
Block a user