chore(embedded): cut v0.0.16-beta
All checks were successful
Notify chart dev on beta cut / notify-chart-dev (push) Successful in 4s
All checks were successful
Notify chart dev on beta cut / notify-chart-dev (push) Successful in 4s
Bake the standardized headers + archive bugfix + browse refactor into the dev binary. Triggers notify-chart-dev → bumps tnd-zddc-chart develop with appVersion=0.0.16-beta-<sha>.
This commit is contained in:
parent
e67c1b2e06
commit
633411770c
9 changed files with 577 additions and 134 deletions
69
mdedit/dist/mdedit.html
vendored
69
mdedit/dist/mdedit.html
vendored
|
|
@ -438,6 +438,24 @@ a:hover {
|
||||||
background: var(--bg-secondary);
|
background: var(--bg-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Subdued / de-emphasized variant.
|
||||||
|
Used on the "Add Local Directory" button when a tool is operating
|
||||||
|
in server (online) mode — the local-dir affordance is still
|
||||||
|
available but visually quieter, since the typical user already
|
||||||
|
has the directory loaded from the server. */
|
||||||
|
.btn.btn--subtle {
|
||||||
|
background: transparent;
|
||||||
|
color: var(--text-muted);
|
||||||
|
border-color: var(--border);
|
||||||
|
box-shadow: none;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn.btn--subtle:not(:disabled):hover {
|
||||||
|
color: var(--text);
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
.btn-success {
|
.btn-success {
|
||||||
background: var(--success);
|
background: var(--success);
|
||||||
color: var(--text-light);
|
color: var(--text-light);
|
||||||
|
|
@ -1774,9 +1792,10 @@ body.help-open .app-header {
|
||||||
</svg>
|
</svg>
|
||||||
<div class="header-title-group">
|
<div class="header-title-group">
|
||||||
<span class="app-header__title">ZDDC Markdown</span>
|
<span class="app-header__title">ZDDC Markdown</span>
|
||||||
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.16-beta · 2026-05-04 · 582db6d</span></span>
|
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.16-beta · 2026-05-04 · e67c1b2</span></span>
|
||||||
</div>
|
</div>
|
||||||
<button id="select-directory" class="btn btn-primary" title="Select a Directory">Select Directory</button>
|
<button id="addDirectoryBtn" class="btn btn-primary" title="Add a local directory">Add Local Directory</button>
|
||||||
|
<button id="refreshHeaderBtn" class="btn btn-secondary hidden" title="Refresh directory" aria-label="Refresh" style="font-size:1.1rem;">⟳</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<button id="theme-btn" class="btn btn-secondary" title="Theme: auto (follows OS)" aria-label="Theme: auto (follows OS)">◐</button>
|
<button id="theme-btn" class="btn btn-secondary" title="Theme: auto (follows OS)" aria-label="Theme: auto (follows OS)">◐</button>
|
||||||
|
|
@ -1792,7 +1811,6 @@ body.help-open .app-header {
|
||||||
<span>Files</span>
|
<span>Files</span>
|
||||||
<div class="flex items-center gap-1">
|
<div class="flex items-center gap-1">
|
||||||
<button id="new-file-root" class="btn btn-secondary btn-sm hidden" title="New file in root directory">+</button>
|
<button id="new-file-root" class="btn btn-secondary btn-sm hidden" title="New file in root directory">+</button>
|
||||||
<button id="refresh-directory" class="btn btn-secondary btn-sm hidden" title="Refresh directory">↻</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1806,7 +1824,7 @@ body.help-open .app-header {
|
||||||
|
|
||||||
<div class="pane content-pane flex-1 relative flex flex-col bg-white dark:bg-gray-900 overflow-hidden" id="main-content">
|
<div class="pane content-pane flex-1 relative flex flex-col bg-white dark:bg-gray-900 overflow-hidden" id="main-content">
|
||||||
<div id="welcome-screen" class="welcome-screen hidden flex-col items-center justify-center h-full text-gray-500 dark:text-gray-400 text-center p-6">
|
<div id="welcome-screen" class="welcome-screen hidden flex-col items-center justify-center h-full text-gray-500 dark:text-gray-400 text-center p-6">
|
||||||
<p id="welcome-hint" class="text-sm">Click <strong>Scratchpad</strong> in the file list to start editing,<br>or <strong>Select Directory</strong> to work with files.</p>
|
<p id="welcome-hint" class="text-sm">Click <strong>Scratchpad</strong> in the file list to start editing,<br>or <strong>Add Local Directory</strong> to work with files.</p>
|
||||||
<p id="welcome-firefox" class="text-sm text-amber-600 hidden mt-2">Your browser doesn't support the File System API.<br>Use <strong>Scratchpad</strong> to edit markdown and download as a file.</p>
|
<p id="welcome-firefox" class="text-sm text-amber-600 hidden mt-2">Your browser doesn't support the File System API.<br>Use <strong>Scratchpad</strong> to edit markdown and download as a file.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -1850,7 +1868,7 @@ body.help-open .app-header {
|
||||||
|
|
||||||
<h3>Getting Started</h3>
|
<h3>Getting Started</h3>
|
||||||
<ol>
|
<ol>
|
||||||
<li>Click <strong>Select Directory</strong> to open a folder. The file tree on the left will populate with all files in that folder.</li>
|
<li>Click <strong>Add Local Directory</strong> to open a folder. The file tree on the left will populate with all files in that folder.</li>
|
||||||
<li>Click any Markdown file (<code>.md</code>) in the tree to open it in the editor.</li>
|
<li>Click any Markdown file (<code>.md</code>) in the tree to open it in the editor.</li>
|
||||||
<li>Use the <strong>Scratchpad</strong> entry (always visible at the top of the tree) for temporary notes without saving to disk.</li>
|
<li>Use the <strong>Scratchpad</strong> entry (always visible at the top of the tree) for temporary notes without saving to disk.</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
@ -2954,7 +2972,7 @@ const SCRATCHPAD_WELCOME = [
|
||||||
'Use this **Scratchpad** for quick notes. Download it any time with the ⬇',
|
'Use this **Scratchpad** for quick notes. Download it any time with the ⬇',
|
||||||
'button on the Scratchpad row in the file list.',
|
'button on the Scratchpad row in the file list.',
|
||||||
'',
|
'',
|
||||||
'Click **Select Directory** above to open a folder of Markdown files,',
|
'Click **Add Local Directory** above to open a folder of Markdown files,',
|
||||||
'or just start typing here.',
|
'or just start typing here.',
|
||||||
'',
|
'',
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
@ -3754,12 +3772,19 @@ async function openDirectory() {
|
||||||
* @param {string} directoryName - Name of the selected directory
|
* @param {string} directoryName - Name of the selected directory
|
||||||
*/
|
*/
|
||||||
function updateDirectoryStatus(directoryName) {
|
function updateDirectoryStatus(directoryName) {
|
||||||
const selectDirectoryBtn = document.getElementById('select-directory');
|
// Standardized header pattern (across all ZDDC tools): the button
|
||||||
|
// keeps the label "Add Local Directory"; de-emphasize it once a
|
||||||
|
// directory is loaded (the user can still click to pick another)
|
||||||
|
// by applying the shared btn--subtle variant. The directory name
|
||||||
|
// is shown in the file-nav pane, not on the button.
|
||||||
|
const selectDirectoryBtn = document.getElementById('addDirectoryBtn');
|
||||||
if (selectDirectoryBtn) {
|
if (selectDirectoryBtn) {
|
||||||
selectDirectoryBtn.textContent = `Directory: ${directoryName}`;
|
selectDirectoryBtn.classList.remove('btn-primary');
|
||||||
|
selectDirectoryBtn.classList.add('btn--subtle');
|
||||||
|
selectDirectoryBtn.title = `Loaded: ${directoryName} — click to switch`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const refreshBtn = document.getElementById('refresh-directory');
|
const refreshBtn = document.getElementById('refreshHeaderBtn');
|
||||||
if (refreshBtn) {
|
if (refreshBtn) {
|
||||||
refreshBtn.classList.remove('hidden');
|
refreshBtn.classList.remove('hidden');
|
||||||
}
|
}
|
||||||
|
|
@ -4260,8 +4285,8 @@ async function loadServerDirectory() {
|
||||||
|
|
||||||
// Only enter server-source mode if the host actually serves JSON directory
|
// Only enter server-source mode if the host actually serves JSON directory
|
||||||
// listings (zddc-server / Caddy). On a plain static host the probe fails
|
// listings (zddc-server / Caddy). On a plain static host the probe fails
|
||||||
// and we must leave "Select Directory" visible so the user can still load
|
// and we must leave "Add Local Directory" visible so the user can still
|
||||||
// local files.
|
// load local files.
|
||||||
try {
|
try {
|
||||||
const resp = await fetch(baseUrl, { headers: { 'Accept': 'application/json' }, cache: 'no-cache' });
|
const resp = await fetch(baseUrl, { headers: { 'Accept': 'application/json' }, cache: 'no-cache' });
|
||||||
if (!resp.ok) return;
|
if (!resp.ok) return;
|
||||||
|
|
@ -4286,12 +4311,18 @@ async function loadServerDirectory() {
|
||||||
entries: {},
|
entries: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Surface refresh, hide write-only controls. "Select Directory" stays
|
// Surface refresh, hide write-only controls. "Add Local Directory"
|
||||||
// visible so the user can switch to a local folder at any time.
|
// stays visible (de-emphasized via btn--subtle) so the user can
|
||||||
const refreshBtn = document.getElementById('refresh-directory');
|
// switch to a local folder at any time.
|
||||||
|
const refreshBtn = document.getElementById('refreshHeaderBtn');
|
||||||
if (refreshBtn) refreshBtn.classList.remove('hidden');
|
if (refreshBtn) refreshBtn.classList.remove('hidden');
|
||||||
const newFileRootBtn = document.getElementById('new-file-root');
|
const newFileRootBtn = document.getElementById('new-file-root');
|
||||||
if (newFileRootBtn) newFileRootBtn.classList.add('hidden');
|
if (newFileRootBtn) newFileRootBtn.classList.add('hidden');
|
||||||
|
const addDirBtn = document.getElementById('addDirectoryBtn');
|
||||||
|
if (addDirBtn) {
|
||||||
|
addDirBtn.classList.remove('btn-primary');
|
||||||
|
addDirBtn.classList.add('btn--subtle');
|
||||||
|
}
|
||||||
|
|
||||||
const stats = await readServerDirectory(baseUrl, fileTree, 0);
|
const stats = await readServerDirectory(baseUrl, fileTree, 0);
|
||||||
renderFileTree();
|
renderFileTree();
|
||||||
|
|
@ -6028,14 +6059,14 @@ function initializeFileNavResizer() {
|
||||||
* Set up all event listeners for the application
|
* Set up all event listeners for the application
|
||||||
*/
|
*/
|
||||||
function setupEventListeners() {
|
function setupEventListeners() {
|
||||||
// Select directory button
|
// Add Local Directory button (was id="select-directory" / "refresh-directory")
|
||||||
const selectDirectoryBtn = document.getElementById('select-directory');
|
const selectDirectoryBtn = document.getElementById('addDirectoryBtn');
|
||||||
if (selectDirectoryBtn) {
|
if (selectDirectoryBtn) {
|
||||||
selectDirectoryBtn.addEventListener('click', openDirectory);
|
selectDirectoryBtn.addEventListener('click', openDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh directory button
|
// Refresh button (now in header, was in file-nav pane)
|
||||||
const refreshDirectoryBtn = document.getElementById('refresh-directory');
|
const refreshDirectoryBtn = document.getElementById('refreshHeaderBtn');
|
||||||
if (refreshDirectoryBtn) {
|
if (refreshDirectoryBtn) {
|
||||||
refreshDirectoryBtn.addEventListener('click', refreshDirectory);
|
refreshDirectoryBtn.addEventListener('click', refreshDirectory);
|
||||||
}
|
}
|
||||||
|
|
@ -6136,7 +6167,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||||
* Initialize UI based on File System API availability
|
* Initialize UI based on File System API availability
|
||||||
*/
|
*/
|
||||||
function initializeApiAvailability() {
|
function initializeApiAvailability() {
|
||||||
const selectDirectoryBtn = document.getElementById('select-directory');
|
const selectDirectoryBtn = document.getElementById('addDirectoryBtn');
|
||||||
const welcomeHint = document.getElementById('welcome-hint');
|
const welcomeHint = document.getElementById('welcome-hint');
|
||||||
const welcomeFirefox = document.getElementById('welcome-firefox');
|
const welcomeFirefox = document.getElementById('welcome-firefox');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -218,6 +218,24 @@ a:hover {
|
||||||
background: var(--bg-secondary);
|
background: var(--bg-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Subdued / de-emphasized variant.
|
||||||
|
Used on the "Add Local Directory" button when a tool is operating
|
||||||
|
in server (online) mode — the local-dir affordance is still
|
||||||
|
available but visually quieter, since the typical user already
|
||||||
|
has the directory loaded from the server. */
|
||||||
|
.btn.btn--subtle {
|
||||||
|
background: transparent;
|
||||||
|
color: var(--text-muted);
|
||||||
|
border-color: var(--border);
|
||||||
|
box-shadow: none;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn.btn--subtle:not(:disabled):hover {
|
||||||
|
color: var(--text);
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
.btn-success {
|
.btn-success {
|
||||||
background: var(--success);
|
background: var(--success);
|
||||||
color: var(--text-light);
|
color: var(--text-light);
|
||||||
|
|
@ -2113,7 +2131,7 @@ td[data-field="trackingNumber"] {
|
||||||
</svg>
|
</svg>
|
||||||
<div class="header-title-group">
|
<div class="header-title-group">
|
||||||
<span class="app-header__title">ZDDC Archive</span>
|
<span class="app-header__title">ZDDC Archive</span>
|
||||||
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.16-beta · 2026-05-04 · 582db6d</span></span>
|
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.16-beta · 2026-05-04 · e67c1b2</span></span>
|
||||||
</div>
|
</div>
|
||||||
<button id="addDirectoryBtn" class="btn btn-primary">Add Local Directory</button>
|
<button id="addDirectoryBtn" class="btn btn-primary">Add Local Directory</button>
|
||||||
<button id="refreshHeaderBtn" class="btn btn-secondary hidden" title="Refresh Data" style="font-size:1.1rem;">⟳</button>
|
<button id="refreshHeaderBtn" class="btn btn-secondary hidden" title="Refresh Data" style="font-size:1.1rem;">⟳</button>
|
||||||
|
|
@ -4444,8 +4462,10 @@ td[data-field="trackingNumber"] {
|
||||||
// Handle drops on grouping folders (for creating transmittals)
|
// Handle drops on grouping folders (for creating transmittals)
|
||||||
document.getElementById('groupingFoldersList').addEventListener('drop', handleDrop, false);
|
document.getElementById('groupingFoldersList').addEventListener('drop', handleDrop, false);
|
||||||
|
|
||||||
// Handle drops on the main app area (for adding directories)
|
// Handle drops on the main app area (for adding directories).
|
||||||
document.getElementById('app').addEventListener('drop', handleAppDrop, false);
|
// Note: the root element is id="appContainer" (id="app" was a
|
||||||
|
// stale reference that crashed dragDrop init in local mode).
|
||||||
|
document.getElementById('appContainer').addEventListener('drop', handleAppDrop, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent default behaviors
|
// Prevent default behaviors
|
||||||
|
|
@ -7820,7 +7840,7 @@ window.app.modules.filtering = {
|
||||||
|
|
||||||
// Show unsupported browser message
|
// Show unsupported browser message
|
||||||
function showUnsupportedBrowserMessage() {
|
function showUnsupportedBrowserMessage() {
|
||||||
const app = document.getElementById('app');
|
const app = document.getElementById('appContainer');
|
||||||
app.innerHTML = `
|
app.innerHTML = `
|
||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
<div class="empty-state-content">
|
<div class="empty-state-content">
|
||||||
|
|
|
||||||
|
|
@ -218,6 +218,24 @@ a:hover {
|
||||||
background: var(--bg-secondary);
|
background: var(--bg-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Subdued / de-emphasized variant.
|
||||||
|
Used on the "Add Local Directory" button when a tool is operating
|
||||||
|
in server (online) mode — the local-dir affordance is still
|
||||||
|
available but visually quieter, since the typical user already
|
||||||
|
has the directory loaded from the server. */
|
||||||
|
.btn.btn--subtle {
|
||||||
|
background: transparent;
|
||||||
|
color: var(--text-muted);
|
||||||
|
border-color: var(--border);
|
||||||
|
box-shadow: none;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn.btn--subtle:not(:disabled):hover {
|
||||||
|
color: var(--text);
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
.btn-success {
|
.btn-success {
|
||||||
background: var(--success);
|
background: var(--success);
|
||||||
color: var(--text-light);
|
color: var(--text-light);
|
||||||
|
|
@ -722,22 +740,6 @@ body {
|
||||||
outline-offset: -1px;
|
outline-offset: -1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Subtle button variant — used for "Select Directory" when the page
|
|
||||||
is server-backed (the user usually doesn't need to switch to a
|
|
||||||
local folder; we keep the option visible but quiet). */
|
|
||||||
.btn.btn--subtle {
|
|
||||||
background: transparent;
|
|
||||||
color: var(--text-muted);
|
|
||||||
border-color: var(--border);
|
|
||||||
box-shadow: none;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn.btn--subtle:hover {
|
|
||||||
color: var(--text);
|
|
||||||
background: var(--bg-hover, rgba(0,0,0,0.04));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Table — folders + files in a tree */
|
/* Table — folders + files in a tree */
|
||||||
|
|
||||||
.browse-table {
|
.browse-table {
|
||||||
|
|
@ -894,10 +896,10 @@ body {
|
||||||
</svg>
|
</svg>
|
||||||
<div class="header-title-group">
|
<div class="header-title-group">
|
||||||
<span class="app-header__title">ZDDC Browse</span>
|
<span class="app-header__title">ZDDC Browse</span>
|
||||||
<span class="build-timestamp">v0.0.16-beta · 2026-05-04 · 582db6d</span>
|
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.16-beta · 2026-05-04 · e67c1b2</span></span>
|
||||||
</div>
|
</div>
|
||||||
<button id="addDirectoryBtn" class="btn btn-primary">Select Directory</button>
|
<button id="addDirectoryBtn" class="btn btn-primary">Add Local Directory</button>
|
||||||
<button id="refreshHeaderBtn" class="btn btn-secondary hidden" title="Refresh listing" aria-label="Refresh listing">⟳</button>
|
<button id="refreshHeaderBtn" class="btn btn-secondary hidden" title="Refresh listing" aria-label="Refresh listing" style="font-size:1.1rem;">⟳</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<button id="theme-btn" class="btn btn-secondary" title="Theme: auto (follows OS)" aria-label="Theme: auto (follows OS)">◐</button>
|
<button id="theme-btn" class="btn btn-secondary" title="Theme: auto (follows OS)" aria-label="Theme: auto (follows OS)">◐</button>
|
||||||
|
|
@ -914,7 +916,7 @@ body {
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>Online</b> — when this page is served by zddc-server, the
|
<li><b>Online</b> — when this page is served by zddc-server, the
|
||||||
listing for the current directory loads automatically.</li>
|
listing for the current directory loads automatically.</li>
|
||||||
<li><b>Local</b> — click <i>Select Directory</i> to pick any folder
|
<li><b>Local</b> — click <i>Add Local Directory</i> to pick any folder
|
||||||
on your computer (Chromium-based browsers).</li>
|
on your computer (Chromium-based browsers).</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Once loaded: click a folder to expand it, <b>shift-click</b>
|
<p>Once loaded: click a folder to expand it, <b>shift-click</b>
|
||||||
|
|
@ -975,6 +977,87 @@ body {
|
||||||
|
|
||||||
<div id="statusBar" class="status-bar"></div>
|
<div id="statusBar" class="status-bar"></div>
|
||||||
|
|
||||||
|
<!-- Help Panel -->
|
||||||
|
<aside id="help-panel" class="help-panel" hidden aria-labelledby="help-panel-title">
|
||||||
|
<div class="help-panel__header">
|
||||||
|
<h2 id="help-panel-title" class="help-panel__title">Help — ZDDC Browse</h2>
|
||||||
|
<button type="button" class="help-panel__close" id="help-panel-close" aria-label="Close">×</button>
|
||||||
|
</div>
|
||||||
|
<div class="help-panel__body">
|
||||||
|
<h3>What is Browse?</h3>
|
||||||
|
<p>Browse is a directory listing for ZDDC archives — and any directory. It works in two modes:</p>
|
||||||
|
<dl>
|
||||||
|
<dt>Online</dt>
|
||||||
|
<dd>When the page is served by zddc-server, the listing for the current
|
||||||
|
URL directory loads automatically. Breadcrumbs link to ancestor folders.</dd>
|
||||||
|
<dt>Local</dt>
|
||||||
|
<dd>Click <strong>Add Local Directory</strong> to pick any folder on your
|
||||||
|
computer. Local mode requires a Chromium-based browser (File System
|
||||||
|
Access API).</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h3>Tree navigation</h3>
|
||||||
|
<dl>
|
||||||
|
<dt>Click a folder</dt>
|
||||||
|
<dd>Toggle expand/collapse on that folder.</dd>
|
||||||
|
<dt>Shift-click a folder</dt>
|
||||||
|
<dd>Recursive expand or collapse — applies to the whole subtree.</dd>
|
||||||
|
<dt>Click a file</dt>
|
||||||
|
<dd>Open in the preview popup. Modifier-click (Ctrl/Cmd) or middle-click
|
||||||
|
opens in a new tab.</dd>
|
||||||
|
<dt>ZIP files</dt>
|
||||||
|
<dd>Behave as folders — click to inspect contents inline. JSZip is
|
||||||
|
bundled, so this works offline.</dd>
|
||||||
|
<dt>Column headers</dt>
|
||||||
|
<dd>Click to sort; click again to reverse.</dd>
|
||||||
|
<dt>Refresh</dt>
|
||||||
|
<dd>Re-fetches the current directory listing — works for both
|
||||||
|
local (re-enumerates the FS handle) and online (re-fetches the JSON).</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h3>Filter rows</h3>
|
||||||
|
<p>Two filter rows live in the table header:</p>
|
||||||
|
<dl>
|
||||||
|
<dt>📄 file row</dt>
|
||||||
|
<dd>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.</dd>
|
||||||
|
<dt>📁 folder row</dt>
|
||||||
|
<dd>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).</dd>
|
||||||
|
</dl>
|
||||||
|
<p>Filter syntax (shared across all ZDDC tools):</p>
|
||||||
|
<dl>
|
||||||
|
<dt><code>term</code></dt>
|
||||||
|
<dd>Contains "term" (case-insensitive)</dd>
|
||||||
|
<dt><code>!term</code></dt>
|
||||||
|
<dd>Does not contain</dd>
|
||||||
|
<dt><code>^term</code></dt>
|
||||||
|
<dd>Starts with</dd>
|
||||||
|
<dt><code>term$</code></dt>
|
||||||
|
<dd>Ends with</dd>
|
||||||
|
<dt><code>a b</code></dt>
|
||||||
|
<dd>Both (AND)</dd>
|
||||||
|
<dt><code>a | b</code></dt>
|
||||||
|
<dd>Either (OR)</dd>
|
||||||
|
<dt><code>el.*spc</code></dt>
|
||||||
|
<dd>Regex — any-char + any-sequence</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h3>Header buttons</h3>
|
||||||
|
<dl>
|
||||||
|
<dt>Add Local Directory</dt>
|
||||||
|
<dd>Pick a folder from your computer. Works in both modes; in online
|
||||||
|
mode it's de-emphasized but still available.</dd>
|
||||||
|
<dt>⟳ Refresh</dt>
|
||||||
|
<dd>Re-load the current directory listing.</dd>
|
||||||
|
<dt>◐ Theme</dt>
|
||||||
|
<dd>Cycle auto / light / dark.</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
/*!
|
/*!
|
||||||
|
|
||||||
|
|
@ -1616,6 +1699,53 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
||||||
}
|
}
|
||||||
}());
|
}());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZDDC shared help panel — open/close logic.
|
||||||
|
* Works with all four tools regardless of their module pattern.
|
||||||
|
* Expects: #help-btn, #help-panel, #help-panel-close in the DOM.
|
||||||
|
*/
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
var helpBtn = document.getElementById('help-btn');
|
||||||
|
var panel = document.getElementById('help-panel');
|
||||||
|
var closeBtn = document.getElementById('help-panel-close');
|
||||||
|
|
||||||
|
if (!helpBtn || !panel) { return; }
|
||||||
|
|
||||||
|
function isOpen() { return !panel.hidden; }
|
||||||
|
|
||||||
|
function openPanel() {
|
||||||
|
panel.hidden = false;
|
||||||
|
document.body.classList.add('help-open');
|
||||||
|
}
|
||||||
|
|
||||||
|
function closePanel() {
|
||||||
|
panel.hidden = true;
|
||||||
|
document.body.classList.remove('help-open');
|
||||||
|
}
|
||||||
|
|
||||||
|
helpBtn.addEventListener('click', function () {
|
||||||
|
if (isOpen()) { closePanel(); } else { openPanel(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (closeBtn) {
|
||||||
|
closeBtn.addEventListener('click', closePanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('keydown', function (e) {
|
||||||
|
if (e.key === 'Escape' && isOpen()) { closePanel(); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.readyState === 'loading') {
|
||||||
|
document.addEventListener('DOMContentLoaded', init);
|
||||||
|
} else {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
}());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ZDDC — shared preview helpers
|
* ZDDC — shared preview helpers
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -218,6 +218,24 @@ a:hover {
|
||||||
background: var(--bg-secondary);
|
background: var(--bg-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Subdued / de-emphasized variant.
|
||||||
|
Used on the "Add Local Directory" button when a tool is operating
|
||||||
|
in server (online) mode — the local-dir affordance is still
|
||||||
|
available but visually quieter, since the typical user already
|
||||||
|
has the directory loaded from the server. */
|
||||||
|
.btn.btn--subtle {
|
||||||
|
background: transparent;
|
||||||
|
color: var(--text-muted);
|
||||||
|
border-color: var(--border);
|
||||||
|
box-shadow: none;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn.btn--subtle:not(:disabled):hover {
|
||||||
|
color: var(--text);
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
.btn-success {
|
.btn-success {
|
||||||
background: var(--success);
|
background: var(--success);
|
||||||
color: var(--text-light);
|
color: var(--text-light);
|
||||||
|
|
@ -1376,10 +1394,10 @@ body.help-open .app-header {
|
||||||
</svg>
|
</svg>
|
||||||
<div class="header-title-group">
|
<div class="header-title-group">
|
||||||
<span class="app-header__title">ZDDC Classifier</span>
|
<span class="app-header__title">ZDDC Classifier</span>
|
||||||
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.16-beta · 2026-05-04 · 582db6d</span></span>
|
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.16-beta · 2026-05-04 · e67c1b2</span></span>
|
||||||
</div>
|
</div>
|
||||||
<button id="selectDirectoryBtn" class="btn btn-primary">Select Directory</button>
|
<button id="addDirectoryBtn" class="btn btn-primary">Add Local Directory</button>
|
||||||
<button id="refreshBtn" class="btn btn-secondary hidden" title="Refresh and rescan directory" aria-label="Refresh" style="font-size:1.1rem;">⟳</button>
|
<button id="refreshHeaderBtn" class="btn btn-secondary hidden" title="Refresh and rescan directory" aria-label="Refresh" style="font-size:1.1rem;">⟳</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<button id="theme-btn" class="btn btn-secondary" title="Theme: auto (follows OS)" aria-label="Theme: auto (follows OS)">◐</button>
|
<button id="theme-btn" class="btn btn-secondary" title="Theme: auto (follows OS)" aria-label="Theme: auto (follows OS)">◐</button>
|
||||||
|
|
@ -1498,7 +1516,7 @@ body.help-open .app-header {
|
||||||
<li>Rename one file or all modified files at once</li>
|
<li>Rename one file or all modified files at once</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>Click <strong>Select Directory</strong> to begin.</p>
|
<p>Click <strong>Add Local Directory</strong> to begin.</p>
|
||||||
|
|
||||||
<p class="note">This application works entirely in your browser. No data is transmitted to any server.</p>
|
<p class="note">This application works entirely in your browser. No data is transmitted to any server.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1517,7 +1535,7 @@ body.help-open .app-header {
|
||||||
|
|
||||||
<h3>Getting Started</h3>
|
<h3>Getting Started</h3>
|
||||||
<ol>
|
<ol>
|
||||||
<li>Click <strong>Select Directory</strong> to open a folder containing files to rename.</li>
|
<li>Click <strong>Add Local Directory</strong> to open a folder containing files to rename.</li>
|
||||||
<li>The folder tree on the left shows all sub-folders. Click a folder to load its files.</li>
|
<li>The folder tree on the left shows all sub-folders. Click a folder to load its files.</li>
|
||||||
<li>Edit cells in the spreadsheet to set the new filename components.</li>
|
<li>Edit cells in the spreadsheet to set the new filename components.</li>
|
||||||
<li>Click <strong>Save All</strong> (or save individual rows) to rename the files on disk.</li>
|
<li>Click <strong>Save All</strong> (or save individual rows) to rename the files on disk.</li>
|
||||||
|
|
@ -2757,7 +2775,7 @@ body.help-open .app-header {
|
||||||
*/
|
*/
|
||||||
function showBrowserWarning() {
|
function showBrowserWarning() {
|
||||||
const warning = document.getElementById('browserWarning');
|
const warning = document.getElementById('browserWarning');
|
||||||
const selectBtn = document.getElementById('selectDirectoryBtn');
|
const selectBtn = document.getElementById('addDirectoryBtn');
|
||||||
if (warning) {
|
if (warning) {
|
||||||
warning.classList.remove('hidden');
|
warning.classList.remove('hidden');
|
||||||
}
|
}
|
||||||
|
|
@ -2777,8 +2795,8 @@ body.help-open .app-header {
|
||||||
mainApp: document.getElementById('mainApp'),
|
mainApp: document.getElementById('mainApp'),
|
||||||
|
|
||||||
// Header buttons
|
// Header buttons
|
||||||
selectDirectoryBtn: document.getElementById('selectDirectoryBtn'),
|
addDirectoryBtn: document.getElementById('addDirectoryBtn'),
|
||||||
refreshBtn: document.getElementById('refreshBtn'),
|
refreshHeaderBtn: document.getElementById('refreshHeaderBtn'),
|
||||||
saveAllBtn: document.getElementById('saveAllBtn'),
|
saveAllBtn: document.getElementById('saveAllBtn'),
|
||||||
cancelAllBtn: document.getElementById('cancelAllBtn'),
|
cancelAllBtn: document.getElementById('cancelAllBtn'),
|
||||||
exportHashesBtn: document.getElementById('exportHashesBtn'),
|
exportHashesBtn: document.getElementById('exportHashesBtn'),
|
||||||
|
|
@ -2812,8 +2830,8 @@ body.help-open .app-header {
|
||||||
*/
|
*/
|
||||||
function setupEventListeners() {
|
function setupEventListeners() {
|
||||||
// Directory selection
|
// Directory selection
|
||||||
app.dom.selectDirectoryBtn.addEventListener('click', handleSelectDirectory);
|
app.dom.addDirectoryBtn.addEventListener('click', handleSelectDirectory);
|
||||||
app.dom.refreshBtn.addEventListener('click', handleRefresh);
|
app.dom.refreshHeaderBtn.addEventListener('click', handleRefresh);
|
||||||
|
|
||||||
// Drag and drop on welcome screen
|
// Drag and drop on welcome screen
|
||||||
setupWelcomeDragDrop();
|
setupWelcomeDragDrop();
|
||||||
|
|
@ -2975,7 +2993,7 @@ body.help-open .app-header {
|
||||||
await app.modules.scanner.scanDirectory(dirHandle);
|
await app.modules.scanner.scanDirectory(dirHandle);
|
||||||
|
|
||||||
// Show refresh button now that a directory is loaded
|
// Show refresh button now that a directory is loaded
|
||||||
if (app.dom.refreshBtn) { app.dom.refreshBtn.classList.remove('hidden'); }
|
if (app.dom.refreshHeaderBtn) { app.dom.refreshHeaderBtn.classList.remove('hidden'); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -218,6 +218,24 @@ a:hover {
|
||||||
background: var(--bg-secondary);
|
background: var(--bg-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Subdued / de-emphasized variant.
|
||||||
|
Used on the "Add Local Directory" button when a tool is operating
|
||||||
|
in server (online) mode — the local-dir affordance is still
|
||||||
|
available but visually quieter, since the typical user already
|
||||||
|
has the directory loaded from the server. */
|
||||||
|
.btn.btn--subtle {
|
||||||
|
background: transparent;
|
||||||
|
color: var(--text-muted);
|
||||||
|
border-color: var(--border);
|
||||||
|
box-shadow: none;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn.btn--subtle:not(:disabled):hover {
|
||||||
|
color: var(--text);
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
.btn-success {
|
.btn-success {
|
||||||
background: var(--success);
|
background: var(--success);
|
||||||
color: var(--text-light);
|
color: var(--text-light);
|
||||||
|
|
@ -867,11 +885,12 @@ body {
|
||||||
</svg>
|
</svg>
|
||||||
<div class="header-title-group">
|
<div class="header-title-group">
|
||||||
<span class="app-header__title">ZDDC</span>
|
<span class="app-header__title">ZDDC</span>
|
||||||
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.16-beta · 2026-05-04 · 582db6d</span></span>
|
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.16-beta · 2026-05-04 · e67c1b2</span></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<button id="theme-btn" class="btn btn-secondary" title="Theme: auto (follows OS)" aria-label="Theme: auto (follows OS)">◐</button>
|
<button id="theme-btn" class="btn btn-secondary" title="Theme: auto (follows OS)" aria-label="Theme: auto (follows OS)">◐</button>
|
||||||
|
<button id="help-btn" class="btn btn-secondary" title="Help" aria-label="Help">?</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
@ -936,6 +955,52 @@ body {
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
<!-- Help Panel -->
|
||||||
|
<aside id="help-panel" class="help-panel" hidden aria-labelledby="help-panel-title">
|
||||||
|
<div class="help-panel__header">
|
||||||
|
<h2 id="help-panel-title" class="help-panel__title">Help — ZDDC</h2>
|
||||||
|
<button type="button" class="help-panel__close" id="help-panel-close" aria-label="Close">×</button>
|
||||||
|
</div>
|
||||||
|
<div class="help-panel__body">
|
||||||
|
<h3>What is this page?</h3>
|
||||||
|
<p>This is the ZDDC archive landing page — a project picker. It lists every
|
||||||
|
project (top-level directory) you have access to on this server, plus any
|
||||||
|
<strong>groups</strong> you've defined for opening multiple projects at once.</p>
|
||||||
|
|
||||||
|
<h3>Projects</h3>
|
||||||
|
<p>Click a project to open it. The project's archive view (list of folders +
|
||||||
|
files, with all the standard ZDDC tools available inside) loads in the same
|
||||||
|
tab. Use back/forward to navigate between projects and the picker.</p>
|
||||||
|
|
||||||
|
<h3>Groups</h3>
|
||||||
|
<p>A group bundles a set of projects you commonly open together. Click
|
||||||
|
<strong>+ New group</strong>, give it a name, click projects to include
|
||||||
|
them, then save. Opening a group opens all its projects in one go.</p>
|
||||||
|
<dl>
|
||||||
|
<dt>Save group</dt>
|
||||||
|
<dd>Persist the selection as a named group on this server (visible to
|
||||||
|
other users with access to the same projects).</dd>
|
||||||
|
<dt>Open selected</dt>
|
||||||
|
<dd>Open the currently-checked projects without saving as a group.</dd>
|
||||||
|
<dt>Cancel</dt>
|
||||||
|
<dd>Exit select mode without saving.</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h3>Access</h3>
|
||||||
|
<p>Projects and groups are filtered by your account's permissions.
|
||||||
|
If a URL references a project you don't have access to, a warning banner
|
||||||
|
appears and the inaccessible items are skipped silently.</p>
|
||||||
|
|
||||||
|
<h3>Header buttons</h3>
|
||||||
|
<dl>
|
||||||
|
<dt>◐ Theme</dt>
|
||||||
|
<dd>Cycle auto / light / dark.</dd>
|
||||||
|
<dt>? Help</dt>
|
||||||
|
<dd>This panel. Press <kbd>Esc</kbd> to close.</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
/**
|
/**
|
||||||
* ZDDC — shared naming convention library
|
* ZDDC — shared naming convention library
|
||||||
|
|
@ -1564,6 +1629,53 @@ body {
|
||||||
}
|
}
|
||||||
}());
|
}());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZDDC shared help panel — open/close logic.
|
||||||
|
* Works with all four tools regardless of their module pattern.
|
||||||
|
* Expects: #help-btn, #help-panel, #help-panel-close in the DOM.
|
||||||
|
*/
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
var helpBtn = document.getElementById('help-btn');
|
||||||
|
var panel = document.getElementById('help-panel');
|
||||||
|
var closeBtn = document.getElementById('help-panel-close');
|
||||||
|
|
||||||
|
if (!helpBtn || !panel) { return; }
|
||||||
|
|
||||||
|
function isOpen() { return !panel.hidden; }
|
||||||
|
|
||||||
|
function openPanel() {
|
||||||
|
panel.hidden = false;
|
||||||
|
document.body.classList.add('help-open');
|
||||||
|
}
|
||||||
|
|
||||||
|
function closePanel() {
|
||||||
|
panel.hidden = true;
|
||||||
|
document.body.classList.remove('help-open');
|
||||||
|
}
|
||||||
|
|
||||||
|
helpBtn.addEventListener('click', function () {
|
||||||
|
if (isOpen()) { closePanel(); } else { openPanel(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (closeBtn) {
|
||||||
|
closeBtn.addEventListener('click', closePanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('keydown', function (e) {
|
||||||
|
if (e.key === 'Escape' && isOpen()) { closePanel(); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.readyState === 'loading') {
|
||||||
|
document.addEventListener('DOMContentLoaded', init);
|
||||||
|
} else {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
}());
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
'use strict';
|
'use strict';
|
||||||
// ZDDC landing page — project picker.
|
// ZDDC landing page — project picker.
|
||||||
|
|
|
||||||
|
|
@ -438,6 +438,24 @@ a:hover {
|
||||||
background: var(--bg-secondary);
|
background: var(--bg-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Subdued / de-emphasized variant.
|
||||||
|
Used on the "Add Local Directory" button when a tool is operating
|
||||||
|
in server (online) mode — the local-dir affordance is still
|
||||||
|
available but visually quieter, since the typical user already
|
||||||
|
has the directory loaded from the server. */
|
||||||
|
.btn.btn--subtle {
|
||||||
|
background: transparent;
|
||||||
|
color: var(--text-muted);
|
||||||
|
border-color: var(--border);
|
||||||
|
box-shadow: none;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn.btn--subtle:not(:disabled):hover {
|
||||||
|
color: var(--text);
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
.btn-success {
|
.btn-success {
|
||||||
background: var(--success);
|
background: var(--success);
|
||||||
color: var(--text-light);
|
color: var(--text-light);
|
||||||
|
|
@ -1774,9 +1792,10 @@ body.help-open .app-header {
|
||||||
</svg>
|
</svg>
|
||||||
<div class="header-title-group">
|
<div class="header-title-group">
|
||||||
<span class="app-header__title">ZDDC Markdown</span>
|
<span class="app-header__title">ZDDC Markdown</span>
|
||||||
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.16-beta · 2026-05-04 · 582db6d</span></span>
|
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.16-beta · 2026-05-04 · e67c1b2</span></span>
|
||||||
</div>
|
</div>
|
||||||
<button id="select-directory" class="btn btn-primary" title="Select a Directory">Select Directory</button>
|
<button id="addDirectoryBtn" class="btn btn-primary" title="Add a local directory">Add Local Directory</button>
|
||||||
|
<button id="refreshHeaderBtn" class="btn btn-secondary hidden" title="Refresh directory" aria-label="Refresh" style="font-size:1.1rem;">⟳</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<button id="theme-btn" class="btn btn-secondary" title="Theme: auto (follows OS)" aria-label="Theme: auto (follows OS)">◐</button>
|
<button id="theme-btn" class="btn btn-secondary" title="Theme: auto (follows OS)" aria-label="Theme: auto (follows OS)">◐</button>
|
||||||
|
|
@ -1792,7 +1811,6 @@ body.help-open .app-header {
|
||||||
<span>Files</span>
|
<span>Files</span>
|
||||||
<div class="flex items-center gap-1">
|
<div class="flex items-center gap-1">
|
||||||
<button id="new-file-root" class="btn btn-secondary btn-sm hidden" title="New file in root directory">+</button>
|
<button id="new-file-root" class="btn btn-secondary btn-sm hidden" title="New file in root directory">+</button>
|
||||||
<button id="refresh-directory" class="btn btn-secondary btn-sm hidden" title="Refresh directory">↻</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1806,7 +1824,7 @@ body.help-open .app-header {
|
||||||
|
|
||||||
<div class="pane content-pane flex-1 relative flex flex-col bg-white dark:bg-gray-900 overflow-hidden" id="main-content">
|
<div class="pane content-pane flex-1 relative flex flex-col bg-white dark:bg-gray-900 overflow-hidden" id="main-content">
|
||||||
<div id="welcome-screen" class="welcome-screen hidden flex-col items-center justify-center h-full text-gray-500 dark:text-gray-400 text-center p-6">
|
<div id="welcome-screen" class="welcome-screen hidden flex-col items-center justify-center h-full text-gray-500 dark:text-gray-400 text-center p-6">
|
||||||
<p id="welcome-hint" class="text-sm">Click <strong>Scratchpad</strong> in the file list to start editing,<br>or <strong>Select Directory</strong> to work with files.</p>
|
<p id="welcome-hint" class="text-sm">Click <strong>Scratchpad</strong> in the file list to start editing,<br>or <strong>Add Local Directory</strong> to work with files.</p>
|
||||||
<p id="welcome-firefox" class="text-sm text-amber-600 hidden mt-2">Your browser doesn't support the File System API.<br>Use <strong>Scratchpad</strong> to edit markdown and download as a file.</p>
|
<p id="welcome-firefox" class="text-sm text-amber-600 hidden mt-2">Your browser doesn't support the File System API.<br>Use <strong>Scratchpad</strong> to edit markdown and download as a file.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -1850,7 +1868,7 @@ body.help-open .app-header {
|
||||||
|
|
||||||
<h3>Getting Started</h3>
|
<h3>Getting Started</h3>
|
||||||
<ol>
|
<ol>
|
||||||
<li>Click <strong>Select Directory</strong> to open a folder. The file tree on the left will populate with all files in that folder.</li>
|
<li>Click <strong>Add Local Directory</strong> to open a folder. The file tree on the left will populate with all files in that folder.</li>
|
||||||
<li>Click any Markdown file (<code>.md</code>) in the tree to open it in the editor.</li>
|
<li>Click any Markdown file (<code>.md</code>) in the tree to open it in the editor.</li>
|
||||||
<li>Use the <strong>Scratchpad</strong> entry (always visible at the top of the tree) for temporary notes without saving to disk.</li>
|
<li>Use the <strong>Scratchpad</strong> entry (always visible at the top of the tree) for temporary notes without saving to disk.</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
@ -2954,7 +2972,7 @@ const SCRATCHPAD_WELCOME = [
|
||||||
'Use this **Scratchpad** for quick notes. Download it any time with the ⬇',
|
'Use this **Scratchpad** for quick notes. Download it any time with the ⬇',
|
||||||
'button on the Scratchpad row in the file list.',
|
'button on the Scratchpad row in the file list.',
|
||||||
'',
|
'',
|
||||||
'Click **Select Directory** above to open a folder of Markdown files,',
|
'Click **Add Local Directory** above to open a folder of Markdown files,',
|
||||||
'or just start typing here.',
|
'or just start typing here.',
|
||||||
'',
|
'',
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
@ -3754,12 +3772,19 @@ async function openDirectory() {
|
||||||
* @param {string} directoryName - Name of the selected directory
|
* @param {string} directoryName - Name of the selected directory
|
||||||
*/
|
*/
|
||||||
function updateDirectoryStatus(directoryName) {
|
function updateDirectoryStatus(directoryName) {
|
||||||
const selectDirectoryBtn = document.getElementById('select-directory');
|
// Standardized header pattern (across all ZDDC tools): the button
|
||||||
|
// keeps the label "Add Local Directory"; de-emphasize it once a
|
||||||
|
// directory is loaded (the user can still click to pick another)
|
||||||
|
// by applying the shared btn--subtle variant. The directory name
|
||||||
|
// is shown in the file-nav pane, not on the button.
|
||||||
|
const selectDirectoryBtn = document.getElementById('addDirectoryBtn');
|
||||||
if (selectDirectoryBtn) {
|
if (selectDirectoryBtn) {
|
||||||
selectDirectoryBtn.textContent = `Directory: ${directoryName}`;
|
selectDirectoryBtn.classList.remove('btn-primary');
|
||||||
|
selectDirectoryBtn.classList.add('btn--subtle');
|
||||||
|
selectDirectoryBtn.title = `Loaded: ${directoryName} — click to switch`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const refreshBtn = document.getElementById('refresh-directory');
|
const refreshBtn = document.getElementById('refreshHeaderBtn');
|
||||||
if (refreshBtn) {
|
if (refreshBtn) {
|
||||||
refreshBtn.classList.remove('hidden');
|
refreshBtn.classList.remove('hidden');
|
||||||
}
|
}
|
||||||
|
|
@ -4260,8 +4285,8 @@ async function loadServerDirectory() {
|
||||||
|
|
||||||
// Only enter server-source mode if the host actually serves JSON directory
|
// Only enter server-source mode if the host actually serves JSON directory
|
||||||
// listings (zddc-server / Caddy). On a plain static host the probe fails
|
// listings (zddc-server / Caddy). On a plain static host the probe fails
|
||||||
// and we must leave "Select Directory" visible so the user can still load
|
// and we must leave "Add Local Directory" visible so the user can still
|
||||||
// local files.
|
// load local files.
|
||||||
try {
|
try {
|
||||||
const resp = await fetch(baseUrl, { headers: { 'Accept': 'application/json' }, cache: 'no-cache' });
|
const resp = await fetch(baseUrl, { headers: { 'Accept': 'application/json' }, cache: 'no-cache' });
|
||||||
if (!resp.ok) return;
|
if (!resp.ok) return;
|
||||||
|
|
@ -4286,12 +4311,18 @@ async function loadServerDirectory() {
|
||||||
entries: {},
|
entries: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Surface refresh, hide write-only controls. "Select Directory" stays
|
// Surface refresh, hide write-only controls. "Add Local Directory"
|
||||||
// visible so the user can switch to a local folder at any time.
|
// stays visible (de-emphasized via btn--subtle) so the user can
|
||||||
const refreshBtn = document.getElementById('refresh-directory');
|
// switch to a local folder at any time.
|
||||||
|
const refreshBtn = document.getElementById('refreshHeaderBtn');
|
||||||
if (refreshBtn) refreshBtn.classList.remove('hidden');
|
if (refreshBtn) refreshBtn.classList.remove('hidden');
|
||||||
const newFileRootBtn = document.getElementById('new-file-root');
|
const newFileRootBtn = document.getElementById('new-file-root');
|
||||||
if (newFileRootBtn) newFileRootBtn.classList.add('hidden');
|
if (newFileRootBtn) newFileRootBtn.classList.add('hidden');
|
||||||
|
const addDirBtn = document.getElementById('addDirectoryBtn');
|
||||||
|
if (addDirBtn) {
|
||||||
|
addDirBtn.classList.remove('btn-primary');
|
||||||
|
addDirBtn.classList.add('btn--subtle');
|
||||||
|
}
|
||||||
|
|
||||||
const stats = await readServerDirectory(baseUrl, fileTree, 0);
|
const stats = await readServerDirectory(baseUrl, fileTree, 0);
|
||||||
renderFileTree();
|
renderFileTree();
|
||||||
|
|
@ -6028,14 +6059,14 @@ function initializeFileNavResizer() {
|
||||||
* Set up all event listeners for the application
|
* Set up all event listeners for the application
|
||||||
*/
|
*/
|
||||||
function setupEventListeners() {
|
function setupEventListeners() {
|
||||||
// Select directory button
|
// Add Local Directory button (was id="select-directory" / "refresh-directory")
|
||||||
const selectDirectoryBtn = document.getElementById('select-directory');
|
const selectDirectoryBtn = document.getElementById('addDirectoryBtn');
|
||||||
if (selectDirectoryBtn) {
|
if (selectDirectoryBtn) {
|
||||||
selectDirectoryBtn.addEventListener('click', openDirectory);
|
selectDirectoryBtn.addEventListener('click', openDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh directory button
|
// Refresh button (now in header, was in file-nav pane)
|
||||||
const refreshDirectoryBtn = document.getElementById('refresh-directory');
|
const refreshDirectoryBtn = document.getElementById('refreshHeaderBtn');
|
||||||
if (refreshDirectoryBtn) {
|
if (refreshDirectoryBtn) {
|
||||||
refreshDirectoryBtn.addEventListener('click', refreshDirectory);
|
refreshDirectoryBtn.addEventListener('click', refreshDirectory);
|
||||||
}
|
}
|
||||||
|
|
@ -6136,7 +6167,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||||
* Initialize UI based on File System API availability
|
* Initialize UI based on File System API availability
|
||||||
*/
|
*/
|
||||||
function initializeApiAvailability() {
|
function initializeApiAvailability() {
|
||||||
const selectDirectoryBtn = document.getElementById('select-directory');
|
const selectDirectoryBtn = document.getElementById('addDirectoryBtn');
|
||||||
const welcomeHint = document.getElementById('welcome-hint');
|
const welcomeHint = document.getElementById('welcome-hint');
|
||||||
const welcomeFirefox = document.getElementById('welcome-firefox');
|
const welcomeFirefox = document.getElementById('welcome-firefox');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -222,6 +222,24 @@ a:hover {
|
||||||
background: var(--bg-secondary);
|
background: var(--bg-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Subdued / de-emphasized variant.
|
||||||
|
Used on the "Add Local Directory" button when a tool is operating
|
||||||
|
in server (online) mode — the local-dir affordance is still
|
||||||
|
available but visually quieter, since the typical user already
|
||||||
|
has the directory loaded from the server. */
|
||||||
|
.btn.btn--subtle {
|
||||||
|
background: transparent;
|
||||||
|
color: var(--text-muted);
|
||||||
|
border-color: var(--border);
|
||||||
|
box-shadow: none;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn.btn--subtle:not(:disabled):hover {
|
||||||
|
color: var(--text);
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
.btn-success {
|
.btn-success {
|
||||||
background: var(--success);
|
background: var(--success);
|
||||||
color: var(--text-light);
|
color: var(--text-light);
|
||||||
|
|
@ -1041,37 +1059,6 @@ body.help-open .app-header {
|
||||||
box-sizing: content-box;
|
box-sizing: content-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-header__spacer {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-header__icons {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-icon-btn {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 28px;
|
|
||||||
height: 28px;
|
|
||||||
border-radius: 0.25rem;
|
|
||||||
border: none;
|
|
||||||
background: transparent;
|
|
||||||
color: var(--text-muted);
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 0;
|
|
||||||
text-decoration: none;
|
|
||||||
transition: color 0.15s, background 0.15s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-icon-btn:hover {
|
|
||||||
color: var(--primary-hover);
|
|
||||||
background: var(--primary-light);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── Fixed footer status bar at viewport bottom ───────── */
|
/* ── Fixed footer status bar at viewport bottom ───────── */
|
||||||
.page-footer {
|
.page-footer {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
|
@ -2193,31 +2180,34 @@ dialog.modal--narrow {
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="font-sans text-gray-900">
|
<body class="font-sans text-gray-900">
|
||||||
<div class="app-header print:hidden" data-no-disable="true">
|
<header class="app-header print:hidden" data-no-disable="true">
|
||||||
<div class="split-button" id="bottom-menu" hidden>
|
<div class="header-left">
|
||||||
<button id="bottom-toggle" type="button" class="btn btn-primary split-button__toggle" data-no-disable="true" aria-haspopup="true" aria-expanded="false">▾</button>
|
<svg class="app-header__logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" aria-hidden="true">
|
||||||
<button id="bottom-primary" type="button" class="btn btn-primary" data-no-disable="true">Publish</button>
|
<rect width="64" height="64" rx="12" fill="#1e3a5f"/>
|
||||||
<div class="dropdown-menu hidden" role="menu" id="bottom-dropdown"></div>
|
<g fill="#fff">
|
||||||
|
<rect x="14" y="18" width="36" height="7"/>
|
||||||
|
<polygon points="43,25 50,25 21,43 14,43"/>
|
||||||
|
<rect x="14" y="43" width="36" height="7"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
<div class="header-title-group">
|
||||||
|
<span class="app-header__title">ZDDC Transmittal</span>
|
||||||
|
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.16-beta · 2026-05-04 · e67c1b2</span></span>
|
||||||
|
</div>
|
||||||
|
<span id="no-js-notice" class="text-gray-400 text-xs italic">JavaScript not available</span>
|
||||||
|
<!-- Publish split-button (Transmittal-specific primary action;
|
||||||
|
other tools have "Add Local Directory" here instead) -->
|
||||||
|
<div class="split-button" id="bottom-menu" hidden>
|
||||||
|
<button id="bottom-toggle" type="button" class="btn btn-primary split-button__toggle" data-no-disable="true" aria-haspopup="true" aria-expanded="false">▾</button>
|
||||||
|
<button id="bottom-primary" type="button" class="btn btn-primary" data-no-disable="true">Publish</button>
|
||||||
|
<div class="dropdown-menu hidden" role="menu" id="bottom-dropdown"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span id="no-js-notice" class="text-gray-400 text-xs italic">JavaScript not available</span>
|
<div class="header-right">
|
||||||
<svg class="app-header__logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" aria-hidden="true">
|
|
||||||
<rect width="64" height="64" rx="12" fill="#1e3a5f"/>
|
|
||||||
<g fill="#fff">
|
|
||||||
<rect x="14" y="18" width="36" height="7"/>
|
|
||||||
<polygon points="43,25 50,25 21,43 14,43"/>
|
|
||||||
<rect x="14" y="43" width="36" height="7"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
<div class="header-title-group">
|
|
||||||
<span class="app-header__title">ZDDC Transmittal</span>
|
|
||||||
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.16-beta · 2026-05-04 · 582db6d</span></span>
|
|
||||||
</div>
|
|
||||||
<div class="app-header__spacer"></div>
|
|
||||||
<div class="app-header__icons">
|
|
||||||
<button type="button" id="theme-btn" class="btn btn-secondary" title="Theme: auto (follows OS)" aria-label="Theme: auto (follows OS)">◐</button>
|
<button type="button" id="theme-btn" class="btn btn-secondary" title="Theme: auto (follows OS)" aria-label="Theme: auto (follows OS)">◐</button>
|
||||||
<button type="button" id="help-btn" class="btn btn-secondary" aria-label="Help" title="Help">?</button>
|
<button type="button" id="help-btn" class="btn btn-secondary" aria-label="Help" title="Help">?</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</header>
|
||||||
<div class="page-container">
|
<div class="page-container">
|
||||||
<form id="transmittal-form">
|
<form id="transmittal-form">
|
||||||
<input type="hidden" id="mode" value="edit">
|
<input type="hidden" id="mode" value="edit">
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
# Generated by build.sh — do not edit. One <app>=<build label> per line.
|
# Generated by build.sh — do not edit. One <app>=<build label> per line.
|
||||||
archive=v0.0.16-beta · 2026-05-04 · 582db6d
|
archive=v0.0.16-beta · 2026-05-04 · e67c1b2
|
||||||
transmittal=v0.0.16-beta · 2026-05-04 · 582db6d
|
transmittal=v0.0.16-beta · 2026-05-04 · e67c1b2
|
||||||
classifier=v0.0.16-beta · 2026-05-04 · 582db6d
|
classifier=v0.0.16-beta · 2026-05-04 · e67c1b2
|
||||||
mdedit=v0.0.16-beta · 2026-05-04 · 582db6d
|
mdedit=v0.0.16-beta · 2026-05-04 · e67c1b2
|
||||||
landing=v0.0.16-beta · 2026-05-04 · 582db6d
|
landing=v0.0.16-beta · 2026-05-04 · e67c1b2
|
||||||
form=v0.0.16-beta · 2026-05-04 · 582db6d
|
form=v0.0.16-beta · 2026-05-04 · e67c1b2
|
||||||
browse=v0.0.16-beta · 2026-05-04 · 582db6d
|
browse=v0.0.16-beta · 2026-05-04 · e67c1b2
|
||||||
|
|
|
||||||
|
|
@ -218,6 +218,24 @@ a:hover {
|
||||||
background: var(--bg-secondary);
|
background: var(--bg-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Subdued / de-emphasized variant.
|
||||||
|
Used on the "Add Local Directory" button when a tool is operating
|
||||||
|
in server (online) mode — the local-dir affordance is still
|
||||||
|
available but visually quieter, since the typical user already
|
||||||
|
has the directory loaded from the server. */
|
||||||
|
.btn.btn--subtle {
|
||||||
|
background: transparent;
|
||||||
|
color: var(--text-muted);
|
||||||
|
border-color: var(--border);
|
||||||
|
box-shadow: none;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn.btn--subtle:not(:disabled):hover {
|
||||||
|
color: var(--text);
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
.btn-success {
|
.btn-success {
|
||||||
background: var(--success);
|
background: var(--success);
|
||||||
color: var(--text-light);
|
color: var(--text-light);
|
||||||
|
|
@ -723,11 +741,12 @@ body.help-open .app-header {
|
||||||
</svg>
|
</svg>
|
||||||
<div class="header-title-group">
|
<div class="header-title-group">
|
||||||
<span class="app-header__title" id="form-title">ZDDC Form</span>
|
<span class="app-header__title" id="form-title">ZDDC Form</span>
|
||||||
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.16-beta · 2026-05-04 · 582db6d</span></span>
|
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.16-beta · 2026-05-04 · e67c1b2</span></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<button id="theme-btn" class="btn btn-secondary" title="Theme: auto (follows OS)" aria-label="Theme: auto (follows OS)">◐</button>
|
<button id="theme-btn" class="btn btn-secondary" title="Theme: auto (follows OS)" aria-label="Theme: auto (follows OS)">◐</button>
|
||||||
|
<button id="help-btn" class="btn btn-secondary" title="Help" aria-label="Help">?</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
@ -739,6 +758,51 @@ body.help-open .app-header {
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
<!-- Help Panel -->
|
||||||
|
<aside id="help-panel" class="help-panel" hidden aria-labelledby="help-panel-title">
|
||||||
|
<div class="help-panel__header">
|
||||||
|
<h2 id="help-panel-title" class="help-panel__title">Help — ZDDC Form</h2>
|
||||||
|
<button type="button" class="help-panel__close" id="help-panel-close" aria-label="Close">×</button>
|
||||||
|
</div>
|
||||||
|
<div class="help-panel__body">
|
||||||
|
<h3>What is this form?</h3>
|
||||||
|
<p>This is a schema-driven form rendered by zddc-server. Every
|
||||||
|
<code><name>.form.yaml</code> file in the archive becomes an
|
||||||
|
editable form at <code><path>/<name>.form.html</code>.
|
||||||
|
Submissions are saved as <code><name>/<id>.yaml</code>
|
||||||
|
files alongside the schema, and re-render with their data filled in
|
||||||
|
when revisited.</p>
|
||||||
|
|
||||||
|
<h3>Filling in the form</h3>
|
||||||
|
<dl>
|
||||||
|
<dt>Required fields</dt>
|
||||||
|
<dd>Marked with an asterisk in their label. Submitting with a
|
||||||
|
required field empty re-renders the form with an inline error.</dd>
|
||||||
|
<dt>Validation</dt>
|
||||||
|
<dd>Server-side via JSON Schema 2020-12 (subset). Client-side
|
||||||
|
hints (<code>required</code>, <code>min</code>, <code>max</code>,
|
||||||
|
<code>pattern</code>) are added where the schema specifies them.</dd>
|
||||||
|
<dt>Submit</dt>
|
||||||
|
<dd>POSTs to the same URL the form was loaded from. On success the
|
||||||
|
browser navigates to the saved submission's URL. On failure the
|
||||||
|
form re-renders with errors inline at each invalid field.</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h3>Editing existing submissions</h3>
|
||||||
|
<p>Open the saved submission's URL — the form re-renders with its
|
||||||
|
current data and any errors. Submitting overwrites the same file.
|
||||||
|
History is in git via your normal commit cycle.</p>
|
||||||
|
|
||||||
|
<h3>Header buttons</h3>
|
||||||
|
<dl>
|
||||||
|
<dt>◐ Theme</dt>
|
||||||
|
<dd>Cycle auto / light / dark.</dd>
|
||||||
|
<dt>? Help</dt>
|
||||||
|
<dd>This panel. Press <kbd>Esc</kbd> to close.</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Server injects the form context here on render. Shape:
|
Server injects the form context here on render. Shape:
|
||||||
{
|
{
|
||||||
|
|
@ -838,6 +902,53 @@ body.help-open .app-header {
|
||||||
}
|
}
|
||||||
}());
|
}());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZDDC shared help panel — open/close logic.
|
||||||
|
* Works with all four tools regardless of their module pattern.
|
||||||
|
* Expects: #help-btn, #help-panel, #help-panel-close in the DOM.
|
||||||
|
*/
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
var helpBtn = document.getElementById('help-btn');
|
||||||
|
var panel = document.getElementById('help-panel');
|
||||||
|
var closeBtn = document.getElementById('help-panel-close');
|
||||||
|
|
||||||
|
if (!helpBtn || !panel) { return; }
|
||||||
|
|
||||||
|
function isOpen() { return !panel.hidden; }
|
||||||
|
|
||||||
|
function openPanel() {
|
||||||
|
panel.hidden = false;
|
||||||
|
document.body.classList.add('help-open');
|
||||||
|
}
|
||||||
|
|
||||||
|
function closePanel() {
|
||||||
|
panel.hidden = true;
|
||||||
|
document.body.classList.remove('help-open');
|
||||||
|
}
|
||||||
|
|
||||||
|
helpBtn.addEventListener('click', function () {
|
||||||
|
if (isOpen()) { closePanel(); } else { openPanel(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (closeBtn) {
|
||||||
|
closeBtn.addEventListener('click', closePanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('keydown', function (e) {
|
||||||
|
if (e.key === 'Escape' && isOpen()) { closePanel(); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.readyState === 'loading') {
|
||||||
|
document.addEventListener('DOMContentLoaded', init);
|
||||||
|
} else {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
}());
|
||||||
|
|
||||||
(function (global) {
|
(function (global) {
|
||||||
'use strict';
|
'use strict';
|
||||||
if (global.formApp) {
|
if (global.formApp) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue