ifcurl/forgejo/custom/public/assets/viewer-url.js
Claude 7e7aadeb5a
Viewer: query field and results table (ifcurl-2iv, ifcurl-4u3)
viewer-url.js: parseIfcUrl returns query field; buildIfcUrl gains optional
fifth query param, included in the QS when non-empty.

viewer.html: add 'query' text field (label + input) in toolbar row 2
after the visibility selector. Add #query-panel (fixed bottom-centre)
with a scrollable table showing GlobalId | value rows, a header
displaying the query path, and a close button.

viewer.js: populate queryInput from parsed URL on load; include query
in buildIfcUrl() wrapper; wire queryInput into Enter-key and focus/blur
listeners. Add applyQuery(srcUrl, queryPath) which calls GET /query,
populates the table, and shows the panel. Called from main() after
applySelector when both selector and query params are present.

viewer-url.test.js: add tests for parseIfcUrl query field, buildIfcUrl
with query, and buildIfcUrl omitting empty query.

https://claude.ai/code/session_01NBsytCd6L7UQPiKbcLn4kn
2026-05-09 11:09:55 +00:00

83 lines
3.3 KiB
JavaScript

// Copyright 2026 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//
// Pure ifc:// URL logic shared between viewer.html and tests.
export function parseIfcUrl(raw) {
if (!raw?.startsWith("ifc://")) return null;
const body = raw.slice("ifc://".length);
const slashIdx = body.indexOf("/");
const authority = slashIdx < 0 ? body : body.slice(0, slashIdx);
const pathAndQuery = slashIdx < 0 ? "" : body.slice(slashIdx + 1);
const atInAuth = authority.indexOf("@");
const userAt = atInAuth < 0 ? "" : authority.slice(0, atInAuth + 1);
const host = atInAuth < 0 ? authority : authority.slice(atInAuth + 1);
const qIdx = pathAndQuery.indexOf("?");
const pathPart = qIdx < 0 ? pathAndQuery : pathAndQuery.slice(0, qIdx);
const qs = new URLSearchParams(qIdx < 0 ? "" : pathAndQuery.slice(qIdx + 1));
const atIdx = pathPart.lastIndexOf("@");
const repoSuffix = atIdx < 0 ? pathPart : pathPart.slice(0, atIdx);
const ref = atIdx < 0 ? "" : pathPart.slice(atIdx + 1);
return {
repo: userAt + host + "/" + repoSuffix,
host, userAt, repoSuffix, ref,
path: qs.get("path") ?? "",
selector: qs.get("selector") ?? "",
query: qs.get("query") ?? "",
camera: qs.get("camera") ?? "",
fov: qs.get("fov") ?? "",
scale: qs.get("scale") ?? "",
};
}
export function buildIfcUrl(repo, ref, path, selector, query) {
if (!repo || !ref) return null;
const qs = new URLSearchParams();
if (path) qs.set("path", path);
if (selector) qs.set("selector", selector);
if (query) qs.set("query", query);
const qsStr = qs.toString().replace(/%2C/g, ",").replace(/%2B/g, "+").replace(/%24/g, "$");
return `ifc://${repo}@${ref}${qsStr ? "?" + qsStr : ""}`;
}
export function toRawUrl(raw) {
const body = raw.slice("ifc://".length);
const slashIdx = body.indexOf("/");
const authority = slashIdx < 0 ? body : body.slice(0, slashIdx);
const pathAndQuery = slashIdx < 0 ? "" : body.slice(slashIdx + 1);
const atInAuth = authority.indexOf("@");
const host = atInAuth < 0 ? authority : authority.slice(atInAuth + 1);
const qIdx = pathAndQuery.indexOf("?");
const pathPart = qIdx < 0 ? pathAndQuery : pathAndQuery.slice(0, qIdx);
const qs = new URLSearchParams(qIdx < 0 ? "" : pathAndQuery.slice(qIdx + 1));
const filePath = qs.get("path") ?? "";
const atIdx = pathPart.lastIndexOf("@");
const repoPath = atIdx < 0 ? pathPart : pathPart.slice(0, atIdx);
const ref = atIdx < 0 ? "" : pathPart.slice(atIdx + 1);
const plainRef = ref.startsWith("heads/") ? ref.slice(6)
: ref.startsWith("tags/") ? ref.slice(5)
: ref;
if (host === "github.com" || host.endsWith(".github.com")) {
return `https://raw.githubusercontent.com/${repoPath}/${plainRef}/${filePath}`;
}
if (host === "gitlab.com" || host.startsWith("gitlab.")) {
const proto = host.startsWith("localhost") ? "http" : "https";
return `${proto}://${host}/${repoPath}/-/raw/${plainRef}/${filePath}`;
}
const refSeg = ref.startsWith("heads/") ? "branch/" + ref.slice(6)
: ref.startsWith("tags/") ? "tag/" + ref.slice(5)
: "commit/" + ref;
const proto = host.startsWith("localhost") ? "http" : "https";
return `${proto}://${host}/${repoPath}/raw/${refSeg}/${filePath}`;
}