| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293 |
- /**
- * @ngdoc overview
- * @name ui.bootstrap.tabs
- *
- * @description
- * AngularJS version of the tabs directive.
- */
- angular.module('ui.bootstrap.tabs', [])
- .controller('TabsetController', ['$scope', function TabsetCtrl($scope) {
- var ctrl = this,
- tabs = ctrl.tabs = $scope.tabs = [];
- ctrl.select = function(selectedTab) {
- angular.forEach(tabs, function(tab) {
- if (tab.active && tab !== selectedTab) {
- tab.active = false;
- tab.onDeselect();
- }
- });
- selectedTab.active = true;
- selectedTab.onSelect();
- };
- ctrl.addTab = function addTab(tab) {
- tabs.push(tab);
- // we can't run the select function on the first tab
- // since that would select it twice
- if (tabs.length === 1 && tab.active !== false) {
- tab.active = true;
- } else if (tab.active) {
- ctrl.select(tab);
- }
- else {
- tab.active = false;
- }
- };
- ctrl.removeTab = function removeTab(tab) {
- var index = tabs.indexOf(tab);
- //Select a new tab if the tab to be removed is selected and not destroyed
- if (tab.active && tabs.length > 1 && !destroyed) {
- //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);
- };
- var destroyed;
- $scope.$on('$destroy', function() {
- destroyed = true;
- });
- }])
- /**
- * @ngdoc directive
- * @name ui.bootstrap.tabs.directive:tabset
- * @restrict EA
- *
- * @description
- * Tabset is the outer container for the tabs directive
- *
- * @param {boolean=} vertical Whether or not to use vertical styling for the tabs.
- * @param {boolean=} justified Whether or not to use justified styling for the tabs.
- *
- * @example
- <example module="ui.bootstrap">
- <file name="index.html">
- <tabset>
- <tab heading="Tab 1"><b>First</b> Content!</tab>
- <tab heading="Tab 2"><i>Second</i> Content!</tab>
- </tabset>
- <hr />
- <tabset vertical="true">
- <tab heading="Vertical Tab 1"><b>First</b> Vertical Content!</tab>
- <tab heading="Vertical Tab 2"><i>Second</i> Vertical Content!</tab>
- </tabset>
- <tabset justified="true">
- <tab heading="Justified Tab 1"><b>First</b> Justified Content!</tab>
- <tab heading="Justified Tab 2"><i>Second</i> Justified Content!</tab>
- </tabset>
- </file>
- </example>
- */
- .directive('tabset', function() {
- return {
- restrict: 'EA',
- transclude: true,
- replace: true,
- scope: {
- type: '@'
- },
- controller: 'TabsetController',
- templateUrl: 'app/partials/bootstrap/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;
- }
- };
- })
- /**
- * @ngdoc directive
- * @name ui.bootstrap.tabs.directive:tab
- * @restrict EA
- *
- * @param {string=} heading The visible heading, or title, of the tab. Set HTML headings with {@link ui.bootstrap.tabs.directive:tabHeading tabHeading}.
- * @param {string=} select An expression to evaluate when the tab is selected.
- * @param {boolean=} active A binding, telling whether or not this tab is selected.
- * @param {boolean=} disabled A binding, telling whether or not this tab is disabled.
- *
- * @description
- * Creates a tab with a heading and content. Must be placed within a {@link ui.bootstrap.tabs.directive:tabset tabset}.
- *
- * @example
- <example module="ui.bootstrap">
- <file name="index.html">
- <div ng-controller="TabsDemoCtrl">
- <button class="btn btn-small" ng-click="items[0].active = true">
- Select item 1, using active binding
- </button>
- <button class="btn btn-small" ng-click="items[1].disabled = !items[1].disabled">
- Enable/disable item 2, using disabled binding
- </button>
- <br />
- <tabset>
- <tab heading="Tab 1">First Tab</tab>
- <tab select="alertMe()">
- <tab-heading><i class="icon-bell"></i> Alert me!</tab-heading>
- Second Tab, with alert callback and html heading!
- </tab>
- <tab ng-repeat="item in items"
- heading="{{item.title}}"
- disabled="item.disabled"
- active="item.active">
- {{item.content}}
- </tab>
- </tabset>
- </div>
- </file>
- <file name="script.js">
- function TabsDemoCtrl($scope) {
- $scope.items = [
- { title:"Dynamic Title 1", content:"Dynamic Item 0" },
- { title:"Dynamic Title 2", content:"Dynamic Item 1", disabled: true }
- ];
- $scope.alertMe = function() {
- setTimeout(function() {
- alert("You've selected the alert tab!");
- });
- };
- };
- </file>
- </example>
- */
- /**
- * @ngdoc directive
- * @name ui.bootstrap.tabs.directive:tabHeading
- * @restrict EA
- *
- * @description
- * Creates an HTML heading for a {@link ui.bootstrap.tabs.directive:tab tab}. Must be placed as a child of a tab element.
- *
- * @example
- <example module="ui.bootstrap">
- <file name="index.html">
- <tabset>
- <tab>
- <tab-heading><b>HTML</b> in my titles?!</tab-heading>
- And some content, too!
- </tab>
- <tab>
- <tab-heading><i class="icon-heart"></i> Icon heading?!?</tab-heading>
- That's right.
- </tab>
- </tabset>
- </file>
- </example>
- */
- .directive('tab', ['$parse', '$log', function($parse, $log) {
- return {
- require: '^tabset',
- restrict: 'EA',
- replace: true,
- templateUrl: 'app/partials/bootstrap/tab.html',
- transclude: true,
- scope: {
- active: '=?',
- heading: '@',
- 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
- },
- compile: function(elm, attrs, transclude) {
- return function postLink(scope, elm, attrs, tabsetCtrl) {
- scope.$watch('active', function(active) {
- if (active) {
- tabsetCtrl.select(scope);
- }
- });
- scope.disabled = false;
- if ( attrs.disable ) {
- scope.$parent.$watch($parse(attrs.disable), function(value) {
- scope.disabled = !! value;
- });
- }
- // Deprecation support of "disabled" parameter
- // fix(tab): IE9 disabled attr renders grey text on enabled tab #2677
- // This code is duplicated from the lines above to make it easy to remove once
- // the feature has been completely deprecated
- if ( attrs.disabled ) {
- $log.warn('Use of "disabled" attribute has been deprecated, please use "disable"');
- scope.$parent.$watch($parse(attrs.disabled), function(value) {
- scope.disabled = !! value;
- });
- }
- scope.select = function() {
- if ( !scope.disabled ) {
- scope.active = true;
- }
- };
- 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('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);
- }
- });
- }
- };
- }])
- .directive('tabContentTransclude', function() {
- return {
- restrict: 'A',
- require: '^tabset',
- link: function(scope, elm, attrs) {
- var tab = scope.$eval(attrs.tabContentTransclude);
- //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('tab-heading') ||
- node.hasAttribute('data-tab-heading') ||
- node.tagName.toLowerCase() === 'tab-heading' ||
- node.tagName.toLowerCase() === 'data-tab-heading'
- );
- }
- })
- ;
|