/todo-example/javascriptmvc/todo/todo/todo.js

https://github.com/mocheng/todomvc · JavaScript · 254 lines · 127 code · 44 blank · 83 comment · 7 complexity · 391d75116bc751dc0c7bce5cdbe05c45 MD5 · raw file

  1. // Load what we need
  2. steal.css('todo')
  3. .plugins('jquery/model/list',
  4. 'jquery/controller',
  5. 'jquery/view/ejs',
  6. 'jquery/lang/json')
  7. .then(function($){
  8. /**
  9. * A todo model for CRUDing todos.
  10. */
  11. $.Model('Todo',{
  12. /**
  13. * Gets JSON data from localStorage. Any changes that
  14. * get made in cb get written back to localStorage.
  15. *
  16. * This is unimportant for understanding JavaScriptMVC!
  17. */
  18. localStore: function(cb){
  19. var name = this.shortName,
  20. data = $.evalJSON( window.localStorage[name] || (window.localStorage[name] = "{}") ),
  21. res = cb.call(this, data);
  22. if(res !== false){
  23. window.localStorage[name] = $.toJSON(data);
  24. }
  25. },
  26. /**
  27. * Gets todos from localStorage.
  28. *
  29. * Todo.findAll({}, success(todos))
  30. */
  31. findAll: function(params , success){
  32. this.localStore(function(todos){
  33. instances = [];
  34. for(var id in todos){
  35. instances.push( new this( todos[id]) )
  36. }
  37. success && success(instances)
  38. })
  39. },
  40. /**
  41. * Destroys a list of todos by id from localStorage
  42. *
  43. * Todo.destroyAll([1,2], success())
  44. */
  45. destroyAll: function(ids, success){
  46. this.localStore(function(todos){
  47. $.each(ids, function(){
  48. delete todos[this]
  49. });
  50. });
  51. success();
  52. },
  53. /**
  54. * Destroys a single todo by id
  55. *
  56. * Todo.destroyAll(1, success())
  57. */
  58. destroy: function(id, success){
  59. this.destroyAll(id, success);
  60. this.localStore(function(todos){
  61. delete todos[id]
  62. });
  63. },
  64. /**
  65. * Creates a todo with the provided attrs. This allows:
  66. *
  67. * new Todo({text: 'hello'}).save( success(todo) );
  68. */
  69. create: function(attrs, success){
  70. this.localStore(function(todos){
  71. attrs.id = attrs.id || parseInt(100000 *Math.random())
  72. todos[attrs.id] = attrs;
  73. });
  74. success({id : attrs.id})
  75. },
  76. /**
  77. * Updates a todo by id with the provided attrs. This allows:
  78. *
  79. * todo.update({text: 'world'}, success(todos) )
  80. */
  81. update: function(id, attrs, success){
  82. this.localStore(function(todos){
  83. var todo = todos[id];
  84. $.extend(todo, attrs);
  85. });
  86. success({});
  87. }
  88. },{});
  89. /**
  90. * Helper methods on collections of todos. But lists can also use their model's
  91. * methods. Ex:
  92. *
  93. * var todos = [new Todo({id: 5}) , new Todo({id: 6})],
  94. * list = new Todo.List(todos);
  95. *
  96. * list.destroyAll() -> calls Todo.destroyAll with [5,6].
  97. */
  98. $.Model.List('Todo.List',{
  99. /**
  100. * Return a new Todo.List of only complete items
  101. */
  102. completed : function(){
  103. return this.grep(function(item){
  104. return item.complete === true;
  105. })
  106. }
  107. });
  108. /**
  109. * A Todos widget created like
  110. *
  111. * $("#todos").todos({ list: new Todo.List() });
  112. *
  113. * It listens on changes to the list and items in the list with the following actions:
  114. *
  115. * - "{list} add" - todos being added to the list
  116. * - "{list} remove" - todos being removed from the list
  117. * - "{list} update" - todos being updated in the list
  118. *
  119. */
  120. $.Controller('Todos',{
  121. // sets up the widget
  122. init : function(){
  123. // empties the create input element
  124. this.find(".create").val("")[0].focus();
  125. // fills this list of items (creates add events on the list)
  126. this.options.list.findAll();
  127. },
  128. // adds existing and created to the list
  129. "{list} add" : function(list, ev, items){
  130. // uses the todosEJS template (in todo.html) to render a list of items
  131. // then adds those items to #list
  132. this.find('#list').append("todosEJS",items)
  133. // calls a helper to update the stats info
  134. this.updateStats();
  135. },
  136. // Creating a todo --------------
  137. // listens for key events and creates a new todo
  138. ".create keyup" : function(el, ev){
  139. if(ev.keyCode == 13){
  140. new Todo({
  141. text : el.val(),
  142. complete : false
  143. }).save(this.callback('created'));
  144. el.val("");
  145. }
  146. },
  147. // When a todo is created, add it to this list
  148. "created" : function(todo){
  149. this.options.list.push(todo); //triggers 'add' on the list
  150. },
  151. // Destroying a todo --------------
  152. // the clear button is clicked
  153. ".todo-clear click" : function(){
  154. // gets completed todos in the list, destroys them
  155. this.options.list.completed()
  156. .destroyAll();
  157. },
  158. // When a todo's destroy button is clicked.
  159. ".todo .todestroy click" : function(el){
  160. el.closest('.todo').model().destroy();
  161. },
  162. // when an item is removed from the list ...
  163. "{list} remove" : function(list, ev, items){
  164. // get the elements in the list and remove them
  165. items.elements(this.element).slideUp(function(){
  166. $(this).remove();
  167. });
  168. this.updateStats();
  169. },
  170. // Updating a todo --------------
  171. // when the checkbox changes, update the model
  172. ".todo [name=complete] change" : function(el, ev){
  173. var todo = el.closest('.todo').model().update({
  174. complete : el.is(':checked')
  175. });
  176. },
  177. // switch to edit mode
  178. ".todo dblclick" : function(el){
  179. var input = $("<input name='text' class='text'/>").val(el.model().text)
  180. el.html(input);
  181. input[0].focus();
  182. },
  183. // update the todo's text on blur
  184. ".todo [name=text] focusout" : function(el, ev){
  185. var todo = el.closest('.todo').model().update({
  186. text : el.val()
  187. });
  188. },
  189. // when an item is updated
  190. "{list} update" : function(list, ev, item){
  191. item.elements().html("todoEJS", item);
  192. this.updateStats();
  193. //update completed
  194. },
  195. // a helper that updates the stats
  196. updateStats : function(){
  197. var list = this.options.list,
  198. completed = list.completed().length;
  199. $("#todo-stats").html("statsEJS",{
  200. completed : completed,
  201. total : list.length,
  202. remaining : list.length - completed
  203. })
  204. }
  205. })
  206. $(function(){
  207. // create a todos widget with a list
  208. $("#todos").todos({list : new Todo.List()});
  209. })
  210. });