# 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
    1061×

    1×
    1×
    77×
    77×
    77×
    77×

    1×
    126×
    126×

    126×

    1×
    2×
    2×

    2×
    2×

    1×

    1×

    1×

    1×

    1×
    1×
    1×

    1×
    1×
    1×
    1×

    1×
    126×

    126×

    126×

    1×
     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());
      }
    }