Skip to content

Commit

Permalink
Re-worked @jsoverson's Marionette implementation to use Marionette's …
Browse files Browse the repository at this point in the history
…modules
  • Loading branch information
Derick Bailey authored and sindresorhus committed Oct 9, 2012
1 parent 2a92388 commit b7cc462
Show file tree
Hide file tree
Showing 12 changed files with 4,435 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
js/lib/underscore.js
js/lib/backbone.js
js/lib/backbone.marionette.js
js/lib/backbone-localStorage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#todoapp.filter-active #todo-list .completed {
display:none
}
#todoapp.filter-completed #todo-list .active {
display:none
}

#main, #footer {
display : none;
}
105 changes: 105 additions & 0 deletions labs/architecture-examples/backbone_marionette_modules/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<!doctype html>
<html lang="en">

<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Marionette • TodoMVC</title>
<link rel="stylesheet" href="../../../assets/base.css">
<link rel="stylesheet" href="css/custom.css">
<!--[if IE]>
<script src="../../../assets/ie.js"></script>
<![endif]-->

<script type="text/html" id="template-footer">
<span id="todo-count"><strong></strong> items left</span>
<ul id="filters">
<li>
<a href="#">All</a>
</li>
<li>
<a href="#active">Active</a>
</li>
<li>
<a href="#completed">Completed</a>
</li>
</ul>
<button id="clear-completed">Clear completed</button>
</script>

<script type="text/html" id="template-header">
<h1>todos</h1>
<input id="new-todo" placeholder="What needs to be done?" autofocus>
</script>

<script type="text/html" id="template-todoItemView">
<div class="view">
<input class="toggle" type="checkbox" <% if (completed) { %>checked<% } %>>
<label><%= title %></label>
<button class="destroy"></button>
</div>
<input class="edit" value="<%= title %>">
</script>

<script type="text/html" id="template-todoListCompositeView">
<input id="toggle-all" type="checkbox">
<label for="toggle-all">Mark all as complete</label>
<ul id="todo-list"></ul>
</script>

