My initial impressions of rich text editors may rest with editors like UEditor and CKEditor, as shown below

When I joined Workitle in 2018, I was introduced to the online disk function in Worktile. I felt that the online disk was very good. Markdown syntax allows you to write well-structured articles without having to worry about typography

Around in August 2019, we began to develop their own knowledge base product PingCode Wiki, and then to online documentation, knowledge base and the rich text editor technology behind have a more profound understanding and the understanding, the rich text editor I was officially into the pit area, also can find the direction of continuous learning and hard work.

Talk about the pitfalls of rich text editors

The acknowledged domain of rich text editors is the existence of sinkholes in the front end.

To sum up, there is a contradiction:

The contradiction between backward productivity and people’s increasing demand

Backward productivity:

  1. Standards for editorial content are moving slowly
  2. Different browser vendors implement the same operations or scenarios, causing compatibility problems
  3. There are too many uncontrollable situations using the HTML DOM to describe rich text content

A growing need:

  1. Uncertain interaction intentions, such as pressing the Delete key, and different focus positions have different situations to consider
  2. The variety of content input, such as typing, pasting, dragging and dropping, can be quite complex to handle
  3. A large number of interception and proxy browser default behavior to ensure data integrity and correctness
  4. Users have higher and higher requirements for the use of editors, such as merging cells, multi-level nesting of lists, collaborative editing, version comparison, and paragraph annotation. Everyone thinks that these are basic requirements, but in fact, the technical difficulty is beyond everyone’s imagination.

Open source rich text editor technology

Although the standard is not perfect, editor technology can be precipitated and developed through open source. Here, I mainly introduce the changes and development of editor in the past 10 years from the perspective of technical implementation and the evolution of programming ideas.

Here are a few editors:

CKEditor 1-4 (2008)

UEditor (2012)

Quill. Js (2012).

CKEditor 5 (2014)

Prosemirror (2015).

Draft. Js (2015).

Slate (2016).

Since it takes several months or even half a year to understand each editor, I would like to talk about my understanding of these editors, introduce their characteristics and the differences between them, and stop there.

Editor technology stage division

Editor technology is generally divided into three phases

Level 0 (starting from zero for some unknown reason) is the initial stage of the editor and represents the implementation of the older generation of editors

The second stage of Level 1, developed from the first stage, is advanced to a certain extent. It also introduces some mainstream programming ideas and abstracts rich text content to a certain extent

Level 2 Stage 3, completely independent of the browser editing capabilities, independent implementation of cursor and typesetting

Below, I will summarize the stages of the editors for your understanding.

2008 – CKEditor 1-4

CKEditor 1-4 can represent the technical route of traditional editors (UEditor is the main technology of the same type). It mainly relies on the native editing ability of the browser. Input of user content is handled directly by the browser, and processing of bold, italic, and return is realized by capturing the browser events to override the default behavior of the browser. With the help of some DOM nested rules (DTDS) and filtering rules for complex data inputs (such as pasting) to constrain the correctness of data, the overall idea of this kind of editor is relatively clear.

Editable content is dependent on the contentEditable property of the DOM. Native execCommand or custom execCommand extensions are used to manipulate the DOM to modify rich content.

Ps: The diagram above is based on my personal understanding of the architectural concept drawing, may be a little different from the actual

  1. Text entry is basically the default behavior of the browser
  2. Complex style or format operations will enter the interactive judgment logic. If the default behavior does not meet the requirements (for example, the performance of different browsers is inconsistent), the default behavior will be blocked, and the developer can customize the operation, that is, independently implement the DOM or Range update.

The characteristics of

  • Rely on the browser’s native editing capabilities (Level 0)
  • An instruction set based on browser execCommand or an extension
  • Dom-based nesting rules and filtering
  • The output rich text content is an HTML string

advantages

  • Based on the browser’s native editing capabilities, the input is very smooth
  • No IME (combined input) headaches

disadvantages

  • Unpredictable interactions, prone to data clutter (drag and drop, copy and paste, delete)
  • Different browsers may have different implementations of the same operation (such as basic bold, italic, and Enter), making it difficult to achieve complete unification of presentation and data
  • Rich text content with a specific structure (image +Caption) is complex
  • Difficulty in co-editor support (root cause of starting from scratch in CKEditor 5)

