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;