"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 '
No definitions found in the database
';
}
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 += '';
}
result += 'Defined in ' + typesCount[sd.type].toString() + ' files as a ' + sd.type + ':
';
result += '';
return result;
}
function generateSymbolReferencesHTML(symbolReferences, project, version) {
let result = "";
if(symbolReferences.length == 0) {
return 'No references found in the database
';
}
result += 'Referenced in ' + symbolReferences.length.toString() + ' files:
';
result += '';
for (let sr of symbolReferences) {
let ln = sr.line.split(',');
if (ln.length == 1) {
let n = ln[0];
result += `- ${sr.path}, line ${n}`;
} else {
if(symbolReferences.length > 100) {
let n = ln.length;
result += `
- ${sr.path}, ${n} times`;
} else {
result += `
- ${sr.path}`;
result += '
'
for(let n of ln) {
result += `- line ${n}`
}
result += '
'
}
}
}
result += '
'
return result;
}
function generateDocCommentsHTML(symbolDocComments, project, version) {
let result = "";
if (symbolDocComments.length == 0) {
return result;
}
result += 'Documented in ' + symbolDocComments.length.toString() + ' files:
';
result += '';
for(let sd of symbolDocComments) {
let ln = sd.line.split(',');
if(ln.length == 1) {
let n = ln[0];
result += `- ${sd.path}, line ${n}`;
} else {
if(symbolDocComments.length > 100) {
let n = ln.length;
result += `
- ${sd.path}, ${n} times`;
} else {
result += `
- ${sd.path}`;
result += '
';
for(let n of ln) {
result += `- line ${n}`;
}
result += '
';
}
}
}
result += '
';
return result;
}
function generateReferencesHTML(data, project, version) {
let symbolDefinitions = data["definitions"];
let symbolReferences = data["references"];
let symbolDocumentations = data["documentations"];
return '' +
generateSymbolDefinitionsHTML(symbolDefinitions, project, version) +
generateDocCommentsHTML(symbolDocumentations, project, version) +
generateSymbolReferencesHTML(symbolReferences, project, version) +
'
';
}
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);
}
});
});