Compare commits

..

No commits in common. "fe598fc1327ef0155eb31361dd447f5368e35291" and "e078b83455ce1dc7f625bd14ca77ee98bbfd869b" have entirely different histories.

10 changed files with 340 additions and 451 deletions

View File

@ -1,39 +1,223 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>KO Shopping Cart</title> <title>KO Shopping Cart</title>
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css" /> <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css" />
</head> </head>
<body> <body>
<div class="container-fluid"> <div class="container-fluid">
<div class="row" data-bind="if: visibleCatalog"> <div class="row" id="catalogContainer">
<div <div class="col-xs-12" data-bind="template:{name:'header'}"></div>
class="col-xs-12" <div class="col-xs-6" data-bind="template:{name:'catalog'}"></div>
data-bind="template:{name:'header'}" <div id="cartContainer" class="col-xs-6 well hidden" data-bind="template:{name:'cart'}"></div>
></div> </div>
<div <div class="row hidden" id="orderContainer" data-bind="template:{name:'order'}"></div>
class="col-xs-6" <div data-bind="template: {name:'add-to-catalog-modal'}"></div>
data-bind="template:{name:'catalog'}" <div data-bind="template: {name:'finish-order-modal'}"></div>
></div> </div>
<div class="col-xs-6 well hidden" data-bind="if: visibleCart">
<div class="well" data-bind="template:{name:'cart'}"></div>
</div>
</div>
<div class="row" data-bind="if: visibleCart">
<div data-bind="template:{name:'order'}"></div>
</div>
<div data-bind="template: {name:'add-to-catalog-modal'}"></div>
<div data-bind="template: {name:'finish-order-modal'}"></div>
</div>
<!-- vendor library --> <!-- templates -->
<script type="text/javascript" src="js/jquery-2.1.1.min.js"></script> <script type="text/html" id="header">
<script type="text/javascript" src="js/bootstrap.js"></script> <h1>Catalog</h1>
<script type="text/javascript" src="js/knockout-3.2.0.js"></script>
<!-- app --> <button
<script type="text/javascript" src="js/models/Product.js"></script> class="btn btn-primary btn-sm"
<script type="text/javascript" src="js/models/CartProduct.js"></script> data-toggle="modal"
<script type="text/javascript" src="js/viewmodel.js"></script> data-target="#addToCatalogModal"
</body> >
Add New Product
</button>
<button
class="btn btn-primary btn-sm"
data-bind="click: showCartDetails, css:{ disabled: cart().length < 1}"
>
Show Cart Details
</button>
<hr />
</script>
<script type="text/html" id="catalog">
<div class="input-group">
<span class="input-group-addon">
<i class="glyphicon glyphicon-search"></i> Search
</span>
<input type="text" class="form-control" data-bind="textInput:searchTerm">
</div>
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Price</th>
<th>Stock</th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach:catalog">
<tr data-bind="style:lineColor">
<td data-bind="text:name"></td>
<td data-bind="text:price"></td>
<td data-bind="text:stock"></td>
<td>
<button class="btn btn-primary" data-bind="click:$parent.addToCart">
<i class="glyphicon glyphicon-plus-sign"></i> Add
</button>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3">
<strong>Items:</strong><span data-bind="text:catalog().length"></span>
</td>
<td colspan="1">
<span data-bind="template:{name: 'cart-widget'}"></span>
</td>
</tr>
</tfoot>
</table>
</script>
<script type="text/html" id="add-to-catalog-modal">
<div class="modal fade" id="addToCatalogModal">
<div class="modal-dialog">
<div class="modal-content">
<form class="form-horizontal" role="form" data-bind="with:newProduct">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">&times;</span>
<span class="sr-only">Close</span>
</button>
<h3>Add New Product to the Catalog</h3>
</div>
<div class="modal-body">
<div class="form-group">
<div class="col-sm-12">
<input type="text" class="form-control" placeholder="Name" data-bind="textInput:name">
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<input type="text" class="form-control" placeholder="Price" data-bind="textInput:price">
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<input type="text" class="form-control" placeholder="Stock" data-bind="textInput:stock">
</div>
</div>
</div>
<div class="modal-footer">
<div class="form-group">
<div class="col-sm-12">
<button type="submit" class="btn btn-default" data-bind="{click:$parent.addProduct}">
<i class="glyphicon glyphicon-plus-sign"></i> Add Product
</button>
</div>
</div>
</div>
</form>
</div> <!-- /.modal-content -->
</div> <!-- /.modal-diaglog -->
</div> <!-- /.modal -->
</script>
<script type="text/html" id="cart-widget">
Total Items: <span data-bind="text:totalItems"></span>
Price: <span data-bind="text:grandTotal"></span>
</script>
<script type="text/html" id="cart-item">
<div class="list-group-item" style="overflow: hidden">
<button type="button" class="close pull-right" data-bind="click:$root.removeFromCart">
<span>&times;</span>
</button>
<h4 class="" data-bind="text:product.name"></h4>
<div class="input-group cart-unit">
<input type="text" class="form-control" data-bind="textInput:units" readonly/>
<span class="input-group-addon">
<div class="btn-group-vertical">
<button class="btn btn-default btn-xs" data-bind="click:addUnit">
<i class="glyphicon glyphicon-chevron-up"></i>
</button>
<button class="btn btn-default btn-xs" data-bind="click:removeUnit">
<i class="glyphicon glyphicon-chevron-down"></i>
</button>
</div>
</span>
</div>
</div>
</script>
<script type="text/html" id="cart">
<button type="button" class="close pull-right" data-bind="click:hideCartDetails">
<span>&times;</span>
</button>
<h1>Cart</h1>
<div data-bind="template: {name: 'cart-item', foreach:cart}" class="list-group"></div>
<div data-bind="template: {name: 'cart-widget'}"></div>
<button class="btn btn-primary btn-sm" data-binid="click:showOrder">
Confirm Order
</button>
</script>
<script type="text/html" id="order">
<div class="col-xs-12">
<button class="btn btn-sm btn-primary" data-bind="click:showCatalog">
Back to catalog
</button>
<button class="btn btn-sm btn-primary" data-bind="click:finishOrder">
Buy & finish
</button>
</div>
<div class="col-xs-6">
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Price</th>
<th>Units</th>
<th>Subtotal</th>
</tr>
</thead>
<tbody data-bind="foreach:cart">
<tr>
<td data-bind="text:product.name"></td>
<td data-bind="text:product.price"></td>
<td data-bind="text:units"></td>
<td data-bind="text:subtotal"></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3"></td>
<td>
Total: <span data-bind="text:grandTotal"></span>
</td>
</tr>
</tfoot>
</table>
</div>
</script>
<script type="text/html" id="finish-order-modal">
<div class="modal fade" id="finishOrderModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
<h2>Your order has been completed!</h2>
</div>
<div class="modal-footer">
<div class="form-group">
<div class="col-sm-12">
<button type="submit" class="btn btn-success" data-dismiss="modal">Continue Shopping</button>
</div>
</div>
</div>
</div>
</div>
</div>
</script>
<!-- vendor library -->
<script type="text/javascript" src="js/jquery-2.1.1.min.js"></script>
<script type="text/javascript" src="js/bootstrap.js"></script>
<script type="text/javascript" src="js/knockout-3.2.0.js"></script>
<!-- app -->
<script type="text/javascript" src="js/models/Product.js"></script>
<script type="text/javascript" src="js/models/CartProduct.js"></script>
<script type="text/javascript" src="js/viewmodel.js"></script>
</body>
</html> </html>

