The introduction
In the last post, we showed how Quill uses Delta to describe editor content and its variations. We learned that Delta is just a normal JSON structure with only three actions and one attribute, but it is extremely expressive.
So how does Quill apply Delta data and render it into the editor?
How to use setContents
There is an API in Quill called setContents that renders Delta data into the editor. This post will focus on how this API is implemented.
Take the Delta data from the previous post as an example:
const delta = { "ops": [
{ "insert": "Hello " },
{ "insert": "World", "attributes": { "bold": true } },
{ "insert": "\n" } ]
}
Once we have created an instance of Quill using new Quill(), we can call its API.
const quill = new Quill('#editor', {
theme: 'snow'
});
Let's try calling the setContents method, passing in the Delta data we just had:
quill.setContents(delta);
The expected formatted text appears in the editor:
Deep into setContents
By looking at the source of setContents, we call the modify method, passing in a function:
setContents(delta, source = Emitter.sources.API) {
return modify.call( this, () => {
delta = new Delta(delta);
const length = this.getLength();
const deleted = this.editor.deleteText(0, length);
const applied = this.editor.applyDelta(delta);
... // The non-core code is omitted for ease of reading
return deleted.compose(applied);
}, source, );
}
The call method is used to call modify to change its internal this pointer, which refers to the current Quill instance. Since the modify method is not defined in the Quill class, it needs to be done.
Let's look at the anonymous function passed in the modify method instead of the modify method.
This function does three main things:
- Delete all the original content in the editor
- Apply the incoming Delta data and render it to the editor
- Returns the Delta data after combining 1 and 2
Let's focus on step 2, which involves the applyDelta method of the Editor class.
How the applyDelta method works
As you might guess by its name, the purpose of this method is to apply and render the incoming Delta data into the editor.
The implementation, as we can probably guess, is that the ops array in the loop Delta is applied to the editor one by one.
Its source code is 54 lines long and looks something like this:
applyDelta(delta) {
let consumeNextNewline = false;
this.scroll.update();
let scrollLength = this.scroll.length();
this.scroll.batchStart();
const normalizedDelta = normalizeDelta(delta);
normalizedDelta.reduce((index, op) => {
const length = op.retain || op.delete || op.insert.length || 1;
let attributes = op.attributes || {};
// 1.Insert text
if (op.insert != null) {
if (typeof op.insert === 'string') {
// Plain text content
let text = op.insert;
... // For ease of reading, omit non-core code
this.scroll.insertAt(index, text);
... // For ease of reading, omit non-core code
} else if (typeof op.insert === 'object') {
// Rich text content
const key = Object.keys(op.insert)[0];
// There should only be one key
if (key == null) return index;
this.scroll.insertAt(index, key, op.insert[key]);
}
scrollLength += length;
}
// 2.Formatting the text
Object.keys(attributes).forEach(name => {
this.scroll.formatAt(index, length, name, attributes[name]);
});
return index + length;
}, 0);
... // For ease of reading, omit non-core code
this.scroll.batchEnd();
this.scroll.optimize();
return this.update(normalizedDelta);
}
As we guessed, this method is to use the Delta reduce method to iterate over the incoming Delta data, separating the logic of content insertion and content deletion. The iteration of content insertion mainly does two things:
- To insert plain text or rich text content: insertAt
- Formats the text: formatAt
At this point, we have parsed the logic to apply and render the Delta data to the editor.
Summary
Here's a summary:
- There's no logic in the setContents method itself, it just calls the modify method, right
- The applyDelta method on the Editor object is called in the anonymous function passed to the modify method
- The applyDelta method iterates over the incoming Delta data and in turn inserts/formats/deletes the editor content described by the Delta data
About DevUI team
DevUI is a team with both design and engineering perspectives, serving for the DevCloud platform of Huawei Cloud and several internal middle and background systems of Huawei, serving designers and front-end engineers.
Official website: devui.design
Ng component library: ng-devui (Welcome to star🌟)
by Kagol
Top comments (0)