Since CKEditor 4 is essentially a direct manipulation of the DOM, based on my understanding of the stages, I put it in the first stage (Level 0), but there should be other editors that use Textarea before that, such as the code editor Codemirror, which are generally in the first stage.

2012 – Quill.js

The most representative editor in 2012 is quill.js. Its emergence brings many new things to rich text editors, and it is also an editor with a large audience among open source editors at present. The number of Github Star is up to 27.7K, and rich text content editing behind graphite documents is realized based on quill.js. Our PingCode Agile originally chose quill.js for its editor technology, which encapsulates an Angular component.

The bottom layer of quill.js still relies on the contentEditable features of the DOM, but Quill abstracts the DOM Tree and data modification operations, which means that editor developers do not modify the DOM directly in most cases. Instead, the model manipulation API was provided by Quill, and the actors became: Delta, Parchment & Blots.

Delta

Quill uses Delta to describe the contents of the editor and its changes. Delta is very concise, but very expressive.

Delta is a subset of JSON that contains only one OPS property, whose value is an array of objects, each entry representing an operation to the editor (based on the editor’s initial empty state).

Here is a rich text description:

Delta is described as follows:

{" ops ": [{" insert" : "Hello"}, {" attributes ": {" bold" : true}, "insert" : "Quill"}, {" insert ":"! "}]}Copy the code

Delta has only three actions and one attribute, which is enough to describe any rich text content and any changes to it.

3 actions:

  • Insert the insert:
  • Retain: keep
  • Delete: delete

1 attributes:

  • Attributes: format attributes

One characteristic of a Delta is that it only describes changes in content, and the final content is made up of a series of changes.

For those of you who are familiar with collaborative editors, the Delta data model should be familiar. Delta is actually an implementation of OT model. OT operation is an idea for collaborative editing, so Quill can be said to be an editor for collaboration.

Parchment & Blots

For the DOM abstraction of Quill. Js, Parchment is actually a structure corresponding to DOM tree. Parchment is composed of Blots and Blot is corresponding to DOM Node. So this layer of model is really an intermediate layer between Delta data and the final UI;

Correspondence:

Editor Container <====> Parchment

DOM Node <====> Blot

With this layer of abstraction, the biggest change is that the content developers directly manipulate has changed from Parchment & Blots to Parchment & Blots that can be strictly constrained, and DOM changes are confined to Blots (and DOM manipulation, of course).

LinkBlot example:

Data form in Delta:

Architecture diagram

  1. While text input is basically the default behavior of the browser, quill.js monitors DOM changes (MutationObserver) and eventually synchronizes DOM changes into Delta model data.
  2. Non-browser default behaviors such as complex style or formatting operations will directly update the Delta model data and the Delta will drive the Parchment & Blots update before the final UI changes.

The characteristics of

  • Rely on the browser’s native editing capabilities (Level 1)
  • The data update subject was Delta and DOM updates were described by separate Parchment & Blots
  • The output data can be either a string of HTML or a series of operations (i.e., JSON) described by Delta, but is rarely saved as result data with poor readability
  • Quill. Js, Parchment and Delta are all independent warehouses with good structure

Since the data model is introduced and the operation of data change is abstracted, the Level 1 stage of quill. js is defined, and the subsequent editors have more or less adopted the implementation ideas of quill. js.

2015 – ProseMirror

The famous Confluence is developed based on ProseMirror, so there should be no doubt about the expansion ability and stability of ProseMirror, because different modules of ProseMirror are stored separately. So I am not quite sure when it was founded (about 2015 according to the description of the community leader).

ProseMirror is also dependent on contentEditable in terms of implementation principles, but what’s great about ProseMirror is that it applies mainstream front-end architectural concepts to editor development, such as completely using pure JSON data to describe rich text content, With the introduction of immutable data and the concept of Virtual DOM, as well as plug-in mechanism, hierarchy, Schemas, etc., ProseMirror is an editor (or framework) with advanced concept and relatively complete system.

JSON describes rich text content

Such as:

JSON is described as follows:

Schemas.

The following is an example of a plugin that uses a Spec to describe the attributes of the node and how to render the contents of the node based on those attributes:

