From ce1928d2b9a95ffb6bb9115edffb5aa7f95a246c Mon Sep 17 00:00:00 2001 From: Vitaly Glibin Date: Fri, 24 Feb 2012 13:30:27 +0400 Subject: [PATCH] Change TODOs --- index.html | 33 +-------------- js/core.js | 95 ++++++++++++++++++++++++++++++++++++++++++++ js/todos.js | 18 +++++---- templates/item.html | 10 +++++ templates/stats.html | 14 +++++++ 5 files changed, 131 insertions(+), 39 deletions(-) create mode 100644 js/core.js create mode 100644 templates/item.html create mode 100644 templates/stats.html diff --git a/index.html b/index.html index 8a8568d..f057a0b 100644 --- a/index.html +++ b/index.html @@ -9,6 +9,7 @@ + @@ -50,38 +51,6 @@

Todos

Jérôme Gravel-Niquet - - - - - - \ No newline at end of file diff --git a/js/core.js b/js/core.js new file mode 100644 index 0000000..b3b4abc --- /dev/null +++ b/js/core.js @@ -0,0 +1,95 @@ +(function(){ + var Core = this.Core = {}; + + Core.Model = Backbone.Model.extend({ + urlRoot : '/data', + defaults: { + id: null, + name: '' + }, + + clear: function() { + this.destroy(); + this.view.remove(); + } + }); + + Core.Collection = Backbone.Collection.extend({ + model: Core.Model, + url: '/data', + /* To prevent JSON array hijacking (http://haacked.com/archive/2009/06/25/json-hijacking.aspx) + all collection data returned from the server should look like: {data : [...]} + */ + parse : function(resp, xhr) { + if (resp.data) { + return resp.data; + } + return []; + } + }); + + Core.Template = { + cache: {}, //cached templates + pending: {}, // queue of callbacks, waiting for template to load + load: function(url, callback) { + if (this.cache[url]) { //template loaded, call cb + if (callback) callback(this.cache[url]); + return; + } + + this.pending[url] = this.pending[url] || []; + if (callback) this.pending[url].push(callback); //add callback to the queue + + jQuery.ajax({ //load template + url : url, + dataType: 'text', + complete: function(resp) { + var cache = + this.cache[url] = _.template(resp.responseText); // cache it + + // proccess all pending callbacks + _.each(this.pending[url], function(cb) { + cb(cache); + }); + + delete this.pending[url]; + }.bind(this), + error: function() { + throw new Error("Could not load " + url); + } + }); + } + }; + + Core.View = Backbone.View.extend({ + el: null, + renderQueue: false, + + initialize: function() { + if (this.templateUrl) { + Core.Template.load(this.templateUrl, function(data) { + this.template = data; + if (this.renderQueue !== false) { + _.each(this.renderQueue, function(item) { + this._render.apply(this, item); + }.bind(this)); + + this.renderQueue = false; + } + }.bind(this)); + } + }, + + _render: function() {}, //Override this for render proccess + + render: function() { + if (!this.template) { + this.renderQueue = this.renderQueue || []; + this.renderQueue.push(arguments); + return this; + } + return this._render.apply(this, arguments); + } + }); + +})(); \ No newline at end of file diff --git a/js/todos.js b/js/todos.js index 5b58fae..026c65d 100644 --- a/js/todos.js +++ b/js/todos.js @@ -71,13 +71,13 @@ $(function(){ // -------------- // The DOM element for a todo item... - window.TodoView = Backbone.View.extend({ + window.TodoView = Core.View.extend({ //... is a list tag. tagName: "li", // Cache the template function for a single item. - template: _.template($('#item-template').html()), + templateUrl: 'templates/item.html', // The DOM events specific to an item. events: { @@ -89,12 +89,14 @@ $(function(){ // The TodoView listens for changes to its model, re-rendering. initialize: function() { + TodoView.__super__.initialize.apply(this); + this.model.bind('change', this.render, this); this.model.bind('destroy', this.remove, this); }, // Re-render the contents of the todo item. - render: function() { + _render: function() { $(this.el).html(this.template(this.model.toJSON())); this.setText(); return this; @@ -147,14 +149,14 @@ $(function(){ // --------------- // Our overall **AppView** is the top-level piece of UI. - window.AppView = Backbone.View.extend({ + window.AppView = Core.View.extend({ // Instead of generating a new element, bind to the existing skeleton of // the App already present in the HTML. el: $("#todoapp"), // Our template for the line of statistics at the bottom of the app. - statsTemplate: _.template($('#stats-template').html()), + templateUrl: 'templates/stats.html', // Delegated events for creating new items, and clearing completed ones. events: { @@ -167,6 +169,8 @@ $(function(){ // collection, when items are added or changed. Kick things off by // loading any preexisting todos that might be saved in *localStorage*. initialize: function() { + AppView.__super__.initialize.apply(this); + this.input = this.$("#new-todo"); Todos.bind('add', this.addOne, this); @@ -178,8 +182,8 @@ $(function(){ // Re-rendering the App just means refreshing the statistics -- the rest // of the app doesn't change. - render: function() { - this.$('#todo-stats').html(this.statsTemplate({ + _render: function() { + this.$('#todo-stats').html(this.template({ total: Todos.length, done: Todos.done().length, remaining: Todos.remaining().length diff --git a/templates/item.html b/templates/item.html new file mode 100644 index 0000000..9365aff --- /dev/null +++ b/templates/item.html @@ -0,0 +1,10 @@ +
+
+ /> +
+ +
+
+ +
+
\ No newline at end of file diff --git a/templates/stats.html b/templates/stats.html new file mode 100644 index 0000000..e4fc428 --- /dev/null +++ b/templates/stats.html @@ -0,0 +1,14 @@ +<% if (total) { %> + + <%= remaining %> + <%= remaining == 1 ? 'item' : 'items' %> left. + +<% } %> +<% if (done) { %> + + + Clear <%= done %> + completed <%= done == 1 ? 'item' : 'items' %> + + +<% } %> \ No newline at end of file