Skip to content
Browse files

updated todos reference app; fixed structure of the app to not be wie…

…rd (global Todos collection?)
  • Loading branch information...
1 parent 805a62d commit 8e550d423a988454435e6dc0ceca052d5bacaba4 @politician committed Feb 14, 2012
Showing with 146 additions and 83 deletions.
  1. +0 −20 examples/todos/index.html
  2. +146 −63 examples/todos/todos.coffee
View
20 examples/todos/index.html
@@ -35,16 +35,13 @@
<span class="ui-tooltip-top" style="display:none;">Press Enter to save this task</span>
</div>
- <!-- Each <li> is a TodoView -->
<div id="todos">
<ul id="todo-list"></ul>
</div>
- <!-- Stats -->
<div id="todo-stats"></div>
</div>
-
</div>
<ul id="instructions">
@@ -58,22 +55,5 @@
<a href="http://jgn.me/">J&eacute;r&ocirc;me Gravel-Niquet</a>
</div>
- <script type="text/template" id="stats-template">
- <% if (total) { %>
- <span class="todo-count">
- <span class="number"><%= remaining %></span>
- <span class="word"><%= remaining == 1 ? 'item' : 'items' %></span> left.
- </span>
- <% } %>
- <% 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>
- <% } %>
- </script>
-
</body>
</html>
View
209 examples/todos/todos.coffee
@@ -10,7 +10,7 @@ Todo Model
class Todo extends Backbone.Model
defaults: ->
done: false
- order: Todos.nextOrder()
+ order: 0
###
@@ -43,15 +43,10 @@ class TodoList extends Backbone.Collection
# Todos are kept sorted by their original insertion order.
comparator: (todo) ->
todo.get 'order'
-
-###
-Todo Item View Model
-###
-# The view model tracks transient state such as whether we're in "edit" mode.
-class TodoViewModel extends Backbone.Model
- defaults:
- editing: false
+ # Destroys any todos which have been completed, removes their views.
+ clearCompleted: =>
+ _.each @done(), (todo) -> todo.destroy()
###
Todo Item View
@@ -63,8 +58,7 @@ class TodoView extends Backbone.View
# ... is a list tag.
tagName: 'li'
- # CoffeeScript + outback === <3
- template: '''
+ html: '''
<div class="todo" data-bind="css: { done: @done }">
<div class="display">
<input class="check" type="checkbox" data-bind="checked: @done" />
@@ -77,38 +71,39 @@ class TodoView extends Backbone.View
</div>
'''
- # The view model...
- viewModel: new TodoViewModel
+ # The view model tracks transient state such as whether we're in "edit" mode.
+ viewModel: new Backbone.Model
+ editing: false
# ... is bound to the DOM, unobtrusively. This is the equivalent of adding
- # a data-bind-view attribute to the div with the todo class.
+ # a data-bind-view attributes to the html.
viewModelBindings:
'div.todo':
css:
- editing: Backbone.outback.modelRef 'editing'
+ editing: @::modelref 'editing'
'div.todo-input':
hasfocus:
- editing: Backbone.outback.modelRef 'editing'
+ editing: @::modelref 'editing'
# Listen to the DOM.
events:
- 'dblclick div.todo-text' : 'edit'
+ 'click div.todo-text' : 'edit'
'click span.todo-destroy' : 'clear'
'keypress .todo-input' : 'updateOnEnter'
# The TodoView listens for changes to its model, re-rendering.
initialize: ->
# Remove the view from the DOM if its model is destroyed.
- @model.bind 'destroy', @remove, @
+ @model.on 'destroy', @remove, @
# Monitor the editing variable, so that we can save the todo after an
# edit.
- @viewModel.bind 'change:editing', @saveIfEditComplete, @
+ @viewModel.on 'change:editing', @editChanging, @
render: =>
# Insert the template into the DOM
- @$el.html @template
+ @$el.html @html
# Tell outback to set up any data bindings
Backbone.outback.bind @
@@ -123,88 +118,172 @@ class TodoView extends Backbone.View
# Switch this view into "editing" mode, displaying the input field.
edit: =>
+ console.log 'edit'
@viewModel.set 'editing', true
# If you hit enter, we're through editing the item.
updateOnEnter: (e) =>
@viewModel.set 'editing', false if e.keyCode is 13
# Close the "editing" mode, saving changes to the todo.
- saveIfEditComplete: =>
+ editChanging: =>
+ console.log 'editChanging'
@model.save() if !@viewModel.get 'editing'
# Destroy the model, triggering the removal of this view.
clear: =>
@model.destroy()
+
+###
+Todo List View
+###
+
+# The DOM element for the todo list...
+class TodoListView extends Backbone.View
+
+ # is already present in the HTML
+ el: $('#todo-list')
+
+ # At initialization we bind to the relevant events on the *TodoList*
+ # collection, when items are added or changed. Kick things off by loading
+ # any preexisting todos that might be saved in localStorage.
+ initialize: ->
+ @model.on 'add', @addOne, @
+ @model.on 'reset', @addAll, @
+
+ @model.fetch()
+
+ # Add a single todo item to the list by creating a view for it, and
+ # appending its element to the `<ul>`.
+ addOne: (todo) =>
+ view = new TodoView model: todo
+ @$el.append(view.render().el);
+
+ # Create views for all of the items in the *Todos* collection at once.
+ addAll: =>
+ @model.each @addOne
+
+###
+Summary View
+###
+
+class SummaryView extends Backbone.View
+
+ el: $('#todo-stats')
+
+ html: '''
+ <span class="todo-count">
+ <span class="number"></span>
+ <span class="word"></span>
+ </span>
+ <span class="todo-clear">
+ <a href="#">
+ Clear <span class="number-done"></span>
+ completed <span class="word-done"></span>
+ </a>
+ </span>
+ '''
+
+ # The view model used to bind transient stats to the view.
+ viewModel: new Backbone.Model
+ total: 0
+ done: 0
+ remaining: 0
+
+ # Configure the data bindings
+ viewModelBindings:
+ '.todo-count':
+ visible: @::modelref 'total'
+
+ '.todo-count .number':
+ text: @::modelref 'remaining'
+
+ '.todo-count .word':
+ plural: @::modelref 'remaining'
+ pluralOptions: word: 'item'
+
+ '.todo-clear':
+ visible: @::modelref 'done'
+
+ '.todo-clear .number-done':
+ text: @::modelref 'done'
+
+ '.todo-count .word-done':
+ plural: @::modelref 'done'
+ pluralOptions: word: 'item'
+
+ # Our model is the the shared instance of the todos collection which we
+ # monitor so that we can keep the statistics up to date.
+ initialize: ->
+ @model.on 'all', @update, @
+ @update()
+
+ render: =>
+ @$el.empty().append @html
+ Backbone.outback.bind @
+
+ remove: =>
+ Backbone.outback.unbind @
+
+ # TODO: Improve outback support for collections so that we don't have to
+ # use a view model for this.
+ update: =>
+ @viewModel.set
+ total: @model.length
+ done: @model.done().length
+ remaining: @model.remaining().length
###
The Application
###
-# Our overall *AppView* is the top-level piece of UI.
-class AppView extends Backbone.View
+# Our overall *MainView* is the top-level piece of UI.
+class MainView extends Backbone.View
# 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()
-
# Delegated events for creating new items, and clearing completed ones.
events:
'keypress #new-todo' : 'createOnEnter'
'keyup #new-todo' : 'showTooltip'
'click .todo-clear a' : 'clearCompleted'
- # At initialization we bind to the relevant events on the `Todos`
- # collection, when items are added or changed. Kick things off by loading
- # any preexisting todos that might be saved in localStorage.
initialize: ->
@input = @$('#new-todo')
- @stats = @$('#todo-stats')
- Todos.on 'add', @addOne, @
- Todos.on 'reset', @addAll, @
- Todos.on 'all', @render, @
+ # Initialize the TodoList, pulling in any existing todos from storage.
+ @collection = new TodoList
- Todos.fetch()
+ # Initialize our nested views.
+ @todos = new TodoListView model: @collection
+ @summary = new SummaryView model: @collection
- # Re-rendering the App just means refreshing the statistics -- the rest of
- # the app doesn't change.
render: =>
- @stats.html @statsTemplate
- total: Todos.length
- done: Todos.done().length
- remaining: Todos.remaining().length
+ @todos.render()
+ @summary.render()
- # Add a single todo item to the list by creating a view for it, and
- # appending its element to the `<ul>`.
- addOne: (todo) =>
- view = new TodoView
- model: todo
-
- $("#todo-list").append(view.render().el);
-
- # Create views for all of the items in the *Todos* collection at once.
- addAll: =>
- Todos.each @addOne
+ remove: =>
+ @todos.remove()
+ @summary.remove()
# If you hit return in the main input field, and there is text to save,
# create new Todo model persisting it to localStorage.
createOnEnter: (e) =>
text = @input.val();
+
return unless !!text and e.keyCode is 13
- Todos.create
- text: text
+ @collection.create
+ text: text,
+ order: @collection.nextOrder()
@input.val ''
# Clear all done todo items, destroying their models.
clearCompleted: (e) =>
- _.each Todos.done(), (todo) -> todo.destroy()
-
+ @collection.clearCompleted()
e.preventDefault()
false
@@ -226,15 +305,19 @@ class AppView extends Backbone.View
@tooltipTimeout = _.delay callback, 1000
-# Attach our globals to the window.
+
+class AppRouter extends Backbone.Router
+
+ routes:
+ '': 'index'
+
+ index: ->
+ @mainView = new MainView
+ @mainView.render()
+
# Finally, kick off the app
$ ->
- #window.Todo = Todo
- #window.TodoList = TodoList
- #window.TodoView = TodoView
- #window.AppView = AppView
-
- window.Todos = new TodoList
- window.App = new AppView
+ window.app = new AppRouter
+ Backbone.history.start()

0 comments on commit 8e550d4

Please sign in to comment.
Something went wrong with that request. Please try again.