Published
Edited
Mar 29, 2022
Importers
1 star
Insert cell
Insert cell
viewof g = highlightedtextarea({
value: "Insert <code> here...",
spellcheck: false,
height: '150px',
width: "50%",
tabsize: 4,
language: 'html'
})
Insert cell
function highlightedtextarea(config = {}) {
let {value, autocomplete, height="200px", width="100%", maxlength, placeholder, spellcheck, wrap, language="html", tabsize=2} = config;
if (typeof config == "string") value = config;
if (value == null) value = "";
const form = input({
form: html`
<form style="height: ${height}">
<textarea style="display: block; font-size: 0.8em; position: absolute; top: 0; left: 0; z-index: 1; margin: 10px; padding: 10px; border: 1; color: transparent; background: transparent; caret-color: black; overflow: auto; white-space: pre-wrap; resize: none; font: 17px/1.5 monospace; tab-size: ${tabsize}; width: calc(${width} - 32px); height: calc(${height} - 50px);" name=input>${value}</textarea>
<pre aria-hidden="true" style="display: block; font-size: 0.8em; position: absolute; top: 0; left: 0; z-index: 0; margin: 10px; padding: 10px; border: 0; overflow: auto; white-space: pre-wrap; font: 17px/1.5 monospace; tab-size: ${tabsize}; width: calc(${width} - 32px); height: calc(${height} - 50px);"><code class="language-${language}" style="font: 17px/1.5 monospace;">${value.replace(new RegExp("&", "g"), "&amp;").replace(new RegExp("<", "g"), "&lt;")}</code>
</pre>
</form>`,
attributes: {autocomplete, maxlength, placeholder, spellcheck, wrap}
});
Prism.highlightAllUnder(form);
form.output.remove();
form.oninput = (e => {
let text = e.target.value;
let result_element = e.target.parentElement.querySelector("pre > code");
// Handle final newlines
if (text[text.length-1] == "\n") text += " ";
// Update code
result_element.innerHTML = text.replace(new RegExp("&", "g"), "&amp;").replace(new RegExp("<", "g"), "&lt;");
// Syntax Highlight
Prism.highlightElement(result_element);
sync_scroll(e);
})
form.querySelector("textarea").onscroll = sync_scroll;
function sync_scroll(e) {
/* Scroll result to scroll coords of event - sync with textarea */
let result_element = e.target.parentElement.querySelector("pre");
// Get and set x and y
result_element.scrollTop = e.target.scrollTop;
result_element.scrollLeft = e.target.scrollLeft;
}
form.querySelector("textarea").onkeydown = check_tab;
function check_tab(e) {
let code = e.target.value;
if(e.key == "Tab") {
e.preventDefault(); // stop normal
let before_tab = code.slice(0, e.target.selectionStart); // text before tab
let after_tab = code.slice(e.target.selectionEnd, e.target.value.length); // text after tab
let cursor_pos = e.target.selectionEnd + 1; // where cursor moves after tab - moving forward by 1 char to after tab
e.target.value = before_tab + "\t" + after_tab; // add tab char
// move cursor
e.target.selectionStart = cursor_pos;
e.target.selectionEnd = cursor_pos;
}
}
return form;
}
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more