can
Version:
MIT-licensed, client-side, JavaScript framework that makes building rich web applications easy.
296 lines (275 loc) • 6.01 kB
HTML
<body>
<style>
* {
font: 13px/16px "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
color: #333;
}
table {
margin: 5px auto;
margin-bottom: 15px;
width: 95%;
}
td {
border-top: 1px solid #eee;
padding: 5px;
}
tr:last-child {
border-bottom: 1px solid #eee;
}
tr:nth-child(odd) {
background-color: #fcfcf1;
}
thead th {
background-color: #ccc;
color: #666;
padding: 5px;
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
}
next-prev { margin: 5px auto;text-align: center;display: block; }
next-prev a {
border-radius: 3px;
padding: 4px 14px;
text-decoration: none;
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
background-color: #f5f5f5;
border: 1px solid #bbbbbb;
border-color: #e6e6e6 #e6e6e6 #bfbfbf;
}
next-prev a.enabled {
color: #ffffff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
background-color: #49afcd;
border-color: #2f96b4 #2f96b4 #1f6377;
}
page-count {
display: block;
}
page-count, page-count * {
font-size: 11px;
color: #ccc;
text-align: center;
}
.waiting {
opacity: 0.5;
}
</style>
<div id='out'></div>
<script id="app-stache" type='text/stache'>
<my-app>
<my-grid {promise-data}='websitesPromise'>
{{#each items}}
<tr>
<td width='40%'>{{name}}</td>
<td width='70%'>{{url}}</td>
</tr>
{{/each}}
</my-grid>
<next-prev {paginate}='paginate'></next-prev>
<page-count {page}='paginate.page' {count}='paginate.pageCount'></page-count>
</my-app>
</script>
<script src="../../node_modules/steal/steal.js" main="@empty">
var DefineMap = require("can-define/map/map");
var DefineList = require("can-define/list/list");
var Component = require("can-component");
var fixture = require("can-fixture");
var stache = require("can-stache");
var superMap = require("can-connect/can/super-map/super-map");
var set = require("can-set");
var compute = require("can-compute");
window.can = require("can-util/namespace");
var Website = DefineMap.extend({
id: "number",
name: "string",
url: "string"
});
Website.List = DefineList.extend({
"#": Website,
count: "number"
});
var websiteAlgebra = new set.Algebra(
set.props.offsetLimit("offset", "limit")
);
superMap({
idProp: "id",
Map: Website,
List: Website.List,
url: "/websites",
name: "website",
algebra: websiteAlgebra
});
var websiteStore = fixture.store([{
id: 1,
name: "CanJS",
url: "http://canjs.us"
}, {
id: 2,
name: "jQuery++",
url: "http://jquerypp.com"
}, {
id: 3,
name: "JavaScriptMVC",
url: "http://javascriptmvc.com"
}, {
id: 4,
name: "Bitovi",
url: "http://bitovi.com"
}, {
id: 5,
name: "FuncUnit",
url: "http://funcunit.com"
}, {
id: 6,
name: "StealJS",
url: "http://stealjs.com"
}, {
id: 7,
name: "jQuery",
url: "http://jquery.com"
}, {
id: 8,
name: "Mootools",
url: "http://mootools.com"
}, {
id: 9,
name: "Dojo",
url: "http://dojo.com"
}, {
id: 10,
name: "YUI",
url: "http://yui.com"
}, {
id: 11,
name: "DoneJS",
url: "http://donejs.com"
}, {
id: 12,
name: "Mindjet Connect",
url: "http://connect.mindjet.com"
}, {
id: 13,
name: "JSFiddle",
url: "http://jsfiddle.net"
}, {
id: 14,
name: "Zepto",
url: "http://zepto.com"
}, {
id: 15,
name: "Spill",
url: "http://spill.com"
}, {
id: 16,
name: "Github",
url: "http://github.com"
}], websiteAlgebra);
fixture("/websites/{id}", websiteStore);
fixture.delay = 2000;
var Paginate = DefineMap.extend({
count: {
value: Infinity,
get: function(lastSetCount) {
return lastSetCount && lastSetCount.isComputed ? lastSetCount() : lastSetCount;
}
},
offset: {
value: 0,
set: function(newOffset) {
return newOffset < 0 ?
0 :
Math.min(newOffset, !isNaN(this.count - 1) ?
this.count - 1 :
Infinity);
}
},
limit: {
value: 5
},
page: {
get: function() {
return Math.floor(this.offset / this.limit) + 1;
},
set: function(newVal) {
this.offset = (parseInt(newVal, 10) - 1) * this.limit;
}
},
pageCount: {
get: function() {
return this.count ?
Math.ceil(this.count / this.limit) : null;
}
},
next: function() {
this.offset = this.offset + this.limit;
},
prev: function() {
this.offset = this.offset - this.limit;
},
canNext: function() {
return this.offset < this.count - this.limit;
},
canPrev: function() {
return this.offset > 0;
}
});
var AppViewModel = DefineMap.extend({
paginate: {
value: function() {
return new Paginate({
limit: 5,
count: compute(this, "websitesPromise.value.count")
});
}
},
websitesPromise: {
get: function() {
return Website.getList({
limit: this.paginate.limit,
offset: this.paginate.offset
});
}
}
});
Component.extend({
tag: "my-app",
ViewModel: AppViewModel,
leakScope: true
});
var GridViewModel = DefineMap.extend({
promiseData: "*",
items: {
get: function(lastSet, resolve) {
this.promiseData.then(resolve);
}
},
waiting: {
get: function(lastSet, resolve) {
var promise = this.promiseData;
promise.then(function() {
resolve(false);
});
return true;
}
}
});
Component.extend({
tag: "my-grid",
template: stache("<table><tbody {{#waiting}}class='waiting'{{/waiting}}><content></content></tbody></table>"),
ViewModel: GridViewModel,
leakScope: true
});
Component.extend({
tag: "next-prev",
template: stache('<a href="javascript://"' +
'class="prev {{#paginate.canPrev}}enabled{{/paginate.canPrev}}" ($click)="paginate.prev()">Prev</a>' +
'<a href="javascript://"' +
'class="next {{#paginate.canNext}}enabled{{/paginate.canNext}}" ($click)="paginate.next()">Next</a>')
});
Component.extend({
tag: "page-count",
template: stache('Page <span>{{page}}</span> of <span>{{count}}</span>.')
});
var template = stache(document.getElementById("app-stache").innerHTML);
document.getElementById("out").appendChild(template({}));
</script>
</body>