Commit dee327ac authored by Addy Osmani's avatar Addy Osmani

Merge pull request #198 from stas/emberjs-routing

Emberjs routing
parents 2c9508c3 f1084f90
This diff is collapsed.
#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
#HTMLReporter a { text-decoration: none; }
#HTMLReporter a:hover { text-decoration: underline; }
#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
#HTMLReporter #jasmine_content { position: fixed; right: 100%; }
#HTMLReporter .version { color: #aaaaaa; }
#HTMLReporter .banner { margin-top: 14px; }
#HTMLReporter .duration { color: #aaaaaa; float: right; }
#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
#HTMLReporter .symbolSummary li.passed { font-size: 14px; }
#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
#HTMLReporter .symbolSummary li.failed { line-height: 9px; }
#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
#HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
#HTMLReporter .symbolSummary li.pending { line-height: 11px; }
#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
#HTMLReporter .runningAlert { background-color: #666666; }
#HTMLReporter .skippedAlert { background-color: #aaaaaa; }
#HTMLReporter .skippedAlert:first-child { background-color: #333333; }
#HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
#HTMLReporter .passingAlert { background-color: #a6b779; }
#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
#HTMLReporter .failingAlert { background-color: #cf867e; }
#HTMLReporter .failingAlert:first-child { background-color: #b03911; }
#HTMLReporter .results { margin-top: 14px; }
#HTMLReporter #details { display: none; }
#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
#HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
#HTMLReporter.showDetails .summary { display: none; }
#HTMLReporter.showDetails #details { display: block; }
#HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
#HTMLReporter .summary { margin-top: 14px; }
#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
#HTMLReporter .summary .specSummary.failed a { color: #b03911; }
#HTMLReporter .description + .suite { margin-top: 0; }
#HTMLReporter .suite { margin-top: 14px; }
#HTMLReporter .suite a { color: #333333; }
#HTMLReporter #details .specDetail { margin-bottom: 28px; }
#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
#HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
#HTMLReporter .resultMessage span.result { display: block; }
#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
#TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
#TrivialReporter a:visited, #TrivialReporter a { color: #303; }
#TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
#TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
#TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
#TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
#TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
#TrivialReporter .runner.running { background-color: yellow; }
#TrivialReporter .options { text-align: right; font-size: .8em; }
#TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
#TrivialReporter .suite .suite { margin: 5px; }
#TrivialReporter .suite.passed { background-color: #dfd; }
#TrivialReporter .suite.failed { background-color: #fdd; }
#TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
#TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
#TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
#TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
#TrivialReporter .spec.skipped { background-color: #bbb; }
#TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
#TrivialReporter .passed { background-color: #cfc; display: none; }
#TrivialReporter .failed { background-color: #fbb; }
#TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
#TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
#TrivialReporter .resultMessage .mismatch { color: black; }
#TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
#TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
#TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
#TrivialReporter #jasmine_content { position: fixed; right: 100%; }
#TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }
This diff is collapsed.
......@@ -5,19 +5,14 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>ember.js + require.js • TodoMVC</title>
<link rel="stylesheet" href="../../assets/base.css">
<link rel="stylesheet" href="../../assets/jasmine/jasmine.css">
<link rel="stylesheet" href="css/app.css">
<!--[if IE]>
<script src="../../assets/ie.js"></script>
<![endif]-->
</head>
<body>
<section id="todoapp">
<header id="header">
<h1>todos</h1>
</header>
<section id="main"></section>
<footer id="footer"></footer>
</section>
<section id="todoapp"></section>
<footer id="info">
<p>Double-click to edit a todo</p>
<p>Template by <a href="http://sindresorhus.com">Sindre Sorhus</a></p>
......@@ -31,4 +26,4 @@
<script src="../../assets/base.js"></script>
<script data-main="js/app.js" src="js/lib/require/require.js"></script>
</body>
</html>
\ No newline at end of file
</html>
......@@ -3,64 +3,37 @@ require.config({
baseUrl: 'js/',
paths: {
jquery: '../../../assets/jquery.min',
ember: 'lib/ember-0.9.8.1.min',
// ember: 'http://cloud.github.com/downloads/emberjs/ember.js/ember-latest.min',
ember: 'lib/ember-latest',
text: 'lib/require/text',
mocha: 'lib/mocha',
chai: 'lib/chai'
jasmine: '../../../assets/jasmine/jasmine',
jasmine_html: '../../../assets/jasmine/jasmine-html'
}
});
// Load our app
define( 'app', [
'jquery',
'app/router',
'app/models/store',
'app/controllers/todos',
'ember',
], function( $, Store, TodosController ) {
'app/controllers/entries',
'app/views/application',
'jquery',
'ember'
], function( Router, Store, EntriesController, ApplicationView ) {
var App = Ember.Application.create({
VERSION: '0.2-omfg',
// Sets up mocha to run some integration tests
specsRunner: function( chai ) {
// Create placeholder for mocha output
// TODO: Make this shit look better and inside body
$( document.body ).before( '<div id="mocha"></div>' );
// Setup mocha and expose chai matchers
window.expect = chai.expect;
mocha.setup('bdd');
// Load testsuite
require([
'app/specs/models/store',
'app/specs/views/basic_acceptance',
'app/specs/controllers/todos'
], function() {
mocha.run().globals( [ '$', 'Ember', 'Todos' ] );
}
);
},
// Constructor
init: function() {
this._super();
// Initiate main controller
this.set(
'todosController',
TodosController.create({
store: new Store( 'todos-emberjs' )
})
);
// Run specs if asked
if ( location.hash.match( /specs/ ) ) {
require( [ 'chai', 'mocha' ], this.specsRunner );
}
}
VERSION: '0.2',
rootElement: '#todoapp',
// Load routes
Router: Router,
// Extend to inherit outlet support
ApplicationController: Ember.Controller.extend(),
ApplicationView: ApplicationView,
entriesController: EntriesController.create(
{ store: new Store( 'todos-emberjs' ) }
)
});
App.initialize();
// Expose the application globally
return window.Todos = App;
}
......
define('app/controllers/entries', ['ember'],
define('app/controllers/entries', [ 'ember' ],
/**
* Entries controller
*
......@@ -23,7 +23,6 @@ define('app/controllers/entries', ['ember'],
},
removeObject: function( item ) {
item = item.get( 'todo' ) || item;
this.get( 'store' ).remove( item );
return this._super( item );
},
......@@ -46,6 +45,10 @@ define('app/controllers/entries', ['ember'],
return this.filterProperty( 'completed', true ).get( 'length' );
}.property( '@each.completed' ),
noneLeft: function() {
return this.get( 'total' ) === 0;
}.property( 'total' ),
allAreDone: function( key, value ) {
if ( value !== undefined ) {
this.setEach( 'completed', value );
......@@ -66,4 +69,4 @@ define('app/controllers/entries', ['ember'],
}
});
}
);
\ No newline at end of file
);
define('app/controllers/todos', [
'app/controllers/entries',
'text!app/views/clear_button.html',
'text!app/views/items.html'
],
define('app/controllers/todos', [ 'ember' ],
/**
* Todos controller
*
* Main controller inherits the `Entries` class
* which is an `ArrayProxy` linked with the `Store` model
*
* @param Class Entries, the Entries class
* @param String button_html, the html view for the clearCompletedButton
* @param String items_html, the html view for the `Todos` items
* @returns Class
*/
function( Entries, button_html, items_html ) {
return Entries.extend({
// New todo input
inputView: Ember.TextField.create({
placeholder: 'What needs to be done?',
elementId: 'new-todo',
storageBinding: 'Todos.todosController',
// Bind this to newly inserted line
insertNewline: function() {
var value = this.get( 'value' );
if ( value ) {
this.get( 'storage' ).createNew( value );
this.set( 'value', '' );
}
}
}),
// Stats report
statsView: Ember.View.create({
elementId: 'todo-count',
tagName: 'span',
contentBinding: 'Todos.todosController',
remainingBinding: 'Todos.todosController.remaining',
template: Ember.Handlebars.compile(
'<strong>{{remaining}}</strong> {{remainingString}} left'
),
remainingString: function() {
var remaining = this.get( 'remaining' );
return ( remaining === 1 ? ' item' : ' items' );
}.property( 'remaining' )
}),
// Handle visibility of some elements as items totals change
visibilityObserver: function() {
$( '#main, #footer' ).toggle( !!this.get( 'total' ) );
}.observes( 'total' ),
function() {
return Ember.Controller.extend({
entries: function() {
var filter = this.getPath( 'content.filterBy' );
// Clear completed tasks button
clearCompletedButton: Ember.Button.create({
template: Ember.Handlebars.compile( button_html ),
target: 'Todos.todosController',
action: 'clearCompleted',
completedCountBinding: 'Todos.todosController.completed',
elementId: 'clear-completed',
classNameBindings: 'buttonClass',
// Observer to update class if completed value changes
buttonClass: function () {
if ( !this.get( 'completedCount' ) )
return 'hidden';
}.property( 'completedCount' )
}),
// Checkbox to mark all todos done.
allDoneCheckbox: Ember.Checkbox.create({
elementId: 'toggle-all',
checkedBinding: 'Todos.todosController.allAreDone'
}),
// Compile and render the todos view
todosView: Ember.View.create({
template: Ember.Handlebars.compile( items_html )
}),
if ( Ember.empty( filter ) ) {
return this.get( 'content' );
}
// Todo list item view
todoView: Ember.View.extend({
classNames: [ 'view' ],
doubleClick: function() {
this.get( 'content' ).set( 'editing', true );
if ( !Ember.compare( filter, 'completed' ) ) {
return this.get( 'content' ).filterProperty( 'completed', true );
}
}),
// Todo list item editing view
todoEditor: Ember.TextField.extend({
storageBinding: 'Todos.todosController',
classNames: [ 'edit' ],
whenDone: function() {
this.get( 'todo' ).set( 'editing', false );
if ( !this.get( 'todo' ).get( 'title' ).trim() ) {
this.get( 'storage' ).removeObject( this.get( 'todo' ) );
}
},
focusOut: function() {
this.whenDone();
},
didInsertElement: function() {
this.$().focus();
},
insertNewline: function() {
this.whenDone();
if ( !Ember.compare( filter, 'active' ) ) {
return this.get( 'content' ).filterProperty( 'completed', false );
}
}),
// Activates the views and other initializations
init: function() {
this._super();
this.get( 'inputView' ).appendTo( 'header' );
this.get( 'allDoneCheckbox' ).appendTo( '#main' );
this.get( 'todosView' ).appendTo( '#main' );
this.get( 'statsView' ).appendTo( '#footer' );
this.get( 'clearCompletedButton' ).appendTo( '#footer' );
}
}.property( 'content.remaining' )
});
}
);
\ No newline at end of file
);
define('app/router', [ 'ember' ],
/**
* Todos Router
*
* Defined routes represent filters according to specs
*
* @returns Class
*/
function() {
return Ember.Router.extend({
root: Ember.Route.extend({
showAll: Ember.Route.transitionTo( 'index' ),
showActive: Ember.Route.transitionTo( 'active' ),
showCompleted: Ember.Route.transitionTo( 'completed' ),
index: Ember.Route.extend({
route: '/',
connectOutlets: function( router ) {
var controller = router.get( 'applicationController' );
var context = controller.namespace.entriesController;
context.set( 'filterBy', '' );
// This require was left here exclusively for design purposes
// Loads decoupled controller/view based on current route
require([ 'app/controllers/todos', 'app/views/items' ],
function( TodosController, ItemsView ) {
controller.connectOutlet({
viewClass: ItemsView,
controller: TodosController.create(),
context: context
});
}
);
}
}),
active: Ember.Route.extend({
route: '/active',
connectOutlets: function( router ) {
var controller = router.get( 'applicationController' );
var context = controller.namespace.entriesController;
context.set( 'filterBy', 'active' );
// This require was left here exclusively for design purposes
// Loads decoupled controller/view based on current route
require([ 'app/controllers/todos', 'app/views/items' ],
function( TodosController, ItemsView ) {
controller.connectOutlet({
viewClass: ItemsView,
controller: TodosController.create(),
context: context
});
}
);
}
}),
completed: Ember.Route.extend({
route: '/completed',
connectOutlets: function( router ) {
var controller = router.get( 'applicationController' );
var context = controller.namespace.entriesController;
context.set( 'filterBy', 'completed' );
// This require was left here exclusively for design purposes
// Loads decoupled controller/view based on current route
require([ 'app/controllers/todos', 'app/views/items' ],
function( TodosController, ItemsView ) {
controller.connectOutlet({
viewClass: ItemsView,
controller: TodosController.create(),
context: context
});
}
);
}
}),
specs: Ember.Route.extend({
route: '/specs',
connectOutlets: function() {
require( [ 'app/specs/helper' ] );
}
})
})
});
}
);
define( 'app/specs/helper', [ 'jasmine', 'jasmine_html' ],
/**
* Specs Runner
*/
function() {
// Load testsuite
require([
'app/specs/todoMVC',
], function() {
var jasmineEnv = jasmine.getEnv();
var htmlReporter = new jasmine.HtmlReporter();
jasmineEnv.addReporter( htmlReporter );
jasmineEnv.execute();
});
}
);
/**
* TodoMVC Project Specs
*
* Use `runs` and `waits` to make sure results are run synchroneously
*/
describe( 'TodoMVC features.', function(){
var enterEvent = $.Event('keyup', { keyCode: 13 });
var todoTitle = 'Foo Bar Todo';
describe( 'Todo creation:', function() {
beforeEach( function(){
// Make sure we are always on the main screen
window.location.hash = '#/';
});
it( 'should allow creating a new todo' , function() {
runs( function(){
$( '#new-todo' ).val( todoTitle ).trigger( enterEvent );
});
waits( 100 );
runs( function() {
!!$( '#todo-list li' ).text().match( todoTitle );
});
});
it( 'should not allow adding an empty todo' , function() {
var ourTodo,
beforeCount = $( '#todo-list li' ).length;
runs( function(){
$( '#new-todo' ).val( ' ' ).trigger( enterEvent );
});
waits( 100 );
runs( function(){
expect( $( '#todo-list li' ).length ).toEqual( beforeCount );
});
});
});
describe( 'Todo completion:', function() {
it( 'should allow marking a todo complete' , function() {
var ourTodo,
beforeCount = $( '#todo-list li.completed' ).length,
postTitle = ' to be completed';
runs( function(){
$( '#new-todo' ).val( todoTitle + postTitle ).trigger( enterEvent );
});
waits( 100 );
runs( function() {
ourTodo = $( '#todo-list li:last-child' );
expect( ourTodo.text() ).toMatch( postTitle );
ourTodo.find( '.toggle' ).click();
expect( $( '#todo-list li.completed' ).length ).toEqual( beforeCount + 1 );
});
});
it( 'should allow clearing completed todos' , function() {
var ourTodo,
beforeCount = $( '#todo-list li.completed' ).length,
postTitle = ' to be completed';
runs( function(){
$( '#new-todo' ).val( todoTitle + postTitle ).trigger( enterEvent );
});
waits( 100 );
runs( function() {
ourTodo = $( '#todo-list li:last-child' );
expect( ourTodo.text() ).toMatch( postTitle );
ourTodo.find( '.toggle' ).click();
$( '#clear-completed' ).click();
expect( $( '#todo-list li.completed' ).length ).toEqual( 0 );
});
});
});
describe( 'Todo deletion:', function() {
it( 'should allow deleting a todo' , function() {
var ourTodo,
beforeCount = $( '#todo-list li' ).length,
postTitle = ' to be deleted';
runs( function(){
$( '#new-todo' ).val( todoTitle + postTitle ).trigger( enterEvent );
});
waits( 100 );
runs( function() {
ourTodo = $( '#todo-list li:last-child' );
expect( ourTodo.text() ).toMatch( postTitle );
ourTodo.find( '.destroy' ).click();
expect( $( '#todo-list li' ).length ).toEqual( beforeCount );
});
});
});
});
{{#with view}}
<button id="clear-completed" {{action "clearCompleted" target="entries"}} >
Clear completed ({{entries.completed}})
</button>
{{/with}}
<ul id="filters">
<li>
<a {{action showAll href=true}}>All</a>
</li>
<li>
<a {{action showActive href=true}}>Active</a>
</li>
<li>
<a {{action showCompleted href=true}}>Completed</a>
</li>
</ul>
{{#unless view.content.editing}}
{{view Ember.Checkbox checkedBinding="view.content.completed" class="toggle"}}
<label>{{view.content.title}}</label>
<button {{action removeItem}} class="destroy" ></button>
{{else}}
{{view view.ItemEditorView contentBinding="view.content"}}
{{/unless}}
{{#with view}}
{{#if oneLeft }}
<strong>{{entries.remaining}}</strong> item left
{{else}}
<strong>{{entries.remaining}}</strong> items left
{{/if}}
{{/with}}
define('app/views/application', [
'app/views/stats',
'app/views/filters',
'app/views/clear_button',
'ember'
],
/**
* Main application view
*
* @param Class StatsView, stats view class
* @param Class FiltersView, filters view class
* @param Class ClearBtnView, clear button view class
* @returns Class
*/
function( StatsView, FiltersView, ClearBtnView ) {
return Ember.ContainerView.extend({
childViews: [ 'headerView', 'mainView', 'footerView' ],
headerView: Ember.ContainerView.create({
childViews: [ 'titleView', 'createTodoView' ],
elementId: 'header',
tagName: 'header',
titleView: Ember.View.create({
tagName: 'h1',
template: function() {
return 'todos';
}
}),
createTodoView: Ember.TextField.create({
entriesBinding: 'controller.namespace.entriesController',
placeholder: 'What needs to be done?',
elementId: 'new-todo',
insertNewline: function() {
var value = this.get( 'value' );
if ( value ) {
this.get( 'entries' ).createNew( value );
this.set( 'value', '' );
}
}
}),
}),
mainView: Em.ContainerView.create({
elementId: 'main',
tagName: 'section',
visibilityBinding: 'controller.namespace.entriesController.noneLeft',
classNameBindings: [ 'visibility:hidden' ],
childViews: [ 'outletView', 'markAllChkbox' ],
outletView: Ember.View.create({
template: Ember.Handlebars.compile( '{{outlet}}' ),
}),
markAllChkbox: Ember.Checkbox.create({
entriesBinding: 'controller.namespace.entriesController',
elementId: 'toggle-all',
checkedBinding: 'entries.allAreDone'
})
}),
footerView: Ember.ContainerView.create({
elementId: 'footer',
tagName: 'footer',
visibilityBinding: 'controller.namespace.entriesController.noneLeft',
classNameBindings: [ 'visibility:hidden' ],
childViews: [
StatsView.create(),
FiltersView.create(),
ClearBtnView.create()
]
})
})
}
);
Clear completed ({{completedCount}})
\ No newline at end of file
define('app/views/clear_button', [
'text!app/templates/clear_button.html',
'ember'
],
/**
* View to clear completed tasks
*
* @param String button_html, the html for view
* @returns Class
*/
function( button_html ) {
return Ember.View.extend({
entriesBinding: 'controller.namespace.entriesController',
template: Ember.Handlebars.compile( button_html ),
classNameBindings: 'buttonClass',
buttonClass: function () {
if ( !this.getPath( 'entries.completed' ) )
return 'hidden';
}.property( 'entries.completed' )
})
}
);
define('app/views/filters', [
'text!app/templates/filters.html',
'ember'
],
/**
* View to render filter links
*
* @param String filters_html, filter links html view
* @returns Class
*/
function( filters_html ) {
return Ember.View.extend({
template: Ember.Handlebars.compile( filters_html )
})
}
);
{{#collection id="todo-list" contentBinding="Todos.todosController" tagName="ul" itemClassBinding="content.completed content.editing" }}
{{#unless content.editing}}
{{#view Todos.todosController.todoView contentBinding="content" }}
{{view Ember.Checkbox valueBinding="content.completed" class="toggle"}}
{{#view Ember.View tagName="label" todoBinding="content"}}
{{todo.title}}
{{/view}}
{{view Ember.Button target="Todos.todosController" action="removeObject" class="destroy" todoBinding="content"}}
{{/view}}
{{else}}
{{view Todos.todosController.todoEditor todoBinding="content" valueBinding="content.title"}}
{{/unless}}
{{/collection}}
\ No newline at end of file
define('app/views/items', [
'text!app/templates/items.html',
'ember'
],
/**
* View to render todos items
*
* @param String items_html, the html view for the `Todos` items
* @returns Class
*/
function( items_html ) {
return Ember.CollectionView.extend({
contentBinding: 'controller.entries',
tagName: 'ul',
elementId: 'todo-list',
itemViewClass: Ember.View.extend({
template: Ember.Handlebars.compile( items_html ),
classNames: [ 'view' ],
classNameBindings: ['content.completed', 'content.editing'],
doubleClick: function() {
this.get( 'content' ).set( 'editing', true );
},
removeItem: function() {
this.getPath( 'controller.content' ).removeObject( this.get( 'content' ) );
},
ItemEditorView: Ember.TextField.extend({
valueBinding: 'content.title',
classNames: [ 'edit' ],
change: function() {
if ( Ember.empty( this.getPath( 'content.title' ) ) ) {
this.getPath( 'controller.content' ).removeObject( this.get( 'content' ) );
}
},
whenDone: function() {
this.get( 'content' ).set( 'editing', false );
},
focusOut: function() {
this.whenDone();
},
didInsertElement: function() {
this.$().focus();
},
insertNewline: function() {
this.whenDone();
}
})
})
})
}
);
define('app/views/stats', [
'text!app/templates/stats.html',
'ember'
],
/**
* View to render todos stats
*
* @param String stats_html, stats indicator view
* @returns Class
*/
function( stats_html ) {
return Ember.View.extend({
entriesBinding: 'controller.namespace.entriesController',
elementId: 'todo-count',
tagName: 'span',
template: Ember.Handlebars.compile( stats_html ),
oneLeft: function() {
return this.getPath( 'entries.remaining' ) === 1;
}.property( 'entries.remaining' )
})
}
);
This diff is collapsed.
This diff is collapsed.
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