One, foreword

We must see this title, the heart can not help but emerge a few questions:

  • What is a rich text editor?

  • What does a rich text editor have to do with a character?

  • Why upgrade ing?

What is rich Text Editor – Rich text editor integrates a series of editing functions such as formatting, media embedding, social interaction, wySIWYG to provide users with a variety of presentation effects. Forums, communities, comments and so on all use rich text editors.

Relationships with Game characters — Rich text editors and game characters have a lot in common. To make the introduction of rich text editors more relevant, this article will use game characters as analogies. As for where the common points are reflected, they will be introduced one by one later.

Why upgrade ING – “upgrade ING” stands for continuous progress, the purpose of this article is to focus on the common problems of rich text editors, hoping to provide some solutions. Rich text editors continue to evolve, and the search for common problems never stops.

This article is mainly divided into five parts:

  • preface

  • Learn about rich text editors

  • Rich text editor selection guide

  • How does a rich text editor extend

  • conclusion

This article, through the game character analogy, hopes to make rich text editor less contact with developers, can have a deep understanding of rich text editor. Today, we will discuss the common problems encountered in the selection and expansion of rich text editors.

2. Understand rich text editors

Usually, before we choose a new game, we choose to go to the official website and forums to learn about the game information, which can help us select the right character.

When developers are asked for a rich text editor, they don’t just pick one of them, they choose the technology based on the huge amount of data. This section is the preparation for the subsequent selection.

2.1 Character Style – Rich text editor form

By default, game characters are equipped with different styles before they go live, which often determines our initial impression of the character.

Rich text editors also have several common initial forms, classic mode, document mode and inline mode, as shown in the following figure:

As you can see from the comparison above, an essential part of a rich text editor is the content editing area. The status bar is used to record relevant data during editing and can be hidden. The toolbar, on the other hand, allows you to adjust the location of the display, the timing of the display and even switch to the background control (triggered by shortcut keys, etc.).

Instead, we get the message that different combinations of toolbars, content areas, status bars, and menu bars can give rich text editors different presentation shapes.

2.2 Growth Stage – development history of rich text editor

Characters in the game are growable characters, and there will always be some bottleneck in their growth, after which their abilities will change significantly.

Throughout its development, rich text editors have encountered some difficulties. Because of these dilemmas, the development process can be divided into stages L0, L1, L2 and L3.

L0->L1

L0, the original rich text editor, relied on the browser’s own execCommand and provided only a limited set of commands to implement the simplest functions. With the increasingly rich style requirements, the rich text editor at this time can not meet the requirements, L1 stage editor came into being. The rich text editor of L1 adopts the scheme of custom execCommand, which can realize richer rich text functions.

L1->L2

Rich text editors for L0 and L1 still modify HTML through execCommand. Rich text with the same representation may have a very different HTML structure in different browsers.

For example, bold, the HTML might be bold, it might be bold, it might be bold, and so on. In order to solve the problem that data and view cannot correspond one by one, the concept of custom data model is proposed.

A custom data model is a data structure extracted by a rich text editor on the basis of a rich text HTML-DOM tree. The same data structure ensures that the HTML rendered is the same. Custom commands directly control the data model and ultimately ensure the consistency of the rendered HTML document.

Different rich text editors end up rendering different data models for the same HTML. Taking Hello EditorName as an example, the data models of Quill, ProseMirror, Draft and Slate are compared as follows:

The rich text editor in L2 stage solves the problems of dirty data and difficult implementation of complex functions in rich text by extracting data model. Data-driven, it can better meet the requirements of customization, cross-end parsing, and online collaboration.

L2->L3

The editor to stage L2 can satisfy most usage scenarios. So why is L3 developed later?

This is because l0-L2’s rich text editors are browser-based contentEditable and often need to intercept user actions when modifying the data model. Interception of user behavior is difficult to control and, coupled with compatibility issues between browsers, prone to bugs.

In order to solve the problem of uncontrolled editing in contentEditable, editors such as Google Docs have moved to L3 with a “homegrown typography engine” **.

An indigenous typesetting engine, which completely eliminates contentEditable, enables browse-like editing by controlling cursor position, selection drawing, typesetting, and listening to input. “From research”, undoubtedly has a higher expansibility. However, due to its high development difficulty, high cost and many hidden problems, it still lags behind native browser rendering in overall experience and performance, and there is still a long way to go for the editor at this stage.

