Demo - UndoStack Undo/Redo for HTML

HTML

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdn.wijmo.com/5.latest/styles/wijmo.min.css">
<script src="https://cdn.wijmo.com/5.latest/controls/wijmo.min.js"></script>
<script src="https://cdn.wijmo.com/5.latest/controls/wijmo.input.min.js"></script>
<script src="https://cdn.wijmo.com/5.latest/controls/wijmo.grid.min.js"></script>
<script src="https://cdn.wijmo.com/5.latest/controls/wijmo.grid.filter.min.js"></script>
<script src="https://cdn.wijmo.com/5.latest/controls/wijmo.gauge.min.js"></script>
<div class="container">

  <h1>
    UndoStack: Undo/Redo for HTML forms
  </h1>
  <p>
    This demo shows an <b>UndoStack</b> class that can be used to provide
    form-level undo/redo functionality. It handles standard HTML elements,
    including text, check, and radio boxes, as well as Wijmo input and 
    FlexGrid controls.</p>
  <p>
    To see how it works, make changes to the form and then use the 
    Undo/Redo buttons on the toolbar at the top of the page.</p>
  <div class="toolbar">
    <button id="undo" class="btn btn-default" disabled>
      <span class="glyphicon glyphicon-repeat glyphicon-flip"></span> Undo (ctrl+Z)
    </button>
    <button id="redo" class="btn btn-default" disabled>
      <span class="glyphicon glyphicon-repeat"></span> Redo (ctrl+Y)
    </button>
    <button id="reset" class="btn btn-default">
      Reset
    </button>
    <span>
            Action Count: <span id="cnt">0</span>
    </span>
  </div>

  <form id="form">
    <div class="row">
      <div class="col-md-5">

        <h3>HTML Input Text Elements</h3>

        <div class="form-group">
          <label for="firstName">First Name:</label>
          <input id="firstName" class="form-control" placeholder="First Name" pattern="[a-zA-Z]{5,15}">
        </div>

        <div class="form-group">
          <label for="lastName">Last Name:</label>
          <input id="lastName"...

CSS

.glyphicon-flip {
  transform: scaleX(-1);
}

.ctlValue {
  display: inline-block;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  max-width: 150px;
  font-size: 80%;
  font-weight: bold;
  margin-left: 3px;
}

.form-group .wj-flexgrid {
  display: inline-block;
  vertical-align: top;
  height: 200px;
  max-width: 350px;
}

.form-group .wj-gauge,
.form-group textarea,
.form-group input[type=range] {
  display: inline-block;
  vertical-align: top;
  max-width: 200px;
}

.wj-dropdown {
  max-width: 250px;
}

label {
  width: 120px;
  text-align: right;
  margin-right: 3px;
}

.wj-control label,
label.checkbox-inline,
label.radio-inline {
  width: auto;
  text-align: left;
}

.label-indent {
  padding-left: 120px;
}

.form-control {
  width: 200px;
  display: inline-block;
}

form {
  padding: 20px;
}

.toolbar {
  padding: 6px;
  background: #e0e0e0;
}

:disabled {
  opacity: .4;
}

JavaScript

onload = function() {

  // create the Wijmo controls
  var c = new wijmo.input.ComboBox('#country', {
    itemsSource: getCountries(),
    textChanged: function(s, e) {
      document.getElementById('countryValue').textContent = s.text;
    }
  });
  var a = new wijmo.input.InputNumber('#amount', {
    format: 'c2',
    value: 0,
    min: 0,
    step: 10,
    valueChanged: function(s, e) {
      document.getElementById('amountValue').textContent = s.value;
    }
  });
  var gg = new wijmo.gauge.LinearGauge('#gauge', {
    isReadOnly: false,
    value: 0,
    min: 0,
    step: 10,
    valueChanged: function(s, e) {
      document.getElementById('gaugeValue').textContent = s.value;
    }
  });
  var d = new wijmo.input.InputDate('#date', {
    valueChanged: function(s, e) {
      document.getElementById('dateValue').textContent = s.value;
    }
  });
  var colors = new wijmo.input.MultiSelect('#colors', {
    itemsSource: 'Red,Green,Blue'.split(','),
    checkedItemsChanged: function(s, e) {
      document.getElementById('colorsValue').textContent = s.checkedItems;
    }
  });
  var mac = new wijmo.input.MultiAutoComplete('#mac', {
    itemsSource: 'Red,Green,Blue'.split(','),
    selectedItemsChanged: function(s, e) {
      document.getElementById('macValue').textContent = s.selectedItems;
    }
  });
  var g = new wijmo.grid.FlexGrid('#grid', {
    itemsSource: getData(),
    allowDelete: true,
    allowAddNew: true,
    //newRowAtTop: true,
    //imeEnabled: true,
    frozenColumns: 2,
    frozenRows: 2
  });
  var col = g.getColumn('country');
  col.dataMap = getCountries();
  col.maxLength = 8;
  col = g.getColumn('discount');
  col.format = 'p0';
  document.getElementById('newRowAtTop').addEventListener('click', function(e) {
    g.newRowAtTop = e.target.checked;
  });

  // create undo stack (after creating the controls)
  var undoStack = new wijmo.undo.UndoStack('#form');
  undoStack.stateChanged.addHandler(function(s, e) {
    updateState();
  });

 ...