Skip to content

Instantly share code, notes, and snippets.

@imjoshdean
Last active December 26, 2015 13:19
Show Gist options
  • Save imjoshdean/7157939 to your computer and use it in GitHub Desktop.
Save imjoshdean/7157939 to your computer and use it in GitHub Desktop.
* {
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;
}
<div id='out'></div>
<script id="appMustache" type='text/mustache'>
<app>
<grid deferredData='websitesDeferred'>
{{#each items}}
<tr>
<td width='40%'>{{name}}</td>
<td width='70%'>{{url}}</td>
</tr>
{{/each}}
</grid>
<next-prev paginate='paginate'></next-prev>
<page-count page='paginate.page' count='paginate.pageCount'></page-count>
</app>
</script>
$(function() {
var Website = can.Model.extend({
findAll: "/websites"
}, {});
var websites = [{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"}];
can.fixture("/websites", function (request) {
var start = request.data.offset || 0
end = start + (request.data.limit || websites.length);
return {
count: websites.length,
data: websites.slice(start, end)
}
});
var Paginate = can.Map.extend({
count: Infinity,
offset: 0,
limit: 5,
next: function () {
this.attr('offset', this.offset + this.limit);
},
prev: function () {
this.attr('offset', this.offset - this.limit)
},
setOffset: function (newOffset) {
return newOffset < 0 ?
0 :
Math.min(newOffset, !isNaN(this.count - 1) ?
this.count - 1 :
Infinity)
},
setCount: function (newCount, success, error) {
return newCount < 0 ? 0 : newCount;
},
canNext: function () {
return this.attr('offset') < this.attr('count') -
this.attr('limit');
},
canPrev: function () {
return this.attr('offset') > 0;
},
page: function (newVal) {
if (newVal === undefined) {
return Math.floor(this.attr('offset') / this.attr('limit')) + 1;
} else {
this.attr('offset', (parseInt(newVal) - 1) * this.attr('limit'));
}
},
pageCount: function () {
return this.attr('count') ?
Math.ceil(this.attr('count') / this.attr('limit')) : null;
}
});
can.Component.extend({
tag: "app",
scope: function () {
return {
paginate: new Paginate({
limit: 5
}),
websitesDeferred: can.compute(function () {
var params = {
limit: this.attr('paginate.limit'),
offset: this.attr('paginate.offset')
},
websitesDeferred = Website.findAll(params),
self = this;
websitesDeferred.then(function (websites) {
self.attr('paginate.count', websites.count)
});
return websitesDeferred;
})
}
}
});
can.Component.extend({
tag: "grid",
scope: {
items: [],
waiting: true
},
template: "<table><tbody><content></content></tbody></table>",
events: {
init: function () {
this.update()
},
"{deferreddata} change": "update",
update: function () {
var deferred = this.scope.attr('deferreddata'),
scope = this.scope,
el = this.element;
if (can.isDeferred(deferred)) {
this.scope.attr("waiting", true);
this.element.find('tbody').css('opacity', 0.5)
deferred.then(function (items) {
scope.attr('items').replace(items)
});
} else {
scope.attr('items').attr(deferred, true)
}
},
"{items} change": function () {
this.scope.attr("waiting", false);
this.element.find('tbody').css('opacity', 1);
}
}
});
can.Component.extend({
tag: "next-prev",
template:
'<a href="javascript://"' +
'class="prev {{#paginate.canPrev}}enabled{{/paginate.canPrev}}" can-click="paginate.prev">Prev</a>' +
'<a href="javascript://"' +
'class="next {{#paginate.canNext}}enabled{{/paginate.canNext}}" can-click="paginate.next">Next</a>'
})
can.Component.extend({
tag: "page-count",
template: 'Page <span>{{page}}</span> of <span>{{count}}</span>.'
})
$("#out").html(can.view("appMustache", {}))
})
name: can.Component Pagination Example
description: Creating a paged widget with can.Component
authors:
- Justin Meyer
resources:
- http://canjs.com/release/2.0.0/can.jquery.js
- http://canjs.com/release/2.0.0/can.map.setter.js
- http://canjs.com/release/2.0.0/can.fixture.js
- http://canjs.com/release/2.0.0/can.object.js
normalize_css: no
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment