This article will show you how to learn to read a good open source project called wangEditor
WangEditor version 4
Typescript Web rich text editor, lightweight, concise, easy to use, open source free Github portal
1. Find the entry file
src/wangEditor.ts
It can be seen that the entry file is very concise, and you can clearly understand some of the files required by wangEidtor
- 1. Style file less
- 2. Wangeditor class files
import Editor from './editor/index'
- 3. Polyfill some functionally compatible files
import './utils/polyfill'
- 4. Initialize some basic menu classes that can be extended and configured
export * from './menus/menu-constructors/index'
Note: do not parse less, the usage of less can refer to the less official website documentation
2. Open the
src/utils/polyfill
2. The following two functions are compatible, and the comments are also written clearly:
-
- A compatible implementation of the matches method
-
- Promise compatibility for IE11
3. The key
src/editor/index.ts
This file is the core entry to the editor
The first is the constructor
This constructor takes two arguments
- ToolbarSelector – must – Selector in the editor toolbar
- TextSelector — Optional — A selector for the editor’s content
This function initializes the function and attribute configuration required by the editor, as shown in figure
The rest are apis exposed to the user
API | note |
---|---|
create() | Create an editor instance |
beforeDestroy() | Destroy front hook |
destroy() | Destroy editor |
fullScreen() | Enter the full screen |
unFullScreen() | Shut down full screen |
scrollToHead() | Jumps to the specified anchor point |
registerMenu() | Register extension Menu |
4. Select API encapsulation
src/editor/selection.ts
API | note |
---|---|
getRange() | Get the current range |
saveRange() | Save the selection range |
saveRange() | Fold selection range |
getSelectionText() | Gets the text in the selection range |
getSelectionContainerElem() | Gets the DOM element of the selection range |
getSelectionStartElem() | The DOM element at the beginning of the selection range |
getSelectionEndElem() | The DOM element at the end of the selection range |
isSelectionEmpty() | Is the selection empty (no text is selected) |
restoreSelection() | Restore selection range |
createEmptyRange() | Create a blank (that is, ​ characters) selection |
createRangeByElems() | Reset selection |
createRangeByElem() | Set the selection based on the DOM element |
getSelectionRangeTopNodes() | Gets the top-level (paragraph) element of the current selection range |
moveCursor() | Moves the cursor position, by default at the tail |
getCursorPos() | Gets the cursor position in the current selection |
clearWindowSelectionRange() | Clears the Range in the current selection. Notice: Does not affect the saved Range |
recordSelectionNodes() | Record node – from the start node of the selection to the end node of the selection |
Summary: This file encapsulates selection and cursor operations for Selection
5. ExecCommand Encapsulates the command
src/editor/command.ts
API | note |
---|---|
do() | A command that performs a rich text operation |
insertHTML() | Insert the HTML |
insertElem() | Insert DOM elements |
Summary: Encapsulates the above three, and there are a few more that are simply added a layer of native encapsulation, which will not be listed. These are some encapsulation for execCommand
6. Initialize the edit area
src/text/index.ts
API | note |
---|---|
togglePlaceholder() | Switch the placeholder |
clear() | Empty content |
html() | Get content/set content |
text() | Get text/Set text |
setJson() | Set the json |
getJson() | Get a json |
append() | Append HTML content |
In addition, some apis are private, so I won’t introduce them. If you are interested, you can check their functions on your own
Summary: Exposed some apis for editing area operations for users to use
There is also a feature worth mentioning here, which is the global management of the event delegate, which takes part of the code:
// keyboard down
$textElem.on('keydown'.(e: KeyboardEvent) = > {
const keydownEvents = eventHooks.keydownEvents
keydownEvents.forEach(fn= > fn(e))
})
Copy the code
The keyDown events for the edit area are placed in an array of keydownEvents, and the loop is executed to reach global management, very elegant.
7. Initialize the menu
src/menus/index.ts
API | note |
---|---|
extend | Custom add menu |
init | Initialization menu |
menuFind | Gets the specified menu object |
changeActive | Modify menu activation status |
This is a class file for menu management and initialization
8. Global zIndex management
src/editor/z-index/index.ts
This file is a unified management of all the styles used by the editor, zIndex
9. Listen for the implementation of changes in editor content
src/editor/change/index.ts
It inherited the Mutation, we follow the open the packaging of Mutation file SRC/utils/observer/Mutation. The ts
Soga, originally using the native MutationObserver API
The MutationObserver API creates and returns a new MutationObserver, which is called when the specified DOM changes
The example used by the Official Web API
// Select the nodes that need to be observed to change
const targetNode = document.getElementById('some-id');
// Observer configuration (what changes need to be observed)
const config = { attributes: true.childList: true.subtree: true };
// The callback function that is executed when changes are observed
const callback = function(mutationsList, observer) {
// Use traditional 'for loops' for IE 11
for(let mutation of mutationsList) {
if (mutation.type === 'childList') {
console.log('A child node has been added or removed.');
}
else if (mutation.type === 'attributes') {
console.log('The ' + mutation.attributeName + ' attribute was modified.'); }}};// Create an observer instance and pass in the callback function
const observer = new MutationObserver(callback);
// Observe the target node from the above configuration
observer.observe(targetNode, config);
// After that, you can stop observing
observer.disconnect();
Copy the code
It is an event API that listens for changes in the STRUCTURE of the DOM tree.
10. Undo and restore functions
src/editor/history/index.ts
To see the implementation, construct the code:
We start with three caches
-
- Content caching
-
- Scroll scrollTop cache
-
- District cache
SRC /utils/data-structure/cache.ts SRC /utils/data-structure/cache.ts
Several protected properties are set
-
- Data: Caches generated by normal operations (user input, JS code modification, recovery)
-
- RevokeData: Cache generated by an undo operation (needed for a recovery operation)
-
- IsRe: Whether the previous step was undo/restore
The constructor passes a maximum size to limit the maximum cache storage
constructor(protected maxSize: number) {
this.data = new CeilStack(maxSize)
this.revokeData = new CeilStack(maxSize)
}
Copy the code
CeilStack is a data structure that stores the cache. It uses an array to cache the stack and achieves the last in, first out effect
To be continued