Permalink
Browse files

backbone.marionette reference app

  • Loading branch information...
jsoverson committed Sep 5, 2012
1 parent 98e27f0 commit 682b13ca79532663a34b6d1cbe92705a182cb5bd
@@ -0,0 +1,4 @@
+js/lib/underscore.js
+js/lib/backbone.js
+js/lib/backbone.marionette.js
+js/lib/backbone-localStorage.js
@@ -0,0 +1,10 @@
+#todoapp.filter-active #todo-list .completed {
+ display:none
+}
+#todoapp.filter-completed #todo-list .active {
+ display:none
+}
+
+#main, #footer {
+ display : none;
+}
@@ -0,0 +1,97 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <title>Marionette • TodoMVC</title>
+ <link rel="stylesheet" href="../../../assets/base.css">
+ <link rel="stylesheet" href="css/custom.css">
+ <!--[if IE]>
+ <script src="../../../assets/ie.js"></script>
+ <![endif]-->
+</head>
+<body>
+<section id="todoapp">
+ <header id="header"></header>
+ <section id="main"></section>
+ <footer id="footer"></footer>
+</section>
+<footer id="info">
+ <p>Double-click to edit a todo</p>
+
+ <p>Created by <a href="http://github.com/jsoverson">Jarrod Overson</a></p>
+</footer>
+
+<!-- vendor libraries -->
+<script src="../../../assets/base.js"></script>
+<script src="../../../assets/jquery.min.js"></script>
+<script src="js/lib/underscore.js"></script>
+<script src="js/lib/backbone.js"></script>
+<script src="js/lib/backbone-localStorage.js"></script>
+<script src="js/lib/backbone.marionette.js"></script>
+
+<!-- application libraries -->
+<script src="js/models/Todo.js"></script>
+<script src="js/collections/TodoList.js"></script>
+<script src="js/Router.js"></script>
+
+<!-- application views -->
+<script src="js/views/Footer.js"></script>
+<script src="js/views/Header.js"></script>
+<script src="js/views/TodoItemView.js"></script>
+<script src="js/views/TodoListCompositeView.js"></script>
+
+<!-- application -->
+<script src="js/app.js"></script>
+
+<script type="text/html" id="template-footer">
+ <span id="todo-count"><strong></strong> items left</span>
+ <ul id="filters">
+ <li>
+ <a href="#/">All</a>
+ </li>
+ <li>
+ <a href="#/active">Active</a>
+ </li>
+ <li>
+ <a href="#/completed">Completed</a>
+ </li>
+ </ul>
+ <button id="clear-completed">Clear completed</button>
+</script>
+
+<script type="text/html" id="template-header">
+ <h1>todos</h1>
+ <input id="new-todo" placeholder="What needs to be done?" autofocus>
+</script>
+
+<script type="text/html" id="template-todoItemView">
+ <div class="view">
+ <input class="toggle" type="checkbox" <% if (completed) { %>checked<% } %>>
+ <label><%= title %></label>
+ <button class="destroy"></button>
+ </div>
+ <input class="edit" value="<%= title %>">
+</script>
+
+<script type="text/html" id="template-todoListCompositeView">
+ <input id="toggle-all" type="checkbox">
+ <label for="toggle-all">Mark all as complete</label>
+ <ul id="todo-list"></ul>
+</script>
+
+<script>
+ var _gaq = _gaq || [];
+ _gaq.push(['_setAccount', 'UA-22728809-1']);
+ _gaq.push(['_trackPageview']);
+ (function () {
+ var ga = document.createElement('script');
+ ga.type = 'text/javascript';
+ ga.async = true;
+ ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+ var s = document.getElementsByTagName('script')[0];
+ s.parentNode.insertBefore(ga, s);
+ })();
+</script>
+</body>
+</html>
@@ -0,0 +1,45 @@
+/*global $*/
+
+var todoList = new TodoList();
+
+var app = new Backbone.Marionette.Application();
+
+app.bindTo(todoList, 'all', function () {
+ if (todoList.length === 0) {
+ app.main.$el.hide();
+ app.footer.$el.hide();
+ } else {
+ app.main.$el.show();
+ app.footer.$el.show();
+ }
+});
+
+app.addRegions({
+ header : '#header',
+ main : '#main',
+ footer : '#footer'
+});
+
+app.addInitializer(function(){
+ app.header.show(new Header());
+ app.main.show(new TodoListCompositeView({
+ collection : todoList
+ }));
+ app.footer.show(new Footer());
+
+ todoList.fetch();
+});
+
+
+app.vent.on('todoList:filter',function(filter) {
+ filter = filter || 'all';
+ $('#todoapp').attr('class', 'filter-' + filter);
+});
+
+$(function(){
+ app.start();
+ new Router();
+ Backbone.history.start();
+});
+
+
@@ -0,0 +1,19 @@
+
+var TodoList = (function(){
+ function isCompleted(todo) { return todo.get('completed'); }
+
+ return Backbone.Collection.extend({
+ model: Todo,
+ localStorage: new Backbone.LocalStorage('todos-backbone'),
+
+ getCompleted: function() {
+ return this.filter(isCompleted);
+ },
+ getActive: function() {
+ return this.reject(isCompleted);
+ },
+ comparator: function( todo ) {
+ return todo.get('created');
+ }
+ });
+}());
@@ -0,0 +1,136 @@
+/**
+ * Backbone localStorage Adapter
+ * https://github.com/jeromegn/Backbone.localStorage
+ */
+
+(function() {
+ // A simple module to replace `Backbone.sync` with *localStorage*-based
+ // persistence. Models are given GUIDS, and saved into a JSON object. Simple
+ // as that.
+
+ // Hold reference to Underscore.js and Backbone.js in the closure in order
+ // to make things work even if they are removed from the global namespace
+ var _ = this._;
+ var Backbone = this.Backbone;
+
+ // 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.
+ // window.Store is deprectated, use Backbone.LocalStorage instead
+ Backbone.LocalStorage = window.Store = function(name) {
+ this.name = name;
+ var store = this.localStorage().getItem(this.name);
+ this.records = (store && store.split(",")) || [];
+ };
+
+ _.extend(Backbone.LocalStorage.prototype, {
+
+ // Save the current state of the **Store** to *localStorage*.
+ save: function() {
+ this.localStorage().setItem(this.name, this.records.join(","));
+ },
+
+ // 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 = guid();
+ model.set(model.idAttribute, model.id);
+ }
+ this.localStorage().setItem(this.name+"-"+model.id, JSON.stringify(model));
+ this.records.push(model.id.toString());
+ this.save();
+ return model.toJSON();
+ },
+
+ // Update a model by replacing its copy in `this.data`.
+ update: function(model) {
+ this.localStorage().setItem(this.name+"-"+model.id, JSON.stringify(model));
+ if (!_.include(this.records, model.id.toString())) this.records.push(model.id.toString()); this.save();
+ return model.toJSON();
+ },
+
+ // Retrieve a model from `this.data` by id.
+ find: function(model) {
+ return JSON.parse(this.localStorage().getItem(this.name+"-"+model.id));
+ },
+
+ // Return the array of all models currently in storage.
+ findAll: function() {
+ return _(this.records).chain()
+ .map(function(id){return JSON.parse(this.localStorage().getItem(this.name+"-"+id));}, this)
+ .compact()
+ .value();
+ },
+
+ // Delete a model from `this.data`, returning it.
+ destroy: function(model) {
+ this.localStorage().removeItem(this.name+"-"+model.id);
+ this.records = _.reject(this.records, function(record_id){return record_id == model.id.toString();});
+ this.save();
+ return model;
+ },
+
+ localStorage: function() {
+ return localStorage;
+ }
+
+ });
+
+ // localSync delegate to the model or collection's
+ // *localStorage* property, which should be an instance of `Store`.
+ // window.Store.sync and Backbone.localSync is deprectated, use Backbone.LocalStorage.sync instead
+ Backbone.LocalStorage.sync = window.Store.sync = Backbone.localSync = function(method, model, options, error) {
+ var store = model.localStorage || model.collection.localStorage;
+
+ // Backwards compatibility with Backbone <= 0.3.3
+ if (typeof options == 'function') {
+ options = {
+ success: options,
+ error: error
+ };
+ }
+
+ var resp;
+
+ switch (method) {
+ case "read": resp = model.id != undefined ? 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");
+ }
+ };
+
+ Backbone.ajaxSync = Backbone.sync;
+
+ Backbone.getSyncMethod = function(model) {
+ if(model.localStorage || (model.collection && model.collection.localStorage))
+ {
+ return Backbone.localSync;
+ }
+
+ return Backbone.ajaxSync;
+ };
+
+ // Override 'Backbone.sync' to default to localSync,
+ // the original 'Backbone.sync' is still available in 'Backbone.ajaxSync'
+ Backbone.sync = function(method, model, options, error) {
+ return Backbone.getSyncMethod(model).apply(this, [method, model, options, error]);
+ };
+
+})();
Oops, something went wrong.

0 comments on commit 682b13c

Please sign in to comment.