Ps: There are a thousand Hamlets in a thousand people’s eyes.

The following classification of growth stages is based on the author’s own opinion.

Reviewing the development of rich text editor, it is not difficult to find that the structure of rich text editor cannot be separated from model, view and controller. As shown below:

Just as game characters broke through the bottleneck, rich text editors changed during the transition from L1 to L2 by pulling out custom data models; The change from L2 to L3: a new definition of the typography engine.

Rich text editor selection guide

Once we have learned about the background and characters from various sources, the next step is to log in and create the characters. At this point, there is no doubt that the problem for beginners is how to choose the most suitable character for them.

Similarly, for those new to rich text editors, the question is: Which rich text editor should I choose?

First, you can choose the rich text editor for the corresponding stage according to your business needs:

  • The business itself is centered on a rich text editor or has collaborative editing requirements. — Select the editor extensions for L2 and L3, or create your own editor. Here you can refer to youdao Cloud notes and language finch scheme, see the reference link at the end of the article.

  • Frequent iteration of business requirements and high interaction design requirements. The editor for L2 is recommended.

  • Relatively stable business, not high requirements. — L1, L2 optional.

  • If the business scenario is complex, it is difficult to evaluate the future business scenario. The editor for L2 is recommended.

Secondly, on the basis of the selected stage, according to the project architecture (Vue, React, Augular, etc.) and the characteristics of rich text editor, it is ok to choose the appropriate editor. It can be considered from the following aspects:

  • Degree of open source

  • Community ecology

  • The interaction details

  • Extended support

  • Customization cost

Above, is the type selection routine I comb. Such as CKEditor, TinyMCE, Quill, etc are well known, you may wish to consider the selection of these editors:

How does the rich text editor extend

Choosing the right character is only the beginning of the game. Over the course of the game, the skill tree of the game character needs to be constantly tweaked to push its potential to the limit.

With the continuous development of business, rich text editors will also put forward higher requirements. In this regard, developers are often troubled by the following questions:

1, how to quickly extend the rich text function?

2. How to change the editor quickly?

For the above two problems, the following will be analyzed from the two aspects of capacity expansion and theme transformation.

4.1 Capability Expansion

This section will not focus on how a rich text editor can be extended, but rather share some general ideas for dealing with the different extensions described above.

4.1.1 Toolbar Extension

Just like in a game character, the final battle power data can be adjusted through different assembly schemes of items. Toolbar extension is the combination and transformation of different functions in the toolbar to meet the final business requirements.

The common toolbar is composed of several function buttons, status button groups, drop-down menus, modal boxes, etc., as shown below:

In general, rich text editors have configuration items for the management toolbar, which can be consulted according to the official documents. Here we explore a scenario, how to extend an existing function button?

Take the “Quill editor font highlighting feature” — the color of the feature button corresponds to the color of the font at the cursor position to create a binding change, as shown below:

So what if the rich text editor introduced in the project does not provide this capability? There are two options:

1) Control function button native UI style.

For example, Tiny’s font highlighting function is shown in the following figure. The button is an SVG structure and can be achieved by controlling strokeColor/fillColor. Add OnSelectionChange for cursor position change, get font highlight color for cursor position, and reset button UI.

2) Replace current button with SVG icon.

This can be used when the function buttons are rendered as images and it is difficult to control UI changes. Replace the image icon with an SVG icon, and change the strokeColor/fillColor of SVG-PATH to achieve the same effect.

Summary: If the project is introducing a rich text editor for the first time, please refer to plan 2 in 4.2 Theme Transformation.

4.1.2 Menu Bar extension

Menu bar expansion is similar to adding ancillary skills to the equipment of the game character. These new abilities depend on the equipment, and each equipment is equipped with different abilities.

The menu bar mentioned in this section refers specifically to the inline menu bar inside the editor. Such as picture toolbar, table toolbar, right-click menu bar and so on. As shown below:

The most common requirement for a menu bar is to add a menu bar to an existing plug-in.

1) The rich text editor provides the ability to associate configuration, which can be configured directly according to the API document. Here are some configuration schemes for the menu bar in Tiny editor, as shown below:

