JSFiddle - React, Tailwind, and code Playground

by marcbuils

HTML

<script src="http://borismoore.github.com/jsviews/jsrender.js"></script>
<script src="http://borismoore.github.com/jsviews/jquery.observable.js"></script>
<script src="http://borismoore.github.com/jsviews/jquery.views.js"></script>
<div id="todoapp">
    <div class="nav"><a href="../demos.html">JsViews Demos</a></div>
    <h1>Todos</h1>

    <input id="new-todo" placeholder="What needs to be done?" />

    <ul id="todo-list"></ul>

    <div id="todo-stats">
        <span data-link="~remainingMessage(remaining)"></span>
        <a href="#" data-link="{:~completedMessage(completed)}" class="todo-clear"></a>
    </div>
</div>

<ul id="instructions">
    <li>Todos: enter to add, double-click to edit...</li>
</ul>

<!-- Templates -->
<script type="text/x-jsrender" id="item-template">
    <li>
        <input data-link="checked{:done} {:done:}" class="check" type="checkbox" />
        <div data-link="{:content || 'empty todo...'} css-text-decoration{:done ? 'line-through' : ''}"
            class="todo-content"></div>
        <span class="todo-destroy"></span>
    </li>
</script>

<script type="text/x-jsrender" id="edit-template">
    <li class="editing">
        <input data-link="content" class="todo-input" />
    </li>
</script>

JavaScript

(function(){
    // Initialize app
    var editing = null,
        useStorage = window.JSON && window.localStorage,
        todos = {
            items: useStorage && $.parseJSON( localStorage.getItem( "JsViewsTodos" )) || [], //    Intialize from local storage
            edit: function( view ) {
                editing = view;
                view.tmpl = "editTemplate";
                view.refresh();
                $( view.nodes ).find('input').focus();
            },
            removeItem: function( index, item ) {
                $.observable( this.items ).remove( index, 1 );
                this.doneChanged( item.done ? -1 : 0 );
            },
            clearCompleted: function( index ) {
                var l = this.items.length;
                while ( l-- ) {
                    if ( this.items[ l ].done ) {
                        this.removeItem( l, this.items[ l ]);
                    }
                }
            },
            doneChanged: function( incr ) {
                var completed = this.completed + incr;
                $.observable( this ).setProperty({
                    remaining: this.items.length - completed,
                    completed: completed
                });
            },
            contentChanged: function( view ) {
                view.tmpl = "itemTemplate";
                view.refresh();
            }
        }
        todos.completed = $( todos.items ).filter( function( index, val ) { return val.done; }).length;
        todos.remaining = todos.items.length - todos.completed;

    // Helper functions
    $.views.helpers({
        remainingMessage: function( remaining ) {
            return remaining ? ( remaining + " item" + ( remaining > 1 ? "s" : "" ) + " left" ) : "";
        },
        completedMessage: function( completed ) {
            return completed ? ( "Clear " + completed + " completed item" + ( completed > 1 ? "s" : "" )) : "";
        },
        // Provide afterChange handler for datalinking. (In...