146 lines
3.8 KiB
JavaScript
146 lines
3.8 KiB
JavaScript
var Delta, Quill, UndoManager, _;
|
|
|
|
Quill = require('../quill');
|
|
|
|
_ = Quill.require('lodash');
|
|
|
|
Delta = Quill.require('delta');
|
|
|
|
UndoManager = (function() {
|
|
UndoManager.DEFAULTS = {
|
|
delay: 1000,
|
|
maxStack: 100
|
|
};
|
|
|
|
UndoManager.hotkeys = {
|
|
UNDO: {
|
|
key: 'Z',
|
|
metaKey: true
|
|
},
|
|
REDO: {
|
|
key: 'Z',
|
|
metaKey: true,
|
|
shiftKey: true
|
|
}
|
|
};
|
|
|
|
function UndoManager(quill, options) {
|
|
this.quill = quill;
|
|
this.options = options != null ? options : {};
|
|
this.lastRecorded = 0;
|
|
this.emittedDelta = null;
|
|
this.clear();
|
|
this.initListeners();
|
|
}
|
|
|
|
UndoManager.prototype.initListeners = function() {
|
|
this.quill.onModuleLoad('keyboard', (function(_this) {
|
|
return function(keyboard) {
|
|
keyboard.addHotkey(UndoManager.hotkeys.UNDO, function() {
|
|
_this.undo();
|
|
return false;
|
|
});
|
|
return keyboard.addHotkey(UndoManager.hotkeys.REDO, function() {
|
|
_this.redo();
|
|
return false;
|
|
});
|
|
};
|
|
})(this));
|
|
return this.quill.on(this.quill.constructor.events.TEXT_CHANGE, (function(_this) {
|
|
return function(delta, origin) {
|
|
if (_.isEqual(delta, _this.emittedDelta)) {
|
|
return;
|
|
}
|
|
_this.record(delta, _this.oldDelta);
|
|
return _this.oldDelta = _this.quill.getContents();
|
|
};
|
|
})(this));
|
|
};
|
|
|
|
UndoManager.prototype.clear = function() {
|
|
this.stack = {
|
|
undo: [],
|
|
redo: []
|
|
};
|
|
return this.oldDelta = this.quill.getContents();
|
|
};
|
|
|
|
UndoManager.prototype.record = function(changeDelta, oldDelta) {
|
|
var change, ignored, timestamp, undoDelta;
|
|
if (!(changeDelta.ops.length > 0)) {
|
|
return;
|
|
}
|
|
this.stack.redo = [];
|
|
try {
|
|
undoDelta = this.quill.getContents().diff(this.oldDelta);
|
|
timestamp = new Date().getTime();
|
|
if (this.lastRecorded + this.options.delay > timestamp && this.stack.undo.length > 0) {
|
|
change = this.stack.undo.pop();
|
|
undoDelta = undoDelta.compose(change.undo);
|
|
changeDelta = change.redo.compose(changeDelta);
|
|
} else {
|
|
this.lastRecorded = timestamp;
|
|
}
|
|
this.stack.undo.push({
|
|
redo: changeDelta,
|
|
undo: undoDelta
|
|
});
|
|
if (this.stack.undo.length > this.options.maxStack) {
|
|
return this.stack.undo.unshift();
|
|
}
|
|
} catch (_error) {
|
|
ignored = _error;
|
|
return this.clear();
|
|
}
|
|
};
|
|
|
|
UndoManager.prototype.redo = function() {
|
|
return this._change('redo', 'undo');
|
|
};
|
|
|
|
UndoManager.prototype.undo = function() {
|
|
return this._change('undo', 'redo');
|
|
};
|
|
|
|
UndoManager.prototype._getLastChangeIndex = function(delta) {
|
|
var index, lastIndex;
|
|
lastIndex = 0;
|
|
index = 0;
|
|
delta.ops.forEach(function(op) {
|
|
if (op.insert != null) {
|
|
return lastIndex = Math.max(index + (op.insert.length || 1), lastIndex);
|
|
} else if (op["delete"] != null) {
|
|
return lastIndex = Math.max(index, lastIndex);
|
|
} else if (op.retain != null) {
|
|
if (op.attributes != null) {
|
|
lastIndex = Math.max(index + op.retain, lastIndex);
|
|
}
|
|
return index += op.retain;
|
|
}
|
|
});
|
|
return lastIndex;
|
|
};
|
|
|
|
UndoManager.prototype._change = function(source, dest) {
|
|
var change, index;
|
|
if (this.stack[source].length > 0) {
|
|
change = this.stack[source].pop();
|
|
this.lastRecorded = 0;
|
|
this.emittedDelta = change[source];
|
|
this.quill.updateContents(change[source], 'user');
|
|
this.emittedDelta = null;
|
|
index = this._getLastChangeIndex(change[source]);
|
|
this.quill.setSelection(index, index);
|
|
this.oldDelta = this.quill.getContents();
|
|
return this.stack[dest].push(change);
|
|
}
|
|
};
|
|
|
|
return UndoManager;
|
|
|
|
})();
|
|
|
|
Quill.registerModule('undo-manager', UndoManager);
|
|
|
|
module.exports = UndoManager;
|