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

71.74% Statements 33/46
50% Branches 9/18
70% Functions 7/10
71.74% Lines 33/46

    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
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    1211×

    1×
    1×
    96×
    96×
    96×
    96×

    1×
    155×
    155×

    155×

    1×
    2×
    2×

    2×
    2×

    1×

    1×

    1×

    1×

    1×

    1×
    1×
    1×

    1×
    1×
    1×
    1×

    1×
    155×

    155×

    155×

    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.isOnEditable()) ? 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 commit
      *  Resets history stack, but keeps current editor's content.
      */
      commit() {
        // Clear the stack.
        this.stack = [];

        // Restore stackOffset to its original value.
        this.stackOffset = -1;

        // Record our first snapshot (of nothing).
        this.recordUndo();
      }

      /**
      * @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());
      }
    }