JSFiddle - React, Tailwind, and code Playground
HTML
<script src="http://cdn.ractivejs.org/edge/ractive.js"></script>
<main></main>
<script id='template' type='text/ractive'>
<button on-click='undo'>undo</button>
<button on-click='redo'>redo</button>
<label>
<p>What is your name?</p>
<input value='{{name}}'/>
</label>
<label>
<p>Enter some numbers:</p>
<input type='number' value='{{a}}'/> <input type='number' value='{{b}}'/>
</label>
<h1>Hello jbbkjbjkbkjb {{name}}!</h1>
<p>{{a}} + {{b}} = <strong>{{a+b+1}}</strong></p>
</script>
CSS
body {
font-family: 'Helvetica Neue', arial, sans-serif;
font-weight: 200;
color: #353535;
}
h1, h2, h3, h4, h5, h6 {
font-weight: 200;
}
JavaScript
var getTraverseFunction = function ( isUndo ) {
return function () {
var bound, state, promise;
bound = isUndo ? 0 : this._undoStack.length - 1;
if ( this._undoStackIndex === bound ) return;
// decrement pointer
this._undoStackIndex += isUndo ? -1 : 1;
state = JSON.parse( this._undoStack[ this._undoStackIndex ] );
this._traversingStack = true;
promise = this.reset( state );
this._traversingStack = false;
return promise;
};
};
var Undoable = Ractive.extend({
data: {
_undoStackSize: 50
},
init: function () {
this._undoStack = [], this._undoStackIndex = -1;
this.observe( function ( data ) {
if ( this._traversingStack ) return;
this._undoStackIndex += 1;
this._undoStack[ this._undoStackIndex ] = JSON.stringify( data );
// most recent change should become the end of the stack
this._undoStack.length = this._undoStackIndex + 1;
});
},
undo: getTraverseFunction( true ),
redo: getTraverseFunction( false )
});
var ractive = new Undoable({
el: 'main',
template: '#template',
data: { name: 'world', a: 2, b: 2 }
});
ractive.on( 'undo', ractive.undo );
ractive.on( 'redo', ractive.redo );