JSFiddle - React, Tailwind, and code Playground
HTML
<script src="http://cdn.ractivejs.org/latest/ractive.js"></script>
<script src="http://ractivejs.github.io/ractive-events-keys/ractive-events-keys.js"></script>
<main></main>
<div id="output" />
<script id='template' type='text/ractive'>
<form>
<input on-change='newTodo' on-enter='blur' class='newTodo' placeholder='What needs to be done?'/>
</form>
<ul class='todos'>
{{#items:i}}
{{>item}}
{{/items}}
</ul>
<h2>To-do list</h2>
<!-- {{>item}} -->
<li data-index='{{i}}' class='{{ done ? "done" : "pending" }}'>
<input type='checkbox' checked='{{done}}'>
<span on-tap='edit'>
{{description}}
{{#.editing}}
<input id='editTodo' class='edit' value='{{description}}' on-blur='stop_editing'>
{{/.editing}}
</span>
<a class='button' on-tap='remove'>x</a>
</li>
<!-- {{/item}} -->
</script>
<script id='dropdown-list' type='text-ractive'>
<select value='{{value}}'>
{{#options}}
<option>{{this}}</option>
{{/options}}
</select>
</script>
<script id='logger' type='text-ractive'>
<p>{{message}}</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
Ractive.events.enterkp = Ractive.events.enter;
var TodoList = Ractive.extend({
template: "#template",
addItem: function ( description ) {
this.items.push({
description: description,
done: false
});
},
removeItem: function ( index ) {
this.items.splice( index, 1 );
},
editItem: function ( index ) {
var self = this, keydownHandler, blurHandler, input, currentDescription;
currentDescription = this.get( 'items.' + index + '.description' );
this.set( 'items.' + index + '.editing', true );
input = this.nodes.editTodo;
input.select();
window.addEventListener( 'keydown', keydownHandler = function ( event ) {
switch ( event.which ) {
case 13: // ENTER
event.preventDefault();
input.blur();
break;
case 27: // ESCAPE
input.value = currentDescription;
self.set( 'items.' + index + '.description', currentDescription );
input.blur();
break;
case 9: // TAB
event.preventDefault();
input.blur();
self.editItem( ( index + 1 ) % self.get( 'items' ).length );
break;
}
});
input.addEventListener( 'blur', blurHandler = function () {
window.removeEventListener( 'keydown', keydownHandler );
input.removeEventListener( 'blur', blurHandler );
});
this.set( 'items.' + index + '.editing', true );
},
init: function ( options ) {
var self = this;
this.items = options.items;
// initialise
this.set( 'items', this.items );
// proxy event handlers
this.on({
remove: function ( event ) {
this.removeItem( event.index.i );
},
newTodo: function ( event ) {
this.addItem( event.node.value );
event.node.value = '';
setTimeout( function () {
event.node.focus();
}, 0 );
},
edit: function ( event ) {
this.editItem( event.index.i );
},
stop_editing: function (...