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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more