I'm trying to create a code editor for a programming language that I made. I'm using a contenteditable <pre>
for the code so that I can style it using JavaScript. However, when I style it, the cursor position goes to the start. I would prefer if it didn't. I would also prefer if I didn't have to use any libraries like JQuery or Codemirror. Here is my code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>SCLIL editor</title>
<style>
* {
margin: 0;
}
html,
body {
width: 100%;
height: 100%;
}
pre {
min-height: 100%;
outline: 0;
padding: 10px;
background-color: #333;
color: #fff;
}
</style>
</head>
<body>
<pre contenteditable>
with background-colour=white
with foreground-colour=red
with font-style=bold,italic
say What is your name?
with foreground-colour=green
with space-after=true
with var=name
ask >
say Your name is $name.
with var=names-exists
file-exists names.txt
function write-to-names
with var=names
read-file names.txt
with var=names
append-line $name
with var=names
write-to-file names.txt
:function.done
if names-exists=true
do write-to-names
:if.done
if names-exists=false
with to-write=$null
with var=$to-write
write-to-file names.txt
do write-to-names
:if.done
say Exit?
with space-after=true
with var=exit
ask >
with var=exit
is-yes-like $exit
if exit=true
exit
:if.done
say Time to add some numbers.
say What is the first number?
with space-after=true
with var=first
ask >
say What is the second number?
with space-after=true
with var=second
ask >
say What is the third number?
with space-after=true
with var=third
ask >
with var=sum
sum $first $second $third
say The result is $sum.</pre
>
<script>
String.prototype.r = function (k, v) {
return this.split(k).join(v);
};
String.prototype.k = function (k, c, it = false, b = false) {
let nt = this.split("\n");
this.split("\n").forEach((line, i) => {
let nl = line.split(" ");
line.split(" ").forEach((word, i) => {
if (word == k) {
nl[i] = `${it ? "<i>" : ""}${
b ? "<b>" : ""
}<span style="color: ${c}">${k}</span>${b ? "</b>" : ""}${
i ? "</i>" : ""
}`;
}
});
nt[i] = nl.join(" ");
});
return nt.join("\n");
};
setInterval(() => {
const pre = document.querySelector("pre"),
code = pre.innerText
.r("&", "&")
.r("<", "<")
.r(">", ">")
.k("say", "#ed7d31")
.k("ask", "#70ad47")
.k("with", "#7030a0")
.k("function", "#7030a0")
.k("if", "#7030a0")
.k("do", "#7030a0")
.k("file-exists", "#c00000")
.k("read-file", "#c00000")
.k("write-to-file", "#c00000")
.k("append-line", "#4472c4")
.k(":function.done", "#00b0f0", true)
.k(":if.done", "#00b0f0", true)
.k("is-yes-like", "yellow")
.k("sum", "yellow")
.k("exit", "#ffc000", false, true);
pre.focus();
const sn = getSelection().anchorNode,
sp = getSelection().anchorOffset,
en = getSelection().focusNode,
ep = getSelection().focusOffset;
pre.innerHTML = code;
getSelection().setBaseAndExtent(sn, sp, en, ep);
});
</script>
</body>
</html>