View File

@ -1,169 +1,134 @@
"use strict";
var vm = (function () { var vm = (function () {
"use strict"; var catalog = ko.observableArray([
Product(1, "T-Shirt", 10.0, 20),
Product(2, "Trousers", 20.0, 10),
Product(3, "Shirt", 15.0, 20),
Product(4, "Shorts", 5.0, 10),
]);
var visibleCatalog = ko.observable(true); var newProduct = Product("", "", "", "");
var visibleCart = ko.observable(false); var clearNewProduct = function () {
newProduct.name("");
newProduct.price("");
newProduct.stock("");
};
var catalog = ko.observableArray([ var addProduct = function (context) {
Product(1, "T-Shirt", 10.0, 20), var id = new Date().valueOf(); // random id from time
Product(2, "Trousers", 20.0, 10),
Product(3, "Shirt", 15.0, 20),
Product(4, "Shorts", 5.0, 10),
]);
var newProduct = Product("", "", "", ""); var product = Product(id, context.name(), context.price(), context.stock());
var clearNewProduct = function () { catalog.push(product);
newProduct.name(""); clearNewProduct();
newProduct.price(""); };
newProduct.stock("");
};
var addProduct = function (context) { var searchTerm = ko.observable("");
var id = new Date().valueOf(); // random id from time var filteredCatalog = ko.computed(function () {
// if catalog is empty return empty array
var product = Product( if (!catalog()) {
id, return [];
context.name(), }
context.price(), var filter = searchTerm().toLowerCase();
context.stock() // if filter is empty return all the catalog
); if (!filter) {
catalog.push(product); return catalog();
clearNewProduct(); }
$('#addToCatalogModal').modal('hide'); //filter data
var filtered = ko.utils.arrayFilter(catalog(), function (item) {
}; var strProp = ko.unwrap(item["name"]).toLocaleLowerCase();
return (strProp.indexOf(filter) > -1);
var searchTerm = ko.observable("");
var filteredCatalog = ko.computed(function () {
// if catalog is empty return empty array
if (!catalog()) {
return [];
}
var filter = searchTerm().toLowerCase();
// if filter is empty return all the catalog
if (!filter) {
return catalog();
}
//filter data
var filtered = ko.utils.arrayFilter(catalog(), function (item) {
var strProp = ko.unwrap(item["name"]).toLocaleLowerCase();
return strProp.indexOf(filter) > -1;
});
return filtered;
}); });
return filtered;
var cart = ko.observableArray([]); });
var showCartDetails = function () {
if (cart().length > 0) { var cart = ko.observableArray([]);
visibleCart(true); var showCartDetails = function () {
} if (cart().length > 0) {
}; $("#cartContainer").removeClass("hidden");
var addToCart = function (data) { }
var item = null; };
var tmpCart = cart(); var addToCart = function(data) {
var n = tmpCart.length; var item = null;
while (n--) { var tmpCart = cart();
if (tmpCart[n].product.id() === data.id()) { var n = tmpCart.length;
item = tmpCart[n]; while(n--) {
} if (tmpCart[n].product.id() === data.id()) {
} item = tmpCart[n];
if (item) { }
item.addUnit(); }
} else { if (item) {
item = new CartProduct(data, 0); item.addUnit();
item.addUnit(); } else {
tmpCart.push(item); item = new CartProduct(data, 0);
} item.addUnit();
cart(tmpCart); tmpCart.push(item);
}; }
cart(tmpCart);
// The cart-widget template };
var totalItems = ko.computed(function () {
var tmpCart = cart(); // The cart-widget template
var total = 0; var totalItems = ko.computed(function() {
tmpCart.forEach(function (item) { var tmpCart = cart();
total += parseInt(item.units(), 10); var total = 0;
}); tmpCart.forEach(function(item) {
return total; total += parseInt(item.units(), 10);
}); });
var grandTotal = ko.computed(function () { return total;
var tmpCart = cart(); })
var total = 0; var grandTotal = ko.computed(function() {
tmpCart.forEach(function (item) { var tmpCart = cart();
total += item.units() * item.product.price(); var total = 0;
}); tmpCart.forEach(function(item) {
return total; total += (item.units() * item.product.price());
}); });
return total;
})
// The cart-item template // The cart-item template
var removeFromCart = function (data) { var removeFromCart = function (data) {
var units = data.units(); var units = data.units();
var stock = data.product.stock(); var stock = data.product.stock();
data.product.stock(units + stock); data.product.stock(units + stock);
cart.remove(data); cart.remove(data);
}; }
// The cart template // The cart template
var hideCartDetails = function () { var hideCartDetails = function() {
visibleCart(false); $('#cartContainer').addClass("hidden");
}; };
var showOrder = function () { var showOrder = function () {
visibleCatalog(false); $('#catalogContainer').addClass("hidden");
}; $('#orderContainer').removeClass("hidden");
}
// The order template // The order template
var showCatalog = function () { var showCatalog = function () {
visibleCatalog(true); $("#catalogContainer").removeClass("hidden");
}; $("$orderContainer").addClass("hidden");
var finishOrder = function () { };
cart([]); var finishOrder = function() {
hideCartDetails(); cart([]);
showCatalog(); hideCartDetails();
$("#finishOrderModal").modal("show"); showCatalog();
}; $("#finishOrderModal").modal('show');
}
return {
return { // first chapter
// first chapter searchTerm: searchTerm,
searchTerm: searchTerm, catalog: filteredCatalog,
catalog: filteredCatalog, newProduct: newProduct,
newProduct: newProduct, addProduct: addProduct,
addProduct: addProduct, // second chapter
// second chapter cart: cart,
cart: cart, showCartDetails: showCartDetails,
showCartDetails: showCartDetails, totalItems: totalItems,
addToCart: addToCart, grandTotal: grandTotal,
totalItems: totalItems, removeFromCart: removeFromCart,
grandTotal: grandTotal, hideCartDetails: hideCartDetails,
removeFromCart: removeFromCart, showOrder: showOrder,
hideCartDetails: hideCartDetails, showCatalog: showCatalog,
showOrder: showOrder, finishOrder: finishOrder
showCatalog: showCatalog, };
finishOrder: finishOrder,
visibleCatalog: visibleCatalog,
visibleCart: visibleCart,
};
})(); })();
ko.applyBindings(vm);
var templates = [
"header",
"catalog",
"cart",
"cart-item",
"cart-widget",
"order",
"add-to-catalog-modal",
"finish-order-modal",
];
var busy = templates.length;
templates.forEach(function (tpl) {
"use strict";
$.get("views/" + tpl + ".html").then(function (data) {
$("body").append(data);
busy--;
if (!busy) {
ko.applyBindings(vm);
}
});
});

