Skip to content

Instantly share code, notes, and snippets.

@itsmikita
Last active November 1, 2023 09:50
Show Gist options
  • Save itsmikita/41d1b8f7c70cf9008726 to your computer and use it in GitHub Desktop.
Save itsmikita/41d1b8f7c70cf9008726 to your computer and use it in GitHub Desktop.
Enables simple "coding" features (tabbing and auto-closing tags) to a textarea
/**
* Simplify your <textarea> life!
*
* This script enables tabbing (2 spaces) on textareas with class '.code'.
* It also auto-closes basic HTML tags.
*
* Enjoy your coffee!
*
* @author Mikita Stankiewicz <[email protected]>
*
* NEU: Removed jQuery and refactored the code to TypeScript.
* WARNING! Not tested, use at your own risk!
*/
class Code_Edit {
private textarea: HTMLTextAreaElement;
private autoClosingTags: string[];
constructor(textarea: HTMLTextAreaElement) {
this.textarea = textarea;
// Tabbing
this.enableTabbing();
// Auto-close tags
// Add more auto-closing tags here
this.autoClosingTags = [
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'a', 'em', 'strong',
'ul', 'ol', 'li',
'table', 'thead', 'tfoot', 'tr', 'td',
'div', 'span', 'section', 'article', 'header', 'footer', 'aside',
'button', 'textarea', 'select', 'option'
];
this.enableAutoCloseTags();
}
/**
* Enable tabbing
*/
enableTabbing() {
this.textarea.addEventListener('keydown', (event) => {
const keyCode = event.keyCode || event.which;
// Tab is '9', ok
if (9 === keyCode) {
event.preventDefault();
const position = this.textarea.selectionStart,
before = this.textarea.value.substr(0, position),
after = this.textarea.value.substr(this.textarea.selectionEnd, this.textarea.value.length);
const tab = " ";
this.textarea.value = before + tab + after;
this.textarea.selectionStart =
this.textarea.selectionEnd = position + tab.length;
this.textarea.focus();
}
// Enter is '13'
if (13 === keyCode) {
const position = this.textarea.selectionStart,
before = this.textarea.value.substr(0, position),
after = this.textarea.value.substr(this.textarea.selectionEnd, this.textarea.value.length);
const lines = before.split("\n"),
lastLine = lines[lines.length - 1],
indent = lastLine.match(/[\s]{4,}/);
if (!indent)
return;
// Cancel that new line, we add it manually
event.preventDefault();
this.textarea.value = before + "\n" + indent[0] + after;
this.textarea.selectionStart =
this.textarea.selectionEnd = position + indent[0].length + 1;
this.textarea.focus();
}
});
}
/**
* Auto-close tags
*/
enableAutoCloseTags() {
this.textarea.addEventListener('keydown', (event) => {
const keyCode = event.keyCode || event.which;
// Close tag '>'
if (190 === keyCode) {
const position = this.textarea.selectionStart,
before = this.textarea.value.substr(0, position),
after = this.textarea.value.substr(this.textarea.selectionEnd, this.textarea.value.length),
tagName = before.match(/<([^>]+)$/)[1].match(/^([a-z1-6]+)/)[1];
// Not an auto-closing tag
if (-1 === this.autoClosingTags.indexOf(tagName))
return;
const closeTag = '</' + tagName + '>';
this.textarea.value = before + closeTag + after;
this.textarea.selectionStart =
this.textarea.selectionEnd = position;
this.textarea.focus();
}
// Mustache '{'
if (219 === keyCode) {
const position = this.textarea.selectionStart,
before = this.textarea.value.substr(0, position),
after = this.textarea.value.substr(this.textarea.selectionEnd, this.textarea.value.length);
this.textarea.value = before + '}' + after;
this.textarea.selectionStart =
this.textarea.selectionEnd = position;
this.textarea.focus();
}
});
}
}
/**
* Onload
*/
window.addEventListener('DOMContentLoaded', () => {
const textareas = document.querySelectorAll('textarea.code');
textareas.forEach((textarea) => {
new Code_Edit(textarea as HTMLTextAreaElement);
});
});
@itsmikita
Copy link
Author

Psst: Duplicate code here and there, look into enableAutoCloseTags() if you need to add more closing tags, I am too lazy for now..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment