feat(browse): generalize the in-pane tool embed to fold classifier/transmittal/archive
grid.js was classifier-only; make it embed ANY embeddable full-page tool the
cascade resolves as default_tool — classifier (incoming/), transmittal
(staging/), archive (the index) — as an iframe scoped to the current dir
(<dir>/<tool>.html). This is the browse-as-shell bridge from the ADR: browse
stays the top-level app and the heavy tools open in-pane (the gridView), so
navigating to staging/ or archive/ inside browse shows transmittal/archive
without leaving the shell, with ?view=browse falling back to the folder
listing (and the standalone tools still served directly at the no-slash URL).
EMBEDDABLE = {classifier, transmittal, archive}; tables/forms embed in the
preview pane instead, landing/browse don't self-embed. resolveViewMode keys
off grid.availableHere() (now generic). Validated in a containerized browser:
each dir embeds its tool, ?view=browse overrides to the listing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d183de434d
commit
1b9fec66b3
2 changed files with 42 additions and 33 deletions
|
|
@ -1121,11 +1121,12 @@
|
||||||
|
|
||||||
// View mode is URL-driven, not UI-driven.
|
// View mode is URL-driven, not UI-driven.
|
||||||
//
|
//
|
||||||
// ?view=grid → grid mode (only honored where classifier is
|
// ?view=grid → embedded-tool view (only honored where the cascade's
|
||||||
// available; otherwise falls back to browse)
|
// default_tool is an embeddable full-page tool —
|
||||||
// ?view=browse → browse mode (always)
|
// classifier/transmittal/archive; else falls back to browse)
|
||||||
// default → path-based: grid when inside an incoming/
|
// ?view=browse → browse listing (always)
|
||||||
// subtree, browse everywhere else
|
// default → embedded-tool view when the dir's default_tool is one
|
||||||
|
// of those tools, browse listing everywhere else
|
||||||
//
|
//
|
||||||
// resolveViewMode reads the current location and returns the mode
|
// resolveViewMode reads the current location and returns the mode
|
||||||
// to render; applyResolvedViewMode toggles the panes accordingly.
|
// to render; applyResolvedViewMode toggles the panes accordingly.
|
||||||
|
|
@ -1134,10 +1135,10 @@
|
||||||
var qs = new URLSearchParams(window.location.search);
|
var qs = new URLSearchParams(window.location.search);
|
||||||
var explicit = (qs.get('view') || '').toLowerCase();
|
var explicit = (qs.get('view') || '').toLowerCase();
|
||||||
var grid = window.app.modules.grid;
|
var grid = window.app.modules.grid;
|
||||||
var classifierHere = !!(grid && grid.availableHere && grid.availableHere());
|
var toolHere = !!(grid && grid.availableHere && grid.availableHere());
|
||||||
if (explicit === 'grid') return classifierHere ? 'grid' : 'browse';
|
if (explicit === 'grid') return toolHere ? 'grid' : 'browse';
|
||||||
if (explicit === 'browse') return 'browse';
|
if (explicit === 'browse') return 'browse';
|
||||||
return classifierHere ? 'grid' : 'browse';
|
return toolHere ? 'grid' : 'browse';
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyResolvedViewMode() {
|
function applyResolvedViewMode() {
|
||||||
|
|
|
||||||
|
|
@ -1,48 +1,53 @@
|
||||||
// grid.js — "Grid mode" plugin for browse. Loads the classifier tool
|
// grid.js — in-pane tool embed for browse (the browse-as-shell bridge; see
|
||||||
// as an iframe scoped to the current directory so users get classifier's
|
// ARCHITECTURE.md's ADR). Loads a heavy, full-page tool as an iframe scoped to
|
||||||
// full bulk-rename workflow without leaving browse.
|
// the current directory so the user gets that tool's full workflow without
|
||||||
|
// leaving the browse shell. browse stays the top-level app; the cascade's
|
||||||
|
// default_tool decides which tool embeds here.
|
||||||
//
|
//
|
||||||
// Availability: the cascade decides. Grid auto-activates wherever the
|
// Availability: the cascade decides — `state.scopeDefaultTool` (the
|
||||||
// .zddc cascade resolves default_tool=classifier (defaults.zddc.yaml
|
// X-ZDDC-Default-Tool header) must name one of the EMBEDDABLE full-page tools:
|
||||||
// declares this for archive/<party>/incoming/). Operators can extend
|
// classifier (archive/<party>/incoming/), transmittal (…/staging/), archive
|
||||||
// — e.g. setting default_tool=classifier on a custom dir activates
|
// (the archive index). tables/forms embed in the preview pane instead
|
||||||
// grid mode there too — without touching this code.
|
// (table-leaf / form view); landing/browse don't self-embed. Operators extend
|
||||||
//
|
// by setting default_tool on a dir — no code change. Iframe src:
|
||||||
// Iframe src resolution: <currentDirURL>/classifier.html. Iframe
|
// <currentDirURL>/<tool>.html. Server mode only (file:// has no server).
|
||||||
// embedding only works in server mode; file:// pages don't get the
|
|
||||||
// Grid toggle.
|
|
||||||
(function () {
|
(function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var state = window.app.state;
|
var state = window.app.state;
|
||||||
var mounted = false;
|
var mounted = false;
|
||||||
|
|
||||||
function classifierAvailableHere() {
|
// Full-page tools that embed in the gridView pane when they're the dir's
|
||||||
// state.scopeDefaultTool is set by the loader from the
|
// default_tool. (tables/form embed in the preview pane; landing/browse are
|
||||||
// X-ZDDC-Default-Tool response header on every listing fetch.
|
// not in-pane embeds.)
|
||||||
// Grid mode is meaningful exactly where the cascade picks
|
var EMBEDDABLE = { classifier: 1, transmittal: 1, archive: 1 };
|
||||||
// classifier as the default — no client-side path matching.
|
|
||||||
return state.scopeDefaultTool === 'classifier';
|
// The cascade-resolved default tool for the current dir when it's an
|
||||||
|
// embeddable full-page tool; "" otherwise.
|
||||||
|
function embedToolHere() {
|
||||||
|
var t = state.scopeDefaultTool;
|
||||||
|
return (t && EMBEDDABLE[t]) ? t : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function activate() {
|
function activate() {
|
||||||
var host = document.getElementById('gridView');
|
var host = document.getElementById('gridView');
|
||||||
if (!host) return;
|
if (!host) return;
|
||||||
if (mounted) return;
|
if (mounted) return;
|
||||||
if (state.source !== 'server' || !classifierAvailableHere()) return;
|
var tool = embedToolHere();
|
||||||
|
if (state.source !== 'server' || !tool) return;
|
||||||
|
|
||||||
// Compute the iframe src: current page's directory + classifier.html.
|
// Compute the iframe src: current page's directory + <tool>.html.
|
||||||
var pathname = window.location.pathname || '/';
|
var pathname = window.location.pathname || '/';
|
||||||
if (!pathname.endsWith('/')) {
|
if (!pathname.endsWith('/')) {
|
||||||
var lastSlash = pathname.lastIndexOf('/');
|
var lastSlash = pathname.lastIndexOf('/');
|
||||||
pathname = lastSlash >= 0 ? pathname.substring(0, lastSlash + 1) : '/';
|
pathname = lastSlash >= 0 ? pathname.substring(0, lastSlash + 1) : '/';
|
||||||
}
|
}
|
||||||
var src = pathname + 'classifier.html';
|
var src = pathname + tool + '.html';
|
||||||
|
|
||||||
host.innerHTML = '';
|
host.innerHTML = '';
|
||||||
var frame = document.createElement('iframe');
|
var frame = document.createElement('iframe');
|
||||||
frame.src = src;
|
frame.src = src;
|
||||||
frame.title = 'ZDDC Classifier (Grid mode)';
|
frame.title = 'ZDDC ' + tool;
|
||||||
frame.style.cssText = 'width:100%;height:100%;border:0;display:block;'
|
frame.style.cssText = 'width:100%;height:100%;border:0;display:block;'
|
||||||
+ 'background:var(--bg);';
|
+ 'background:var(--bg);';
|
||||||
host.appendChild(frame);
|
host.appendChild(frame);
|
||||||
|
|
@ -61,9 +66,12 @@
|
||||||
window.app.modules.grid = {
|
window.app.modules.grid = {
|
||||||
activate: activate,
|
activate: activate,
|
||||||
reset: reset,
|
reset: reset,
|
||||||
// Hook for events.js to show/hide the Grid toggle button.
|
// Hook for events.js's view-mode resolution: is an embeddable tool the
|
||||||
|
// default here?
|
||||||
availableHere: function () {
|
availableHere: function () {
|
||||||
return state.source === 'server' && classifierAvailableHere();
|
return state.source === 'server' && !!embedToolHere();
|
||||||
}
|
},
|
||||||
|
// The embeddable tool name (or "") — lets the shell label the view.
|
||||||
|
toolHere: embedToolHere
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue