<!DOCTYPE html> <html> <head> <link href="//cdn.jsdelivr.net/picnicss/4.1.1/picnic.min.css" rel="stylesheet"> <link rel="stylesheet" href="style.css"> <meta charset="utf-8"> <title>Mag.JS</title> </head> <body> <nav> <h1>Hello Mag.JS!</h1> <a target="_tab" href="https://github.com/magnumjs/mag.js">GitHub</a> </nav> <article class="card"> <header> <h2>Multiple Modules</h2> </header> <footer> <div id="app"> <label> <input type="checkbox" name="product"> <span class="toggle button">Product Table</span> </label> <label> <input type="checkbox" name="invoice"> <span class="toggle button">Invoice Form</span> </label> <Invoices></Invoices> <Products></Products> </div> <div class="templates hide"> <div class="ProductRow"> <div class="row"> <div class="row-cell name">NAME</div> <div class="row-cell price">PRICE</div> </div> </div> <div class="ProductCategoryRow"> <div class="row row-header"> <category></category> </div> </div> <div class="ProductTable"> <div class="row header row-header"> <div>Name <i></i></div> </div> <div class="row rows"></div> </div> <div id="InvoiceForm"> <form class="commentForm"> <input name="category" type="text" placeholder="The category" /> <input name="name" type="text" placeholder="Product name" /> <input name="price" type="text" placeholder="Price" /> <input type="submit" value="Post" /> </form> </div> </div> </footer> </article> <script src="//rawgit.com/magnumjs/mag.js/master/mag-latest.min.js"></script> <script src="//rawgit.com/magnumjs/mag.js/master/dist/mag.addons.0.22.min.js"></script> <script src="dataservice.js"></script> <script src="invoiceform.js"></script> <script src="products.js"></script> <script src="producttable.js"></script> <script src="app.js"></script> </body> </html>
var app = {}
app.onHeaderClick = function(name) {
var headers = this.props.products.getHeaders()
var data = this.props.products.getData()
headers.forEach(function(header) {
if (header.name == name) {
header.selected = header.selected == "^" ? "v" : "^"
} else {
header.selected = ""
}
})
var first = data[0],
prop = name.toLowerCase()
data.sort(function(a, b) {
return a[prop] > b[prop] ? 1 : a[prop] < b[prop] ? -1 : 0
})
if (first === data[0]) data.reverse()
}
app.controller = function(props) {
this.product = {};
this.invoice = {};
this.items = props.products.getData();
}
app.view = function(state, props) {
state.Products = state.product._checked ? ProductTable({
products: state.items,
headers: props.products.getHeaders(),
onHeaderClick: this.onHeaderClick
}) : null;
state.Invoices = state.invoice._checked ? InvoiceForm({
products: props.products,
onCommentSubmit: ()=>{
state.items = props.products.getData()
}
}) : null;
}
dataService.setData(PRODUCTS)
dataService.setHeaders(HEADERS);
var props = {
products: dataService
}
mag.module("app", app, props)
li:empty,
.hide {
display: none;
}
a {
display: block;
}
a:after {
content: " \bb";
}
.mainButton {
font-size: 1.5em;
}
nav a {
float: right;
margin-top: -50px;
}
body {
background: #fff;
text-align: left;
width: 90%;
max-width: 960px;
margin: 0 auto;
padding: 20px 0 0;
}
nav {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 3em;
padding: 0 .6em;
background: #fff;
box-shadow: 0 0 0.2em rgba(17, 17, 17, 0.2);
z-index: 10000;
transition: all .3s;
transform-style: preserve-3d;
}
header {
font-weight: bold;
position: relative;
border-bottom: 1px solid #eee;
padding: .6em .8em;
}
footer {
padding: .8em;
}
article {
top: 100px;
}
.card {
max-width: 100%;
display: block;
position: relative;
box-shadow: 0;
border-radius: .2em;
border: 1px solid #ccc;
overflow: hidden;
text-align: left;
background: #fff;
margin-bottom: .6em;
padding: 6px;
transition: all .3s ease;
}
/* table */
.row-header {
text-align: left;
font-weight: 900;
color: #fff;
background-color: #0074d9;
}
.row-title {
font-weight: bold
}
.row {
width: calc(100% + 2 * 0.6em);
display: table;
table-layout: fixed;
padding-left: 4px;
}
.row.outofstock .name {
color: red;
}
.row:nth-child(even) {
background: rgba(0, 0, 0, 0.05);
}
.row-header div,
.row-cell {
float: left;
width: 50%;
}
.header div {
cursor: pointer;
}
.header div i {
vertical-align:super;
font-size:10px;
}
#Mag.JS
## plunk boilerplate of "Things"
Basic Mag.JS boilerplate to count and create a list of things dynamically.
var ProductTable = mag('ProductTable', ({products, headers, onHeaderClick})=>{
var lastCategory = null, rows=[], header={div:[]};
if (products) {
header.div = headers.map(function(head){
return {i: head.selected, _text: head.name, _onClick: ()=>onHeaderClick(head.name)}
})
products.forEach(function(product, i) {
if (product.category !== lastCategory) {
rows.push(ProductCategoryRow({
category: product.category,
key: product.category + i
}));
}
rows.push(ProductRow({
product: product,
key: product.name
}));
lastCategory = product.category;
});
}
return {rows, header};
});
var ProductCategoryRow = mag('ProductCategoryRow', ({category})=>({category: category}))
var ProductRow = mag('ProductRow', (props)=>{
var name = props.product.stocked ?
props.product.name : {
_style: 'color: red',
_text: props.product.name
};
var price = props.product.price;
return {name, price};
}, {product: {}})
var PRODUCTS = [
{category: 'Sporting Goods', price: '$49.99', stocked: true, name: 'Football'},
{category: 'Sporting Goods', price: '$9.99', stocked: true, name: 'Baseball'},
{category: 'Sporting Goods', price: '$29.99', stocked: false, name: 'Basketball'},
{category: 'Electronics', price: '$99.99', stocked: true, name: 'iPod Touch'},
{category: 'Electronics', price: '$399.99', stocked: false, name: 'iPhone 5'},
{category: 'Electronics', price: '$199.99', stocked: true, name: 'Nexus 7'}
];
var HEADERS = [{name: "Name", selected: ""},{name: "Price", selected: ""}];
var InvoiceForm = mag("InvoiceForm", {
handleCommentSubmit: function(comment) {
setTimeout(() => {
var comments = this.state.data.getData();
// Optimistically set an id on the new comment. It will be replaced by an
// id generated by the server. In a production application you would likely
// not use Date.now() for this and would have a more robust system in place.
comment.id = Date.now();
var newComments = comments.concat([comment]);
this.state.data.setData(newComments);
this.props.onCommentSubmit()
}, 450)
},
controller: function(props){
this.data = props.products;
},
view: function(state, props) {
state.form = {
_onSubmit: function(e) {
e.preventDefault();
if (!state.category || !state.name || !state.price) {
return;
}
var data = {
category: state.category,
price: state.price,
stocked: true,
name: state.name
};
this.handleCommentSubmit(data);
state.category = '';
state.price = '';
state.name = '';
}
}
}
})
var dataService= {data:[], headers: []};
dataService.getData = function(){
return this.data;
}
dataService.setData =function(data){
this.data=data;
}
dataService.getHeaders = function(){
return this.headers;
}
dataService.setHeaders =function(headers){
this.headers=headers;
}