Skip to content

Commit

Permalink
initial thorax todos commit
Browse files Browse the repository at this point in the history
  • Loading branch information
RYan Eastridge committed Sep 19, 2012
1 parent 83cf863 commit 466307f
Show file tree
Hide file tree
Showing 12 changed files with 2,816 additions and 0 deletions.
80 changes: 80 additions & 0 deletions labs/architecture-examples/thorax/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Thorax • TodoMVC</title>
<link rel="stylesheet" href="../../../assets/base.css">
<!--[if IE]>
<script src="../../../assets/ie.js"></script>
<![endif]-->
</head>
<body>
<script type="text/template" data-template-name="app">
<section id="todoapp">
<header id="header">
<h1>todos</h1>
<input id="new-todo" placeholder="What needs to be done?" autofocus>
</header>
{{^empty todosCollection}}
<section id="main">
<input id="toggle-all" type="checkbox">
<label for="toggle-all">Mark all as complete</label>
{{#collection todosCollection item-view="todo-item" tag="ul" id="todo-list"}}
<div class="view">
<input class="toggle" type="checkbox" {{#if completed}}checked{{/if}}>
<label>{{title}}</label>
<button class="destroy"></button>
</div>
<input class="edit" value="{{title}}">
{{/collection}}
</section>
{{view "stats" tag="footer" id="footer"}}
{{/empty}}
</section>
<div id="info">
<p>Double-click to edit a todo</p>
<p>Written by <a href="https://github.com/addyosmani">Addy Osmani</a> &amp; <a href="https://github.com/beastridge">Ryan Eastridge</a></p>
<p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
</div>
</script>
<script type="text/template" data-template-name="stats">
<span id="todo-count"><strong>{{remaining}}</strong> {{itemText}} left</span>
<ul id="filters">
<li>
{{#link "/" class="selected"}}All{{/link}}
</li>
<li>
{{#link "/active"}}Active{{/link}}
</li>
<li>
{{#link "/completed"}}Completed{{/link}}
</li>
</ul>
{{#if completed}}
<button id="clear-completed">Clear completed ({{completed}})</button>
{{/if}}
</script>
<script src="../../../assets/base.js"></script>
<script src="../../../assets/jquery.min.js"></script>
<script src="../../../assets/lodash.min.js"></script>
<script src="../../../assets/handlebars.min.js"></script>
<script src="js/lib/backbone-min.js"></script>
<script src="js/lib/backbone-localstorage.js"></script>
<script src="js/lib/thorax.js"></script>
<script>
// Grab the text from the templates we created above
Thorax.templates = {
app: Handlebars.compile($('script[data-template-name="app"]').html()),
stats: Handlebars.compile($('script[data-template-name="stats"]').html())
};
</script>
<script src="js/models/todo.js"></script>
<script src="js/collections/todos.js"></script>
<script src="js/views/todo-item.js"></script>
<script src="js/views/stats.js"></script>
<script src="js/views/app.js"></script>
<script src="js/routers/router.js"></script>
<script src="js/app.js"></script>
</body>
</html>
9 changes: 9 additions & 0 deletions labs/architecture-examples/thorax/js/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
var app = app || {};
var ENTER_KEY = 13;

$(function() {

// Kick things off by creating the **App**.
var view = new Thorax.Views['app']();
$('body').append(view.el);
});
49 changes: 49 additions & 0 deletions labs/architecture-examples/thorax/js/collections/todos.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
var app = app || {};

(function() {
'use strict';

// Todo Collection
// ---------------

// The collection of todos is backed by *localStorage* instead of a remote
// server.
var TodoList = Backbone.Collection.extend({

// Reference to this collection's model.
model: app.Todo,

// Save all of the todo items under the `"todos"` namespace.
localStorage: new Store('todos-backbone'),

// Filter down the list of all todo items that are finished.
completed: function() {
return this.filter(function( todo ) {
return todo.get('completed');
});
},

// Filter down the list to only todo items that are still not finished.
remaining: function() {
return this.without.apply( this, this.completed() );
},

// We keep the Todos in sequential order, despite being saved by unordered
// GUID in the database. This generates the next order number for new items.
nextOrder: function() {
if ( !this.length ) {
return 1;
}
return this.last().get('order') + 1;
},

// Todos are sorted by their original insertion order.
comparator: function( todo ) {
return todo.get('order');
}
});

// Create our global collection of **Todos**.
app.Todos = new TodoList();

}());
84 changes: 84 additions & 0 deletions labs/architecture-examples/thorax/js/lib/backbone-localstorage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// A simple module to replace `Backbone.sync` with *localStorage*-based
// persistence. Models are given GUIDS, and saved into a JSON object. Simple
// as that.

// Generate four random hex digits.
function S4() {
return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
};

// Generate a pseudo-GUID by concatenating random hexadecimal.
function guid() {
return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
};

// Our Store is represented by a single JS object in *localStorage*. Create it
// with a meaningful name, like the name you'd give a table.
var Store = function(name) {
this.name = name;
var store = localStorage.getItem(this.name);
this.data = (store && JSON.parse(store)) || {};
};

_.extend(Store.prototype, {

// Save the current state of the **Store** to *localStorage*.
save: function() {
localStorage.setItem(this.name, JSON.stringify(this.data));
},

// Add a model, giving it a (hopefully)-unique GUID, if it doesn't already
// have an id of it's own.
create: function(model) {
if (!model.id) model.id = model.attributes.id = guid();
this.data[model.id] = model;
this.save();
return model;
},

// Update a model by replacing its copy in `this.data`.
update: function(model) {
this.data[model.id] = model;
this.save();
return model;
},

// Retrieve a model from `this.data` by id.
find: function(model) {
return this.data[model.id];
},

// Return the array of all models currently in storage.
findAll: function() {
return _.values(this.data);
},

// Delete a model from `this.data`, returning it.
destroy: function(model) {
delete this.data[model.id];
this.save();
return model;
}

});

// Override `Backbone.sync` to use delegate to the model or collection's
// *localStorage* property, which should be an instance of `Store`.
Backbone.sync = function(method, model, options) {

var resp;
var store = model.localStorage || model.collection.localStorage;

switch (method) {
case "read": resp = model.id ? store.find(model) : store.findAll(); break;
case "create": resp = store.create(model); break;
case "update": resp = store.update(model); break;
case "delete": resp = store.destroy(model); break;
}

if (resp) {
options.success(resp);
} else {
options.error("Record not found");
}
};
Loading

0 comments on commit 466307f

Please sign in to comment.