Commit 955a40e0 authored by Addy Osmani's avatar Addy Osmani

adding current versions of many of the applications in our backlog still being...

adding current versions of many of the applications in our backlog still being worked on for 1.0 or consideration for 1.0 as a part of labs
parent 597fefcc
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Agility.js • TodoMVC</title>
<link rel="stylesheet" href="../../assets/base.css">
</head>
<body>
<section id="todoapp">
<header id="header">
<h1>todos</h1>
<input id="new-todo" type="text" data-bind="newtitle" placeholder="What needs to be done?" autofocus>
</header>
<section id="main" data-bind="class = mainStyle">
<input id="toggle-all" type="checkbox">
<label for="toggle-all">Mark all as complete</label>
<ul id="todo-list">
<li>
<div class="view">
<input class="toggle" type="checkbox" data-bind="complete">
<label data-bind="title"></label>
<button class="destroy"></button>
</div>
<input class="edit" type="text" data-bind="title">
</li>
</ul>
</section>
<footer id="footer" data-bind="class = mainStyle">
<span id="todo-count"><strong data-bind='todoCount'></strong> item<span data-bind='pluralizer'></span> left</span>
<ul id="filters">
<li>
<a class="selected" href="#/">All</a>
</li>
<li>
<a href="#/active">Active</a>
</li>
<li>
<a href="#/completed">Completed</a>
</li>
</ul>
<button id="clear-completed" data-bind="class = clearBtnStyle">Clear completed (<span data-bind="completeCount"></span>)</button>
</footer>
</section>
<footer id="info">
<p>Double-click to edit a todo</p>
<p>Template by <a href="http://sindresorhus.com">Sindre Sorhus</a></p>
<p>Created by <a href="http://github.com/tshm/todomvc/">Tosh Shimayama</a></p>
</footer>
<script src="../../assets/jquery.min.js"></script>
<script src="js/lib/agility.min.js"></script>
<script src="js/localstorage.js"></script>
<script src="js/app.js"></script>
</body>
</html>
(function( $, $$ ) {
'use strict';
var ENTER_KEY = 13;
// Hack of taking out html elements from DOM so that agility's view can use it.
// We need 'outerhtml' also, as agilityjs will append DOM, so removing it.
var drawHtml = function( selector ) {
return $(selector).remove().wrap( '<div>' ).parent().html();
};
// Simple Two layer composition:
// individual 'todoitem' and 'app'lication which holds multiple todoitems.
$(function() {
// todo item
var todoitem = $$({
model: {
title: 'no name',
complete: false
},
view: {
format: drawHtml( '#todo-list li' ),
style: '.hidden { display: none }'
},
controller: {
'change:complete': function() {
this.view.$().toggleClass( 'complete', this.model.get( 'complete' ));
app.updateStatus();
},
'dblclick .view': function() {
this.view.$().addClass( 'editing' );
this.view.$('.edit').select();
},
'click .destroy': function() {
this.destroy();
},
'create': function() {
this.view.$().toggleClass( 'complete', this.model.get( 'complete' ));
},
'change': function() {
this.save();
},
'destroy': function() {
this.erase();
},
'change:title': function() {
this.view.$().removeClass( 'editing' );
var title = this.model.get( 'title' ).trim();
if ( title ) {
this.model.set({
title: title
});
} else {
this.destroy();
}
}
}
}).persist( $$.adapter.localStorage, {
collection: 'todos-agilityjs'
});
// The main application which holds todo items.
var app = $$({
model: {
todoCount: '0',
pluralizer: '',
completeCount: '0',
newtitle: '',
mainStyle: '',
clearBtnStyle: ''
},
view: {
format: drawHtml( '#todoapp' ),
style: '.hidden { display: none }'
},
controller: {
'remove': function() {
this.updateStatus();
},
'append': function() {
this.updateStatus();
},
'keyup #new-todo': function( event ) {
var title;
if ( event.which === ENTER_KEY && (title = $('#new-todo').val().trim()) ) {
var item = $$(todoitem, {
title: title
}).save();
this.append( item, '#todo-list' );
event.target.value = ''; // clear input field
}
},
'click #toggle-all': function() {
var ischecked = this.view.$('#toggle-all').prop('checked');
this.each(function( id, item ) {
item.model.set({
complete: ischecked
});
});
},
'click #clear-completed': function() {
this.each(function( id, item ) {
if ( item.model.get( 'complete' ) ) {
item.destroy();
}
});
}
},
// utility functions
updateStatus: function() {
// update counts
var count = this.size(),
completeCount = 0;
this.each(function( id, item ) {
if ( item.model.get( 'complete' ) ) {
completeCount++;
}
});
this.model.set({
todoCount: count - completeCount + '',
pluralizer: (count > 1 ? 's' : ''),
completeCount: completeCount + '',
mainStyle: (count === 0 ? 'hidden' : ''),
clearBtnStyle: (completeCount === 0 ? 'hidden' : '')
});
// update toggle-all checked status
$('#toggle-all').prop( 'checked', completeCount === count );
},
// filter handler
filters: {
'#/': function( item ) {
return true;
},
'#/active': function( item ) {
return !item.model.get( 'complete' );
},
'#/completed': function( item ) {
return item.model.get( 'complete' );
}
},
applyFilter: function( hash ) {
var isVisible = this.filters[hash];
this.each(function( id, item ) {
item.view.$().toggleClass( 'hidden', !isVisible( item ));
});
}
}).persist();
$$.document.prepend( app );
// load from localStorage
app.gather( todoitem, 'append', '#todo-list' ).updateStatus();
// manual routing (not supported by agilityjs)
$(window).on( 'hashchange', function() {
var hash = location.hash;
app.applyFilter( hash );
$('#filters a').each(function() {
if ( hash === $(this).attr( 'href' ) ) {
$(this).addClass( 'selected' );
} else {
$(this).removeClass( 'selected' );
}
});
});
if ( location.hash ) {
$(window).trigger( 'hashchange' );
}
});
})( window.jQuery, window.agility );
This diff is collapsed.
// custom agilityjs adapter for localstorage
(function( $$, undefined ) {
'use strict';
$$.adapter.localStorage = function( _params ) {
var storageKey = (this._data.persist.baseUrl || '') + this._data.persist.collection,
storageStr = localStorage[storageKey],
items = (storageStr ? JSON.parse( storageStr ) : {});
//
if ( _params.type === 'GET' ) {
if ( _params.id !== undefined ) { // normal get
if ( typeof items[_params.id] === 'object' ) {
_params.success( items[_params.id] );
} else {
_params.error();
}
} else { // gather call
_params.success( items );
}
} else if ( _params.type === 'DELETE' ) {
delete items[_params.id];
localStorage[storageKey] = JSON.stringify( items );
} else if ( _params.type === 'PUT' || _params.type === 'POST' ) {
if ( _params.id === undefined ) {
_params.id = (new Date()).getTime();
_params.data.id = _params.id;
}
items[_params.id] = _params.data;
localStorage[storageKey] = JSON.stringify( items );
} else {
_params.error();
}
_params.complete();
};
})( window.agility );
html,
body {
margin: 0;
padding: 0;
}
body {
font: 14px "Helvetica Neue", Helvetica, Arial, sans-serif;
line-height: 1.4em;
background: #eeeeee;
color: #333333;
width: 520px;
margin: 0 auto;
-webkit-font-smoothing: antialiased;
}
#todoapp {
background: #fff;
padding: 20px;
margin-bottom: 40px;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0;
-ms-box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0;
-o-box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0;
box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0;
-webkit-border-radius: 0 0 5px 5px;
-moz-border-radius: 0 0 5px 5px;
-ms-border-radius: 0 0 5px 5px;
-o-border-radius: 0 0 5px 5px;
border-radius: 0 0 5px 5px;
}
#todoapp h1 {
font-size: 36px;
font-weight: bold;
text-align: center;
padding: 0 0 10px 0;
}
#todoapp input[type="text"] {
width: 466px;
font-size: 24px;
font-family: inherit;
line-height: 1.4em;
border: 0;
outline: none;
padding: 6px;
border: 1px solid #999999;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
-ms-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
-o-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
}
#todoapp input::-webkit-input-placeholder {
font-style: italic;
}
#main {
display: none;
}
#todo-list {
margin: 10px 0;
padding: 0;
list-style: none;
}
#todo-list li {
padding: 18px 20px 18px 0;
position: relative;
font-size: 24px;
border-bottom: 1px solid #cccccc;
}
#todo-list li:last-child {
border-bottom: none;
}
#todo-list li.done label {
color: #777777;
text-decoration: line-through;
}
#todo-list li .destroy {
display: none;
position: absolute;
top: 20px;
right: 10px;
cursor: pointer;
width: 20px;
height: 20px;
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUBAMAAAB/pwA+AAAABGdBTUEAALGPC/xhBQAAACdQTFRFzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMAAAA////zMzMhnu0WAAAAAt0Uk5T5u3pqtV3jFQEKAC0bVelAAAAfUlEQVQI12NYtWpFsc8R865VqxhWrZpyBgg8QcylZ8AgCsjMgTCPrWJYfgYKqhjWwJgaDDVnzpw+c2bPmTPHGWzOnNm95/TuM2cOM/AARXfvBooeZAAp270bRCIz4QoOIGtDMqwJZoUEQzvCYrhzuhhWtUKYEahOX7UK6iEA3A6NUGwCTZIAAAAASUVORK5CYII=') no-repeat center center;
}
#todo-list li:hover .destroy {
display: block;
}
#todo-list li.editing {
border-bottom: none;
margin-top: -1px;
padding: 0;
}
#todo-list li.editing:last-child {
margin-bottom: -1px;
}
#todo-list li.editing .edit {
display: block;
width: 444px;
padding: 13px 15px 14px 20px;
margin: 0;
}
#todo-list li.editing .view {
display: none;
}
#todo-list li .view label {
word-break: break-word;
}
#todo-list li .edit {
display: none;
}
#todoapp footer {
display: none;
margin: 0 -20px -20px -20px;
overflow: hidden;
color: #555555;
background: #f4fce8;
border-top: 1px solid #ededed;
padding: 0 20px;
line-height: 37px;
-webkit-border-radius: 0 0 5px 5px;
-moz-border-radius: 0 0 5px 5px;
-ms-border-radius: 0 0 5px 5px;
-o-border-radius: 0 0 5px 5px;
border-radius: 0 0 5px 5px;
}
#clear-completed {
display: none;
float: right;
line-height: 20px;
text-decoration: none;
background: rgba(0, 0, 0, 0.1);
color: #555555;
font-size: 11px;
margin-top: 8px;
margin-bottom: 8px;
padding: 0 10px 1px;
cursor: pointer;
-webkit-border-radius: 12px;
-moz-border-radius: 12px;
-ms-border-radius: 12px;
-o-border-radius: 12px;
border-radius: 12px;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
-ms-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
-o-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
}
#clear-completed:hover {
background: rgba(0, 0, 0, 0.15);
-webkit-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
-moz-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
-ms-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
-o-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
}
#clear-completed:active {
position: relative;
top: 1px;
}
#todo-count span {
font-weight: bold;
}
#instructions {
margin: 10px auto;
color: #777777;
text-shadow: rgba(255, 255, 255, 0.8) 0 1px 0;
text-align: center;
}
#instructions a {
color: #336699;
}
#credits {
margin: 30px auto;
color: #999;
text-shadow: rgba(255, 255, 255, 0.8) 0 1px 0;
text-align: center;
}
#credits a {
color: #888;
}
\ No newline at end of file
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>jQuery - TodoMVC</title>
<link rel="stylesheet" href="css/app.css">
</head>
<body>
<div id="todoapp">
<header>
<h1>Todos</h1>
<input id="new-todo" type="text" placeholder="What needs to be done?">
</header>
<section id="main">
<input id="toggle-all" type="checkbox">
<label for="toggle-all">Mark all as complete</label>
<ul id="todo-list"></ul>
</section>
<footer>
<a id="clear-completed">Clear completed</a>
<div id="todo-count"></div>
</footer>
</div>
<div id="instructions">
Double-click to edit a todo.
</div>
<div id="credits">
Created by <a href="http://sindresorhus.com">Sindre Sorhus</a>.
</div>
<script type="text/x-handlebars-template" id="todo-template">
{{#this}}
<li {{#if done}}class="done"{{/if}} data-id="{{id}}">
<div class="view">
<input class="toggle" type="checkbox" {{#if done}}checked{{/if}}>
<label>{{title}}</label>
<a class="destroy"></a>
</div>
<input class="edit" type="text" value="{{title}}">
</li>
{{/this}}
</script>
<script src="js/libs/json2.js"></script>
<script src="js/libs/jquery-1.7.1.min.js"></script>
<script src="js/libs/handlebars-1.0.0.beta.6.js"></script>
<script src="js/libs/dijon-0.5.1.min.js"></script>
<script src="js/config.js"></script>
<script src="js/models/TodosModel.js"></script>
<script src="js/services/LocalStorageService.js"></script>
<script src="js/controllers/TodosController.js"></script>
<script src="js/utils/Utils.js"></script>
<script src="js/views/FooterView.js"></script>
<script src="js/views/TodoFormView.js"></script>
<script src="js/views/TodoListView.js"></script>
<script src="js/app.js"></script>
</body>
</html>
\ No newline at end of file
/*
[MIT licensed](http://en.wikipedia.org/wiki/MIT_License)
(c) [Sindre Sorhus](http://sindresorhus.com)
*/
( function( ns ){
ns.App = function(){
var system;
return {
startup : function(){
system = new dijon.System();
system.mapValue( 'system', system );
system.mapOutlet( 'system' );
system.injectInto( new ns.Config() );
system.notify( 'App:startup' );
system.notify( 'App:startupComplete' );
}
}
}
}( dijondemo ) );
dijondemo.app = new dijondemo.App();
dijondemo.app.startup();
\ No newline at end of file
/**
* @author Camille Reynders
* Date: 03/02/12
* Time: 15:23
*/
var dijondemo = {};
( function( ns ){
ns.views = {};
ns.models = {};
ns.controllers = {};
ns.services = {};
ns.utils = {};
ns.Config = function(){
return{
system : undefined, //inject
setup : function(){
this.system.autoMapOutlets = true;
//values
this.system.mapValue( 'enterKey', 13 );
this.system.mapValue( 'uuidUtil', ns.utils.Utils );
this.system.mapValue( 'pluralizeUtil', ns.utils.Utils );
//models
this.system.mapSingleton( 'todosModel', ns.models.TodosModel );
//services
this.system.mapSingleton( 'storageService', ns.services.LocalStorageService );
//controllers
this.system.mapSingleton( 'todosController', ns.controllers.TodosController );
//views
this.system.mapSingleton( 'footerView', ns.views.FooterView );
this.system.mapSingleton( 'formView', ns.views.TodoFormView );
this.system.mapSingleton( 'listView', ns.views.TodoListView );
//handlers
this.system.mapHandler( 'TodoFormView:addTodo', 'todosModel', 'add' );
this.system.mapHandler( 'TodoListView:toggleDoneOfTodo', 'todosModel', 'toggleDone' );
this.system.mapHandler( 'TodoListView:setTitleOfTodo', 'todosModel', 'setTitle' );
this.system.mapHandler( 'TodoListView:removeTodo', 'todosModel', 'remove' );
this.system.mapHandler( 'TodoListView:setDoneForAllTodos', 'todosModel', 'setDoneForAll')
this.system.mapHandler( 'TodoListView:removeAllDoneTodos', 'todosModel', 'removeAllDone' );
this.system.mapHandler( 'StorageService:retrieveCompleted', 'todosModel', 'setList' );
this.system.mapHandler( 'FooterView:retrieveTodoCounts', 'todosController', 'retrieveCounts' );
this.system.mapHandler( 'TodosController:todoCountsRetrieved', 'footerView', 'updateCounts' );
this.system.mapHandler( 'TodosModel:todosListUpdated', 'listView', 'render' );
this.system.mapHandler( 'TodosModel:todosListUpdated', 'footerView', 'render' );
this.system.mapHandler( 'TodosModel:todosListUpdated', 'storageService', 'store' );
this.system.mapHandler( 'App:startup', 'storageService', 'retrieve' );
this.system.mapHandler( 'App:startupComplete', 'formView', 'render' );
this.system.mapHandler( 'App:startupComplete', 'storageService', 'retrieve' );
}
}
}
}( dijondemo ) );
\ No newline at end of file
/**
* @author Camille Reynders
* Date: 03/02/12
* Time: 14:36
*/
( function( ns ){
ns.controllers.TodosController = function(){
return {
system : undefined, //inject
todosModel : undefined, //inject
retrieveCounts : function(){
this.system.notify( 'TodosController:todoCountsRetrieved', this.todosModel.getNumTotal(), this.todosModel.getNumActive() );
}
}
}
}( dijondemo ) );
\ No newline at end of file
var dijon={VERSION:"0.5.0"};dijon.System=function(){this._mappings={};this._outlets={};this._handlers={};this.strictInjections=true;this.autoMapOutlets=false};dijon.System.prototype={_createAndSetupInstance:function(c,b){var a=new b();this.injectInto(a,c);return a},_retrieveFromCacheOrCreate:function(d,c){if(c==undefined){c=false}if(this._mappings.hasOwnProperty(d)){var b=this._mappings[d];var a=null;if(!c&&b.isSingleton){if(b.object==null){b.object=this._createAndSetupInstance(d,b.clazz)}a=b.object}else{if(b.clazz){a=this._createAndSetupInstance(d,b.clazz)}else{}}}else{throw new Error(1020)}return a},mapOutlet:function(c,b,a){if(c==undefined){throw new Error(1010)}if(b==undefined){b="global"}if(a==undefined){a=c}if(!this._outlets.hasOwnProperty(b)){this._outlets[b]={}}this._outlets[b][a]=c;return this},getObject:function(a){if(a==undefined){throw new Error(1010)}return this._retrieveFromCacheOrCreate(a)},mapValue:function(a,b){if(a==undefined){throw new Error(1010)}this._mappings[a]={clazz:null,object:b,isSingleton:true};if(this.autoMapOutlets){this.mapOutlet(a)}return this},hasMapping:function(a){if(a==undefined){throw new Error(1010)}return this._mappings.hasOwnProperty(a)},mapClass:function(b,a){if(b==undefined){throw new Error(1010)}if(b==undefined){throw new Error(1010)}this._mappings[b]={clazz:a,object:null,isSingleton:false};if(this.autoMapOutlets){this.mapOutlet(b)}return this},mapSingleton:function(b,a){if(b==undefined){throw new Error(1010)}if(a==undefined){throw new Error(1010)}this._mappings[b]={clazz:a,object:null,isSingleton:true};if(this.autoMapOutlets){this.mapOutlet(b)}return this},instantiate:function(a){if(a==undefined){throw new Error(1010)}return this._retrieveFromCacheOrCreate(a,true)},injectInto:function(a,d){if(a==undefined){throw new Error(1010)}var g=[];if(this._outlets.hasOwnProperty("global")){g.push(this._outlets.global)}if(d!=undefined&&this._outlets.hasOwnProperty(d)){g.push(this._outlets[d])}for(var c in g){var b=g[c];for(var f in b){var e=b[f];if(!this.strictInjections||f in a){a[f]=this.getObject(e)}}}if("setup" in a){a.setup.call(a)}return this},unmap:function(a){if(a==undefined){throw new Error(1010)}delete this._mappings[a];return this},unmapOutlet:function(b,a){if(b==undefined){throw new Error(1010)}if(a==undefined){throw new Error(1010)}delete this._outlets[b][a];return this},mapHandler:function(b,c,d,e,a){if(b==undefined){throw new Error(1010)}if(c==undefined){c="global"}if(d==undefined){d=b}if(e==undefined){e=false}if(a==undefined){a=false}if(!this._handlers.hasOwnProperty(b)){this._handlers[b]={}}if(!this._handlers[b].hasOwnProperty(c)){this._handlers[b][c]=[]}this._handlers[b][c].push({handler:d,oneShot:e,passEvent:a});return this},unmapHandler:function(b,e,f){if(b==undefined){throw new Error(1010)}if(e==undefined){e="global"}if(f==undefined){f=b}if(this._handlers.hasOwnProperty(b)&&this._handlers[b].hasOwnProperty(e)){var a=this._handlers[b][e];for(var d in a){var c=a[d];if(c.handler==f){a.splice(d,1);break}}}return this},notify:function(g){var j=Array.prototype.slice.call(arguments);var c=j.slice(1);if(this._handlers.hasOwnProperty(g)){var d=this._handlers[g];for(var k in d){var h=d[k];var l;if(k!="global"){l=this.getObject(k)}var f=[];for(var e=0,b=h.length;e<b;e++){var m;var a=h[e];if(l&&typeof a.handler=="string"){m=l[a.handler]}else{m=a.handler}if(a.oneShot){f.unshift(e)}if(a.passEvent){m.apply(l,j)}else{m.apply(l,c)}}for(var e=0,b=f.length;e<b;e++){h.splice(f[e],1)}}}return this}};
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/**
* @author Camille Reynders
* Date: 03/02/12
* Time: 14:39
*/
( function( ns ){
ns.models.TodosModel = function(){
var _list = [];
return {
system : undefined, //inject,
getTodo : function( id ){
return _list[ this.getIndex( id ) ];
},
getIndex : function( id ){
var list = _list;
for( var i in _list ){
var todo = _list[ i ];
if( todo.id == id ) {
return i;
}
}
return -1;
},
notifyOfListUpdate : function(){
var list = this.getList();
this.system.notify( 'TodosModel:todosListUpdated', list );
},
setList : function( list ){
_list = list || [];
this.system.notify( 'TodosModel:todosListUpdated', list );
},
getList : function(){
return _list;
},
add : function( vo ){
_list.push( vo );
this.notifyOfListUpdate();
},
toggleDone : function( id ){
var todo = this.getTodo( id );
todo.done = ! todo.done;
this.notifyOfListUpdate();
},
setTitle : function( id, title ){
this.getTodo( id ).title = title;
this.notifyOfListUpdate();
},
remove : function( id ){
_list.splice( this.getIndex( id ), 1 );
this. notifyOfListUpdate();
},
setDoneForAll : function( done ){
for( var i in _list ){
_list[ i ].done = done;
}
this.notifyOfListUpdate();
},
removeAllDone : function(){
for( var i = _list.length - 1, n = 0; i >= n; i-- ){
if( _list[ i ].done ){
_list.splice( i, 1 );
}
}
this.notifyOfListUpdate();
},
getNumTotal : function(){
return _list.length;
},
getNumActive : function(){
var count = 0;
for( var i in _list ){
if( ! _list[ i ].done ){
count++;
}
}
return count;
}
}
}
}( dijondemo ) );
\ No newline at end of file
/**
* @author Camille Reynders
* Date: 03/02/12
* Time: 13:27
*/
( function( ns ){
dijondemo.services.LocalStorageService = function(){
return {
system : undefined, //inject
store : function( data ){
return localStorage.setItem( 'todo-jquery', JSON.stringify( data ) );
},
retrieve : function(){
var data = localStorage.getItem('todo-jquery');
var output = ( data && JSON.parse( data ) ) || [];
this.system.notify( 'StorageService:retrieveCompleted', output );
}
}
}
}( dijondemo ) )
\ No newline at end of file
/**
* @author Camille Reynders
* Date: 03/02/12
* Time: 14:34
*/
( function( ns ){
ns.utils.Utils = {
// 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},
pluralize: function( count, word ) {
return count === 1 ? word : word + 's';
}
};
}( dijondemo ) );
\ No newline at end of file
/**
* @author Camille Reynders
* Date: 03/02/12
* Time: 14:20
*/
( function( ns ){
ns.views.FooterView = function(){
var $count = $('#todo-count');
var $clearBtn = $('#clear-completed');
var $footer = $('#todoapp').find('footer');
return {
system : undefined, //inject
pluralizeUtil : undefined, //inject,
setup : function(){
var self = this;
$clearBtn.on( 'click', function() {
self.system.notify( 'TodoListView:removeAllDoneTodos' );
} );
},
render : function(){
this.system.notify( 'FooterView:retrieveTodoCounts' );
},
updateCounts : function( numTodosTotal, numTodosActive ){
var numTodosCompleted = numTodosTotal - numTodosActive;
var countTitle = '<b>' + numTodosActive + '</b> ' + this.pluralizeUtil.pluralize( numTodosActive, 'item' ) + ' left';
var clearTitle = 'Clear ' + numTodosCompleted + ' completed ' + this.pluralizeUtil.pluralize( numTodosCompleted, 'item' );
// Only show the footer when there are at least one todo.
$footer.toggle( !!numTodosTotal );
// Active todo count
$count.html( countTitle );
// Toggle clear button and update title
$clearBtn.text( clearTitle ).toggle( !!numTodosCompleted );
}
}
}
}( dijondemo ) );
\ No newline at end of file
/**
* @author Camille Reynders
* Date: 03/02/12
* Time: 13:38
*/
( function(ns){
ns.views.TodoFormView = function(){
var $newTodo = $('#new-todo');
return {
system : undefined, //inject
enterKey : undefined, //inject
uuidUtil : undefined, //inject
setup : function(){
var self = this;
$newTodo.on( 'keyup', function(e) {
if ( e.which !== self.enterKey ) {
return;
}
var $input = $(this);
var inputVal = $input.val();
if ( !inputVal ) {
return;
}
self.system.notify( 'TodoFormView:addTodo', {
title: inputVal,
id: self.uuidUtil.uuid(),
done: false
})
$input.val('');
} );
},
render : function(){
}
}
}
}( dijondemo ))
\ No newline at end of file
/**
* @author Camille Reynders
* Date: 03/02/12
* Time: 13:39
*/
( function(ns){
ns.views.TodoListView = function(){
var _template = Handlebars.compile( $('#todo-template').html() );
var $toggleAll = $('#toggle-all');
var $todoList = $('#todo-list');
var $main = $('#main');
var $count = $('#todo-count');
return {
system : undefined, //inject
enterKey : undefined,
setup : function(){
var self = this;
$todoList.on( 'change', '.toggle', function() {
var id = $( this ).closest('li').data('id');
self.system.notify( 'TodoListView:toggleDoneOfTodo', id );
} );
$todoList.on( 'dblclick', '.view', function() {
$(this)
.closest('li')
.addClass('editing')
.find('.edit')
.focus();
} );
$todoList.on( 'keypress', '.edit', function(e) {
if ( e.keyCode === self.enterKey ) {
console.log( e.target );
e.target.blur();
}
} );
$todoList.on( 'blur', '.edit', function() {
var id = $( this ).closest('li').data('id');
var val = $(this).removeClass('editing').val();
self.system.notify( 'TodoListView:setTitleOfTodo', id, val );
} );
$todoList.on( 'click', '.destroy', function() {
var id = $( this ).closest('li').data('id');
self.system.notify( 'TodoListView:removeTodo', id );
} );
$toggleAll.on( 'change', function() {
var isChecked = !!$(this).attr('checked');
self.system.notify( 'TodoListView:setDoneForAllTodos', isChecked );
} );
},
render : function( todosList ){
$todoList.html( _template( todosList ) );
$main.toggle( !!todosList.length );
}
}
}
}( dijondemo ))
\ No newline at end of file
Fun TodoMVC
===========
This is an implementation of the [TodoMVC example application](http://addyosmani.github.com/todomvc/) in [Fun](https://github.com/marcuswestin/fun), a new programming language for web apps.
Note that `index.html` is the compiled output - see `app.fun` for the original source.
Getting started
---------------
To make changes to the todos-fun example you need to install fun:
sudo npm install fun@0.2.22 -g
fun app.fun --normalize.css=false
To compile, run
fun --compile app.fun --normalize.css=false > index.html
import localstorage
import list
import text
<head>
<meta charset="utf-8" />
<title>"Fun • TodoMVC"</title>
<link rel="stylesheet" href="../../assets/base.css" />
<link rel="stylesheet" href="css/app.css" />
</head>
tasks = []
localstorage.persist(tasks, 'todos-fun')
nextId = 1
localstorage.persist(nextId, 'todos-id')
displayTasks = tasks
displayFilter = 'all'
<section id="todoapp">
<header id="header">
<h1>"todos"</h1>
newTaskName = ''
<input id="new-todo" placeholder="What needs to be done?" autofocus=true data=newTaskName onkeypress=handler(event) {
if (event.keyCode is 13) {
trimmedName = text.trim(newTaskName.copy())
id = nextId.copy()
if trimmedName is ! '' {
tasks push: { title:trimmedName, completed:false, id:id }
newTaskName set: ''
}
nextId set: nextId.copy() + 1
}
}/>
</header>
if tasks.length {
<section id="main">
toggleAll = false
<input id="toggle-all" type="checkbox" data=toggleAll onchange=handler() {
for task in tasks {
task.completed set: !toggleAll.copy()
}
} />
<label for="toggle-all">"Mark all as complete"</label>
<ul id="todo-list">
for task in displayTasks {
<li class=(task.completed ? "complete" : "")>
<div class="view">
<input class="toggle" type="checkbox" data=task.completed />
<label>task.title</label>
<button class="destroy"></button onclick=handler() {
tasks set: list.filter(tasks.copy(), function(checkTask) { return checkTask.id is ! task.id })
}>
</div>
// TODO Implement editing
<input class="edit" data=task.title />
</li>
}
</ul>
</section>
<footer id="footer">
completedTasks = list.filter(tasks, function(task) { return task.completed })
pluralize = function(num) { return num is > 1 ? "items" : "item" }
<span id="todo-count">
numTasksLeft = tasks.length - completedTasks.length
<strong>numTasksLeft</strong>" "pluralize(numTasksLeft)" left"
</span>
<ul id="filters">
<li><a href="#" class=(displayFilter is 'all' ? 'selected' : '')>"All"</a></li onclick=handler() {
displayTasks set: tasks
displayFilter set:'all'
}>
<li><a href="#" class=(displayFilter is 'active' ? 'selected' : '')>"Active"</a></li onclick=handler() {
displayTasks set: list.filter(tasks, function(task) { return !task.completed })
displayFilter set:'active'
}>
<li><a href="#" class=(displayFilter is 'completed' ? 'selected' : '')>"Completed"</a></li onclick=handler() {
displayTasks set: list.filter(tasks, function(task) { return task.completed })
displayFilter set:'completed'
}>
</ul>
<button id="clear-completed">"Clear completed ("completedTasks.length")"</button onclick=handler() {
remainingTasks = []
for task in tasks {
if !task.completed {
remainingTasks push: task
}
}
tasks set: remainingTasks
}>
</footer>
}
</section>
<footer id="info">
<p>"Double-click to edit a todo"</p>
<p>"Created with "<a href="https://github.com/marcuswestin/fun">"Fun"</a>" by "<a href="http://marcuswest.in">"Marcus Westin"</a></p>
</footer>
/*
Fun injects "hook" dom nodes into the dom tree. The
reason why is too involved to outline here. However,
they break a few of the todo app styles, such as
`#todo-list li:last-child { border-bottom:none; }`.
This should be rectified in fun in the future, but
these css modifications are fine in the meantime.
*/
body {
background:
#EEE url('../../assets/bg.png');
}
#todo-list li:last-child {
border-bottom: 1px dotted #CCC;
}
#todo-list li label {
margin:20px 22px;
}
\ No newline at end of file
This diff is collapsed.
## TodoMVC - GWT Version
This is a Google Web Toolkit (GWT) implementation of the TodoMVC application. The GWT version
is rather different to all the other TodoMVC versions (Backbone, Knockout etc ...) in that it is
written in Java which is compiled to JavaScript. The files within the `gwttodo` folder are the result
of running the GWT compilation process on the Java files found within the src folder. The UI
pattern used by this application is Model-View-Presenter.
Whilst this application is very different to the other TodoMVC implementations, it still makes for
an interesting comparison. Large-scale JavaScript applications are often written with GWT or Closure,
with the resulting JavaScript code delivered to the client being compiled.
### Folder structure
- `css` - includes the template `app.css` file and the GWT specific `override.css`
- `gwttodo` - the GWT compiled output, this includes various HTML files, which contain the JavaScript
code for each <a href "http://code.google.com/webtoolkit/doc/latest/tutorial/compile.html">GWT permutation</a>. This
folder also includes some redundant files, see the issue <a href="https://github.com/ColinEberhardt/todomvc/issues/9">
Remove redundant compiler output</a>.
- `src` - the Java source for this application
### Building this application
The GWT TodoMVC application was built with Java 1.6 and GWT 2.4.0. The easiest way to build this application
is to download the GWT SDK:
http://code.google.com/webtoolkit/gettingstarted.html
Together with the Eclipse plugin:
http://code.google.com/webtoolkit/usingeclipse.html
html,
body {
margin: 0;
padding: 0;
}
body {
font: 14px "Helvetica Neue", Helvetica, Arial, sans-serif;
line-height: 1.4em;
background: #eeeeee;
color: #333333;
width: 520px;
margin: 0 auto;
-webkit-font-smoothing: antialiased;
}
#todoapp {
background: #fff;
padding: 20px;
margin-bottom: 40px;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0;
-ms-box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0;
-o-box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0;
box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0;
-webkit-border-radius: 0 0 5px 5px;
-moz-border-radius: 0 0 5px 5px;
-ms-border-radius: 0 0 5px 5px;
-o-border-radius: 0 0 5px 5px;
border-radius: 0 0 5px 5px;
}
#todoapp h1 {
font-size: 36px;
font-weight: bold;
text-align: center;
padding: 0 0 10px 0;
}
#todoapp input[type="text"] {
width: 466px;
font-size: 24px;
font-family: inherit;
line-height: 1.4em;
border: 0;
outline: none;
padding: 6px;
border: 1px solid #999999;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
-ms-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
-o-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
}
#todoapp input::-webkit-input-placeholder {
font-style: italic;
}
#main {
display: none;
}
#todo-list {
margin: 10px 0;
padding: 0;
list-style: none;
}
#todo-list li {
padding: 18px 20px 18px 0;
position: relative;
font-size: 24px;
border-bottom: 1px solid #cccccc;
}
#todo-list li:last-child {
border-bottom: none;
}
#todo-list li.done label {
color: #777777;
text-decoration: line-through;
}
#todo-list li .destroy {
display: none;
position: absolute;
top: 20px;
right: 10px;
cursor: pointer;
width: 20px;
height: 20px;
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUBAMAAAB/pwA+AAAABGdBTUEAALGPC/xhBQAAACdQTFRFzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMAAAA////zMzMhnu0WAAAAAt0Uk5T5u3pqtV3jFQEKAC0bVelAAAAfUlEQVQI12NYtWpFsc8R865VqxhWrZpyBgg8QcylZ8AgCsjMgTCPrWJYfgYKqhjWwJgaDDVnzpw+c2bPmTPHGWzOnNm95/TuM2cOM/AARXfvBooeZAAp270bRCIz4QoOIGtDMqwJZoUEQzvCYrhzuhhWtUKYEahOX7UK6iEA3A6NUGwCTZIAAAAASUVORK5CYII=') no-repeat center center;
}
#todo-list li:hover .destroy {
display: block;
}
#todo-list li.editing {
border-bottom: none;
margin-top: -1px;
padding: 0;
}
#todo-list li.editing:last-child {
margin-bottom: -1px;
}
#todo-list li.editing .edit {
display: block;
width: 444px;
padding: 13px 15px 14px 20px;
margin: 0;
}
#todo-list li.editing .view {
display: none;
}
#todo-list li .view label {
word-break: break-word;
}
#todo-list li .edit {
display: none;
}
#todoapp footer {
display: none;
margin: 0 -20px -20px -20px;
overflow: hidden;
color: #555555;
background: #f4fce8;
border-top: 1px solid #ededed;
padding: 0 20px;
line-height: 37px;
-webkit-border-radius: 0 0 5px 5px;
-moz-border-radius: 0 0 5px 5px;
-ms-border-radius: 0 0 5px 5px;
-o-border-radius: 0 0 5px 5px;
border-radius: 0 0 5px 5px;
}
#clear-completed {
display: none;
float: right;
line-height: 20px;
text-decoration: none;
background: rgba(0, 0, 0, 0.1);
color: #555555;
font-size: 11px;
margin-top: 8px;
margin-bottom: 8px;
padding: 0 10px 1px;
cursor: pointer;
-webkit-border-radius: 12px;
-moz-border-radius: 12px;
-ms-border-radius: 12px;
-o-border-radius: 12px;
border-radius: 12px;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
-ms-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
-o-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
}
#clear-completed:hover {
background: rgba(0, 0, 0, 0.15);
-webkit-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
-moz-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
-ms-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
-o-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
}
#clear-completed:active {
position: relative;
top: 1px;
}
#todo-count span {
font-weight: bold;
}
#instructions {
margin: 10px auto;
color: #777777;
text-shadow: rgba(255, 255, 255, 0.8) 0 1px 0;
text-align: center;
}
#instructions a {
color: #336699;
}
#credits {
margin: 30px auto;
color: #999;
text-shadow: rgba(255, 255, 255, 0.8) 0 1px 0;
text-align: center;
}
#credits a {
color: #888;
}
\ No newline at end of file
#todo-count span.word {
font-weight: normal;
}
/* The GWT TodoMVC uses a CellList - a framework widget for rendering a list of cells - to
render the list of todo items. Unfortunately the CellList uses a div as its root container
and wraps each cell in a separate div. There are no extension points that allow you to change this.
As a result, this application deviates from the TodoMVC standard of ul / li for the to do list. The
styles applied to the li elements are duplicated here, matching a listItem class instead. */
#todo-list .listItem {
padding: 18px 20px 18px 0;
position: relative;
font-size: 24px;
border-bottom: 1px solid #cccccc;
}
#todo-list div :last-child .listItem {
border-bottom: none;
}
#todo-list .listItem.done label {
color: #777777;
text-decoration: line-through;
}
#todo-list .listItem .destroy {
display: none;
position: absolute;
top: 20px;
right: 10px;
cursor: pointer;
width: 20px;
height: 20px;
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUBAMAAAB/pwA+AAAABGdBTUEAALGPC/xhBQAAACdQTFRFzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMAAAA////zMzMhnu0WAAAAAt0Uk5T5u3pqtV3jFQEKAC0bVelAAAAfUlEQVQI12NYtWpFsc8R865VqxhWrZpyBgg8QcylZ8AgCsjMgTCPrWJYfgYKqhjWwJgaDDVnzpw+c2bPmTPHGWzOnNm95/TuM2cOM/AARXfvBooeZAAp270bRCIz4QoOIGtDMqwJZoUEQzvCYrhzuhhWtUKYEahOX7UK6iEA3A6NUGwCTZIAAAAASUVORK5CYII=') no-repeat center center;
}
#todo-list .listItem:hover .destroy {
display: block;
}
#todo-list .listItem.editing {
border-bottom: none;
margin-top: -1px;
padding: 0;
}
#todo-list .listItem.editing:last-child {
margin-bottom: -1px;
}
#todo-list .listItem.editing .edit {
display: block;
width: 444px;
padding: 13px 15px 14px 20px;
margin: 0;
}
#todo-list .listItem.editing .view {
display: none;
}
#todo-list .listItem .view label {
word-break: break-word;
}
#todo-list .listItem .edit {
display: none;
}
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
function gwttodo(){var L='',ec='\n-',sb='" for "gwt:onLoadErrorFn"',qb='" for "gwt:onPropertyErrorFn"',Tb='"<script src=\\"',eb='"><\/script>',V='#',dc=');',Xb='-\n',fc='-><\/scr',Ub='.cache.js\\"><\/scr" + "ipt>"',X='/',Kb='5FD4AAC86E219AC1FF43B8231BBFC9A4',Lb='87D689CCFADB5E3A71E49647FA69B184',Mb='935405CAEE8D167A6A3D4E8FAE65D368',Qb=':',kb='::',Vb='<scr',db='<script id="',nb='=',W='?',xb='ActiveXObject',Nb='B0CF42A3AE3A14F349D922E798684002',pb='Bad handler "',yb='ChromeTab.ChromeFrame',Hb='Cross-site hosted mode not yet implemented. See issue ',Rb='DOMContentLoaded',Ob='F489C51DB09285D5DF4838E66BE501DB',Pb='FE73BA09C21765BDF56D7DE5BC958B2F',fb='SCRIPT',cb='__gwt_marker_gwttodo',gb='base',$='baseUrl',P='begin',O='bootstrap',wb='chromeframe',Z='clear.cache.gif',mb='content',cc='document.write(',U='end',$b='evtGroup: "loadExternalRefs", millis:(new Date()).getTime(),',ac='evtGroup: "moduleStartup", millis:(new Date()).getTime(),',Eb='gecko',Fb='gecko1_8',Q='gwt.codesvr=',R='gwt.hosted=',S='gwt.hybrid',rb='gwt:onLoadErrorFn',ob='gwt:onPropertyErrorFn',lb='gwt:property',M='gwttodo',ab='gwttodo.nocache.js',jb='gwttodo::',Ib='http://code.google.com/p/google-web-toolkit/issues/detail?id=2079',Db='ie6',Cb='ie8',Bb='ie9',Y='img',gc='ipt>',Wb='ipt><!-',Sb='loadExternalRefs',hb='meta',Zb='moduleName:"gwttodo", sessionId:window.__gwtStatsSessionId, subSystem:"startup",',T='moduleStartup',Ab='msie',ib='name',ub='opera',zb='safari',_='script',Jb='selectingPermutation',N='startup',_b='type: "end"});',bc='type: "moduleRequested"});',bb='undefined',Gb='unknown',tb='user.agent',vb='webkit',Yb='window.__gwtStatsEvent && window.__gwtStatsEvent({';var l=window,m=document,n=l.__gwtStatsEvent?function(a){return l.__gwtStatsEvent(a)}:null,o=l.__gwtStatsSessionId?l.__gwtStatsSessionId:null,p,q,r=L,s={},t=[],u=[],v=[],w=0,x,y;n&&n({moduleName:M,sessionId:o,subSystem:N,evtGroup:O,millis:(new Date).getTime(),type:P});if(!l.__gwt_stylesLoaded){l.__gwt_stylesLoaded={}}if(!l.__gwt_scriptsLoaded){l.__gwt_scriptsLoaded={}}function z(){var b=false;try{var c=l.location.search;return (c.indexOf(Q)!=-1||(c.indexOf(R)!=-1||l.external&&l.external.gwtOnLoad))&&c.indexOf(S)==-1}catch(a){}z=function(){return b};return b}
function A(){if(p&&q){p(x,M,r,w);n&&n({moduleName:M,sessionId:o,subSystem:N,evtGroup:T,millis:(new Date).getTime(),type:U})}}
function B(){function e(a){var b=a.lastIndexOf(V);if(b==-1){b=a.length}var c=a.indexOf(W);if(c==-1){c=a.length}var d=a.lastIndexOf(X,Math.min(c,b));return d>=0?a.substring(0,d+1):L}
function f(a){if(a.match(/^\w+:\/\//)){}else{var b=m.createElement(Y);b.src=a+Z;a=e(b.src)}return a}
function g(){var a=D($);if(a!=null){return a}return L}
function h(){var a=m.getElementsByTagName(_);for(var b=0;b<a.length;++b){if(a[b].src.indexOf(ab)!=-1){return e(a[b].src)}}return L}
function i(){var a;if(typeof isBodyLoaded==bb||!isBodyLoaded()){var b=cb;var c;m.write(db+b+eb);c=m.getElementById(b);a=c&&c.previousSibling;while(a&&a.tagName!=fb){a=a.previousSibling}if(c){c.parentNode.removeChild(c)}if(a&&a.src){return e(a.src)}}return L}
function j(){var a=m.getElementsByTagName(gb);if(a.length>0){return a[a.length-1].href}return L}
var k=g();if(k==L){k=h()}if(k==L){k=i()}if(k==L){k=j()}if(k==L){k=e(m.location.href)}k=f(k);r=k;return k}
function C(){var b=document.getElementsByTagName(hb);for(var c=0,d=b.length;c<d;++c){var e=b[c],f=e.getAttribute(ib),g;if(f){f=f.replace(jb,L);if(f.indexOf(kb)>=0){continue}if(f==lb){g=e.getAttribute(mb);if(g){var h,i=g.indexOf(nb);if(i>=0){f=g.substring(0,i);h=g.substring(i+1)}else{f=g;h=L}s[f]=h}}else if(f==ob){g=e.getAttribute(mb);if(g){try{y=eval(g)}catch(a){alert(pb+g+qb)}}}else if(f==rb){g=e.getAttribute(mb);if(g){try{x=eval(g)}catch(a){alert(pb+g+sb)}}}}}}
function D(a){var b=s[a];return b==null?null:b}
function E(a,b){var c=v;for(var d=0,e=a.length-1;d<e;++d){c=c[a[d]]||(c[a[d]]=[])}c[a[e]]=b}
function F(a){var b=u[a](),c=t[a];if(b in c){return b}var d=[];for(var e in c){d[c[e]]=e}if(y){y(a,d,b)}throw null}
u[tb]=function(){var c=navigator.userAgent.toLowerCase();var d=function(a){return parseInt(a[1])*1000+parseInt(a[2])};if(function(){return c.indexOf(ub)!=-1}())return ub;if(function(){return c.indexOf(vb)!=-1||function(){if(c.indexOf(wb)!=-1){return true}if(typeof window[xb]!=bb){try{var b=new ActiveXObject(yb);if(b){b.registerBhoIfNeeded();return true}}catch(a){}}return false}()}())return zb;if(function(){return c.indexOf(Ab)!=-1&&m.documentMode>=9}())return Bb;if(function(){return c.indexOf(Ab)!=-1&&m.documentMode>=8}())return Cb;if(function(){var a=/msie ([0-9]+)\.([0-9]+)/.exec(c);if(a&&a.length==3)return d(a)>=6000}())return Db;if(function(){return c.indexOf(Eb)!=-1}())return Fb;return Gb};t[tb]={gecko1_8:0,ie6:1,ie8:2,ie9:3,opera:4,safari:5};gwttodo.onScriptLoad=function(a){gwttodo.onScriptLoad=null;p=a;A()};if(z()){alert(Hb+Ib);return}C();B();n&&n({moduleName:M,sessionId:o,subSystem:N,evtGroup:O,millis:(new Date).getTime(),type:Jb});var G;try{E([Fb],Kb);E([ub],Lb);E([Db],Mb);E([Bb],Nb);E([Cb],Ob);E([zb],Pb);G=v[F(tb)];var H=G.indexOf(Qb);if(H!=-1){w=Number(G.substring(H+1));G=G.substring(0,H)}}catch(a){return}var I;function J(){if(!q){q=true;A();if(m.removeEventListener){m.removeEventListener(Rb,J,false)}if(I){clearInterval(I)}}}
if(m.addEventListener){m.addEventListener(Rb,function(){J()},false)}var I=setInterval(function(){if(/loaded|complete/.test(m.readyState)){J()}},50);n&&n({moduleName:M,sessionId:o,subSystem:N,evtGroup:O,millis:(new Date).getTime(),type:U});n&&n({moduleName:M,sessionId:o,subSystem:N,evtGroup:Sb,millis:(new Date).getTime(),type:P});var K=Tb+r+G+Ub;m.write(Vb+Wb+Xb+Yb+Zb+$b+_b+Yb+Zb+ac+bc+cc+K+dc+ec+fc+gc)}
gwttodo();
\ No newline at end of file
<!doctype html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link type="text/css" rel="stylesheet" href="css/app.css">
<link type="text/css" rel="stylesheet" href="css/override.css">
<title>GWT Todo App</title>
<script type="text/javascript" language="javascript" src="gwttodo/gwttodo.nocache.js"></script>
</head>
<body>
<noscript>
<div style="width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; background-color: white; border: 1px solid red; padding: 4px; font-family: sans-serif">
Your web browser must have JavaScript enabled
in order for this application to display correctly.
</div>
</noscript>
</body>
</html>
<?xml version="1.0" encoding="UTF-8"?>
<module rename-to='gwttodo'>
<!-- Inherit the core Web Toolkit stuff. -->
<inherits name='com.google.gwt.user.User'/>
<inherits name='com.google.gwt.json.JSON'/>
<!-- Don't inherit any GWT styles - they're ugly! -->
<!-- <inherits name='com.google.gwt.user.theme.clean.Clean'/>-->
<!-- Other module inherits -->
<!-- Specify the app entry point class. -->
<entry-point class='com.todo.client.GwtToDo'/>
<!-- Specify the paths for translatable code -->
<source path='client'/>
<add-linker name="xs" />
</module>
package com.todo.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.RootPanel;
/**
* Entry point class
*/
public class GwtToDo implements EntryPoint {
public void onModuleLoad() {
ToDoView toDoView = new ToDoView();
new ToDoPresenter(toDoView);
RootPanel.get().add(toDoView);
}
}
package com.todo.client;
import com.google.gwt.user.client.ui.TextBox;
public class TextBoxWithPlaceholder extends TextBox {
/**
* Sets the placeholder for this textbox
*
* @param value the placeholder value
*/
public void setPlaceholder(String value){
getElement().setAttribute("placeholder", value);
}
/**
* Gets the placeholder for this textbox
*
* @return the placeholder
*/
public String getPlaceholder(){
return getElement().getAttribute("placeholder");
}
}
package com.todo.client;
import java.util.Date;
import com.google.gwt.cell.client.AbstractCell;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.EventTarget;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
/**
* A cell that renders {@link ToDoItem} instances. This cell is rendered in both view and edit modes
* based on user interaction. In edit mode, browser events are handled in order to update
* the model item state.
*
* @author ceberhardt
*
*/
public class ToDoCell extends AbstractCell<ToDoItem> {
/**
* The HTML templates used to render the cell.
*/
interface Templates extends SafeHtmlTemplates {
/**
* The view-mode template
*/
@SafeHtmlTemplates.Template(
"<div class='{2}' data-timestamp='{3}'>" +
"{0} " +
"<label>{1}</label>" +
"<a class='destroy'></a>" +
"</div>")
SafeHtml view(SafeHtml checked, SafeHtml task, String done, String timestamp);
/**
* A template the renders a checked input
*/
@SafeHtmlTemplates.Template("<input class='check' type='checkbox' checked>")
SafeHtml inputChecked();
/**
* A template the renders an un-checked input
*/
@SafeHtmlTemplates.Template("<input class='check' type='checkbox'>")
SafeHtml inputClear();
/**
* The edit-mode template
*/
@SafeHtmlTemplates.Template("<div class='listItem editing'><input class='edit' value='{0}' type='text'></div>")
SafeHtml edit(String task);
}
private static Templates templates = GWT.create(Templates.class);
/**
* The item that is currently being edited
*/
private ToDoItem editingItem = null;
/**
* A flag that indicates that we are starting to edit the cell
*/
private boolean beginningEdit = false;
public ToDoCell() {
super("click", "keyup", "blur", "dblclick");
}
@Override
public void render(Context context, ToDoItem value, SafeHtmlBuilder sb) {
// render the cell in edit or view mode
if (isEditing(value)) {
SafeHtml rendered = templates.edit(value.getTitle());
sb.append(rendered);
} else {
SafeHtml rendered = templates.view(
value.isDone() ? templates.inputChecked() : templates.inputClear(),
SafeHtmlUtils.fromString(value.getTitle()),
value.isDone() ? "listItem view done" : "listItem view",
// NOTE: The addition of a timestamp here is a bit of a HACK! The problem
// is that the CellList uses a HasDataPresenter for rendering. This class
// caches the more recent rendered contents for each cell, skipping a render
// if it looks like the cell hasn't changed. However, this fails for editable cells
// that are able to change the DOM representation directly. This hack simply
// ensures that the presenter always renders the cell.
Long.toString(new Date().getTime()));
sb.append(rendered);
}
}
@Override
public boolean isEditing(Context context, Element parent, ToDoItem value) {
return isEditing(value);
}
@Override
public void onBrowserEvent(Context context, Element parent, ToDoItem value, NativeEvent event,
ValueUpdater<ToDoItem> valueUpdater) {
String type = event.getType();
if (isEditing(value)) {
// handle keyup events
if ("keyup".equals(type)) {
int keyCode = event.getKeyCode();
// handle enter key to commit the edit
if (keyCode == KeyCodes.KEY_ENTER) {
commitEdit(parent, value);
endEdit(context, parent, value);
}
// handle escape key to cancel the edit
if (keyCode == KeyCodes.KEY_ESCAPE) {
endEdit(context, parent, value);
}
}
// handle blur event
if ("blur".equals(type) && !beginningEdit) {
commitEdit(parent, value);
endEdit(context, parent, value);
}
} else {
// handle double clicks to enter edit more
if ("dblclick".equals(type)) {
beginEdit(context, parent, value);
beginningEdit = true;
InputElement input = getInputElement(parent);
input.focus();
input.select();
beginningEdit = false;
}
// when not in edit mode - handle click events on the cell
if ("click".equals(type)) {
EventTarget eventTarget = event.getEventTarget();
Element clickedElement = Element.as(eventTarget);
String tagName = clickedElement.getTagName();
// check whether the checkbox was clicked
if (tagName.equals("INPUT")) {
// if so, synchronise the model state
InputElement input = clickedElement.cast();
value.setDone(input.isChecked());
// update the 'row' style
if (input.isChecked()) {
getViewRootElement(parent).addClassName("done");
} else {
getViewRootElement(parent).removeClassName("done");
}
} else if (tagName.equals("A")) {
// if the delete anchor was clicked - delete the item
value.delete();
}
}
}
}
/**
* Commits the changes in text value to the ToDoItem
*/
private void commitEdit(Element parent, ToDoItem value) {
InputElement input = getInputElement(parent);
value.setTitle(input.getValue());
}
/**
* Begins editing the given item, rendering the cell in edit mode
*/
private void beginEdit(Context context, Element parent, ToDoItem value) {
editingItem = value;
renderCell(context, parent, value);
}
/**
* Ends editing the given item, rendering the cell in view mode
*/
private void endEdit(Context context, Element parent, ToDoItem value) {
editingItem = null;
renderCell(context, parent, value);
}
/**
* Renders the cell, replacing the contents of the parent with the newly rendered content.
*/
private void renderCell(Context context, Element parent, ToDoItem value) {
SafeHtmlBuilder sb = new SafeHtmlBuilder();
render(context, value, sb);
parent.setInnerHTML(sb.toSafeHtml().asString());
}
/**
* Gets whether the given item is being edited.
*/
private boolean isEditing(ToDoItem item) {
return editingItem == item;
}
/**
* Get the input element in edit mode.
*/
private InputElement getInputElement(Element parent) {
return parent.getFirstChild().getFirstChild().<InputElement> cast();
}
/**
* Gets the root DIV element of the view mode template.
*/
private DivElement getViewRootElement(Element parent) {
return parent.getFirstChild().<DivElement> cast();
}
}
package com.todo.client;
/**
* An individual ToDo item.
*
* @author ceberhardt
*
*/
public class ToDoItem {
private final ToDoPresenter presenter;
private String title;
private boolean done;
public ToDoItem(String text, ToDoPresenter presenter) {
this.title = text;
this.done = false;
this.presenter = presenter;
}
public ToDoItem(String title, boolean done, ToDoPresenter presenter) {
this.title = title;
this.done = done;
this.presenter = presenter;
}
public boolean isDone() {
return done;
}
public void setDone(boolean done) {
this.done = done;
presenter.itemStateChanged(this);
}
public void delete() {
presenter.deleteTask(this);
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
presenter.itemStateChanged(this);
}
}
package com.todo.client;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONBoolean;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONParser;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.storage.client.Storage;
import com.google.gwt.view.client.AbstractDataProvider;
import com.google.gwt.view.client.ListDataProvider;
/**
* The presenter for the ToDo application. This class is responsible for the lifecycle
* of the {@link ToDoItem} instances.
*
* @author ceberhardt
*
*/
public class ToDoPresenter {
private static final String STORAGE_KEY = "todo-gwt-state";
/**
* The interface that a view for this presenter must implement.
*/
public interface View {
/**
* Gets the text that the user has input for the creation of new tasks.
*/
String getTaskText();
/**
* Clears the user input field where new tasks are added.
*/
void clearTaskText();
/**
* Sets the current task statistics.
*/
void setTaskStatistics(int totalTasks, int completedTasks);
/**
* Sets the data provider that acts as a source of {@link ToDoItem} instances.
*/
void setDataProvider(AbstractDataProvider<ToDoItem> data);
/**
* Adds the handler to the events raised by the view.
*/
void addhandler(ViewEventHandler handler);
}
/**
* The interface that handles interactions from the view.
*
*/
public interface ViewEventHandler {
/**
* Invoked when a user adds a new task.
*/
void addTask();
/**
* Invoked when a user wishes to clear completed tasks.
*/
void clearCompletedTasks();
/**
* Sets the completed state of all tasks to the given state
*/
void markAllCompleted(boolean completed);
}
/**
* Handler for view events, defers to private presenter methods.
*/
private ViewEventHandler viewHandler = new ViewEventHandler() {
@Override
public void addTask() {
ToDoPresenter.this.addTask();
}
@Override
public void clearCompletedTasks() {
ToDoPresenter.this.clearCompletedTasks();
}
@Override
public void markAllCompleted(boolean completed) {
ToDoPresenter.this.markAllCompleted(completed);
}
};
private final ListDataProvider<ToDoItem> todos = new ListDataProvider<ToDoItem>();
private final View view;
private boolean suppressStateChanged = false;
public ToDoPresenter(View view) {
this.view = view;
loadState();
view.addhandler(viewHandler);
view.setDataProvider(todos);
updateTaskStatistics();
}
/**
* Computes the tasks statistics and updates the view.
*/
private void updateTaskStatistics() {
int totalTasks = todos.getList().size();
int completeTask = 0;
for(ToDoItem task : todos.getList()){
if (task.isDone()){
completeTask ++;
}
}
view.setTaskStatistics(totalTasks, completeTask);
}
/**
* Deletes the given task and updates statistics.
*/
protected void deleteTask(ToDoItem toDoItem) {
todos.getList().remove(toDoItem);
updateTaskStatistics();
saveState();
}
/**
* Invoked by a task when its state changes so that we can update
* the view statistics and persist.
*/
protected void itemStateChanged(ToDoItem toDoItem) {
if (suppressStateChanged) {
return;
}
// if the item has become empty, remove it
if (toDoItem.getTitle().trim().equals("")) {
todos.getList().remove(toDoItem);
}
updateTaskStatistics();
saveState();
}
/**
* Sets the completed state of all tasks
*/
private void markAllCompleted(boolean completed) {
// update the completed state of each item
suppressStateChanged = true;
for(ToDoItem task : todos.getList()){
task.setDone(completed);
}
suppressStateChanged = false;
// cause the view to refresh the whole list - yes, this is a bit ugly!
List<ToDoItem> items = new ArrayList<ToDoItem>(todos.getList());
todos.getList().clear();
todos.getList().addAll(items);
updateTaskStatistics();
saveState();
}
/**
* Adds a new task based on the user input field
*/
private void addTask() {
String taskTitle = view.getTaskText().trim();
// if white-space only, do not add a todo
if (taskTitle.equals(""))
return;
ToDoItem toDoItem = new ToDoItem(taskTitle, this);
view.clearTaskText();
todos.getList().add(toDoItem);
updateTaskStatistics();
saveState();
}
/**
* Clears completed tasks and updates the view.
*/
private void clearCompletedTasks() {
Iterator<ToDoItem> iterator = todos.getList().iterator();
while (iterator.hasNext()) {
ToDoItem item = iterator.next();
if (item.isDone()) {
iterator.remove();
}
}
updateTaskStatistics();
saveState();
}
/**
* Saves the current to-do items to local storage
*/
private void saveState() {
Storage storage = Storage.getLocalStorageIfSupported();
if (storage != null) {
// JSON encode the items
JSONArray todoItems = new JSONArray();
for (int i = 0; i < todos.getList().size(); i++) {
ToDoItem toDoItem = todos.getList().get(i);
JSONObject jsonObject = new JSONObject();
jsonObject.put("task", new JSONString(toDoItem.getTitle()));
jsonObject.put("complete", JSONBoolean.getInstance(toDoItem.isDone()));
todoItems.set(i, jsonObject);
}
// save to local storage
storage.setItem(STORAGE_KEY, todoItems.toString());
}
}
private void loadState() {
Storage storage = Storage.getLocalStorageIfSupported();
if (storage != null) {
try {
// get state
String state = storage.getItem(STORAGE_KEY);
// parse the JSON array
JSONArray todoItems = JSONParser.parseStrict(state).isArray();
for (int i = 0; i < todoItems.size(); i++) {
// extract the to-do item values
JSONObject jsonObject = todoItems.get(i).isObject();
String task = jsonObject.get("task").isString().stringValue();
boolean completed = jsonObject.get("complete").isBoolean().booleanValue();
// add a new item to our list
todos.getList().add(new ToDoItem(task, completed, this));
}
} catch (Exception e) {
}
}
}
}
This diff is collapsed.
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:cv="urn:import:com.google.gwt.user.cellview.client"
xmlns:todo="urn:import:com.todo.client">
<g:HTMLPanel>
<div id="todoapp">
<header>
<h1>Todos</h1>
<todo:TextBoxWithPlaceholder
placeholder="What needs to be done?" ui:field="taskText">
</todo:TextBoxWithPlaceholder>
</header>
<section ui:field="mainSection">
<g:CheckBox ui:field="toggleAllCheckBox">Mark all as complete</g:CheckBox>
<div id="todo-list">
<cv:CellList ui:field="todoTable"></cv:CellList>
</div>
</section>
<footer ui:field="todoStatsContainer">
<g:Anchor href="#" ui:field="clearCompleted">
Clear
<span class="number-done" ui:field="clearTasksCount"></span>
completed
<span class="word-done" ui:field="clearTasksLabel"></span>
</g:Anchor>
<div id="todo-count">
<span class="number" ui:field="remainingTasksCount"></span>
<span class="word" ui:field="remainingTasksLabel"></span>
left.
</div>
</footer>
</div>
<div id="instructions">
Double-click to edit a todo.
</div>
<div id="credits">
Created by
<br />
<a href="http://jgn.me/">Jérôme Gravel-Niquet</a>
<br />
Modified to use
<a href="http://code.google.com/webtoolkit/">Google Web Toolkit</a>
by
<a href="http://www.scottlogic.co.uk/blog/colin/">Colin Eberhardt</a>
</div>
</g:HTMLPanel>
</ui:UiBinder>
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
# Simple Todo App build with rAppid.js
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
{
"xamlClasses": ["js.ui.Link", "js.ui.MenuButton", "js.ui.SplitButton" , "js.ui.TabView", "app.view.TodoView"],
"namespaceMap": null,
"rewriteMap": null
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
// defined under rAppid.js
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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