Commit 3b8c596a authored by Stephen Sawchuk's avatar Stephen Sawchuk

Merge pull request #591 from stephenplusplus/epitome-bug

Epitome Code Style + Spec Issue
parents cc132b80 29f9c0a7
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
"name": "todomvc-epitome", "name": "todomvc-epitome",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"epitome": "0.3.1", "todomvc-common": "~0.1.6",
"todomvc-common": "~0.1.6" "Epitome": "~0.3.1"
} }
} }
...@@ -22,19 +22,21 @@ ...@@ -22,19 +22,21 @@
<footer id="info"> <footer id="info">
<p>Double-click to edit a todo</p> <p>Double-click to edit a todo</p>
<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="http://dimitarchristoff.github.com/Epitome">Epitome for MooTools</a></p> <p>Powered by <a href="http://epitome-mvc.github.io/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" 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>
...@@ -54,7 +56,7 @@ ...@@ -54,7 +56,7 @@
<!-- mootools --> <!-- mootools -->
<script src="js/lib/mootools-yui-compressed.js"></script> <script src="js/lib/mootools-yui-compressed.js"></script>
<!-- epitome pre-compiled --> <!-- epitome pre-compiled -->
<script src="bower_components/epitome/Epitome-min.js"></script> <script src="bower_components/Epitome/Epitome-min.js"></script>
<!-- todo app --> <!-- todo app -->
<script src="js/models/todo-model.js"></script> <script src="js/models/todo-model.js"></script>
<script src="js/collections/todo-collection.js"></script> <script src="js/collections/todo-collection.js"></script>
......
/*global Epitome */
/*jshint mootools:true */ /*jshint mootools:true */
(function( window ) { (function (window) {
'use strict'; 'use strict';
var App = window.App; var App = window.App;
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({
...@@ -20,10 +19,10 @@ ...@@ -20,10 +19,10 @@
collection: todos, collection: todos,
// encapsulating element to bind to // encapsulating element to bind to
element: document.id( 'todo-list' ), element: document.id('todo-list'),
// template to use // template to use
template: document.id( 'item-template' ).get( 'text' ) template: document.id('item-template').get('text')
}); });
...@@ -37,11 +36,11 @@ ...@@ -37,11 +36,11 @@
element: document.id('todoapp'), element: document.id('todoapp'),
// stats template from DOM // stats template from DOM
template: document.id( 'stats-template' ).get( 'text' ), template: document.id('stats-template').get('text'),
onReady: function() { onReady: function () {
// need to work with controller that sets the current state of filtering // need to work with controller that sets the current state of filtering
var proxy = function() { var proxy = function () {
App.router.showActiveFilter(); App.router.showActiveFilter();
}; };
...@@ -57,12 +56,12 @@ ...@@ -57,12 +56,12 @@
'#!/:filter': 'applyFilter' '#!/:filter': 'applyFilter'
}, },
onInit: function() { onInit: function () {
// we want to always have a state // we want to always have a state
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;
...@@ -73,4 +72,4 @@ ...@@ -73,4 +72,4 @@
this.showActiveFilter(); this.showActiveFilter();
} }
}); });
}( window )); })(window);
/*global Epitome, App */ /*global Epitome, App */
/*jshint mootools:true */ /*jshint mootools:true */
(function(window) { (function (window) {
'use strict'; 'use strict';
window.App = window.App || {}; window.App = window.App || {};
...@@ -21,9 +21,9 @@ ...@@ -21,9 +21,9 @@
completed: 1 completed: 1
}, },
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 : this.map[this.filterType] === +model.get( 'completed' ); return this.filterType === false ? true : this.map[this.filterType] === +model.get('completed');
} }
}); });
}( window )); })(window);
/*global Epitome, App */ /*global Epitome, App */
/*jshint mootools:true */ /*jshint mootools:true */
(function(window) { (function (window) {
'use strict'; 'use strict';
window.App = window.App || {}; window.App = window.App || {};
...@@ -9,14 +9,14 @@ ...@@ -9,14 +9,14 @@
Extends: Epitome.Router, Extends: Epitome.Router,
showActiveFilter: function() { showActiveFilter: function () {
// fix up the links for current filter // fix up the links for current filter
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 )); })(window);
/*global Epitome, App */ /*global Epitome, App */
/*jshint mootools:true */ /*jshint mootools:true */
(function(window) { (function (window) {
'use strict'; 'use strict';
window.App = window.App || {}; window.App = window.App || {};
...@@ -28,4 +28,4 @@ ...@@ -28,4 +28,4 @@
model: App.Todo model: App.Todo
}); });
}( window )); })(window);
/*global Epitome, App */ /*global Epitome, App */
/*jshint mootools:true */ /*jshint mootools:true */
(function( window ) { (function (window) {
'use strict'; 'use strict';
window.App = window.App || {}; window.App = window.App || {};
...@@ -29,89 +29,91 @@ ...@@ -29,89 +29,91 @@
}, },
// define actual event handlers // define actual event handlers
onReady: function() { onReady: function () {
// initial view // initial view
this.render(); this.render();
}, },
// 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 () {
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 () {
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 () {
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) {
if ( e && e.stop ) { if (e && e.stop) {
e.stop(); e.stop();
} }
var container = el.getParent('li'); var container = el.getParent('li');
container.addClass( this.options.editingClass ); var input = container.getElement(this.options.input);
container.getElement( this.options.input ).focus();
container.addClass(this.options.editingClass);
input.focus();
input.value = input.value;
}, },
// when enter pressed while editing // when enter pressed while editing
onHandleKeypress: function( e, el ) { onHandleKeypress: function (e, el) {
// on enter, blur() and let it bubble to onUpdate. // on enter, blur() and let it bubble to onUpdate.
if ( e.key === 'enter' ) { if (e.key === 'enter') {
el.blur(); el.blur();
} }
}, },
// 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);
var val = el.get( 'value' ).trim(); var val = el.get('value').trim();
if ( !val.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', val ); 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');
var done = !!el.get( 'checked' ); var done = !!el.get('checked');
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) {
if ( e && e.stop ) { if (e && e.stop) {
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();
var self = this; var self = this;
...@@ -120,23 +122,23 @@ ...@@ -120,23 +122,23 @@
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();
var li = new Element( self.tagName ).toggleClass( 'completed', obj.completed ).store( 'model', model ); var li = new Element(self.tagName).toggleClass('completed', obj.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 ? 'checked' : ''; obj.completedCheckbox = obj.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);
/*global Epitome, App */ /*global Epitome, App */
/*jshint mootools:true */ /*jshint mootools:true */
(function( window ) { (function (window) {
'use strict'; 'use strict';
window.App = window.App || {}; window.App = window.App || {};
...@@ -25,70 +25,77 @@ ...@@ -25,70 +25,77 @@
footer: 'footer', footer: 'footer',
main: 'main',
filters: '#filters li a', filters: '#filters li a',
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' ); var state = !!el.get('checked');
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) {
// on enter, submit. // on enter, submit.
if ( e.key === 'enter' ) { if (e.key === 'enter') {
this.addTodo(); this.addTodo();
} }
}, },
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' ); return model.get('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();
}, },
onAddTodo: function() { onAddTodo: function () {
// go to method // go to method
this.addTodo(); this.addTodo();
}, },
'onChange:collection': function() { 'onChange:collection': function () {
// also, re-render on change of collection // also, re-render on change of collection
this.render(); this.render();
}, },
'onAdd:collection': function() { 'onRemove:collection': function () {
this.render();
},
'onAdd:collection': function () {
// 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);
this.main = document.id(this.options.main);
// draw it. // draw it.
this.render(); this.render();
}, },
addTodo: function() { addTodo: function () {
// 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: false completed: false
...@@ -96,33 +103,37 @@ ...@@ -96,33 +103,37 @@
} }
// 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;
var completed = this.collection.filter(function( model ) { var completed = this.collection.filter(function (model) {
var status = model.get( 'completed' ); var status = model.get('completed');
if ( status === false ) { if (status === false) {
remaining++; remaining++;
} }
return status; return status;
}).length; }).length;
var visibleClass = remaining || completed ? '' : 'hidden';
// output footer // output footer
this.footer.set( 'html', this.template({ this.footer.set('html', this.template({
completed: completed, completed: completed,
remaining: remaining remaining: remaining
})); })).set('class', visibleClass);
this.main.set('class', visibleClass);
// 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);
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