Simple Backbone.Marionette tutorial
The result of blog posts http://davidsulc.com/blog/2012/04/15/a-simple-backbone-marionette-tutorial/ http://davidsulc.com/blog/2012/04/22/a-simple-backbone-marionette-tutorial-part-2/
by hoffmanc
HTML
<script src="http://documentcloud.github.com/underscore/underscore-min.js"></script>
<script src="http://documentcloud.github.com/backbone/backbone-min.js"></script>
<script src="https://raw.github.com/derickbailey/backbone.marionette/master/lib/backbone.marionette.js"></script>
<div id="content">
</div>
<script type="text/template" id="angry_cats-template">
<thead>
<tr class='header'>
<th>Rank</th>
<th>Votes</th>
<th>Name</th>
<th>Image</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</script>
<script type="text/template" id="angry_cat-template">
<td><%= rank %></td>
<td><%= votes %></td>
<td><%= name %></td>
<td><img class='angry_cat_pic' src='<%= image_path %>' /></td>
<td>
<div class='rank_up'><img id="rank_up" src='http://placehold.it/12x24&text=^' /></div>
<div class='rank_down'><img src='http://placehold.it/12x24&text=v' /></div>
</td>
<td><a href="#" class="disqualify">Disqualify</a></td>
</script>
CSS
/*!
* Bootstrap v2.0.2
*
* Copyright 2012 Twitter, Inc
* Licensed under the Apache License v2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Designed and built with all the love in the world @twitter by @mdo and @fat.
*/
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
nav,
section {
display: block;
}
audio,
canvas,
video {
display: inline-block;
*display: inline;
*zoom: 1;
}
audio:not([controls]) {
display: none;
}
html {
font-size: 100%;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
a:focus {
outline: thin dotted #333;
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
a:hover,
a:active {
outline: 0;
}
sub,
sup {
position: relative;
font-size: 75%;
line-height: 0;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
img {
height: auto;
border: 0;
-ms-interpolation-mode: bicubic;
vertical-align: middle;
}
button,
input,
select,
textarea {
margin: 0;
font-size: 100%;
vertical-align: middle;
}
button,
input {
*overflow: visible;
line-height: normal;
}
button::-moz-focus-inner,
input::-moz-focus-inner {
padding: 0;
border: 0;
}
button,
input[type="button"],
input[type="reset"],
input[type="submit"] {
cursor: pointer;
-webkit-appearance: button;
}
input[type="search"] {
-webkit-appearance: textfield;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
}
input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-cancel-button {
-webkit-appearance: none;
}
textarea {
overflow: auto;
vertical-align: top;
}
.clearfix {
*zoom: 1;
}
.clearfix:before,
.clearfix:after {
display: table;
content: "";
}
.clearfix:after {
clear: both;
}
.hide-text {
overflow: hidden;
text-indent: 100%;
white-space: nowrap;
}
.input-block-level {
display: block;
width: 100%;
min-height: 28px;
/* Make inputs at least the height of their button...
JavaScript
MyApp = new Backbone.Marionette.Application();
MyApp.addRegions({
mainRegion: "#content"
});
AngryCat = Backbone.Model.extend({
defaults: {
votes: 0
},
addVote: function(){
this.set('votes', this.get('votes') + 1);
},
rankUp: function() {
this.set({rank: this.get('rank') - 1});
},
rankDown: function() {
this.set({rank: this.get('rank') + 1});
}
});
AngryCats = Backbone.Collection.extend({
model: AngryCat,
initialize: function(cats){
var rank = 1;
_.each(cats, function(cat) {
cat.set('rank', rank);
++rank;
});
this.on('add', function(cat){ if( ! cat.get('rank') ) console.error("Cat must have a rank defined before being added to the collection"); });
var self = this;
MyApp.vent.on("rank:up", function(cat){
if (cat.get('rank') == 1) {
// can't increase rank of top-ranked cat
return true;
}
self.rankUp(cat);
self.sort();
});
MyApp.vent.on("rank:down", function(cat){
if (cat.get('rank') == self.size()) {
// can't decrease rank of lowest ranked cat
return true;
}
self.rankDown(cat);
self.sort();
});
MyApp.vent.on("cat:disqualify", function(cat){
var disqualifiedRank = cat.get('rank');
var catsToUprank = self.filter(
function(cat){ return cat.get('rank') > disqualifiedRank; }
);
catsToUprank.forEach(function(cat){
cat.rankUp();
});
self.trigger('reset');
});
},
comparator: function(cat) {
return cat.get('rank');
},
rankUp: function(cat) {
// find the cat we're going to swap ranks with
var rankToSwap = cat.get('rank') - 1;
var otherCat = this.at(rankToSwap - 1);
// swap ranks
cat.rankUp();
otherCat.rankDown();
},
rankDown: function(cat) {
// find the cat we're going to swap ranks with
var rankToSwap = cat.get('rank') + 1;
var otherCat = this.at(rankToSwap...