all files / src/js/base/editing/ History.js

76.19% Statements 32/42
43.75% Branches 7/16
77.78% Functions 7/9
76.19% Lines 32/42
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106   77× 77× 77× 77×     126× 126×   126×                                                                                                                             126×     126×         126×    
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) {
    Eif (snapshot.contents !== null) {
      this.$editable.html(snapshot.contents);
    }
    Eif (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
    Iif (this.$editable.html() !== this.stack[this.stackOffset].contents) {
      this.recordUndo();
    }
 
    Eif (this.stackOffset > 0) {
      this.stackOffset--;
      this.applySnapshot(this.stack[this.stackOffset]);
    }
  }
 
  /**
   * redo
   */
  redo() {
    Eif (this.stack.length - 1 > this.stackOffset) {
      this.stackOffset++;
      this.applySnapshot(this.stack[this.stackOffset]);
    }
  }
 
  /**
   * recorded undo
   */
  recordUndo() {
    this.stackOffset++;
 
    // Wash out stack after stackOffset
    Iif (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());
  }
}