jodit
Version:
Jodit is awesome and usefully wysiwyg editor with filebrowser
189 lines (159 loc) • 3.91 kB
text/typescript
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2020 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
import { Config } from '../../config';
import { IJodit, SnapshotType } from '../../types';
import { ViewComponent } from '../../core/component';
import { Snapshot } from './snapshot';
import { Stack } from './stack';
import { Command } from './command';
import { debounce } from '../../core/decorators';
/**
* @property {object} observer module settings {@link Observer|Observer}
* @property {int} observer.timeout=100 Delay on every change
*/
declare module '../../config' {
interface Config {
observer: {
timeout: number;
};
}
}
Config.prototype.observer = {
timeout: 100
};
/**
* The module monitors the status of the editor and creates / deletes the required number of Undo / Redo shots .
* To track changes in use {@link https://developer.mozilla.org/ru/docs/Web/API/MutationObserver|MutationObserver}
*
* @module Observer
* @see {@link Snapshot|Snapshot}
* @params {Jodit} parent Jodit main object
*/
export class Observer extends ViewComponent<IJodit> {
private __startValue!: SnapshotType;
get startValue(): SnapshotType {
return this.__startValue;
}
set startValue(value: SnapshotType) {
this.__startValue = value;
}
stack: Stack = new Stack();
snapshot: Snapshot = new Snapshot(this.j);
private updateTick: number = 0;
upTick(): void {
this.updateTick += 1;
}
/**
* Push new command in stack on some changes
*/
private onChange(): void {
if (this.snapshot.isBlocked) {
return;
}
this.updateStack();
}
/**
* Update history stack
*/
private updateStack(replace: boolean = false): void {
const newValue = this.snapshot.make();
if (!Snapshot.equal(newValue, this.startValue)) {
const newCommand = new Command(
this.startValue,
newValue,
this,
this.updateTick
);
if (replace) {
const command = this.stack.current();
if (command && this.updateTick === command.tick) {
this.stack.replace(newCommand);
}
} else {
this.stack.push(newCommand);
}
this.startValue = newValue;
this.fireChangeStack();
}
}
/**
* Return state of the WYSIWYG editor to step back
*/
redo(): void {
if (this.stack.redo()) {
this.startValue = this.snapshot.make();
this.fireChangeStack();
}
}
/**
* Return the state of the WYSIWYG editor to step forward
*/
undo(): void {
if (this.stack.undo()) {
this.startValue = this.snapshot.make();
this.fireChangeStack();
}
}
clear(): void {
this.startValue = this.snapshot.make();
this.stack.clear();
this.fireChangeStack();
}
replaceSnapshot(): void {
this.updateStack(true);
}
private fireChangeStack(): void {
this.j && !this.j.isInDestruct && this.j.events?.fire('changeStack');
}
constructor(editor: IJodit) {
super(editor);
editor.e.on('afterAddPlace.observer', () => {
if (this.isInDestruct) {
return;
}
this.startValue = this.snapshot.make();
editor.events
// save selection
.on('internalChange', () => {
this.startValue = this.snapshot.make();
})
.on(
editor.editor,
[
'changeSelection',
'selectionstart',
'selectionchange',
'mousedown',
'mouseup',
'keydown',
'keyup'
]
.map(f => f + '.observer')
.join(' '),
() => {
if (
this.startValue.html ===
this.j.getNativeEditorValue()
) {
this.startValue = this.snapshot.make();
}
}
)
.on(this, 'change.observer', this.onChange);
});
}
destruct(): void {
if (this.j.events) {
this.j.e.off('.observer');
}
this.snapshot.destruct();
delete this.snapshot;
delete this.stack;
delete this.startValue;
super.destruct();
}
}