Commit 8100a7c3 authored by Sindre Sorhus's avatar Sindre Sorhus

Epitome app: Clean up, code style fixes, add readme

parent 91c5de72
/* base.css overrides */
\ No newline at end of file
<!doctype html> <!doctype html>
<html lang="en" xmlns="http://www.w3.org/1999/html"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Epitome • TodoMVC</title> <title>Epitome • TodoMVC</title>
<link rel="stylesheet" href="../../../assets/base.css"> <link rel="stylesheet" href="../../../assets/base.css">
<!-- CSS overrides - remove if you don't need it -->
<link rel="stylesheet" href="css/app.css">
<!--[if IE]> <!--[if IE]>
<script src="../../../assets/ie.js"></script> <script src="../../../assets/ie.js"></script>
<![endif]--> <![endif]-->
...@@ -17,35 +15,29 @@ ...@@ -17,35 +15,29 @@
<h1>todos</h1> <h1>todos</h1>
<input id="new-todo" placeholder="What needs to be done?" autofocus> <input id="new-todo" placeholder="What needs to be done?" autofocus>
</header> </header>
<!-- This section should be hidden by default and shown when there are todos -->
<section id="main"> <section id="main">
<input id="toggle-all" type="checkbox"> <input id="toggle-all" type="checkbox">
<label for="toggle-all">Mark all as complete</label> <label for="toggle-all">Mark all as complete</label>
<ul id="todo-list"></ul> <ul id="todo-list"></ul>
</section> </section>
<!-- This footer should hidden by default and shown when there are todos -->
<footer id="footer"></footer> <footer id="footer"></footer>
</section> </section>
<footer id="info"> <footer id="info">
<p>Double-click to edit a todo</p> <p>Double-click to edit a todo</p>
<!-- Remove the below line ↓ -->
<!-- Change this out with your name and url ↓ -->
<p>Created by <a href="https://github.com/DimitarChristoff/">Dimitar Christoff</a></p> <p>Created by <a href="https://github.com/DimitarChristoff/">Dimitar Christoff</a></p>
<p>Powered by <a href="https://github.com/DimitarChristoff/Epitome">Epitome for MooTools</a><br/> <a href="http://travis-ci.org/DimitarChristoff/Epitome"></a><img src="https://secure.travis-ci.org/DimitarChristoff/Epitome.png?branch=master" /></a</p> <p>Powered by <a href="https://github.com/DimitarChristoff/Epitome">Epitome for MooTools</a></p>
<p>Part of <a href="http://todomvc.com">TodoMVC</a></p> <p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
</footer> </footer>
<script type="text/template" id="item-template"> <script type="text/template" id="item-template">
<div class="view"> <div class="view">
<input class="toggle" type="checkbox" <%=completedCheckbox%> /> <input class="toggle" type="checkbox" <%=completedCheckbox%>>
<label><%=title%></label> <label><%=title%></label>
<button class="destroy"></button> <button class="destroy"></button>
</div> </div>
<input class="edit" type="text" value="<%=title%>" /> <input class="edit" value="<%=title%>">
</script> </script>
<script type="text/template" id="stats-template"> <script type="text/template" id="stats-template">
<span id="todo-count"><strong><%=remaining%></strong> item<% if (obj.remaining != 1) { %>s<% } %> left</span> <span id="todo-count"><strong><%=remaining%></strong> item<% if (obj.remaining !== 1) { %>s<% } %> left</span>
<ul id="filters"> <ul id="filters">
<li> <li>
<a class="selected" href="#!/">All</a> <a class="selected" href="#!/">All</a>
...@@ -61,22 +53,14 @@ ...@@ -61,22 +53,14 @@
<button id="clear-completed">Clear completed (<%=completed%>)</button> <button id="clear-completed">Clear completed (<%=completed%>)</button>
<% } %> <% } %>
</script> </script>
<script src="../../../assets/base.js"></script>
<!-- Scripts here. Don't remove this ↓ --> <!-- mootools -->
<script src="../assets/base.js"></script> <script src="js/lib/mootools-yui-compressed.js"></script>
<!-- epitome pre-compiled -->
<!-- mootools --> <script src="js/lib/Epitome-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/mootools/1.4.5/mootools-yui-compressed.js"></script> <!-- todo app -->
<script src="js/models/todo-model.js"></script>
<!-- epitome pre-compiled --> <script src="js/collections/todo-collection.js"></script>
<script src="../../../Epitome-min.js"></script>
<!-- fallback outside the main repo submodule-->
<script>window.Epitome || document.write('<script src="js/Epitome-min.js">\x3C/script>')</script>
<!-- todo app -->
<script src="js/models/todo-model.js"></script>
<script src="js/collections/todo-collection.js"></script>
<script src="js/views/todo-list.js"></script> <script src="js/views/todo-list.js"></script>
<script src="js/views/todo-main.js"></script> <script src="js/views/todo-main.js"></script>
<script src="js/app.js"></script> <script src="js/app.js"></script>
......
(function(window) { /*global Epitome */
(function( window ) {
'use strict'; 'use strict';
var App = window.App; var App = window.App;
// Your starting point. Enjoy the ride! var todos = new App.TodoCollection( null, {
var todos = new App.TodoCollection(null, { // a consistent collection if is needed if you want to use storage for a collection
// a consistent collection if is needed if you want to use storage for a collection.
id: 'todos' id: 'todos'
}); });
// populate from storage if available // populate from storage if available
todos.setUp(todos.retrieve()); todos.setUp( todos.retrieve() );
// instantiate the todo list view // instantiate the todo list view
App.todoView = new App.TodoView({ App.todoView = new App.TodoView({
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
this.navigate('#!/'); this.navigate('#!/');
}, },
onApplyFilter: function(filter) { onApplyFilter: function( filter ) {
// the filter is being used by the todo collection and view. // the filter is being used by the todo collection and view.
// when false, the whole collection is being passed. // when false, the whole collection is being passed.
todos.filterType = filter || false; todos.filterType = filter || false;
...@@ -62,12 +62,9 @@ ...@@ -62,12 +62,9 @@
// fix up the links quickie. // fix up the links quickie.
var self = this; var self = this;
document.getElements('#filters li a').each(function(link) { document.getElements('#filters li a').each(function( link ) {
link.set('class', link.get('href') == self.req ? 'selected' : ''); link.set( 'class', link.get('href') === self.req ? 'selected' : '' );
}); });
} }
}); });
}( window ));
\ No newline at end of file
})(window);
\ No newline at end of file
;(function(window) { /*global Epitome, App, Class */
(function(window) {
'use strict'; 'use strict';
window.App = window.App || {}; window.App = window.App || {};
// a collection that holds the todos // a collection that holds the todos
App.TodoCollection = new Class({ App.TodoCollection = new Class({
// normal collection or Collection.Sync // normal collection or Collection.Sync
Extends: Epitome.Collection, Extends: Epitome.Collection,
...@@ -15,12 +15,9 @@ ...@@ -15,12 +15,9 @@
// base model class prototype // base model class prototype
model: App.Todo, model: App.Todo,
todoFilter: function(model) { todoFilter: function( model ) {
// references the filterType which the controller sets // references the filterType which the controller sets
return this.filterType === false ? true : model.get('completed') == this.filterType; return this.filterType === false ? true : model.get('completed') === this.filterType;
} }
}); });
}( window ));
\ No newline at end of file
}(window));
;(function(window) { /*global Epitome, App, Class */
(function(window) {
'use strict'; 'use strict';
window.App = window.App || {}; window.App = window.App || {};
// base structure for the todos themselves // base structure for the todos themselves
App.Todo = new Class({ App.Todo = new Class({
...@@ -27,6 +27,4 @@ ...@@ -27,6 +27,4 @@
model: App.Todo model: App.Todo
}); });
}( window ));
\ No newline at end of file
}(window));
This diff is collapsed.
;(function(window) { /*global Epitome, App, Class, Elements, Element */
(function( window ) {
'use strict'; 'use strict';
window.App = window.App || {}; window.App = window.App || {};
...@@ -33,95 +34,98 @@ ...@@ -33,95 +34,98 @@
}, },
// when collection changes, save the data to storage and re-render // when collection changes, save the data to storage and re-render
"onChange:collection": function(model) { 'onChange:collection': function( model ) {
this.collection.store(); this.collection.store();
this.render(); this.render();
}, },
// when models get removed, re-render // when models get removed, re-render
"onRemove:collection": function(model) { 'onRemove:collection': function( model ) {
this.collection.store(); this.collection.store();
this.render(); this.render();
}, },
// when sort is applied, re-render // when sort is applied, re-render
"onSort:collection": function() { 'onSort:collection': function() {
this.collection.store(); this.collection.store();
this.render(); this.render();
}, },
// when a new model is added, re-render // when a new model is added, re-render
"onAdd:collection": function(model) { 'onAdd:collection': function( model ) {
this.collection.store(); this.collection.store();
this.render(); this.render();
}, },
// handler for the edit event // handler for the edit event
onEditing: function(e, el) { onEditing: function( e, el ) {
e && e.stop && e.stop(); if ( e && e.stop ) {
el.addClass(this.options.editingClass); e.stop();
el.getElement(this.options.input).focus(); }
el.addClass( this.options.editingClass );
el.getElement( this.options.input ).focus();
}, },
// fired when editing ends // fired when editing ends
onUpdate: function(e, el) { onUpdate: function( e, el ) {
var p = el.getParent('li').removeClass(this.options.editingClass), var p = el.getParent('li').removeClass( this.options.editingClass );
value = el.get('value').trim(); var val = el.get('value').trim();
if (!value.length) { if ( !val.length ) {
// the render method stores the model into the element, get it and remove // the render method stores the model into the element, get it and remove
this.collection.removeModel(p.retrieve('model')); this.collection.removeModel( p.retrieve('model') );
return; return;
} }
p.retrieve('model').set('title', value);
p.retrieve('model').set( 'title', val );
}, },
// handler for clicks on the checkboxes // handler for clicks on the checkboxes
onStatusChange: function(e, el) { onStatusChange: function( e, el ) {
var p = el.getParent('li'), var p = el.getParent('li');
done = !!el.get('checked') ? 'completed' : 'active'; var done = !!el.get('checked') ? 'completed' : 'active';
p.retrieve('model').set('completed', done); p.retrieve('model').set( 'completed', done );
}, },
// when the X is pressed, drop the model // when the X is pressed, drop the model
onRemoveItem: function(e, el) { onRemoveItem: function( e, el ) {
e && e.stop && e.stop(); if ( e && e.stop ) {
e.stop();
}
// the render method stores the model into the element, get it and remove // the render method stores the model into the element, get it and remove
this.collection.removeModel(el.getParent('li').retrieve('model')); this.collection.removeModel( el.getParent('li').retrieve('model') );
} }
}, },
render: function() { render: function() {
// main render method, will also fire onRender // main render method, will also fire onRender
var todos = new Elements(), var todos = new Elements();
self = this; var self = this;
// empty the container. // empty the container.
this.empty(); this.empty();
// the route controller works with the todoFilter to help determine what we render. // the route controller works with the todoFilter to help determine what we render.
this.collection.filter(this.collection.todoFilter.bind(this.collection)).each(function(model) { this.collection.filter( this.collection.todoFilter.bind( this.collection ) ).each(function( model ) {
var obj = model.toJSON(), var obj = model.toJSON();
li = new Element(self.tagName).toggleClass('completed', obj.completed == 'completed').store('model', model); var li = new Element( self.tagName ).toggleClass( 'completed', obj.completed === 'completed' ).store( 'model', model );
// help the template to avoid slower logic in the template layer // help the template to avoid slower logic in the template layer
obj.completedCheckbox = obj.completed == 'completed' ? 'checked="checked"' : ''; obj.completedCheckbox = obj.completed === 'completed' ? 'checked' : '';
// compile template and store resulting element in our Elements collection // compile template and store resulting element in our Elements collection
todos.push(li.set('html', self.template(obj))); todos.push( li.set( 'html', self.template( obj ) ) );
}); });
// inject the elements collection into the container element // inject the elements collection into the container element
this.element.adopt(todos); this.element.adopt( todos );
// propagate the render event. // propagate the render event.
this.parent(); this.parent();
return this; return this;
} }
}); });
}( window ));
}(window)); \ No newline at end of file
\ No newline at end of file
;(function(window) { /*global Epitome, App, Class */
(function( window ) {
'use strict'; 'use strict';
window.App = window.App || {}; window.App = window.App || {};
...@@ -27,32 +28,29 @@ ...@@ -27,32 +28,29 @@
toggleAll: 'toggle-all', toggleAll: 'toggle-all',
onToggleAll: function(e, el) { onToggleAll: function( e, el ) {
// all todos will change their models to the new completed value // all todos will change their models to the new completed value
var state = el.get('checked') ? 'completed' : 'active'; var state = el.get('checked') ? 'completed' : 'active';
this.collection.each(function(model) { this.collection.each(function( model ) {
model.set('completed', state); model.set( 'completed', state );
}); });
}, },
onHandleKeypress: function(e, el) { onHandleKeypress: function( e, el ) {
// on enter, submit. // on enter, submit.
if (e.key == 'enter') if ( e.key === 'enter' ) {
this.addTodo(); this.addTodo();
}
// om esc, reset
if (e.key == 'esc')
this.newTodo.set('value', '').blur();
}, },
onClearCompleted: function() { onClearCompleted: function() {
// because removing a model re-indexes so we don't get a sparse array, cannot apply that in a normal loop. // because removing a model re-indexes so we don't get a sparse array, cannot apply that in a normal loop.
var toRemove = this.collection.filter(function(model) { var toRemove = this.collection.filter(function( model ) {
return model.get('completed') == 'completed'; return model.get('completed') === 'completed';
}); });
// removeModel actually supports a single model or an array of models as arguments. // removeModel actually supports a single model or an array of models as arguments.
this.collection.removeModel(toRemove); this.collection.removeModel( toRemove );
this.render(); this.render();
}, },
...@@ -70,17 +68,16 @@ ...@@ -70,17 +68,16 @@
// when adding, re-render. // when adding, re-render.
this.render(); this.render();
} }
}, },
initialize: function(options) { initialize: function( options ) {
// call default view constructor. // call default view constructor.
this.parent(options); this.parent( options );
// store some pointers to static elements // store some pointers to static elements
this.newTodo = document.id(this.options.newTodo); this.newTodo = document.id( this.options.newTodo );
this.footer = document.id(this.options.footer); this.footer = document.id( this.options.footer );
this.toggleAll = document.id(this.options.toggleAll); this.toggleAll = document.id( this.options.toggleAll );
// draw it. // draw it.
this.render(); this.render();
...@@ -90,7 +87,7 @@ ...@@ -90,7 +87,7 @@
// adding a new model when data exists // adding a new model when data exists
var val = this.newTodo.get('value').trim(); var val = this.newTodo.get('value').trim();
if (val.length) { if ( val.length ) {
this.collection.addModel({ this.collection.addModel({
title: val, title: val,
completed: 'active' completed: 'active'
...@@ -98,32 +95,33 @@ ...@@ -98,32 +95,33 @@
} }
// clear the input // clear the input
this.newTodo.set('value', ''); this.newTodo.set( 'value', '' );
}, },
render: function() { render: function() {
// main method to output everything. well. the footer anyway. // main method to output everything. well. the footer anyway.
// work out what we have remaining and what is complete // work out what we have remaining and what is complete
var remaining = 0, var remaining = 0;
completed = this.collection.filter(function(el) {
var status = el.get('completed') == 'completed'; var completed = this.collection.filter(function( el ) {
if (!status) var status = el.get('completed') === 'completed';
remaining++;
return status; if ( !status ) {
}).length; remaining++;
}
return status;
}).length;
// output footer // output footer
this.footer.set('html', this.template({ this.footer.set( 'html', this.template({
completed: completed, completed: completed,
remaining: remaining remaining: remaining
})); }));
// auto-correct the toggle-all checkbox with the new stats. // auto-correct the toggle-all checkbox with the new stats.
this.toggleAll.set('checked', this.collection.length ? !remaining : false); this.toggleAll.set( 'checked', this.collection.length ? !remaining : false );
} }
}); });
}( window ));
}(window)); \ No newline at end of file
\ No newline at end of file
# Template • [TodoMVC](http://todomvc.com) # Epitome TodoMVC app
[Epitome](http://dimitarchristoff.github.com/Epitome) is a new extensible and modular open-source MVP* framework, built out of MooTools Classes and Events.
\ No newline at end of file
## Getting Started
Read the [App Specification](https://github.com/addyosmani/todomvc/wiki/App-Specification) before touching the template.
## Need help?
Feel free to [contact us](https://github.com/sindresorhus) if you have any questions or need help with the template.
## Credit
Created by [Sindre Sorhus](http://sindresorhus.com)
\ 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