UNPKG

angular-ui-bootstrap

Version:

Native AngularJS (Angular) directives for Bootstrap

237 lines (211 loc) 6.3 kB
angular.module('ui.bootstrap.tabs', []) .controller('UibTabsetController', ['$scope', function ($scope) { var ctrl = this, oldIndex; ctrl.tabs = []; ctrl.select = function(index, evt) { if (!destroyed) { var previousIndex = findTabIndex(oldIndex); var previousSelected = ctrl.tabs[previousIndex]; if (previousSelected) { previousSelected.tab.onDeselect({ $event: evt, $selectedIndex: index }); if (evt && evt.isDefaultPrevented()) { return; } previousSelected.tab.active = false; } var selected = ctrl.tabs[index]; if (selected) { selected.tab.onSelect({ $event: evt }); selected.tab.active = true; ctrl.active = selected.index; oldIndex = selected.index; } else if (!selected && angular.isDefined(oldIndex)) { ctrl.active = null; oldIndex = null; } } }; ctrl.addTab = function addTab(tab) { ctrl.tabs.push({ tab: tab, index: tab.index }); ctrl.tabs.sort(function(t1, t2) { if (t1.index > t2.index) { return 1; } if (t1.index < t2.index) { return -1; } return 0; }); if (tab.index === ctrl.active || !angular.isDefined(ctrl.active) && ctrl.tabs.length === 1) { var newActiveIndex = findTabIndex(tab.index); ctrl.select(newActiveIndex); } }; ctrl.removeTab = function removeTab(tab) { var index; for (var i = 0; i < ctrl.tabs.length; i++) { if (ctrl.tabs[i].tab === tab) { index = i; break; } } if (ctrl.tabs[index].index === ctrl.active) { var newActiveTabIndex = index === ctrl.tabs.length - 1 ? index - 1 : index + 1 % ctrl.tabs.length; ctrl.select(newActiveTabIndex); } ctrl.tabs.splice(index, 1); }; $scope.$watch('tabset.active', function(val) { if (angular.isDefined(val) && val !== oldIndex) { ctrl.select(findTabIndex(val)); } }); var destroyed; $scope.$on('$destroy', function() { destroyed = true; }); function findTabIndex(index) { for (var i = 0; i < ctrl.tabs.length; i++) { if (ctrl.tabs[i].index === index) { return i; } } } }]) .directive('uibTabset', function() { return { transclude: true, replace: true, scope: {}, bindToController: { active: '=?', type: '@' }, controller: 'UibTabsetController', controllerAs: 'tabset', templateUrl: function(element, attrs) { return attrs.templateUrl || 'uib/template/tabs/tabset.html'; }, link: function(scope, element, attrs) { scope.vertical = angular.isDefined(attrs.vertical) ? scope.$parent.$eval(attrs.vertical) : false; scope.justified = angular.isDefined(attrs.justified) ? scope.$parent.$eval(attrs.justified) : false; } }; }) .directive('uibTab', ['$parse', function($parse) { return { require: '^uibTabset', replace: true, templateUrl: function(element, attrs) { return attrs.templateUrl || 'uib/template/tabs/tab.html'; }, transclude: true, scope: { heading: '@', index: '=?', classes: '@?', onSelect: '&select', //This callback is called in contentHeadingTransclude //once it inserts the tab's content into the dom onDeselect: '&deselect' }, controller: function() { //Empty controller so other directives can require being 'under' a tab }, controllerAs: 'tab', link: function(scope, elm, attrs, tabsetCtrl, transclude) { scope.disabled = false; if (attrs.disable) { scope.$parent.$watch($parse(attrs.disable), function(value) { scope.disabled = !! value; }); } if (angular.isUndefined(attrs.index)) { if (tabsetCtrl.tabs && tabsetCtrl.tabs.length) { scope.index = Math.max.apply(null, tabsetCtrl.tabs.map(function(t) { return t.index; })) + 1; } else { scope.index = 0; } } if (angular.isUndefined(attrs.classes)) { scope.classes = ''; } scope.select = function(evt) { if (!scope.disabled) { var index; for (var i = 0; i < tabsetCtrl.tabs.length; i++) { if (tabsetCtrl.tabs[i].tab === scope) { index = i; break; } } tabsetCtrl.select(index, evt); } }; tabsetCtrl.addTab(scope); scope.$on('$destroy', function() { tabsetCtrl.removeTab(scope); }); //We need to transclude later, once the content container is ready. //when this link happens, we're inside a tab heading. scope.$transcludeFn = transclude; } }; }]) .directive('uibTabHeadingTransclude', function() { return { restrict: 'A', require: '^uibTab', link: function(scope, elm) { scope.$watch('headingElement', function updateHeadingElement(heading) { if (heading) { elm.html(''); elm.append(heading); } }); } }; }) .directive('uibTabContentTransclude', function() { return { restrict: 'A', require: '^uibTabset', link: function(scope, elm, attrs) { var tab = scope.$eval(attrs.uibTabContentTransclude).tab; //Now our tab is ready to be transcluded: both the tab heading area //and the tab content area are loaded. Transclude 'em both. tab.$transcludeFn(tab.$parent, function(contents) { angular.forEach(contents, function(node) { if (isTabHeading(node)) { //Let tabHeadingTransclude know. tab.headingElement = node; } else { elm.append(node); } }); }); } }; function isTabHeading(node) { return node.tagName && ( node.hasAttribute('uib-tab-heading') || node.hasAttribute('data-uib-tab-heading') || node.hasAttribute('x-uib-tab-heading') || node.tagName.toLowerCase() === 'uib-tab-heading' || node.tagName.toLowerCase() === 'data-uib-tab-heading' || node.tagName.toLowerCase() === 'x-uib-tab-heading' || node.tagName.toLowerCase() === 'uib:tab-heading' ); } });