elixir/static/dynamic-references.js
Franciszek Stachura 9e18f26aeb Restructure Elixir to avoid Python path hacks
* Move static files from http to a new directory
2024-08-27 11:33:18 +02:00

247 lines
7.6 KiB
JavaScript

"use strict";
function identUrl(project, ident, version, family) {
return `/api/ident/${project}/${ident}?version=${version}&family=${family}`;
}
/*
"definitions": [
{
"path": "arch/x86_64/kstat.h",
"line": 1,
"type": "struct"
}
],
"references": [
{
"path": "src/stat/fstatat.c",
"line": "78,142",
"type": null
}
],
"documentations": [
{
"path": "Documentation/devicetree/bindings/arm/arm,cci-400.yaml",
"line": "15,17,18",
"type": null
}
]
*/
function generateSymbolDefinitionsHTML(symbolDefinitions, project, version) {
let result = "";
let typesCount = {};
let previous_type = "";
if(symbolDefinitions.length == 0) {
return '<h2>No definitions found in the database</h2>';
}
for(let symbolDefinition of symbolDefinitions) {
if (symbolDefinition.type in typesCount) {
typesCount[symbolDefinition.type] += 1;
} else {
typesCount[symbolDefinition.type] = 1;
}
}
for (let sd of symbolDefinitions) {
if (sd.type != previous_type) {
if (previous_type != '') {
result += '</ul>';
}
result += '<h2>Defined in ' + typesCount[sd.type].toString() + ' files as a ' + sd.type + ':</h2>';
result += '<ul>';
previous_type = sd.type;
}
let ln = sd.line.toString().split(',');
if (ln.length == 1) {
let n = ln[0];
result += `<li><a href="/${project}/${version}/source/${sd.path}#L${n}"><strong>${sd.path}</strong>, line ${n} <em>(as a ${sd.type})</em></a>`;
} else {
if (symbolDefinitions.length > 100) {
let n = ln.length;
result += `<li><a href="/${project}/${version}/source/${sd.path}#L${ln[0]}"><strong>${sd.path}</strong>, <em>${n} times</em> <em>(as a ${sd.type})</em></a>`;
} else {
result += `<li><a href="/${project}/${version}/source/${sd.path}#L${ln[0]}"><strong>${sd.path}</strong> <em>(as a ${sd.type})</em></a>`;
result += '<ul>';
for(let n of ln) {
result += `<li><a href="/${project}/${version}/source/${sd.path}#L${n}">line ${n}</a></li>`;
}
result += '</ul>';
}
}
}
result += '</ul>';
return result;
}
function generateSymbolReferencesHTML(symbolReferences, project, version) {
let result = "";
if(symbolReferences.length == 0) {
return '<h2>No references found in the database</h2>';
}
result += '<h2>Referenced in ' + symbolReferences.length.toString() + ' files:</h2>';
result += '<ul>';
for (let sr of symbolReferences) {
let ln = sr.line.split(',');
if (ln.length == 1) {
let n = ln[0];
result += `<li><a href="/${project}/${version}/source/${sr.path}#L${n}"><strong>${sr.path}</strong>, line ${n}</a>`;
} else {
if(symbolReferences.length > 100) {
let n = ln.length;
result += `<li><a href="/${project}/${version}/source/${sr.path}#L${ln[0]}"><strong>${sr.path}</strong>, <em>${n} times</em></a>`;
} else {
result += `<li><a href="/${project}/${version}/source/${sr.path}#L${ln[0]}"><strong>${sr.path}</strong></a>`;
result += '<ul>'
for(let n of ln) {
result += `<li><a href="/${project}/${version}/source/${sr.path}#L${n}">line ${n}</a>`
}
result += '</ul>'
}
}
}
result += '</ul>'
return result;
}
function generateDocCommentsHTML(symbolDocComments, project, version) {
let result = "";
if (symbolDocComments.length == 0) {
return result;
}
result += '<h2>Documented in ' + symbolDocComments.length.toString() + ' files:</h2>';
result += '<ul>';
for(let sd of symbolDocComments) {
let ln = sd.line.split(',');
if(ln.length == 1) {
let n = ln[0];
result += `<li><a href="/${project}/${version}/source/${sd.path}#L${n}"><strong>${sd.path}</strong>, line ${n}</a>`;
} else {
if(symbolDocComments.length > 100) {
let n = ln.length;
result += `<li><a href="/${project}/${version}/source/${sd.path}#L${ln[0]}"><strong>${sd.path}</strong>, <em>${n} times</em></a>`;
} else {
result += `<li><a href="/${project}/${version}/source/${sd.path}#L${ln[0]}"><strong>${sd.path}</strong></a>`;
result += '<ul>';
for(let n of ln) {
result += `<li><a href="/${project}/${version}/source/${sd.path}#L${n}">line ${n}</a>`;
}
result += '</ul>';
}
}
}
result += '</ul>';
return result;
}
function generateReferencesHTML(data, project, version) {
let symbolDefinitions = data["definitions"];
let symbolReferences = data["references"];
let symbolDocumentations = data["documentations"];
return '<div class="lxrident">' +
generateSymbolDefinitionsHTML(symbolDefinitions, project, version) +
generateDocCommentsHTML(symbolDocumentations, project, version) +
generateSymbolReferencesHTML(symbolReferences, project, version) +
'</div>';
}
function showPopup(referencePopup, target) {
let targetRect = target.getBoundingClientRect();
let x = target.offsetLeft;
let y = target.offsetTop + targetRect.height;
referencePopup.style.visibility = "visible";
referencePopup.style.display = "block";
referencePopup.style.left = `${x}px`;
referencePopup.style.top = `${y}px`;
referencePopup.scrollTop = 0;
referencePopup.scrollLeft = 0;
let referenceRect = referencePopup.getBoundingClientRect();
if((referenceRect.top + referenceRect.height) > window.innerHeight) {
referencePopup.style.top = `${target.offsetTop - referenceRect.height}px`;
}
if((referenceRect.left + referenceRect.width) > window.innerWidth) {
x -= ((referenceRect.left + referenceRect.width) - window.innerWidth);
referencePopup.style.left = `${x}px`;
}
}
function hidePopup(referencePopup) {
referencePopup.style.visibility = "hidden";
referencePopup.style.display = "none";
}
document.addEventListener("DOMContentLoaded", _ => {
let referencePopup = document.getElementById("reference-popup");
let loadingPopup = document.getElementById("loading-popup");
var loadingTimer;
var popupId = 0;
var abortController;
document.body.querySelectorAll(".ident").forEach(el => {
el.addEventListener("click", async ev => {
if (ev.ctrlKey || ev.metaKey || ev.shiftKey) {
return;
}
ev.preventDefault();
let splitPath = ev.target.pathname.split("/");
let [_, project, version, family, _i, ident] = splitPath;
let currentPopupId = ++popupId;
if(abortController !== undefined)
abortController.abort();
abortController = new AbortController();
hidePopup(loadingPopup);
clearTimeout(loadingTimer);
loadingTimer = setTimeout(() => {
showPopup(loadingPopup, ev.target);
}, 200);
function cancelLoadingPopup() {
if (currentPopupId == popupId) {
hidePopup(loadingPopup);
clearTimeout(loadingTimer);
}
}
try {
let result = await fetch(identUrl(project, ident, version, family),
{ signal: abortController.signal })
.then(r => r.json());
if(currentPopupId == popupId) {
referencePopup.innerHTML = generateReferencesHTML(result, project, version);
showPopup(referencePopup, ev.target);
}
} catch(e) {
if(e.name !== "AbortError") {
cancelLoadingPopup();
throw e;
}
}
cancelLoadingPopup();
});
});
referencePopup.addEventListener("click", ev => ev.stopPropagation());
document.body.addEventListener("click", _ => hidePopup(referencePopup));
document.body.addEventListener("keydown", ev => {
if (ev.key === "Escape") {
hidePopup(referencePopup);
}
});
});