View File

@ -1,76 +0,0 @@
<script type="text/html" id="add-to-catalog-modal">
<div class="modal fade" id="addToCatalogModal">
<div class="modal-dialog">
<div class="modal-content">
<form
class="form-horizontal"
role="form"
data-bind="with:newProduct"
>
<div class="modal-header">
<button
type="button"
class="close"
data-dismiss="modal"
>
<span aria-hidden="true">&times;</span>
<span class="sr-only">Close</span>
</button>
<h3>Add New Product to the Catalog</h3>
</div>
<div class="modal-body">
<div class="form-group">
<div class="col-sm-12">
<input
type="text"
class="form-control"
placeholder="Name"
data-bind="textInput:name"
/>
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<input
type="text"
class="form-control"
placeholder="Price"
data-bind="textInput:price"
/>
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<input
type="text"
class="form-control"
placeholder="Stock"
data-bind="textInput:stock"
/>
</div>
</div>
</div>
<div class="modal-footer">
<div class="form-group">
<div class="col-sm-12">
<button
type="submit"
class="btn btn-default"
data-bind="{click:$parent.addProduct}"
>
<i
class="glyphicon glyphicon-plus-sign"
></i>
Add Product
</button>
</div>
</div>
</div>
</form>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-diaglog -->
</div>
<!-- /.modal -->
</script>

