CanJS jQuery Template

Includes jQuery, CanJS and all of its plugins. Use it as a starting point when you want to demo something.

HTML

<script src="http://canjs.us/release/latest/can.jquery.js"></script>
<script src="http://canjs.us/release/latest/can.construct.proxy.js"></script>
<script src="http://canjs.us/release/latest/can.control.plugin.js"></script>
<script src="http://canjs.us/release/latest/can.observe.attributes.js"></script>
<script src="http://canjs.us/release/latest/can.observe.backup.js"></script>
<script src="http://canjs.us/release/latest/can.observe.delegate.js"></script>
<script src="http://canjs.us/release/latest/can.observe.setter.js"></script>
<script src="http://canjs.us/release/latest/can.observe.validations.js"></script>
<script src="http://canjs.us/release/latest/can.view.modifiers.js"></script>
<script src="http://canjs.us/release/latest/can.fixture.js"></script>
<script src="http://canjs.us/release/latest/can.view.mustache.js"></script>
<script src="http://canjs.us/release/latest/can.construct.super.js"></script>
<script src="http://canjs.us/release/latest/can.object.js"></script>
<table id='websites'></table>
<div id='nextprev'></div>
<div id='pagecount'></div>

<!-- TEMPLATES -->
<script id="nextPrevStache" type="text/mustache">
  <a href="javascript://" 
     class="prev {{#paginate.canPrev}}enabled{{/paginate.canPrev}}">Prev</a>
  <a href="javascript://" 
     class="next {{#paginate.canNext}}enabled{{/paginate.canNext}}">Next</a>
</script>

<script id="pageCountStache" type="text/mustache">
Page <span>{{page}}</span> of <span>{{pageCount}}</span>.
</script>

<script id="websiteStache" type="text/mustache">
  <thead>
  	<tr>
  		<th>Name</th><th>Url</th>
  	</tr>
  </thead>
  <tbody>
  	{{#items}}
  	  <tr>
  	  	<td width="40%">{{name}}</td>
  	  	<td width="70%">{{url}}</td>
  	  </tr>
  	{{/items}}
  </tbody>
</script>

CSS

* {
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);
}
#nextprev { margin: 5px auto;text-align: center; }
#nextprev 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;
}
#nextprev a.enabled {
    color: #ffffff;
    text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
    background-color: #49afcd;
    border-color: #2f96b4 #2f96b4 #1f6377;
}
#pagecount, #pagecount * {
    font-size: 11px;
    color: #ccc;
    text-align: center;
}

JavaScript

(function() {
    // Organizes pagination state and 
	// provides some helper methods
    var Paginate = can.Observe({
      defaults : {
        count: Infinity,
        offset: 0,
        limit: 100
      }
    },{
      // Prevent negative counts
      setCount: function(newCount, success, error){
        return newCount < 0 ? 0 : newCount;
      },
      // Prevent negative offsets
      setOffset: function(newOffset){
        return newOffset < 0 ? 
            0 : 
            Math.min(newOffset, ! isNaN(this.count - 1) ? 
                     this.count - 1 : 
                     Infinity )
      },
      // move next
      next: function(){
        this.attr('offset', this.offset+this.limit);
      },
      prev : function(){
        this.attr('offset', this.offset - this.limit )
      },
      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;
      }
    });

	// Hooks up client state to can.route and
	// various controls.
	var AppControl = can.Control({
	  init: function(){
		// Create an Observe that organizes
		// the page's state.
	    var paginate = this.options.paginate = new Paginate({
	        limit: 5
	    });
	    
	    // Create widget that uses the page's state.
	    new NextPrev("#nextprev",{paginate: paginate});
	    
	    // Create widget by mapping page's state
	    // to the options the widget it accepts.
	    new PageCount("#pagecount",{
          page: can.compute(paginate.page,paginate),
         ...