editor.js is a free, block-style (composable) editor with universal JSON output. Hence, it's a nice foundation for building your own rich-text editor.
mathlive is a math editor for the Web, specifically a custom HTML element with functionality to edit math formulas:
<math-field> x^2 + y^2 = 1 </math-field>
editor.js is extensible. Specifically, when creating an editor.js instance, one can provide customized tools to it:
new EditorJS({
holder: editorContainer,
autofocus: true,
tools: {
header: Header,
underline: Underline,
strikethrough: Strikethrough,
list: List,
}
})
These tools are node packages you need to install. As you can see, editor.js is highly modular, which is good because I'm going to add a new tool here. I'm going to show how to build a mathlive tool called Formula for editor.js (and perhaps I'll extract it as a package in the future).
A custom tool requires some basic setup, which is common to all tools
class Formula {
static get toolbox() {
return {
title: "Formula",
icon: "...",
};
}
constructor({ data }) {
this.data = data;
this.wrapper = undefined;
}
}
- A tool is a JS class
- In
toolboxwe can configure the title to show and the icon (which is a string of svg syntax) - We need to restore from data when constructing the tool (when loading from existing JSON!)
- and we need a wrapper (a HTML element) to store the UI of this tool
Then we need to define how to store data into the output JSON, so we define save method
save(blockContent) {
return {
latex: blockContent.value,
};
}
The blockContent is what the render method returns. We'll look at that part now
render() {
this.wrapper = document.createElement("math-field");
this.wrapper.setValue(this.data.latex);
this.wrapper.macros = {
RR: "\\mathbb{R}",
};
this.wrapper.mathVirtualKeyboardPolicy = "sandboxed";
this.wrapper.addEventListener("focusin", (evt) =>
window.mathVirtualKeyboard.show()
);
this.wrapper.addEventListener("focusout", (evt) =>
window.mathVirtualKeyboard.hide()
);
this.wrapper.addEventListener("keydown", (e) => {
const navigationKeys = [
"ArrowLeft",
"ArrowRight",
"ArrowUp",
"ArrowDown",
"Home",
"End",
"Backspace",
"Delete",
"Enter",
"/",
];
if (navigationKeys.includes(e.key)) {
e.stopPropagation();
}
});
return this.wrapper;
}
This function is quite long, but let's break it down
- We assign the HTML element
math-fieldto the wrapper - Set the value of the math-field to the LaTeX formula loaded from data (which can be
undefined) - Define macros for LaTeX input
- Configure the policy and focusin/focusout event handlers to automatically open the virtual keyboard when the user focuses on the math-field
- Add an event listener to intercept keys that would otherwise cause you to lose focus on the math-field (remember that editor.js is an editor, and those keys would trigger other operations in the background editor)
- Finally, we return the wrapper, this HTML element will be the UI element of this tool
At the end, remember you also need to import css of mathlive in HTML
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/mathlive/mathlive-static.css" />
How to package Mathlive JS code depends on your bundler - that's an entirely separate issue that I won't cover here.
Now that the technical details are covered, I can discuss the motivation. Basically, most editors split math formula input into two phases: When you focus on it, it show the original LaTeX syntax so you can edit it. When you focus out, it use KaTeX to render the formula result. But that's messy!
This model makes it easy to miss small problems, that's why there are many small typos in complicated formulas. WYSIWYG is the tool to solve this, and mathlive is such editor I need.
The full plan - though I'm not sure if I'll actually do it - is a complete note-taking system for academic knowledge. Some great tools include forester, Heptabase, Obsidian, etc. However, they all have some rough edges for example
- forester has no editor part (there are some external editor projects though)
- I can't contribute to codebase of Heptabase
- Obsidian's format in long period is problematic
- An Obsidian editor extension can't be ported to non-markdown formats, so notes taken here can't be ported to forester, for example
I have to say these aren't problems with the tools themselves, but I do want a tool that has WYSIWYG + portable format (JSON is good enough) + searchability.
Of course, to keep learning progress of mine, I can't spend all the time on a tool - working on problems and reading papers are much more important for learning.