diff --git a/misc/demo/index.html b/misc/demo/index.html
index d6b358ff30..374acc5cb9 100644
--- a/misc/demo/index.html
+++ b/misc/demo/index.html
@@ -182,10 +182,14 @@
<%= module.displayName %>
-
- <%- module.docs.html %>
- <%- module.docs.js %>
-
+
+
+ <%- module.docs.html %>
+
+
+ <%- module.docs.js %>
+
+
diff --git a/src/tabs/docs/demo.html b/src/tabs/docs/demo.html
index f16e31da19..ee8a435ee9 100644
--- a/src/tabs/docs/demo.html
+++ b/src/tabs/docs/demo.html
@@ -1,10 +1,23 @@
-
- Static content
- {{pane.content}}
-
-
-
-
-
-
\ No newline at end of file
+ Select a tab by setting active binding to true:
+
+
+
+
+
+ Static content
+
+ {{tab.content}}
+
+
+
+ Select me for alert!
+
+ I've got an HTML heading, and a select callback. Pretty cool!
+
+
+
diff --git a/src/tabs/docs/demo.js b/src/tabs/docs/demo.js
index 59ce3accd2..509b746aa0 100644
--- a/src/tabs/docs/demo.js
+++ b/src/tabs/docs/demo.js
@@ -1,6 +1,12 @@
var TabsDemoCtrl = function ($scope) {
- $scope.panes = [
+ $scope.tabs = [
{ title:"Dynamic Title 1", content:"Dynamic content 1" },
{ title:"Dynamic Title 2", content:"Dynamic content 2" }
];
-};
\ No newline at end of file
+
+ $scope.alertMe = function() {
+ setTimeout(function() {
+ alert("You've selected the alert tab!");
+ });
+ };
+};
diff --git a/src/tabs/docs/readme.md b/src/tabs/docs/readme.md
index 3c746c49eb..620b63045e 100644
--- a/src/tabs/docs/readme.md
+++ b/src/tabs/docs/readme.md
@@ -1 +1,5 @@
-AngularJS version of the tabs directive.
\ No newline at end of file
+AngularJS version of the tabs directive.
+
+Allows a `select` callback attribute, and `active` binding attribute.
+
+Allows either `heading` text-heading as an attribute, or a `` element inside as the heading.
diff --git a/src/tabs/tabs.js b/src/tabs/tabs.js
index b05d75f1b2..2d3d0a5c62 100644
--- a/src/tabs/tabs.js
+++ b/src/tabs/tabs.js
@@ -1,75 +1,168 @@
angular.module('ui.bootstrap.tabs', [])
-.controller('TabsController', ['$scope', '$element', function($scope, $element) {
- var panes = $scope.panes = [];
- this.select = $scope.select = function selectPane(pane) {
- angular.forEach(panes, function(pane) {
- pane.selected = false;
- });
- pane.selected = true;
+.directive('tabs', function() {
+ return function() {
+ throw new Error("The `tabs` directive is deprecated, please migrate to `tabset`. Instructions can be found at http://github.com/angular-ui/bootstrap/tree/master/CHANGELOG.md");
};
+})
- this.addPane = function addPane(pane) {
- if (!panes.length) {
- $scope.select(pane);
+.controller('TabsetController', ['$scope', '$element',
+function TabsetCtrl($scope, $element) {
+ var ctrl = this,
+ tabs = ctrl.tabs = $scope.tabs = [];
+
+ ctrl.select = function(tab) {
+ angular.forEach(tabs, function(tab) {
+ tab.active = false;
+ });
+ tab.active = true;
+ };
+
+ ctrl.addTab = function addTab(tab) {
+ tabs.push(tab);
+ if (tabs.length == 1) {
+ ctrl.select(tab);
}
- panes.push(pane);
};
- this.removePane = function removePane(pane) {
- var index = panes.indexOf(pane);
- panes.splice(index, 1);
- //Select a new pane if removed pane was selected
- if (pane.selected && panes.length > 0) {
- $scope.select(panes[index < panes.length ? index : index-1]);
+ ctrl.removeTab = function removeTab(tab) {
+ var index = tabs.indexOf(tab);
+ //Select a new tab if the tab to be removed is selected
+ if (tab.active && tabs.length > 1) {
+ //If this is the last tab, select the previous tab. else, the next tab.
+ var newActiveIndex = index == tabs.length - 1 ? index - 1 : index + 1;
+ ctrl.select(tabs[newActiveIndex]);
}
+ tabs.splice(index, 1);
};
}])
-.directive('tabs', function() {
+
+.directive('tabset', function() {
return {
restrict: 'EA',
transclude: true,
scope: {},
- controller: 'TabsController',
- templateUrl: 'template/tabs/tabs.html',
- replace: true
+ controller: 'TabsetController',
+ templateUrl: 'template/tabs/tabset.html'
};
})
-.directive('pane', ['$parse', function($parse) {
+
+.directive('tab', ['$parse', '$http', '$templateCache', '$compile',
+function($parse, $http, $templateCache, $compile) {
return {
- require: '^tabs',
+ require: '^tabset',
restrict: 'EA',
+ replace: true,
+ templateUrl: 'template/tabs/tab.html',
transclude: true,
- scope:{
- heading:'@'
+ scope: {
+ heading: '@',
+ onSelect: '&select' //This callback is called in contentHeadingTransclude
+ //once it inserts the tab's content into the dom
+ },
+ controller: function() {
+ //Empty controller so other directives can require being 'under' a tab
},
- link: function(scope, element, attrs, tabsCtrl) {
- var getSelected, setSelected;
- scope.selected = false;
- if (attrs.active) {
- getSelected = $parse(attrs.active);
- setSelected = getSelected.assign;
- scope.$watch(
- function watchSelected() {return getSelected(scope.$parent);},
- function updateSelected(value) {scope.selected = value;}
- );
- scope.selected = getSelected ? getSelected(scope.$parent) : false;
- }
- scope.$watch('selected', function(selected) {
- if(selected) {
- tabsCtrl.select(scope);
+ compile: function(elm, attrs, transclude) {
+ return function postLink(scope, elm, attrs, tabsetCtrl) {
+ var getActive, setActive;
+ scope.active = false; // default value
+ if (attrs.active) {
+ getActive = $parse(attrs.active);
+ setActive = getActive.assign;
+ scope.$parent.$watch(getActive, function updateActive(value) {
+ scope.active = !!value;
+ });
+ } else {
+ setActive = getActive = angular.noop;
}
- if(setSelected) {
- setSelected(scope.$parent, selected);
+
+ scope.$watch('active', function(active) {
+ setActive(scope.$parent, active);
+ if (active) {
+ tabsetCtrl.select(scope);
+ scope.onSelect();
+ }
+ });
+
+ scope.select = function() {
+ scope.active = true;
+ };
+
+ tabsetCtrl.addTab(scope);
+ scope.$on('$destroy', function() {
+ tabsetCtrl.removeTab(scope);
+ });
+ //If the tabset sets this tab to active, set the parent scope's active
+ //binding too. We do this so the watch for the parent's initial active
+ //value won't overwrite what is initially set by the tabset
+ if (scope.active) {
+ setActive(scope.$parent, true);
+ }
+
+ //Transclude the collection of sibling elements. Use forEach to find
+ //the heading if it exists. We don't use a directive for tab-heading
+ //because it is problematic. Discussion @ http://git.io/MSNPwQ
+ transclude(scope.$parent, function(clone) {
+ //Look at every element in the clone collection. If it's tab-heading,
+ //mark it as that. If it's not tab-heading, mark it as tab contents
+ var contents = [], heading;
+ angular.forEach(clone, function(el) {
+ //See if it's a tab-heading attr or element directive
+ //First make sure it's a normal element, one that has a tagName
+ if (el.tagName &&
+ (el.hasAttribute("tab-heading") ||
+ el.hasAttribute("data-tab-heading") ||
+ el.tagName.toLowerCase() == "tab-heading" ||
+ el.tagName.toLowerCase() == "data-tab-heading"
+ )) {
+ heading = el;
+ } else {
+ contents.push(el);
+ }
+ });
+ //Share what we found on the scope, so our tabHeadingTransclude and
+ //tabContentTransclude directives can find out what the heading and
+ //contents are.
+ if (heading) {
+ scope.headingElement = angular.element(heading);
+ }
+ scope.contentElement = angular.element(contents);
+ });
+ };
+ }
+ };
+}])
+
+.directive('tabHeadingTransclude', [function() {
+ return {
+ restrict: 'A',
+ require: '^tab',
+ link: function(scope, elm, attrs, tabCtrl) {
+ scope.$watch('headingElement', function updateHeadingElement(heading) {
+ if (heading) {
+ elm.html('');
+ elm.append(heading);
}
});
+ }
+ };
+}])
- tabsCtrl.addPane(scope);
- scope.$on('$destroy', function() {
- tabsCtrl.removePane(scope);
+.directive('tabContentTransclude', ['$parse', function($parse) {
+ return {
+ restrict: 'A',
+ require: '^tabset',
+ link: function(scope, elm, attrs, tabsetCtrl) {
+ scope.$watch($parse(attrs.tabContentTransclude), function(tab) {
+ elm.html('');
+ if (tab) {
+ elm.append(tab.contentElement);
+ }
});
- },
- templateUrl: 'template/tabs/pane.html',
- replace: true
+ }
};
-}]);
+}])
+
+;
+
diff --git a/src/tabs/test/tabsSpec.js b/src/tabs/test/tabsSpec.js
index 0c7ca733a9..74002e152f 100644
--- a/src/tabs/test/tabsSpec.js
+++ b/src/tabs/test/tabsSpec.js
@@ -1,257 +1,381 @@
describe('tabs', function() {
- var elm, scope;
-
- // load the tabs code
- beforeEach(module('ui.bootstrap.tabs'));
-
- // load the templates
- beforeEach(module('template/tabs/tabs.html', 'template/tabs/pane.html'));
-
- beforeEach(inject(function($rootScope, $compile) {
- // we might move this tpl into an html file as well...
- elm = angular.element(
- '' +
- '
' +
- '' +
- 'first content is {{first}}' +
- '' +
- '' +
- 'second content is {{second}}' +
- '' +
- '' +
- '
');
-
- scope = $rootScope;
- $compile(elm)(scope);
- scope.$digest();
- }));
-
-
- it('should create clickable titles', inject(function($compile, $rootScope) {
- var titles = elm.find('ul.nav-tabs li a');
-
- expect(titles.length).toBe(2);
- expect(titles.eq(0).text()).toBe('First Tab');
- expect(titles.eq(1).text()).toBe('Second Tab');
- }));
+ beforeEach(module('ui.bootstrap.tabs', 'template/tabs/tabset.html', 'template/tabs/tab.html'));
+ var elm, scope;
+ function titles() {
+ return elm.find('ul.nav-tabs li');
+ }
+ function contents() {
+ return elm.find('div.tab-content div.tab-pane');
+ }
+
+ function expectTitles(titlesArray) {
+ var t = titles();
+ expect(t.length).toEqual(titlesArray.length);
+ for (var i=0; i',
+ ' ',
+ ' ',
+ ' first content is {{first}}',
+ ' ',
+ ' ',
+ ' Second Tab {{second}}',
+ ' second content is {{second}}',
+ ' ',
+ ' ',
+ ''
+ ].join('\n'))(scope);
+ scope.$apply();
+ return elm;
+ }));
+
+ it('should create clickable titles', function() {
+ var t = titles();
+ expect(t.length).toBe(2);
+ expect(t.find('a').eq(0).text()).toBe('First Tab 1');
+ //It should put the tab-heading element into the 'a' title
+ expect(t.find('a').eq(1).children().is('tab-heading')).toBe(true);
+ expect(t.find('a').eq(1).children().html()).toBe('Second Tab 2');
+ });
- it('should bind the content', function() {
- var contents = elm.find('div.tab-content div.tab-pane');
+ it('should bind tabs content and set first tab active', function() {
+ expectContents(['first content is 1', 'second content is 2']);
+ expect(titles().eq(0)).toHaveClass('active');
+ expect(titles().eq(1)).not.toHaveClass('active');
+ expect(scope.actives.one).toBe(true);
+ expect(scope.actives.two).toBe(false);
+ });
- expect(contents.length).toBe(2);
- expect(contents.eq(0).text()).toBe('first content is ');
- expect(contents.eq(1).text()).toBe('second content is ');
+ it('should change active on click', function() {
+ titles().eq(1).find('a').click();
+ expect(contents().eq(1)).toHaveClass('active');
+ expect(titles().eq(0)).not.toHaveClass('active');
+ expect(titles().eq(1)).toHaveClass('active');
+ expect(scope.actives.one).toBe(false);
+ expect(scope.actives.two).toBe(true);
+ });
- scope.$apply(function() {
- scope.first = 123;
- scope.second = 456;
+ it('should call select callback on select', function() {
+ titles().eq(1).find('a').click();
+ expect(scope.selectSecond).toHaveBeenCalled();
+ titles().eq(0).find('a').click();
+ expect(scope.selectFirst).toHaveBeenCalled();
});
- expect(contents.eq(0).text()).toBe('first content is 123');
- expect(contents.eq(1).text()).toBe('second content is 456');
});
+ describe('ng-repeat', function() {
+
+ beforeEach(inject(function($compile, $rootScope) {
+ scope = $rootScope.$new();
+
+ function makeTab() {
+ return {
+ active: false,
+ select: jasmine.createSpy()
+ };
+ }
+ scope.tabs = [
+ makeTab(), makeTab(), makeTab(), makeTab()
+ ];
+ elm = $compile([
+ '',
+ ' ',
+ ' heading {{index}}',
+ ' content {{$index}}',
+ ' ',
+ ''
+ ].join('\n'))(scope);
+ scope.$apply();
+ }));
- it('should set active class on title', function() {
- var titles = elm.find('ul.nav-tabs li');
-
- expect(titles.eq(0)).toHaveClass('active');
- expect(titles.eq(1)).not.toHaveClass('active');
- });
-
+ function titles() {
+ return elm.find('ul.nav-tabs li');
+ }
+ function contents() {
+ return elm.find('div.tab-content div.tab-pane');
+ }
- it('should set active class on content', function() {
- var contents = elm.find('div.tab-content div.tab-pane');
+ function expectTabActive(activeTab) {
+ var _titles = titles();
+ angular.forEach(scope.tabs, function(tab, i) {
+ if (activeTab === tab) {
+ expect(tab.active).toBe(true);
+ //It should only call select ONCE for each select
+ expect(tab.select.callCount).toBe(1);
+ expect(_titles.eq(i)).toHaveClass('active');
+ expect(contents().eq(i).text().trim()).toBe('content ' + i);
+ expect(contents().eq(i)).toHaveClass('active');
+ } else {
+ expect(tab.active).toBe(false);
+ expect(_titles.eq(i)).not.toHaveClass('active');
+ }
+ });
+ }
- expect(contents.eq(0)).toHaveClass('active');
- expect(contents.eq(1)).not.toHaveClass('active');
- });
+ it('should make tab titles with first content and first active', function() {
+ expect(titles().length).toBe(scope.tabs.length);
+ expectTabActive(scope.tabs[0]);
+ });
- it('should change active and display on pane when title clicked', function() {
- var titles = elm.find('ul.nav-tabs li');
- var contents = elm.find('div.tab-content div.tab-pane');
+ it('should switch active when clicking', function() {
+ titles().eq(3).find('a').click();
+ expectTabActive(scope.tabs[3]);
+ });
- // click the second tab
- titles.eq(1).find('a').click();
+ it('should switch active when setting active=true', function() {
+ scope.$apply('tabs[2].active = true');
+ expectTabActive(scope.tabs[2]);
+ });
- // second title should be active
- expect(titles.eq(0)).not.toHaveClass('active');
- expect(titles.eq(1)).toHaveClass('active');
+ it('should deselect all when no tabs are active', function() {
+ angular.forEach(scope.tabs, function(t) { t.active = false; });
+ scope.$apply();
+ expectTabActive(null);
+ expect(contents().filter('.active').length).toBe(0);
- // second content should be active and visible
- expect(contents.eq(0)).not.toHaveClass('active');
- expect(contents.eq(0).css('display')).toBe('none');
- expect(contents.eq(1)).toHaveClass('active');
- expect(contents.eq(1).css('display')).not.toBe('none');
+ scope.tabs[2].active = true;
+ scope.$apply();
+ expectTabActive(scope.tabs[2]);
+ });
});
-});
+ describe('advanced tab-heading element', function() {
+ beforeEach(inject(function($compile, $rootScope) {
+ scope = $rootScope.$new();
+ scope.myHtml = "hello, there!";
+ scope.value = true;
+ elm = $compile([
+ '',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' 1',
+ ' 2
',
+ ' 3
',
+ ''
+ ].join('\n'))(scope);
+ scope.$apply();
+ }));
+
+ function heading() {
+ return elm.find('ul li a').children();
+ }
-describe('remote selection', function() {
- var elm, scope;
+ it('should create a heading bound to myHtml', function() {
+ expect(heading().eq(0).html()).toBe("hello, there!");
+ });
- // load the tabs code
- beforeEach(module('ui.bootstrap.tabs'));
-
- // load the templates
- beforeEach(module('template/tabs/tabs.html', 'template/tabs/pane.html'));
-
- beforeEach(inject(function($rootScope, $compile) {
- // we might move this tpl into an html file as well...
- elm = angular.element(
- '' +
- '
' +
- '' +
- '{{pane.content}}}' +
- '' +
- '' +
- '
'
- );
- scope = $rootScope;
- scope.panes = [
- { title:"Dynamic Title 1", content:"Dynamic content 1", active:true},
- { title:"Dynamic Title 2", content:"Dynamic content 2" }
- ];
-
- $compile(elm)(scope);
- scope.$digest();
- }));
-
- it('should handle select attribute when select/deselect', function() {
- var titles = elm.find('ul.nav-tabs li');
- scope.$apply('panes[1].active=true');
- expect(titles.eq(1)).toHaveClass('active');
-
- titles.eq(0).find('a').click();
-
- expect(scope.panes[1].active).toBe(false);
- });
+ it('should hide and show the heading depending on value', function() {
+ expect(heading().eq(0).css('display')).not.toBe('none');
+ scope.$apply('value = false');
+ expect(heading().eq(0).css('display')).toBe('none');
+ scope.$apply('value = true');
+ expect(heading().eq(0).css('display')).not.toBe('none');
+ });
- it('should select last active tab when multiple panes evaluate to active=true', function() {
- var titles = elm.find('ul.nav-tabs li');
- scope.$apply('panes[0].active=true;panes[1].active=true');
- expect(titles.eq(1)).toHaveClass('active');
+ it('should have a tab-heading no matter what syntax was used', function() {
+ expect(heading().eq(1).text()).toBe('1');
+ expect(heading().eq(2).text()).toBe('2');
+ expect(heading().eq(3).text()).toBe('3');
+ });
+
});
- it('should deselect all panes when all atrributes set to false', function() {
- var titles = elm.find('ul.nav-tabs li');
- scope.$apply('panes[0].active=false');
- expect(titles.eq(0)).not.toHaveClass('active');
- expect(titles.eq(1)).not.toHaveClass('active');
+ //Tests that http://git.io/lG6I9Q is fixed
+ describe('tab ordering', function() {
+
+ beforeEach(inject(function($compile, $rootScope) {
+ scope = $rootScope.$new();
+ scope.tabs = [
+ { title:"Title 1", available:true },
+ { title:"Title 2", available:true },
+ { title:"Title 3", available:true }
+ ];
+ elm = $compile([
+ '',
+ ' ',
+ ' div that makes troubles
',
+ ' First Static',
+ ' another div that may do evil
',
+ ' some content',
+ ' ',
+ ' Mid Static',
+ ' a text node',
+ ' ',
+ ' yet another span that may do evil',
+ ' some content',
+ ' a text node',
+ ' yet another span that may do evil',
+ ' ',
+ ' Last Static',
+ ' a text node',
+ ' yet another span that may do evil',
+ ' ',
+ ''
+ ].join('\n'))(scope);
+
+ scope.tabIsAvailable = function(tab) {
+ return tab.available;
+ };
+ }));
+
+ it('should preserve correct ordering', function() {
+ function titles() {
+ return elm.find('ul.nav-tabs li a');
+ }
+ scope.$apply();
+ expect(titles().length).toBe(9);
+ scope.$apply('tabs[1].available=false');
+ scope.$digest();
+ expect(titles().length).toBe(7);
+ scope.$apply('tabs[0].available=false');
+ scope.$digest();
+ expect(titles().length).toBe(5);
+ scope.$apply('tabs[2].available=false');
+ scope.$digest();
+ expect(titles().length).toBe(3);
+ scope.$apply('tabs[0].available=true');
+ scope.$digest();
+ expect(titles().length).toBe(5);
+ scope.$apply('tabs[1].available=true');
+ scope.$apply('tabs[2].available=true');
+ scope.$digest();
+ expect(titles().length).toBe(9);
+ expect(titles().eq(0).text().trim()).toBe("first");
+ expect(titles().eq(1).text().trim()).toBe("Title 1");
+ expect(titles().eq(2).text().trim()).toBe("Title 2");
+ expect(titles().eq(3).text().trim()).toBe("Title 3");
+ expect(titles().eq(4).text().trim()).toBe("mid");
+ expect(titles().eq(5).text().trim()).toBe("Second Title 1");
+ expect(titles().eq(6).text().trim()).toBe("Second Title 2");
+ expect(titles().eq(7).text().trim()).toBe("Second Title 3");
+ expect(titles().eq(8).text().trim()).toBe("last");
+ });
});
-});
-
-describe('tabs controller', function() {
- var scope, ctrl;
- beforeEach(module('ui.bootstrap.tabs'));
- beforeEach(inject(function($controller, $rootScope) {
- scope = $rootScope;
+ describe('tabset controller', function() {
+ function mockTab() {
+ return { active: false };
+ }
- // instantiate the controller stand-alone, without the directive
- ctrl = $controller('TabsController', {$scope: scope, $element: null});
- }));
+ var ctrl;
+ beforeEach(inject(function($controller, $rootScope) {
+ scope = $rootScope;
+ //instantiate the controller stand-alone, without the directive
+ ctrl = $controller('TabsetController', {$scope: scope, $element: null});
+ }));
- describe('select', function() {
+ describe('select', function() {
- it('should mark given pane selected', function() {
- var pane = {};
+ it('should mark given tab selected', function() {
+ var tab = mockTab();
- scope.select(pane);
- expect(pane.selected).toBe(true);
- });
+ ctrl.select(tab);
+ expect(tab.active).toBe(true);
+ });
- it('should deselect other panes', function() {
- var pane1 = {}, pane2 = {}, pane3 = {};
+ it('should deselect other tabs', function() {
+ var tab1 = mockTab(), tab2 = mockTab(), tab3 = mockTab();
- ctrl.addPane(pane1);
- ctrl.addPane(pane2);
- ctrl.addPane(pane3);
+ ctrl.addTab(tab1);
+ ctrl.addTab(tab2);
+ ctrl.addTab(tab3);
- scope.select(pane1);
- expect(pane1.selected).toBe(true);
- expect(pane2.selected).toBe(false);
- expect(pane3.selected).toBe(false);
+ ctrl.select(tab1);
+ expect(tab1.active).toBe(true);
+ expect(tab2.active).toBe(false);
+ expect(tab3.active).toBe(false);
- scope.select(pane2);
- expect(pane1.selected).toBe(false);
- expect(pane2.selected).toBe(true);
- expect(pane3.selected).toBe(false);
+ ctrl.select(tab2);
+ expect(tab1.active).toBe(false);
+ expect(tab2.active).toBe(true);
+ expect(tab3.active).toBe(false);
- scope.select(pane3);
- expect(pane1.selected).toBe(false);
- expect(pane2.selected).toBe(false);
- expect(pane3.selected).toBe(true);
+ ctrl.select(tab3);
+ expect(tab1.active).toBe(false);
+ expect(tab2.active).toBe(false);
+ expect(tab3.active).toBe(true);
+ });
});
- });
- describe('addPane', function() {
+ describe('addTab', function() {
- it('should append pane', function() {
- var pane1 = {}, pane2 = {};
+ it('should append tab', function() {
+ var tab1 = mockTab(), tab2 = mockTab();
- expect(scope.panes).toEqual([]);
+ expect(ctrl.tabs).toEqual([]);
- ctrl.addPane(pane1);
- expect(scope.panes).toEqual([pane1]);
+ ctrl.addTab(tab1);
+ expect(ctrl.tabs).toEqual([tab1]);
- ctrl.addPane(pane2);
- expect(scope.panes).toEqual([pane1, pane2]);
- });
+ ctrl.addTab(tab2);
+ expect(ctrl.tabs).toEqual([tab1, tab2]);
+ });
- it('should select the first one', function() {
- var pane1 = {}, pane2 = {};
+ it('should select the first one', function() {
+ var tab1 = mockTab(), tab2 = mockTab();
- ctrl.addPane(pane1);
- expect(pane1.selected).toBe(true);
+ ctrl.addTab(tab1);
+ expect(tab1.active).toBe(true);
- ctrl.addPane(pane2);
- expect(pane1.selected).toBe(true);
+ ctrl.addTab(tab2);
+ expect(tab1.active).toBe(true);
+ });
});
});
-});
-describe('remove tabs', function() {
+ describe('remove', function() {
- beforeEach(module("ui.bootstrap.tabs", "template/tabs/tabs.html", "template/tabs/pane.html"));
+ it('should remove title tabs when elements are destroyed and change selection', inject(function($controller, $compile, $rootScope) {
+ scope = $rootScope.$new();
+ elm = $compile("Hellocontent {{i}}")(scope);
+ scope.$apply();
- it('should remove title panes when elements are destroyed and change selection', inject(function($controller, $compile, $rootScope) {
- var scope = $rootScope;
- var elm = $compile("Hellocontent {{i}}")(scope);
- scope.$apply();
+ expectTitles(['1']);
+ expectContents(['Hello']);
- function titles() {
- return elm.find('ul.nav-tabs li');
- }
- function panes() {
- return elm.find('div.tab-pane');
- }
+ scope.$apply('list = [1,2,3]');
+ expectTitles(['1', 'tab 1', 'tab 2', 'tab 3']);
+ expectContents(['Hello', 'content 1', 'content 2', 'content 3']);
- expect(titles().length).toBe(1);
- expect(panes().length).toBe(1);
-
- scope.$apply('list = [1,2,3]');
- expect(titles().length).toBe(4);
- expect(panes().length).toBe(4);
- titles().find('a').eq(3).click();
- expect(panes().eq(3)).toHaveClass('active');
- expect(panes().eq(3).text().trim()).toBe('content 3');
- expect(titles().eq(3)).toHaveClass('active');
- expect(titles().eq(3).text().trim()).toBe('tab 3');
-
- scope.$apply('list = [1,2]');
- expect(panes().length).toBe(3);
- expect(titles().length).toBe(3);
- expect(panes().eq(2)).toHaveClass('active');
- expect(panes().eq(2).text().trim()).toBe('content 2');
- expect(titles().eq(2)).toHaveClass('active');
- expect(titles().eq(2).text().trim()).toBe('tab 2');
- }));
+ titles().find('a').eq(3).click();
+ expect(contents().eq(3)).toHaveClass('active');
+ expect(titles().eq(3)).toHaveClass('active');
-});
+ scope.$apply('list = [1,2]');
+ expectTitles(['1', 'tab 1', 'tab 2']);
+ expectContents(['Hello', 'content 1', 'content 2']);
+ expect(titles().eq(2)).toHaveClass('active');
+ expect(contents().eq(2)).toHaveClass('active');
+ }));
+ });
+});
diff --git a/template/tabs/pane.html b/template/tabs/pane.html
deleted file mode 100644
index 0783d02f0e..0000000000
--- a/template/tabs/pane.html
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/template/tabs/tab.html b/template/tabs/tab.html
new file mode 100644
index 0000000000..d8b06452e5
--- /dev/null
+++ b/template/tabs/tab.html
@@ -0,0 +1,3 @@
+
+ {{heading}}
+
diff --git a/template/tabs/tabs.html b/template/tabs/tabs.html
deleted file mode 100644
index 27bec3274e..0000000000
--- a/template/tabs/tabs.html
+++ /dev/null
@@ -1,8 +0,0 @@
-
diff --git a/template/tabs/tabset.html b/template/tabs/tabset.html
new file mode 100644
index 0000000000..08d3212835
--- /dev/null
+++ b/template/tabs/tabset.html
@@ -0,0 +1,12 @@
+
+