profoundjs
Version:
Profound.js Framework and Server
211 lines (193 loc) • 6.72 kB
JavaScript
let slider, stepSpan, fileDropdown, codeContainer, transformedCodeButton, coverageButton, currentStep, currentStepNumber, stepListDiv;
// eslint-disable-next-line no-unused-vars
function init() {
slider = document.querySelector("input.log-slider");
stepSpan = document.querySelector("span.step");
fileDropdown = document.querySelector("select.file-dropdown");
codeContainer = document.querySelector("div.code-container");
transformedCodeButton = document.querySelector("button.transformed-code-button");
coverageButton = document.querySelector("button.coverage-button");
stepListDiv = document.querySelector("div.step-list");
fileDropdown.onchange = function() {
const entry = vlog[fileDropdown.value];
loadCode(entry.lines, entry.map);
slider.focus();
};
transformedCodeButton.onclick = showTransformedCodeButtonClick;
coverageButton.onclick = showCoverage;
loadFiles();
const max = vlog.log.length;
slider.max = max;
slider.value = max;
changeStep(max);
slider.oninput = changeStep;
slider.focus();
}
function changeStep(stepNumber) {
stepListDiv.style.display = "none";
let text = "";
if (typeof stepNumber !== "number") stepNumber = Number(this.value);
text = "Step " + stepNumber;
stepSpan.innerText = text;
const step = vlog.log[stepNumber - 1];
if (!step) return;
currentStep = step;
currentStepNumber = stepNumber;
setFile(step.file);
const transformedView = (transformedCodeButton.innerText !== "Show Tranformed Code");
// Remove old current-line
let curLine = codeContainer.querySelector("pre.current-line"); // get old current line
if (curLine) {
let contentEl = curLine.querySelector(".jscode");
if (!contentEl) contentEl = curLine;
curLine.classList.remove("current-line");
const lineNumberStr = contentEl.innerHTML.split(":")[0] + ": ";
let lines;
if (transformedView) lines = vlog[fileDropdown.value].transformedLines;
else lines = vlog[fileDropdown.value].lines;
const lineNumber = Number(lineNumberStr.trim().split(":")[0]);
const line = lines[lineNumber - 1].split("pjs.log(")[0];
contentEl.innerHTML = lineNumberStr + hiLine(line);
}
// Set new current-line
curLine = codeContainer.querySelector(`pre:nth-child(${step.lineNum})`);
if (curLine) {
let contentEl = curLine.querySelector(".jscode");
if (!contentEl) contentEl = curLine;
const lineNumberStr = contentEl.innerHTML.split(":")[0] + ": ";
// const line = step.line;
if (!transformedView) contentEl.innerHTML = lineNumberStr + hiLine(step.line);
curLine.classList.add("current-line");
setTimeout(function() {
curLine.scrollIntoView({
behavior: "smooth",
block: "center"
});
}, 0);
}
}
function hiLine(line) {
return "<code>" + hljs.highlight(line, { language: "JavaScript" }).value + "</code>";
}
function loadFiles() {
for (file in vlog) {
if (file === "log") continue;
fileDropdown.options.add(new Option(file));
}
// Load last file
fileDropdown.value = file;
const entry = vlog[file];
loadCode(entry.lines, entry.map);
}
function setFile(file) {
if (fileDropdown.value === file) return;
fileDropdown.value = file;
const entry = vlog[file];
loadCode(entry.lines, entry.map);
}
function showTransformedCodeButtonClick() {
const entry = vlog[fileDropdown.value];
if (!entry) return;
if (transformedCodeButton.innerText === "Show Tranformed Code") {
loadCode(entry.transformedLines, entry.map, true);
}
else {
loadCode(entry.lines, entry.map);
}
if (currentStep && currentStep.file === fileDropdown.value) {
changeStep(currentStepNumber);
}
slider.focus();
}
function loadCode(lines, map, transformed) {
codeContainer.innerHTML = "";
if (!lines) return;
const lineNumWidth = String(lines.length).length;
for (let i = 0; i < lines.length; i++) {
let line = lines[i];
if (transformed) line = line.split("pjs.log(")[0];
const pre = document.createElement("pre");
const lineNumber = i + 1;
const lineNumberStr = (" " + lineNumber).substr(-lineNumWidth) + ": ";
let html = lineNumberStr + hiLine(line);
if (map) {
let prevMapEntry = map[i - 1];
if (!prevMapEntry) prevMapEntry = {};
const mapEntry = map[i];
let rpgLine = "";
if (mapEntry && mapEntry.lineNum && prevMapEntry.lineNum !== mapEntry.lineNum) {
const rpgLineNumberStr = (" " + mapEntry.lineNum).substr(-6) + ": ";
rpgLine = rpgLineNumberStr + mapEntry.code;
}
html = `
<div class="jscode">${html}</div>
<div class="rpgcode">${rpgLine}</div>
`;
}
pre.innerHTML = html;
codeContainer.appendChild(pre);
}
if (transformed) {
transformedCodeButton.innerText = "Show Original Code";
}
else {
transformedCodeButton.innerText = "Show Tranformed Code";
}
}
function showCoverage() {
const covered = {};
const lineEls = codeContainer.children;
const log = vlog.log;
for (let i = 0; i < log.length; i++) {
const step = log[i];
if (step.file !== fileDropdown.value) continue;
if (!covered[step.lineNum - 1]) covered[step.lineNum - 1] = [];
step.stepNumber = i + 1;
covered[step.lineNum - 1].push(step);
}
for (let i = 0; i < lineEls.length; i++) {
const el = lineEls[i];
if (covered[i]) {
el.classList.add("covered");
el.steps = covered[i];
setupMouseOver(el);
}
}
slider.focus();
}
// eslint-disable-next-line no-unused-vars
function hideCoverage() {
const lineEls = codeContainer.children;
for (let i = 0; i < lineEls.length; i++) {
const el = lineEls[i];
el.classList.remove("covered");
el.onmouseover = function() {};
}
}
function setupMouseOver(el) {
el.onmouseover = function(e) {
const steps = el.steps;
let html = "";
steps.forEach(step => {
const line = step.line;
const parts = line.split("//");
html += `<a href="JavaScript:changeStep(${step.stepNumber}); hideCoverage(); slider.value = ${step.stepNumber}; slider.focus();">
Step ${step.stepNumber}
</a>
-
<span class="step-details">
//${parts[parts.length - 1]}
</span>
<br/>`;
});
stepListDiv.innerHTML = html;
stepListDiv.style.left = e.clientX + 5 + "px";
stepListDiv.style.top = e.clientY - 5 + "px";
stepListDiv.style.display = "";
};
el.onmouseout = stepListDiv.onmouseout = function(e) {
const toElement = e.toElement || e.relatedTarget;
if (toElement === stepListDiv || stepListDiv.contains(toElement)) return;
stepListDiv.style.display = "none";
};
}