import range from '../core/range'; export default class History { constructor($editable) { this.stack = []; this.stackOffset = -1; this.$editable = $editable; this.editable = $editable[0]; } makeSnapshot() { const rng = range.create(this.editable); const emptyBookmark = {s: {path: [], offset: 0}, e: {path: [], offset: 0}}; return { contents: this.$editable.html(), bookmark: (rng ? rng.bookmark(this.editable) : emptyBookmark) }; } applySnapshot(snapshot) { if (snapshot.contents !== null) { this.$editable.html(snapshot.contents); } if (snapshot.bookmark !== null) { range.createFromBookmark(this.editable, snapshot.bookmark).select(); } } /** * @method rewind * Rewinds the history stack back to the first snapshot taken. * Leaves the stack intact, so that "Redo" can still be used. */ rewind() { // Create snap shot if not yet recorded if (this.$editable.html() !== this.stack[this.stackOffset].contents) { this.recordUndo(); } // Return to the first available snapshot. this.stackOffset = 0; // Apply that snapshot. this.applySnapshot(this.stack[this.stackOffset]); } /** * @method reset * Resets the history stack completely; reverting to an empty editor. */ reset() { // Clear the stack. this.stack = []; // Restore stackOffset to its original value. this.stackOffset = -1; // Clear the editable area. this.$editable.html(''); // Record our first snapshot (of nothing). this.recordUndo(); } /** * undo */ undo() { // Create snap shot if not yet recorded if (this.$editable.html() !== this.stack[this.stackOffset].contents) { this.recordUndo(); } if (this.stackOffset > 0) { this.stackOffset--; this.applySnapshot(this.stack[this.stackOffset]); } } /** * redo */ redo() { if (this.stack.length - 1 > this.stackOffset) { this.stackOffset++; this.applySnapshot(this.stack[this.stackOffset]); } } /** * recorded undo */ recordUndo() { this.stackOffset++; // Wash out stack after stackOffset if (this.stack.length > this.stackOffset) { this.stack = this.stack.slice(0, this.stackOffset); } // Create new snapshot and push it to the end this.stack.push(this.makeSnapshot()); } }