With the data and the corresponding data type paradigm defined, changes from JSON data to the DOM can be completely taken over by ProseMirror, which makes a virtual DOM layer in the middle to do the data to the DOM driver update.

Attrs: user-defined attribute of a storage node

Content: Constraint description of child elements (regular matching)

ToDOM: Definition of DOM rendering based on node data

ParseDOM: Extract the definition of the DOM node attribute of todo-item

React uses JSX to define instructions for rendering the DOM, but it’s not as powerful as JSX.

Transform

ProseMirror have a single module to define and implement the document revision, such content changes are unified, and eventually into the bottom of the atoms (possible) for collaborative editing operation, and can do intercept processing in any plug-ins, such as: record data change operation to implement undo and redo, etc.

Go to ProseMirror and you can have a state graph here:

The front end should look familiar by now:

  1. The concept of immutable data is introduced to unify the modification of content, and the original DOM modification method is changed to the modification of immutable data
  2. React implements a one-way data drive, so the editor has a complete data flow that is stable and controllable.

The characteristics of

  • Rely on the browser’s native editing capabilities (Level 1)
  • Nested document model (different from the OT model of Delta, its document model is a JS object model in the normal sense, and the corresponding model data can be stored directly as the result)
  • Model nesting and rendering rules are agreed upon
  • Unified data update flow, using one-way data flow, immutable data, and virtual DOM to avoid direct DOM manipulation (this does incorporate mainstream functional programming ideas)
  • The output data is pure JSON
  • The only downside I think is that it requires developers to relearn its own paradigm for describing the DOM (as opposed to Slate)

ProseMirror is another effort by CodeMirror authors. The concept is quite new, and in implementation it proxies most of the browser’s default behavior, converting operations into data transformations to update the UI, and is a worthy Level 1 phase.

2015 – Draft.js

Draft.js is the first open source work that combines rich text editor and React. When developing the editor, developers do not need to operate DOM or learn a set of UI construction paradigm. Instead, they can directly write the React component to implement the UI of the editor, which is a huge productivity improvement in a sense. Because draft. js is also an open source framework for the Facebook team like React, the overall concept of Draft.js is very much in line with React and represents the mainstream programming thinking. For example, using state management to save rich text data, using the Immutable. Js library, data modification is almost entirely proxy browser default behavior, through state management to modify rich text data.

Zhihu’s rich text editor is implemented with draft.js

Of course, it has some limitations, because it only serves the React framework rich text editor, which should be very difficult for other frameworks to use.

General situation of Draft

I opened the Demo and tried it out, and found that even this reference or list is implemented using a flat data structure, which distinguishes block types by type;

As you can see, draft.js abstracts the JSON-based data model, but its support for nested data is weak, which is also its weakness.

The characteristics of

  • Rely on the browser’s native editing capabilities (Level 1 Pro)
  • React acts as the UI layer
  • Rich text data management with React (State Management)
  • No doubt draft.js has a lot more stability and detail than other frameworks (Slate) because it doesn’t have any major architectural updates
  • Draft for document data description is too rigid, such as the need to nested nodes of the table is not easy to achieve, even if a table as rich text components embedded in the Draft editor, it has great limitations (such as cells in the basic bold, italic, link can not be achieved with the ability of the editor), So its data model is not perfect.

Because draft. js directly integrates rich text editor development with React, developers extend the editor’s functions to write React components. This is a huge improvement, and uses state management to manage rich text data. So define it as Level 1 Pro for Phase 2.

2016 – Slate

Slate can be said to be the best men in the world editor framework (personal opinion), compared with the introduction of a series of editor it’s appearance is the night, but it also absorbed some experience of other editors, and since the author has the pursuit of perfection, Slate architecture also constantly refactoring to upgrade, at present is still in beta, The latest version is 0.58.x.

Slate has learned a lot from the advantages of Quill, ProseMirror and draft. js. Although Slate is a late starter among the mainstream editors, it is still a popular editor due to its good structure, novel concept and the author’s continuous improvement on the architecture.

Architecture diagram

Slate is what you might call an editor framework. It does not provide out-of-the-box functionality, but only an infrastructure for developing an editor. If you want to implement an editor, you need to implement a series of plug-ins based on this architecture.