<script>
// Google analytics
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-22728809-1']);
_gaq.push(['_trackPageview']);
(function () {
var ga = document.createElement('script');
ga.type = 'text/javascript';
ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();
</script>

</head>

<body>
<section id="todoapp">
<header id="header"></header>
<section id="main"></section>
<footer id="footer"></footer>
</section>

<footer id="info">
<p>Double-click to edit a todo</p>
<p>
Created by <a href="http://github.com/jsoverson">Jarrod Overson</a>
and <a href="http://github.com/derickbailey">Derick Bailey</a>,
using <a href="http://marionettejs.com">Backbone.Marionette</a>
</p>
</footer>

<!-- vendor libraries -->
<script src="../../../assets/base.js"></script>
<script src="../../../assets/jquery.min.js"></script>
<script src="js/lib/underscore.js"></script>
<script src="js/lib/backbone.js"></script>
<script src="js/lib/backbone-localStorage.js"></script>
<script src="js/lib/backbone.marionette.js"></script>

<!-- application -->
<script src="js/TodoMVC.js"></script>
<script src="js/TodoMVC.Todos.js"></script>
<script src="js/TodoMVC.Layout.js"></script>
<script src="js/TodoMVC.TodoList.Views.js"></script>
<script src="js/TodoMVC.TodoList.js"></script>

<script>
$(function(){
// Start the TodoMVC app (defined in js/TodoMVC.js)
TodoMVC.start();
});
</script>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
TodoMVC.module("Layout", function(Layout, App, Backbone, Marionette, $, _){

// Layout Header View
// ------------------

Layout.Header = Backbone.Marionette.ItemView.extend({
template : "#template-header",

// UI bindings create cached attributes that
// point to jQuery selected objects
ui : {
input : '#new-todo'
},

events : {
'keypress #new-todo': 'onInputKeypress'
},

onInputKeypress : function(evt) {
var ENTER_KEY = 13;
var todoText = this.ui.input.val().trim();

if ( evt.which === ENTER_KEY && todoText ) {
this.collection.create({
title : todoText
});
this.ui.input.val('');
}
}
});

// Layout Footer View
// ------------------

Layout.Footer = Backbone.Marionette.Layout.extend({
template : "#template-footer",

// UI bindings create cached attributes that
// point to jQuery selected objects
ui : {
count : '#todo-count strong',
filters : '#filters a'
},

events : {
'click #clear-completed' : 'onClearClick'
},

initialize : function() {
this.bindTo(App.vent, 'todoList:filter', this.updateFilterSelection, this);
this.bindTo(this.collection, 'all', this.updateCount, this);
},

onRender : function() {
this.updateCount();
},

updateCount : function() {
var count = this.collection.getActive().length;
this.ui.count.html(count);

if (count === 0) {
this.$el.parent().hide();
} else {
this.$el.parent().show();
}
},

updateFilterSelection : function(filter) {
this.ui.filters
.removeClass('selected')
.filter('[href="#' + filter + '"]')
.addClass('selected');
},

onClearClick : function() {
var completed = this.collection.getCompleted();
completed.forEach(function destroy(todo) {
todo.destroy();
});
}
});

});
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
TodoMVC.module("TodoList.Views", function(Views, App, Backbone, Marionette, $, _){

// Todo List Item View
// -------------------
//
// Display an individual todo item, and respond to changes
// that are made to the item, including marking completed.

Views.ItemView = Marionette.ItemView.extend({
tagName : 'li',
template : "#template-todoItemView",

ui : {
edit : '.edit'
},

events : {
'click .destroy' : 'destroy',
'dblclick label' : 'onEditClick',
'keypress .edit' : 'onEditKeypress',
'click .toggle' : 'toggle'
},

initialize : function() {
this.bindTo(this.model, 'change', this.render, this);
},

onRender : function() {
this.$el.removeClass('active completed');
if (this.model.get('completed')) this.$el.addClass('completed');
else this.$el.addClass('active');
},

destroy : function() {
this.model.destroy();
},

toggle : function() {
this.model.toggle().save();
},

onEditClick : function() {
this.$el.addClass('editing');
this.ui.edit.focus();
},

onEditKeypress : function(evt) {
var ENTER_KEY = 13;
var todoText = this.ui.edit.val().trim();

if ( evt.which === ENTER_KEY && todoText ) {
this.model.set('title', todoText).save();
this.$el.removeClass('editing');
}
}
});

// Item List View
// --------------
//
// Controls the rendering of the list of items, including the
// filtering of activs vs completed items for display.

Views.ListView = Backbone.Marionette.CompositeView.extend({
template : "#template-todoListCompositeView",
itemView : Views.ItemView,
itemViewContainer : '#todo-list',

ui : {
toggle : '#toggle-all'
},

events : {
'click #toggle-all' : 'onToggleAllClick'
},

initialize : function() {
this.bindTo(this.collection, 'all', this.update, this);
},

onRender : function() {
this.update();
},

update : function() {
function reduceCompleted(left, right) { return left && right.get('completed'); }
var allCompleted = this.collection.reduce(reduceCompleted,true);
this.ui.toggle.prop('checked', allCompleted);

if (this.collection.length === 0) {
this.$el.parent().hide();
} else {
this.$el.parent().show();
}
},

onToggleAllClick : function(evt) {
var isChecked = evt.currentTarget.checked;
this.collection.each(function(todo){
todo.save({'completed': isChecked});
});
}
});

// Application Event Handlers
// --------------------------
//
// Handler for filtering the list of items by showing and
// hiding through the use of various CSS classes

App.vent.on('todoList:filter',function(filter) {
filter = filter || 'all';
$('#todoapp').attr('class', 'filter-' + filter);
});

});
Loading

0 comments on commit b7cc462

Please sign in to comment.