Files

165 lines
4.5 KiB
JavaScript

/**
* angular-strap
* @version v2.1.2 - 2014-10-19
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
*/
'use strict';
angular.module('mgcrea.ngStrap.tab', [])
.provider('$tab', function() {
var defaults = this.defaults = {
animation: 'am-fade',
template: 'tab/tab.tpl.html',
navClass: 'nav-tabs',
activeClass: 'active'
};
var controller = this.controller = function($scope, $element, $attrs) {
var self = this;
// Attributes options
self.$options = angular.copy(defaults);
angular.forEach(['animation', 'navClass', 'activeClass'], function(key) {
if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];
});
// Publish options on scope
$scope.$navClass = self.$options.navClass;
$scope.$activeClass = self.$options.activeClass;
self.$panes = $scope.$panes = [];
self.$viewChangeListeners = [];
self.$push = function(pane) {
self.$panes.push(pane);
};
self.$remove = function(pane) {
var index = self.$panes.indexOf(pane);
var activeIndex = self.$panes.$active;
// remove pane from $panes array
self.$panes.splice(index, 1);
if (index < activeIndex) {
// we removed a pane before the active pane, so we need to
// decrement the active pane index
activeIndex--;
}
else if (index === activeIndex && activeIndex === self.$panes.length) {
// we remove the active pane and it was the one at the end,
// so select the previous one
activeIndex--;
}
self.$setActive(activeIndex);
};
self.$panes.$active = 0;
self.$setActive = $scope.$setActive = function(value) {
self.$panes.$active = value;
self.$viewChangeListeners.forEach(function(fn) {
fn();
});
};
};
this.$get = function() {
var $tab = {};
$tab.defaults = defaults;
$tab.controller = controller;
return $tab;
};
})
.directive('bsTabs', ["$window", "$animate", "$tab", function($window, $animate, $tab) {
var defaults = $tab.defaults;
return {
require: ['?ngModel', 'bsTabs'],
transclude: true,
scope: true,
controller: ['$scope', '$element', '$attrs', $tab.controller],
templateUrl: function(element, attr) {
return attr.template || defaults.template;
},
link: function postLink(scope, element, attrs, controllers) {
var ngModelCtrl = controllers[0];
var bsTabsCtrl = controllers[1];
if(ngModelCtrl) {
// Update the modelValue following
bsTabsCtrl.$viewChangeListeners.push(function() {
ngModelCtrl.$setViewValue(bsTabsCtrl.$panes.$active);
});
// modelValue -> $formatters -> viewValue
ngModelCtrl.$formatters.push(function(modelValue) {
// console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);
bsTabsCtrl.$setActive(modelValue * 1);
return modelValue;
});
}
}
};
}])
.directive('bsPane', ["$window", "$animate", "$sce", function($window, $animate, $sce) {
return {
require: ['^?ngModel', '^bsTabs'],
scope: true,
link: function postLink(scope, element, attrs, controllers) {
var ngModelCtrl = controllers[0];
var bsTabsCtrl = controllers[1];
// Add base class
element.addClass('tab-pane');
// Observe title attribute for change
attrs.$observe('title', function(newValue, oldValue) {
scope.title = $sce.trustAsHtml(newValue);
});
// Add animation class
if(bsTabsCtrl.$options.animation) {
element.addClass(bsTabsCtrl.$options.animation);
}
// Push pane to parent bsTabs controller
bsTabsCtrl.$push(scope);
// remove pane from tab controller when pane is destroyed
scope.$on('$destroy', function() {
bsTabsCtrl.$remove(scope);
});
function render() {
var index = bsTabsCtrl.$panes.indexOf(scope);
var active = bsTabsCtrl.$panes.$active;
$animate[index === active ? 'addClass' : 'removeClass'](element, bsTabsCtrl.$options.activeClass);
}
bsTabsCtrl.$viewChangeListeners.push(function() {
render();
});
render();
}
};
}]);