Skip to content

Instantly share code, notes, and snippets.

@justinbmeyer
Created February 1, 2015 18:36
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save justinbmeyer/e308658f3115da921020 to your computer and use it in GitHub Desktop.
Save justinbmeyer/e308658f3115da921020 to your computer and use it in GitHub Desktop.
tabs.stache
<can-component tag='can-tabs'>
<style type='less'>
margin-top: 20px;
button {clear: both;}
ul {
padding: 0px; margin: 0px;
}
ul:after { content: "."; display: block; height: 1px; clear: both; visibility: hidden; }
ul { display: inline-block; }
li {
float: left;
padding: 10px;
background-color: #F6F6F6;
list-style: none;
margin-left: 10px;
color: #1C94C4;
font-weight: bold;
text-decoration: none;
}
li.active {
color: #F6A828;
cursor: default;
}
can-panel {
clear: both;
display: block;
}
</style>
<template type='text/stache'>
<ul>
{{#panels}}
<li {{#isActive}}class='active'{{/isActive}}
can-click='makeActive'>
{{title}}
</li>
{{/panels}}
</ul>
<content></content>
</template>
<scope>
import can from "can";
import "can-panel.stache!"
export default can.Map.extend({
// Contains a list of all panel scopes within the
// tabs element.
panels: [],
// When a `<panel>` element is inserted into the document,
// it calls this method to add the panel's scope to the
// panels array.
addPanel: function(panel){
// If this is the first panel, activate it.
if( this.attr("panels").length === 0 ) {
this.makeActive(panel);
}
this.attr("panels").push(panel);
},
// When a `<panel>` element is removed from the document,
// it calls this method to remove the panel's scope from
// the panels array.
removePanel: function(panel){
var panels = this.attr("panels");
can.batch.start();
panels.splice(panels.indexOf(panel),1);
// if the panel was active, make the first item active
if(panel === this.attr("active")){
if(panels.length){
this.makeActive(panels[0]);
} else {
this.removeAttr("active")
}
}
can.batch.stop()
},
makeActive: function(panel){
this.attr("active",panel);
this.attr("panels").each(function(panel){
panel.attr("active", false)
});
panel.attr("active",true);
},
// this is scope, not mustache
// consider removing scope as arg
isActive: function( panel ) {
return this.attr('active') == panel;
}
});
</scope>
<events>
export default {}
</events>
<helpers>
export default {}
</helpers>
</can-component>
@matthewp
Copy link

Wow, this is really nice. I guess scope, events, and helpers would go through System.module and then set up a can.Component. At cursory glance this doesn't seem super hard to implement. Are you interested in working on a POC for this? If not I would like to give it a shot. It might be a bit harder to make work for other module loaders.

@wclr
Copy link

wclr commented Mar 13, 2015

What about IDE support of syntax hightlight for this?

@mjstahl
Copy link

mjstahl commented Apr 7, 2015

This is a wonderful, fantastic, (insert more compliments here) example! If I could make a few suggestions.

  1. In the scope tag, I would replace the export default can.Map.extend with just export default {.
    CanJS itself could call can.Map.extend with whatever is exported from scope tag and decrease the potential of questions from new developers. On the flip side, increases the perception of "framework magic", because we are hiding some of the implementation details.
  2. Remove the need to add export default {} in the events and helpers tags. If those tags don't exist, or the tags exist but are empty, we could assign an empty object.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment