Commit e280987d authored by Sindre Sorhus's avatar Sindre Sorhus

Batman app: Cleanup

parent e1843aab
# Batman TodoMVC # Batman • [TodoMVC](http://todomvc.com)
A todo app built using [Batman](http://batmanjs.org), inspired by [TodoMVC](https://github.com/addyosmani/todomvc). A todo app built using [Batman](http://batmanjs.org)
## Running it
Spin up an HTTP server and visit http://localhost/labs/architecture-examples/batman/index.html ## Run
Spin up an HTTP server and visit http://localhost/labs/architecture-examples/batman/
## Persistence ## Persistence
A quick note: This app uses `Batman.LocalStorage` to persist the Todo records across page reloads. Batman's `localStorage` engine sticks each record under it's own key in `localStorage`, which is a departure from the TodoMVC application specification, which asks that all the records are stored under one key as a big blob. Batman stores records this way so that the whole set doesn't need to be parsed just to find one record or check if that record exists. A quick note: This app uses `Batman.LocalStorage` to persist the Todo records across page reloads. Batman's `localStorage` engine sticks each record under it's own key in `localStorage`, which is a departure from the TodoMVC application specification, which asks that all the records are stored under one key as a big blob. Batman stores records this way so that the whole set doesn't need to be parsed just to find one record or check if that record exists.
## Building it
This app is written in CoffeeScript, so to make changes, please edit `js/app.coffee` and rebuild the JavaScript with the `coffee` compiler.
## Build
This app is written in CoffeeScript, so to make changes, please edit `js/app.coffee` and rebuild the JavaScript with the `coffee` compiler.
\ No newline at end of file
...@@ -7,68 +7,66 @@ ...@@ -7,68 +7,66 @@
<link rel="stylesheet" href="../../../assets/base.css"> <link rel="stylesheet" href="../../../assets/base.css">
</head> </head>
<body> <body>
<div data-yield="main"></div> <div data-yield="main"></div>
<div data-defineview="todos/all"> <div data-defineview="todos/all">
<section id="todoapp"> <section id="todoapp">
<header id="header"> <header id="header">
<h1>todos</h1> <h1>todos</h1>
<form data-formfor-todo="newTodo" data-event-submit="createTodo"> <form data-formfor-todo="newTodo" data-event-submit="createTodo">
<input id="new-todo" type="text" placeholder="What needs to be completed?" autofocus data-bind="todo.title"> <input id="new-todo" type="text" placeholder="What needs to be completed?" autofocus data-bind="todo.title">
</form> </form>
</header> </header>
<section id="main" data-showif="Todo.all.length"> <section id="main" data-showif="Todo.all.length">
<input id="toggle-all" type="checkbox" data-event-change="toggleAll" data-source="Todo.completed.length | equals Todo.all.length"> <input id="toggle-all" type="checkbox" data-event-change="toggleAll" data-source="Todo.completed.length | equals Todo.all.length">
<label for="toggle-all">Mark all as complete</label> <label for="toggle-all">Mark all as complete</label>
<ul id="todo-list"> <ul id="todo-list">
<li data-foreach-todo="currentTodos" <li data-foreach-todo="currentTodos"
data-addclass-completed="todo.completed" data-addclass-completed="todo.completed"
data-addclass-editing="todo.editing" > data-addclass-editing="todo.editing" >
<div class="view" data-hideif="todo.editing" data-event-doubleclick="toggleEditing">
<div class="view" data-hideif="todo.editing" data-event-doubleclick="toggleEditing"> <input class="toggle" type="checkbox" data-bind="todo.completed" data-event-change="todoDoneChanged">
<input class="toggle" type="checkbox" data-bind="todo.completed" data-event-change="todoDoneChanged"> <label data-bind="todo.title"></label>
<label data-bind="todo.title"></label> <button class="destroy" data-event-click="destroyTodo"></button>
<button class="destroy" data-event-click="destroyTodo"></button> </div>
</div> <input class="edit" type="text"
data-bind="todo.title"
<input class="edit" type="text" data-bind-id="'todo-input-' | append todo.id"
data-bind="todo.title" data-event-blur="toggleEditing"
data-bind-id="'todo-input-' | append todo.id" data-event-keypress="disableEditingUponSubmit">
data-event-blur="toggleEditing" </li>
data-event-keypress="disableEditingUponSubmit" > </ul>
</section>
</li> <footer id="footer" data-showif="Todo.all.length">
</ul> <span id="todo-count">
</section> <strong data-bind="Todo.active.length"></strong>
<footer id="footer" data-showif="Todo.all.length"> <span data-bind="'item' | pluralize Todo.active.length, false"></span> left
<span id="todo-count"> </span>
<strong data-bind="Todo.active.length"></strong> <ul id="filters">
<span data-bind="'item' | pluralize Todo.active.length, false"></span> <li>
left <a data-addclass-selected="currentRoute.action | equals 'all'" data-route="'/'">All</a>
</span> </li>
<ul id="filters"> <li>
<li> <a data-addclass-selected="currentRoute.action | equals 'active'" data-route="'/active'">Active</a>
<a data-addclass-selected="currentRoute.action | equals 'all'" data-route="'/'">All</a> </li>
</li> <li>
<li> <a data-addclass-selected="currentRoute.action | equals 'completed'" data-route="'/completed'">Completed</a>
<a data-addclass-selected="currentRoute.action | equals 'active'" data-route="'/active'">Active</a> </li>
</li> </ul>
<li> <button id="clear-completed" data-event-click="clearCompleted" data-showif="Todo.completed.length">
<a data-addclass-selected="currentRoute.action | equals 'completed'" data-route="'/completed'">Completed</a> Clear completed (<span data-bind="Todo.completed.length"></span>)
</li> </button>
</ul> </footer>
<button id="clear-completed" data-event-click="clearCompleted" data-showif="Todo.completed.length">Clear completed (<span data-bind="Todo.completed.length"></span>)</button> </section>
</footer> <footer id="info">
</section> <p>Double-click to edit a todo</p>
<footer id="info"> <p>Template by <a href="http://sindresorhus.com">Sindre Sorhus</a></p>
<p>Double-click to edit a todo</p> <p>Created by <a href="http://batmanjs.org">Harry Brundage</a></p>
<p>Template by <a href="http://sindresorhus.com">Sindre Sorhus</a></p> <p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
<p>Created by <a href="http://batmanjs.org">Harry Brundage</a></p> </footer>
<p>Part of <a href="http://todomvc.com">TodoMVC</a></p> </div>
</footer>
</div>
<script src="../../../assets/base.js"></script> <script src="../../../assets/base.js"></script>
<script src="js/es5-shim.js"></script> <script src="js/es5-shim.js"></script>
<script src="js/batman.js"></script> <script src="js/lib/batman.js"></script>
<script src="js/app.js"></script> <script src="js/app.js"></script>
</body> </body>
</html> </html>
\ No newline at end of file
class Alfred extends Batman.App class Alfred extends Batman.App
@root 'todos#all' @root 'todos#all'
@route "/completed", "todos#completed" @route '/completed', 'todos#completed'
@route "/active", "todos#active" @route '/active', 'todos#active'
class Alfred.TodosController extends Batman.Controller class Alfred.TodosController extends Batman.Controller
constructor: -> constructor: ->
super super
@set 'newTodo', new Alfred.Todo(completed: false) @set 'newTodo', new Alfred.Todo(completed: false)
all: -> all: ->
@set 'currentTodos', Alfred.Todo.get('all') @set 'currentTodos', Alfred.Todo.get('all')
completed: -> completed: ->
@set 'currentTodos', Alfred.Todo.get('completed') @set 'currentTodos', Alfred.Todo.get('completed')
@render source: 'todos/all' @render source: 'todos/all'
active: -> active: ->
@set 'currentTodos', Alfred.Todo.get('active') @set 'currentTodos', Alfred.Todo.get('active')
@render source: 'todos/all' @render source: 'todos/all'
createTodo: -> createTodo: ->
@get('newTodo').save (err, todo) => @get('newTodo').save (err, todo) =>
if err if err
throw err unless err instanceof Batman.ErrorsSet throw err unless err instanceof Batman.ErrorsSet
else else
@set 'newTodo', new Alfred.Todo(completed: false, title: "") @set 'newTodo', new Alfred.Todo(completed: false, title: "")
todoDoneChanged: (node, event, context) -> todoDoneChanged: (node, event, context) ->
todo = context.get('todo') todo = context.get('todo')
todo.save (err) -> todo.save (err) ->
throw err if err && !err instanceof Batman.ErrorsSet throw err if err && !err instanceof Batman.ErrorsSet
destroyTodo: (node, event, context) -> destroyTodo: (node, event, context) ->
todo = context.get('todo') todo = context.get('todo')
todo.destroy (err) -> throw err if err todo.destroy (err) -> throw err if err
toggleAll: (node, context) -> toggleAll: (node, context) ->
Alfred.Todo.get('all').forEach (todo) -> Alfred.Todo.get('all').forEach (todo) ->
todo.set('completed', !!node.checked) todo.set('completed', !!node.checked)
todo.save (err) -> todo.save (err) ->
throw err if err && !err instanceof Batman.ErrorsSet throw err if err && !err instanceof Batman.ErrorsSet
clearCompleted: -> clearCompleted: ->
Alfred.Todo.get('completed').forEach (todo) -> Alfred.Todo.get('completed').forEach (todo) ->
todo.destroy (err) -> throw err if err todo.destroy (err) -> throw err if err
toggleEditing: (node, event, context) -> toggleEditing: (node, event, context) ->
todo = context.get('todo') todo = context.get('todo')
editing = todo.set('editing', !todo.get('editing')) editing = todo.set('editing', !todo.get('editing'))
if editing if editing
input = document.getElementById("todo-input-#{todo.get('id')}") input = document.getElementById("todo-input-#{todo.get('id')}")
input.focus() input.select()
input.select() else
else if todo.get('title')?.length > 0
if todo.get('title')?.length > 0 todo.save (err, todo) ->
todo.save (err, todo) -> throw err if err && !err instanceof Batman.ErrorsSet
throw err if err && !err instanceof Batman.ErrorsSet else
else todo.destroy (err, todo) ->
todo.destroy (err, todo) -> throw err if err
throw err if err
disableEditingUponSubmit: (node, event, context) ->
disableEditingUponSubmit: (node, event, context) -> if Batman.DOM.events.isEnter(event)
if Batman.DOM.events.isEnter(event) @toggleEditing(node, event, context)
@toggleEditing(node, event, context)
class Alfred.Todo extends Batman.Model class Alfred.Todo extends Batman.Model
@encode 'title', 'completed' @encode 'title', 'completed'
@persist Batman.LocalStorage @persist Batman.LocalStorage
@validate 'title', presence: true @validate 'title', presence: true
@storageKey: 'todos-batman' @storageKey: 'todos-batman'
@classAccessor 'active', -> @classAccessor 'active', ->
@get('all').filter (todo) -> !todo.get('completed') @get('all').filter (todo) -> !todo.get('completed')
@classAccessor 'completed', -> @classAccessor 'completed', ->
@get('all').filter (todo) -> todo.get('completed') @get('all').filter (todo) -> todo.get('completed')
@wrapAccessor 'title', (core) -> @wrapAccessor 'title', (core) ->
set: (key, value) -> core.set.call(@, key, value?.trim()) set: (key, value) -> core.set.call(@, key, value?.trim())
window.Alfred = Alfred window.Alfred = Alfred
Alfred.run() Alfred.run()
\ No newline at end of file
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