View File

@ -1,36 +0,0 @@
<script type="text/html" id="cart-item">
<div class="list-group-item" style="overflow: hidden">
<button
type="button"
class="close pull-right"
data-bind="click:$root.removeFromCart"
>
<span>&times;</span>
</button>
<h4 class="" data-bind="text:product.name"></h4>
<div class="input-group cart-unit">
<input
type="text"
class="form-control"
data-bind="textInput:units"
readonly
/>
<span class="input-group-addon">
<div class="btn-group-vertical">
<button
class="btn btn-default btn-xs"
data-bind="click:addUnit"
>
<i class="glyphicon glyphicon-chevron-up"></i>
</button>
<button
class="btn btn-default btn-xs"
data-bind="click:removeUnit"
>
<i class="glyphicon glyphicon-chevron-down"></i>
</button>
</div>
</span>
</div>
</div>
</script>

View File

@ -1,4 +0,0 @@
<script type="text/html" id="cart-widget">
Total Items: <span data-bind="text:totalItems"></span> Price:
<span data-bind="text:grandTotal"></span>
</script>

View File

@ -1,18 +0,0 @@
<script type="text/html" id="cart">
<button
type="button"
class="close pull-right"
data-bind="click:hideCartDetails"
>
<span>&times;</span>
</button>
<h1>Cart</h1>
<div
data-bind="template: {name: 'cart-item', foreach:cart}"
class="list-group"
></div>
<div data-bind="template: {name: 'cart-widget'}"></div>
<button class="btn btn-primary btn-sm" data-bind="click:showOrder">
Confirm Order
</button>
</script>

