Commit 254fa67a authored by DimitarChristoff's avatar DimitarChristoff

refactor for code style, spaces creep in, fix issue with active filter, change...

refactor for code style, spaces creep in, fix issue with active filter, change completed to boolean, editing enter fires blur, see pull/235#issuecomment-7264416
parent 9447769a
......@@ -25,19 +25,19 @@
<footer id="info">
<p>Double-click to edit a todo</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></p>
<p>Powered by <a href="https://dimitarchristoff.github.com/Epitome">Epitome for MooTools</a></p>
<p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
</footer>
<script type="text/template" id="item-template">
<div class="view">
<input class="toggle" type="checkbox" <%=completedCheckbox%>>
<input class="toggle" type="checkbox" <%=completedCheckbox%>>
<label><%=title%></label>
<button class="destroy"></button>
</div>
<input class="edit" value="<%=title%>">
<input class="edit" value="<%=title%>">
</script>
<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">
<li>
<a class="selected" href="#!/">All</a>
......@@ -53,16 +53,17 @@
<button id="clear-completed">Clear completed (<%=completed%>)</button>
<% } %>
</script>
<script src="../../../assets/base.js"></script>
<!-- mootools -->
<script src="js/lib/mootools-yui-compressed.js"></script>
<!-- epitome pre-compiled -->
<script src="js/lib/Epitome-min.js"></script>
<!-- todo app -->
<script src="js/models/todo-model.js"></script>
<script src="js/collections/todo-collection.js"></script>
<script src="../../../assets/base.js"></script>
<!-- mootools -->
<script src="js/lib/mootools-yui-compressed.js"></script>
<!-- epitome pre-compiled -->
<script src="js/lib/Epitome-min.js"></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-main.js"></script>
<script src="js/controllers/todo-router.js"></script>
<script src="js/app.js"></script>
</body>
</html>
\ No newline at end of file
/*global Epitome */
/*jshint mootools:true */
(function( window ) {
'use strict';
var App = window.App;
var todos = new App.TodoCollection( null, {
// a consistent collection if is needed if you want to use storage for a collection
var todos = new App.TodoCollection( null, {
// a consistent collection if is needed if you want to use storage for a collection
id: 'todos'
});
// populate from storage if available
todos.setUp( todos.retrieve() );
todos.setUp( todos.retrieve() );
// instantiate the todo list view
App.todoView = new App.TodoView({
......@@ -19,10 +20,10 @@
collection: todos,
// encapsulating element to bind to
element: document.id('todo-list'),
element: document.id( 'todo-list' ),
// template to use
template: document.id('item-template').get('text')
template: document.id( 'item-template' ).get( 'text' )
});
......@@ -36,11 +37,23 @@
element: document.id('todoapp'),
// stats template from DOM
template: document.id('stats-template').get('text')
template: document.id( 'stats-template' ).get( 'text' ),
onReady: function() {
// need to work with controller that sets the current state of filtering
var proxy = function() {
App.router.showActiveFilter();
};
this.addEvents({
'add:collection': proxy,
'change:collection': proxy
});
}
});
// the pseudo controller via Epitome.Router
App.router = new Epitome.Router({
App.router = new App.Router({
routes: {
'': 'init',
'#!/': 'applyFilter',
......@@ -49,10 +62,10 @@
onInit: function() {
// 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.
// when false, the whole collection is being passed.
todos.filterType = filter || false;
......@@ -60,11 +73,7 @@
// render as per current filter
App.todoView.render();
// fix up the links quickie.
var self = this;
document.getElements('#filters li a').each(function( link ) {
link.set( 'class', link.get('href') === self.req ? 'selected' : '' );
});
this.showActiveFilter();
}
});
}( window ));
\ No newline at end of file
/*global Epitome, App, Class */
/*global Epitome, App */
/*jshint mootools:true */
(function(window) {
'use strict';
......@@ -15,9 +16,14 @@
// base model class prototype
model: App.Todo,
todoFilter: function( model ) {
map: {
active: 0,
completed: 1
},
todoFilter: function( model ) {
// references the filterType which the controller sets
return this.filterType === false ? true : model.get('completed') === this.filterType;
return this.filterType === false ? true : this.map[this.filterType] === +model.get( 'completed' );
}
});
}( window ));
\ No newline at end of file
/*global Epitome, App */
/*jshint mootools:true */
(function(window) {
'use strict';
window.App = window.App || {};
App.Router = new Class({
Extends: Epitome.Router,
showActiveFilter: function() {
// fix up the links for current filter
var self = this;
document.getElements( '#filters li a' ).each(function( link ) {
link.set( 'class', link.get( 'href' ) === self.req ? 'selected' : '' );
});
}
});
}( window ));
\ No newline at end of file
/*global Epitome, App, Class */
/*global Epitome, App */
/*jshint mootools:true */
(function(window) {
'use strict';
......@@ -11,7 +12,7 @@
options: {
defaults: {
completed: 'active',
completed: false,
title: ''
}
}
......
/*global Epitome, App, Class, Elements, Element */
/*global Epitome, App */
/*jshint mootools:true */
(function( window ) {
'use strict';
......@@ -34,94 +35,103 @@
},
// when collection changes, save the data to storage and re-render
'onChange:collection': function( model ) {
'onChange:collection': function( model ) {
this.collection.store();
this.render();
},
// when models get removed, re-render
'onRemove:collection': function( model ) {
'onRemove:collection': function( model ) {
this.collection.store();
this.render();
},
// when sort is applied, re-render
'onSort:collection': function() {
'onSort:collection': function() {
this.collection.store();
this.render();
},
// when a new model is added, re-render
'onAdd:collection': function( model ) {
'onAdd:collection': function( model ) {
this.collection.store();
this.render();
},
// handler for the edit event
onEditing: function( e, el ) {
if ( e && e.stop ) {
e.stop();
}
onEditing: function( e, el ) {
if ( e && e.stop ) {
e.stop();
}
el.addClass( this.options.editingClass );
el.getElement( this.options.input ).focus();
},
el.addClass( this.options.editingClass );
el.getElement( this.options.input ).focus();
// when enter pressed while editing
onHandleKeypress: function( e, el ) {
// on enter, blur() and let it bubble to onUpdate.
if ( e.key === 'enter' ) {
el.blur();
}
},
// fired when editing ends
onUpdate: function( e, el ) {
var p = el.getParent('li').removeClass( this.options.editingClass );
var val = el.get('value').trim();
onUpdate: function( e, el ) {
var p = el.getParent( 'li ').removeClass( this.options.editingClass );
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
this.collection.removeModel( p.retrieve('model') );
this.collection.removeModel( p.retrieve( 'model' ) );
return;
}
p.retrieve('model').set( 'title', val );
p.retrieve( 'model' ).set( 'title', val );
},
// handler for clicks on the checkboxes
onStatusChange: function( e, el ) {
var p = el.getParent('li');
var done = !!el.get('checked') ? 'completed' : 'active';
onStatusChange: function( e, el ) {
var p = el.getParent( 'li' );
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
onRemoveItem: function( e, el ) {
if ( e && e.stop ) {
e.stop();
}
onRemoveItem: function( e, el ) {
if ( e && e.stop ) {
e.stop();
}
// 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() {
// main render method, will also fire onRender
var todos = new Elements();
var self = this;
var todos = new Elements();
var self = this;
// empty the container.
this.empty();
// 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 ) {
var obj = model.toJSON();
var li = new Element( self.tagName ).toggleClass( 'completed', obj.completed === 'completed' ).store( 'model', model );
this.collection.filter( this.collection.todoFilter.bind( this.collection ) ).each(function( model ) {
var obj = model.toJSON();
var li = new Element( self.tagName ).toggleClass( 'completed', obj.completed ).store( 'model', model );
// help the template to avoid slower logic in the template layer
obj.completedCheckbox = obj.completed === 'completed' ? 'checked' : '';
obj.completedCheckbox = obj.completed ? 'checked' : '';
// 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
this.element.adopt( todos );
this.element.adopt( todos );
// propagate the render event.
this.parent();
......
/*global Epitome, App, Class */
/*global Epitome, App */
/*jshint mootools:true */
(function( window ) {
'use strict';
......@@ -28,29 +29,29 @@
toggleAll: 'toggle-all',
onToggleAll: function( e, el ) {
onToggleAll: function( e, el ) {
// all todos will change their models to the new completed value
var state = el.get('checked') ? 'completed' : 'active';
this.collection.each(function( model ) {
model.set( 'completed', state );
var state = !!el.get( 'checked' );
this.collection.each( function( model ) {
model.set( 'completed', state );
});
},
onHandleKeypress: function( e, el ) {
onHandleKeypress: function( e, el ) {
// on enter, submit.
if ( e.key === 'enter' ) {
if ( e.key === 'enter' ) {
this.addTodo();
}
}
},
onClearCompleted: function() {
// 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 ) {
return model.get('completed') === 'completed';
var toRemove = this.collection.filter(function( model ) {
return model.get( 'completed' );
});
// removeModel actually supports a single model or an array of models as arguments.
this.collection.removeModel( toRemove );
this.collection.removeModel( toRemove );
this.render();
},
......@@ -70,14 +71,14 @@
}
},
initialize: function( options ) {
initialize: function( options ) {
// call default view constructor.
this.parent( options );
this.parent( options );
// store some pointers to static elements
this.newTodo = document.id( this.options.newTodo );
this.footer = document.id( this.options.footer );
this.toggleAll = document.id( this.options.toggleAll );
this.newTodo = document.id( this.options.newTodo );
this.footer = document.id( this.options.footer );
this.toggleAll = document.id( this.options.toggleAll );
// draw it.
this.render();
......@@ -85,43 +86,43 @@
addTodo: function() {
// 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({
title: val,
completed: 'active'
completed: false
});
}
// clear the input
this.newTodo.set( 'value', '' );
this.newTodo.set( 'value', '' );
},
render: function() {
// main method to output everything. well. the footer anyway.
// work out what we have remaining and what is complete
var remaining = 0;
var remaining = 0;
var completed = this.collection.filter(function( el ) {
var status = el.get('completed') === 'completed';
var completed = this.collection.filter(function( model ) {
var status = model.get( 'completed' );
if ( !status ) {
remaining++;
}
if ( status === false ) {
remaining++;
}
return status;
}).length;
return status;
}).length;
// output footer
this.footer.set( 'html', this.template({
this.footer.set( 'html', this.template({
completed: completed,
remaining: remaining
}));
// 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 ));
\ 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