PageRenderTime 41ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/ch12/todos/todos.js

http://github.com/maccman/book-assets
JavaScript | 164 lines | 107 code | 35 blank | 22 comment | 5 complexity | 51930201ca5688ba2090094705dbaf65 MD5 | raw file
Possible License(s): JSON
  1. jQuery(function($){
  2. // Our basic Todo model has `content` and `done` attributes.
  3. window.Todo = Backbone.Model.extend({
  4. defaults: {
  5. done: false
  6. },
  7. toggle: function() {
  8. this.save({done: !this.get("done")});
  9. }
  10. });
  11. window.TodoList = Backbone.Collection.extend({
  12. model: Todo,
  13. // Save all of the todo items under the `"todos"` namespace.
  14. localStorage: new Store("todos"),
  15. // Filter down the list of all todo items that are finished.
  16. done: function() {
  17. return this.filter(function(todo){ return todo.get('done'); });
  18. },
  19. remaining: function() {
  20. return this.without.apply(this, this.done());
  21. }
  22. });
  23. // Create our global collection of Todos.
  24. window.Todos = new TodoList;
  25. window.TodoView = Backbone.View.extend({
  26. //... is a list tag.
  27. tagName: "li",
  28. // Cache the template function for a single item.
  29. template: $("#item-template").template(),
  30. events: {
  31. "change .check" : "toggleDone",
  32. "dblclick .todo-content" : "edit",
  33. "click .todo-destroy" : "destroy",
  34. "keypress .todo-input" : "updateOnEnter",
  35. "blur .todo-input" : "close"
  36. },
  37. initialize: function() {
  38. _.bindAll(this, 'render', 'close', 'remove', 'edit');
  39. this.model.bind('change', this.render);
  40. this.model.bind('destroy', this.remove);
  41. },
  42. render: function() {
  43. var element = jQuery.tmpl(this.template, this.model.toJSON());
  44. $(this.el).html(element);
  45. this.input = this.$(".todo-input");
  46. return this;
  47. },
  48. toggleDone: function() {
  49. this.model.toggle();
  50. },
  51. // Switch this view into `"editing"` mode, displaying the input field.
  52. edit: function() {
  53. $(this.el).addClass("editing");
  54. this.input.focus();
  55. },
  56. // Close the `"editing"` mode, saving changes to the todo.
  57. close: function(e) {
  58. this.model.save({content: this.input.val()});
  59. $(this.el).removeClass("editing");
  60. },
  61. // If you hit `enter`, we're through editing the item.
  62. updateOnEnter: function(e) {
  63. if (e.keyCode == 13) e.target.blur();
  64. },
  65. remove: function() {
  66. $(this.el).remove();
  67. },
  68. destroy: function() {
  69. this.model.destroy();
  70. }
  71. });
  72. // Our overall **AppView** is the top-level piece of UI.
  73. window.AppView = Backbone.View.extend({
  74. // Instead of generating a new element, bind to the existing skeleton of
  75. // the App already present in the HTML.
  76. el: $("#todoapp"),
  77. statsTemplate: $("#stats-template").template(),
  78. events: {
  79. "keypress #new-todo": "createOnEnter",
  80. "click .todo-clear a": "clearCompleted"
  81. },
  82. // At initialization we bind to the relevant events on the `Todos`
  83. // collection, when items are added or changed. Kick things off by
  84. // loading any preexisting todos that might be saved in *localStorage*.
  85. initialize: function() {
  86. _.bindAll(this, 'addOne', 'addAll', 'render');
  87. this.input = this.$("#new-todo");
  88. Todos.bind('add', this.addOne);
  89. Todos.bind('refresh', this.addAll);
  90. Todos.bind('all', this.render);
  91. Todos.fetch();
  92. },
  93. // Re-rendering the App just means refreshing the statistics -- the rest
  94. // of the app doesn't change.
  95. render: function() {
  96. var done = Todos.done().length;
  97. var element = jQuery.tmpl(this.statsTemplate, {
  98. total: Todos.length,
  99. done: Todos.done().length,
  100. remaining: Todos.remaining().length
  101. });
  102. this.$('#todo-stats').html(element);
  103. },
  104. // Add a single todo item to the list by creating a view for it, and
  105. // appending its element to the `<ul>`.
  106. addOne: function(todo) {
  107. var view = new TodoView({model: todo});
  108. this.$("#todo-list").append(view.render().el);
  109. },
  110. // Add all items in the **Todos** collection at once.
  111. addAll: function() {
  112. Todos.each(this.addOne);
  113. },
  114. // If you hit return in the main input field, create new **Todo** model
  115. createOnEnter: function(e) {
  116. if (e.keyCode != 13) return;
  117. var value = this.input.val();
  118. if ( !value ) return;
  119. Todos.create({content: value});
  120. this.input.val('');
  121. },
  122. clearCompleted: function() {
  123. _.each(Todos.done(), function(todo){ todo.destroy(); });
  124. return false;
  125. }
  126. });
  127. // Finally, we kick things off by creating the **App**.
  128. window.App = new AppView;
  129. });