Commit 10dee133 authored by Romuald Quantin's avatar Romuald Quantin

soma.js version 2 in progress

todo scope in models updated

somajs update and comments

somajs update

soma.js and require.js added

whitespace update

main view hide update

jshint errors update

jshint errors update

cleanup requirejs dependencies

save on blur and remote persistent editing

todomvc-common update on soma.js

cleanup bower components in soma.js
parent 3af9f7bb
......@@ -3,7 +3,8 @@
"version": "0.0.0",
"dependencies": {
"todomvc-common": "~0.1.6",
"jquery": "~2.0.0",
"handlebars.js": "~1.0.0-rc.3"
"director": "~1.2.0",
"soma.js": "~2.0.0",
"soma-template": "~0.1.8"
}
}
{
"name": "todomvc-common",
"version": "0.1.7",
"gitHead": "42348a8146fe0be847b93cd98664813fbae62be9",
"_id": "todomvc-common@0.1.7",
"readme": "ERROR: No README.md file found!",
"description": "ERROR: No README.md file found!",
"repository": {
"type": "git",
"url": "git://github.com/tastejs/todomvc-common.git"
}
}
\ No newline at end of file
.data-cloak {
display: none;
}
\ No newline at end of file
<!doctype html>
<html lang="en" data-framework="somajs">
<head>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>soma.js • TodoMVC</title>
<link rel="stylesheet" href="bower_components/todomvc-common/base.css">
</head>
<body>
<link rel="stylesheet" href="components/todomvc-common/base.css">
<link rel="stylesheet" href="css/app.css">
</head>
<body>
<section id="todoapp">
<!-- HEADER VIEW, template: /views/header.js (todo.HeaderView) -->
<header id="header">
<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 data-keypress="add()" data-blur="clear()">
</header>
<section id="main">
<input id="toggle-all" type="checkbox">
<!-- MAIN VIEW, template: /views/main.js (todo.MainView) -->
<section id="main" data-show="{{isVisible}}">
<input id="toggle-all" type="checkbox" data-click="toggleAll()" data-checked="{{allCompleted}}">
<label for="toggle-all">Mark all as complete</label>
<ul id="todo-list"></ul>
<ul id="todo-list" class="data-cloak">
<li data-repeat="todo in items" class="{{completedClass(todo.completed)}} {{todo.editing}}">
<div class="view">
<input class="toggle" type="checkbox" data-checked="{{todo.completed}}" data-click="toggle(todo)">
<label data-dblclick="edit(todo)">{{todo.title}}</label>
<button class="destroy" data-click="remove(todo)"></button>
</div>
<input class="edit" value="{{todo.title}}" data-keypress="update(todo)" data-blur="update(todo)">
</li>
</ul>
</section>
<footer id="footer"></footer>
<!-- FOOTER VIEW, template: /views/footer.js (todo.FooterView) -->
<footer id="footer" class="data-cloak" data-show="{{footerVisible}}">
<span id="todo-count"><strong>{{active}}</strong> {{itemLabel}} left</span>
<ul id="filters">
<li>
<a class="{{highlightFilter('')}}" href="#/">All</a>
</li>
<li>
<a class="{{highlightFilter('active')}}" href="#/active">Active</a>
</li>
<li>
<a class="{{highlightFilter('completed')}}" href="#/completed">Completed</a>
</li>
</ul>
<button id="clear-completed" data-show="{{clearCompletedVisible()}}" data-click="clearCompleted()">Clear completed ({{completed}})</button>
</footer>
</section>
<footer id="info">
<p>Double-click to edit a todo</p>
<p>Created by <a href="http://soundstep.com">Romuald Quantin</a></p>
<p>With <a href="http://somajs.github.com/somajs">soma.js</a></p>
<p>Created by <a href="http://soundstep.com">Romuald Quantin</a> (<a href="http://somajs.github.io/somajs/">soma.js</a>)</p>
<p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
</footer>
<script id="todo-list-template" type="text/x-handlebars-template">
{{#this}}
<li {{#if completed}}class="completed"{{/if}} data-id="{{id}}">
<div class="view">
<input class="toggle" type="checkbox" {{#if completed}}checked{{/if}}>
<label>{{title}}</label>
<button class="destroy"></button>
</div>
<input class="edit" value="{{title}}">
</li>
{{/this}}
</script>
<script id="footer-template" type="text/x-handlebars-template">
<span id="todo-count"><strong>{{active}}</strong> {{itemLabel}} left</span>
<button id="clear-completed">Clear completed ({{completed}})</button>
</script>
<script src="bower_components/todomvc-common/base.js"></script>
<script src="bower_components/handlebars.js/handlebars.js"></script>
<script src="bower_components/jquery/jquery.js"></script>
<script src="js/lib/soma-native_v1.0.2_min.js"></script>
<script src="js/todos/models/models.js"></script>
<script src="js/todos/views/views.js"></script>
<script src="js/todos/controllers/controllers.js"></script>
<!-- LIBRARIES -->
<script src="components/todomvc-common/base.js"></script>
<script src="components/director/build/director.js"></script>
<script src="components/soma.js/build/soma.js"></script>
<script src="components/soma-template/build/soma-template.js"></script>
<!-- TODO APP -->
<script src="js/models/todos.js"></script>
<script src="js/models/router.js"></script>
<script src="js/views/header.js"></script>
<script src="js/views/main.js"></script>
<script src="js/views/footer.js"></script>
<script src="js/app.js"></script>
</body>
</body>
</html>
var todo = window.todo || {};
/*global soma:false */
(function (todo, soma) {
(function( window ) {
'use strict';
todo.TodoApp = new soma.Application.extend({
init: function() {
this.addModel( todo.TodoModel.NAME, new todo.TodoModel() );
this.addCommand( todo.TodoEvent.RENDER, todo.TodoCommand );
this.addCommand( todo.TodoEvent.CREATE, todo.TodoCommand );
this.addCommand( todo.TodoEvent.DELETE, todo.TodoCommand );
this.addCommand( todo.TodoEvent.TOGGLE, todo.TodoCommand );
this.addCommand( todo.TodoEvent.UPDATE, todo.TodoCommand );
this.addCommand( todo.TodoEvent.TOGGLE_ALL, todo.TodoCommand );
this.addCommand( todo.TodoEvent.CLEAR_COMPLETED, todo.TodoCommand );
this.addView( todo.TodoListView.NAME, new todo.TodoListView( $('#todo-list')[0] ) );
this.addView( todo.FooterView.NAME, new todo.FooterView( $('#footer')[0] ) );
this.addView( todo.TodoInputView.NAME, new todo.TodoInputView( $('#new-todo')[0] ) );
todo.TodoApp = soma.Application.extend({
init: function () {
// mapping rules so the model and router can be injected
this.injector.mapClass('model', todo.Model, true);
this.injector.mapClass('router', todo.Router, true);
// create templates for DOM Elements (optional soma-template plugin)
this.createTemplate(todo.HeaderView, document.getElementById('header'));
this.createTemplate(todo.MainView, document.getElementById('main'));
this.createTemplate(todo.FooterView, document.getElementById('footer'));
},
start: function() {
this.dispatchEvent( new todo.TodoEvent( todo.TodoEvent.RENDER ) );
start: function () {
// dispatch a custom event to render the templates
this.dispatcher.dispatch('render');
}
});
var app = new todo.TodoApp();
// create the application
new todo.TodoApp();
})( window );
})(window.todo = window.todo || {}, soma);
/*global Router:false */
(function (todo, Router) {
'use strict';
todo.Router = function (dispatcher) {
// create the router (director.js)
var router = new Router().init();
// dispatch a custom event to render the template on a route change
router.on(/.*/, function () {
dispatcher.dispatch('render');
});
return {
getRoute: function () {
return router.getRoute()[0];
}
};
};
})(window.todo = window.todo || {}, Router);
(function (todo) {
'use strict';
todo.Model = function () {
var storeKey = 'todos-somajs';
return {
get: function () {
// get the data from the local storage
return JSON.parse(localStorage.getItem(storeKey) || '[]');
},
set: function (items) {
// set the data to the local storage
localStorage.setItem(storeKey, JSON.stringify(items));
},
getActive: function () {
// returns items that are not completed
return this.get().filter(function (item) {
return !item.completed;
}).length;
}
};
};
})(window.todo = window.todo || {});
var todo = window.todo || {};
(function( window ) {
'use strict';
todo.TodoCommand = soma.Command.extend({
execute: function( event ) {
var model = this.getModel( todo.TodoModel.NAME );
switch( event.type ) {
case todo.TodoEvent.RENDER:
this.getView( todo.TodoListView.NAME ).render( model.data, model.getActiveLength() );
this.getView( todo.FooterView.NAME ).render( model.dataFooter );
break;
case todo.TodoEvent.CREATE:
model.addItem( event.params.todoTitle );
break;
case todo.TodoEvent.DELETE:
model.removeItem( event.params.todoId );
break;
case todo.TodoEvent.TOGGLE:
model.toggleItem( event.params.todoId );
break;
case todo.TodoEvent.TOGGLE_ALL:
model.toggleAll( event.params.toggleAll );
break;
case todo.TodoEvent.UPDATE:
model.updateItem( event.params.todoId, event.params.todoTitle );
break;
case todo.TodoEvent.CLEAR_COMPLETED:
model.clearCompleted();
break;
}
}
});
todo.TodoEvent = soma.Event.extend({
constructor: function( type, todoTitle, todoId, toggleAll ) {
return soma.Event.call( this, type, {
todoTitle: todoTitle,
todoId: todoId,
toggleAll: toggleAll
});
}
});
todo.TodoEvent.RENDER = 'TodoEvent.RENDER';
todo.TodoEvent.CREATE = 'TodoEvent.CREATE';
todo.TodoEvent.DELETE = 'TodoEvent.DELETE';
todo.TodoEvent.UPDATE = 'TodoEvent.UPDATE';
todo.TodoEvent.TOGGLE = 'TodoEvent.TOGGLE';
todo.TodoEvent.TOGGLE_ALL = 'TodoEvent.TOGGLE_ALL';
todo.TodoEvent.CLEAR_COMPLETED = 'TodoEvent.CLEAR_COMPLETED';
})( window );
var todo = window.todo || {};
(function( window ) {
'use strict';
todo.TodoModel = new soma.Model.extend({
dataFooter: null,
init: function() {
this.storeKey = 'todos-somajs';
this.data = JSON.parse( this.getStore() ) || [];
this.updateDataFooter();
},
updateDataFooter: function() {
var active = this.getActiveLength();
this.dataFooter = {
active: active,
itemLabel: active === 1 ? 'item' : 'items',
completed: this.data.length - active,
length: this.data.length
};
},
addItem: function( title ) {
this.data.push({
id: this.uuid(),
title: title,
completed: false
});
this.update();
},
removeItem: function( id ) {
this.data.splice( this.getIndexById( id ), 1 );
this.update();
},
toggleItem: function( id ) {
var item = this.data[ this.getIndexById( id ) ];
item.completed = !item.completed;
this.update();
},
updateItem: function( id, title ) {
this.data[ this.getIndexById( id ) ].title = title;
this.update();
},
toggleAll: function( toggleValue ) {
var i;
for ( i = 0; i < this.data.length; i++ ) {
this.data[i].completed = toggleValue;
}
this.update();
},
clearCompleted: function() {
var i = this.data.length;
while ( i-- ) {
if ( this.data[ i ].completed ) {
this.data.splice( i, 1 );
}
}
this.update();
},
getIndexById: function( id ) {
var i;
for ( i = 0; i < this.data.length; i++ ) {
if ( this.data[ i ].id === id ) {
return i;
}
}
return -1;
},
getActiveLength: function() {
var i,
count = 0;
for ( i = 0; i < this.data.length; i++ ) {
if ( !this.data[ i ].completed ) {
count++;
}
}
return count;
},
update: function() {
this.updateDataFooter();
this.setStore( this.data );
this.dispatchEvent( new todo.TodoEvent( todo.TodoEvent.RENDER ) );
},
getStore: function() {
return localStorage.getItem( this.storeKey );
},
setStore: function() {
localStorage.setItem( this.storeKey, JSON.stringify( this.data ) );
},
// https://gist.github.com/1308368
uuid: function(a,b){for(b=a='';a++<36;b+=a*51&52?(a^15?8^Math.random()*(a^20?16:4):4).toString(16):'-');return b;}
});
todo.TodoModel.NAME = 'TodoModel';
})( window );
var todo = window.todo || {};
(function( window ) {
'use strict';
var ENTER_KEY = 13;
todo.TodoListView = soma.View.extend({
template: null,
init: function() {
this.template = Handlebars.compile( $( '#' + this.domElement.id + '-template' ).html() );
$( this.domElement ).on( 'click', '.destroy', this.destroy.bind( this ) );
$( this.domElement ).on( 'click', '.toggle', this.toggle.bind( this ) );
$( this.domElement ).on( 'dblclick', 'label', this.edit );
$( this.domElement ).on( 'blur', '.edit', this.update.bind( this ) );
$( this.domElement ).on( 'keypress', '.edit', this.blurInput );
$('#toggle-all').click( this.toggleAll );
},
render: function( data, activeCount ) {
$(this.domElement).html( this.template( data ) );
$('#toggle-all').prop( 'checked', !activeCount );
$('#main').toggle( !!data.length );
},
destroy: function( event ) {
var id = $(event.target).closest('li').attr('data-id');
this.dispatchEvent( new todo.TodoEvent( todo.TodoEvent.DELETE, null, id ) );
},
toggle: function( event ) {
var id = $(event.target).closest('li').attr('data-id');
this.dispatchEvent( new todo.TodoEvent( todo.TodoEvent.TOGGLE, null, id ) );
},
toggleAll: function() {
this.dispatchEvent( new todo.TodoEvent( todo.TodoEvent.TOGGLE_ALL, null, null, $( this ).prop('checked') ) );
},
edit: function( event ) {
$( this ).closest('li').addClass('editing').find('.edit').focus();
},
update: function( event ) {
var li = $( event.target ).closest('li').removeClass('editing'),
id = li.data('id'),
val = li.find('.edit').val().trim();
if ( val ) {
this.dispatchEvent( new todo.TodoEvent( todo.TodoEvent.UPDATE, val, id ) );
}
else {
this.dispatchEvent( new todo.TodoEvent( todo.TodoEvent.DELETE, null, id ) );
}
},
blurInput: function( event ) {
if ( event.which === ENTER_KEY ) {
event.target.blur();
}
}
});
todo.TodoListView.NAME = 'TodoListView';
todo.TodoInputView = soma.View.extend({
init: function() {
$( this.domElement ).keypress( this.keyPressHandler.bind( this ) );
$( this.domElement ).blur( this.blur );
},
keyPressHandler: function( event ) {
if ( event.which === ENTER_KEY ) {
this.createItem();
}
},
createItem: function() {
var value = this.domElement.value.trim();
if ( value ) {
this.dispatchEvent( new todo.TodoEvent( todo.TodoEvent.CREATE, value ) );
}
this.domElement.value = '';
},
blur: function( event ) {
if ( !this.value.trim() ) {
this.value = '';
}
}
});
todo.TodoInputView.NAME = 'TodoInputView';
todo.FooterView = soma.View.extend({
template: null,
init: function() {
this.template = Handlebars.compile( $( '#' + this.domElement.id + '-template' ).html() );
$( this.domElement ).on( 'click', '#clear-completed', this.clearCompleted.bind( this ) );
},
render: function( data ) {
$( this.domElement ).html( this.template( data ) );
$( this.domElement ).toggle( !!data.length );
$('#clear-completed').toggle( !!data.completed );
},
clearCompleted: function( event ) {
this.dispatchEvent( new todo.TodoEvent( todo.TodoEvent.CLEAR_COMPLETED ) );
}
});
todo.FooterView.NAME = 'FooterView';
})( window );
(function (todo) {
'use strict';
todo.FooterView = function (scope, template, model, router, dispatcher) {
// get data from the injected model
var items = model.get();
// template function: returns a css class for the current filter (all/active/completed)
scope.highlightFilter = function (filter) {
var route = router.getRoute();
return route === filter ? 'selected' : '';
};
// template function: returns the number of completed items
scope.clearCompleted = function () {
items = items.filter(function (item) {
return !item.completed;
});
update();
};
// save the changes to the model and dispatch a custom event to render the templates
function update() {
model.set(items);
dispatcher.dispatch('render');
}
// listen to a custom event to render the footer view
dispatcher.addEventListener('render', function () {
items = model.get();
scope.active = model.getActive();
scope.completed = items.length - scope.active;
scope.itemLabel = scope.active === 1 ? 'item' : 'items';
scope.footerVisible = items.length > 0 ? true : false;
scope.clearCompletedVisible = scope.completed > 0 ? true : false;
template.render();
});
};
})(window.todo = window.todo || {});
(function (todo) {
'use strict';
var ENTER_KEY = 13;
todo.HeaderView = function (scope, template, model, dispatcher) {
// get data from the injected model
var items = model.get();
// template function: add a new item on an enter key press
scope.add = function (event) {
var value = event.currentTarget.value.trim();
if (event.which === ENTER_KEY && value !== '') {
items.push({
title: value,
completed: false
});
event.currentTarget.value = '';
update();
}
};
// template function: remove text from the input (used on blur event)
scope.clear = function (event) {
event.currentTarget.value = '';
};
// save the changes to the model and dispatch a custom event to render the templates
function update() {
model.set(items);
dispatcher.dispatch('render');
}
// listen to a custom event to render the header view
dispatcher.addEventListener('render', function () {
items = model.get();
template.render();
});
};
})(window.todo = window.todo || {});
This diff is collapsed.
......@@ -21,7 +21,6 @@ Get help from other soma.js users:
* [Mailing list on Google Groups](https://groups.google.com/forum/#!forum/somajs)
* [soma.js on Twitter](http://twitter.com/soundstep)
_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._
......
{
"name": "todomvc-somajs",
"version": "0.0.0",
"dependencies": {
"todomvc-common": "~0.1.6",
"director": "~1.2.0",
"requirejs": "~2.1.5",
"soma.js": "~2.0.0",
"soma-template": "~0.1.8"
}
}
{
"name": "todomvc-common",
"version": "0.1.7",
"gitHead": "42348a8146fe0be847b93cd98664813fbae62be9",
"_id": "todomvc-common@0.1.7",
"readme": "ERROR: No README.md file found!",
"description": "ERROR: No README.md file found!",
"repository": {
"type": "git",
"url": "git://github.com/tastejs/todomvc-common.git"
}
}
\ No newline at end of file
.data-cloak {
display: none;
}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
/*global define:false */
(function () {
'use strict';
define(['director'], function (Router) {
var RouterModel = function (dispatcher) {
// create the router (director.js)
var router = new Router().init();
// dispatch a custom event to render the template on a route change
router.on(/.*/, function () {
dispatcher.dispatch('render');
});
return {
getRoute: function () {
return router.getRoute()[0];
}
};
};
return RouterModel;
});
})();
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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