2) If you do not have the ability to associate configuration, you need to monitor cursor position changes. Triggers an event/command to control this menu bar display when the cursor changes in the corresponding rich text data area.

In either case, the extended menu bar can optionally be implemented within the editor, or it can be thrown outside the editor by events and associated as a custom component. I prefer to use a custom menu-bar component:

// The pseudocode is just an example for understanding
// Rich text editor
<Editor :config="editorConfig"/>
// Customize menu bar components
<ContextToolBarComponent @command="handleCommand"/>
editor.on("selectionChange",(selection)=>{
  // Determine the selection position
  CheckSelectionDataModel(selection)
  // Control menu bar to display hidden, bound data entities
  ControlContextToolBarComponentShowHide(selectionPosition)
})
// Menu function triggers
handleCommand(command, _instance){
  editor.execCommand(command, _instance)
}

Copy the code

4.1.3 Editor internal extensions

For the enhancement of combat power of game characters, props and equipment belong to the enhancement of external forces, and the characters themselves also need to be focused on.

In the section on the development history of rich text editor, it is concluded that the structure of rich text editor cannot be separated from the three modules of model, view and controller, so the expansion scheme is differentiated from these three modules.

Data model extension

As mentioned in the previous introduction, the key behavior of phase L1-L2 transition is to pull away from the custom data model. The data model of the rich text editor determines the structure of the final rich text rendering. When a predefined rich text structure does not meet expectations, the rich text data model needs to be extended. Depending on whether the rich text editor is before or after the L2 stage, the way it expands is quite different.

<figure> <img SRC = "XXX" /> </figure> <img SRC = "XXX" /> <img SRC = "XXX" /> </figure>Copy the code

1) Rich text editors in L2 stage and later stage are capable of data model abstraction. At this point, you only need to add/edit defined data objects to the data structure and bind the rendered HTML structure:

{type:'image', SRC :' XXX '}
Type :'image', SRC :' XXX ',caption:' Image '}
// Add caption:' Caption ', add HTML structure ' caption>'

Copy the code

2) Before L2 stage, rich text data is not abstracted from the data model. For this scenario, the htML-parse-stringify plug-in can be used to extract the data model itself and then extend the data. In order to

Hello HTML – parse – stringfy!

Html-parse-stringify is a plugin that converts HTML_AST into the required data structure. There are also some problems with htML-parse-stringify.

The view extension

The view should be easy to understand, and characters with the same stats, with different skins or skill effects, will appear differently during combat. The same rich text data source can present different visual effects with different view extensions.

1) Do not change the data structure of rich text, only distinguish in style setting

Toggle different styles by toggling the class attribute bound to the DOM structure:

<blockquote class="pgc-blockquote-abstract"> Quote content </blockquote> <blockquote> Quote content </blockquote> <blockquoteclass="pgc-blockquote-quote"</blockquote>Copy the code

2) Directly change the data structure of rich text

The normal link switches to the card, the data structure switches from inline-block to Block (link-card), and DOM rendering switches accordingly. DOM structure comparison is as follows:

<p><br></p><p><a href="http://www.vivo.com.cn"> vivo smartphone official website - the X60 series 丨 flagship professional image < / a > < / p > < p > < br > < / p > < p > < br > < / p > < a href ="http://www.vivo.com.cn" data-draft-node="block" data-draft-type="link-card"<p><br></p>Copy the code

Controller expansion

A controller is an abstract concept that is used by a character to control skill trigger conditions, release timing, trigger conditions, attribute effects, etc.

Similarly, the controller of a rich text editor is a general term for the data layer and view layer control. The controller can be expanded by events, commands, and configuration items. Today, we’ll talk briefly about how events and commands can be extended.

1) Expansion of events

Events are kind of like active abilities, which are actively released by the character. Rich text editors actively throw events to control both inside and outside the editor, such as OnselectionChange, OnInit, and so on. When the new function needs to be controlled by the editor inside the external components, and the native event cannot meet, it is often necessary to implement the new event listener.

The extension of events is useful in cross-side operations and will be highlighted later in cross-side practices.

