<textarea name="editor" id="editor"></textarea>
#editor {
tab-size: 4;
}
const editing = document.getElementById("editor");
const keymap = {
"<": { value: "<>", pos: 1 },
"(": { value: "()", pos: 1 },
"{": { value: "{}", pos: 1 },
"[": { value: "[]", pos: 1 },
"'": { value: "''", pos: 1 },
'"': { value: '""', pos: 1 },
"“": { value: "“”", pos: 1 },
"`": { value: "``", pos: 1 },
"‘": { value: "‘’", pos: 1 },
"«": { value: "«»", pos: 1 },
"「": { value: "「」", pos: 1 },
"*": { value: "**", pos: 1 },
_: { value: "__", pos: 1 },
">": { value: "> ", pos: 2 },
"~": { value: "~~", pos: 1 },
",": { value: ", ", pos: 2 }
};
const snipmap = {
// These make no sense but I'll add them for completeness
"1#": "# ",
"2#": "## ",
// These make sense
"3#": "### ",
"4#": "#### ",
"5#": "##### ",
"6#": "###### ",
// Lorem ipsum
Lorem:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime mollitia, molestiae quas vel sint commodi repudiandae consequuntur voluptatum laborum numquam blanditiis harum quisquam eius sed odit fugiat iusto fuga praesentium optio, eaque rerum!"
// Might be a good idea to add a snippet for a tables sometime.
};
function getWord(text, caretPos) {
let preText = text.substring(0, caretPos);
let split = preText.split(/\s/);
return split[split.length - 1].trim();
}
function looksLikeBullet(text, caretPos) {
let bulletRegex = /^([ \t]*[\*\-\+]\s*).*/gim;
let line = text
.substring(0, caretPos)
.split(/\r?\n|\r/)
.pop();
let numberedListRegex = /^([ \t]*\d+\.\s*).*/gim;
if (bulletRegex.test(line)) {
return {
bullet: line.replace(bulletRegex, "$1")
};
} else if (numberedListRegex.test(line)) {
return {
bullet: line
.replace(numberedListRegex, "$1")
.replace(/\d+/, (number) => +number + 1)
};
}
return false;
}
function resize() {
editing.style.height = '24px';
editing.style.height = editing.scrollHeight + 'px';
}
//>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>
editing.addEventListener("keydown", function (event) {
if (keymap[event.key]) {
event.preventDefault();
const pos = editing.selectionStart;
editing.value =
editing.value.slice(0, pos) +
keymap[event.key].value +
editing.value.slice(editing.selectionEnd);
editing.selectionStart = editing.selectionEnd = pos + keymap[event.key].pos;
}
if (event.key === "Tab") {
const word = getWord(editing.value, editing.selectionStart);
if (word && snipmap[word]) {
event.preventDefault();
const pos = editing.selectionStart;
editing.value =
editing.value.slice(0, pos - word.length) +
snipmap[word] +
editing.value.slice(editing.selectionEnd);
editing.selectionStart = editing.selectionEnd =
pos + (snipmap[word].length - 1);
} else {
event.preventDefault();
const pos = editing.selectionStart;
editing.value =
editing.value.slice(0, pos) +
" " +
editing.value.slice(editing.selectionEnd);
editing.selectionStart = editing.selectionEnd = pos + 1;
}
}
if (event.key === "Enter") {
let bullet = looksLikeBullet(editing.value, editing.selectionStart);
if (bullet) {
event.preventDefault();
let addition = editing.value.substring(editing.selectionStart);
editing.value = editing.value.substring(0, editing.selectionStart);
editing.value += "\n" + bullet.bullet + addition;
}
}
resize();
});
editing.addEventListener('input', resize)
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.