// Kyler Olsen // November 2023 class PythonEditor{ constructor(ele) { this.element = ele; this.element.addEventListener("input", this.textInput.bind(this)); this.element.addEventListener("keydown", this.handleKeyDown.bind(this)); this.view_code = document.createElement("code"); this.edit_code = document.createElement("code"); this.view_pre = document.createElement("pre"); this.edit_pre = document.createElement("pre"); this.edit_code.contentEditable = true; this.edit_code.spellcheck = false; this.view_pre.classList.add("view-code"); this.edit_pre.classList.add("edit-code"); this.view_pre.appendChild(this.view_code); this.edit_pre.appendChild(this.edit_code); this.element.appendChild(this.view_pre); this.element.appendChild(this.edit_pre); } textInput(e) { let text = this.edit_code.innerHTML; syntax_highlight(text).forEach(ele => this.view_code.appendChild(ele)); } handleKeyDown(e) { if (e.key === "Tab") { e.preventDefault(); insertTab(e.target); } } } function insertTab() { const selection = window.getSelection(); if (selection.rangeCount > 0) { const range = selection.getRangeAt(0); const startOffset = range.startOffset; const lineStart = range.startContainer.textContent.lastIndexOf('\n', startOffset - 1) + 1; const spacesToAdd = 4 - ((startOffset - lineStart) % 4); const tabSpaces = ' '.repeat(spacesToAdd); const tabNode = document.createTextNode(tabSpaces); range.deleteContents(); range.insertNode(tabNode); range.setStartAfter(tabNode); range.setEndAfter(tabNode); selection.removeAllRanges(); selection.addRange(range); } } function syntax_highlight(text) { const whitespace = " \n\t"; const string_start = `'"`; const elements = []; var char = text.substr(0, 1); text = text.substr(1); while (text.length) { const element = document.createElement("span"); var token_type = ""; if (whitespace.includes(char)) token_type = "whitespace"; else if (string_start.includes(char)) token_type = "string"; while (text.length) { if (token_type == "whitespace" && !whitespace.includes(char)) break; element.innerText.concat(char); char = text.substr(0, 1); text = text.substr(1); } elements.push(element); } return elements; } document.addEventListener('DOMContentLoaded', () => { document.querySelectorAll(".code").forEach(ele => new PythonEditor(ele)) });