6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney<style scoped>
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney.yui3-tabview {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney margin-bottom: 1em;
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney}
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney.yui3-skin-sam .yui3-tab {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney position: relative;
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney}
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney.yui3-skin-sam .yui3-tabview-removeable .yui3-tab-label,
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney.yui3-skin-sam .yui3-tabview-removeable .yui3-tab-selected .yui3-tab-label {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney padding-right: 1.3em; /* make room for close link */
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney}
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney.yui3-skin-sam .yui3-tabview-removeable .yui3-tab-add {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney padding-right: 0.75em; /* no close link for add tab link */
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney}
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney.yui3-skin-sam .yui3-tab-add {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney color: #999;
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney font: bold 120%/1 verdana;
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney margin-left: 0.25em;
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney}
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney.yui3-tab-remove {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney color: #999;
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney font:bold 80% verdana;
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney position: absolute;
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney right: 0.4em;
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney top: 0.4em;
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney}
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney.yui3-tab-remove:hover {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney color: #666;
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney}
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney.yui3-skin-sam .yui3-tab-selected .yui3-tab-remove {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney top: 0.52em;
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney}
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney.yui3-skin-sam .yui3-tab-selected .yui3-tab-remove:hover {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney color: #fff;
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney}
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney#main #example-canvas .yui3-tabview .yui3-tab-selected a {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney color:white;
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney}
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney</style>
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney<div class="intro">
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney <p>This example shows how to give <code>TabView</code> buttons for adding and removing tabs.</p>
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney</div>
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney<div class="example yui3-skin-sam">
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney{{>tabview-add-remove-source}}
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney</div>
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney<h2>Plugin Template</h2>
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney<p>In order to make these addons reusable, we can build them as plugins. This
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneyallows the option for multiple tabviews that mix and match functionality.
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt SweeneyTo get started, we will first fill in a basic <code>Plugin</code> template.
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt SweeneyThe <code>NAME</code> property is required to prefix events, classNames, et cetera.
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt SweeneyThe <code>NS</code> is the namespace where the plugin will live on the
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney<code>host</code>. This is where its API can be accessed (e.g. "node.addable.destroy()").
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt SweeneyAdding the <code>this._host</code> alias provides a convenient way to get back to the TabView
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneyinstance. Calling the superclass constructor kicks off the <code>Base</code> lifecycle,
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneywhich will call the <code>initializer</code>.
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney</p>
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney```
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneyvar Addable = function(config) {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney this._host = config.host;
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney Addable.superclass.constructor.apply(this, arguments);
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney};
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt SweeneyAddable.NAME = 'addableTabs';
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt SweeneyAddable.NS = 'addable';
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt SweeneyY.extend(Addable, Y.Plugin.Base, {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney initializer: function(config) {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney }
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney});
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney```
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney<h2>Addable Tab Plugin</h2>
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney<p>To simplify adding new tabs, we are going to add a button that
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneyusers can click and that will prompt them for some details regarding the new tab.
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt SweeneyThe main task we are trying to accomplish is to add some HTML to the
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney<code>TabView</code>, listen for clicks on the button, prompt the user for input,
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneyand update the tabs accordingly.</p>
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney<h3>HTML Template</h3>
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney<p>The first thing we need is a template for the markup to be generated. Adding
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneythis to the prototype allows separate customization for each <code>TabView</code>
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneyinstance. For this example, we want it to look and feel like another <code>Tab</code>
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneywithout actually being one.</p>
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney```
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt SweeneyY.extend(Addable, Y.Plugin.Base, {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney ADD_TEMPLATE: '<li class="yui3-tab" title="add a tab">' +
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney '<a class="yui3-tab-label yui3-tab-add">+</a></li>',
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney initializer: function(config) {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney }
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney});
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney```
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney<h3>Adding the HTML</h3>
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney<p>Now that we have a markup template, we will need to add it to the <code>TabView</code>
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneysomehow. The <code>render</code> phase is the appropriate moment to do so. Listening
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneyfor the <code>render</code> event will give us access to that moment. Listening
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneyfor <code>after('render')</code> ensure that the rendering has actually happened. Then
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneywe just need to find the tab list and, using the template, add the new item.
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt SweeneyThe <code>contentBox</code> provides a <code>Node</code> that can be used to manage
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneythe <code>TabView</code> HTML.</p>
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney```
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt SweeneyY.extend(Addable, Y.Plugin.Base, {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney ADD_TEMPLATE: '<li class="yui3-tab" title="add a tab">' +
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney '<a class="yui3-tab-label yui3-tab-add">+</a></li>',
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney initializer: function(config) {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney var tabview = this.get('host');
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney tabview.after('render', this.afterRender, this);
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney },
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney afterRender: function(e) {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney var tabview = this.get('host');
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney tabview.get('contentBox').one('> ul').append(this.ADD_TEMPLATE);
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney }
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney});
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney```
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney<h3>Handling the Click</h3>
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney<p>All that remains is to listen for clicks on the add button and prompt
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneythe user for the relevant <code>Tab</code> data. Again we can leverage
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneythe <code>Node</code> API, this time to delegate clicks on the add button.
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt SweeneyStopping event propagation in our handler ensures that the event does
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneynot bubble any further, preventing the <code>TabView</code> from trying
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneyto handle it. To keep the example simple, a basic <code>prompt</code> is
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneyused to get the user input. This could be refined to use an
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney<code>Overlay</code> or other custom control. The data is then handed off
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneyto <code>TabView</code>'s <code>add</code> method.</p>
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney```
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt SweeneyY.extend(Addable, Y.Plugin.Base, {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney ADD_TEMPLATE: '<li class="yui3-tab" title="add a tab">' +
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney '<a class="yui3-tab-label yui3-tab-add">+</a></li>',
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney initializer: function(config) {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney var tabview = this.get('host');
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney tabview.after('render', this.afterRender, this);
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney tabview.get('contentBox')
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney .delegate('click', this.onAddClick, '.yui3-tab-add', this);
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney },
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney afterRender: function(e) {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney this.get('host').get('contentBox').one('> ul').append(this.ADD_TEMPLATE);
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney },
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney getTabInput: function() {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney return {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney label: window.prompt('label:', 'new tab'),
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney content: window.prompt('content:', '<p>new content</p>'),
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney index: Number(window.prompt('index:', this._host.size()))
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney }
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney },
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney onAddClick: function(e) {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney e.stopPropagation();
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney var tabview = this.get('host');
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney input = this.getTabInput();
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney tabview.add(input, input.index);
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney }
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney});
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney```
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney<h3>Using the Plugin</h3>
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney<p>Now we can go ahead and plug in our functionality. This can be during
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneyconstruction with the <code>plugins</code> attribute, or subsequently
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneyvia the <code>plug</code> method.</p>
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney```
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneyvar tabview = new Y.TabView({
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney children: [{
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney label: 'foo',
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney content: '<p>foo content</p>'
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney }, {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney label: 'bar',
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney content: '<p>bar content</p>'
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney }, {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney label: 'baz',
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney content: '<p>baz content</p>'
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney }],
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney plugins: [Addable]
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney});
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney// or
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney// tabview.plug(Addable);
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney```
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney<h2>Removeable Tabs Plugin</h2>
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney<p>The process for creating a removeable plugin for <code>TabView</code>
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneyis very similar. The full source is provided below.</p>
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney```
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeneyvar Removeable = function(config) {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney Removeable.superclass.constructor.apply(this, arguments);
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney};
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt SweeneyRemoveable.NAME = 'removeableTabs';
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt SweeneyRemoveable.NS = 'removeable';
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt SweeneyY.extend(Removeable, Y.Plugin.Base, {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney REMOVE_TEMPLATE: '<a class="yui3-tab-remove" title="remove tab">x</a>',
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney initializer: function(config) {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney var tabview = this.get('host'),
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney cb = tabview.get('contentBox');
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney cb.addClass('yui3-tabview-removeable');
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney cb.delegate('click', this.onRemoveClick, '.yui3-tab-remove', this);
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney // Tab events bubble to TabView
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney tabview.after('tab:render', this.afterTabRender, this);
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney },
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney afterTabRender: function(e) {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney // boundingBox is the Tab's LI
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney e.target.get('boundingBox').append(this.REMOVE_TEMPLATE);
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney },
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney onRemoveClick: function(e) {
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney e.stopPropagation();
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney var tab = Y.Widget.getByNode(e.target);
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney tab.remove();
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney }
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney});
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney```
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney<h2>Complete Example Source</h2>
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney```
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney{{>tabview-add-remove-source}}
6f22811f3148a8875c32d1e4a34f19dc1b8579d4Matt Sweeney```