CanJS Recipe: History Tabs
This recipe shows how to make a history-based tabs widget and have routes configured independently by can.route.
by donejs
HTML
<script src="http://canjs.com/release/2.0.1/can.jquery.js"></script>
<ul id="components" class="tabs ui-helper-clearfix">
<li><a href="#model">can.Model</a></li>
<li><a href="#view">can.View</a></li>
<li><a href="#control">can.Control</a></li>
</ul>
<div id="model" class="tab">
can.Model is used for getting data and listening to it.
</div>
<div id="view" class="tab">
can.View is used to present data and update with changes to it.
</div>
<div id="control" class="tab">
can.Control is used to listen to things.
</div>
<br/><br/>
<ul id="people" class="tabs ui-helper-clearfix">
<li><a href="#brian">Brian</a></li>
<li><a href="#justin">Justin</a></li>
<li><a href="#mihael">Michael</a></li>
</ul>
<div id="brian" class="tab">
<img src='http://bitovi.com/images/people/brian.jpg'/>
</div>
<div id="justin" class="tab">
<img src='http://bitovi.com/images/people/justin.jpg'/>
</div>
<div id="mihael" class="tab">
<img src='http://bitovi.com/images/people/mihael.jpg'/>
</div>
CSS
@import url(http://fonts.googleapis.com/css?family=Lato:100,400,700);
* {
font-family: 'Lato', sans-serif;
font-size: 12px;
text-shadow: 0 -1px 0 #ffffff;
}
.tabs {
padding: 0px;
margin: 10px 0px 0px 0px;
position: relative;
z-index: 1;
top: 1px;
}
.tabs li {
float: left;
padding: 7px 10px;
background-color: #F6F6F6;
list-style: none;
margin-left: 5px;
border: 1px solid #ccc;
-webkit-border-top-left-radius: 3px;
-webkit-border-top-right-radius: 3px;
-moz-border-radius-topleft: 3px;
-moz-border-radius-topright: 3px;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
}
.tabs li a {
color: #999;
font-weight: bold;
text-decoration: none;
}
.tabs li.active {
background-color: #fff;
border-bottom: 1px solid #fff;
}
.tabs li.active a {
color: #000;
cursor: default;
}
.tab {
border: solid 1px #ccc;
padding: 10px;
}
/* clearfix from jQueryUI */
.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
.ui-helper-clearfix { display: inline-block; }
/* required comment for clearfix to work in Opera \*/
* html .ui-helper-clearfix { height:1%; }
.ui-helper-clearfix { display:block; }
/* end clearfix */
JavaScript
var HistoryTabs = can.Control.extend({
init: function( el ) {
// hide all tabs
var tab = this.tab;
this.element.children( 'li' ).each(function() {
tab( $( this ) ).hide();
});
// activate the first tab
var active = can.route.attr(this.options.attr);
this.activate(active);
},
"{can.route} {attr}" : function(route, ev, newVal, oldVal){
this.activate(newVal, oldVal)
},
// helper function finds the tab for a given li
tab: function( li ) {
return $( li.find( 'a' ).attr( 'href' ) );
},
// helper function finds li for a given id
button : function(id){
// if nothing is active, activate the first
return id ? this.element.find("a[href=#"+id+"]").parent() :
this.element.children( 'li:first' );
},
// activates
activate: function( active, oldActive ){
// deactivate the old active
var oldButton = this.button(oldActive).removeClass('active');
this.tab(oldButton).hide();
// activate new
var newButton = this.button(active).addClass('active');
this.tab(newButton).show();
},
"li click" : function(el, ev){
// prevent the default setting
ev.preventDefault();
// update the route data
can.route.attr(this.options.attr, this.tab(el)[0].id)
}
});
// configure routes
can.route(":component",{
component: "model",
person: "mihael"
});
can.route(":component/:person",{
component: "model",
person: "mihael"
});
// adds the controller to the element
new HistoryTabs( '#components',{attr: 'component'});
new HistoryTabs( '#people',{attr: 'person'});