mirror of
https://github.com/brunopostle/ifcurl.git
synced 2026-07-12 02:08:13 +00:00
Case 3 in footer.tmpl detects /{owner}/{repo}/pulls/{N}/files, fetches base/
head SHAs from the Forgejo API, then injects <img src="/render_diff?…"> below
the file header of each .ifc file in the diff. Returns early so Case 2 (history
page) does not also run on the PR diff page.
README documents the required Nginx proxy for /preview and /render_diff, and
clarifies that PREVIEW_SERVICE_URL is server-side-only (localhost:8000 is
correct for it); the browser-side diff images need the proxy.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
117 lines
4.9 KiB
Cheetah
117 lines
4.9 KiB
Cheetah
<script>
|
|
// Copyright 2026 The Forgejo Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
//
|
|
// ifcurl — inject "View in 3D" button on .ifc file view and history pages.
|
|
//
|
|
// Deploy to: /etc/forgejo/templates/custom/footer.tmpl
|
|
//
|
|
// Uses commit-hash hrefs (always unambiguous) to construct ifc:// URLs.
|
|
(function () {
|
|
"use strict";
|
|
|
|
var VIEWER_BASE = "/assets/viewer.html";
|
|
|
|
// Parse /owner/repo/src/commit/{40hex}/{treepath}
|
|
// Returns {repoPath, hash, treePath} or null.
|
|
function parseCommitHref(href) {
|
|
var m = href.match(/^\/([^/]+\/[^/]+)\/src\/commit\/([0-9a-f]{40})\/(.+)$/i);
|
|
if (!m) return null;
|
|
return { repoPath: m[1], hash: m[2], treePath: m[3] };
|
|
}
|
|
|
|
function makeViewerLink(info, label, cls) {
|
|
var host = window.location.host;
|
|
var ifcUrl = "ifc://" + host + "/" + info.repoPath
|
|
+ "@" + info.hash
|
|
+ "?path=" + encodeURIComponent(info.treePath);
|
|
var a = document.createElement("a");
|
|
a.href = VIEWER_BASE + "?url=" + encodeURIComponent(ifcUrl);
|
|
a.target = "_blank";
|
|
a.rel = "noopener noreferrer";
|
|
a.className = cls || "ui mini basic button";
|
|
a.textContent = label;
|
|
return a;
|
|
}
|
|
|
|
function init() {
|
|
var host = window.location.host;
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Case 1: single file view — permalink button in .file-header-right.
|
|
// -----------------------------------------------------------------------
|
|
var btnGroup = document.querySelector(".file-header-right .ui.buttons");
|
|
if (btnGroup) {
|
|
// Permalink href or current URL when already at a commit.
|
|
var a = document.querySelector('a[href*="/src/commit/"]');
|
|
var href = a ? a.getAttribute("href") : window.location.pathname;
|
|
var info = parseCommitHref(href);
|
|
if (info && info.treePath.toLowerCase().endsWith(".ifc")) {
|
|
btnGroup.appendChild(makeViewerLink(info, "View in 3D"));
|
|
}
|
|
return;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Case 3: PR diff page — inject a render_diff image below the header of
|
|
// each .ifc file in the diff. Requires Nginx to proxy /render_diff to
|
|
// the ifcurl preview service (see forgejo/README.md).
|
|
// -----------------------------------------------------------------------
|
|
var prMatch = window.location.pathname.match(/^\/([^/]+\/[^/]+)\/pulls\/(\d+)\/files$/);
|
|
if (prMatch) {
|
|
var prRepoPath = prMatch[1];
|
|
var prNum = prMatch[2];
|
|
fetch("/api/v1/repos/" + prRepoPath + "/pulls/" + prNum)
|
|
.then(function(r) { return r.ok ? r.json() : Promise.reject(r.status); })
|
|
.then(function(pr) {
|
|
var baseSha = pr.base && pr.base.sha;
|
|
var headSha = pr.head && pr.head.sha;
|
|
if (!baseSha || !headSha) return;
|
|
var origin = window.location.origin;
|
|
document.querySelectorAll('a[href*="/src/commit/"]').forEach(function(a) {
|
|
var info = parseCommitHref(a.getAttribute("href"));
|
|
if (!info || !info.treePath.toLowerCase().endsWith(".ifc")) return;
|
|
if (info.hash !== headSha) return;
|
|
var baseIfc = "ifc://" + host + "/" + prRepoPath + "@" + baseSha
|
|
+ "?path=" + encodeURIComponent(info.treePath);
|
|
var headIfc = "ifc://" + host + "/" + prRepoPath + "@" + headSha
|
|
+ "?path=" + encodeURIComponent(info.treePath);
|
|
var img = document.createElement("img");
|
|
img.src = origin + "/render_diff"
|
|
+ "?base=" + encodeURIComponent(baseIfc)
|
|
+ "&head=" + encodeURIComponent(headIfc);
|
|
img.style.cssText = "max-width:100%;display:block;margin:8px 0";
|
|
img.alt = info.treePath;
|
|
var fileBox = a.closest(".diff-file-box");
|
|
var header = fileBox && fileBox.querySelector(".file-header");
|
|
if (header) {
|
|
header.insertAdjacentElement("afterend", img);
|
|
} else {
|
|
a.insertAdjacentElement("afterend", img);
|
|
}
|
|
});
|
|
})
|
|
.catch(function() {}); // silently skip on API error
|
|
return;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Case 2: file history page — inject a "3D" link next to each commit's
|
|
// browse-file link (/src/commit/{hash}/{treepath}).
|
|
// -----------------------------------------------------------------------
|
|
document.querySelectorAll('a[href*="/src/commit/"]').forEach(function(a) {
|
|
var info = parseCommitHref(a.getAttribute("href"));
|
|
if (!info || !info.treePath.toLowerCase().endsWith(".ifc")) return;
|
|
var btn = makeViewerLink(info, "3D");
|
|
btn.style.marginLeft = "4px";
|
|
a.insertAdjacentElement("afterend", btn);
|
|
});
|
|
}
|
|
|
|
if (document.readyState === "loading") {
|
|
document.addEventListener("DOMContentLoaded", init);
|
|
} else {
|
|
init();
|
|
}
|
|
})();
|
|
</script>
|