diff --git a/zddc/internal/apps/embedded/archive.html b/zddc/internal/apps/embedded/archive.html index 36493dd..6009207 100644 --- a/zddc/internal/apps/embedded/archive.html +++ b/zddc/internal/apps/embedded/archive.html @@ -2245,7 +2245,7 @@ td[data-field="trackingNumber"] {
ZDDC Archive - v0.0.17-beta · 2026-05-10 · lily-quilt-hazel + v0.0.17-beta · 2026-05-10 · rock-cliff-boat
diff --git a/zddc/internal/apps/embedded/browse.html b/zddc/internal/apps/embedded/browse.html index 267f009..5e914b6 100644 --- a/zddc/internal/apps/embedded/browse.html +++ b/zddc/internal/apps/embedded/browse.html @@ -791,58 +791,6 @@ body { white-space: nowrap; } -/* Auto-filter rows in . Two rows — one targets file rows - (📄 icon, with file-name + ext inputs), one targets folder rows - (📁 icon, with folder-name input). The icons make it visually - obvious which row controls which kind of filter. The rows are - non-sticky (only the sortable header row sticks) — keeps the - stack-positioning math out of the picture and accepts that - filters scroll out of view on long lists. */ -.browse-table thead .filter-row th { - position: static; - padding: 0.25rem 0.6rem; - background: var(--bg-secondary); - border-bottom: 1px solid var(--border); - cursor: default; - font-weight: normal; - z-index: 0; -} - -.browse-table thead .filter-row th:hover { - background: var(--bg-secondary); -} - -.filter-row__icon { - display: inline-block; - width: 1.2rem; - text-align: center; - margin-right: 0.3rem; - vertical-align: middle; - font-size: 0.95rem; - color: var(--text-muted); -} - -.column-filter { - width: calc(100% - 1.5rem); - padding: 0.2rem 0.4rem; - border: 1px solid var(--border); - border-radius: 3px; - background: var(--bg); - color: var(--text); - font-size: 0.8rem; - font-family: Consolas, Monaco, monospace; - box-sizing: border-box; -} - -.filter-row th.col-name .column-filter { - width: calc(100% - 1.7rem); /* leave space for the icon */ -} - -.column-filter:focus { - outline: 1px solid var(--primary); - outline-offset: -1px; -} - /* Table — folders + files in a tree */ .browse-table { @@ -999,7 +947,7 @@ body {
ZDDC Browse - v0.0.17-beta · 2026-05-10 · lily-quilt-hazel + v0.0.17-beta · 2026-05-10 · rock-cliff-boat
@@ -1024,10 +972,7 @@ body {

Once loaded: click a folder to expand it, shift-click to expand its entire subtree (or collapse it again), - click column headers to sort. Use the 📄 row to filter files - (and the 📁 row to scope to matching folders) — file matches - stay visible together with their containing folders. - Click any file to open it.

+ click column headers to sort. Click any file to open it.

@@ -1045,32 +990,6 @@ body { Type Modified - - - - - - - - - - - - - - - - - - - - @@ -1122,36 +1041,6 @@ body { local (re-enumerates the FS handle) and online (re-fetches the JSON). -

Filter rows

-

Two filter rows live in the table header:

-
-
📄 file row
-
Filter by file name (left input) and/or extension (Type input). - File matches stay visible together with their ancestor folders, so - the path to each hit is always shown.
-
📁 folder row
-
Filter by folder name. Matching folders show with their entire - subtree. Combined with file filter: file must also be inside a - matching folder's subtree (intersection).
-
-

Filter syntax (shared across all ZDDC tools):

-
-
term
-
Contains "term" (case-insensitive)
-
!term
-
Does not contain
-
^term
-
Starts with
-
term$
-
Ends with
-
a b
-
Both (AND)
-
a | b
-
Either (OR)
-
el.*spc
-
Regex — any-char + any-sequence
-
-

Header buttons

Add Local Directory
@@ -2634,15 +2523,6 @@ https://github.com/nodeca/pako/blob/main/LICENSE // Sort state. key: 'name' | 'size' | 'ext' | 'date'. dir: 1 or -1. sort: { key: 'name', dir: 1 }, - // Auto-filter row state. Each is a raw string from the input, - // plus a parsed AST (zddc.filter.parse) cached on every keystroke. - // Empty raw → AST empty → matches everything. - filters: { - file: { raw: '', ast: null }, // matches against file basename - folder: { raw: '', ast: null }, // matches against folder basename - ext: { raw: '', ast: null } // matches against file extension - }, - // The tree's in-memory representation. Each node: // { id, name, isDir, size, modTime, ext, url, depth, // parentId, expanded, loaded, childIds, isZip, zipFile, @@ -2925,17 +2805,14 @@ https://github.com/nodeca/pako/blob/main/LICENSE parent.loaded = true; } - // Walk visible nodes in render order. Excludes nodes whose - // node.visible is false (filter-hidden) and skips the children of - // a collapsed expandable. Filter visibility is computed by - // recomputeVisibility() before this is called from render(). + // Walk nodes in render order. Skips the children of a collapsed + // expandable. function visibleIds() { var out = []; function walk(ids) { for (var i = 0; i < ids.length; i++) { var n = state.nodes.get(ids[i]); if (!n) continue; - if (n.visible === false) continue; out.push(ids[i]); if ((n.isDir || n.isZip) && n.expanded) walk(n.childIds); } @@ -3015,7 +2892,6 @@ https://github.com/nodeca/pako/blob/main/LICENSE function render() { var tbody = document.getElementById('browseTbody'); if (!tbody) return; - recomputeVisibility(); var ids = visibleIds(); var html = ''; for (var i = 0; i < ids.length; i++) { @@ -3027,111 +2903,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE renderBreadcrumbs(); } - // Compute model-level visibility per node based on the three - // filter ASTs: - // - fileFilter → matches a file's basename - // - folderFilter→ matches a folder's basename - // - extFilter → matches a file's extension (no leading dot) - // - // Visibility rules: - // 1. A FILE is "self-matched" when it passes both file+ext filter. - // 2. A FOLDER is "self-matched" when it passes the folder filter. - // 3. A file is "in-scope" when either no folder filter is active, - // OR at least one ancestor folder is folder-self-matched. - // 4. A file is VISIBLE when self-matched AND in-scope. - // 5. A folder is VISIBLE when: - // - any descendant is visible (so the path to a hit is - // always shown), OR - // - the folder itself is folder-self-matched AND no file - // filter is active (when a file filter is set, we hide - // folders that have no matching files inside — keeps - // the result list focused). - // - // Pure model walk; the renderer just consumes node.visible. Hidden - // expandable nodes get their `expanded` flag respected even though - // they're not in the DOM, so toggling filters preserves the user's - // expand state. - function recomputeVisibility() { - var fileAst = state.filters.file.ast; - var folderAst = state.filters.folder.ast; - var extAst = state.filters.ext.ast; - var hasFile = !!(state.filters.file.raw); - var hasFolder = !!(state.filters.folder.raw); - var hasExt = !!(state.filters.ext.raw); - var anyActive = hasFile || hasFolder || hasExt; - - // Fast path: nothing filtered → everything visible. - if (!anyActive) { - state.nodes.forEach(function (n) { n.visible = true; }); - return; - } - - var f = window.zddc && window.zddc.filter; - - // Walk top-down to propagate folder scope, then bottom-up to - // propagate descendant visibility. Done in one DFS recursion. - // ZIPs are hybrids — they match FILE filter (their name is a - // filename) AND can be matched by FOLDER filter (they're - // container-like — clicking expands them like a folder). - function visit(nodeId, ancestorMatchesFolder) { - var n = state.nodes.get(nodeId); - if (!n) return false; - - if (!(n.isDir || n.isZip)) { - // Plain file. Visible iff its name+ext pass file/ext - // filters AND it's inside the folder-filter scope. - var nameOk = f.matches(n.name, fileAst); - var extOk = f.matches(n.ext || '', extAst); - n.visible = nameOk && extOk && ancestorMatchesFolder; - return n.visible; - } - - // Folder or zip — has childIds and contributes to scope. - // Folder self-match: the folder/zip name passes folder - // filter. A folder match also opens the file-filter scope - // for descendants. - var asFolderMatch = f.matches(n.name, folderAst); - // A zip can also match the FILE filter (it's a file too). - // Typing a zip name into file filter surfaces the zip. - // Gate on hasFile||hasExt — when neither is active, the - // empty filter matches every name and would falsely - // surface every zip regardless of the active folder filter. - var asFileMatch = n.isZip - && (hasFile || hasExt) - && f.matches(n.name, fileAst) - && f.matches(n.ext || '', extAst); - - var nextAncestorScope = ancestorMatchesFolder - || asFolderMatch || asFileMatch; - - var anyChildVisible = false; - for (var i = 0; i < n.childIds.length; i++) { - if (visit(n.childIds[i], nextAncestorScope)) anyChildVisible = true; - } - - // Visible if: - // - any descendant is visible (path-to-hit visibility), or - // - self-folder-match with no file/ext filter active - // (let the folder surface even if it's empty/unloaded), or - // - self-file-match (for zips, where the user is searching - // for the archive by name in the file filter). - n.visible = anyChildVisible - || (asFolderMatch && !hasFile && !hasExt) - || asFileMatch; - return n.visible; - } - - // Initial ancestor scope = folder filter empty (so files don't - // require ancestor matches when there's no folder filter). - var initialScope = !hasFolder; - for (var i = 0; i < state.rootIds.length; i++) { - visit(state.rootIds[i], initialScope); - } - } - - // Count nodes that would render if no filter were active - // (i.e. anything at the root, or under an expanded ancestor). - // Used to express " of shown" while a filter is on. + // Count nodes that render at the root + every expanded subtree. function expandedSetSize() { var n = 0; function walk(ids) { @@ -3150,14 +2922,8 @@ https://github.com/nodeca/pako/blob/main/LICENSE function updateCount() { var el = document.getElementById('entryCount'); if (!el) return; - var visible = visibleIds().length; var total = expandedSetSize(); - var anyFilter = state.filters.file.raw - || state.filters.folder.raw - || state.filters.ext.raw; - el.textContent = anyFilter - ? visible + ' of ' + total + ' shown' - : total + ' item' + (total === 1 ? '' : 's'); + el.textContent = total + ' item' + (total === 1 ? '' : 's'); } // ── Breadcrumbs ────────────────────────────────────────────────────── @@ -3470,17 +3236,6 @@ https://github.com/nodeca/pako/blob/main/LICENSE } render(); }, - // Update one of the three column filters and re-render. `which` - // is 'file' | 'folder' | 'ext'. Empty raw → AST cleared. - setFilter: function (which, raw) { - var slot = state.filters[which]; - if (!slot) return; - slot.raw = raw || ''; - slot.ast = slot.raw && window.zddc && window.zddc.filter - ? window.zddc.filter.parse(slot.raw) - : null; - render(); - }, pathFor: pathFor }; })(); @@ -3849,19 +3604,6 @@ https://github.com/nodeca/pako/blob/main/LICENSE var refresh = document.getElementById('refreshHeaderBtn'); if (refresh) refresh.addEventListener('click', refreshListing); - // Auto-filter row inputs. There are three of them (file, folder, - // ext) — wire each by its `data-filter` attribute. Idempotent - // re: re-init. - var filterInputs = document.querySelectorAll('input.column-filter[data-filter]'); - for (var fi = 0; fi < filterInputs.length; fi++) { - (function (input) { - var which = input.dataset.filter; - input.addEventListener('input', function () { - tree.setFilter(which, input.value); - }); - })(filterInputs[fi]); - } - // Sort headers var ths = document.querySelectorAll('#browseTable thead th.sortable'); for (var i = 0; i < ths.length; i++) { diff --git a/zddc/internal/apps/embedded/classifier.html b/zddc/internal/apps/embedded/classifier.html index 580712e..1a84641 100644 --- a/zddc/internal/apps/embedded/classifier.html +++ b/zddc/internal/apps/embedded/classifier.html @@ -1464,7 +1464,7 @@ body.help-open .app-header {
ZDDC Classifier - v0.0.17-beta · 2026-05-10 · lily-quilt-hazel + v0.0.17-beta · 2026-05-10 · rock-cliff-boat
diff --git a/zddc/internal/apps/embedded/index.html b/zddc/internal/apps/embedded/index.html index f541ded..352add9 100644 --- a/zddc/internal/apps/embedded/index.html +++ b/zddc/internal/apps/embedded/index.html @@ -988,7 +988,7 @@ body {
ZDDC - v0.0.17-beta · 2026-05-10 · lily-quilt-hazel + v0.0.17-beta · 2026-05-10 · rock-cliff-boat
diff --git a/zddc/internal/apps/embedded/mdedit.html b/zddc/internal/apps/embedded/mdedit.html index c954574..3fcff20 100644 --- a/zddc/internal/apps/embedded/mdedit.html +++ b/zddc/internal/apps/embedded/mdedit.html @@ -1903,7 +1903,7 @@ body.help-open .app-header {
ZDDC Markdown - v0.0.17-beta · 2026-05-10 · lily-quilt-hazel + v0.0.17-beta · 2026-05-10 · rock-cliff-boat
diff --git a/zddc/internal/apps/embedded/transmittal.html b/zddc/internal/apps/embedded/transmittal.html index 2abf87e..80f0f46 100644 --- a/zddc/internal/apps/embedded/transmittal.html +++ b/zddc/internal/apps/embedded/transmittal.html @@ -2263,7 +2263,7 @@ dialog.modal--narrow {
ZDDC Transmittal - v0.0.17-beta · 2026-05-10 · lily-quilt-hazel + v0.0.17-beta · 2026-05-10 · rock-cliff-boat
JavaScript not available