// For a simple example, an image upload failure usually triggers a re-upload:
// If the image is uploaded through the editor, click re-upload after the failure is the editor's own behavior logic.
// However, in the scenario where the client controls resource uploading, the editor needs to notify the client that "certain resource requests to upload again".
// For cross-endpoint communication, the rich text editor needs to throw events to inform the client to perform the operation.
 
editor.on('appRetryingUploadImage', ({ data }) => {
  call('reUploadPic', { picUrl: data.path, fileId: data.id })
})

Copy the code

2) Command extension

Command control is the opposite of event control logic. Commands are like passive skills that trigger an action of a character when the external environment reaches a certain condition. Command management for a rich text editor provides the ability to control operations inside the editor from outside the editor. When operations are not in the Commond Command library, the Command Command needs to be extended. Command extensions vary from editor to editor, but they remain the same — exec and Refresh are at the heart of Command.

Take CKEditor versus Tiny: CK5class XXXCommand extends Command{
   refresh(){}
   execute(){}
 }
CK4
 editor.addCommand('XXXCommand', {
        exec: ()=> {},
        refresh: ()=>{}
      })
Tiny
editor.addCommand('XXXCommand', () = > {});Copy the code

Exec is the callback function for executing commands, which is used to control the execution of related operations in the editor. Refresh is a callback function at the end of a command line. It is often used to control the refresh of the editor status after the command is executed.

In addition to events and commands, some editors can also customize operations by extending configuration items.

4.1.4 Added rich text function plug-in

To maximize the value of a new skill, not only do you need to raise your character’s stats to the right level, but you also need to be flexible with skill sets, appropriate items, and so on.

Add a plug-in to a rich text editor, which often requires multiple modules to extend:

Expand on the modules shown above:

Defining the data model

From the section 4.1.3 Data Model Extension, we can see that the data model is the core of the new rich text feature. Only when the data layer is determined can you determine how the view rendering is controlled and ultimately rendered in the front end.

To define a data model, there are three main steps:

1. Determine whether the DOM of the data model is Inline, Block, or swappable;

2, clear the data model access restrictions and editable restrictions, such as the title can not be nested hyperlinks and other similar rules;

3. Determine the data model and its data input and output;

  • Data input is the content that needs to be configured. For example, an image URL and a comment copy are required

  • The data output is the DOM structure rendered by the editor’s HTML

  • Data models include: stored HTML strings, abstract custom data types (JSON)

Input-model-output transformation example diagram, as shown below:

Customize toolbar buttons

Toolbar button is a window for data control, which can be displayed in the toolbar or hidden by shortcut keys. If it is displayed on the toolbar, customize function buttons, bind menus, or control operations based on specific requirements. For details, see 4.1.1 Toolbar Extension.

Added events or commands

Once the data core and control window have been identified, the next step is to develop a control strategy. First determine whether the control strategy in the requirement is positive, with rich text editor actions triggering external feedback, or negative, with the external triggering the editor’s internal actions, or both. Then, depending on the control policy, the corresponding options extend events, commands, or both. For details about the expansion scheme, see 4.1.3 Controller Expansion

Associated cursor selection

The data structure corresponding to the current selection can be determined by the cursor position, so as to control the switch of special state. How do I determine if I need to correlate cursor selection?

1. Whether the button status of the new function is related to the cursor position. This can be done in the custom toolbar button step;

2. Whether new functions need to be displayed in the menu bar. Refer to the section 4.1.2 Menu Bar Extension for solutions.

3. Whether the new function is associated with other rich text functions. For example, mutual exclusion logic — hyperlinks are not allowed to be inserted into headings;

If it is determined that the cursor selection needs to be associated, then the rich text editor needs to add OnSelectionChange listener to complete the related processing.

editor.on("selectionChange",(selection)=>{
  // Determine the selection position
  CheckSelectionDataModel(selection)
  // Change the state of its own and other buttons
  ChangeButtonStatus(button)
  // The control menu is hidden
  ControlMenuShow(menuBar)
})

Copy the code

Associated Operation Record Management (undo, redo)

When you interoperate in a rich text editor, it is inevitable that some misoperations will occur. The more complex the interaction scenario of a rich text editor, the higher the probability of misoperation. Therefore, rich text editors generally manage operation records to reduce the impact of misoperations.

