Editor
HTML
<div id="editor" contentEditable="true" oninput="change(this)" spellcheck="false">Try typing something. All numbers you type should be green.</div>
CSS
#editor {
position: fixed;
top: 0;
right: 0;
left: 0;
bottom: 0;
padding: 16px;
outline: none;
font-family: monospace;
}
#editor .number {
color: green;
}
JavaScript
function change(element) {
const text = setCursorMarker(element.innerText, element);
const html = manipulate(text);
element.innerHTML = html;
const index = findCursorIndex(element);
document.getSelection().collapse(element, index)
}
function setCursorMarker(text, element) {
const [pos] = getCaretPosition(element)
console.log(pos)
text = text.slice(0, pos + 1) + '<span id="caret-position"></span>' + text.slice(pos + 1, text.length);
return text;
}
function findCursorIndex(element) {
return childIndexInParent(element.children.namedItem('caret-position'))
}
function childIndexInParent(element){
if (element == null) return 0;
let i = 0;
while((element = element.previousSibling) != null) ++i;
return i;
}
function manipulate(str) {
str = str.replace(/([0-9])/g, '<span class="number">$1</span>');
str = str.replace(/(?:\r\n|\r|\n)/g, '<br>');
// your syntax highlighter code...
return str;
}
// Below this line is code from https://stackoverflow.com/a/53128599/10533154
// -------------------------------------
// node_walk: walk the element tree, stop when func(node) returns false
function node_walk(node, func) {
var result = func(node);
for(node = node.firstChild; result !== false && node; node = node.nextSibling)
result = node_walk(node, func);
return result;
}
// getCaretPosition: return [start, end] as offsets to elem.textContent that
// correspond to the selected portion of text
// (if start == end, caret is at given position and no text is selected)
function getCaretPosition(elem) {
var sel = window.getSelection();
var cum_length = [0, 0];
if(sel.anchorNode == elem)
cum_length = [sel.anchorOffset, sel.extentOffset];
else {
var nodes_to_find = [sel.anchorNode, sel.extentNode];
if(!elem.contains(sel.anchorNode) || !elem.contains(sel.extentNode))
return undefined;
else {
var found = [0,0];
var i;
node_walk(elem, function(node) {
for(i = 0;...