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";
  };
}