mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-02-24 04:00:59 +01:00
feat: improve code-block ux
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user