The characteristics of

  1. Rely on the browser’s native editing capabilities (Level 1 Pro)
  2. Shchema defines data constraint rules (ProseMirror)
  3. Nest Data Model (ProseMirror)
  4. React as a View layer (draft.js)
  5. Plug-ins are first-class citizens, and developers have a lot of control over interactions (draft.js)
  6. Immutable, uniform data changes Commands (draft.js)

The Slate of this period was more of a shadow of other editors, the best of all.

Take a look at the original Slate data:

2018 – Slate Core

  1. Extract a separate view layer that no longer relies heavily on React

This makes it possible for The Angular/Vue framework to use the Slate framework, but there is a certain threshold because you need to re-implement a view layer

As noted in Slate’s Issue, the Angular view layer will not be officially available now or for a long time to come.

Slate data at this point:

There are some optimizations in the structure compared to the original.

Architecture diagram

2019 – Slate Migration

At the end of 2019, Slate launched a major architectural upgrade of its own, called a major overhaul (0.50.x). First, iT reimplements all TypeScript code, and second, it simplifies the complex plugin mechanism. The immutable data model is also changed to a simpler and more novice friendly Immer, which also separates the view layer from the core implementation. Although there are still many defects, including Chinese input and browser compatibility problems, it has been found that these can be fixed in the view layer.

Architecture diagram

The characteristics of

  1. Very compact data model
  2. Designed a set of editor business Hook with high abstraction, business side can rewrite and expand, can be used as a substitute for plug-in, it is very easy to understand and debug
  3. Use Immer as an immutable data model
  4. Coding ideas using pure function + interface, ideas and code are very simple

Data from the latest Slate:

The simplest structure by far

While Slate is the best of the best and is constantly being upgraded, it still relies on the editable capabilities of the browser and has to do a lot of careful work on how to synchronize Slate behavior with the browser’s default behavior. Chinese input processing is still a headache. So it’s essentially Level 1 Pro.

2021 – Slate

Slate has been reconfigured with TypeScript, and its API style and concepts are simpler and friendlier to beginners. The community has been more responsive to Slate, especially Slate plugins. Slate itself is improving support for TypeScript generics, as well as support for multiple editors, iframe, Android, collaboration, and more.

The future of editors

The future is already here. In 2010, Google Doc introduced a new technology to implement a rich text editor, which is often referred to as Level 2. The rich text editor is capable of independent typesetting of text without relying on any browser editing functions. There is just no open source technology based on this architecture.

Although the independent implementation of typesetting can solve many existing problems, but the implementation is too difficult, small companies can not afford this cost. Therefore, browser-based solutions for ContentedItable technologies remain the best option for the time being. With the standardization of content input events and the development of technology, many existing problems can be gradually solved, so Contenteditable is the future of editing.

conclusion

Thanks to the open source technology, the practical experience of editors has been extended and developed. There is no absolute good or bad, and each editor has its own characteristics. CKEditor has the longest development time, and its technical path is clear and can be found. From CKEditor 4 to CKEditor 5, it has undergone a complete reconstruction, fundamentally solving the problem of collaborative editing. Quill.js can also be called an old editor, with a large audience. ProseMirror is a very stable editor, and has been compared to Slate, which Confluence does. Slate, which is the latest in a long line of refactoring, has a very elegant and concise architecture with TypeScript. The feeling is very strong momentum, are very worth learning.

Finally, take a look at the history of the open source rich text editor with a timeline

Finally, slate-Angular

Personally, I like Slate framework very much. Our team’s front-end stack is Angular. In order to use Slate in Angular, we developed the Angular view layer Slate-Angular based on the official Slate-React. Personally, developing an Angular view layer is a very interesting process, and there is currently no implementation of the Angular Slate editor in the open source community, so we wanted to open source our practice and give back to the Slate and Angular community. Let more Angular developers develop rich text editors using Slate.

PingCode Wiki has been running steadily for over a year. The original version is based on [email protected] (JavaScript version SLATE). The second version is based on the latest Slate implementation (TypeScript). Currently, the third version has been prepared since the beginning of this year, including opening the Github repository, unifying the underlying implementation and API style, and building online demos.

Github:github.com/worktile/sl…

The Live Demo: slate-angular.ngnice.com/

Feel free to Issue slate-Angular if you have any questions!