jodit
Version:
Jodit is an awesome and useful wysiwyg editor with filebrowser
169 lines (168 loc) • 5.3 kB
JavaScript
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
r = Reflect.decorate(decorators, target, key, desc);
else
for (var i = decorators.length - 1; i >= 0; i--)
if (d = decorators[i])
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { ViewComponent } from "../../core/component/index.js";
import { debounce } from "../../core/decorators/index.js";
import { Config } from "../../config.js";
import { Command } from "./command.js";
import { Snapshot } from "./snapshot.js";
import { Stack } from "./stack.js";
Config.prototype.history = {
enable: true,
maxHistoryLength: Infinity,
timeout: 1000
};
/**
* The module monitors the status of the editor and creates / deletes the required number of Undo / Redo shots .
*/
export class History extends ViewComponent {
/** @override */
className() {
return 'History';
}
/**
* Return state of the WYSIWYG editor to step back
*/
redo() {
if (this.__stack.redo()) {
this.startValue = this.snapshot.make();
this.fireChangeStack();
}
}
canRedo() {
return this.__stack.canRedo();
}
/**
* Return the state of the WYSIWYG editor to step forward
*/
undo() {
if (this.__stack.undo()) {
this.startValue = this.snapshot.make();
this.fireChangeStack();
}
}
canUndo() {
return this.__stack.canUndo();
}
clear() {
this.startValue = this.snapshot.make();
this.__stack.clear();
this.fireChangeStack();
}
get length() {
return this.__stack.length;
}
get startValue() {
return this.__startValue;
}
set startValue(value) {
this.__startValue = value;
}
constructor(editor, stack = new Stack(editor.o.history.maxHistoryLength), snapshot = new Snapshot(editor)) {
super(editor);
this.updateTick = 0;
this.__stack = stack;
this.snapshot = snapshot;
if (editor.o.history.enable) {
editor.e.on('afterAddPlace.history', () => {
if (this.isInDestruct) {
return;
}
this.startValue = this.snapshot.make();
editor.events
// save selection
.on('internalChange internalUpdate', () => {
this.startValue = this.snapshot.make();
})
.on(editor.editor, [
'changeSelection',
'selectionstart',
'selectionchange',
'mousedown',
'mouseup',
'keydown',
'keyup'
]
.map(f => f + '.history')
.join(' '), () => {
if (this.startValue.html ===
this.j.getNativeEditorValue()) {
this.startValue = this.snapshot.make();
}
})
.on(this, 'change.history', this.onChange);
});
}
}
/**
* Update change counter
* @internal
*/
__upTick() {
this.updateTick += 1;
}
/**
* Push new command in stack on some changes
*/
onChange() {
this.__processChanges();
}
/**
* @internal
*/
__processChanges() {
if (this.snapshot.isBlocked || !this.j.o.history.enable) {
return;
}
this.updateStack();
}
/**
* Update history stack
*/
updateStack(replace = false) {
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();
}
}
fireChangeStack() {
var _a;
this.j && !this.j.isInDestruct && ((_a = this.j.events) === null || _a === void 0 ? void 0 : _a.fire('changeStack'));
}
destruct() {
if (this.isInDestruct) {
return;
}
if (this.j.events) {
this.j.e.off('.history');
}
this.snapshot.destruct();
super.destruct();
}
}
__decorate([
debounce()
], History.prototype, "onChange", null);