web_python_editor/editor.js

92 lines
2.7 KiB
JavaScript

// 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))
});