feat: add word search

This commit is contained in:
2025-06-25 16:25:52 +03:00
parent dbb6806a78
commit 80d4bff0b4
17 changed files with 78 additions and 15 deletions

View File

@@ -88,5 +88,8 @@
},
"global_highlight_toggle": {
"message": "Aktivieren"
}
},
"search_placeholder": {
"message": "Suchen..."
}
}

View File

@@ -88,5 +88,8 @@
},
"global_highlight_toggle": {
"message": "Enable"
},
"search_placeholder": {
"message": "Search..."
}
}

View File

@@ -88,5 +88,8 @@
},
"global_highlight_toggle": {
"message": "Activar"
},
"search_placeholder": {
"message": "Buscar..."
}
}

View File

@@ -88,5 +88,8 @@
},
"global_highlight_toggle": {
"message": "Activer"
},
"search_placeholder": {
"message": "Rechercher..."
}
}

View File

@@ -88,5 +88,8 @@
},
"global_highlight_toggle": {
"message": "सक्षम करें"
},
"search_placeholder": {
"message": "खोजें..."
}
}

View File

@@ -88,5 +88,8 @@
},
"global_highlight_toggle": {
"message": "Attiva"
},
"search_placeholder": {
"message": "Cerca..."
}
}

View File

@@ -88,5 +88,8 @@
},
"global_highlight_toggle": {
"message": "有効にする"
},
"search_placeholder": {
"message": "検索..."
}
}

View File

@@ -88,5 +88,8 @@
},
"global_highlight_toggle": {
"message": "활성화"
},
"search_placeholder": {
"message": "검색..."
}
}

View File

@@ -88,5 +88,8 @@
},
"global_highlight_toggle": {
"message": "Inschakelen"
},
"search_placeholder": {
"message": "Zoeken..."
}
}

View File

@@ -88,5 +88,8 @@
},
"global_highlight_toggle": {
"message": "Włącz"
},
"search_placeholder": {
"message": "Szukaj..."
}
}

View File

@@ -88,5 +88,8 @@
},
"global_highlight_toggle": {
"message": "Ativar"
}
},
"search_placeholder": {
"message": "Pesquisar..."
}
}

View File

@@ -88,5 +88,8 @@
},
"global_highlight_toggle": {
"message": "Вкл"
},
"search_placeholder": {
"message": "Поиск..."
}
}

View File

@@ -88,5 +88,8 @@
},
"global_highlight_toggle": {
"message": "Etkinleştir"
},
"search_placeholder": {
"message": "Ara..."
}
}

View File

@@ -88,5 +88,8 @@
},
"global_highlight_toggle": {
"message": "启用"
}
},
"search_placeholder": {
"message": "搜索..."
}
}

View File

@@ -236,6 +236,12 @@ button.danger:hover {
gap: 6px;
}
#wordSearch{
width:100%;
margin-bottom:8px;
margin-top: 8px;
}
#wordList {
margin-top: 8px;
position: relative;

View File

@@ -77,6 +77,7 @@
<button id="disableSelectedBtn"><span data-i18n="disable_selected">Disable</span></button>
<button id="deleteSelectedBtn" class="danger"><span data-i18n="delete_selected">Delete</span></button>
</div>
<input type="text" id="wordSearch" data-i18n="search_placeholder" placeholder="Search..."/>
<div id="wordList"></div>
</div>

View File

@@ -11,6 +11,7 @@ let currentListIndex = 0;
let saveTimeout;
let selectedCheckboxes = new Set();
let globalHighlightEnabled = true;
let wordSearchQuery = "";
function escapeHtml(str) {
return str.replace(/[&<>"']/g, function (m) {
@@ -108,7 +109,12 @@ function updateListForm() {
function renderWords() {
const list = lists[currentListIndex];
const fragment = document.createDocumentFragment();
let filteredWords = list.words;
if (wordSearchQuery.trim()) {
const q = wordSearchQuery.trim().toLowerCase();
filteredWords = list.words.filter(w => w.wordStr.toLowerCase().includes(q));
}
const itemHeight = 32;
const containerHeight = wordList.clientHeight;
@@ -116,18 +122,19 @@ function renderWords() {
const startIndex = Math.floor(scrollTop / itemHeight);
const endIndex = Math.min(
startIndex + Math.ceil(containerHeight / itemHeight) + 2,
list.words.length
filteredWords.length
);
wordList.innerHTML = '';
const spacer = document.createElement('div');
spacer.style.position = 'relative';
spacer.style.height = `${list.words.length * itemHeight}px`;
spacer.style.height = `${filteredWords.length * itemHeight}px`;
spacer.style.width = '100%';
for (let i = startIndex; i < endIndex; i++) {
const w = list.words[i];
const w = filteredWords[i];
if (!w) continue;
const container = document.createElement("div");
container.style.height = `${itemHeight}px`;
container.style.position = 'absolute';
@@ -143,18 +150,20 @@ function renderWords() {
container.style.background = 'var(--highlight-tag)';
container.style.border = '1px solid var(--highlight-tag-border)';
const realIndex = list.words.indexOf(w);
const cbSelect = document.createElement("input");
cbSelect.type = "checkbox";
cbSelect.className = "word-checkbox";
cbSelect.dataset.index = i;
if (selectedCheckboxes.has(i)) {
cbSelect.dataset.index = realIndex;
if (selectedCheckboxes.has(realIndex)) {
cbSelect.checked = true;
}
const inputWord = document.createElement("input");
inputWord.type = "text";
inputWord.value = w.wordStr;
inputWord.dataset.wordEdit = i;
inputWord.dataset.wordEdit = realIndex;
inputWord.style.flexGrow = '1';
inputWord.style.minWidth = '0';
inputWord.style.padding = '4px 8px';
@@ -166,7 +175,7 @@ function renderWords() {
const inputBg = document.createElement("input");
inputBg.type = "color";
inputBg.value = w.background || list.background;
inputBg.dataset.bgEdit = i;
inputBg.dataset.bgEdit = realIndex;
inputBg.style.width = '24px';
inputBg.style.height = '24px';
inputBg.style.flexShrink = '0';
@@ -174,7 +183,7 @@ function renderWords() {
const inputFg = document.createElement("input");
inputFg.type = "color";
inputFg.value = w.foreground || list.foreground;
inputFg.dataset.fgEdit = i;
inputFg.dataset.fgEdit = realIndex;
inputFg.style.width = '24px';
inputFg.style.height = '24px';
inputFg.style.flexShrink = '0';
@@ -189,7 +198,7 @@ function renderWords() {
const cbActive = document.createElement("input");
cbActive.type = "checkbox";
cbActive.checked = w.active !== false;
cbActive.dataset.activeEdit = i;
cbActive.dataset.activeEdit = realIndex;
cbActive.className = "switch";
activeContainer.appendChild(cbActive);
@@ -207,7 +216,7 @@ function renderWords() {
const wordCount = document.getElementById('wordCount');
if (wordCount) {
wordCount.textContent = list.words.length;
wordCount.textContent = filteredWords.length;
}
}
@@ -221,7 +230,6 @@ document.addEventListener('DOMContentLoaded', () => {
renderWords();
};
// Add event listener for the global toggle
document.getElementById("globalHighlightToggle").addEventListener('change', function () {
globalHighlightEnabled = this.checked;
updateGlobalToggleState();
@@ -415,5 +423,11 @@ document.addEventListener('DOMContentLoaded', () => {
renderWords();
};
const wordSearch = document.getElementById("wordSearch");
wordSearch.addEventListener("input", (e) => {
wordSearchQuery = e.target.value;
renderWords();
});
load();
});