feat: improve code-block ux

This commit is contained in:
thecodrr
2021-10-17 13:04:27 +05:00
parent 28bd768793
commit cb1ccc19e5
3 changed files with 72 additions and 17 deletions

View File

@@ -2,11 +2,13 @@ const {
addPluginToPluginManager,
getCharacterRange,
moveCaretTo,
getCurrentLine,
} = require("../utils");
const { createCodeBlock, isCodeBlock, TAGNAME, state } = require("./utils");
const { addCodeBlockToolbar, refreshHighlighting } = require("./toolbar");
const TAB = " ";
const TAB = `  `;
const TAB_LENGTH = 2;
const EMPTY_LINE = "<p><br></p>";
/**
@@ -44,6 +46,7 @@ var toggleCodeBlock = function (editor, api, type) {
} else {
var content = editor.selection.getContent({ format: "text" }); //.replace(/^\n/gm, "");
if (type === "shortcut") content = "<br>";
if (!content) content = "<br>";
insertCodeBlock(editor, content);
}
};
@@ -81,6 +84,12 @@ function blurCodeBlock(editor, block) {
}
var isCreatingCodeBlock = false;
/**
*
* @param {*} api
* @param {import("tinymce").Editor} editor
* @returns
*/
var registerHandlers = function (api, editor) {
function onNodeChanged(event) {
api.setActive(event.element.tagName === TAGNAME);
@@ -128,13 +137,34 @@ var registerHandlers = function (api, editor) {
// we have to handle all the logic manually.
function onKeyDown(e) {
const node = state.activeBlock;
if (!node || e.code !== "Tab") return;
if (!node) return;
if (e.code === "Tab") {
e.preventDefault();
handleTab(e, node);
} else if (e.ctrlKey && e.code === "KeyA") {
e.preventDefault();
handleCtrlA(node);
} else if (e.code === "Enter") {
handleEnter(node);
}
}
function handleEnter(node) {
const currentLine = getCurrentLine(node);
const indent =
(currentLine.length - currentLine.trimStart().length) / TAB_LENGTH;
editor.insertContent(TAB.repeat(indent));
}
function handleCtrlA(node) {
editor.selection.select(node, true);
}
function handleTab(e, node) {
const characterRange = getCharacterRange(node);
if (!characterRange) return;
e.preventDefault();
// Shift + Tab = Deindent on all major platforms
const isDeindent = e.shiftKey;
const text = node.textContent;
@@ -171,7 +201,7 @@ var registerHandlers = function (api, editor) {
moveCaretTo(node, characterRange.start, endIndex);
} else {
// TODO: handle line deindent
editor.insertContent(TAB);
editor.selection.setContent(TAB);
}
} else {
editor.insertContent(TAB);

View File

@@ -72,7 +72,7 @@ function changeLanguageSelectLabel(text) {
function parseCodeblockLanguage(node) {
if (!node || node.tagName !== TAGNAME) return;
const languageAliases = getLanguageFromClassName(node.className).split("-");
const languageAliases = getLanguageFromClassList(node).split("-");
if (languageAliases.length <= 1) return;
return hljs.getLanguage(languageAliases[1]);
}
@@ -93,26 +93,33 @@ function applyHighlighting(editor, language) {
const alias = language.aliases[0];
persistSelection(node, () => {
node.innerHTML = hljs.highlight(node.innerText, {
const code = hljs.highlight(node.innerText, {
language: alias,
}).value;
});
node.innerHTML = code.value.replace(/\n/gm, "<br>");
editor.save();
});
changeCodeblockClassName(node, ` language-${alias} `);
changeCodeblockClassName(node, `language-${alias}`);
}
function changeCodeblockClassName(node, className) {
node.className = node.className.replace(
getLanguageFromClassName(node.className),
className
);
const language = getLanguageFromClassList(node);
if (!!language)
node.classList.replace(getLanguageFromClassList(node), className);
else node.classList.add(className);
}
function getLanguageFromClassName(className) {
const classes = className.split(" ");
const languageKey = classes.find((c) => c.startsWith("lang"));
return languageKey || "";
/**
*
* @param {Element} node
*/
function getLanguageFromClassList(node) {
for (let className of node.classList.values()) {
if (className.startsWith("language") || className.startsWith("lang"))
return className;
}
return "";
}
function refreshHighlighting(editor) {

View File

@@ -35,6 +35,23 @@ function moveCaretTo(node, index, endIndex) {
rangy.getSelection().restoreCharacterRanges(node, [newCharacterRange]);
}
function getCurrentLine(node) {
const characterRange = getCharacterRange(node);
const lines = node.innerText.split("\n");
let currentLine = "";
let prevLength = 0;
for (let line of lines) {
let length = prevLength + line.length + 1;
if (characterRange.start === length) {
currentLine = line;
break;
}
prevLength += line.length + 1;
}
return currentLine;
}
function persistSelection(node, action) {
let saved = rangy.getSelection().saveCharacterRanges(node);
action();
@@ -52,6 +69,7 @@ function addPluginToPluginManager(name, register) {
}
module.exports = {
getCurrentLine,
getCharacterRange,
moveCaretTo,
persistSelection,