diff --git a/shared/zddc-source.js b/shared/zddc-source.js index ab649ec..c550452 100644 --- a/shared/zddc-source.js +++ b/shared/zddc-source.js @@ -289,13 +289,33 @@ // Top-level helpers // ----------------------------------------------------------------- - // Strip a trailing tool .html (e.g. classifier.html) from a path - // to land on the "directory the tool was opened in". + // Resolve "the directory the tool was opened in" for the current + // page URL. Two URL shapes serve a tool: + // + // /…/.html — file URL; strip the trailing filename. + // /…// — trailing-slash directory URL; keep it. + // /…/ — bare-directory URL served by the + // cascade's `default_tool` (e.g. + // archive//mdl serves the tables + // tool). Treat as the directory itself + // and append the missing slash. + // + // Discrimination is "does the last segment contain a dot?" — a dot + // is a reliable proxy for "looks like a file with an extension" + // since neither directory names nor default_tool paths contain + // them in this system. function pathToDir(pathname) { if (!pathname) return '/'; if (pathname.endsWith('/')) return pathname; var slash = pathname.lastIndexOf('/'); - return slash >= 0 ? pathname.substring(0, slash + 1) : '/'; + var lastSeg = slash >= 0 ? pathname.substring(slash + 1) : pathname; + if (lastSeg.indexOf('.') !== -1) { + // Has an extension → looks like a file URL → strip the + // filename to land on the parent directory. + return slash >= 0 ? pathname.substring(0, slash + 1) : '/'; + } + // No extension → the URL IS the directory; just close it. + return pathname + '/'; } // Probe the server-mode root for the current page. Returns: diff --git a/tables/js/context.js b/tables/js/context.js index 656cd33..5f77c6a 100644 --- a/tables/js/context.js +++ b/tables/js/context.js @@ -117,10 +117,20 @@ } function tableNameFromUrl(pathname) { - // //...//table.html → name is the rows-dir's - // basename. - const m = String(pathname || '').match(/\/([^\/]+)\/table\.html$/); - return m ? m[1] : null; + // Two URL shapes resolve to a table page: + // Form A — /<…>//table.html (legacy/explicit + // entry-point; the tool was opened via the + // literal file URL). + // Form B — /<…>/ or /<…>// (served + // by the cascade's `default_tool: tables` at + // archive//mdl; the URL is the directory + // itself, no trailing filename). + // In both cases the table name is the rows-directory basename. + const a = String(pathname || '').match(/\/([^\/]+)\/table\.html$/); + if (a) return a[1]; + const trimmed = String(pathname || '').replace(/\/$/, ''); + const b = trimmed.match(/\/([^\/]+)$/); + return b ? b[1] : null; } function stripDotSlash(p) { @@ -198,11 +208,13 @@ return rows; } - // Re-edit URL for one row. Page is at //table.html; row file - // lives at //.yaml; form re-edit URL is - // //.yaml.html — same directory. + // Re-edit URL for one row. The page directory is the same + // directory the rows live in, regardless of which URL shape + // (Form A `…/table.html` vs Form B bare `…/`) we were + // opened with — see tableNameFromUrl. function rowEditUrl(rowFileName) { - const pageDir = location.pathname.replace(/\/table\.html$/, '/'); + let pageDir = location.pathname.replace(/\/table\.html$/, '/'); + if (!pageDir.endsWith('/')) pageDir += '/'; return pageDir + rowFileName + '.html'; }