Undo /redo processing logic varies with rich text editors. Similarly, rich text editors define key behaviors (such as common inserts and deletes) during operations and store them in operation records.

When we associate operation log management with the new plug-in functionality, we simply reuse the in-and-out logic of other plug-in key actions.

// Pseudo code, just for understanding
UndoManage.push(keyOperation)
UndoManage.undo()
UndoManage.redo()

Copy the code

Add copy and paste control

“Copy and paste” is one of the most troublesome problems in rich text editor operation. If you have experience in related development, you should have encountered the problem of pasting content copied from other sources into the editor. In this case, it is often necessary to filter the data in the clipboard and convert it into data that can be recognized by a rich text editor.

editor.on('paste',(evt)=>{
  // Determine the filtering rule according to the data structure corresponding to the cursor
  let filterRules = checkSelection()
  // filterRulers JSON data structure Filters and modifies data objects
  // filterRulers HTML strings can use regular expressions or built-in filtering methods of the editor
  evt.data =  filterRulers.exec(evt.data)
})

Copy the code

4.2 Theme Transformation

“Theme reinvention” should be easy to understand. It means changing the skin in the game, quickly changing the style of the game character.

Theme modification in a rich text editor is a change in the style of toolbars, menu bars, and special rich text. There are two common treatment schemes:

Introduce a new theme style file. Replace a new theme style file, or style overwrite an old theme style.

Build toolbar components separate from the editor itself. Separate the toolbar and menu bar involved in the theme modification from the editor, and create a new toolbar component and menu bar component in the project.

If it is to transform existing projects, the input-output ratio of switching between old and new themes should be taken into account and the optimal selection should be made. If the project is new and requires a high level of thematic style detail, plan 2 can be used.

// The pseudocode is just an aid to understanding<! Customize toolbars --> <CustomToolbarComponent> <ButtonBold@click="execCommondBold"/>
 <ButtonUnderline @click="execCommondUnderline"/>
 <ButtonHead @click="execCommondHead"/> </CustomToolbarComponent> <! -- Rich text editor edit area --> <EditorContainer></EditorContainer> <script>// Execute Commond for the rich text editor
execCommondBold:()=>{
    editor.execCommond('bold')
}
execCommondUnderline:()=>{
    editor.execCommond('underline')
}
execCommondHead:()=>{
    editor.execCommond('head')
}
</script>
<style>
// Customize theme styles
button-bold{}
button-underline{}
button-head{}
</style>

Copy the code

Compared with Plan 1, Plan 2:

  • Advantages: The control of the toolbar is transferred from a third-party editor to the project, which maximizes controllability and expansibility. The adaptability of cross-terminal business is higher, each end only needs a set of control scheme, each functional component can be customized by channel;

  • Disadvantages: Control schemes such as command/event and state binding in the toolbar need to be transferred to the new component, which will occupy some development cost.

Summary: There are more than these solutions for functional expansion and theme transformation, and there are other compromise solutions. You just need to choose the right solution according to the business scenario. As the saying goes, “the best may not fit, but the right one is the best”.

At this point, the content of this article is close to the end. I hope you can get some answers to the following questions:

1. Based on current business requirements, which rich text editor should I choose?

2. As the business expands, how to extend the rich text function?

3, design revision, how to quickly change the face?

Five, the summary

It’s like in the game world, you have to level up against monsters. In the process, you will also accumulate more skills and lay a solid foundation for the future. In the development process of rich text editor, we will indeed encounter many difficult problems and complex requirements, which cost us a lot of time and energy. In the exercise again and again, we will gain and grow.

This article shares some thoughts about common problems in the development process of rich text editor, hoping to bring some help to friends who will participate in the development of rich text editor, or partners who are developing rich text editor.

I’ll share some of the rich text editor’s experience in cross-end solutions, if you’re interested.

The resources

  1. Architecture Design of the new version of Youdao Cloud Note Editor (PART 1)

  2. Architecture Design of the new version of Youdao Cloud Note Editor (Part 2)

  3. Technical evolution of rich text editors

  4. Evolution of Open Source Rich Text Editor Technology (2020 1024)

  5. Talk about the plight of rich text editors from popular editor architectures

  6. Quill Editor

  7. CKEditor

  8. TinyMCE

Author: Tian Yuhan, Vivo Internet Front-end team