View File

@ -1,48 +0,0 @@
<script type="text/html" id="catalog">
<div class="input-group">
<span class="input-group-addon">
<i class="glyphicon glyphicon-search"></i> Search
</span>
<input
type="text"
class="form-control"
data-bind="textInput:searchTerm"
/>
</div>
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Price</th>
<th>Stock</th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach:catalog">
<tr data-bind="style:lineColor">
<td data-bind="text:name"></td>
<td data-bind="text:price"></td>
<td data-bind="text:stock"></td>
<td>
<button
class="btn btn-primary"
data-bind="click:$parent.addToCart"
>
<i class="glyphicon glyphicon-plus-sign"></i> Add
</button>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3">
<strong>Items:</strong
><span data-bind="text:catalog().length"></span>
</td>
<td colspan="1">
<span data-bind="template:{name: 'cart-widget'}"></span>
</td>
</tr>
</tfoot>
</table>
</script>

View File

@ -1,24 +0,0 @@
<script type="text/html" id="finish-order-modal">
<div class="modal fade" id="finishOrderModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
<h2>Your order has been completed!</h2>
</div>
<div class="modal-footer">
<div class="form-group">
<div class="col-sm-12">
<button
type="submit"
class="btn btn-success"
data-dismiss="modal"
>
Continue Shopping
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</script>

View File

@ -1,18 +0,0 @@
<script type="text/html" id="header">
<h1>Catalog</h1>
<button
class="btn btn-primary btn-sm"
data-toggle="modal"
data-target="#addToCatalogModal"
>
Add New Product
</button>
<button
class="btn btn-primary btn-sm"
data-bind="click: showCartDetails, css:{ disabled: cart().length < 1}"
>
Show Cart Details
</button>
<hr />
</script>

View File

@ -1,36 +0,0 @@
<script type="text/html" id="order">
<div class="col-xs-12">
<button class="btn btn-sm btn-primary" data-bind="click:showCatalog">
Back to catalog
</button>
<button class="btn btn-sm btn-primary" data-bind="click:finishOrder">
Buy & finish
</button>
</div>
<div class="col-xs-6">
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Price</th>
<th>Units</th>
<th>Subtotal</th>
</tr>
</thead>
<tbody data-bind="foreach:cart">
<tr>
<td data-bind="text:product.name"></td>
<td data-bind="text:product.price"></td>
<td data-bind="text:units"></td>
<td data-bind="text:subtotal"></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3"></td>
<td>Total: <span data-bind="text:grandTotal"></span></td>
</tr>
</tfoot>
</table>
</div>
</script>