Working now.
This commit is contained in:
parent
1c417adc6e
commit
d0af7f22e6
11
Makefile
11
Makefile
|
@ -6,14 +6,14 @@ ECHO= echo
|
||||||
|
|
||||||
LIBS:= htdocs/lib/underscore.js htdocs/lib/jquery.js htdocs/lib/backbone.js
|
LIBS:= htdocs/lib/underscore.js htdocs/lib/jquery.js htdocs/lib/backbone.js
|
||||||
|
|
||||||
all: htdocs/index.html htdocs/store.js htdocs/jsonstore.css htdocs/data/items.json
|
all: htdocs/index.html htdocs/store.js htdocs/data/items.json
|
||||||
@if [ ! -e "./htdocs/lib" ]; then \
|
@if [ ! -e "./htdocs/lib" ]; then \
|
||||||
echo "Please do 'make setup' before continuing"; \
|
echo "Please do 'make setup' before continuing"; \
|
||||||
exit 1; \
|
exit 1; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
serve: all
|
serve: all
|
||||||
$(COFFEE) ./bin/autoreload
|
./bin/autoreload
|
||||||
|
|
||||||
store: all
|
store: all
|
||||||
|
|
||||||
|
@ -39,10 +39,7 @@ docs:
|
||||||
mkdir -p docs
|
mkdir -p docs
|
||||||
|
|
||||||
htdocs/index.html: src/backbonestore.nw
|
htdocs/index.html: src/backbonestore.nw
|
||||||
$(NOTANGLE) -c -Rindex.haml src/backbonestore.nw > htdocs/index.html
|
$(NOTANGLE) -c -Rindex.html src/backbonestore.nw > htdocs/index.html
|
||||||
|
|
||||||
htdocs/jsonstore.css: src/backbonestore.nw
|
|
||||||
$(NOTANGLE) -c -Rjsonstore.css src/backbonestore.nw > htdocs/jsonstore.css
|
|
||||||
|
|
||||||
htdocs/store.js: src/backbonestore.nw
|
htdocs/store.js: src/backbonestore.nw
|
||||||
$(NOTANGLE) -c -Rstore.js src/backbonestore.nw > htdocs/store.js
|
$(NOTANGLE) -c -Rstore.js src/backbonestore.nw > htdocs/store.js
|
||||||
|
@ -67,7 +64,7 @@ docs/backbonestore.html: docs src/backbonestore.nw
|
||||||
html: docs/backbonestore.html
|
html: docs/backbonestore.html
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
- rm -f htdocs/*.* docs/*.tex docs/*.dvi docs/*.aux docs/*.toc docs/*.log docs/*.out
|
- rm -f htdocs/*.js htdocs/*.html docs/*.tex docs/*.dvi docs/*.aux docs/*.toc docs/*.log docs/*.out
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
- rm -fr ./htdocs/lib
|
- rm -fr ./htdocs/lib
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var Inotify = require('inotify').Inotify;
|
var Inotify = require('inotify').Inotify;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<title>The Backbone Store</title>
|
||||||
|
<link charset="utf-8" href="jsonstore.css" rel="stylesheet" type="text/css">
|
||||||
|
<script id="store_index_template" type="text/x-underscore-tmplate">
|
||||||
|
<h1>Product Catalog</h1>
|
||||||
|
<ul>
|
||||||
|
<% for(i=0,l=products.length;i<l;++i) { p = products[i]; %>
|
||||||
|
<li class="item">
|
||||||
|
<div class="item-image">
|
||||||
|
<a href="#item/<%= p.id %>">
|
||||||
|
<img alt="<%= p.title %>" src="<%= p.image %>">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="item-artist"><%= p.artist %></div>
|
||||||
|
<div class="item-title"><%= p.title %></div>
|
||||||
|
<div class="item-price">$<%= p.price %></div>
|
||||||
|
</li>
|
||||||
|
<% } %>
|
||||||
|
</ul>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="store_item_template" type="text/x-underscore-template">
|
||||||
|
<div class="item-detail">
|
||||||
|
<div class="item-image">
|
||||||
|
<img alt="<%= title %>" src="<%= large_image %>">
|
||||||
|
</div>
|
||||||
|
<div class="item-info">
|
||||||
|
<div class="item-artist"><%= artist %></div>
|
||||||
|
<div class="item-title"><%= title %></div>
|
||||||
|
<div class="item-price">$<%= price %></div>
|
||||||
|
<div class="item-form"></div>
|
||||||
|
<form action="#/cart" method="post">
|
||||||
|
<p>
|
||||||
|
<label>Quantity:</label>
|
||||||
|
<input class="uqf" name="quantity" size="2" type="text" value="1">
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<input class="uq" type="submit" value="Add to Cart">
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
<div class="item-link">
|
||||||
|
<a href="<%= url %>">Buy this item on Amazon</a>
|
||||||
|
</div>
|
||||||
|
<div class="back-link">
|
||||||
|
<a href="#">« Back to Items</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="store_cart_template" type="text/x-underscore-template">
|
||||||
|
<p>Items: <%= count %> ($<%= cost %>)</p>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="container">
|
||||||
|
<div id="header">
|
||||||
|
<h1>
|
||||||
|
The Backbone Store
|
||||||
|
</h1>
|
||||||
|
<div class="cart-info"></div>
|
||||||
|
</div>
|
||||||
|
<div id="main"></div>
|
||||||
|
</div>
|
||||||
|
<script src="lib/jquery.js" type="text/javascript"></script>
|
||||||
|
<script src="lib/underscore.js" type="text/javascript"></script>
|
||||||
|
<script src="lib/backbone.js" type="text/javascript"></script>
|
||||||
|
<script src="store.js" type="text/javascript"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
body {
|
||||||
|
font-family: "Lucida Grande", Lucida, Helvetica, Arial, sans-serif;
|
||||||
|
background: #fff;
|
||||||
|
color: #333;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
#main {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
#header {
|
||||||
|
background: #999;
|
||||||
|
background: -webkit-gradient(linear, left top, left bottom, from(#adadad), to(#7a7a7a));
|
||||||
|
background: -moz-linear-gradient(top, #adadad, #7a7a7a);
|
||||||
|
margin: 0px;
|
||||||
|
padding: 20px;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
#header h1 {
|
||||||
|
font-family: Inconsolata, Monaco, Courier, mono;
|
||||||
|
color: #fff;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
#header .cart-info {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
right: 0px;
|
||||||
|
text-align: right;
|
||||||
|
padding: 10px;
|
||||||
|
background: #555;
|
||||||
|
background: -webkit-gradient(linear, left top, left bottom, from(#777), to(#444));
|
||||||
|
background: -moz-linear-gradient(top, #777, #444);
|
||||||
|
color: #fff;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
.productitemview {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
#productlistview {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
#productlistview ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
.item {
|
||||||
|
float: left;
|
||||||
|
width: 250px;
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding: 5px;
|
||||||
|
-moz-border-radius-topleft: 5px;
|
||||||
|
-moz-border-radius-topright: 5px;
|
||||||
|
-moz-border-radius-bottomleft: 5px;
|
||||||
|
-moz-border-radius-bottomright: 5px;
|
||||||
|
-webkit-border-bottom-right-radius: 5px;
|
||||||
|
-webkit-border-top-left-radius: 5px;
|
||||||
|
-webkit-border-top-right-radius: 5px;
|
||||||
|
-webkit-border-bottom-left-radius: 5px;
|
||||||
|
border-bottom-right-radius: 5px;
|
||||||
|
border-top-left-radius: 5px;
|
||||||
|
border-top-right-radius: 5px;
|
||||||
|
border-bottom-left-radius: 5px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.item-title {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.item-artist {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.item-detail {
|
||||||
|
margin: 10px 0 0 10px;
|
||||||
|
}
|
||||||
|
.item-detail .item-image {
|
||||||
|
float: left;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
.item-detail .item-info {
|
||||||
|
padding: 100px 10px 0px 10px;
|
||||||
|
}
|
|
@ -0,0 +1,227 @@
|
||||||
|
var Product = Backbone.Model.extend({});
|
||||||
|
|
||||||
|
var Item = Backbone.Model.extend({
|
||||||
|
update: function(amount) {
|
||||||
|
if (amount === this.get('quantity')) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
this.set({quantity: amount}, {silent: true});
|
||||||
|
this.collection.trigger('update', this);
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
price: function() {
|
||||||
|
return this.get('product').get('price') * this.get('quantity');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var ProductCollection = Backbone.Collection.extend({
|
||||||
|
model: Product,
|
||||||
|
initialize: function(models, options) {
|
||||||
|
this.url = options.url;
|
||||||
|
},
|
||||||
|
|
||||||
|
comparator: function(item) {
|
||||||
|
return item.get('title');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var ItemCollection = Backbone.Collection.extend({
|
||||||
|
model: Item,
|
||||||
|
|
||||||
|
updateItemForProduct: function(product, amount) {
|
||||||
|
amount = amount != null ? amount : 0;
|
||||||
|
var pid = product.get('id');
|
||||||
|
var item = this.detect(function(obj) {
|
||||||
|
return obj.get('product').get('id') === pid;
|
||||||
|
});
|
||||||
|
if (item) {
|
||||||
|
item.update(amount);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
return this.add({
|
||||||
|
product: product,
|
||||||
|
quantity: amount
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getTotalCount: function() {
|
||||||
|
var addup = function(memo, obj) {
|
||||||
|
return memo + obj.get('quantity');
|
||||||
|
};
|
||||||
|
return this.reduce(addup, 0);
|
||||||
|
},
|
||||||
|
|
||||||
|
getTotalCost: function() {
|
||||||
|
var addup = function(memo, obj) {
|
||||||
|
return memo + obj.price();
|
||||||
|
};
|
||||||
|
return this.reduce(addup, 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var BaseView = Backbone.View.extend({
|
||||||
|
parent: $('#main'),
|
||||||
|
className: 'viewport',
|
||||||
|
|
||||||
|
initialize: function(options) {
|
||||||
|
Backbone.View.prototype.initialize.apply(this, arguments);
|
||||||
|
this.$el.hide();
|
||||||
|
this.parent.append(this.el);
|
||||||
|
},
|
||||||
|
|
||||||
|
hide: function() {
|
||||||
|
var dfd = $.Deferred();
|
||||||
|
if (!this.$el.is(':visible')) {
|
||||||
|
return dfd.resolve();
|
||||||
|
}
|
||||||
|
this.$el.fadeOut('fast', function() {
|
||||||
|
return dfd.resolve();
|
||||||
|
});
|
||||||
|
return dfd.promise();
|
||||||
|
},
|
||||||
|
|
||||||
|
show: function() {
|
||||||
|
var dfd = $.Deferred();
|
||||||
|
if (this.$el.is(':visible')) {
|
||||||
|
return dfd.resolve();
|
||||||
|
}
|
||||||
|
this.$el.fadeIn('fast', function() {
|
||||||
|
return dfd.resolve();
|
||||||
|
});
|
||||||
|
return dfd.promise();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var ProductListView = BaseView.extend({
|
||||||
|
id: 'productlistview',
|
||||||
|
template: _.template($("#store_index_template").html()),
|
||||||
|
|
||||||
|
initialize: function(options) {
|
||||||
|
BaseView.prototype.initialize.apply(this, arguments);
|
||||||
|
this.collection.bind('reset', this.render.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
this.$el.html(this.template({
|
||||||
|
'products': this.collection.toJSON()
|
||||||
|
}));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var ProductView = BaseView.extend({
|
||||||
|
className: 'productitemview',
|
||||||
|
template: _.template($("#store_item_template").html()),
|
||||||
|
|
||||||
|
initialize: function(options) {
|
||||||
|
BaseView.prototype.initialize.apply(this, [options]);
|
||||||
|
this.itemcollection = options.itemcollection;
|
||||||
|
},
|
||||||
|
|
||||||
|
events: {
|
||||||
|
"keypress .uqf" : "updateOnEnter",
|
||||||
|
"click .uq" : "update"
|
||||||
|
},
|
||||||
|
|
||||||
|
update: function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
return this.itemcollection.updateItemForProduct(this.model, parseInt(this.$('.uqf').val()));
|
||||||
|
},
|
||||||
|
|
||||||
|
updateOnEnter: function(e) {
|
||||||
|
if (e.keyCode === 13) {
|
||||||
|
this.update(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
this.$el.html(this.template(this.model.toJSON()));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var CartWidget = Backbone.View.extend({
|
||||||
|
el: $('.cart-info'),
|
||||||
|
template: _.template($('#store_cart_template').html()),
|
||||||
|
|
||||||
|
initialize: function() {
|
||||||
|
Backbone.View.prototype.initialize.apply(this, arguments);
|
||||||
|
this.collection.bind('update', this.render.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
var tel = this.$el.html(this.template({
|
||||||
|
'count': this.collection.getTotalCount(),
|
||||||
|
'cost': this.collection.getTotalCost()
|
||||||
|
}));
|
||||||
|
tel.animate({ paddingTop: '30px' }).animate({ paddingTop: '10px' });
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var BackboneStore = Backbone.Router.extend({
|
||||||
|
views: {},
|
||||||
|
products: null,
|
||||||
|
cart: null,
|
||||||
|
|
||||||
|
routes: {
|
||||||
|
"": "index",
|
||||||
|
"item/:id": "product"
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize: function(data) {
|
||||||
|
Backbone.Router.prototype.initialize.apply(this, arguments);
|
||||||
|
this.cart = new ItemCollection();
|
||||||
|
new CartWidget({ collection: this.cart });
|
||||||
|
this.products = new ProductCollection([], { url: 'data/items.json' });
|
||||||
|
this.views = {
|
||||||
|
'_index': new ProductListView({ collection: this.products })
|
||||||
|
};
|
||||||
|
$.when(this.products.fetch({ reset: true })).then(function() {
|
||||||
|
return window.location.hash = '';
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
hideAllViews: function() {
|
||||||
|
return _.filter(_.map(this.views, function(v) { return v.hide(); }),
|
||||||
|
function(t) { return t !== null; });
|
||||||
|
},
|
||||||
|
|
||||||
|
index: function() {
|
||||||
|
var view = this.views['_index'];
|
||||||
|
return $.when.apply($, this.hideAllViews()).then(function() {
|
||||||
|
return view.show();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
product: function(id) {
|
||||||
|
var view = this.views[id];
|
||||||
|
if (!view) {
|
||||||
|
var product = this.products.detect(function(p) {
|
||||||
|
return p.get('id') === id;
|
||||||
|
});
|
||||||
|
view = this.views[id] = new ProductView({
|
||||||
|
model: product,
|
||||||
|
itemcollection: this.cart
|
||||||
|
}).render();
|
||||||
|
}
|
||||||
|
return $.when(this.hideAllViews()).then(function() {
|
||||||
|
return view.show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
new BackboneStore();
|
||||||
|
return Backbone.history.start();
|
||||||
|
});
|
||||||
|
|
|
@ -106,10 +106,11 @@ var Product = Backbone.Model.extend({});
|
||||||
var Item = Backbone.Model.extend({
|
var Item = Backbone.Model.extend({
|
||||||
update: function(amount) {
|
update: function(amount) {
|
||||||
if (amount === this.get('quantity')) {
|
if (amount === this.get('quantity')) {
|
||||||
return;
|
return this;
|
||||||
}
|
}
|
||||||
this.set({quantity: amount}, {silent: true});
|
this.set({quantity: amount}, {silent: true});
|
||||||
return this.collection.trigger('update', this);
|
this.collection.trigger('update', this);
|
||||||
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
price: function() {
|
price: function() {
|
||||||
|
@ -295,9 +296,9 @@ be rendered.
|
||||||
As an alternative, the viewport object may already exist, in which case
|
As an alternative, the viewport object may already exist, in which case
|
||||||
you just find it with a selector, and the view attaches itself to that
|
you just find it with a selector, and the view attaches itself to that
|
||||||
DOM object from then on. In older versions of the Backbone Store, we
|
DOM object from then on. In older versions of the Backbone Store, we
|
||||||
used to assign [[@el]] to a jQuery-wrapped version of the element;
|
used to assign [[this.el]] to a jQuery-wrapped version of the element;
|
||||||
that's no longer necessary, as Backbone provides you with its own
|
that's no longer necessary, as Backbone provides you with its own
|
||||||
version automatically in [[@$el]].
|
version automatically in [[this.$el]].
|
||||||
|
|
||||||
The 'parent' field is something I created for my own use, since I intend
|
The 'parent' field is something I created for my own use, since I intend
|
||||||
to have multiple child objects share the same piece of real-estate. The
|
to have multiple child objects share the same piece of real-estate. The
|
||||||
|
@ -319,10 +320,10 @@ Next, we will define the hide and show functions.
|
||||||
<<base view>>=
|
<<base view>>=
|
||||||
hide: function() {
|
hide: function() {
|
||||||
var dfd = $.Deferred();
|
var dfd = $.Deferred();
|
||||||
if (!this.el.is(':visible')) {
|
if (!this.$el.is(':visible')) {
|
||||||
return dfd.resolve();
|
return dfd.resolve();
|
||||||
}
|
}
|
||||||
this.el.fadeOut('fast', function() {
|
this.$el.fadeOut('fast', function() {
|
||||||
return dfd.resolve();
|
return dfd.resolve();
|
||||||
});
|
});
|
||||||
return dfd.promise();
|
return dfd.promise();
|
||||||
|
@ -330,10 +331,10 @@ Next, we will define the hide and show functions.
|
||||||
|
|
||||||
show: function() {
|
show: function() {
|
||||||
var dfd = $.Deferred();
|
var dfd = $.Deferred();
|
||||||
if (this.el.is(':visible')) {
|
if (this.$el.is(':visible')) {
|
||||||
return dfd.resolve();
|
return dfd.resolve();
|
||||||
}
|
}
|
||||||
this.el.fadeIn('fast', function() {
|
this.$el.fadeIn('fast', function() {
|
||||||
return dfd.resolve();
|
return dfd.resolve();
|
||||||
});
|
});
|
||||||
return dfd.promise();
|
return dfd.promise();
|
||||||
|
@ -414,9 +415,9 @@ var ProductListView = BaseView.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
this.el.html(this.template({
|
this.$el.html(this.template({
|
||||||
'products': this.collection.toJSON()
|
'products': this.collection.toJSON()
|
||||||
});
|
}));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -506,7 +507,7 @@ to be just about all of them.
|
||||||
|
|
||||||
<<product detail view>>=
|
<<product detail view>>=
|
||||||
events: {
|
events: {
|
||||||
"keypress .uqf" : "updateOnEnter"
|
"keypress .uqf" : "updateOnEnter",
|
||||||
"click .uq" : "update"
|
"click .uq" : "update"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -527,11 +528,11 @@ cart model, which is where it belongs: \textit{knowledge about items
|
||||||
and each item's relationship to its collection belongs in the
|
and each item's relationship to its collection belongs in the
|
||||||
collection}.
|
collection}.
|
||||||
|
|
||||||
Look closely at the [[update()]] method. The reference [[@\$]] is a
|
Look closely at the [[update()]] method. The reference [[this.$]] is a
|
||||||
special Backbone object that limits selectors to objects inside the
|
special Backbone object that limits selectors to objects inside the
|
||||||
element of the view. Without it, jQuery would have found the first
|
element of the view. Without it, jQuery would have found the first
|
||||||
input field of class 'uqf' in the DOM, not the one for this specific
|
input field of class 'uqf' in the DOM, not the one for this specific
|
||||||
view. [[@\$('.uqf')]] is shorthand for [[$('uqf', @el)]], and helps
|
view. [[this.$('.uqf')]] is shorthand for [[$('uqf', this.el)]], and helps
|
||||||
clarify what it is you're looking for.
|
clarify what it is you're looking for.
|
||||||
|
|
||||||
<<product detail view>>=
|
<<product detail view>>=
|
||||||
|
@ -542,7 +543,7 @@ clarify what it is you're looking for.
|
||||||
|
|
||||||
updateOnEnter: function(e) {
|
updateOnEnter: function(e) {
|
||||||
if (e.keyCode === 13) {
|
if (e.keyCode === 13) {
|
||||||
return this.update(e);
|
this.update(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -552,7 +553,7 @@ The render is straightforward:
|
||||||
|
|
||||||
<<product detail view>>=
|
<<product detail view>>=
|
||||||
render: function() {
|
render: function() {
|
||||||
this.el.html(this.template(this.model.toJSON()));
|
this.$el.html(this.template(this.model.toJSON()));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -622,7 +623,7 @@ template with the new count and cost, and then wiggle it a little to
|
||||||
show that it did changed:
|
show that it did changed:
|
||||||
|
|
||||||
<<cart widget>>=
|
<<cart widget>>=
|
||||||
CartWidget.prototype.render = function() {
|
render: function() {
|
||||||
var tel = this.$el.html(this.template({
|
var tel = this.$el.html(this.template({
|
||||||
'count': this.collection.getTotalCount(),
|
'count': this.collection.getTotalCount(),
|
||||||
'cost': this.collection.getTotalCost()
|
'cost': this.collection.getTotalCost()
|
||||||
|
@ -729,7 +730,7 @@ hidden) or null. The [[_.filter()]] call at the end means that this
|
||||||
method returns only an array of deferreds.
|
method returns only an array of deferreds.
|
||||||
|
|
||||||
<<router>>=
|
<<router>>=
|
||||||
hideAllViews = function() {
|
hideAllViews: function() {
|
||||||
return _.filter(_.map(this.views, function(v) { return v.hide(); }),
|
return _.filter(_.map(this.views, function(v) { return v.hide(); }),
|
||||||
function(t) { return t !== null; });
|
function(t) { return t !== null; });
|
||||||
},
|
},
|
||||||
|
@ -775,7 +776,7 @@ the [[CartWidget]] to update automagically as well.
|
||||||
view = this.views[id] = new ProductView({
|
view = this.views[id] = new ProductView({
|
||||||
model: product,
|
model: product,
|
||||||
itemcollection: this.cart
|
itemcollection: this.cart
|
||||||
}).render()
|
}).render();
|
||||||
}
|
}
|
||||||
return $.when(this.hideAllViews()).then(function() {
|
return $.when(this.hideAllViews()).then(function() {
|
||||||
return view.show();
|
return view.show();
|
||||||
|
@ -802,7 +803,7 @@ Finally, we need to start the program
|
||||||
Here's the entirety of the program. Coffeescript provides its own
|
Here's the entirety of the program. Coffeescript provides its own
|
||||||
namespace wrapper:
|
namespace wrapper:
|
||||||
|
|
||||||
<<store.coffee>>=
|
<<store.js>>=
|
||||||
<<models>>
|
<<models>>
|
||||||
|
|
||||||
<<product collection>>
|
<<product collection>>
|
||||||
|
|
Loading…
Reference in New Issue