CanJS Recipe: History Tabs
This recipe shows how to make a history-based tabs widget and have routes
configured independently by can.route.
HTML
<script src="http://canjs.us/release/latest/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
.tabs {
padding: 0px; margin: 0px;
}
.tabs li {
float: left;
padding: 10px;
background-color: #F6F6F6;
list-style: none;
margin-left: 10px;
}
.tabs li a {
color: #1C94C4;
font-weight: bold;
text-decoration: none;
}
.tabs li.active a {
color: #F6A828;
cursor: default;
}
.tab {
border: solid 1px #F6A828;
}
/* 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({
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'});