Modern Rich Text Editor: Quill Editor
Introduce
Recently I have been working on content related to rich text editors, and Quill Editor (hereinafter referred to as Quill) is used in the project. Quill claims to be a modern and powerful rich text editor. What makes it different from other rich text editors (such as UEditor) is that the data operated by past editors and the view layer displayed to the user are the same HTML/DOM. HTML It is a tree structure. Obviously, the tree structure is not as easy to process as the linear structure. Quill uses the linear structure internally to make it easy to operate the rich text editor. Moreover, the data layer and the view layer are separated, which makes Quill more suitable for the current situation. The popular React, Vue or Angular are all well supported. Let me briefly introduce the use of Quill:
Easy to get started
Simple example:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Quick Start</title>
<link href="https://cdn.quilljs.com/1.3.2/quill.snow.css" rel="stylesheet">
</head>
<body>
<div id="editor">
<p>Hello World!</p>
<p>Some initial <strong>bold</strong> text</p>
<p><br></p>
</div>
<script src="https://cdn.quilljs.com/1.3.2/quill.js"></script>
<script>
var quill = new Quill('#editor', {
theme: 'snow'
});
</script>
</body>
</html>
Through the above few lines of code, we can see a simple but basic rich text editor in the browser.
Of course, the above is just a very simple text editor, and Quill has built-in support for many rich text operation functions. It provides both UI control and API operations. Here is a complete editor function that comes with Quill:
From the picture above, we can see that these functions have basically met daily rich text editing needs.
In addition, Quill provides two sets of themes and commonly used rich text editor modules:
1. Toolbar
2. Shortcut key binding
3. History
4. Clipboard
5. Formula
6. Syntax highlighting
We can customize the module during initialization or perform extended operations on the module. The specific documentation can be viewed:
Quill Modules
Finally, Quill also provides operation APIs like other text editors:
https://quilljs.com/docs/api/, through the API we can achieve customized needs.
So far we haven’t seen the difference between Quill and other rich text editors, because this is just the beginning. I will introduce the unique features of Quill below.
Delta
As mentioned earlier, HTML has a tree structure. Tree structures are more troublesome to process, and Quill introduces a Delta concept through modification.
Delta is a simple JSON format used to describe rich text content. Through Delta, we can describe text and formatted content even without DOM/HTML, and even describe changes in text content.
Moreover, Delta is linearly structured data, so it is easier to operate.
Here is a rich text content described using Delta:
{
ops: [
{ insert: 'Gandalf', attributes: { bold: true } },
{ insert: ' the ' },
{ insert: 'Grey', attributes: { color: '#cccccc' } },
{ insert: '\n', attributes: { header: 1 } }
]
}
From the above description, we can clearly know that there is such a text “Gandalf the Grey”, in which “Gandalf” is bold, and the color value of “Grey” is “#ccc”, and the last “\n” It represents a line break. What needs to be noted here is that if there is a line break, there are also attributes here. This represents the format of the current line in Quill. It means that this text is wrapped by an h1 tag.
By using Delta to describe rich text content, we can get rid of the dilemma of using HTML to describe rich text content, and Quill also provides very rich api operations for Delta.
In addition, Delta can also describe changes in rich text content, or the text “Gandalf the Grey” is used as an example:
{
ops: [
{ retain: 7, attributes: { bold: null, italic: true } },
{ retain: 5 },
{ insert: "White", attributes: { color: '#fff' } },
{ delete: 4 }
]
}
It is important to learn the concept of Delta, because if we need to add some customized functions, we will most likely need to operate Delta.
For a detailed introduction to Delta, please refer to the official website here
- https://quilljs.com/guides/designing-the-delta-format/
- https://quilljs.com/docs/delta/
Blots & Parchments
There is a concept of blots in Quill. Imagine that a piece of text is a paragraph, which is a block element. This paragraph can contain the following basic elements:
- Block elements (Block), such as titles; block styles, such as line height, indentation, centering, etc.;
-Plain text content (Text), which is a leaf node;
- Inline elements (Inline), such as etc.; inline styles, such as text color, text size, etc.;
- Non-text leaf nodes (Embed), such as pictures and videos;
Blots are composed of these types. In fact, these categories are collectively called Parchment in Quill.
The main function of Parchment is to operate the document model. We can initialize the DOM through the interface it provides, return the specified format or specify tags and scopes, etc. The blots in Quill are all extended by inheriting the classes in Parchment.
For example, if I want to implement the function of adding links and bolding, I can use Parchment:
let Inline = Quill.import('blots/inline');
class BoldBlot extends Inline { }
BoldBlot.blotName = 'bold';
BoldBlot.tagName = 'strong';
class LinkBlot extends Inline {
static create(url) {
let node = super.create();
// Sanitize url if desired
node.setAttribute('href', url);
// Okay to set other non-format related attributes
node.setAttribute('target', '_blank');
return node;
}
static formats(node) {
// We will only be called with a node already
// determined to be a Link blot, so we do
// not need to check ourselves
return node.getAttribute('href');
}
}
LinkBlot.blotName = 'link';
LinkBlot.tagName = 'a';
Quill.register(BoldBlot);
Quill.register(LinkBlot);
let quill = new Quill('#editor-container');
$('#bold-button').click(function() {
quill.format('bold', true);
});
$('#link-button').click(function() {
let value = prompt('Enter link URL');
quill.format('link', value);
});
What the above code implements is that I want to click the specified button to bold and add links to the rich text application.
Being proficient in using Parchment will be very useful (and necessary) if we need to add new functions or personalized functions that Quill does not have in the future. If you want to explain Parchment in depth, it will take a lot of space. I will explain the use of Parchment separately in the next article.
Parchment related information:
- https://quilljs.com/guides/cloning-medium-with-parchment/
- https://github.com/quilljs/parchment
Summary
One disadvantage of Quill is that there are relatively few documents. If we only need basic functions, we don’t need to understand the concepts of API, Delta and Parchment, we just need to simply introduce js and initialize it. But if the design involves personalized functions, we must understand and be familiar with these concepts, and we must view Quill’s source code. Fortunately, Quill’s source code implementation is relatively elegant.
Quill uses a different concept from other rich text editors to express and process rich text, allowing us to get rid of the troubles caused by HTML and DOM, making everything simpler.
Of course, Quill will also have pitfalls. After all, the entire rich text editing is a big pitfall. Some of the problems I’m currently encountering are:
1. Quill uses MutationObserver, which means it will not be supported by some old browsers.
2. Quill’s Range and Selection use native APIs at the bottom. We also know that native Selection/Range is inherently tricky, otherwise no one would implement a set of Selection and Range by themselves.
3. What I just said is that there are too few documents. It is difficult to find in-depth articles on the configuration items of Modules and the use of Parchment. You can only read the source code yourself.
Overall, Quill has brought us a lot of benefits, and I believe Quill will definitely get better and better in the future.