feat: implémenter système de gestion des tags cachés avec panel de configuration, présets système (note/shaarli-pin/readitlater/archiver), support wildcards (note-color-*/notebg-*/notefilter-*), ajout/suppression tags personnalisés, filtrage automatique DOM avec MutationObserver, exclusion tags cachés dans recherche/bookmarks/tag cloud, amélioration responsive modale recherche mobile (95% width, 90vh height, padding 5vh), et styles modernes avec gradients bleus, chips interactifs, toggle
This commit is contained in:
+125
-2
@@ -84,6 +84,124 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
});
|
||||
|
||||
// ===== Hidden Tags Management =====
|
||||
const HIDDEN_TAGS_STORAGE_KEY = 'shaarli_hidden_tags';
|
||||
|
||||
// Default system tags that are hidden by default
|
||||
const DEFAULT_HIDDEN_TAGS = [
|
||||
'note',
|
||||
'shaarli-pin',
|
||||
'note-color-*',
|
||||
'notebg-*',
|
||||
'notefilter-*',
|
||||
'readitlater',
|
||||
'shaarli-archiver'
|
||||
];
|
||||
|
||||
// Get hidden tags from localStorage
|
||||
function getHiddenTags() {
|
||||
try {
|
||||
const stored = localStorage.getItem(HIDDEN_TAGS_STORAGE_KEY);
|
||||
if (stored) {
|
||||
return JSON.parse(stored);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error loading hidden tags:', e);
|
||||
}
|
||||
return [...DEFAULT_HIDDEN_TAGS];
|
||||
}
|
||||
|
||||
// Check if a tag matches a wildcard pattern
|
||||
function matchesWildcard(pattern, tag) {
|
||||
const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$', 'i');
|
||||
return regex.test(tag);
|
||||
}
|
||||
|
||||
// Check if a tag should be hidden
|
||||
function isTagHidden(tag) {
|
||||
if (!tag) return false;
|
||||
const normalizedTag = tag.toLowerCase().trim();
|
||||
const hiddenTags = getHiddenTags();
|
||||
|
||||
return hiddenTags.some(hiddenTag => {
|
||||
const normalizedHidden = hiddenTag.toLowerCase().trim();
|
||||
if (normalizedHidden.includes('*')) {
|
||||
return matchesWildcard(normalizedHidden, normalizedTag);
|
||||
}
|
||||
return normalizedHidden === normalizedTag;
|
||||
});
|
||||
}
|
||||
|
||||
// Filter out hidden tags from a list
|
||||
function filterHiddenTags(tags) {
|
||||
if (!Array.isArray(tags)) return [];
|
||||
return tags.filter(tag => !isTagHidden(tag));
|
||||
}
|
||||
|
||||
// Hide tag elements in the DOM
|
||||
function hideHiddenTagElements() {
|
||||
// Hide tag chips in bookmark cards
|
||||
document.querySelectorAll('.link-tag[data-tag]').forEach(el => {
|
||||
const tag = el.getAttribute('data-tag');
|
||||
if (isTagHidden(tag)) {
|
||||
el.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
// Hide tags in tag list
|
||||
document.querySelectorAll('#tagListContainer .list-group-item[data-tag-name]').forEach(el => {
|
||||
const tagName = el.getAttribute('data-tag-name');
|
||||
if (isTagHidden(tagName)) {
|
||||
el.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
// Hide tags in tag cloud
|
||||
document.querySelectorAll('.tag-item[data-tag]').forEach(el => {
|
||||
const tag = el.getAttribute('data-tag');
|
||||
if (isTagHidden(tag)) {
|
||||
el.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
// Update visible tag count in tag list
|
||||
const visibleTagCountEl = document.getElementById('visibleTagCount');
|
||||
if (visibleTagCountEl) {
|
||||
const visibleTags = document.querySelectorAll('#tagListContainer .list-group-item:not([style*="display: none"])');
|
||||
visibleTagCountEl.textContent = visibleTags.length;
|
||||
}
|
||||
}
|
||||
|
||||
// Run on page load
|
||||
hideHiddenTagElements();
|
||||
|
||||
// Set up MutationObserver to handle dynamically added tags
|
||||
const tagObserver = new MutationObserver((mutations) => {
|
||||
let shouldFilter = false;
|
||||
mutations.forEach((mutation) => {
|
||||
if (mutation.type === 'childList') {
|
||||
mutation.addedNodes.forEach((node) => {
|
||||
if (node.nodeType === Node.ELEMENT_NODE) {
|
||||
// Check if added node contains tags
|
||||
if (node.matches?.('.link-tag[data-tag], .tag-item[data-tag], [data-tag-name], .list-group-item[data-tag-name]') ||
|
||||
node.querySelector?.('.link-tag[data-tag], .tag-item[data-tag], [data-tag-name], .list-group-item[data-tag-name]')) {
|
||||
shouldFilter = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
if (shouldFilter) {
|
||||
hideHiddenTagElements();
|
||||
}
|
||||
});
|
||||
|
||||
// Start observing once DOM is ready
|
||||
tagObserver.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
|
||||
// ===== Search Overlay (Spotlight Style) =====
|
||||
try {
|
||||
const searchOverlay = document.getElementById('search-overlay');
|
||||
@@ -127,7 +245,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
return text.toLowerCase().includes(query.toLowerCase());
|
||||
}
|
||||
|
||||
// Fetch all unique tags from the page
|
||||
// Fetch all unique tags from the page (excluding hidden tags)
|
||||
function fetchTags() {
|
||||
if (cachedTags) return cachedTags;
|
||||
try {
|
||||
@@ -137,6 +255,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
if (typeof value !== 'string') return;
|
||||
const cleaned = value.trim();
|
||||
if (!cleaned || cleaned.includes('•')) return;
|
||||
// Skip hidden tags
|
||||
if (isTagHidden(cleaned)) return;
|
||||
tagsSet.add(cleaned);
|
||||
};
|
||||
|
||||
@@ -172,7 +292,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
isNote: (el.querySelector('.link-title')?.getAttribute('title') || '').toLowerCase().includes('note'),
|
||||
title: el.querySelector('.link-title a')?.textContent || el.querySelector('.link-title')?.textContent || '',
|
||||
url: el.querySelector('.link-url a')?.href || el.querySelector('.link-title a')?.href || '',
|
||||
tags: Array.from(el.querySelectorAll('.link-tag[data-tag]')).map(t => (t.getAttribute('data-tag') || '').trim()).filter(Boolean),
|
||||
// Filter out hidden tags
|
||||
tags: filterHiddenTags(
|
||||
Array.from(el.querySelectorAll('.link-tag[data-tag]')).map(t => (t.getAttribute('data-tag') || '').trim()).filter(Boolean)
|
||||
),
|
||||
description: el.querySelector('.link-description')?.textContent || ''
|
||||
}));
|
||||
return cachedBookmarks;
|
||||
|
||||
Reference in New Issue
Block a user