Commit 7188e3bf authored by Laszlo Bacsi's avatar Laszlo Bacsi Committed by Sindre Sorhus

DerbyJS: Various improvements

parent 66197be6
......@@ -3,21 +3,25 @@ derby = require 'derby'
derby.use(require '../../ui')
# Define a rendering function to handle both /:groupName and
# /:groupName/filterName.
renderGroup = (page, model, {groupName, filterName}) ->
## ROUTES ##
# Redirect the visitor to a random todo list
get '/', (page) ->
page.redirect '/' + parseInt(Math.random() * 1e9).toString(36)
# Sets up the model, the reactive function for stats and renders the todo list
get '/:groupName', (page, model, {groupName}) ->
groupTodosQuery = model.query('todos').forGroup(groupName)
model.subscribe "groups.#{groupName}", groupTodosQuery, (err, group, groupTodos) ->
model.ref '_group', group
model.setNull('_group._id', groupName)
group.setNull 'id', groupName
todoIds = group.at 'todoIds' or []
# The refList supports array methods, but it stores the todo values on an
# object by id. The todos are stored on the object
# 'groups.groupName.todos', and their order is stored in an array of ids at
# '_group.todoIds'
model.refList '_todoList', "groups.#{groupName}.todos", todoIds
# The refList supports array methods, but it stores the todo values
# on an object by id. The todos are stored on the object 'todos',
# and their order is stored in an array of ids at '_group.todoIds'
model.refList '_todoList', 'todos', todoIds
# Create a reactive function that automatically keeps '_stats'
# updated with the number of remaining and completed todos.
......@@ -36,63 +40,60 @@ renderGroup = (page, model, {groupName, filterName}) ->
oneOnly: remaining == 1,
}
filterName = filterName or 'all'
page.render 'todo',
filterName: filterName
groupName: groupName
# Do not filter the list by default
model.del '_filter'
## ROUTES ##
get '/', (page) ->
page.redirect '/' + parseInt(Math.random() * 1e9).toString(36)
page.render 'todo'
get '/:groupName', renderGroup
get '/:groupName/:filterName', renderGroup
# Transitional route for enabling a filter
get {from: '/:groupName', to: '/:groupName/:filterName'},
forward: (model, {filterName}, next) ->
# enable the filter
model.set '_filter', filterName
back: (model, params, next) ->
# disable the filter
model.del '_filter'
ready (model) ->
list = model.at '_todoList'
group = model.at '_group'
all_completed = group.at 'all_completed'
group.on 'set', 'select_all', (select_all, previous_value, isLocal, e) ->
# We only want to react to select_all being set if it's in response
group.on 'set', 'all_completed', (all_completed, previous_value, isLocal, e) ->
# We only want to react to all_completed being set if it's in response
# to a UI event (as opposed to our checkAllCompleted below checking
# individual items).
return unless e
# Is there a way to do this with one call rather than iterating?
todos = model.at('_group.todos')
for item in list.get()
todos.set("#{item.id}.completed", select_all)
for {id} in list.get()
model.set "todos.#{id}.completed", all_completed
newTodo = model.at '_newTodo'
exports.add = ->
# Don't add a blank todo
text = view.escapeHtml newTodo.get().trim()
text = newTodo.get().trim()
newTodo.set ''
return unless text
# Insert the new todo before the first completed item in the list
# or append to the end if none are completed
items = list.get()
i = 0
if items
for todo, i in list.get()
break if todo.completed
list.insert i, {text:text, completed: false, group: model.get '_group.id'}
group.set('select_all', false)
list.push text: text, completed: false, group: group.get('id')
all_completed.set false
exports.del = (e) ->
# Derby extends model.at to support creation from DOM nodes
model.at(e.target).remove()
exports.clearCompleted = ->
completed_indexes = (i for item, i in list.get() when item.completed)
completed_indexes = (i for {completed}, i in list.get() when completed)
list.remove(i) for i in completed_indexes.reverse()
group.set('select_all', false)
all_completed.set false
exports.checkAllCompleted = ->
allCompleted = true
allCompleted &&= item.completed for item in list.get()
group.set('select_all', allCompleted)
for {completed} in list.get() when not completed
all_completed.set false
return
all_completed.set true
exports.endEdit = (e) ->
target = e.target
......@@ -100,11 +101,9 @@ ready (model) ->
target.firstChild.blur()
return
item = model.at(target)
item.set('_editing', false)
text = item.get('text').trim()
if not text
item.remove()
item.set '_editing', false
item.remove() if item.get('text').trim() == ''
exports.startEdit = (e) ->
item = model.at(e.target)
item.set('_editing', true)
item.set '_editing', true
......@@ -61,12 +61,6 @@ button#clear-completed.non-completed {
display: none;
}
#filters.all li.all a,
#filters.active li.active a,
#filters.completed li.completed a {
font-weight: bold;
}
#todo-list li.editing input.toggle,
#todo-list li.editing button.destroy {
display: none;
......
......@@ -24,9 +24,9 @@
<app:TodoHeader>
<section id="main" class="{#unless _todoList}empty-list{/}">
<input id="toggle-all" type="checkbox" checked="{_group.select_all}">
<input id="toggle-all" type="checkbox" checked="{_group.all_completed}">
<label for="toggle-all">Mark all as complete</label>
<ul id=todo-list class={{filterName}}>{#each _todoList}<app:todo>{/}</ul>
<ul id=todo-list class={_filter}>{#each _todoList}<app:todo>{/}</ul>
</section>
<app:TodoFooter>
......@@ -47,15 +47,15 @@
<TodoFooter:>
<footer id="footer" class="{#unless _todoList}empty-list{/}">
<span id="todo-count"><strong>{_stats.remaining}</strong> item{#unless _stats.oneOnly}s{/} left</span>
<ul id="filters" class="{filterName}">
<ul id="filters">
<li class="all">
<a href="/{{groupName}}">All</a>
<a href="/{{_group.id}}" class="{#unless _filter}selected{/}">All</a>
</li>
<li class="active">
<a href="/{{groupName}}/active">Active</a>
<a href="/{{_group.id}}/active" class="{#if equal(_filter, 'active')}selected{/}">Active</a>
</li>
<li class="completed">
<a href="/{{groupName}}/completed">Completed</a>
<a href="/{{_group.id}}/completed" class="{#if equal(_filter, 'completed')}selected{/}">Completed</a>
</li>
</ul>
<button x-bind=click:clearCompleted id="clear-completed" class="{#unless _stats.completed}non-completed{/}">Clear completed (<span>{_stats.completed}</span>)</button>
......@@ -63,7 +63,8 @@
<Info:>
<footer id="info">
<h3>Open this <a href="/{{groupName}}">ToDo list</a> in another browser, or share it with a friend to collaborate!</h3>
<h3>Open this <a href="/{{_group.id}}">ToDo list</a> in another browser, or share it with a friend to collaborate!</h3>
<p>Click on a todo to edit</p>
<p>Template by <a href="http://github.com/sindresorhus">Sindre Sorhus</a></p>
<p>Created by <a href="http://micknelson.wordpress.com">Michael Nelson</a> and <a href="https://github.com/lackac">László Bácsi</a></p>
<p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment