From af619634409a6542cf8eb0e2281e0ac089620adc Mon Sep 17 00:00:00 2001 From: Michael Ochmann Date: Thu, 25 Aug 2022 19:01:17 +0200 Subject: [PATCH] better editor features: * statusbar with percent scrolled and `row:col` info * current line highlights --- playground/index.php | 84 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 78 insertions(+), 6 deletions(-) diff --git a/playground/index.php b/playground/index.php index b0f6f63..a2fbc10 100644 --- a/playground/index.php +++ b/playground/index.php @@ -11,19 +11,44 @@ return elements.length < 2 ? elements[0] : elements; }; - const output = $("#output"); - const input = $("#input"); - const numbers = $(".linenumbers"); - let timeout; + const output = $("#output"); + const input = $("#input"); + const numbers = $(".linenumbers"); + const position = $("#position"); + const percent = $("#percent"); + const editor = $(".editor"); + let lastLine = 1; + let timeout; + let lastSelection; + + const onLineChange = event => { + const start = input.selectionStart; + if (start === lastSelection) + return; + + const linesToCursor = input.value.substr(0, start).split("\n"); + const currentLine = linesToCursor.length; + const char = linesToCursor[linesToCursor.length - 1].length; + const ll = $(`#line_${lastLine}`); + if (ll) + ll.classList.remove("active"); + $(`#line_${currentLine}`).classList.add("active"); + + position.innerHTML = `[${currentLine}:${char}]`; + + lastLine = currentLine; + lastSelection = start; + } const updateOutput = (event) => { const text = event ? event.target.value : input.value; const lines = text.split("\n").length; let html = ""; for (let i = 1; i <= lines; i++) { - html += `${i}
`; + html += `${i}`; } numbers.innerHTML = html; + onLineChange(); timeout = setTimeout(() => { @@ -40,6 +65,9 @@ document.addEventListener("DOMContentLoaded", () => { updateOutput(); + for (event of ["click", "change", "keydown", "focus"]) + input.addEventListener(event, () => onLineChange()); + input.addEventListener("keydown", event => { if (event.key !== "Tab") return; @@ -56,6 +84,16 @@ clearTimeout(timeout); updateOutput(event); }); + + editor.addEventListener("scroll", () => { + const height = input.clientHeight - editor.clientHeight; + const top = editor.scrollTop; + + const fromTop = Math.min(100, Math.max(0, Math.round(top * 100 / height))); + percent.innerHTML = `${fromTop}%`; + + console.log("SCROOLLL", fromTop, height, top); + }); }); window.highlight = (col, row) => { @@ -102,6 +140,7 @@ body { display: grid; grid-template-columns: 1fr 1fr; + grid-template-rows: auto 30px; font-family: sans-serif; margin: 0; padding: 0; @@ -146,28 +185,57 @@ height: 100%; border-right: none; overflow-y: auto; + border-bottom: none; overflow-x: hidden; } .linenumbers { font-size: 1.2rem; text-align: right; - padding: 1rem; + padding: 1rem 0; color: #aaa; font-family: monospace; background: #222; } + .linenumbers span { + display: block; + padding: 0 1rem; + } + .linenumbers span.active { + color: yellow; + background: rgba(255,255,255,0.05); + } + + .statusbar { + font-size: 0.6rem; + line-height: 30px; + padding: 0 1rem; + background: rgba(0,0,0,0.2); + text-align: right; + border: none; + color: #888; + } + + #position { + color: dodgerblue; + font-weight: bold; + } #output { overflow-y: auto; padding: 4rem; max-width: 100%; + grid-row: span 2; } #output code { word-break: break-word; white-space: break-spaces; } + #output table { + width: 100%; + } + #output img { max-width: 100%; height: auto; @@ -395,6 +463,10 @@ Unit tests can be run via `composer`:
+
+ 0% + [1:2] +
\ No newline at end of file