can
Version:
MIT-licensed, client-side, JavaScript framework that makes building rich web applications easy.
192 lines (170 loc) • 4.76 kB
HTML
<html>
<head>
<style>
.done {
text-decoration: line-through;
}
</style>
</head>
<body>
<ul id='todos'></ul>
<input id='editor'/>
<script type='text/ejs' id='todosEjs'>
<% list(this, function( todo ) { %>
<li <%= (el) -> el.data('todo',todo) %>>
<input type="checkbox" class="complete" <%= todo.attr('complete') ? 'checked' : '' %>>
<span class="<%= todo.attr('complete') ? 'done' : '' %>">
<%= todo.attr('name') %>
</span>
<a href="javascript://" class='destroy'>X</a>
</li>
<% }) %>
</script>
<h1>Welcome To History-Todo</h1>
<p>History-Todo shows how to build 2 independent widgets (a list and an editor) and tie them together with a managing controller. The managing controller also listens to routes. A full write-up can be found <a href='http://localhost:3002/javascriptmvc/jmvc/docs.html#!rapidstart'>here</a>.</p>
<p>Combined, this lets you:</p>
<ol>
<li>Click a todo, an input will appear that allows you to change the name. The change happens when you blur the input element.</li>
<li>Click several todos, then use the browser's forward and back button to toggle between them.</li>
</ol>
<script type='text/javascript' src='../../../steal/steal.js'></script>
<script type='text/javascript'>
STEALDOJO = true;
steal('can/model',
'can/util/fixture',
'can/view/ejs',
'can/control',
'can/control/route',
function($){
// GETS TODOS FROM THE SERVER
can.Model('Todo',{
findAll : "GET /todos",
findOne : "GET /todos/{id}",
create : "POST /todos",
update : "PUT /todos/{id}",
destroy : "DELETE /todos/{id}"
},
{});
// WE DON'T HAVE A SERVER, USE FIXTURES
// TO SIMULATE ONE:
// Our fake todos
var TODOS = [
{id: 1, name: "wake up", complete: true},
{id: 2, name: "take out trash", complete: false},
{id: 3, name: "do dishes", complete: false}
];
// findAll
$.fixture("GET /todos", function(){
return [TODOS]
});
// findOne
$.fixture("GET /todos/{id}", function(orig){
// using the id, return that todo
return TODOS[(+orig.data.id)-1];
})
// create
var id= 4;
$.fixture("POST /todos", function(){
// just need to send back a new id
return {id: (id++)}
})
// update
$.fixture("PUT /todos/{id}", function(){
// just send back success
return {};
})
// destroy
$.fixture("DELETE /todos/{id}", function(){
// just send back success
return {};
});
// CONTROLLERS ARE USED FOR WIDGETS LIKE A LIST OF TODOS
// OR FOR MANGING WIDGETS
// Organizes a list of todos
can.Control("Todos",{
// called when a new Todos() is created
"init" : function( element , options ){
// get all todos and render them with
// a template in the element's html
var self = this;
can.view('todosEjs', Todo.findAll()).then(function(frag){
self.element.html(frag)
});
},
// when a todo is clicked, create a 'selected'
// event for others to listen to
"li click" : function(li){
li.trigger('selected', li.data('todo') );
},
// when .complete is clicked, mark the todo completed
"li .complete click" : function(el, ev){
el.closest('li')
.data('todo')
.attr('complete', el.prop('checked'))
.save();
ev.stopPropagation();
},
// when .destroy is clicked, destroy the
// todo
"li .destroy click" : function(el, ev){
el.closest('li')
.data('todo')
.destroy();
ev.stopPropagation();
}
});
// Editor manages editing a todo's name
// call update on the editor like
can.Control('Editor',{
todo : function(todo){
this.update({todo: todo});
this.setName()
},
// a helper that sets the value of the input
// to the todo's name
setName : function(){
this.element.val(this.options.todo.name);
},
// listen for changes in the todo
// and update the input
"{todo} updated" : function(){
this.setName();
},
"{todo} destroyed" : function(){
this.element.hide();
},
// when the input changes
// update the todo instance
"change" : function(){
var todo = this.options.todo
todo.attr('name',this.element.val())
todo.save();
}
});
// Routing puts all the widget controllers together
// along with managing routes
can.Control("Routing",{
init : function(){
this.editor = new Editor("#editor")
new Todos("#todos");
},
// the index page
"route" : function(){
$("#editor").hide();
},
"todos/:id route" : function(data){
$("#editor").show();
Todo.findOne(data, $.proxy(function(todo){
this.editor.todo(todo);
}, this))
},
"li selected" : function(el, ev, todo){
can.route.attr('id',todo.id);
}
});
// create routing controller
new Routing(document.body);
})
</script>
</body>
</html>