UNPKG

jodit

Version:

Jodit is awesome and usefully wysiwyg editor with filebrowser

189 lines (159 loc) 3.91 kB
/*! * 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 */ @debounce() 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(); } }