Permalink
Browse files

initial commit of todo list with backbone and require working

  • Loading branch information...
Ryan Rauh
Ryan Rauh committed Feb 26, 2011
0 parents commit 87918d4c3ad6bcc9e6dd697b3892ecfb17324d0f
Binary file not shown.

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -0,0 +1,24 @@
+define([ "../models/todo","../localStorage"], function(Todo){
+ var TodoList = Backbone.Collection.extend({
+ model : Todo,
+ localStorage: new Store("todos"),
+ done: function(){
+ return this.filter(function(todo){ return todo.get('done'); });
+ },
+ remaining: function(){
+ return this.without.apply(this, this.done());
+ },
+ nextOrder : function() {
+ if(!this.length) return 1;
+ return this.last().get('order') + 1;
+ },
+ comparator: function(todo){
+ return todo.get('order');
+ }
+
+
+
+ });
+
+ return new TodoList;
+});
@@ -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");
+ }
+};
@@ -0,0 +1,10 @@
+define(["./views/appView",
+ "util/loadCss",
+ "/content/scripts/lib/backbone.js",
+ "/content/scripts/lib/underscore.js",
+ "/content/scripts/lib/jquery.tmpl.js"],
+ function (AppView, loadCss) {
+ //loadCss("todos");
+ var app = new AppView();
+ return {};
+ });
@@ -0,0 +1,22 @@
+define([], function(){
+ var Todo = Backbone.Model.extend({
+ defaults : {
+ content: "empty todo ...",
+ done: false
+ },
+ initialize: function (){
+ if(!this.get("content")){
+ this.set({"content":this.defaults.content});
+ }
+ },
+ toggle : function () {
+ this.save({done: !this.get('done')});
+ },
+ clear: function () {
+ this.destroy();
+ this.view.remove();
+ }
+
+ });
+ return Todo;
+});
@@ -0,0 +1,14 @@
+{{if (total) }}
+<span class="todo-count">
+ <span class="number">${ remaining }</span>
+ <span class="word">${ remaining == 1 ? 'item' : 'items' }</span> left.
+</span>
+{{/if}}
+{{if (done) }}
+<span class="todo-clear">
+ <a href="#">
+ Clear <span class="number-done">${ done }</span>
+ completed <span class="word-done">${ done == 1 ? 'item' : 'items' }</span>
+ </a>
+</span>
+{{/if}}
@@ -0,0 +1,11 @@
+<div class="todo ${ done ? 'done' : '' }">
+ <div class="display">
+ <input class="check" type="checkbox" ${ done ? 'checked="checked"' : '' } />
+ <div class="todo-content"></div>
+ <span class="todo-destroy"></span>
+ </div>
+ <div class="edit">
+ <input class="todo-input" type="text" value="" />
+ </div>
+</div>
+
@@ -0,0 +1,65 @@
+define(["text!../templates/stats.js","../collections/todoList","./todoView"], function(statsTemplate, Todos,TodoView){
+ var AppView = Backbone.View.extend({
+ el : $("#todoapp"),
+ statsTemplate: function(data, options){return $.tmpl(statsTemplate, data, options);},
+ events: {
+ "keypress #new-todo":"createOnEnter",
+ "keyup #new-todo" : "showTooltip",
+ "click .todo-clear a": "clearCompleted"
+ },
+ initialize: function(){
+ _.bindAll(this, 'addOne', 'addAll', 'render');
+ this.input = this.$("#new-todo");
+
+ Todos.bind('add', this.addOne);
+ Todos.bind('refresh', this.addAll);
+ Todos.bind('all', this.render);
+
+ Todos.fetch();
+ },
+ render: function(){
+ var done = Todos.done().length;
+ this.$('#todo-stats').html(this.statsTemplate({
+ total: Todos.length,
+ done: Todos.done().length,
+ remaining: Todos.remaining().length
+ }))
+ },
+ addOne : function(todo){
+ var view = new TodoView({model:todo});
+ this.$("#todo-list").append(view.render().el);
+ },
+ addAll : function() {
+ Todos.each(this.addOne);
+ },
+ newAttributes : function(){
+ return {
+ content: this.input.val(),
+ order: Todos.nextOrder(),
+ done: false
+ };
+ },
+ createOnEnter: function(e) {
+ if (e.keyCode != 13) return;
+ Todos.create(this.newAttributes());
+ this.input.val('');
+ },
+ clearCompleted: function() {
+ _.each(Todos.done(), function(todo){ todo.clear(); });
+ return false;
+ },
+ showTooltip: function(e) {
+ var tooltip = this.$(".ui-tooltip-top");
+ var val = this.input.val();
+ tooltip.fadeOut();
+ if (this.tooltipTimeout) clearTimeout(this.tooltipTimeout);
+ if (val == '' || val == this.input.attr('placeholder')) return;
+ var show = function(){ tooltip.show().fadeIn(); };
+ this.tooltipTimeout = _.delay(show, 1000);
+ }
+
+ });
+ return AppView;
+
+});
+
@@ -0,0 +1,66 @@
+define(["text!../templates/todo.js"], function (templateText) {
+ var TodoView = Backbone.View.extend({
+ tagName:"li",
+ template: function(data, options){ return $.tmpl(templateText, data, options)},
+ events: {
+ "click .check" : "toggleDone",
+ "dblclick div.todo-content" : "edit",
+ "click span.todo-destroy" : "clear",
+ "keypress .todo-input" : "updateOnEnter"
+ },
+ initialize : function(){
+ _.bindAll(this, 'render', this.render);
+ this.model.bind('change', this.render);
+ this.model.view = this;
+ },
+
+ render : function(){
+ $(this.el).html(this.template(this.model.toJSON()));
+ this.setContent();
+ return this;
+ },
+ // To avoid XSS (not that it would be harmful in this particular app),
+ // we use `jQuery.text` to set the contents of the todo item.
+ setContent: function() {
+ var content = this.model.get('content');
+ this.$('.todo-content').text(content);
+ this.input = this.$('.todo-input');
+ this.input.bind('blur', this.close);
+ this.input.val(content);
+ },
+ // Toggle the `"done"` state of the model.
+ toggleDone: function() {
+ this.model.toggle();
+ },
+
+ // Switch this view into `"editing"` mode, displaying the input field.
+ edit: function() {
+ $(this.el).addClass("editing");
+ this.input.focus();
+ },
+
+ // Close the `"editing"` mode, saving changes to the todo.
+ close: function() {
+ this.model.save({content: this.input.val()});
+ $(this.el).removeClass("editing");
+ },
+
+ // If you hit `enter`, we're through editing the item.
+ updateOnEnter: function(e) {
+ if (e.keyCode == 13) this.close();
+ },
+
+ // Remove this view from the DOM.
+ remove: function() {
+ $(this.el).remove();
+ },
+
+ // Remove the item, destroy the model.
+ clear: function() {
+ this.model.clear();
+ }
+
+
+ });
+ return TodoView;
+});
Oops, something went wrong.

0 comments on commit 87918d4

Please sign in to comment.