Add browser search/filter for media items
- Search bar appears when browsing inside a folder - Client-side filtering with 200ms debounce - Clear button and search icon - Hides at root level, resets on navigation - Localized placeholder (en/ru) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1460,6 +1460,8 @@ let totalItems = 0;
|
||||
let mediaFolders = {};
|
||||
let viewMode = localStorage.getItem('mediaBrowser.viewMode') || 'grid';
|
||||
let cachedItems = null;
|
||||
let browserSearchTerm = '';
|
||||
let browserSearchTimer = null;
|
||||
|
||||
// Load media folders on page load
|
||||
async function loadMediaFolders() {
|
||||
@@ -1490,6 +1492,10 @@ function showRootFolders() {
|
||||
currentFolderId = '';
|
||||
currentPath = '';
|
||||
currentOffset = 0;
|
||||
cachedItems = null;
|
||||
|
||||
// Hide search at root level
|
||||
showBrowserSearch(false);
|
||||
|
||||
// Render breadcrumb with just "Home" (not clickable at root)
|
||||
const breadcrumb = document.getElementById('breadcrumb');
|
||||
@@ -1550,6 +1556,9 @@ function showRootFolders() {
|
||||
}
|
||||
|
||||
async function browsePath(folderId, path, offset = 0, nocache = false) {
|
||||
// Clear search when navigating
|
||||
showBrowserSearch(false);
|
||||
|
||||
try {
|
||||
const token = localStorage.getItem('media_server_token');
|
||||
if (!token) {
|
||||
@@ -1582,6 +1591,9 @@ async function browsePath(folderId, path, offset = 0, nocache = false) {
|
||||
renderBrowserItems(cachedItems);
|
||||
renderPagination();
|
||||
|
||||
// Show search bar when inside a folder
|
||||
showBrowserSearch(true);
|
||||
|
||||
// Show/hide Play All button based on whether media items exist
|
||||
const hasMedia = data.items.some(item => item.is_media);
|
||||
document.getElementById('playAllBtn').style.display = hasMedia ? '' : 'none';
|
||||
@@ -2072,6 +2084,54 @@ function refreshBrowser() {
|
||||
}
|
||||
}
|
||||
|
||||
// Browser search
|
||||
function onBrowserSearch() {
|
||||
const input = document.getElementById('browserSearchInput');
|
||||
const clearBtn = document.getElementById('browserSearchClear');
|
||||
const term = input.value.trim();
|
||||
|
||||
clearBtn.style.display = term ? 'flex' : 'none';
|
||||
|
||||
// Debounce: wait 200ms after typing stops
|
||||
if (browserSearchTimer) clearTimeout(browserSearchTimer);
|
||||
browserSearchTimer = setTimeout(() => {
|
||||
browserSearchTerm = term.toLowerCase();
|
||||
applyBrowserSearch();
|
||||
}, 200);
|
||||
}
|
||||
|
||||
function clearBrowserSearch() {
|
||||
const input = document.getElementById('browserSearchInput');
|
||||
input.value = '';
|
||||
document.getElementById('browserSearchClear').style.display = 'none';
|
||||
browserSearchTerm = '';
|
||||
applyBrowserSearch();
|
||||
input.focus();
|
||||
}
|
||||
|
||||
function applyBrowserSearch() {
|
||||
if (!cachedItems) return;
|
||||
|
||||
if (!browserSearchTerm) {
|
||||
renderBrowserItems(cachedItems);
|
||||
return;
|
||||
}
|
||||
|
||||
const filtered = cachedItems.filter(item =>
|
||||
item.name.toLowerCase().includes(browserSearchTerm)
|
||||
);
|
||||
renderBrowserItems(filtered);
|
||||
}
|
||||
|
||||
function showBrowserSearch(visible) {
|
||||
document.getElementById('browserSearchWrapper').style.display = visible ? '' : 'none';
|
||||
if (!visible) {
|
||||
document.getElementById('browserSearchInput').value = '';
|
||||
document.getElementById('browserSearchClear').style.display = 'none';
|
||||
browserSearchTerm = '';
|
||||
}
|
||||
}
|
||||
|
||||
function setViewMode(mode) {
|
||||
if (mode === viewMode) return;
|
||||
viewMode = mode;
|
||||
@@ -2084,7 +2144,7 @@ function setViewMode(mode) {
|
||||
|
||||
// Re-render current view from cache (no network request)
|
||||
if (currentFolderId && cachedItems) {
|
||||
renderBrowserItems(cachedItems);
|
||||
applyBrowserSearch();
|
||||
} else {
|
||||
showRootFolders();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user