diff --git a/dist/angular-strap.js b/dist/angular-strap.js
index ce7b5170a..76747ee16 100644
--- a/dist/angular-strap.js
+++ b/dist/angular-strap.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
@@ -383,6 +383,95 @@ angular.module('mgcrea.ngStrap.alert', ['mgcrea.ngStrap.modal'])
}]);
+// Source: aside.js
+angular.module('mgcrea.ngStrap.aside', ['mgcrea.ngStrap.modal'])
+
+ .provider('$aside', function() {
+
+ var defaults = this.defaults = {
+ animation: 'am-fade-and-slide-right',
+ prefixClass: 'aside',
+ prefixEvent: 'aside',
+ placement: 'right',
+ template: 'aside/aside.tpl.html',
+ contentTemplate: false,
+ container: false,
+ element: null,
+ backdrop: true,
+ keyboard: true,
+ html: false,
+ show: true
+ };
+
+ this.$get = ["$modal", function($modal) {
+
+ function AsideFactory(config) {
+
+ var $aside = {};
+
+ // Common vars
+ var options = angular.extend({}, defaults, config);
+
+ $aside = $modal(options);
+
+ return $aside;
+
+ }
+
+ return AsideFactory;
+
+ }];
+
+ })
+
+ .directive('bsAside', ["$window", "$sce", "$aside", function($window, $sce, $aside) {
+
+ var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;
+
+ return {
+ restrict: 'EAC',
+ scope: true,
+ link: function postLink(scope, element, attr, transclusion) {
+ // Directive options
+ var options = {scope: scope, element: element, show: false};
+ angular.forEach(['template', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation'], function(key) {
+ if(angular.isDefined(attr[key])) options[key] = attr[key];
+ });
+
+ // Support scope as data-attrs
+ angular.forEach(['title', 'content'], function(key) {
+ attr[key] && attr.$observe(key, function(newValue, oldValue) {
+ scope[key] = $sce.trustAsHtml(newValue);
+ });
+ });
+
+ // Support scope as an object
+ attr.bsAside && scope.$watch(attr.bsAside, function(newValue, oldValue) {
+ if(angular.isObject(newValue)) {
+ angular.extend(scope, newValue);
+ } else {
+ scope.content = newValue;
+ }
+ }, true);
+
+ // Initialize aside
+ var aside = $aside(options);
+
+ // Trigger
+ element.on(attr.trigger || 'click', aside.toggle);
+
+ // Garbage collection
+ scope.$on('$destroy', function() {
+ if (aside) aside.destroy();
+ options = null;
+ aside = null;
+ });
+
+ }
+ };
+
+ }]);
+
// Source: button.js
angular.module('mgcrea.ngStrap.button', [])
@@ -553,902 +642,902 @@ angular.module('mgcrea.ngStrap.button', [])
}]);
-// Source: datepicker.js
-angular.module('mgcrea.ngStrap.datepicker', [
- 'mgcrea.ngStrap.helpers.dateParser',
- 'mgcrea.ngStrap.helpers.dateFormatter',
- 'mgcrea.ngStrap.tooltip'])
+// Source: collapse.js
+angular.module('mgcrea.ngStrap.collapse', [])
- .provider('$datepicker', function() {
+ .provider('$collapse', function() {
var defaults = this.defaults = {
- animation: 'am-fade',
- prefixClass: 'datepicker',
- placement: 'bottom-left',
- template: 'datepicker/datepicker.tpl.html',
- trigger: 'focus',
- container: false,
- keyboard: true,
- html: false,
- delay: 0,
- // lang: $locale.id,
- useNative: false,
- dateType: 'date',
- dateFormat: 'shortDate',
- modelDateFormat: null,
- dayFormat: 'dd',
- monthFormat: 'MMM',
- yearFormat: 'yyyy',
- monthTitleFormat: 'MMMM yyyy',
- yearTitleFormat: 'yyyy',
- strictFormat: false,
- autoclose: false,
- minDate: -Infinity,
- maxDate: +Infinity,
- startView: 0,
- minView: 0,
- startWeek: 0,
- daysOfWeekDisabled: '',
- iconLeft: 'glyphicon glyphicon-chevron-left',
- iconRight: 'glyphicon glyphicon-chevron-right'
+ animation: 'am-collapse',
+ disallowToggle: false,
+ activeClass: 'in',
+ startCollapsed: false,
+ allowMultiple: false
};
- this.$get = ["$window", "$document", "$rootScope", "$sce", "$dateFormatter", "datepickerViews", "$tooltip", "$timeout", function($window, $document, $rootScope, $sce, $dateFormatter, datepickerViews, $tooltip, $timeout) {
-
- var bodyEl = angular.element($window.document.body);
- var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);
- var isTouch = ('createTouch' in $window.document) && isNative;
- if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();
+ var controller = this.controller = function($scope, $element, $attrs) {
+ var self = this;
- function DatepickerFactory(element, controller, config) {
+ // Attributes options
+ self.$options = angular.copy(defaults);
+ angular.forEach(['animation', 'disallowToggle', 'activeClass', 'startCollapsed', 'allowMultiple'], function (key) {
+ if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];
+ });
- var $datepicker = $tooltip(element, angular.extend({}, defaults, config));
- var parentScope = config.scope;
- var options = $datepicker.$options;
- var scope = $datepicker.$scope;
- if(options.startView) options.startView -= options.minView;
+ self.$toggles = [];
+ self.$targets = [];
- // View vars
+ self.$viewChangeListeners = [];
- var pickerViews = datepickerViews($datepicker);
- $datepicker.$views = pickerViews.views;
- var viewDate = pickerViews.viewDate;
- scope.$mode = options.startView;
- scope.$iconLeft = options.iconLeft;
- scope.$iconRight = options.iconRight;
- var $picker = $datepicker.$views[scope.$mode];
+ self.$registerToggle = function(element) {
+ self.$toggles.push(element);
+ };
+ self.$registerTarget = function(element) {
+ self.$targets.push(element);
+ };
- // Scope methods
+ self.$unregisterToggle = function(element) {
+ var index = self.$toggles.indexOf(element);
+ // remove toggle from $toggles array
+ self.$toggles.splice(index, 1);
+ };
+ self.$unregisterTarget = function(element) {
+ var index = self.$targets.indexOf(element);
- scope.$select = function(date) {
- $datepicker.select(date);
- };
- scope.$selectPane = function(value) {
- $datepicker.$selectPane(value);
- };
- scope.$toggleMode = function() {
- $datepicker.setMode((scope.$mode + 1) % $datepicker.$views.length);
- };
+ // remove element from $targets array
+ self.$targets.splice(index, 1);
- // Public methods
+ if (self.$options.allowMultiple) {
+ // remove target index from $active array values
+ deactivateItem(element);
+ }
- $datepicker.update = function(date) {
- // console.warn('$datepicker.update() newValue=%o', date);
- if(angular.isDate(date) && !isNaN(date.getTime())) {
- $datepicker.$date = date;
- $picker.update.call($picker, date);
- }
- // Build only if pristine
- $datepicker.$build(true);
- };
+ // fix active item indexes
+ fixActiveItemIndexes(index);
- $datepicker.updateDisabledDates = function(dateRanges) {
- options.disabledDateRanges = dateRanges;
- for(var i = 0, l = scope.rows.length; i < l; i++) {
- angular.forEach(scope.rows[i], $datepicker.$setDisabledEl);
- }
- };
+ self.$viewChangeListeners.forEach(function(fn) {
+ fn();
+ });
+ };
- $datepicker.select = function(date, keep) {
- // console.warn('$datepicker.select', date, scope.$mode);
- if(!angular.isDate(controller.$dateValue)) controller.$dateValue = new Date(date);
- if(!scope.$mode || keep) {
- controller.$setViewValue(angular.copy(date));
- controller.$render();
- if(options.autoclose && !keep) {
- $timeout(function() { $datepicker.hide(true); });
- }
- } else {
- angular.extend(viewDate, {year: date.getFullYear(), month: date.getMonth(), date: date.getDate()});
- $datepicker.setMode(scope.$mode - 1);
- $datepicker.$build();
- }
- };
+ // use array to store all the currently open panels
+ self.$targets.$active = !self.$options.startCollapsed ? [0] : [];
+ self.$setActive = $scope.$setActive = function(value) {
+ if(angular.isArray(value)) {
+ self.$targets.$active = angular.copy(value);
+ }
+ else if(!self.$options.disallowToggle) {
+ // toogle element active status
+ isActive(value) ? deactivateItem(value) : activateItem(value);
+ } else {
+ activateItem(value);
+ }
- $datepicker.setMode = function(mode) {
- // console.warn('$datepicker.setMode', mode);
- scope.$mode = mode;
- $picker = $datepicker.$views[scope.$mode];
- $datepicker.$build();
- };
+ self.$viewChangeListeners.forEach(function(fn) {
+ fn();
+ });
+ };
- // Protected methods
+ self.$activeIndexes = function() {
+ return self.$options.allowMultiple ? self.$targets.$active :
+ self.$targets.$active.length === 1 ? self.$targets.$active[0] : -1;
+ };
- $datepicker.$build = function(pristine) {
- // console.warn('$datepicker.$build() viewDate=%o', viewDate);
- if(pristine === true && $picker.built) return;
- if(pristine === false && !$picker.built) return;
- $picker.build.call($picker);
- };
+ function fixActiveItemIndexes(index) {
+ // item with index was removed, so we
+ // need to adjust other items index values
+ var activeIndexes = self.$targets.$active;
+ for(var i = 0; i < activeIndexes.length; i++) {
+ if (index < activeIndexes[i]) {
+ activeIndexes[i] = activeIndexes[i] - 1;
+ }
- $datepicker.$updateSelected = function() {
- for(var i = 0, l = scope.rows.length; i < l; i++) {
- angular.forEach(scope.rows[i], updateSelected);
+ // the last item is active, so we need to
+ // adjust its index
+ if (activeIndexes[i] === self.$targets.length) {
+ activeIndexes[i] = self.$targets.length - 1;
}
- };
+ }
+ }
- $datepicker.$isSelected = function(date) {
- return $picker.isSelected(date);
- };
+ function isActive(value) {
+ var activeItems = self.$targets.$active;
+ return activeItems.indexOf(value) === -1 ? false : true;
+ }
- $datepicker.$setDisabledEl = function(el) {
- el.disabled = $picker.isDisabled(el.date);
- };
+ function deactivateItem(value) {
+ var index = self.$targets.$active.indexOf(value);
+ if (index !== -1) {
+ self.$targets.$active.splice(index, 1);
+ }
+ }
- $datepicker.$selectPane = function(value) {
- var steps = $picker.steps;
- // set targetDate to first day of month to avoid problems with
- // date values rollover. This assumes the viewDate does not
- // depend on the day of the month
- var targetDate = new Date(Date.UTC(viewDate.year + ((steps.year || 0) * value), viewDate.month + ((steps.month || 0) * value), 1));
- angular.extend(viewDate, {year: targetDate.getUTCFullYear(), month: targetDate.getUTCMonth(), date: targetDate.getUTCDate()});
- $datepicker.$build();
- };
+ function activateItem(value) {
+ if (!self.$options.allowMultiple) {
+ // remove current selected item
+ self.$targets.$active.splice(0, 1);
+ }
- $datepicker.$onMouseDown = function(evt) {
- // Prevent blur on mousedown on .dropdown-menu
- evt.preventDefault();
- evt.stopPropagation();
- // Emulate click for mobile devices
- if(isTouch) {
- var targetEl = angular.element(evt.target);
- if(targetEl[0].nodeName.toLowerCase() !== 'button') {
- targetEl = targetEl.parent();
- }
- targetEl.triggerHandler('click');
- }
- };
+ if (self.$targets.$active.indexOf(value) === -1) {
+ self.$targets.$active.push(value);
+ }
+ }
- $datepicker.$onKeyDown = function(evt) {
- if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;
- evt.preventDefault();
- evt.stopPropagation();
+ };
- if(evt.keyCode === 13) {
- if(!scope.$mode) {
- return $datepicker.hide(true);
- } else {
- return scope.$apply(function() { $datepicker.setMode(scope.$mode - 1); });
- }
- }
+ this.$get = function() {
+ var $collapse = {};
+ $collapse.defaults = defaults;
+ $collapse.controller = controller;
+ return $collapse;
+ };
- // Navigate with keyboard
- $picker.onKeyDown(evt);
- parentScope.$digest();
- };
+ })
- // Private
+ .directive('bsCollapse', ["$window", "$animate", "$collapse", function($window, $animate, $collapse) {
- function updateSelected(el) {
- el.selected = $datepicker.$isSelected(el.date);
- }
+ var defaults = $collapse.defaults;
- function focusElement() {
- element[0].focus();
- }
+ return {
+ require: ['?ngModel', 'bsCollapse'],
+ controller: ['$scope', '$element', '$attrs', $collapse.controller],
+ link: function postLink(scope, element, attrs, controllers) {
- // Overrides
+ var ngModelCtrl = controllers[0];
+ var bsCollapseCtrl = controllers[1];
- var _init = $datepicker.init;
- $datepicker.init = function() {
- if(isNative && options.useNative) {
- element.prop('type', 'date');
- element.css('-webkit-appearance', 'textfield');
- return;
- } else if(isTouch) {
- element.prop('type', 'text');
- element.attr('readonly', 'true');
- element.on('click', focusElement);
- }
- _init();
- };
+ if(ngModelCtrl) {
- var _destroy = $datepicker.destroy;
- $datepicker.destroy = function() {
- if(isNative && options.useNative) {
- element.off('click', focusElement);
- }
- _destroy();
- };
+ // Update the modelValue following
+ bsCollapseCtrl.$viewChangeListeners.push(function() {
+ ngModelCtrl.$setViewValue(bsCollapseCtrl.$activeIndexes());
+ });
- var _show = $datepicker.show;
- $datepicker.show = function() {
- _show();
- // use timeout to hookup the events to prevent
- // event bubbling from being processed imediately.
- $timeout(function() {
- $datepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);
- if(options.keyboard) {
- element.on('keydown', $datepicker.$onKeyDown);
+ // modelValue -> $formatters -> viewValue
+ ngModelCtrl.$formatters.push(function(modelValue) {
+ // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);
+ if (angular.isArray(modelValue)) {
+ // model value is an array, so just replace
+ // the active items directly
+ bsCollapseCtrl.$setActive(modelValue);
}
- }, 0, false);
- };
+ else {
+ var activeIndexes = bsCollapseCtrl.$activeIndexes();
- var _hide = $datepicker.hide;
- $datepicker.hide = function(blur) {
- if(!$datepicker.$isShown) return;
- $datepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);
- if(options.keyboard) {
- element.off('keydown', $datepicker.$onKeyDown);
- }
- _hide(blur);
- };
+ if (angular.isArray(activeIndexes)) {
+ // we have an array of selected indexes
+ if (activeIndexes.indexOf(modelValue * 1) === -1) {
+ // item with modelValue index is not active
+ bsCollapseCtrl.$setActive(modelValue * 1);
+ }
+ }
+ else if (activeIndexes !== modelValue * 1) {
+ bsCollapseCtrl.$setActive(modelValue * 1);
+ }
+ }
+ return modelValue;
+ });
- return $datepicker;
+ }
}
+ };
- DatepickerFactory.defaults = defaults;
- return DatepickerFactory;
+ }])
- }];
+ .directive('bsCollapseToggle', function() {
- })
+ return {
+ require: ['^?ngModel', '^bsCollapse'],
+ link: function postLink(scope, element, attrs, controllers) {
- .directive('bsDatepicker', ["$window", "$parse", "$q", "$dateFormatter", "$dateParser", "$datepicker", function($window, $parse, $q, $dateFormatter, $dateParser, $datepicker) {
+ var ngModelCtrl = controllers[0];
+ var bsCollapseCtrl = controllers[1];
- var defaults = $datepicker.defaults;
- var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);
+ // Add base attr
+ element.attr('data-toggle', 'collapse');
- return {
- restrict: 'EAC',
- require: 'ngModel',
- link: function postLink(scope, element, attr, controller) {
+ // Push pane to parent bsCollapse controller
+ bsCollapseCtrl.$registerToggle(element);
- // Directive options
- var options = {scope: scope, controller: controller};
- angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'dateType', 'dateFormat', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled'], function(key) {
- if(angular.isDefined(attr[key])) options[key] = attr[key];
+ // remove toggle from collapse controller when toggle is destroyed
+ scope.$on('$destroy', function() {
+ bsCollapseCtrl.$unregisterToggle(element);
});
- // Visibility binding support
- attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {
- if(!datepicker || !angular.isDefined(newValue)) return;
- if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(datepicker),?/i);
- newValue === true ? datepicker.show() : datepicker.hide();
+ element.on('click', function() {
+ var index = attrs.bsCollapseToggle || bsCollapseCtrl.$toggles.indexOf(element);
+ bsCollapseCtrl.$setActive(index * 1);
+ scope.$apply();
});
- // Initialize datepicker
- var datepicker = $datepicker(element, controller, options);
- options = datepicker.$options;
- // Set expected iOS format
- if(isNative && options.useNative) options.dateFormat = 'yyyy-MM-dd';
+ }
+ };
- var lang = options.lang;
+ })
- var formatDate = function(date, format) {
- return $dateFormatter.formatDate(date, format, lang);
- };
-
- var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});
+ .directive('bsCollapseTarget', ["$animate", function($animate) {
- // Observe attributes for changes
- angular.forEach(['minDate', 'maxDate'], function(key) {
- // console.warn('attr.$observe(%s)', key, attr[key]);
- angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {
- // console.warn('attr.$observe(%s)=%o', key, newValue);
- datepicker.$options[key] = dateParser.getDateForAttribute(key, newValue);
- // Build only if dirty
- !isNaN(datepicker.$options[key]) && datepicker.$build(false);
- validateAgainstMinMaxDate(controller.$dateValue);
- });
- });
+ return {
+ require: ['^?ngModel', '^bsCollapse'],
+ // scope: true,
+ link: function postLink(scope, element, attrs, controllers) {
- // Watch model for changes
- scope.$watch(attr.ngModel, function(newValue, oldValue) {
- datepicker.update(controller.$dateValue);
- }, true);
+ var ngModelCtrl = controllers[0];
+ var bsCollapseCtrl = controllers[1];
- // Normalize undefined/null/empty array,
- // so that we don't treat changing from undefined->null as a change.
- function normalizeDateRanges(ranges) {
- if (!ranges || !ranges.length) return null;
- return ranges;
- }
-
- if (angular.isDefined(attr.disabledDates)) {
- scope.$watch(attr.disabledDates, function(disabledRanges, previousValue) {
- disabledRanges = normalizeDateRanges(disabledRanges);
- previousValue = normalizeDateRanges(previousValue);
+ // Add base class
+ element.addClass('collapse');
- if (disabledRanges) {
- datepicker.updateDisabledDates(disabledRanges);
- }
- });
+ // Add animation class
+ if(bsCollapseCtrl.$options.animation) {
+ element.addClass(bsCollapseCtrl.$options.animation);
}
- function validateAgainstMinMaxDate(parsedDate) {
- if (!angular.isDate(parsedDate)) return;
- var isMinValid = isNaN(datepicker.$options.minDate) || parsedDate.getTime() >= datepicker.$options.minDate;
- var isMaxValid = isNaN(datepicker.$options.maxDate) || parsedDate.getTime() <= datepicker.$options.maxDate;
- var isValid = isMinValid && isMaxValid;
- controller.$setValidity('date', isValid);
- controller.$setValidity('min', isMinValid);
- controller.$setValidity('max', isMaxValid);
- // Only update the model when we have a valid date
- if(isValid) controller.$dateValue = parsedDate;
- }
+ // Push pane to parent bsCollapse controller
+ bsCollapseCtrl.$registerTarget(element);
- // viewValue -> $parsers -> modelValue
- controller.$parsers.unshift(function(viewValue) {
- // console.warn('$parser("%s"): viewValue=%o', element.attr('ng-model'), viewValue);
- // Null values should correctly reset the model value & validity
- if(!viewValue) {
- controller.$setValidity('date', true);
- // BREAKING CHANGE:
- // return null (not undefined) when input value is empty, so angularjs 1.3
- // ngModelController can go ahead and run validators, like ngRequired
- return null;
- }
- var parsedDate = dateParser.parse(viewValue, controller.$dateValue);
- if(!parsedDate || isNaN(parsedDate.getTime())) {
- controller.$setValidity('date', false);
- // return undefined, causes ngModelController to
- // invalidate model value
- return;
- } else {
- validateAgainstMinMaxDate(parsedDate);
- }
- if(options.dateType === 'string') {
- return formatDate(parsedDate, options.modelDateFormat || options.dateFormat);
- } else if(options.dateType === 'number') {
- return controller.$dateValue.getTime();
- } else if(options.dateType === 'unix') {
- return controller.$dateValue.getTime() / 1000;
- } else if(options.dateType === 'iso') {
- return controller.$dateValue.toISOString();
- } else {
- return new Date(controller.$dateValue);
- }
+ // remove pane target from collapse controller when target is destroyed
+ scope.$on('$destroy', function() {
+ bsCollapseCtrl.$unregisterTarget(element);
});
- // modelValue -> $formatters -> viewValue
- controller.$formatters.push(function(modelValue) {
- // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);
- var date;
- if(angular.isUndefined(modelValue) || modelValue === null) {
- date = NaN;
- } else if(angular.isDate(modelValue)) {
- date = modelValue;
- } else if(options.dateType === 'string') {
- date = dateParser.parse(modelValue, null, options.modelDateFormat);
- } else if(options.dateType === 'unix') {
- date = new Date(modelValue * 1000);
- } else {
- date = new Date(modelValue);
+ function render() {
+ var index = bsCollapseCtrl.$targets.indexOf(element);
+ var active = bsCollapseCtrl.$activeIndexes();
+ var action = 'removeClass';
+ if (angular.isArray(active)) {
+ if (active.indexOf(index) !== -1) {
+ action = 'addClass';
+ }
+ }
+ else if (index === active) {
+ action = 'addClass';
}
- // Setup default value?
- // if(isNaN(date.getTime())) {
- // var today = new Date();
- // date = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0, 0);
- // }
- controller.$dateValue = date;
- return getDateFormattedString();
- });
-
- // viewValue -> element
- controller.$render = function() {
- // console.warn('$render("%s"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);
- element.val(getDateFormattedString());
- };
- function getDateFormattedString() {
- return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.dateFormat);
+ $animate[action](element, bsCollapseCtrl.$options.activeClass);
}
- // Garbage collection
- scope.$on('$destroy', function() {
- if(datepicker) datepicker.destroy();
- options = null;
- datepicker = null;
+ bsCollapseCtrl.$viewChangeListeners.push(function() {
+ render();
});
+ render();
}
};
- }])
+ }]);
- .provider('datepickerViews', function() {
+// Source: datepicker.js
+angular.module('mgcrea.ngStrap.datepicker', [
+ 'mgcrea.ngStrap.helpers.dateParser',
+ 'mgcrea.ngStrap.helpers.dateFormatter',
+ 'mgcrea.ngStrap.tooltip'])
+
+ .provider('$datepicker', function() {
var defaults = this.defaults = {
+ animation: 'am-fade',
+ prefixClass: 'datepicker',
+ placement: 'bottom-left',
+ template: 'datepicker/datepicker.tpl.html',
+ trigger: 'focus',
+ container: false,
+ keyboard: true,
+ html: false,
+ delay: 0,
+ // lang: $locale.id,
+ useNative: false,
+ dateType: 'date',
+ dateFormat: 'shortDate',
+ modelDateFormat: null,
dayFormat: 'dd',
- daySplit: 7
+ monthFormat: 'MMM',
+ yearFormat: 'yyyy',
+ monthTitleFormat: 'MMMM yyyy',
+ yearTitleFormat: 'yyyy',
+ strictFormat: false,
+ autoclose: false,
+ minDate: -Infinity,
+ maxDate: +Infinity,
+ startView: 0,
+ minView: 0,
+ startWeek: 0,
+ daysOfWeekDisabled: '',
+ iconLeft: 'glyphicon glyphicon-chevron-left',
+ iconRight: 'glyphicon glyphicon-chevron-right'
};
- // Split array into smaller arrays
- function split(arr, size) {
- var arrays = [];
- while(arr.length > 0) {
- arrays.push(arr.splice(0, size));
- }
- return arrays;
- }
+ this.$get = ["$window", "$document", "$rootScope", "$sce", "$dateFormatter", "datepickerViews", "$tooltip", "$timeout", function($window, $document, $rootScope, $sce, $dateFormatter, datepickerViews, $tooltip, $timeout) {
- // Modulus operator
- function mod(n, m) {
- return ((n % m) + m) % m;
- }
+ var bodyEl = angular.element($window.document.body);
+ var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);
+ var isTouch = ('createTouch' in $window.document) && isNative;
+ if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();
- this.$get = ["$dateFormatter", "$dateParser", "$sce", function($dateFormatter, $dateParser, $sce) {
+ function DatepickerFactory(element, controller, config) {
- return function(picker) {
+ var $datepicker = $tooltip(element, angular.extend({}, defaults, config));
+ var parentScope = config.scope;
+ var options = $datepicker.$options;
+ var scope = $datepicker.$scope;
+ if(options.startView) options.startView -= options.minView;
- var scope = picker.$scope;
- var options = picker.$options;
+ // View vars
- var lang = options.lang;
- var formatDate = function(date, format) {
- return $dateFormatter.formatDate(date, format, lang);
- };
- var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});
+ var pickerViews = datepickerViews($datepicker);
+ $datepicker.$views = pickerViews.views;
+ var viewDate = pickerViews.viewDate;
+ scope.$mode = options.startView;
+ scope.$iconLeft = options.iconLeft;
+ scope.$iconRight = options.iconRight;
+ var $picker = $datepicker.$views[scope.$mode];
- var weekDaysMin = $dateFormatter.weekdaysShort(lang);
- var weekDaysLabels = weekDaysMin.slice(options.startWeek).concat(weekDaysMin.slice(0, options.startWeek));
- var weekDaysLabelsHtml = $sce.trustAsHtml('
' + weekDaysLabels.join(' ') + ' ');
+ // Scope methods
- var startDate = picker.$date || (options.startDate ? dateParser.getDateForAttribute('startDate', options.startDate) : new Date());
- var viewDate = {year: startDate.getFullYear(), month: startDate.getMonth(), date: startDate.getDate()};
- var timezoneOffset = startDate.getTimezoneOffset() * 6e4;
+ scope.$select = function(date) {
+ $datepicker.select(date);
+ };
+ scope.$selectPane = function(value) {
+ $datepicker.$selectPane(value);
+ };
+ scope.$toggleMode = function() {
+ $datepicker.setMode((scope.$mode + 1) % $datepicker.$views.length);
+ };
- var views = [{
- format: options.dayFormat,
- split: 7,
- steps: { month: 1 },
- update: function(date, force) {
- if(!this.built || force || date.getFullYear() !== viewDate.year || date.getMonth() !== viewDate.month) {
- angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});
- picker.$build();
- } else if(date.getDate() !== viewDate.date) {
- viewDate.date = picker.$date.getDate();
- picker.$updateSelected();
- }
- },
- build: function() {
- var firstDayOfMonth = new Date(viewDate.year, viewDate.month, 1), firstDayOfMonthOffset = firstDayOfMonth.getTimezoneOffset();
- var firstDate = new Date(+firstDayOfMonth - mod(firstDayOfMonth.getDay() - options.startWeek, 7) * 864e5), firstDateOffset = firstDate.getTimezoneOffset();
- var today = new Date().toDateString();
- // Handle daylight time switch
- if(firstDateOffset !== firstDayOfMonthOffset) firstDate = new Date(+firstDate + (firstDateOffset - firstDayOfMonthOffset) * 60e3);
- var days = [], day;
- for(var i = 0; i < 42; i++) { // < 7 * 6
- day = dateParser.daylightSavingAdjust(new Date(firstDate.getFullYear(), firstDate.getMonth(), firstDate.getDate() + i));
- days.push({date: day, isToday: day.toDateString() === today, label: formatDate(day, this.format), selected: picker.$date && this.isSelected(day), muted: day.getMonth() !== viewDate.month, disabled: this.isDisabled(day)});
- }
- scope.title = formatDate(firstDayOfMonth, options.monthTitleFormat);
- scope.showLabels = true;
- scope.labels = weekDaysLabelsHtml;
- scope.rows = split(days, this.split);
- this.built = true;
- },
- isSelected: function(date) {
- return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth() && date.getDate() === picker.$date.getDate();
- },
- isDisabled: function(date) {
- var time = date.getTime();
+ // Public methods
- // Disabled because of min/max date.
- if (time < options.minDate || time > options.maxDate) return true;
+ $datepicker.update = function(date) {
+ // console.warn('$datepicker.update() newValue=%o', date);
+ if(angular.isDate(date) && !isNaN(date.getTime())) {
+ $datepicker.$date = date;
+ $picker.update.call($picker, date);
+ }
+ // Build only if pristine
+ $datepicker.$build(true);
+ };
- // Disabled due to being a disabled day of the week
- if (options.daysOfWeekDisabled.indexOf(date.getDay()) !== -1) return true;
+ $datepicker.updateDisabledDates = function(dateRanges) {
+ options.disabledDateRanges = dateRanges;
+ for(var i = 0, l = scope.rows.length; i < l; i++) {
+ angular.forEach(scope.rows[i], $datepicker.$setDisabledEl);
+ }
+ };
- // Disabled because of disabled date range.
- if (options.disabledDateRanges) {
- for (var i = 0; i < options.disabledDateRanges.length; i++) {
- if (time >= options.disabledDateRanges[i].start && time <= options.disabledDateRanges[i].end) {
- return true;
- }
- }
- }
+ $datepicker.select = function(date, keep) {
+ // console.warn('$datepicker.select', date, scope.$mode);
+ if(!angular.isDate(controller.$dateValue)) controller.$dateValue = new Date(date);
+ if(!scope.$mode || keep) {
+ controller.$setViewValue(angular.copy(date));
+ controller.$render();
+ if(options.autoclose && !keep) {
+ $timeout(function() { $datepicker.hide(true); });
+ }
+ } else {
+ angular.extend(viewDate, {year: date.getFullYear(), month: date.getMonth(), date: date.getDate()});
+ $datepicker.setMode(scope.$mode - 1);
+ $datepicker.$build();
+ }
+ };
- return false;
- },
- onKeyDown: function(evt) {
- if (!picker.$date) {
- return;
- }
- var actualTime = picker.$date.getTime();
- var newDate;
+ $datepicker.setMode = function(mode) {
+ // console.warn('$datepicker.setMode', mode);
+ scope.$mode = mode;
+ $picker = $datepicker.$views[scope.$mode];
+ $datepicker.$build();
+ };
- if(evt.keyCode === 37) newDate = new Date(actualTime - 1 * 864e5);
- else if(evt.keyCode === 38) newDate = new Date(actualTime - 7 * 864e5);
- else if(evt.keyCode === 39) newDate = new Date(actualTime + 1 * 864e5);
- else if(evt.keyCode === 40) newDate = new Date(actualTime + 7 * 864e5);
+ // Protected methods
- if (!this.isDisabled(newDate)) picker.select(newDate, true);
- }
- }, {
- name: 'month',
- format: options.monthFormat,
- split: 4,
- steps: { year: 1 },
- update: function(date, force) {
- if(!this.built || date.getFullYear() !== viewDate.year) {
- angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});
- picker.$build();
- } else if(date.getMonth() !== viewDate.month) {
- angular.extend(viewDate, {month: picker.$date.getMonth(), date: picker.$date.getDate()});
- picker.$updateSelected();
- }
- },
- build: function() {
- var firstMonth = new Date(viewDate.year, 0, 1);
- var months = [], month;
- for (var i = 0; i < 12; i++) {
- month = new Date(viewDate.year, i, 1);
- months.push({date: month, label: formatDate(month, this.format), selected: picker.$isSelected(month), disabled: this.isDisabled(month)});
- }
- scope.title = formatDate(month, options.yearTitleFormat);
- scope.showLabels = false;
- scope.rows = split(months, this.split);
- this.built = true;
- },
- isSelected: function(date) {
- return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth();
- },
- isDisabled: function(date) {
- var lastDate = +new Date(date.getFullYear(), date.getMonth() + 1, 0);
- return lastDate < options.minDate || date.getTime() > options.maxDate;
- },
- onKeyDown: function(evt) {
- if (!picker.$date) {
- return;
- }
- var actualMonth = picker.$date.getMonth();
- var newDate = new Date(picker.$date);
+ $datepicker.$build = function(pristine) {
+ // console.warn('$datepicker.$build() viewDate=%o', viewDate);
+ if(pristine === true && $picker.built) return;
+ if(pristine === false && !$picker.built) return;
+ $picker.build.call($picker);
+ };
- if(evt.keyCode === 37) newDate.setMonth(actualMonth - 1);
- else if(evt.keyCode === 38) newDate.setMonth(actualMonth - 4);
- else if(evt.keyCode === 39) newDate.setMonth(actualMonth + 1);
- else if(evt.keyCode === 40) newDate.setMonth(actualMonth + 4);
+ $datepicker.$updateSelected = function() {
+ for(var i = 0, l = scope.rows.length; i < l; i++) {
+ angular.forEach(scope.rows[i], updateSelected);
+ }
+ };
- if (!this.isDisabled(newDate)) picker.select(newDate, true);
+ $datepicker.$isSelected = function(date) {
+ return $picker.isSelected(date);
+ };
+
+ $datepicker.$setDisabledEl = function(el) {
+ el.disabled = $picker.isDisabled(el.date);
+ };
+
+ $datepicker.$selectPane = function(value) {
+ var steps = $picker.steps;
+ // set targetDate to first day of month to avoid problems with
+ // date values rollover. This assumes the viewDate does not
+ // depend on the day of the month
+ var targetDate = new Date(Date.UTC(viewDate.year + ((steps.year || 0) * value), viewDate.month + ((steps.month || 0) * value), 1));
+ angular.extend(viewDate, {year: targetDate.getUTCFullYear(), month: targetDate.getUTCMonth(), date: targetDate.getUTCDate()});
+ $datepicker.$build();
+ };
+
+ $datepicker.$onMouseDown = function(evt) {
+ // Prevent blur on mousedown on .dropdown-menu
+ evt.preventDefault();
+ evt.stopPropagation();
+ // Emulate click for mobile devices
+ if(isTouch) {
+ var targetEl = angular.element(evt.target);
+ if(targetEl[0].nodeName.toLowerCase() !== 'button') {
+ targetEl = targetEl.parent();
}
- }, {
- name: 'year',
- format: options.yearFormat,
- split: 4,
- steps: { year: 12 },
- update: function(date, force) {
- if(!this.built || force || parseInt(date.getFullYear()/20, 10) !== parseInt(viewDate.year/20, 10)) {
- angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});
- picker.$build();
- } else if(date.getFullYear() !== viewDate.year) {
- angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});
- picker.$updateSelected();
- }
- },
- build: function() {
- var firstYear = viewDate.year - viewDate.year % (this.split * 3);
- var years = [], year;
- for (var i = 0; i < 12; i++) {
- year = new Date(firstYear + i, 0, 1);
- years.push({date: year, label: formatDate(year, this.format), selected: picker.$isSelected(year), disabled: this.isDisabled(year)});
- }
- scope.title = years[0].label + '-' + years[years.length - 1].label;
- scope.showLabels = false;
- scope.rows = split(years, this.split);
- this.built = true;
- },
- isSelected: function(date) {
- return picker.$date && date.getFullYear() === picker.$date.getFullYear();
- },
- isDisabled: function(date) {
- var lastDate = +new Date(date.getFullYear() + 1, 0, 0);
- return lastDate < options.minDate || date.getTime() > options.maxDate;
- },
- onKeyDown: function(evt) {
- if (!picker.$date) {
- return;
- }
- var actualYear = picker.$date.getFullYear(),
- newDate = new Date(picker.$date);
+ targetEl.triggerHandler('click');
+ }
+ };
- if(evt.keyCode === 37) newDate.setYear(actualYear - 1);
- else if(evt.keyCode === 38) newDate.setYear(actualYear - 4);
- else if(evt.keyCode === 39) newDate.setYear(actualYear + 1);
- else if(evt.keyCode === 40) newDate.setYear(actualYear + 4);
+ $datepicker.$onKeyDown = function(evt) {
+ if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;
+ evt.preventDefault();
+ evt.stopPropagation();
- if (!this.isDisabled(newDate)) picker.select(newDate, true);
+ if(evt.keyCode === 13) {
+ if(!scope.$mode) {
+ return $datepicker.hide(true);
+ } else {
+ return scope.$apply(function() { $datepicker.setMode(scope.$mode - 1); });
}
- }];
+ }
- return {
- views: options.minView ? Array.prototype.slice.call(views, options.minView) : views,
- viewDate: viewDate
+ // Navigate with keyboard
+ $picker.onKeyDown(evt);
+ parentScope.$digest();
};
- };
+ // Private
- }];
+ function updateSelected(el) {
+ el.selected = $datepicker.$isSelected(el.date);
+ }
- });
+ function focusElement() {
+ element[0].focus();
+ }
-// Source: collapse.js
-angular.module('mgcrea.ngStrap.collapse', [])
+ // Overrides
- .provider('$collapse', function() {
+ var _init = $datepicker.init;
+ $datepicker.init = function() {
+ if(isNative && options.useNative) {
+ element.prop('type', 'date');
+ element.css('-webkit-appearance', 'textfield');
+ return;
+ } else if(isTouch) {
+ element.prop('type', 'text');
+ element.attr('readonly', 'true');
+ element.on('click', focusElement);
+ }
+ _init();
+ };
- var defaults = this.defaults = {
- animation: 'am-collapse',
- disallowToggle: false,
- activeClass: 'in',
- startCollapsed: false,
- allowMultiple: false
- };
+ var _destroy = $datepicker.destroy;
+ $datepicker.destroy = function() {
+ if(isNative && options.useNative) {
+ element.off('click', focusElement);
+ }
+ _destroy();
+ };
- var controller = this.controller = function($scope, $element, $attrs) {
- var self = this;
+ var _show = $datepicker.show;
+ $datepicker.show = function() {
+ _show();
+ // use timeout to hookup the events to prevent
+ // event bubbling from being processed imediately.
+ $timeout(function() {
+ $datepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);
+ if(options.keyboard) {
+ element.on('keydown', $datepicker.$onKeyDown);
+ }
+ }, 0, false);
+ };
- // Attributes options
- self.$options = angular.copy(defaults);
- angular.forEach(['animation', 'disallowToggle', 'activeClass', 'startCollapsed', 'allowMultiple'], function (key) {
- if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];
- });
+ var _hide = $datepicker.hide;
+ $datepicker.hide = function(blur) {
+ if(!$datepicker.$isShown) return;
+ $datepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);
+ if(options.keyboard) {
+ element.off('keydown', $datepicker.$onKeyDown);
+ }
+ _hide(blur);
+ };
- self.$toggles = [];
- self.$targets = [];
+ return $datepicker;
- self.$viewChangeListeners = [];
+ }
- self.$registerToggle = function(element) {
- self.$toggles.push(element);
- };
- self.$registerTarget = function(element) {
- self.$targets.push(element);
- };
+ DatepickerFactory.defaults = defaults;
+ return DatepickerFactory;
- self.$unregisterToggle = function(element) {
- var index = self.$toggles.indexOf(element);
- // remove toggle from $toggles array
- self.$toggles.splice(index, 1);
- };
- self.$unregisterTarget = function(element) {
- var index = self.$targets.indexOf(element);
+ }];
- // remove element from $targets array
- self.$targets.splice(index, 1);
+ })
- if (self.$options.allowMultiple) {
- // remove target index from $active array values
- deactivateItem(element);
- }
+ .directive('bsDatepicker', ["$window", "$parse", "$q", "$dateFormatter", "$dateParser", "$datepicker", function($window, $parse, $q, $dateFormatter, $dateParser, $datepicker) {
- // fix active item indexes
- fixActiveItemIndexes(index);
+ var defaults = $datepicker.defaults;
+ var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);
- self.$viewChangeListeners.forEach(function(fn) {
- fn();
+ return {
+ restrict: 'EAC',
+ require: 'ngModel',
+ link: function postLink(scope, element, attr, controller) {
+
+ // Directive options
+ var options = {scope: scope, controller: controller};
+ angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'dateType', 'dateFormat', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled'], function(key) {
+ if(angular.isDefined(attr[key])) options[key] = attr[key];
});
- };
- // use array to store all the currently open panels
- self.$targets.$active = !self.$options.startCollapsed ? [0] : [];
- self.$setActive = $scope.$setActive = function(value) {
- if(angular.isArray(value)) {
- self.$targets.$active = angular.copy(value);
- }
- else if(!self.$options.disallowToggle) {
- // toogle element active status
- isActive(value) ? deactivateItem(value) : activateItem(value);
- } else {
- activateItem(value);
- }
+ // Visibility binding support
+ attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {
+ if(!datepicker || !angular.isDefined(newValue)) return;
+ if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(datepicker),?/i);
+ newValue === true ? datepicker.show() : datepicker.hide();
+ });
- self.$viewChangeListeners.forEach(function(fn) {
- fn();
+ // Initialize datepicker
+ var datepicker = $datepicker(element, controller, options);
+ options = datepicker.$options;
+ // Set expected iOS format
+ if(isNative && options.useNative) options.dateFormat = 'yyyy-MM-dd';
+
+ var lang = options.lang;
+
+ var formatDate = function(date, format) {
+ return $dateFormatter.formatDate(date, format, lang);
+ };
+
+ var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});
+
+ // Observe attributes for changes
+ angular.forEach(['minDate', 'maxDate'], function(key) {
+ // console.warn('attr.$observe(%s)', key, attr[key]);
+ angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {
+ // console.warn('attr.$observe(%s)=%o', key, newValue);
+ datepicker.$options[key] = dateParser.getDateForAttribute(key, newValue);
+ // Build only if dirty
+ !isNaN(datepicker.$options[key]) && datepicker.$build(false);
+ validateAgainstMinMaxDate(controller.$dateValue);
+ });
});
- };
- self.$activeIndexes = function() {
- return self.$options.allowMultiple ? self.$targets.$active :
- self.$targets.$active.length === 1 ? self.$targets.$active[0] : -1;
- };
+ // Watch model for changes
+ scope.$watch(attr.ngModel, function(newValue, oldValue) {
+ datepicker.update(controller.$dateValue);
+ }, true);
- function fixActiveItemIndexes(index) {
- // item with index was removed, so we
- // need to adjust other items index values
- var activeIndexes = self.$targets.$active;
- for(var i = 0; i < activeIndexes.length; i++) {
- if (index < activeIndexes[i]) {
- activeIndexes[i] = activeIndexes[i] - 1;
+ // Normalize undefined/null/empty array,
+ // so that we don't treat changing from undefined->null as a change.
+ function normalizeDateRanges(ranges) {
+ if (!ranges || !ranges.length) return null;
+ return ranges;
+ }
+
+ if (angular.isDefined(attr.disabledDates)) {
+ scope.$watch(attr.disabledDates, function(disabledRanges, previousValue) {
+ disabledRanges = normalizeDateRanges(disabledRanges);
+ previousValue = normalizeDateRanges(previousValue);
+
+ if (disabledRanges) {
+ datepicker.updateDisabledDates(disabledRanges);
+ }
+ });
+ }
+
+ function validateAgainstMinMaxDate(parsedDate) {
+ if (!angular.isDate(parsedDate)) return;
+ var isMinValid = isNaN(datepicker.$options.minDate) || parsedDate.getTime() >= datepicker.$options.minDate;
+ var isMaxValid = isNaN(datepicker.$options.maxDate) || parsedDate.getTime() <= datepicker.$options.maxDate;
+ var isValid = isMinValid && isMaxValid;
+ controller.$setValidity('date', isValid);
+ controller.$setValidity('min', isMinValid);
+ controller.$setValidity('max', isMaxValid);
+ // Only update the model when we have a valid date
+ if(isValid) controller.$dateValue = parsedDate;
+ }
+
+ // viewValue -> $parsers -> modelValue
+ controller.$parsers.unshift(function(viewValue) {
+ // console.warn('$parser("%s"): viewValue=%o', element.attr('ng-model'), viewValue);
+ // Null values should correctly reset the model value & validity
+ if(!viewValue) {
+ controller.$setValidity('date', true);
+ // BREAKING CHANGE:
+ // return null (not undefined) when input value is empty, so angularjs 1.3
+ // ngModelController can go ahead and run validators, like ngRequired
+ return null;
+ }
+ var parsedDate = dateParser.parse(viewValue, controller.$dateValue);
+ if(!parsedDate || isNaN(parsedDate.getTime())) {
+ controller.$setValidity('date', false);
+ // return undefined, causes ngModelController to
+ // invalidate model value
+ return;
+ } else {
+ validateAgainstMinMaxDate(parsedDate);
+ }
+ if(options.dateType === 'string') {
+ return formatDate(parsedDate, options.modelDateFormat || options.dateFormat);
+ } else if(options.dateType === 'number') {
+ return controller.$dateValue.getTime();
+ } else if(options.dateType === 'unix') {
+ return controller.$dateValue.getTime() / 1000;
+ } else if(options.dateType === 'iso') {
+ return controller.$dateValue.toISOString();
+ } else {
+ return new Date(controller.$dateValue);
}
+ });
- // the last item is active, so we need to
- // adjust its index
- if (activeIndexes[i] === self.$targets.length) {
- activeIndexes[i] = self.$targets.length - 1;
+ // modelValue -> $formatters -> viewValue
+ controller.$formatters.push(function(modelValue) {
+ // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);
+ var date;
+ if(angular.isUndefined(modelValue) || modelValue === null) {
+ date = NaN;
+ } else if(angular.isDate(modelValue)) {
+ date = modelValue;
+ } else if(options.dateType === 'string') {
+ date = dateParser.parse(modelValue, null, options.modelDateFormat);
+ } else if(options.dateType === 'unix') {
+ date = new Date(modelValue * 1000);
+ } else {
+ date = new Date(modelValue);
}
- }
- }
+ // Setup default value?
+ // if(isNaN(date.getTime())) {
+ // var today = new Date();
+ // date = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0, 0);
+ // }
+ controller.$dateValue = date;
+ return getDateFormattedString();
+ });
- function isActive(value) {
- var activeItems = self.$targets.$active;
- return activeItems.indexOf(value) === -1 ? false : true;
- }
+ // viewValue -> element
+ controller.$render = function() {
+ // console.warn('$render("%s"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);
+ element.val(getDateFormattedString());
+ };
- function deactivateItem(value) {
- var index = self.$targets.$active.indexOf(value);
- if (index !== -1) {
- self.$targets.$active.splice(index, 1);
+ function getDateFormattedString() {
+ return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.dateFormat);
}
- }
- function activateItem(value) {
- if (!self.$options.allowMultiple) {
- // remove current selected item
- self.$targets.$active.splice(0, 1);
- }
+ // Garbage collection
+ scope.$on('$destroy', function() {
+ if(datepicker) datepicker.destroy();
+ options = null;
+ datepicker = null;
+ });
- if (self.$targets.$active.indexOf(value) === -1) {
- self.$targets.$active.push(value);
- }
}
-
- };
-
- this.$get = function() {
- var $collapse = {};
- $collapse.defaults = defaults;
- $collapse.controller = controller;
- return $collapse;
};
- })
-
- .directive('bsCollapse', ["$window", "$animate", "$collapse", function($window, $animate, $collapse) {
-
- var defaults = $collapse.defaults;
-
- return {
- require: ['?ngModel', 'bsCollapse'],
- controller: ['$scope', '$element', '$attrs', $collapse.controller],
- link: function postLink(scope, element, attrs, controllers) {
-
- var ngModelCtrl = controllers[0];
- var bsCollapseCtrl = controllers[1];
-
- if(ngModelCtrl) {
-
- // Update the modelValue following
- bsCollapseCtrl.$viewChangeListeners.push(function() {
- ngModelCtrl.$setViewValue(bsCollapseCtrl.$activeIndexes());
- });
-
- // modelValue -> $formatters -> viewValue
- ngModelCtrl.$formatters.push(function(modelValue) {
- // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);
- if (angular.isArray(modelValue)) {
- // model value is an array, so just replace
- // the active items directly
- bsCollapseCtrl.$setActive(modelValue);
- }
- else {
- var activeIndexes = bsCollapseCtrl.$activeIndexes();
+ }])
- if (angular.isArray(activeIndexes)) {
- // we have an array of selected indexes
- if (activeIndexes.indexOf(modelValue * 1) === -1) {
- // item with modelValue index is not active
- bsCollapseCtrl.$setActive(modelValue * 1);
- }
- }
- else if (activeIndexes !== modelValue * 1) {
- bsCollapseCtrl.$setActive(modelValue * 1);
- }
- }
- return modelValue;
- });
+ .provider('datepickerViews', function() {
- }
+ var defaults = this.defaults = {
+ dayFormat: 'dd',
+ daySplit: 7
+ };
+ // Split array into smaller arrays
+ function split(arr, size) {
+ var arrays = [];
+ while(arr.length > 0) {
+ arrays.push(arr.splice(0, size));
}
- };
+ return arrays;
+ }
- }])
+ // Modulus operator
+ function mod(n, m) {
+ return ((n % m) + m) % m;
+ }
- .directive('bsCollapseToggle', function() {
+ this.$get = ["$dateFormatter", "$dateParser", "$sce", function($dateFormatter, $dateParser, $sce) {
- return {
- require: ['^?ngModel', '^bsCollapse'],
- link: function postLink(scope, element, attrs, controllers) {
+ return function(picker) {
- var ngModelCtrl = controllers[0];
- var bsCollapseCtrl = controllers[1];
+ var scope = picker.$scope;
+ var options = picker.$options;
- // Add base attr
- element.attr('data-toggle', 'collapse');
+ var lang = options.lang;
+ var formatDate = function(date, format) {
+ return $dateFormatter.formatDate(date, format, lang);
+ };
+ var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});
- // Push pane to parent bsCollapse controller
- bsCollapseCtrl.$registerToggle(element);
+ var weekDaysMin = $dateFormatter.weekdaysShort(lang);
+ var weekDaysLabels = weekDaysMin.slice(options.startWeek).concat(weekDaysMin.slice(0, options.startWeek));
+ var weekDaysLabelsHtml = $sce.trustAsHtml('' + weekDaysLabels.join(' ') + ' ');
- // remove toggle from collapse controller when toggle is destroyed
- scope.$on('$destroy', function() {
- bsCollapseCtrl.$unregisterToggle(element);
- });
+ var startDate = picker.$date || (options.startDate ? dateParser.getDateForAttribute('startDate', options.startDate) : new Date());
+ var viewDate = {year: startDate.getFullYear(), month: startDate.getMonth(), date: startDate.getDate()};
+ var timezoneOffset = startDate.getTimezoneOffset() * 6e4;
- element.on('click', function() {
- var index = attrs.bsCollapseToggle || bsCollapseCtrl.$toggles.indexOf(element);
- bsCollapseCtrl.$setActive(index * 1);
- scope.$apply();
- });
+ var views = [{
+ format: options.dayFormat,
+ split: 7,
+ steps: { month: 1 },
+ update: function(date, force) {
+ if(!this.built || force || date.getFullYear() !== viewDate.year || date.getMonth() !== viewDate.month) {
+ angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});
+ picker.$build();
+ } else if(date.getDate() !== viewDate.date) {
+ viewDate.date = picker.$date.getDate();
+ picker.$updateSelected();
+ }
+ },
+ build: function() {
+ var firstDayOfMonth = new Date(viewDate.year, viewDate.month, 1), firstDayOfMonthOffset = firstDayOfMonth.getTimezoneOffset();
+ var firstDate = new Date(+firstDayOfMonth - mod(firstDayOfMonth.getDay() - options.startWeek, 7) * 864e5), firstDateOffset = firstDate.getTimezoneOffset();
+ var today = new Date().toDateString();
+ // Handle daylight time switch
+ if(firstDateOffset !== firstDayOfMonthOffset) firstDate = new Date(+firstDate + (firstDateOffset - firstDayOfMonthOffset) * 60e3);
+ var days = [], day;
+ for(var i = 0; i < 42; i++) { // < 7 * 6
+ day = dateParser.daylightSavingAdjust(new Date(firstDate.getFullYear(), firstDate.getMonth(), firstDate.getDate() + i));
+ days.push({date: day, isToday: day.toDateString() === today, label: formatDate(day, this.format), selected: picker.$date && this.isSelected(day), muted: day.getMonth() !== viewDate.month, disabled: this.isDisabled(day)});
+ }
+ scope.title = formatDate(firstDayOfMonth, options.monthTitleFormat);
+ scope.showLabels = true;
+ scope.labels = weekDaysLabelsHtml;
+ scope.rows = split(days, this.split);
+ this.built = true;
+ },
+ isSelected: function(date) {
+ return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth() && date.getDate() === picker.$date.getDate();
+ },
+ isDisabled: function(date) {
+ var time = date.getTime();
- }
- };
+ // Disabled because of min/max date.
+ if (time < options.minDate || time > options.maxDate) return true;
- })
+ // Disabled due to being a disabled day of the week
+ if (options.daysOfWeekDisabled.indexOf(date.getDay()) !== -1) return true;
- .directive('bsCollapseTarget', ["$animate", function($animate) {
+ // Disabled because of disabled date range.
+ if (options.disabledDateRanges) {
+ for (var i = 0; i < options.disabledDateRanges.length; i++) {
+ if (time >= options.disabledDateRanges[i].start && time <= options.disabledDateRanges[i].end) {
+ return true;
+ }
+ }
+ }
- return {
- require: ['^?ngModel', '^bsCollapse'],
- // scope: true,
- link: function postLink(scope, element, attrs, controllers) {
+ return false;
+ },
+ onKeyDown: function(evt) {
+ if (!picker.$date) {
+ return;
+ }
+ var actualTime = picker.$date.getTime();
+ var newDate;
- var ngModelCtrl = controllers[0];
- var bsCollapseCtrl = controllers[1];
+ if(evt.keyCode === 37) newDate = new Date(actualTime - 1 * 864e5);
+ else if(evt.keyCode === 38) newDate = new Date(actualTime - 7 * 864e5);
+ else if(evt.keyCode === 39) newDate = new Date(actualTime + 1 * 864e5);
+ else if(evt.keyCode === 40) newDate = new Date(actualTime + 7 * 864e5);
- // Add base class
- element.addClass('collapse');
+ if (!this.isDisabled(newDate)) picker.select(newDate, true);
+ }
+ }, {
+ name: 'month',
+ format: options.monthFormat,
+ split: 4,
+ steps: { year: 1 },
+ update: function(date, force) {
+ if(!this.built || date.getFullYear() !== viewDate.year) {
+ angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});
+ picker.$build();
+ } else if(date.getMonth() !== viewDate.month) {
+ angular.extend(viewDate, {month: picker.$date.getMonth(), date: picker.$date.getDate()});
+ picker.$updateSelected();
+ }
+ },
+ build: function() {
+ var firstMonth = new Date(viewDate.year, 0, 1);
+ var months = [], month;
+ for (var i = 0; i < 12; i++) {
+ month = new Date(viewDate.year, i, 1);
+ months.push({date: month, label: formatDate(month, this.format), selected: picker.$isSelected(month), disabled: this.isDisabled(month)});
+ }
+ scope.title = formatDate(month, options.yearTitleFormat);
+ scope.showLabels = false;
+ scope.rows = split(months, this.split);
+ this.built = true;
+ },
+ isSelected: function(date) {
+ return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth();
+ },
+ isDisabled: function(date) {
+ var lastDate = +new Date(date.getFullYear(), date.getMonth() + 1, 0);
+ return lastDate < options.minDate || date.getTime() > options.maxDate;
+ },
+ onKeyDown: function(evt) {
+ if (!picker.$date) {
+ return;
+ }
+ var actualMonth = picker.$date.getMonth();
+ var newDate = new Date(picker.$date);
- // Add animation class
- if(bsCollapseCtrl.$options.animation) {
- element.addClass(bsCollapseCtrl.$options.animation);
- }
+ if(evt.keyCode === 37) newDate.setMonth(actualMonth - 1);
+ else if(evt.keyCode === 38) newDate.setMonth(actualMonth - 4);
+ else if(evt.keyCode === 39) newDate.setMonth(actualMonth + 1);
+ else if(evt.keyCode === 40) newDate.setMonth(actualMonth + 4);
- // Push pane to parent bsCollapse controller
- bsCollapseCtrl.$registerTarget(element);
+ if (!this.isDisabled(newDate)) picker.select(newDate, true);
+ }
+ }, {
+ name: 'year',
+ format: options.yearFormat,
+ split: 4,
+ steps: { year: 12 },
+ update: function(date, force) {
+ if(!this.built || force || parseInt(date.getFullYear()/20, 10) !== parseInt(viewDate.year/20, 10)) {
+ angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});
+ picker.$build();
+ } else if(date.getFullYear() !== viewDate.year) {
+ angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});
+ picker.$updateSelected();
+ }
+ },
+ build: function() {
+ var firstYear = viewDate.year - viewDate.year % (this.split * 3);
+ var years = [], year;
+ for (var i = 0; i < 12; i++) {
+ year = new Date(firstYear + i, 0, 1);
+ years.push({date: year, label: formatDate(year, this.format), selected: picker.$isSelected(year), disabled: this.isDisabled(year)});
+ }
+ scope.title = years[0].label + '-' + years[years.length - 1].label;
+ scope.showLabels = false;
+ scope.rows = split(years, this.split);
+ this.built = true;
+ },
+ isSelected: function(date) {
+ return picker.$date && date.getFullYear() === picker.$date.getFullYear();
+ },
+ isDisabled: function(date) {
+ var lastDate = +new Date(date.getFullYear() + 1, 0, 0);
+ return lastDate < options.minDate || date.getTime() > options.maxDate;
+ },
+ onKeyDown: function(evt) {
+ if (!picker.$date) {
+ return;
+ }
+ var actualYear = picker.$date.getFullYear(),
+ newDate = new Date(picker.$date);
- // remove pane target from collapse controller when target is destroyed
- scope.$on('$destroy', function() {
- bsCollapseCtrl.$unregisterTarget(element);
- });
+ if(evt.keyCode === 37) newDate.setYear(actualYear - 1);
+ else if(evt.keyCode === 38) newDate.setYear(actualYear - 4);
+ else if(evt.keyCode === 39) newDate.setYear(actualYear + 1);
+ else if(evt.keyCode === 40) newDate.setYear(actualYear + 4);
- function render() {
- var index = bsCollapseCtrl.$targets.indexOf(element);
- var active = bsCollapseCtrl.$activeIndexes();
- var action = 'removeClass';
- if (angular.isArray(active)) {
- if (active.indexOf(index) !== -1) {
- action = 'addClass';
+ if (!this.isDisabled(newDate)) picker.select(newDate, true);
}
- }
- else if (index === active) {
- action = 'addClass';
- }
+ }];
- $animate[action](element, bsCollapseCtrl.$options.activeClass);
- }
+ return {
+ views: options.minView ? Array.prototype.slice.call(views, options.minView) : views,
+ viewDate: viewDate
+ };
- bsCollapseCtrl.$viewChangeListeners.push(function() {
- render();
- });
- render();
+ };
- }
- };
+ }];
- }]);
+ });
// Source: dropdown.js
angular.module('mgcrea.ngStrap.dropdown', ['mgcrea.ngStrap.tooltip'])
@@ -1557,1112 +1646,1023 @@ angular.module('mgcrea.ngStrap.dropdown', ['mgcrea.ngStrap.tooltip'])
return {
restrict: 'EAC',
scope: true,
- link: function postLink(scope, element, attr, transclusion) {
-
- // Directive options
- var options = {scope: scope};
- angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template'], function(key) {
- if(angular.isDefined(attr[key])) options[key] = attr[key];
- });
-
- // Support scope as an object
- attr.bsDropdown && scope.$watch(attr.bsDropdown, function(newValue, oldValue) {
- scope.content = newValue;
- }, true);
-
- // Visibility binding support
- attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {
- if(!dropdown || !angular.isDefined(newValue)) return;
- if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(dropdown),?/i);
- newValue === true ? dropdown.show() : dropdown.hide();
- });
-
- // Initialize dropdown
- var dropdown = $dropdown(element, options);
-
- // Garbage collection
- scope.$on('$destroy', function() {
- if (dropdown) dropdown.destroy();
- options = null;
- dropdown = null;
- });
-
- }
- };
-
- }]);
-
-// Source: date-formatter.js
-angular.module('mgcrea.ngStrap.helpers.dateFormatter', [])
-
- .service('$dateFormatter', ["$locale", "dateFilter", function($locale, dateFilter) {
-
- // The unused `lang` arguments are on purpose. The default implementation does not
- // use them and it always uses the locale loaded into the `$locale` service.
- // Custom implementations might use it, thus allowing different directives to
- // have different languages.
-
- this.getDefaultLocale = function() {
- return $locale.id;
- };
-
- // Format is either a data format name, e.g. "shortTime" or "fullDate", or a date format
- // Return either the corresponding date format or the given date format.
- this.getDatetimeFormat = function(format, lang) {
- return $locale.DATETIME_FORMATS[format] || format;
- };
-
- this.weekdaysShort = function(lang) {
- return $locale.DATETIME_FORMATS.SHORTDAY;
- };
-
- function splitTimeFormat(format) {
- return /(h+)([:\.])?(m+)[ ]?(a?)/i.exec(format).slice(1);
- }
-
- // h:mm a => h
- this.hoursFormat = function(timeFormat) {
- return splitTimeFormat(timeFormat)[0];
- };
-
- // h:mm a => mm
- this.minutesFormat = function(timeFormat) {
- return splitTimeFormat(timeFormat)[2];
- };
-
- // h:mm a => :
- this.timeSeparator = function(timeFormat) {
- return splitTimeFormat(timeFormat)[1];
- };
-
- // h:mm a => true, H.mm => false
- this.showAM = function(timeFormat) {
- return !!splitTimeFormat(timeFormat)[3];
- };
-
- this.formatDate = function(date, format, lang){
- return dateFilter(date, format);
- };
-
- }]);
-
-// Source: date-parser.js
-angular.module('mgcrea.ngStrap.helpers.dateParser', [])
-
-.provider('$dateParser', ["$localeProvider", function($localeProvider) {
-
- // define a custom ParseDate object to use instead of native Date
- // to avoid date values wrapping when setting date component values
- function ParseDate() {
- this.year = 1970;
- this.month = 0;
- this.day = 1;
- this.hours = 0;
- this.minutes = 0;
- this.seconds = 0;
- this.milliseconds = 0;
- }
-
- ParseDate.prototype.setMilliseconds = function(value) { this.milliseconds = value; };
- ParseDate.prototype.setSeconds = function(value) { this.seconds = value; };
- ParseDate.prototype.setMinutes = function(value) { this.minutes = value; };
- ParseDate.prototype.setHours = function(value) { this.hours = value; };
- ParseDate.prototype.getHours = function() { return this.hours; };
- ParseDate.prototype.setDate = function(value) { this.day = value; };
- ParseDate.prototype.setMonth = function(value) { this.month = value; };
- ParseDate.prototype.setFullYear = function(value) { this.year = value; };
- ParseDate.prototype.fromDate = function(value) {
- this.year = value.getFullYear();
- this.month = value.getMonth();
- this.day = value.getDate();
- this.hours = value.getHours();
- this.minutes = value.getMinutes();
- this.seconds = value.getSeconds();
- this.milliseconds = value.getMilliseconds();
- return this;
- };
-
- ParseDate.prototype.toDate = function() {
- return new Date(this.year, this.month, this.day, this.hours, this.minutes, this.seconds, this.milliseconds);
- };
-
- var proto = ParseDate.prototype;
-
- function noop() {
- }
-
- function isNumeric(n) {
- return !isNaN(parseFloat(n)) && isFinite(n);
- }
-
- function indexOfCaseInsensitive(array, value) {
- var len = array.length, str=value.toString().toLowerCase();
- for (var i=0; i ');
+ $modal.$promise.then(function(template) {
+ if(angular.isObject(template)) template = template.data;
+ if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html="');
+ template = trim.apply(template);
+ modalLinker = $compile(template);
+ $modal.init();
+ });
- /* Handle switch to/from daylight saving.
- * Hours may be non-zero on daylight saving cut-over:
- * > 12 when midnight changeover, but then cannot generate
- * midnight datetime, so jump to 1AM, otherwise reset.
- * @param date (Date) the date to check
- * @return (Date) the corrected date
- *
- * __ copied from jquery ui datepicker __
- */
- $dateParser.daylightSavingAdjust = function(date) {
- if (!date) {
- return null;
- }
- date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
- return date;
- };
+ $modal.init = function() {
- // Private functions
+ // Options: show
+ if(options.show) {
+ scope.$$postDigest(function() {
+ $modal.show();
+ });
+ }
- function setMapForFormat(format) {
- var keys = Object.keys(setFnMap), i;
- var map = [], sortedMap = [];
- // Map to setFn
- var clonedFormat = format;
- for(i = 0; i < keys.length; i++) {
- if(format.split(keys[i]).length > 1) {
- var index = clonedFormat.search(keys[i]);
- format = format.split(keys[i]).join('');
- if(setFnMap[keys[i]]) {
- map[index] = setFnMap[keys[i]];
- }
+ };
+
+ $modal.destroy = function() {
+
+ // Remove element
+ if(modalElement) {
+ modalElement.remove();
+ modalElement = null;
+ }
+ if(backdropElement) {
+ backdropElement.remove();
+ backdropElement = null;
}
- }
- // Sort result map
- angular.forEach(map, function(v) {
- // conditional required since angular.forEach broke around v1.2.21
- // related pr: https://github.com/angular/angular.js/pull/8525
- if(v) sortedMap.push(v);
- });
- return sortedMap;
- }
- function escapeReservedSymbols(text) {
- return text.replace(/\//g, '[\\/]').replace('/-/g', '[-]').replace(/\./g, '[.]').replace(/\\s/g, '[\\s]');
- }
+ // Destroy scope
+ scope.$destroy();
- function regExpForFormat(format) {
- var keys = Object.keys(regExpMap), i;
+ };
- var re = format;
- // Abstract replaces to avoid collisions
- for(i = 0; i < keys.length; i++) {
- re = re.split(keys[i]).join('${' + i + '}');
- }
- // Replace abstracted values
- for(i = 0; i < keys.length; i++) {
- re = re.split('${' + i + '}').join('(' + regExpMap[keys[i]] + ')');
- }
- format = escapeReservedSymbols(format);
+ $modal.show = function() {
+ if($modal.$isShown) return;
- return new RegExp('^' + re + '$', ['i']);
- }
+ if(scope.$emit(options.prefixEvent + '.show.before', $modal).defaultPrevented) {
+ return;
+ }
+ var parent, after;
+ if(angular.isElement(options.container)) {
+ parent = options.container;
+ after = options.container[0].lastChild ? angular.element(options.container[0].lastChild) : null;
+ } else {
+ if (options.container) {
+ parent = findElement(options.container);
+ after = parent[0].lastChild ? angular.element(parent[0].lastChild) : null;
+ } else {
+ parent = null;
+ after = options.element;
+ }
+ }
- $dateParser.init();
- return $dateParser;
+ // Fetch a cloned element linked from template
+ modalElement = $modal.$element = modalLinker(scope, function(clonedElement, scope) {});
- };
+ // Set the initial positioning.
+ modalElement.css({display: 'block'}).addClass(options.placement);
- return DateParserFactory;
+ // Options: animation
+ if(options.animation) {
+ if(options.backdrop) {
+ backdropElement.addClass(options.backdropAnimation);
+ }
+ modalElement.addClass(options.animation);
+ }
- }];
+ if(options.backdrop) {
+ $animate.enter(backdropElement, bodyElement, null);
+ }
+ // Support v1.3+ $animate
+ // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9
+ var promise = $animate.enter(modalElement, parent, after, enterAnimateCallback);
+ if(promise && promise.then) promise.then(enterAnimateCallback);
-}]);
+ $modal.$isShown = scope.$isShown = true;
+ safeDigest(scope);
+ // Focus once the enter-animation has started
+ // Weird PhantomJS bug hack
+ var el = modalElement[0];
+ requestAnimationFrame(function() {
+ el.focus();
+ });
-// Source: debounce.js
-angular.module('mgcrea.ngStrap.helpers.debounce', [])
+ bodyElement.addClass(options.prefixClass + '-open');
+ if(options.animation) {
+ bodyElement.addClass(options.prefixClass + '-with-' + options.animation);
+ }
-// @source jashkenas/underscore
-// @url https://github.com/jashkenas/underscore/blob/1.5.2/underscore.js#L693
-.factory('debounce', ["$timeout", function($timeout) {
- return function(func, wait, immediate) {
- var timeout = null;
- return function() {
- var context = this,
- args = arguments,
- callNow = immediate && !timeout;
- if(timeout) {
- $timeout.cancel(timeout);
- }
- timeout = $timeout(function later() {
- timeout = null;
- if(!immediate) {
- func.apply(context, args);
+ // Bind events
+ if(options.backdrop) {
+ modalElement.on('click', hideOnBackdropClick);
+ backdropElement.on('click', hideOnBackdropClick);
+ backdropElement.on('wheel', preventEventDefault);
+ }
+ if(options.keyboard) {
+ modalElement.on('keyup', $modal.$onKeyUp);
+ }
+ };
+
+ function enterAnimateCallback() {
+ scope.$emit(options.prefixEvent + '.show', $modal);
}
- }, wait, false);
- if(callNow) {
- func.apply(context, args);
- }
- return timeout;
- };
- };
-}])
+ $modal.hide = function() {
+ if(!$modal.$isShown) return;
-// @source jashkenas/underscore
-// @url https://github.com/jashkenas/underscore/blob/1.5.2/underscore.js#L661
-.factory('throttle', ["$timeout", function($timeout) {
- return function(func, wait, options) {
- var timeout = null;
- options || (options = {});
- return function() {
- var context = this,
- args = arguments;
- if(!timeout) {
- if(options.leading !== false) {
- func.apply(context, args);
- }
- timeout = $timeout(function later() {
- timeout = null;
- if(options.trailing !== false) {
- func.apply(context, args);
+ if(scope.$emit(options.prefixEvent + '.hide.before', $modal).defaultPrevented) {
+ return;
}
- }, wait, false);
- }
- };
- };
-}]);
+ var promise = $animate.leave(modalElement, leaveAnimateCallback);
+ // Support v1.3+ $animate
+ // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9
+ if(promise && promise.then) promise.then(leaveAnimateCallback);
-// Source: dimensions.js
-angular.module('mgcrea.ngStrap.helpers.dimensions', [])
+ if(options.backdrop) {
+ $animate.leave(backdropElement);
+ }
+ $modal.$isShown = scope.$isShown = false;
+ safeDigest(scope);
- .factory('dimensions', ["$document", "$window", function($document, $window) {
+ // Unbind events
+ if(options.backdrop) {
+ modalElement.off('click', hideOnBackdropClick);
+ backdropElement.off('click', hideOnBackdropClick);
+ backdropElement.off('wheel', preventEventDefault);
+ }
+ if(options.keyboard) {
+ modalElement.off('keyup', $modal.$onKeyUp);
+ }
+ };
- var jqLite = angular.element;
- var fn = {};
+ function leaveAnimateCallback() {
+ scope.$emit(options.prefixEvent + '.hide', $modal);
+ bodyElement.removeClass(options.prefixClass + '-open');
+ if(options.animation) {
+ bodyElement.removeClass(options.prefixClass + '-with-' + options.animation);
+ }
+ }
- /**
- * Test the element nodeName
- * @param element
- * @param name
- */
- var nodeName = fn.nodeName = function(element, name) {
- return element.nodeName && element.nodeName.toLowerCase() === name.toLowerCase();
- };
+ $modal.toggle = function() {
- /**
- * Returns the element computed style
- * @param element
- * @param prop
- * @param extra
- */
- fn.css = function(element, prop, extra) {
- var value;
- if (element.currentStyle) { //IE
- value = element.currentStyle[prop];
- } else if (window.getComputedStyle) {
- value = window.getComputedStyle(element)[prop];
- } else {
- value = element.style[prop];
- }
- return extra === true ? parseFloat(value) || 0 : value;
- };
+ $modal.$isShown ? $modal.hide() : $modal.show();
- /**
- * Provides read-only equivalent of jQuery's offset function:
- * @required-by bootstrap-tooltip, bootstrap-affix
- * @url http://api.jquery.com/offset/
- * @param element
- */
- fn.offset = function(element) {
- var boxRect = element.getBoundingClientRect();
- var docElement = element.ownerDocument;
- return {
- width: boxRect.width || element.offsetWidth,
- height: boxRect.height || element.offsetHeight,
- top: boxRect.top + (window.pageYOffset || docElement.documentElement.scrollTop) - (docElement.documentElement.clientTop || 0),
- left: boxRect.left + (window.pageXOffset || docElement.documentElement.scrollLeft) - (docElement.documentElement.clientLeft || 0)
- };
- };
+ };
- /**
- * Provides read-only equivalent of jQuery's position function
- * @required-by bootstrap-tooltip, bootstrap-affix
- * @url http://api.jquery.com/offset/
- * @param element
- */
- fn.position = function(element) {
+ $modal.focus = function() {
+ modalElement[0].focus();
+ };
- var offsetParentRect = {top: 0, left: 0},
- offsetParentElement,
- offset;
+ // Protected methods
- // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent
- if (fn.css(element, 'position') === 'fixed') {
+ $modal.$onKeyUp = function(evt) {
- // We assume that getBoundingClientRect is available when computed position is fixed
- offset = element.getBoundingClientRect();
+ if (evt.which === 27 && $modal.$isShown) {
+ $modal.hide();
+ evt.stopPropagation();
+ }
+
+ };
- } else {
+ // Private methods
- // Get *real* offsetParentElement
- offsetParentElement = offsetParent(element);
+ function hideOnBackdropClick(evt) {
+ if(evt.target !== evt.currentTarget) return;
+ options.backdrop === 'static' ? $modal.focus() : $modal.hide();
+ }
- // Get correct offsets
- offset = fn.offset(element);
- if (!nodeName(offsetParentElement, 'html')) {
- offsetParentRect = fn.offset(offsetParentElement);
+ function preventEventDefault(evt) {
+ evt.preventDefault();
}
- // Add offsetParent borders
- offsetParentRect.top += fn.css(offsetParentElement, 'borderTopWidth', true);
- offsetParentRect.left += fn.css(offsetParentElement, 'borderLeftWidth', true);
- }
+ return $modal;
- // Subtract parent offsets and element margins
- return {
- width: element.offsetWidth,
- height: element.offsetHeight,
- top: offset.top - offsetParentRect.top - fn.css(element, 'marginTop', true),
- left: offset.left - offsetParentRect.left - fn.css(element, 'marginLeft', true)
- };
+ }
- };
+ // Helper functions
- /**
- * Returns the closest, non-statically positioned offsetParent of a given element
- * @required-by fn.position
- * @param element
- */
- var offsetParent = function offsetParentElement(element) {
- var docElement = element.ownerDocument;
- var offsetParent = element.offsetParent || docElement;
- if(nodeName(offsetParent, '#document')) return docElement.documentElement;
- while(offsetParent && !nodeName(offsetParent, 'html') && fn.css(offsetParent, 'position') === 'static') {
- offsetParent = offsetParent.offsetParent;
+ function safeDigest(scope) {
+ scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();
}
- return offsetParent || docElement.documentElement;
- };
- /**
- * Provides equivalent of jQuery's height function
- * @required-by bootstrap-affix
- * @url http://api.jquery.com/height/
- * @param element
- * @param outer
- */
- fn.height = function(element, outer) {
- var value = element.offsetHeight;
- if(outer) {
- value += fn.css(element, 'marginTop', true) + fn.css(element, 'marginBottom', true);
- } else {
- value -= fn.css(element, 'paddingTop', true) + fn.css(element, 'paddingBottom', true) + fn.css(element, 'borderTopWidth', true) + fn.css(element, 'borderBottomWidth', true);
+ function findElement(query, element) {
+ return angular.element((element || document).querySelectorAll(query));
}
- return value;
- };
- /**
- * Provides equivalent of jQuery's width function
- * @required-by bootstrap-affix
- * @url http://api.jquery.com/width/
- * @param element
- * @param outer
- */
- fn.width = function(element, outer) {
- var value = element.offsetWidth;
- if(outer) {
- value += fn.css(element, 'marginLeft', true) + fn.css(element, 'marginRight', true);
- } else {
- value -= fn.css(element, 'paddingLeft', true) + fn.css(element, 'paddingRight', true) + fn.css(element, 'borderLeftWidth', true) + fn.css(element, 'borderRightWidth', true);
+ var fetchPromises = {};
+ function fetchTemplate(template) {
+ if(fetchPromises[template]) return fetchPromises[template];
+ return (fetchPromises[template] = $q.when($templateCache.get(template) || $http.get(template))
+ .then(function(res) {
+ if(angular.isObject(res)) {
+ $templateCache.put(template, res.data);
+ return res.data;
+ }
+ return res;
+ }));
}
- return value;
- };
- return fn;
+ return ModalFactory;
- }]);
+ }];
-// Source: parse-options.js
-angular.module('mgcrea.ngStrap.helpers.parseOptions', [])
+ })
- .provider('$parseOptions', function() {
+ .directive('bsModal', ["$window", "$sce", "$modal", function($window, $sce, $modal) {
- var defaults = this.defaults = {
- regexp: /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/
- };
+ return {
+ restrict: 'EAC',
+ scope: true,
+ link: function postLink(scope, element, attr, transclusion) {
- this.$get = ["$parse", "$q", function($parse, $q) {
+ // Directive options
+ var options = {scope: scope, element: element, show: false};
+ angular.forEach(['template', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation'], function(key) {
+ if(angular.isDefined(attr[key])) options[key] = attr[key];
+ });
- function ParseOptionsFactory(attr, config) {
+ // Support scope as data-attrs
+ angular.forEach(['title', 'content'], function(key) {
+ attr[key] && attr.$observe(key, function(newValue, oldValue) {
+ scope[key] = $sce.trustAsHtml(newValue);
+ });
+ });
- var $parseOptions = {};
+ // Support scope as an object
+ attr.bsModal && scope.$watch(attr.bsModal, function(newValue, oldValue) {
+ if(angular.isObject(newValue)) {
+ angular.extend(scope, newValue);
+ } else {
+ scope.content = newValue;
+ }
+ }, true);
- // Common vars
- var options = angular.extend({}, defaults, config);
- $parseOptions.$values = [];
+ // Initialize modal
+ var modal = $modal(options);
- // Private vars
- var match, displayFn, valueName, keyName, groupByFn, valueFn, valuesFn;
+ // Trigger
+ element.on(attr.trigger || 'click', modal.toggle);
- $parseOptions.init = function() {
- $parseOptions.$match = match = attr.match(options.regexp);
- displayFn = $parse(match[2] || match[1]),
- valueName = match[4] || match[6],
- keyName = match[5],
- groupByFn = $parse(match[3] || ''),
- valueFn = $parse(match[2] ? match[1] : valueName),
- valuesFn = $parse(match[7]);
- };
+ // Garbage collection
+ scope.$on('$destroy', function() {
+ if (modal) modal.destroy();
+ options = null;
+ modal = null;
+ });
- $parseOptions.valuesFn = function(scope, controller) {
- return $q.when(valuesFn(scope, controller))
- .then(function(values) {
- $parseOptions.$values = values ? parseValues(values, scope) : {};
- return $parseOptions.$values;
- });
- };
+ }
+ };
- $parseOptions.displayValue = function(modelValue) {
- var scope = {};
- scope[valueName] = modelValue;
- return displayFn(scope);
- };
+ }]);
- // Private functions
+// Source: date-formatter.js
+angular.module('mgcrea.ngStrap.helpers.dateFormatter', [])
- function parseValues(values, scope) {
- return values.map(function(match, index) {
- var locals = {}, label, value;
- locals[valueName] = match;
- label = displayFn(scope, locals);
- value = valueFn(scope, locals);
- return {label: label, value: value, index: index};
- });
- }
+ .service('$dateFormatter', ["$locale", "dateFilter", function($locale, dateFilter) {
- $parseOptions.init();
- return $parseOptions;
+ // The unused `lang` arguments are on purpose. The default implementation does not
+ // use them and it always uses the locale loaded into the `$locale` service.
+ // Custom implementations might use it, thus allowing different directives to
+ // have different languages.
- }
+ this.getDefaultLocale = function() {
+ return $locale.id;
+ };
- return ParseOptionsFactory;
+ // Format is either a data format name, e.g. "shortTime" or "fullDate", or a date format
+ // Return either the corresponding date format or the given date format.
+ this.getDatetimeFormat = function(format, lang) {
+ return $locale.DATETIME_FORMATS[format] || format;
+ };
- }];
+ this.weekdaysShort = function(lang) {
+ return $locale.DATETIME_FORMATS.SHORTDAY;
+ };
- });
+ function splitTimeFormat(format) {
+ return /(h+)([:\.])?(m+)[ ]?(a?)/i.exec(format).slice(1);
+ }
-// Source: raf.js
-(angular.version.minor < 3 && angular.version.dot < 14) && angular.module('ng')
+ // h:mm a => h
+ this.hoursFormat = function(timeFormat) {
+ return splitTimeFormat(timeFormat)[0];
+ };
-.factory('$$rAF', ["$window", "$timeout", function($window, $timeout) {
+ // h:mm a => mm
+ this.minutesFormat = function(timeFormat) {
+ return splitTimeFormat(timeFormat)[2];
+ };
- var requestAnimationFrame = $window.requestAnimationFrame ||
- $window.webkitRequestAnimationFrame ||
- $window.mozRequestAnimationFrame;
+ // h:mm a => :
+ this.timeSeparator = function(timeFormat) {
+ return splitTimeFormat(timeFormat)[1];
+ };
- var cancelAnimationFrame = $window.cancelAnimationFrame ||
- $window.webkitCancelAnimationFrame ||
- $window.mozCancelAnimationFrame ||
- $window.webkitCancelRequestAnimationFrame;
+ // h:mm a => true, H.mm => false
+ this.showAM = function(timeFormat) {
+ return !!splitTimeFormat(timeFormat)[3];
+ };
- var rafSupported = !!requestAnimationFrame;
- var raf = rafSupported ?
- function(fn) {
- var id = requestAnimationFrame(fn);
- return function() {
- cancelAnimationFrame(id);
- };
- } :
- function(fn) {
- var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
- return function() {
- $timeout.cancel(timer);
- };
+ this.formatDate = function(date, format, lang){
+ return dateFilter(date, format);
};
- raf.supported = rafSupported;
+ }]);
+
+// Source: date-parser.js
+angular.module('mgcrea.ngStrap.helpers.dateParser', [])
+
+.provider('$dateParser', ["$localeProvider", function($localeProvider) {
+
+ // define a custom ParseDate object to use instead of native Date
+ // to avoid date values wrapping when setting date component values
+ function ParseDate() {
+ this.year = 1970;
+ this.month = 0;
+ this.day = 1;
+ this.hours = 0;
+ this.minutes = 0;
+ this.seconds = 0;
+ this.milliseconds = 0;
+ }
+
+ ParseDate.prototype.setMilliseconds = function(value) { this.milliseconds = value; };
+ ParseDate.prototype.setSeconds = function(value) { this.seconds = value; };
+ ParseDate.prototype.setMinutes = function(value) { this.minutes = value; };
+ ParseDate.prototype.setHours = function(value) { this.hours = value; };
+ ParseDate.prototype.getHours = function() { return this.hours; };
+ ParseDate.prototype.setDate = function(value) { this.day = value; };
+ ParseDate.prototype.setMonth = function(value) { this.month = value; };
+ ParseDate.prototype.setFullYear = function(value) { this.year = value; };
+ ParseDate.prototype.fromDate = function(value) {
+ this.year = value.getFullYear();
+ this.month = value.getMonth();
+ this.day = value.getDate();
+ this.hours = value.getHours();
+ this.minutes = value.getMinutes();
+ this.seconds = value.getSeconds();
+ this.milliseconds = value.getMilliseconds();
+ return this;
+ };
- return raf;
+ ParseDate.prototype.toDate = function() {
+ return new Date(this.year, this.month, this.day, this.hours, this.minutes, this.seconds, this.milliseconds);
+ };
-}]);
+ var proto = ParseDate.prototype;
-// .factory('$$animateReflow', function($$rAF, $document) {
+ function noop() {
+ }
-// var bodyEl = $document[0].body;
+ function isNumeric(n) {
+ return !isNaN(parseFloat(n)) && isFinite(n);
+ }
-// return function(fn) {
-// //the returned function acts as the cancellation function
-// return $$rAF(function() {
-// //the line below will force the browser to perform a repaint
-// //so that all the animated elements within the animation frame
-// //will be properly updated and drawn on screen. This is
-// //required to perform multi-class CSS based animations with
-// //Firefox. DO NOT REMOVE THIS LINE.
-// var a = bodyEl.offsetWidth + 1;
-// fn();
-// });
-// };
+ function indexOfCaseInsensitive(array, value) {
+ var len = array.length, str=value.toString().toLowerCase();
+ for (var i=0; i 12 when midnight changeover, but then cannot generate
+ * midnight datetime, so jump to 1AM, otherwise reset.
+ * @param date (Date) the date to check
+ * @return (Date) the corrected date
+ *
+ * __ copied from jquery ui datepicker __
+ */
+ $dateParser.daylightSavingAdjust = function(date) {
+ if (!date) {
+ return null;
+ }
+ date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
+ return date;
+ };
- // Trigger
- element.on(attr.trigger || 'click', aside.toggle);
+ // Private functions
- // Garbage collection
- scope.$on('$destroy', function() {
- if (aside) aside.destroy();
- options = null;
- aside = null;
+ function setMapForFormat(format) {
+ var keys = Object.keys(setFnMap), i;
+ var map = [], sortedMap = [];
+ // Map to setFn
+ var clonedFormat = format;
+ for(i = 0; i < keys.length; i++) {
+ if(format.split(keys[i]).length > 1) {
+ var index = clonedFormat.search(keys[i]);
+ format = format.split(keys[i]).join('');
+ if(setFnMap[keys[i]]) {
+ map[index] = setFnMap[keys[i]];
+ }
+ }
+ }
+ // Sort result map
+ angular.forEach(map, function(v) {
+ // conditional required since angular.forEach broke around v1.2.21
+ // related pr: https://github.com/angular/angular.js/pull/8525
+ if(v) sortedMap.push(v);
});
+ return sortedMap;
+ }
+ function escapeReservedSymbols(text) {
+ return text.replace(/\//g, '[\\/]').replace('/-/g', '[-]').replace(/\./g, '[.]').replace(/\\s/g, '[\\s]');
}
- };
- }]);
+ function regExpForFormat(format) {
+ var keys = Object.keys(regExpMap), i;
-// Source: modal.js
-angular.module('mgcrea.ngStrap.modal', ['mgcrea.ngStrap.helpers.dimensions'])
+ var re = format;
+ // Abstract replaces to avoid collisions
+ for(i = 0; i < keys.length; i++) {
+ re = re.split(keys[i]).join('${' + i + '}');
+ }
+ // Replace abstracted values
+ for(i = 0; i < keys.length; i++) {
+ re = re.split('${' + i + '}').join('(' + regExpMap[keys[i]] + ')');
+ }
+ format = escapeReservedSymbols(format);
- .provider('$modal', function() {
+ return new RegExp('^' + re + '$', ['i']);
+ }
+
+ $dateParser.init();
+ return $dateParser;
- var defaults = this.defaults = {
- animation: 'am-fade',
- backdropAnimation: 'am-fade',
- prefixClass: 'modal',
- prefixEvent: 'modal',
- placement: 'top',
- template: 'modal/modal.tpl.html',
- contentTemplate: false,
- container: false,
- element: null,
- backdrop: true,
- keyboard: true,
- html: false,
- show: true
};
- this.$get = ["$window", "$rootScope", "$compile", "$q", "$templateCache", "$http", "$animate", "$timeout", "$sce", "dimensions", function($window, $rootScope, $compile, $q, $templateCache, $http, $animate, $timeout, $sce, dimensions) {
+ return DateParserFactory;
- var forEach = angular.forEach;
- var trim = String.prototype.trim;
- var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;
- var bodyElement = angular.element($window.document.body);
- var htmlReplaceRegExp = /ng-bind="/ig;
+ }];
- function ModalFactory(config) {
+}]);
- var $modal = {};
+// Source: debounce.js
+angular.module('mgcrea.ngStrap.helpers.debounce', [])
- // Common vars
- var options = $modal.$options = angular.extend({}, defaults, config);
- $modal.$promise = fetchTemplate(options.template);
- var scope = $modal.$scope = options.scope && options.scope.$new() || $rootScope.$new();
- if(!options.element && !options.container) {
- options.container = 'body';
+// @source jashkenas/underscore
+// @url https://github.com/jashkenas/underscore/blob/1.5.2/underscore.js#L693
+.factory('debounce', ["$timeout", function($timeout) {
+ return function(func, wait, immediate) {
+ var timeout = null;
+ return function() {
+ var context = this,
+ args = arguments,
+ callNow = immediate && !timeout;
+ if(timeout) {
+ $timeout.cancel(timeout);
+ }
+ timeout = $timeout(function later() {
+ timeout = null;
+ if(!immediate) {
+ func.apply(context, args);
}
+ }, wait, false);
+ if(callNow) {
+ func.apply(context, args);
+ }
+ return timeout;
+ };
+ };
+}])
- // Support scope as string options
- forEach(['title', 'content'], function(key) {
- if(options[key]) scope[key] = $sce.trustAsHtml(options[key]);
- });
-
- // Provide scope helpers
- scope.$hide = function() {
- scope.$$postDigest(function() {
- $modal.hide();
- });
- };
- scope.$show = function() {
- scope.$$postDigest(function() {
- $modal.show();
- });
- };
- scope.$toggle = function() {
- scope.$$postDigest(function() {
- $modal.toggle();
- });
- };
- // Publish isShown as a protected var on scope
- $modal.$isShown = scope.$isShown = false;
- // Support contentTemplate option
- if(options.contentTemplate) {
- $modal.$promise = $modal.$promise.then(function(template) {
- var templateEl = angular.element(template);
- return fetchTemplate(options.contentTemplate)
- .then(function(contentTemplate) {
- var contentEl = findElement('[ng-bind="content"]', templateEl[0]).removeAttr('ng-bind').html(contentTemplate);
- // Drop the default footer as you probably don't want it if you use a custom contentTemplate
- if(!config.template) contentEl.next().remove();
- return templateEl[0].outerHTML;
- });
- });
+// @source jashkenas/underscore
+// @url https://github.com/jashkenas/underscore/blob/1.5.2/underscore.js#L661
+.factory('throttle', ["$timeout", function($timeout) {
+ return function(func, wait, options) {
+ var timeout = null;
+ options || (options = {});
+ return function() {
+ var context = this,
+ args = arguments;
+ if(!timeout) {
+ if(options.leading !== false) {
+ func.apply(context, args);
}
-
- // Fetch, compile then initialize modal
- var modalLinker, modalElement;
- var backdropElement = angular.element('
');
- $modal.$promise.then(function(template) {
- if(angular.isObject(template)) template = template.data;
- if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html="');
- template = trim.apply(template);
- modalLinker = $compile(template);
- $modal.init();
- });
-
- $modal.init = function() {
-
- // Options: show
- if(options.show) {
- scope.$$postDigest(function() {
- $modal.show();
- });
+ timeout = $timeout(function later() {
+ timeout = null;
+ if(options.trailing !== false) {
+ func.apply(context, args);
}
+ }, wait, false);
+ }
+ };
+ };
+}]);
- };
-
- $modal.destroy = function() {
-
- // Remove element
- if(modalElement) {
- modalElement.remove();
- modalElement = null;
- }
- if(backdropElement) {
- backdropElement.remove();
- backdropElement = null;
- }
+// Source: dimensions.js
+angular.module('mgcrea.ngStrap.helpers.dimensions', [])
- // Destroy scope
- scope.$destroy();
+ .factory('dimensions', ["$document", "$window", function($document, $window) {
- };
+ var jqLite = angular.element;
+ var fn = {};
- $modal.show = function() {
- if($modal.$isShown) return;
+ /**
+ * Test the element nodeName
+ * @param element
+ * @param name
+ */
+ var nodeName = fn.nodeName = function(element, name) {
+ return element.nodeName && element.nodeName.toLowerCase() === name.toLowerCase();
+ };
- if(scope.$emit(options.prefixEvent + '.show.before', $modal).defaultPrevented) {
- return;
- }
- var parent, after;
- if(angular.isElement(options.container)) {
- parent = options.container;
- after = options.container[0].lastChild ? angular.element(options.container[0].lastChild) : null;
- } else {
- if (options.container) {
- parent = findElement(options.container);
- after = parent[0].lastChild ? angular.element(parent[0].lastChild) : null;
- } else {
- parent = null;
- after = options.element;
- }
- }
+ /**
+ * Returns the element computed style
+ * @param element
+ * @param prop
+ * @param extra
+ */
+ fn.css = function(element, prop, extra) {
+ var value;
+ if (element.currentStyle) { //IE
+ value = element.currentStyle[prop];
+ } else if (window.getComputedStyle) {
+ value = window.getComputedStyle(element)[prop];
+ } else {
+ value = element.style[prop];
+ }
+ return extra === true ? parseFloat(value) || 0 : value;
+ };
- // Fetch a cloned element linked from template
- modalElement = $modal.$element = modalLinker(scope, function(clonedElement, scope) {});
+ /**
+ * Provides read-only equivalent of jQuery's offset function:
+ * @required-by bootstrap-tooltip, bootstrap-affix
+ * @url http://api.jquery.com/offset/
+ * @param element
+ */
+ fn.offset = function(element) {
+ var boxRect = element.getBoundingClientRect();
+ var docElement = element.ownerDocument;
+ return {
+ width: boxRect.width || element.offsetWidth,
+ height: boxRect.height || element.offsetHeight,
+ top: boxRect.top + (window.pageYOffset || docElement.documentElement.scrollTop) - (docElement.documentElement.clientTop || 0),
+ left: boxRect.left + (window.pageXOffset || docElement.documentElement.scrollLeft) - (docElement.documentElement.clientLeft || 0)
+ };
+ };
- // Set the initial positioning.
- modalElement.css({display: 'block'}).addClass(options.placement);
+ /**
+ * Provides read-only equivalent of jQuery's position function
+ * @required-by bootstrap-tooltip, bootstrap-affix
+ * @url http://api.jquery.com/offset/
+ * @param element
+ */
+ fn.position = function(element) {
- // Options: animation
- if(options.animation) {
- if(options.backdrop) {
- backdropElement.addClass(options.backdropAnimation);
- }
- modalElement.addClass(options.animation);
- }
+ var offsetParentRect = {top: 0, left: 0},
+ offsetParentElement,
+ offset;
- if(options.backdrop) {
- $animate.enter(backdropElement, bodyElement, null);
- }
- // Support v1.3+ $animate
- // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9
- var promise = $animate.enter(modalElement, parent, after, enterAnimateCallback);
- if(promise && promise.then) promise.then(enterAnimateCallback);
+ // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent
+ if (fn.css(element, 'position') === 'fixed') {
- $modal.$isShown = scope.$isShown = true;
- safeDigest(scope);
- // Focus once the enter-animation has started
- // Weird PhantomJS bug hack
- var el = modalElement[0];
- requestAnimationFrame(function() {
- el.focus();
- });
+ // We assume that getBoundingClientRect is available when computed position is fixed
+ offset = element.getBoundingClientRect();
- bodyElement.addClass(options.prefixClass + '-open');
- if(options.animation) {
- bodyElement.addClass(options.prefixClass + '-with-' + options.animation);
- }
+ } else {
- // Bind events
- if(options.backdrop) {
- modalElement.on('click', hideOnBackdropClick);
- backdropElement.on('click', hideOnBackdropClick);
- backdropElement.on('wheel', preventEventDefault);
- }
- if(options.keyboard) {
- modalElement.on('keyup', $modal.$onKeyUp);
- }
- };
+ // Get *real* offsetParentElement
+ offsetParentElement = offsetParent(element);
- function enterAnimateCallback() {
- scope.$emit(options.prefixEvent + '.show', $modal);
+ // Get correct offsets
+ offset = fn.offset(element);
+ if (!nodeName(offsetParentElement, 'html')) {
+ offsetParentRect = fn.offset(offsetParentElement);
}
- $modal.hide = function() {
- if(!$modal.$isShown) return;
+ // Add offsetParent borders
+ offsetParentRect.top += fn.css(offsetParentElement, 'borderTopWidth', true);
+ offsetParentRect.left += fn.css(offsetParentElement, 'borderLeftWidth', true);
+ }
- if(scope.$emit(options.prefixEvent + '.hide.before', $modal).defaultPrevented) {
- return;
- }
- var promise = $animate.leave(modalElement, leaveAnimateCallback);
- // Support v1.3+ $animate
- // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9
- if(promise && promise.then) promise.then(leaveAnimateCallback);
+ // Subtract parent offsets and element margins
+ return {
+ width: element.offsetWidth,
+ height: element.offsetHeight,
+ top: offset.top - offsetParentRect.top - fn.css(element, 'marginTop', true),
+ left: offset.left - offsetParentRect.left - fn.css(element, 'marginLeft', true)
+ };
- if(options.backdrop) {
- $animate.leave(backdropElement);
- }
- $modal.$isShown = scope.$isShown = false;
- safeDigest(scope);
+ };
- // Unbind events
- if(options.backdrop) {
- modalElement.off('click', hideOnBackdropClick);
- backdropElement.off('click', hideOnBackdropClick);
- backdropElement.off('wheel', preventEventDefault);
- }
- if(options.keyboard) {
- modalElement.off('keyup', $modal.$onKeyUp);
- }
- };
+ /**
+ * Returns the closest, non-statically positioned offsetParent of a given element
+ * @required-by fn.position
+ * @param element
+ */
+ var offsetParent = function offsetParentElement(element) {
+ var docElement = element.ownerDocument;
+ var offsetParent = element.offsetParent || docElement;
+ if(nodeName(offsetParent, '#document')) return docElement.documentElement;
+ while(offsetParent && !nodeName(offsetParent, 'html') && fn.css(offsetParent, 'position') === 'static') {
+ offsetParent = offsetParent.offsetParent;
+ }
+ return offsetParent || docElement.documentElement;
+ };
- function leaveAnimateCallback() {
- scope.$emit(options.prefixEvent + '.hide', $modal);
- bodyElement.removeClass(options.prefixClass + '-open');
- if(options.animation) {
- bodyElement.removeClass(options.prefixClass + '-with-' + options.animation);
- }
- }
+ /**
+ * Provides equivalent of jQuery's height function
+ * @required-by bootstrap-affix
+ * @url http://api.jquery.com/height/
+ * @param element
+ * @param outer
+ */
+ fn.height = function(element, outer) {
+ var value = element.offsetHeight;
+ if(outer) {
+ value += fn.css(element, 'marginTop', true) + fn.css(element, 'marginBottom', true);
+ } else {
+ value -= fn.css(element, 'paddingTop', true) + fn.css(element, 'paddingBottom', true) + fn.css(element, 'borderTopWidth', true) + fn.css(element, 'borderBottomWidth', true);
+ }
+ return value;
+ };
- $modal.toggle = function() {
+ /**
+ * Provides equivalent of jQuery's width function
+ * @required-by bootstrap-affix
+ * @url http://api.jquery.com/width/
+ * @param element
+ * @param outer
+ */
+ fn.width = function(element, outer) {
+ var value = element.offsetWidth;
+ if(outer) {
+ value += fn.css(element, 'marginLeft', true) + fn.css(element, 'marginRight', true);
+ } else {
+ value -= fn.css(element, 'paddingLeft', true) + fn.css(element, 'paddingRight', true) + fn.css(element, 'borderLeftWidth', true) + fn.css(element, 'borderRightWidth', true);
+ }
+ return value;
+ };
- $modal.$isShown ? $modal.hide() : $modal.show();
+ return fn;
- };
+ }]);
- $modal.focus = function() {
- modalElement[0].focus();
- };
+// Source: parse-options.js
+angular.module('mgcrea.ngStrap.helpers.parseOptions', [])
- // Protected methods
+ .provider('$parseOptions', function() {
- $modal.$onKeyUp = function(evt) {
+ var defaults = this.defaults = {
+ regexp: /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/
+ };
- if (evt.which === 27 && $modal.$isShown) {
- $modal.hide();
- evt.stopPropagation();
- }
+ this.$get = ["$parse", "$q", function($parse, $q) {
- };
+ function ParseOptionsFactory(attr, config) {
- // Private methods
+ var $parseOptions = {};
- function hideOnBackdropClick(evt) {
- if(evt.target !== evt.currentTarget) return;
- options.backdrop === 'static' ? $modal.focus() : $modal.hide();
- }
+ // Common vars
+ var options = angular.extend({}, defaults, config);
+ $parseOptions.$values = [];
- function preventEventDefault(evt) {
- evt.preventDefault();
- }
+ // Private vars
+ var match, displayFn, valueName, keyName, groupByFn, valueFn, valuesFn;
- return $modal;
+ $parseOptions.init = function() {
+ $parseOptions.$match = match = attr.match(options.regexp);
+ displayFn = $parse(match[2] || match[1]),
+ valueName = match[4] || match[6],
+ keyName = match[5],
+ groupByFn = $parse(match[3] || ''),
+ valueFn = $parse(match[2] ? match[1] : valueName),
+ valuesFn = $parse(match[7]);
+ };
- }
+ $parseOptions.valuesFn = function(scope, controller) {
+ return $q.when(valuesFn(scope, controller))
+ .then(function(values) {
+ $parseOptions.$values = values ? parseValues(values, scope) : {};
+ return $parseOptions.$values;
+ });
+ };
- // Helper functions
+ $parseOptions.displayValue = function(modelValue) {
+ var scope = {};
+ scope[valueName] = modelValue;
+ return displayFn(scope);
+ };
- function safeDigest(scope) {
- scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();
- }
+ // Private functions
- function findElement(query, element) {
- return angular.element((element || document).querySelectorAll(query));
- }
+ function parseValues(values, scope) {
+ return values.map(function(match, index) {
+ var locals = {}, label, value;
+ locals[valueName] = match;
+ label = displayFn(scope, locals);
+ value = valueFn(scope, locals);
+ return {label: label, value: value, index: index};
+ });
+ }
+
+ $parseOptions.init();
+ return $parseOptions;
- var fetchPromises = {};
- function fetchTemplate(template) {
- if(fetchPromises[template]) return fetchPromises[template];
- return (fetchPromises[template] = $q.when($templateCache.get(template) || $http.get(template))
- .then(function(res) {
- if(angular.isObject(res)) {
- $templateCache.put(template, res.data);
- return res.data;
- }
- return res;
- }));
}
- return ModalFactory;
+ return ParseOptionsFactory;
}];
- })
+ });
- .directive('bsModal', ["$window", "$sce", "$modal", function($window, $sce, $modal) {
+// Source: raf.js
+(angular.version.minor < 3 && angular.version.dot < 14) && angular.module('ng')
- return {
- restrict: 'EAC',
- scope: true,
- link: function postLink(scope, element, attr, transclusion) {
+.factory('$$rAF', ["$window", "$timeout", function($window, $timeout) {
+
+ var requestAnimationFrame = $window.requestAnimationFrame ||
+ $window.webkitRequestAnimationFrame ||
+ $window.mozRequestAnimationFrame;
- // Directive options
- var options = {scope: scope, element: element, show: false};
- angular.forEach(['template', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation'], function(key) {
- if(angular.isDefined(attr[key])) options[key] = attr[key];
- });
+ var cancelAnimationFrame = $window.cancelAnimationFrame ||
+ $window.webkitCancelAnimationFrame ||
+ $window.mozCancelAnimationFrame ||
+ $window.webkitCancelRequestAnimationFrame;
- // Support scope as data-attrs
- angular.forEach(['title', 'content'], function(key) {
- attr[key] && attr.$observe(key, function(newValue, oldValue) {
- scope[key] = $sce.trustAsHtml(newValue);
- });
- });
+ var rafSupported = !!requestAnimationFrame;
+ var raf = rafSupported ?
+ function(fn) {
+ var id = requestAnimationFrame(fn);
+ return function() {
+ cancelAnimationFrame(id);
+ };
+ } :
+ function(fn) {
+ var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
+ return function() {
+ $timeout.cancel(timer);
+ };
+ };
- // Support scope as an object
- attr.bsModal && scope.$watch(attr.bsModal, function(newValue, oldValue) {
- if(angular.isObject(newValue)) {
- angular.extend(scope, newValue);
- } else {
- scope.content = newValue;
- }
- }, true);
+ raf.supported = rafSupported;
- // Initialize modal
- var modal = $modal(options);
+ return raf;
- // Trigger
- element.on(attr.trigger || 'click', modal.toggle);
+}]);
- // Garbage collection
- scope.$on('$destroy', function() {
- if (modal) modal.destroy();
- options = null;
- modal = null;
- });
+// .factory('$$animateReflow', function($$rAF, $document) {
- }
- };
+// var bodyEl = $document[0].body;
- }]);
+// return function(fn) {
+// //the returned function acts as the cancellation function
+// return $$rAF(function() {
+// //the line below will force the browser to perform a repaint
+// //so that all the animated elements within the animation frame
+// //will be properly updated and drawn on screen. This is
+// //required to perform multi-class CSS based animations with
+// //Firefox. DO NOT REMOVE THIS LINE.
+// var a = bodyEl.offsetWidth + 1;
+// fn();
+// });
+// };
+
+// });
// Source: navbar.js
angular.module('mgcrea.ngStrap.navbar', [])
@@ -2729,6 +2729,151 @@ angular.module('mgcrea.ngStrap.navbar', [])
}]);
+// Source: popover.js
+angular.module('mgcrea.ngStrap.popover', ['mgcrea.ngStrap.tooltip'])
+
+ .provider('$popover', function() {
+
+ var defaults = this.defaults = {
+ animation: 'am-fade',
+ customClass: '',
+ container: false,
+ target: false,
+ placement: 'right',
+ template: 'popover/popover.tpl.html',
+ contentTemplate: false,
+ trigger: 'click',
+ keyboard: true,
+ html: false,
+ title: '',
+ content: '',
+ delay: 0,
+ autoClose: false
+ };
+
+ this.$get = ["$tooltip", function($tooltip) {
+
+ function PopoverFactory(element, config) {
+
+ // Common vars
+ var options = angular.extend({}, defaults, config);
+
+ var $popover = $tooltip(element, options);
+
+ // Support scope as string options [/*title, */content]
+ if(options.content) {
+ $popover.$scope.content = options.content;
+ }
+
+ return $popover;
+
+ }
+
+ return PopoverFactory;
+
+ }];
+
+ })
+
+ .directive('bsPopover', ["$window", "$sce", "$popover", function($window, $sce, $popover) {
+
+ var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;
+
+ return {
+ restrict: 'EAC',
+ scope: true,
+ link: function postLink(scope, element, attr) {
+
+ // Directive options
+ var options = {scope: scope};
+ angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'customClass', 'autoClose'], function(key) {
+ if(angular.isDefined(attr[key])) options[key] = attr[key];
+ });
+
+ // Support scope as data-attrs
+ angular.forEach(['title', 'content'], function(key) {
+ attr[key] && attr.$observe(key, function(newValue, oldValue) {
+ scope[key] = $sce.trustAsHtml(newValue);
+ angular.isDefined(oldValue) && requestAnimationFrame(function() {
+ popover && popover.$applyPlacement();
+ });
+ });
+ });
+
+ // Support scope as an object
+ attr.bsPopover && scope.$watch(attr.bsPopover, function(newValue, oldValue) {
+ if(angular.isObject(newValue)) {
+ angular.extend(scope, newValue);
+ } else {
+ scope.content = newValue;
+ }
+ angular.isDefined(oldValue) && requestAnimationFrame(function() {
+ popover && popover.$applyPlacement();
+ });
+ }, true);
+
+ // Visibility binding support
+ attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {
+ if(!popover || !angular.isDefined(newValue)) return;
+ if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(popover),?/i);
+ newValue === true ? popover.show() : popover.hide();
+ });
+
+ // Initialize popover
+ var popover = $popover(element, options);
+
+ // Garbage collection
+ scope.$on('$destroy', function() {
+ if (popover) popover.destroy();
+ options = null;
+ popover = null;
+ });
+
+ }
+ };
+
+ }]);
+
+// Source: progressbar.js
+angular.module('mgcrea.ngStrap.progressbar', [])
+.provider('$progressbar', function (){
+ var defaults = {
+ barType: '',
+ animate: function (){ return true;}
+ };
+
+ this.$get = function (){
+ return {
+ defaults: defaults
+ };
+ };
+ })
+ .directive('bsProgressbar', ["$progressbar", function ($progressbar){
+ return {
+ restrict: 'E',
+ transclude: true,
+ replace: true,
+ templateUrl: 'progressbar/progressbar.tpl.html',
+ scope:{
+ value: '=',
+ type: '@',
+ animate: '&'
+ },
+ link: function (scope, element, attr){
+ scope.type = scope.type || $progressbar.defaults.barType;
+ scope.animate = angular.isDefined(scope.animate()) ? scope.animate : $progressbar.defaults.animate;
+ scope.$watch('type', function (){
+ if(scope.type) {
+ scope.barClass = 'progress-bar-' + scope.type;
+ }
+ else{
+ scope.barClass = null;
+ }
+ });
+ }
+ };
+ }]);
+
// Source: scrollspy.js
angular.module('mgcrea.ngStrap.scrollspy', ['mgcrea.ngStrap.helpers.debounce', 'mgcrea.ngStrap.helpers.dimensions'])
@@ -2980,48 +3125,7 @@ angular.module('mgcrea.ngStrap.scrollspy', ['mgcrea.ngStrap.helpers.debounce', '
}
};
-
- }]);
-
-// Source: progressbar.js
-angular.module('mgcrea.ngStrap.progressbar', [])
-.provider('$progressbar', function (){
- var defaults = {
- barType: '',
- animate: function (){ return true;}
- };
-
- this.$get = function (){
- return {
- defaults: defaults
- };
- };
- })
- .directive('bsProgressbar', ["$progressbar", function ($progressbar){
- return {
- restrict: 'E',
- transclude: true,
- replace: true,
- templateUrl: 'progressbar/progressbar.tpl.html',
- scope:{
- value: '=',
- type: '@',
- animate: '&'
- },
- link: function (scope, element, attr){
- scope.type = scope.type || $progressbar.defaults.barType;
- scope.animate = angular.isDefined(scope.animate()) ? scope.animate : $progressbar.defaults.animate;
- console.log(scope.animate(), $progressbar.defaults.animate, angular.isDefined(scope.animate));
- scope.$watch('type', function (){
- if(scope.type) {
- scope.barClass = 'progress-bar-' + scope.type;
- }
- else{
- scope.barClass = null;
- }
- });
- }
- };
+
}]);
// Source: select.js
@@ -3461,1310 +3565,1205 @@ angular.module('mgcrea.ngStrap.tab', [])
// Update bsActivePane value with change
bsTabsCtrl.$activePaneChangeListeners.push(function() {
- parsedBsActivePane.assign(scope, bsTabsCtrl.$panes.$active);
- });
-
- // watch bsActivePane for value changes
- scope.$watch(attrs.bsActivePane, function(newValue, oldValue) {
- bsTabsCtrl.$setActive(newValue * 1);
- }, true);
- }
- }
- };
-
- }])
-
- .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.$activePaneChangeListeners.push(function() {
- render();
- });
- render();
-
- }
- };
-
- }]);
-
-// Source: popover.js
-angular.module('mgcrea.ngStrap.popover', ['mgcrea.ngStrap.tooltip'])
-
- .provider('$popover', function() {
-
- var defaults = this.defaults = {
- animation: 'am-fade',
- customClass: '',
- container: false,
- target: false,
- placement: 'right',
- template: 'popover/popover.tpl.html',
- contentTemplate: false,
- trigger: 'click',
- keyboard: true,
- html: false,
- title: '',
- content: '',
- delay: 0,
- autoClose: false
- };
-
- this.$get = ["$tooltip", function($tooltip) {
-
- function PopoverFactory(element, config) {
-
- // Common vars
- var options = angular.extend({}, defaults, config);
-
- var $popover = $tooltip(element, options);
-
- // Support scope as string options [/*title, */content]
- if(options.content) {
- $popover.$scope.content = options.content;
- }
-
- return $popover;
-
- }
-
- return PopoverFactory;
-
- }];
-
- })
-
- .directive('bsPopover', ["$window", "$sce", "$popover", function($window, $sce, $popover) {
-
- var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;
-
- return {
- restrict: 'EAC',
- scope: true,
- link: function postLink(scope, element, attr) {
-
- // Directive options
- var options = {scope: scope};
- angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'customClass', 'autoClose'], function(key) {
- if(angular.isDefined(attr[key])) options[key] = attr[key];
- });
-
- // Support scope as data-attrs
- angular.forEach(['title', 'content'], function(key) {
- attr[key] && attr.$observe(key, function(newValue, oldValue) {
- scope[key] = $sce.trustAsHtml(newValue);
- angular.isDefined(oldValue) && requestAnimationFrame(function() {
- popover && popover.$applyPlacement();
- });
- });
- });
-
- // Support scope as an object
- attr.bsPopover && scope.$watch(attr.bsPopover, function(newValue, oldValue) {
- if(angular.isObject(newValue)) {
- angular.extend(scope, newValue);
- } else {
- scope.content = newValue;
- }
- angular.isDefined(oldValue) && requestAnimationFrame(function() {
- popover && popover.$applyPlacement();
- });
- }, true);
-
- // Visibility binding support
- attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {
- if(!popover || !angular.isDefined(newValue)) return;
- if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(popover),?/i);
- newValue === true ? popover.show() : popover.hide();
- });
-
- // Initialize popover
- var popover = $popover(element, options);
-
- // Garbage collection
- scope.$on('$destroy', function() {
- if (popover) popover.destroy();
- options = null;
- popover = null;
- });
-
- }
- };
-
- }]);
-
-// Source: tooltip.js
-angular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions'])
-
- .provider('$tooltip', function() {
-
- var defaults = this.defaults = {
- animation: 'am-fade',
- customClass: '',
- prefixClass: 'tooltip',
- prefixEvent: 'tooltip',
- container: false,
- target: false,
- placement: 'top',
- template: 'tooltip/tooltip.tpl.html',
- contentTemplate: false,
- trigger: 'hover focus',
- keyboard: false,
- html: false,
- show: false,
- title: '',
- type: '',
- delay: 0,
- autoClose: false,
- bsEnabled: true
- };
-
- this.$get = ["$window", "$rootScope", "$compile", "$q", "$templateCache", "$http", "$animate", "$sce", "dimensions", "$$rAF", "$timeout", function($window, $rootScope, $compile, $q, $templateCache, $http, $animate, $sce, dimensions, $$rAF, $timeout) {
-
- var trim = String.prototype.trim;
- var isTouch = 'createTouch' in $window.document;
- var htmlReplaceRegExp = /ng-bind="/ig;
- var $body = angular.element($window.document);
-
- function TooltipFactory(element, config) {
-
- var $tooltip = {};
-
- // Common vars
- var nodeName = element[0].nodeName.toLowerCase();
- var options = $tooltip.$options = angular.extend({}, defaults, config);
- $tooltip.$promise = fetchTemplate(options.template);
- var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new();
- if(options.delay && angular.isString(options.delay)) {
- var split = options.delay.split(',').map(parseFloat);
- options.delay = split.length > 1 ? {show: split[0], hide: split[1]} : split[0];
- }
-
- // Support scope as string options
- if(options.title) {
- scope.title = $sce.trustAsHtml(options.title);
- }
-
- // Provide scope helpers
- scope.$setEnabled = function(isEnabled) {
- scope.$$postDigest(function() {
- $tooltip.setEnabled(isEnabled);
- });
- };
- scope.$hide = function() {
- scope.$$postDigest(function() {
- $tooltip.hide();
- });
- };
- scope.$show = function() {
- scope.$$postDigest(function() {
- $tooltip.show();
- });
- };
- scope.$toggle = function() {
- scope.$$postDigest(function() {
- $tooltip.toggle();
- });
- };
- // Publish isShown as a protected var on scope
- $tooltip.$isShown = scope.$isShown = false;
-
- // Private vars
- var timeout, hoverState;
-
- // Support contentTemplate option
- if(options.contentTemplate) {
- $tooltip.$promise = $tooltip.$promise.then(function(template) {
- var templateEl = angular.element(template);
- return fetchTemplate(options.contentTemplate)
- .then(function(contentTemplate) {
- var contentEl = findElement('[ng-bind="content"]', templateEl[0]);
- if(!contentEl.length) contentEl = findElement('[ng-bind="title"]', templateEl[0]);
- contentEl.removeAttr('ng-bind').html(contentTemplate);
- return templateEl[0].outerHTML;
- });
+ parsedBsActivePane.assign(scope, bsTabsCtrl.$panes.$active);
});
+
+ // watch bsActivePane for value changes
+ scope.$watch(attrs.bsActivePane, function(newValue, oldValue) {
+ bsTabsCtrl.$setActive(newValue * 1);
+ }, true);
}
+ }
+ };
- // Fetch, compile then initialize tooltip
- var tipLinker, tipElement, tipTemplate, tipContainer, tipScope;
- $tooltip.$promise.then(function(template) {
- if(angular.isObject(template)) template = template.data;
- if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html="');
- template = trim.apply(template);
- tipTemplate = template;
- tipLinker = $compile(template);
- $tooltip.init();
- });
+ }])
- $tooltip.init = function() {
+ .directive('bsPane', ["$window", "$animate", "$sce", function($window, $animate, $sce) {
- // Options: delay
- if (options.delay && angular.isNumber(options.delay)) {
- options.delay = {
- show: options.delay,
- hide: options.delay
- };
- }
+ return {
+ require: ['^?ngModel', '^bsTabs'],
+ scope: true,
+ link: function postLink(scope, element, attrs, controllers) {
- // Replace trigger on touch devices ?
- // if(isTouch && options.trigger === defaults.trigger) {
- // options.trigger.replace(/hover/g, 'click');
- // }
+ var ngModelCtrl = controllers[0];
+ var bsTabsCtrl = controllers[1];
- // Options : container
- if(options.container === 'self') {
- tipContainer = element;
- } else if(angular.isElement(options.container)) {
- tipContainer = options.container;
- } else if(options.container) {
- tipContainer = findElement(options.container);
- }
+ // Add base class
+ element.addClass('tab-pane');
- // Options: trigger
- bindTriggerEvents();
+ // Observe title attribute for change
+ attrs.$observe('title', function(newValue, oldValue) {
+ scope.title = $sce.trustAsHtml(newValue);
+ });
- // Options: target
- if(options.target) {
- options.target = angular.isElement(options.target) ? options.target : findElement(options.target);
- }
+ // Add animation class
+ if(bsTabsCtrl.$options.animation) {
+ element.addClass(bsTabsCtrl.$options.animation);
+ }
- // Options: show
- if(options.show) {
- scope.$$postDigest(function() {
- options.trigger === 'focus' ? element[0].focus() : $tooltip.show();
- });
- }
+ // 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);
+ });
- $tooltip.destroy = function() {
+ function render() {
+ var index = bsTabsCtrl.$panes.indexOf(scope);
+ var active = bsTabsCtrl.$panes.$active;
+ $animate[index === active ? 'addClass' : 'removeClass'](element, bsTabsCtrl.$options.activeClass);
+ }
- // Unbind events
- unbindTriggerEvents();
+ bsTabsCtrl.$activePaneChangeListeners.push(function() {
+ render();
+ });
+ render();
- // Remove element
- destroyTipElement();
+ }
+ };
- // Destroy scope
- scope.$destroy();
+ }]);
- };
+// Source: timepicker.js
+angular.module('mgcrea.ngStrap.timepicker', [
+ 'mgcrea.ngStrap.helpers.dateParser',
+ 'mgcrea.ngStrap.helpers.dateFormatter',
+ 'mgcrea.ngStrap.tooltip'])
- $tooltip.enter = function() {
+ .provider('$timepicker', function() {
- clearTimeout(timeout);
- hoverState = 'in';
- if (!options.delay || !options.delay.show) {
- return $tooltip.show();
- }
+ var defaults = this.defaults = {
+ animation: 'am-fade',
+ prefixClass: 'timepicker',
+ placement: 'bottom-left',
+ template: 'timepicker/timepicker.tpl.html',
+ trigger: 'focus',
+ container: false,
+ keyboard: true,
+ html: false,
+ delay: 0,
+ // lang: $locale.id,
+ useNative: true,
+ timeType: 'date',
+ timeFormat: 'shortTime',
+ modelTimeFormat: null,
+ autoclose: false,
+ minTime: -Infinity,
+ maxTime: +Infinity,
+ length: 5,
+ hourStep: 1,
+ minuteStep: 5,
+ iconUp: 'glyphicon glyphicon-chevron-up',
+ iconDown: 'glyphicon glyphicon-chevron-down',
+ arrowBehavior: 'pager'
+ };
- timeout = setTimeout(function() {
- if (hoverState ==='in') $tooltip.show();
- }, options.delay.show);
+ this.$get = ["$window", "$document", "$rootScope", "$sce", "$dateFormatter", "$tooltip", "$timeout", function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) {
+
+ var bodyEl = angular.element($window.document.body);
+ var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);
+ var isTouch = ('createTouch' in $window.document) && isNative;
+ if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();
+
+ function timepickerFactory(element, controller, config) {
+
+ var $timepicker = $tooltip(element, angular.extend({}, defaults, config));
+ var parentScope = config.scope;
+ var options = $timepicker.$options;
+ var scope = $timepicker.$scope;
+ var lang = options.lang;
+ var formatDate = function(date, format) {
+ return $dateFormatter.formatDate(date, format, lang);
};
- $tooltip.show = function() {
- if (!options.bsEnabled || $tooltip.$isShown) return;
+ // View vars
- scope.$emit(options.prefixEvent + '.show.before', $tooltip);
- var parent, after;
- if (options.container) {
- parent = tipContainer;
- if (tipContainer[0].lastChild) {
- after = angular.element(tipContainer[0].lastChild);
- } else {
- after = null;
- }
- } else {
- parent = null;
- after = element;
- }
+ var selectedIndex = 0;
+ var startDate = controller.$dateValue || new Date();
+ var viewDate = {hour: startDate.getHours(), meridian: startDate.getHours() < 12, minute: startDate.getMinutes(), second: startDate.getSeconds(), millisecond: startDate.getMilliseconds()};
+ var format = $dateFormatter.getDatetimeFormat(options.timeFormat, lang);
- // Hide any existing tipElement
- if(tipElement) destroyTipElement();
- // Fetch a cloned element linked from template
- tipScope = $tooltip.$scope.$new();
- tipElement = $tooltip.$element = tipLinker(tipScope, function(clonedElement, scope) {});
+ var hoursFormat = $dateFormatter.hoursFormat(format),
+ timeSeparator = $dateFormatter.timeSeparator(format),
+ minutesFormat = $dateFormatter.minutesFormat(format),
+ showAM = $dateFormatter.showAM(format);
- // Set the initial positioning. Make the tooltip invisible
- // so IE doesn't try to focus on it off screen.
- tipElement.css({top: '-9999px', left: '-9999px', display: 'block', visibility: 'hidden'});
+ scope.$iconUp = options.iconUp;
+ scope.$iconDown = options.iconDown;
- // Options: animation
- if(options.animation) tipElement.addClass(options.animation);
- // Options: type
- if(options.type) tipElement.addClass(options.prefixClass + '-' + options.type);
- // Options: custom classes
- if(options.customClass) tipElement.addClass(options.customClass);
+ // Scope methods
- // Support v1.3+ $animate
- // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9
- var promise = $animate.enter(tipElement, parent, after, enterAnimateCallback);
- if(promise && promise.then) promise.then(enterAnimateCallback);
+ scope.$select = function(date, index) {
+ $timepicker.select(date, index);
+ };
+ scope.$moveIndex = function(value, index) {
+ $timepicker.$moveIndex(value, index);
+ };
+ scope.$switchMeridian = function(date) {
+ $timepicker.switchMeridian(date);
+ };
- $tooltip.$isShown = scope.$isShown = true;
- safeDigest(scope);
- $$rAF(function () {
- $tooltip.$applyPlacement();
+ // Public methods
- // Once placed, make the tooltip visible
- if(tipElement) tipElement.css({visibility: 'visible'});
- }); // var a = bodyEl.offsetWidth + 1; ?
+ $timepicker.update = function(date) {
+ // console.warn('$timepicker.update() newValue=%o', date);
+ if(angular.isDate(date) && !isNaN(date.getTime())) {
+ $timepicker.$date = date;
+ angular.extend(viewDate, {hour: date.getHours(), minute: date.getMinutes(), second: date.getSeconds(), millisecond: date.getMilliseconds()});
+ $timepicker.$build();
+ } else if(!$timepicker.$isBuilt) {
+ $timepicker.$build();
+ }
+ };
- // Bind events
- if(options.keyboard) {
- if(options.trigger !== 'focus') {
- $tooltip.focus();
- }
- bindKeyboardEvents();
+ $timepicker.select = function(date, index, keep) {
+ // console.warn('$timepicker.select', date, scope.$mode);
+ if(!controller.$dateValue || isNaN(controller.$dateValue.getTime())) controller.$dateValue = new Date(1970, 0, 1);
+ if(!angular.isDate(date)) date = new Date(date);
+ if(index === 0) controller.$dateValue.setHours(date.getHours());
+ else if(index === 1) controller.$dateValue.setMinutes(date.getMinutes());
+ controller.$setViewValue(angular.copy(controller.$dateValue));
+ controller.$render();
+ if(options.autoclose && !keep) {
+ $timeout(function() { $timepicker.hide(true); });
+ }
+ };
+
+ $timepicker.switchMeridian = function(date) {
+ if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) {
+ return;
+ }
+ var hours = (date || controller.$dateValue).getHours();
+ controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12);
+ controller.$setViewValue(angular.copy(controller.$dateValue));
+ controller.$render();
+ };
+
+ // Protected methods
+
+ $timepicker.$build = function() {
+ // console.warn('$timepicker.$build() viewDate=%o', viewDate);
+ var i, midIndex = scope.midIndex = parseInt(options.length / 2, 10);
+ var hours = [], hour;
+ for(i = 0; i < options.length; i++) {
+ hour = new Date(1970, 0, 1, viewDate.hour - (midIndex - i) * options.hourStep);
+ hours.push({date: hour, label: formatDate(hour, hoursFormat), selected: $timepicker.$date && $timepicker.$isSelected(hour, 0), disabled: $timepicker.$isDisabled(hour, 0)});
}
-
- if(options.autoClose) {
- bindAutoCloseEvents();
+ var minutes = [], minute;
+ for(i = 0; i < options.length; i++) {
+ minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep);
+ minutes.push({date: minute, label: formatDate(minute, minutesFormat), selected: $timepicker.$date && $timepicker.$isSelected(minute, 1), disabled: $timepicker.$isDisabled(minute, 1)});
}
+ var rows = [];
+ for(i = 0; i < options.length; i++) {
+ rows.push([hours[i], minutes[i]]);
+ }
+ scope.rows = rows;
+ scope.showAM = showAM;
+ scope.isAM = ($timepicker.$date || hours[midIndex].date).getHours() < 12;
+ scope.timeSeparator = timeSeparator;
+ $timepicker.$isBuilt = true;
};
- function enterAnimateCallback() {
- scope.$emit(options.prefixEvent + '.show', $tooltip);
- }
+ $timepicker.$isSelected = function(date, index) {
+ if(!$timepicker.$date) return false;
+ else if(index === 0) {
+ return date.getHours() === $timepicker.$date.getHours();
+ } else if(index === 1) {
+ return date.getMinutes() === $timepicker.$date.getMinutes();
+ }
+ };
- $tooltip.leave = function() {
+ $timepicker.$isDisabled = function(date, index) {
+ var selectedTime;
+ if(index === 0) {
+ selectedTime = date.getTime() + viewDate.minute * 6e4;
+ } else if(index === 1) {
+ selectedTime = date.getTime() + viewDate.hour * 36e5;
+ }
+ return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1;
+ };
- clearTimeout(timeout);
- hoverState = 'out';
- if (!options.delay || !options.delay.hide) {
- return $tooltip.hide();
+ scope.$arrowAction = function (value, index) {
+ if (options.arrowBehavior === 'picker') {
+ $timepicker.$setTimeByStep(value,index);
+ } else {
+ $timepicker.$moveIndex(value,index);
}
- timeout = setTimeout(function () {
- if (hoverState === 'out') {
- $tooltip.hide();
- }
- }, options.delay.hide);
+ };
+ $timepicker.$setTimeByStep = function(value, index) {
+ var newDate = new Date($timepicker.$date);
+ var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;
+ var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;
+ if (index === 0) {
+ newDate.setHours(hours - (parseInt(options.hourStep, 10) * value));
+ }
+ else {
+ newDate.setMinutes(minutes - (parseInt(options.minuteStep, 10) * value));
+ }
+ $timepicker.select(newDate, index, true);
};
- var _blur;
- $tooltip.hide = function(blur) {
+ $timepicker.$moveIndex = function(value, index) {
+ var targetDate;
+ if(index === 0) {
+ targetDate = new Date(1970, 0, 1, viewDate.hour + (value * options.length), viewDate.minute);
+ angular.extend(viewDate, {hour: targetDate.getHours()});
+ } else if(index === 1) {
+ targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + (value * options.length * options.minuteStep));
+ angular.extend(viewDate, {minute: targetDate.getMinutes()});
+ }
+ $timepicker.$build();
+ };
- if(!$tooltip.$isShown) return;
- scope.$emit(options.prefixEvent + '.hide.before', $tooltip);
+ $timepicker.$onMouseDown = function(evt) {
+ // Prevent blur on mousedown on .dropdown-menu
+ if(evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault();
+ evt.stopPropagation();
+ // Emulate click for mobile devices
+ if(isTouch) {
+ var targetEl = angular.element(evt.target);
+ if(targetEl[0].nodeName.toLowerCase() !== 'button') {
+ targetEl = targetEl.parent();
+ }
+ targetEl.triggerHandler('click');
+ }
+ };
- // store blur value for leaveAnimateCallback to use
- _blur = blur;
+ $timepicker.$onKeyDown = function(evt) {
+ if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;
+ evt.preventDefault();
+ evt.stopPropagation();
- // Support v1.3+ $animate
- // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9
- var promise = $animate.leave(tipElement, leaveAnimateCallback);
- if(promise && promise.then) promise.then(leaveAnimateCallback);
+ // Close on enter
+ if(evt.keyCode === 13) return $timepicker.hide(true);
- $tooltip.$isShown = scope.$isShown = false;
- safeDigest(scope);
+ // Navigate with keyboard
+ var newDate = new Date($timepicker.$date);
+ var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;
+ var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;
+ var lateralMove = /(37|39)/.test(evt.keyCode);
+ var count = 2 + showAM * 1;
- // Unbind events
- if(options.keyboard && tipElement !== null) {
- unbindKeyboardEvents();
+ // Navigate indexes (left, right)
+ if (lateralMove) {
+ if(evt.keyCode === 37) selectedIndex = selectedIndex < 1 ? count - 1 : selectedIndex - 1;
+ else if(evt.keyCode === 39) selectedIndex = selectedIndex < count - 1 ? selectedIndex + 1 : 0;
}
- if(options.autoClose && tipElement !== null) {
- unbindAutoCloseEvents();
+ // Update values (up, down)
+ var selectRange = [0, hoursLength];
+ if(selectedIndex === 0) {
+ if(evt.keyCode === 38) newDate.setHours(hours - parseInt(options.hourStep, 10));
+ else if(evt.keyCode === 40) newDate.setHours(hours + parseInt(options.hourStep, 10));
+ // re-calculate hours length because we have changed hours value
+ hoursLength = formatDate(newDate, hoursFormat).length;
+ selectRange = [0, hoursLength];
+ } else if(selectedIndex === 1) {
+ if(evt.keyCode === 38) newDate.setMinutes(minutes - parseInt(options.minuteStep, 10));
+ else if(evt.keyCode === 40) newDate.setMinutes(minutes + parseInt(options.minuteStep, 10));
+ // re-calculate minutes length because we have changes minutes value
+ minutesLength = formatDate(newDate, minutesFormat).length;
+ selectRange = [hoursLength + 1, hoursLength + 1 + minutesLength];
+ } else if(selectedIndex === 2) {
+ if(!lateralMove) $timepicker.switchMeridian();
+ selectRange = [hoursLength + 1 + minutesLength + 1, hoursLength + 1 + minutesLength + 3];
}
+ $timepicker.select(newDate, selectedIndex, true);
+ createSelection(selectRange[0], selectRange[1]);
+ parentScope.$digest();
};
- function leaveAnimateCallback() {
- scope.$emit(options.prefixEvent + '.hide', $tooltip);
- // Allow to blur the input when hidden, like when pressing enter key
- if(_blur && options.trigger === 'focus') {
- return element[0].blur();
+ // Private
+
+ function createSelection(start, end) {
+ if(element[0].createTextRange) {
+ var selRange = element[0].createTextRange();
+ selRange.collapse(true);
+ selRange.moveStart('character', start);
+ selRange.moveEnd('character', end);
+ selRange.select();
+ } else if(element[0].setSelectionRange) {
+ element[0].setSelectionRange(start, end);
+ } else if(angular.isUndefined(element[0].selectionStart)) {
+ element[0].selectionStart = start;
+ element[0].selectionEnd = end;
}
+ }
- // clean up child scopes
- destroyTipElement();
+ function focusElement() {
+ element[0].focus();
}
- $tooltip.toggle = function() {
- $tooltip.$isShown ? $tooltip.leave() : $tooltip.enter();
- };
+ // Overrides
- $tooltip.focus = function() {
- tipElement[0].focus();
+ var _init = $timepicker.init;
+ $timepicker.init = function() {
+ if(isNative && options.useNative) {
+ element.prop('type', 'time');
+ element.css('-webkit-appearance', 'textfield');
+ return;
+ } else if(isTouch) {
+ element.prop('type', 'text');
+ element.attr('readonly', 'true');
+ element.on('click', focusElement);
+ }
+ _init();
};
- $tooltip.setEnabled = function(isEnabled) {
- options.bsEnabled = isEnabled;
+ var _destroy = $timepicker.destroy;
+ $timepicker.destroy = function() {
+ if(isNative && options.useNative) {
+ element.off('click', focusElement);
+ }
+ _destroy();
};
- // Protected methods
+ var _show = $timepicker.show;
+ $timepicker.show = function() {
+ _show();
+ // use timeout to hookup the events to prevent
+ // event bubbling from being processed imediately.
+ $timeout(function() {
+ $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);
+ if(options.keyboard) {
+ element.on('keydown', $timepicker.$onKeyDown);
+ }
+ }, 0, false);
+ };
- $tooltip.$applyPlacement = function() {
- if(!tipElement) return;
+ var _hide = $timepicker.hide;
+ $timepicker.hide = function(blur) {
+ if(!$timepicker.$isShown) return;
+ $timepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);
+ if(options.keyboard) {
+ element.off('keydown', $timepicker.$onKeyDown);
+ }
+ _hide(blur);
+ };
- // Determine if we're doing an auto or normal placement
- var placement = options.placement,
- autoToken = /\s?auto?\s?/i,
- autoPlace = autoToken.test(placement);
+ return $timepicker;
- if (autoPlace) {
- placement = placement.replace(autoToken, '') || defaults.placement;
- }
+ }
- // Need to add the position class before we get
- // the offsets
- tipElement.addClass(options.placement);
+ timepickerFactory.defaults = defaults;
+ return timepickerFactory;
- // Get the position of the target element
- // and the height and width of the tooltip so we can center it.
- var elementPosition = getPosition(),
- tipWidth = tipElement.prop('offsetWidth'),
- tipHeight = tipElement.prop('offsetHeight');
+ }];
- // If we're auto placing, we need to check the positioning
- if (autoPlace) {
- var originalPlacement = placement;
- var container = options.container ? angular.element(document.querySelector(options.container)) : element.parent();
- var containerPosition = getPosition(container);
+ })
- // Determine if the vertical placement
- if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > containerPosition.bottom) {
- placement = originalPlacement.replace('bottom', 'top');
- } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < containerPosition.top) {
- placement = originalPlacement.replace('top', 'bottom');
- }
- // Determine the horizontal placement
- // The exotic placements of left and right are opposite of the standard placements. Their arrows are put on the left/right
- // and flow in the opposite direction of their placement.
- if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') &&
- elementPosition.right + tipWidth > containerPosition.width) {
+ .directive('bsTimepicker', ["$window", "$parse", "$q", "$dateFormatter", "$dateParser", "$timepicker", function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) {
- placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right');
- } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') &&
- elementPosition.left - tipWidth < containerPosition.left) {
+ var defaults = $timepicker.defaults;
+ var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);
+ var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;
- placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left');
- }
+ return {
+ restrict: 'EAC',
+ require: 'ngModel',
+ link: function postLink(scope, element, attr, controller) {
- tipElement.removeClass(originalPlacement).addClass(placement);
- }
+ // Directive options
+ var options = {scope: scope, controller: controller};
+ angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'timeType', 'timeFormat', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown'], function(key) {
+ if(angular.isDefined(attr[key])) options[key] = attr[key];
+ });
- // Get the tooltip's top and left coordinates to center it with this directive.
- var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight);
- applyPlacementCss(tipPosition.top, tipPosition.left);
- };
+ // Visibility binding support
+ attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {
+ if(!timepicker || !angular.isDefined(newValue)) return;
+ if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(timepicker),?/i);
+ newValue === true ? timepicker.show() : timepicker.hide();
+ });
- $tooltip.$onKeyUp = function(evt) {
- if (evt.which === 27 && $tooltip.$isShown) {
- $tooltip.hide();
- evt.stopPropagation();
- }
- };
+ // Initialize timepicker
+ if(isNative && (options.useNative || defaults.useNative)) options.timeFormat = 'HH:mm';
+ var timepicker = $timepicker(element, controller, options);
+ options = timepicker.$options;
- $tooltip.$onFocusKeyUp = function(evt) {
- if (evt.which === 27) {
- element[0].blur();
- evt.stopPropagation();
- }
+ var lang = options.lang;
+ var formatDate = function(date, format) {
+ return $dateFormatter.formatDate(date, format, lang);
};
- $tooltip.$onFocusElementMouseDown = function(evt) {
- evt.preventDefault();
- evt.stopPropagation();
- // Some browsers do not auto-focus buttons (eg. Safari)
- $tooltip.$isShown ? element[0].blur() : element[0].focus();
- };
+ // Initialize parser
+ var dateParser = $dateParser({format: options.timeFormat, lang: lang});
- // bind/unbind events
- function bindTriggerEvents() {
- var triggers = options.trigger.split(' ');
- angular.forEach(triggers, function(trigger) {
- if(trigger === 'click') {
- element.on('click', $tooltip.toggle);
- } else if(trigger !== 'manual') {
- element.on(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);
- element.on(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);
- nodeName === 'button' && trigger !== 'hover' && element.on(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);
- }
+ // Observe attributes for changes
+ angular.forEach(['minTime', 'maxTime'], function(key) {
+ // console.warn('attr.$observe(%s)', key, attr[key]);
+ angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {
+ timepicker.$options[key] = dateParser.getTimeForAttribute(key, newValue);
+ !isNaN(timepicker.$options[key]) && timepicker.$build();
+ validateAgainstMinMaxTime(controller.$dateValue);
});
- }
+ });
- function unbindTriggerEvents() {
- var triggers = options.trigger.split(' ');
- for (var i = triggers.length; i--;) {
- var trigger = triggers[i];
- if(trigger === 'click') {
- element.off('click', $tooltip.toggle);
- } else if(trigger !== 'manual') {
- element.off(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);
- element.off(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);
- nodeName === 'button' && trigger !== 'hover' && element.off(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);
- }
+ // Watch model for changes
+ scope.$watch(attr.ngModel, function(newValue, oldValue) {
+ // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue, controller.$dateValue);
+ timepicker.update(controller.$dateValue);
+ }, true);
+
+ function validateAgainstMinMaxTime(parsedTime) {
+ if (!angular.isDate(parsedTime)) return;
+ var isMinValid = isNaN(options.minTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) >= options.minTime;
+ var isMaxValid = isNaN(options.maxTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) <= options.maxTime;
+ var isValid = isMinValid && isMaxValid;
+ controller.$setValidity('date', isValid);
+ controller.$setValidity('min', isMinValid);
+ controller.$setValidity('max', isMaxValid);
+ // Only update the model when we have a valid date
+ if(!isValid) {
+ return;
}
+ controller.$dateValue = parsedTime;
}
- function bindKeyboardEvents() {
- if(options.trigger !== 'focus') {
- tipElement.on('keyup', $tooltip.$onKeyUp);
+ // viewValue -> $parsers -> modelValue
+ controller.$parsers.unshift(function(viewValue) {
+ // console.warn('$parser("%s"): viewValue=%o', element.attr('ng-model'), viewValue);
+ // Null values should correctly reset the model value & validity
+ if(!viewValue) {
+ // BREAKING CHANGE:
+ // return null (not undefined) when input value is empty, so angularjs 1.3
+ // ngModelController can go ahead and run validators, like ngRequired
+ controller.$setValidity('date', true);
+ return null;
+ }
+ var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue);
+ if(!parsedTime || isNaN(parsedTime.getTime())) {
+ controller.$setValidity('date', false);
+ // return undefined, causes ngModelController to
+ // invalidate model value
+ return;
} else {
- element.on('keyup', $tooltip.$onFocusKeyUp);
+ validateAgainstMinMaxTime(parsedTime);
}
- }
-
- function unbindKeyboardEvents() {
- if(options.trigger !== 'focus') {
- tipElement.off('keyup', $tooltip.$onKeyUp);
+ if(options.timeType === 'string') {
+ return formatDate(parsedTime, options.modelTimeFormat || options.timeFormat);
+ } else if(options.timeType === 'number') {
+ return controller.$dateValue.getTime();
+ } else if(options.timeType === 'unix') {
+ return controller.$dateValue.getTime() / 1000;
+ } else if(options.timeType === 'iso') {
+ return controller.$dateValue.toISOString();
} else {
- element.off('keyup', $tooltip.$onFocusKeyUp);
+ return new Date(controller.$dateValue);
}
- }
-
- var _autoCloseEventsBinded = false;
- function bindAutoCloseEvents() {
- // use timeout to hookup the events to prevent
- // event bubbling from being processed imediately.
- $timeout(function() {
- // Stop propagation when clicking inside tooltip
- tipElement.on('click', stopEventPropagation);
-
- // Hide when clicking outside tooltip
- $body.on('click', $tooltip.hide);
-
- _autoCloseEventsBinded = true;
- }, 0, false);
- }
+ });
- function unbindAutoCloseEvents() {
- if (_autoCloseEventsBinded) {
- tipElement.off('click', stopEventPropagation);
- $body.off('click', $tooltip.hide);
- _autoCloseEventsBinded = false;
+ // modelValue -> $formatters -> viewValue
+ controller.$formatters.push(function(modelValue) {
+ // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);
+ var date;
+ if(angular.isUndefined(modelValue) || modelValue === null) {
+ date = NaN;
+ } else if(angular.isDate(modelValue)) {
+ date = modelValue;
+ } else if(options.timeType === 'string') {
+ date = dateParser.parse(modelValue, null, options.modelTimeFormat);
+ } else if(options.timeType === 'unix') {
+ date = new Date(modelValue * 1000);
+ } else {
+ date = new Date(modelValue);
}
- }
-
- function stopEventPropagation(event) {
- event.stopPropagation();
- }
+ // Setup default value?
+ // if(isNaN(date.getTime())) date = new Date(new Date().setMinutes(0) + 36e5);
+ controller.$dateValue = date;
+ return getTimeFormattedString();
+ });
- // Private methods
+ // viewValue -> element
+ controller.$render = function() {
+ // console.warn('$render("%s"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);
+ element.val(getTimeFormattedString());
+ };
- function getPosition($element) {
- $element = $element || (options.target || element);
+ function getTimeFormattedString() {
+ return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat);
+ }
- var el = $element[0];
+ // Garbage collection
+ scope.$on('$destroy', function() {
+ if (timepicker) timepicker.destroy();
+ options = null;
+ timepicker = null;
+ });
- var elRect = el.getBoundingClientRect();
- if (elRect.width === null) {
- // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
- elRect = angular.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top });
- }
+ }
+ };
- var elPos;
- if (options.container === 'body') {
- elPos = dimensions.offset(el);
- } else {
- elPos = dimensions.position(el);
- }
+ }]);
- return angular.extend({}, elRect, elPos);
- }
+// Source: tooltip.js
+angular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions'])
- function getCalculatedOffset(placement, position, actualWidth, actualHeight) {
- var offset;
- var split = placement.split('-');
+ .provider('$tooltip', function() {
- switch (split[0]) {
- case 'right':
- offset = {
- top: position.top + position.height / 2 - actualHeight / 2,
- left: position.left + position.width
- };
- break;
- case 'bottom':
- offset = {
- top: position.top + position.height,
- left: position.left + position.width / 2 - actualWidth / 2
- };
- break;
- case 'left':
- offset = {
- top: position.top + position.height / 2 - actualHeight / 2,
- left: position.left - actualWidth
- };
- break;
- default:
- offset = {
- top: position.top - actualHeight,
- left: position.left + position.width / 2 - actualWidth / 2
- };
- break;
- }
+ var defaults = this.defaults = {
+ animation: 'am-fade',
+ customClass: '',
+ prefixClass: 'tooltip',
+ prefixEvent: 'tooltip',
+ container: false,
+ target: false,
+ placement: 'top',
+ template: 'tooltip/tooltip.tpl.html',
+ contentTemplate: false,
+ trigger: 'hover focus',
+ keyboard: false,
+ html: false,
+ show: false,
+ title: '',
+ type: '',
+ delay: 0,
+ autoClose: false,
+ bsEnabled: true
+ };
- if(!split[1]) {
- return offset;
- }
+ this.$get = ["$window", "$rootScope", "$compile", "$q", "$templateCache", "$http", "$animate", "$sce", "dimensions", "$$rAF", "$timeout", function($window, $rootScope, $compile, $q, $templateCache, $http, $animate, $sce, dimensions, $$rAF, $timeout) {
- // Add support for corners @todo css
- if(split[0] === 'top' || split[0] === 'bottom') {
- switch (split[1]) {
- case 'left':
- offset.left = position.left;
- break;
- case 'right':
- offset.left = position.left + position.width - actualWidth;
- }
- } else if(split[0] === 'left' || split[0] === 'right') {
- switch (split[1]) {
- case 'top':
- offset.top = position.top - actualHeight;
- break;
- case 'bottom':
- offset.top = position.top + position.height;
- }
- }
+ var trim = String.prototype.trim;
+ var isTouch = 'createTouch' in $window.document;
+ var htmlReplaceRegExp = /ng-bind="/ig;
+ var $body = angular.element($window.document);
- return offset;
+ function TooltipFactory(element, config) {
+
+ var $tooltip = {};
+
+ // Common vars
+ var nodeName = element[0].nodeName.toLowerCase();
+ var options = $tooltip.$options = angular.extend({}, defaults, config);
+ $tooltip.$promise = fetchTemplate(options.template);
+ var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new();
+ if(options.delay && angular.isString(options.delay)) {
+ var split = options.delay.split(',').map(parseFloat);
+ options.delay = split.length > 1 ? {show: split[0], hide: split[1]} : split[0];
}
- function applyPlacementCss(top, left) {
- tipElement.css({ top: top + 'px', left: left + 'px' });
+ // Support scope as string options
+ if(options.title) {
+ scope.title = $sce.trustAsHtml(options.title);
}
- function destroyTipElement() {
- // Cancel pending callbacks
- clearTimeout(timeout);
+ // Provide scope helpers
+ scope.$setEnabled = function(isEnabled) {
+ scope.$$postDigest(function() {
+ $tooltip.setEnabled(isEnabled);
+ });
+ };
+ scope.$hide = function() {
+ scope.$$postDigest(function() {
+ $tooltip.hide();
+ });
+ };
+ scope.$show = function() {
+ scope.$$postDigest(function() {
+ $tooltip.show();
+ });
+ };
+ scope.$toggle = function() {
+ scope.$$postDigest(function() {
+ $tooltip.toggle();
+ });
+ };
+ // Publish isShown as a protected var on scope
+ $tooltip.$isShown = scope.$isShown = false;
- if($tooltip.$isShown && tipElement !== null) {
- if(options.autoClose) {
- unbindAutoCloseEvents();
- }
+ // Private vars
+ var timeout, hoverState;
- if(options.keyboard) {
- unbindKeyboardEvents();
- }
- }
+ // Support contentTemplate option
+ if(options.contentTemplate) {
+ $tooltip.$promise = $tooltip.$promise.then(function(template) {
+ var templateEl = angular.element(template);
+ return fetchTemplate(options.contentTemplate)
+ .then(function(contentTemplate) {
+ var contentEl = findElement('[ng-bind="content"]', templateEl[0]);
+ if(!contentEl.length) contentEl = findElement('[ng-bind="title"]', templateEl[0]);
+ contentEl.removeAttr('ng-bind').html(contentTemplate);
+ return templateEl[0].outerHTML;
+ });
+ });
+ }
- if(tipScope) {
- tipScope.$destroy();
- tipScope = null;
- }
+ // Fetch, compile then initialize tooltip
+ var tipLinker, tipElement, tipTemplate, tipContainer, tipScope;
+ $tooltip.$promise.then(function(template) {
+ if(angular.isObject(template)) template = template.data;
+ if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html="');
+ template = trim.apply(template);
+ tipTemplate = template;
+ tipLinker = $compile(template);
+ $tooltip.init();
+ });
- if(tipElement) {
- tipElement.remove();
- tipElement = $tooltip.$element = null;
- }
- }
+ $tooltip.init = function() {
- return $tooltip;
+ // Options: delay
+ if (options.delay && angular.isNumber(options.delay)) {
+ options.delay = {
+ show: options.delay,
+ hide: options.delay
+ };
+ }
- }
+ // Replace trigger on touch devices ?
+ // if(isTouch && options.trigger === defaults.trigger) {
+ // options.trigger.replace(/hover/g, 'click');
+ // }
- // Helper functions
+ // Options : container
+ if(options.container === 'self') {
+ tipContainer = element;
+ } else if(angular.isElement(options.container)) {
+ tipContainer = options.container;
+ } else if(options.container) {
+ tipContainer = findElement(options.container);
+ }
- function safeDigest(scope) {
- scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();
- }
+ // Options: trigger
+ bindTriggerEvents();
- function findElement(query, element) {
- return angular.element((element || document).querySelectorAll(query));
- }
+ // Options: target
+ if(options.target) {
+ options.target = angular.isElement(options.target) ? options.target : findElement(options.target);
+ }
- var fetchPromises = {};
- function fetchTemplate(template) {
- if(fetchPromises[template]) return fetchPromises[template];
- return (fetchPromises[template] = $q.when($templateCache.get(template) || $http.get(template))
- .then(function(res) {
- if(angular.isObject(res)) {
- $templateCache.put(template, res.data);
- return res.data;
+ // Options: show
+ if(options.show) {
+ scope.$$postDigest(function() {
+ options.trigger === 'focus' ? element[0].focus() : $tooltip.show();
+ });
}
- return res;
- }));
- }
- return TooltipFactory;
+ };
- }];
+ $tooltip.destroy = function() {
- })
+ // Unbind events
+ unbindTriggerEvents();
- .directive('bsTooltip', ["$window", "$location", "$sce", "$tooltip", "$$rAF", function($window, $location, $sce, $tooltip, $$rAF) {
+ // Remove element
+ destroyTipElement();
- return {
- restrict: 'EAC',
- scope: true,
- link: function postLink(scope, element, attr, transclusion) {
+ // Destroy scope
+ scope.$destroy();
- // Directive options
- var options = {scope: scope};
- angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'backdropAnimation', 'type', 'customClass'], function(key) {
- if(angular.isDefined(attr[key])) options[key] = attr[key];
- });
+ };
- // overwrite inherited title value when no value specified
- // fix for angular 1.3.1 531a8de72c439d8ddd064874bf364c00cedabb11
- if (!scope.hasOwnProperty('title')){
- scope.title = '';
- }
+ $tooltip.enter = function() {
- // Observe scope attributes for change
- attr.$observe('title', function(newValue) {
- if (angular.isDefined(newValue) || !scope.hasOwnProperty('title')) {
- var oldValue = scope.title;
- scope.title = $sce.trustAsHtml(newValue);
- angular.isDefined(oldValue) && $$rAF(function() {
- tooltip && tooltip.$applyPlacement();
- });
+ clearTimeout(timeout);
+ hoverState = 'in';
+ if (!options.delay || !options.delay.show) {
+ return $tooltip.show();
}
- });
- // Support scope as an object
- attr.bsTooltip && scope.$watch(attr.bsTooltip, function(newValue, oldValue) {
- if(angular.isObject(newValue)) {
- angular.extend(scope, newValue);
- } else {
- scope.title = newValue;
- }
- angular.isDefined(oldValue) && $$rAF(function() {
- tooltip && tooltip.$applyPlacement();
- });
- }, true);
+ timeout = setTimeout(function() {
+ if (hoverState ==='in') $tooltip.show();
+ }, options.delay.show);
- // Visibility binding support
- attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {
- if(!tooltip || !angular.isDefined(newValue)) return;
- if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(tooltip),?/i);
- newValue === true ? tooltip.show() : tooltip.hide();
- });
+ };
+
+ $tooltip.show = function() {
+ if (!options.bsEnabled || $tooltip.$isShown) return;
+
+ scope.$emit(options.prefixEvent + '.show.before', $tooltip);
+ var parent, after;
+ if (options.container) {
+ parent = tipContainer;
+ if (tipContainer[0].lastChild) {
+ after = angular.element(tipContainer[0].lastChild);
+ } else {
+ after = null;
+ }
+ } else {
+ parent = null;
+ after = element;
+ }
- // Enabled binding support
- attr.bsEnabled && scope.$watch(attr.bsEnabled, function(newValue, oldValue) {
- // console.warn('scope.$watch(%s)', attr.bsEnabled, newValue, oldValue);
- if(!tooltip || !angular.isDefined(newValue)) return;
- if(angular.isString(newValue)) newValue = !!newValue.match(/true|1|,?(tooltip),?/i);
- newValue === false ? tooltip.setEnabled(false) : tooltip.setEnabled(true);
- });
- // Initialize popover
- var tooltip = $tooltip(element, options);
+ // Hide any existing tipElement
+ if(tipElement) destroyTipElement();
+ // Fetch a cloned element linked from template
+ tipScope = $tooltip.$scope.$new();
+ tipElement = $tooltip.$element = tipLinker(tipScope, function(clonedElement, scope) {});
- // Garbage collection
- scope.$on('$destroy', function() {
- if(tooltip) tooltip.destroy();
- options = null;
- tooltip = null;
- });
+ // Set the initial positioning. Make the tooltip invisible
+ // so IE doesn't try to focus on it off screen.
+ tipElement.css({top: '-9999px', left: '-9999px', display: 'block', visibility: 'hidden'});
- }
- };
+ // Options: animation
+ if(options.animation) tipElement.addClass(options.animation);
+ // Options: type
+ if(options.type) tipElement.addClass(options.prefixClass + '-' + options.type);
+ // Options: custom classes
+ if(options.customClass) tipElement.addClass(options.customClass);
- }]);
+ // Support v1.3+ $animate
+ // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9
+ var promise = $animate.enter(tipElement, parent, after, enterAnimateCallback);
+ if(promise && promise.then) promise.then(enterAnimateCallback);
-// Source: timepicker.js
-angular.module('mgcrea.ngStrap.timepicker', [
- 'mgcrea.ngStrap.helpers.dateParser',
- 'mgcrea.ngStrap.helpers.dateFormatter',
- 'mgcrea.ngStrap.tooltip'])
+ $tooltip.$isShown = scope.$isShown = true;
+ safeDigest(scope);
+ $$rAF(function () {
+ $tooltip.$applyPlacement();
- .provider('$timepicker', function() {
+ // Once placed, make the tooltip visible
+ if(tipElement) tipElement.css({visibility: 'visible'});
+ }); // var a = bodyEl.offsetWidth + 1; ?
- var defaults = this.defaults = {
- animation: 'am-fade',
- prefixClass: 'timepicker',
- placement: 'bottom-left',
- template: 'timepicker/timepicker.tpl.html',
- trigger: 'focus',
- container: false,
- keyboard: true,
- html: false,
- delay: 0,
- // lang: $locale.id,
- useNative: true,
- timeType: 'date',
- timeFormat: 'shortTime',
- modelTimeFormat: null,
- autoclose: false,
- minTime: -Infinity,
- maxTime: +Infinity,
- length: 5,
- hourStep: 1,
- minuteStep: 5,
- iconUp: 'glyphicon glyphicon-chevron-up',
- iconDown: 'glyphicon glyphicon-chevron-down',
- arrowBehavior: 'pager'
- };
+ // Bind events
+ if(options.keyboard) {
+ if(options.trigger !== 'focus') {
+ $tooltip.focus();
+ }
+ bindKeyboardEvents();
+ }
- this.$get = ["$window", "$document", "$rootScope", "$sce", "$dateFormatter", "$tooltip", "$timeout", function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) {
+ if(options.autoClose) {
+ bindAutoCloseEvents();
+ }
- var bodyEl = angular.element($window.document.body);
- var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);
- var isTouch = ('createTouch' in $window.document) && isNative;
- if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();
+ };
- function timepickerFactory(element, controller, config) {
+ function enterAnimateCallback() {
+ scope.$emit(options.prefixEvent + '.show', $tooltip);
+ }
- var $timepicker = $tooltip(element, angular.extend({}, defaults, config));
- var parentScope = config.scope;
- var options = $timepicker.$options;
- var scope = $timepicker.$scope;
+ $tooltip.leave = function() {
+
+ clearTimeout(timeout);
+ hoverState = 'out';
+ if (!options.delay || !options.delay.hide) {
+ return $tooltip.hide();
+ }
+ timeout = setTimeout(function () {
+ if (hoverState === 'out') {
+ $tooltip.hide();
+ }
+ }, options.delay.hide);
- var lang = options.lang;
- var formatDate = function(date, format) {
- return $dateFormatter.formatDate(date, format, lang);
};
- // View vars
+ var _blur;
+ $tooltip.hide = function(blur) {
- var selectedIndex = 0;
- var startDate = controller.$dateValue || new Date();
- var viewDate = {hour: startDate.getHours(), meridian: startDate.getHours() < 12, minute: startDate.getMinutes(), second: startDate.getSeconds(), millisecond: startDate.getMilliseconds()};
+ if(!$tooltip.$isShown) return;
+ scope.$emit(options.prefixEvent + '.hide.before', $tooltip);
- var format = $dateFormatter.getDatetimeFormat(options.timeFormat, lang);
+ // store blur value for leaveAnimateCallback to use
+ _blur = blur;
- var hoursFormat = $dateFormatter.hoursFormat(format),
- timeSeparator = $dateFormatter.timeSeparator(format),
- minutesFormat = $dateFormatter.minutesFormat(format),
- showAM = $dateFormatter.showAM(format);
+ // Support v1.3+ $animate
+ // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9
+ var promise = $animate.leave(tipElement, leaveAnimateCallback);
+ if(promise && promise.then) promise.then(leaveAnimateCallback);
- scope.$iconUp = options.iconUp;
- scope.$iconDown = options.iconDown;
+ $tooltip.$isShown = scope.$isShown = false;
+ safeDigest(scope);
- // Scope methods
+ // Unbind events
+ if(options.keyboard && tipElement !== null) {
+ unbindKeyboardEvents();
+ }
- scope.$select = function(date, index) {
- $timepicker.select(date, index);
- };
- scope.$moveIndex = function(value, index) {
- $timepicker.$moveIndex(value, index);
- };
- scope.$switchMeridian = function(date) {
- $timepicker.switchMeridian(date);
+ if(options.autoClose && tipElement !== null) {
+ unbindAutoCloseEvents();
+ }
};
- // Public methods
-
- $timepicker.update = function(date) {
- // console.warn('$timepicker.update() newValue=%o', date);
- if(angular.isDate(date) && !isNaN(date.getTime())) {
- $timepicker.$date = date;
- angular.extend(viewDate, {hour: date.getHours(), minute: date.getMinutes(), second: date.getSeconds(), millisecond: date.getMilliseconds()});
- $timepicker.$build();
- } else if(!$timepicker.$isBuilt) {
- $timepicker.$build();
+ function leaveAnimateCallback() {
+ scope.$emit(options.prefixEvent + '.hide', $tooltip);
+ // Allow to blur the input when hidden, like when pressing enter key
+ if(_blur && options.trigger === 'focus') {
+ return element[0].blur();
}
+
+ // clean up child scopes
+ destroyTipElement();
+ }
+
+ $tooltip.toggle = function() {
+ $tooltip.$isShown ? $tooltip.leave() : $tooltip.enter();
};
- $timepicker.select = function(date, index, keep) {
- // console.warn('$timepicker.select', date, scope.$mode);
- if(!controller.$dateValue || isNaN(controller.$dateValue.getTime())) controller.$dateValue = new Date(1970, 0, 1);
- if(!angular.isDate(date)) date = new Date(date);
- if(index === 0) controller.$dateValue.setHours(date.getHours());
- else if(index === 1) controller.$dateValue.setMinutes(date.getMinutes());
- controller.$setViewValue(angular.copy(controller.$dateValue));
- controller.$render();
- if(options.autoclose && !keep) {
- $timeout(function() { $timepicker.hide(true); });
- }
+ $tooltip.focus = function() {
+ tipElement[0].focus();
};
- $timepicker.switchMeridian = function(date) {
- if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) {
- return;
- }
- var hours = (date || controller.$dateValue).getHours();
- controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12);
- controller.$setViewValue(angular.copy(controller.$dateValue));
- controller.$render();
+ $tooltip.setEnabled = function(isEnabled) {
+ options.bsEnabled = isEnabled;
};
// Protected methods
- $timepicker.$build = function() {
- // console.warn('$timepicker.$build() viewDate=%o', viewDate);
- var i, midIndex = scope.midIndex = parseInt(options.length / 2, 10);
- var hours = [], hour;
- for(i = 0; i < options.length; i++) {
- hour = new Date(1970, 0, 1, viewDate.hour - (midIndex - i) * options.hourStep);
- hours.push({date: hour, label: formatDate(hour, hoursFormat), selected: $timepicker.$date && $timepicker.$isSelected(hour, 0), disabled: $timepicker.$isDisabled(hour, 0)});
- }
- var minutes = [], minute;
- for(i = 0; i < options.length; i++) {
- minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep);
- minutes.push({date: minute, label: formatDate(minute, minutesFormat), selected: $timepicker.$date && $timepicker.$isSelected(minute, 1), disabled: $timepicker.$isDisabled(minute, 1)});
+ $tooltip.$applyPlacement = function() {
+ if(!tipElement) return;
+
+ // Determine if we're doing an auto or normal placement
+ var placement = options.placement,
+ autoToken = /\s?auto?\s?/i,
+ autoPlace = autoToken.test(placement);
+
+ if (autoPlace) {
+ placement = placement.replace(autoToken, '') || defaults.placement;
}
- var rows = [];
- for(i = 0; i < options.length; i++) {
- rows.push([hours[i], minutes[i]]);
+ // Need to add the position class before we get
+ // the offsets
+ tipElement.addClass(options.placement);
+
+ // Get the position of the target element
+ // and the height and width of the tooltip so we can center it.
+ var elementPosition = getPosition(),
+ tipWidth = tipElement.prop('offsetWidth'),
+ tipHeight = tipElement.prop('offsetHeight');
+
+ // If we're auto placing, we need to check the positioning
+ if (autoPlace) {
+ var originalPlacement = placement;
+ var container = options.container ? angular.element(document.querySelector(options.container)) : element.parent();
+ var containerPosition = getPosition(container);
+
+ // Determine if the vertical placement
+ if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > containerPosition.bottom) {
+ placement = originalPlacement.replace('bottom', 'top');
+ } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < containerPosition.top) {
+ placement = originalPlacement.replace('top', 'bottom');
+ }
+
+ // Determine the horizontal placement
+ // The exotic placements of left and right are opposite of the standard placements. Their arrows are put on the left/right
+ // and flow in the opposite direction of their placement.
+ if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') &&
+ elementPosition.right + tipWidth > containerPosition.width) {
+
+ placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right');
+ } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') &&
+ elementPosition.left - tipWidth < containerPosition.left) {
+
+ placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left');
+ }
+
+ tipElement.removeClass(originalPlacement).addClass(placement);
}
- scope.rows = rows;
- scope.showAM = showAM;
- scope.isAM = ($timepicker.$date || hours[midIndex].date).getHours() < 12;
- scope.timeSeparator = timeSeparator;
- $timepicker.$isBuilt = true;
+
+ // Get the tooltip's top and left coordinates to center it with this directive.
+ var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight);
+ applyPlacementCss(tipPosition.top, tipPosition.left);
};
- $timepicker.$isSelected = function(date, index) {
- if(!$timepicker.$date) return false;
- else if(index === 0) {
- return date.getHours() === $timepicker.$date.getHours();
- } else if(index === 1) {
- return date.getMinutes() === $timepicker.$date.getMinutes();
+ $tooltip.$onKeyUp = function(evt) {
+ if (evt.which === 27 && $tooltip.$isShown) {
+ $tooltip.hide();
+ evt.stopPropagation();
}
};
- $timepicker.$isDisabled = function(date, index) {
- var selectedTime;
- if(index === 0) {
- selectedTime = date.getTime() + viewDate.minute * 6e4;
- } else if(index === 1) {
- selectedTime = date.getTime() + viewDate.hour * 36e5;
+ $tooltip.$onFocusKeyUp = function(evt) {
+ if (evt.which === 27) {
+ element[0].blur();
+ evt.stopPropagation();
}
- return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1;
};
- scope.$arrowAction = function (value, index) {
- if (options.arrowBehavior === 'picker') {
- $timepicker.$setTimeByStep(value,index);
- } else {
- $timepicker.$moveIndex(value,index);
- }
+ $tooltip.$onFocusElementMouseDown = function(evt) {
+ evt.preventDefault();
+ evt.stopPropagation();
+ // Some browsers do not auto-focus buttons (eg. Safari)
+ $tooltip.$isShown ? element[0].blur() : element[0].focus();
};
- $timepicker.$setTimeByStep = function(value, index) {
- var newDate = new Date($timepicker.$date);
- var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;
- var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;
- if (index === 0) {
- newDate.setHours(hours - (parseInt(options.hourStep, 10) * value));
+ // bind/unbind events
+ function bindTriggerEvents() {
+ var triggers = options.trigger.split(' ');
+ angular.forEach(triggers, function(trigger) {
+ if(trigger === 'click') {
+ element.on('click', $tooltip.toggle);
+ } else if(trigger !== 'manual') {
+ element.on(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);
+ element.on(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);
+ nodeName === 'button' && trigger !== 'hover' && element.on(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);
+ }
+ });
+ }
+
+ function unbindTriggerEvents() {
+ var triggers = options.trigger.split(' ');
+ for (var i = triggers.length; i--;) {
+ var trigger = triggers[i];
+ if(trigger === 'click') {
+ element.off('click', $tooltip.toggle);
+ } else if(trigger !== 'manual') {
+ element.off(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);
+ element.off(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);
+ nodeName === 'button' && trigger !== 'hover' && element.off(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);
+ }
}
- else {
- newDate.setMinutes(minutes - (parseInt(options.minuteStep, 10) * value));
+ }
+
+ function bindKeyboardEvents() {
+ if(options.trigger !== 'focus') {
+ tipElement.on('keyup', $tooltip.$onKeyUp);
+ } else {
+ element.on('keyup', $tooltip.$onFocusKeyUp);
}
- $timepicker.select(newDate, index, true);
- };
+ }
- $timepicker.$moveIndex = function(value, index) {
- var targetDate;
- if(index === 0) {
- targetDate = new Date(1970, 0, 1, viewDate.hour + (value * options.length), viewDate.minute);
- angular.extend(viewDate, {hour: targetDate.getHours()});
- } else if(index === 1) {
- targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + (value * options.length * options.minuteStep));
- angular.extend(viewDate, {minute: targetDate.getMinutes()});
+ function unbindKeyboardEvents() {
+ if(options.trigger !== 'focus') {
+ tipElement.off('keyup', $tooltip.$onKeyUp);
+ } else {
+ element.off('keyup', $tooltip.$onFocusKeyUp);
}
- $timepicker.$build();
- };
+ }
- $timepicker.$onMouseDown = function(evt) {
- // Prevent blur on mousedown on .dropdown-menu
- if(evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault();
- evt.stopPropagation();
- // Emulate click for mobile devices
- if(isTouch) {
- var targetEl = angular.element(evt.target);
- if(targetEl[0].nodeName.toLowerCase() !== 'button') {
- targetEl = targetEl.parent();
- }
- targetEl.triggerHandler('click');
+ var _autoCloseEventsBinded = false;
+ function bindAutoCloseEvents() {
+ // use timeout to hookup the events to prevent
+ // event bubbling from being processed imediately.
+ $timeout(function() {
+ // Stop propagation when clicking inside tooltip
+ tipElement.on('click', stopEventPropagation);
+
+ // Hide when clicking outside tooltip
+ $body.on('click', $tooltip.hide);
+
+ _autoCloseEventsBinded = true;
+ }, 0, false);
+ }
+
+ function unbindAutoCloseEvents() {
+ if (_autoCloseEventsBinded) {
+ tipElement.off('click', stopEventPropagation);
+ $body.off('click', $tooltip.hide);
+ _autoCloseEventsBinded = false;
}
- };
+ }
- $timepicker.$onKeyDown = function(evt) {
- if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;
- evt.preventDefault();
- evt.stopPropagation();
+ function stopEventPropagation(event) {
+ event.stopPropagation();
+ }
- // Close on enter
- if(evt.keyCode === 13) return $timepicker.hide(true);
+ // Private methods
- // Navigate with keyboard
- var newDate = new Date($timepicker.$date);
- var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;
- var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;
- var lateralMove = /(37|39)/.test(evt.keyCode);
- var count = 2 + showAM * 1;
+ function getPosition($element) {
+ $element = $element || (options.target || element);
- // Navigate indexes (left, right)
- if (lateralMove) {
- if(evt.keyCode === 37) selectedIndex = selectedIndex < 1 ? count - 1 : selectedIndex - 1;
- else if(evt.keyCode === 39) selectedIndex = selectedIndex < count - 1 ? selectedIndex + 1 : 0;
+ var el = $element[0];
+
+ var elRect = el.getBoundingClientRect();
+ if (elRect.width === null) {
+ // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
+ elRect = angular.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top });
}
- // Update values (up, down)
- var selectRange = [0, hoursLength];
- if(selectedIndex === 0) {
- if(evt.keyCode === 38) newDate.setHours(hours - parseInt(options.hourStep, 10));
- else if(evt.keyCode === 40) newDate.setHours(hours + parseInt(options.hourStep, 10));
- // re-calculate hours length because we have changed hours value
- hoursLength = formatDate(newDate, hoursFormat).length;
- selectRange = [0, hoursLength];
- } else if(selectedIndex === 1) {
- if(evt.keyCode === 38) newDate.setMinutes(minutes - parseInt(options.minuteStep, 10));
- else if(evt.keyCode === 40) newDate.setMinutes(minutes + parseInt(options.minuteStep, 10));
- // re-calculate minutes length because we have changes minutes value
- minutesLength = formatDate(newDate, minutesFormat).length;
- selectRange = [hoursLength + 1, hoursLength + 1 + minutesLength];
- } else if(selectedIndex === 2) {
- if(!lateralMove) $timepicker.switchMeridian();
- selectRange = [hoursLength + 1 + minutesLength + 1, hoursLength + 1 + minutesLength + 3];
+ var elPos;
+ if (options.container === 'body') {
+ elPos = dimensions.offset(el);
+ } else {
+ elPos = dimensions.position(el);
}
- $timepicker.select(newDate, selectedIndex, true);
- createSelection(selectRange[0], selectRange[1]);
- parentScope.$digest();
- };
- // Private
+ return angular.extend({}, elRect, elPos);
+ }
- function createSelection(start, end) {
- if(element[0].createTextRange) {
- var selRange = element[0].createTextRange();
- selRange.collapse(true);
- selRange.moveStart('character', start);
- selRange.moveEnd('character', end);
- selRange.select();
- } else if(element[0].setSelectionRange) {
- element[0].setSelectionRange(start, end);
- } else if(angular.isUndefined(element[0].selectionStart)) {
- element[0].selectionStart = start;
- element[0].selectionEnd = end;
+ function getCalculatedOffset(placement, position, actualWidth, actualHeight) {
+ var offset;
+ var split = placement.split('-');
+
+ switch (split[0]) {
+ case 'right':
+ offset = {
+ top: position.top + position.height / 2 - actualHeight / 2,
+ left: position.left + position.width
+ };
+ break;
+ case 'bottom':
+ offset = {
+ top: position.top + position.height,
+ left: position.left + position.width / 2 - actualWidth / 2
+ };
+ break;
+ case 'left':
+ offset = {
+ top: position.top + position.height / 2 - actualHeight / 2,
+ left: position.left - actualWidth
+ };
+ break;
+ default:
+ offset = {
+ top: position.top - actualHeight,
+ left: position.left + position.width / 2 - actualWidth / 2
+ };
+ break;
+ }
+
+ if(!split[1]) {
+ return offset;
+ }
+
+ // Add support for corners @todo css
+ if(split[0] === 'top' || split[0] === 'bottom') {
+ switch (split[1]) {
+ case 'left':
+ offset.left = position.left;
+ break;
+ case 'right':
+ offset.left = position.left + position.width - actualWidth;
+ }
+ } else if(split[0] === 'left' || split[0] === 'right') {
+ switch (split[1]) {
+ case 'top':
+ offset.top = position.top - actualHeight;
+ break;
+ case 'bottom':
+ offset.top = position.top + position.height;
+ }
}
- }
- function focusElement() {
- element[0].focus();
+ return offset;
}
- // Overrides
+ function applyPlacementCss(top, left) {
+ tipElement.css({ top: top + 'px', left: left + 'px' });
+ }
- var _init = $timepicker.init;
- $timepicker.init = function() {
- if(isNative && options.useNative) {
- element.prop('type', 'time');
- element.css('-webkit-appearance', 'textfield');
- return;
- } else if(isTouch) {
- element.prop('type', 'text');
- element.attr('readonly', 'true');
- element.on('click', focusElement);
- }
- _init();
- };
+ function destroyTipElement() {
+ // Cancel pending callbacks
+ clearTimeout(timeout);
- var _destroy = $timepicker.destroy;
- $timepicker.destroy = function() {
- if(isNative && options.useNative) {
- element.off('click', focusElement);
- }
- _destroy();
- };
+ if($tooltip.$isShown && tipElement !== null) {
+ if(options.autoClose) {
+ unbindAutoCloseEvents();
+ }
- var _show = $timepicker.show;
- $timepicker.show = function() {
- _show();
- // use timeout to hookup the events to prevent
- // event bubbling from being processed imediately.
- $timeout(function() {
- $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);
if(options.keyboard) {
- element.on('keydown', $timepicker.$onKeyDown);
+ unbindKeyboardEvents();
}
- }, 0, false);
- };
+ }
- var _hide = $timepicker.hide;
- $timepicker.hide = function(blur) {
- if(!$timepicker.$isShown) return;
- $timepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);
- if(options.keyboard) {
- element.off('keydown', $timepicker.$onKeyDown);
+ if(tipScope) {
+ tipScope.$destroy();
+ tipScope = null;
}
- _hide(blur);
- };
- return $timepicker;
+ if(tipElement) {
+ tipElement.remove();
+ tipElement = $tooltip.$element = null;
+ }
+ }
+
+ return $tooltip;
}
- timepickerFactory.defaults = defaults;
- return timepickerFactory;
+ // Helper functions
- }];
+ function safeDigest(scope) {
+ scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();
+ }
- })
+ function findElement(query, element) {
+ return angular.element((element || document).querySelectorAll(query));
+ }
+ var fetchPromises = {};
+ function fetchTemplate(template) {
+ if(fetchPromises[template]) return fetchPromises[template];
+ return (fetchPromises[template] = $q.when($templateCache.get(template) || $http.get(template))
+ .then(function(res) {
+ if(angular.isObject(res)) {
+ $templateCache.put(template, res.data);
+ return res.data;
+ }
+ return res;
+ }));
+ }
- .directive('bsTimepicker', ["$window", "$parse", "$q", "$dateFormatter", "$dateParser", "$timepicker", function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) {
+ return TooltipFactory;
- var defaults = $timepicker.defaults;
- var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);
- var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;
+ }];
+
+ })
+
+ .directive('bsTooltip', ["$window", "$location", "$sce", "$tooltip", "$$rAF", function($window, $location, $sce, $tooltip, $$rAF) {
return {
restrict: 'EAC',
- require: 'ngModel',
- link: function postLink(scope, element, attr, controller) {
+ scope: true,
+ link: function postLink(scope, element, attr, transclusion) {
// Directive options
- var options = {scope: scope, controller: controller};
- angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'timeType', 'timeFormat', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown'], function(key) {
+ var options = {scope: scope};
+ angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'backdropAnimation', 'type', 'customClass'], function(key) {
if(angular.isDefined(attr[key])) options[key] = attr[key];
});
- // Visibility binding support
- attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {
- if(!timepicker || !angular.isDefined(newValue)) return;
- if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(timepicker),?/i);
- newValue === true ? timepicker.show() : timepicker.hide();
- });
-
- // Initialize timepicker
- if(isNative && (options.useNative || defaults.useNative)) options.timeFormat = 'HH:mm';
- var timepicker = $timepicker(element, controller, options);
- options = timepicker.$options;
-
- var lang = options.lang;
- var formatDate = function(date, format) {
- return $dateFormatter.formatDate(date, format, lang);
- };
-
- // Initialize parser
- var dateParser = $dateParser({format: options.timeFormat, lang: lang});
-
- // Observe attributes for changes
- angular.forEach(['minTime', 'maxTime'], function(key) {
- // console.warn('attr.$observe(%s)', key, attr[key]);
- angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {
- timepicker.$options[key] = dateParser.getTimeForAttribute(key, newValue);
- !isNaN(timepicker.$options[key]) && timepicker.$build();
- validateAgainstMinMaxTime(controller.$dateValue);
- });
- });
-
- // Watch model for changes
- scope.$watch(attr.ngModel, function(newValue, oldValue) {
- // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue, controller.$dateValue);
- timepicker.update(controller.$dateValue);
- }, true);
-
- function validateAgainstMinMaxTime(parsedTime) {
- if (!angular.isDate(parsedTime)) return;
- var isMinValid = isNaN(options.minTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) >= options.minTime;
- var isMaxValid = isNaN(options.maxTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) <= options.maxTime;
- var isValid = isMinValid && isMaxValid;
- controller.$setValidity('date', isValid);
- controller.$setValidity('min', isMinValid);
- controller.$setValidity('max', isMaxValid);
- // Only update the model when we have a valid date
- if(!isValid) {
- return;
- }
- controller.$dateValue = parsedTime;
+ // overwrite inherited title value when no value specified
+ // fix for angular 1.3.1 531a8de72c439d8ddd064874bf364c00cedabb11
+ if (!scope.hasOwnProperty('title')){
+ scope.title = '';
}
- // viewValue -> $parsers -> modelValue
- controller.$parsers.unshift(function(viewValue) {
- // console.warn('$parser("%s"): viewValue=%o', element.attr('ng-model'), viewValue);
- // Null values should correctly reset the model value & validity
- if(!viewValue) {
- // BREAKING CHANGE:
- // return null (not undefined) when input value is empty, so angularjs 1.3
- // ngModelController can go ahead and run validators, like ngRequired
- controller.$setValidity('date', true);
- return null;
- }
- var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue);
- if(!parsedTime || isNaN(parsedTime.getTime())) {
- controller.$setValidity('date', false);
- // return undefined, causes ngModelController to
- // invalidate model value
- return;
- } else {
- validateAgainstMinMaxTime(parsedTime);
- }
- if(options.timeType === 'string') {
- return formatDate(parsedTime, options.modelTimeFormat || options.timeFormat);
- } else if(options.timeType === 'number') {
- return controller.$dateValue.getTime();
- } else if(options.timeType === 'unix') {
- return controller.$dateValue.getTime() / 1000;
- } else if(options.timeType === 'iso') {
- return controller.$dateValue.toISOString();
- } else {
- return new Date(controller.$dateValue);
+ // Observe scope attributes for change
+ attr.$observe('title', function(newValue) {
+ if (angular.isDefined(newValue) || !scope.hasOwnProperty('title')) {
+ var oldValue = scope.title;
+ scope.title = $sce.trustAsHtml(newValue);
+ angular.isDefined(oldValue) && $$rAF(function() {
+ tooltip && tooltip.$applyPlacement();
+ });
}
});
- // modelValue -> $formatters -> viewValue
- controller.$formatters.push(function(modelValue) {
- // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);
- var date;
- if(angular.isUndefined(modelValue) || modelValue === null) {
- date = NaN;
- } else if(angular.isDate(modelValue)) {
- date = modelValue;
- } else if(options.timeType === 'string') {
- date = dateParser.parse(modelValue, null, options.modelTimeFormat);
- } else if(options.timeType === 'unix') {
- date = new Date(modelValue * 1000);
+ // Support scope as an object
+ attr.bsTooltip && scope.$watch(attr.bsTooltip, function(newValue, oldValue) {
+ if(angular.isObject(newValue)) {
+ angular.extend(scope, newValue);
} else {
- date = new Date(modelValue);
+ scope.title = newValue;
}
- // Setup default value?
- // if(isNaN(date.getTime())) date = new Date(new Date().setMinutes(0) + 36e5);
- controller.$dateValue = date;
- return getTimeFormattedString();
+ angular.isDefined(oldValue) && $$rAF(function() {
+ tooltip && tooltip.$applyPlacement();
+ });
+ }, true);
+
+ // Visibility binding support
+ attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {
+ if(!tooltip || !angular.isDefined(newValue)) return;
+ if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(tooltip),?/i);
+ newValue === true ? tooltip.show() : tooltip.hide();
});
- // viewValue -> element
- controller.$render = function() {
- // console.warn('$render("%s"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);
- element.val(getTimeFormattedString());
- };
+ // Enabled binding support
+ attr.bsEnabled && scope.$watch(attr.bsEnabled, function(newValue, oldValue) {
+ // console.warn('scope.$watch(%s)', attr.bsEnabled, newValue, oldValue);
+ if(!tooltip || !angular.isDefined(newValue)) return;
+ if(angular.isString(newValue)) newValue = !!newValue.match(/true|1|,?(tooltip),?/i);
+ newValue === false ? tooltip.setEnabled(false) : tooltip.setEnabled(true);
+ });
- function getTimeFormattedString() {
- return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat);
- }
+ // Initialize popover
+ var tooltip = $tooltip(element, options);
// Garbage collection
scope.$on('$destroy', function() {
- if (timepicker) timepicker.destroy();
+ if(tooltip) tooltip.destroy();
options = null;
- timepicker = null;
+ tooltip = null;
});
}
diff --git a/dist/angular-strap.min.js b/dist/angular-strap.min.js
index 07d2617b9..2f28c7aa9 100644
--- a/dist/angular-strap.min.js
+++ b/dist/angular-strap.min.js
@@ -1,11 +1,11 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
*/
-!function(e,t,n){"use strict";angular.module("mgcrea.ngStrap",["mgcrea.ngStrap.modal","mgcrea.ngStrap.aside","mgcrea.ngStrap.alert","mgcrea.ngStrap.button","mgcrea.ngStrap.select","mgcrea.ngStrap.datepicker","mgcrea.ngStrap.timepicker","mgcrea.ngStrap.navbar","mgcrea.ngStrap.tooltip","mgcrea.ngStrap.popover","mgcrea.ngStrap.dropdown","mgcrea.ngStrap.typeahead","mgcrea.ngStrap.scrollspy","mgcrea.ngStrap.affix","mgcrea.ngStrap.tab","mgcrea.ngStrap.collapse","mgcrea.ngStrap.progressbar"]),angular.module("mgcrea.ngStrap.affix",["mgcrea.ngStrap.helpers.dimensions","mgcrea.ngStrap.helpers.debounce"]).provider("$affix",function(){var e=this.defaults={offsetTop:"auto"};this.$get=["$window","debounce","dimensions",function(t,n,a){function o(o,s){function l(e,t,n){var a=u(),o=c();return v>=a?"top":null!==e&&a+e<=t.top?"middle":null!==y&&t.top+n+$>=o-y?"bottom":"middle"}function u(){return p[0]===t?t.pageYOffset:p[0].scrollTop}function c(){return p[0]===t?t.document.body.scrollHeight:p[0].scrollHeight}var d={},f=angular.extend({},e,s),p=f.target,g="affix affix-top affix-bottom",m=!1,$=0,h=0,v=0,y=0,w=null,b=null,D=o.parent();if(f.offsetParent)if(f.offsetParent.match(/^\d+$/))for(var k=0;k<1*f.offsetParent-1;k++)D=D.parent();else D=angular.element(f.offsetParent);return d.init=function(){this.$parseOffsets(),h=a.offset(o[0]).top+$,m=!o[0].style.width,p.on("scroll",this.checkPosition),p.on("click",this.checkPositionWithEventLoop),r.on("resize",this.$debouncedOnResize),this.checkPosition(),this.checkPositionWithEventLoop()},d.destroy=function(){p.off("scroll",this.checkPosition),p.off("click",this.checkPositionWithEventLoop),r.off("resize",this.$debouncedOnResize)},d.checkPositionWithEventLoop=function(){setTimeout(d.checkPosition,1)},d.checkPosition=function(){var e=u(),t=a.offset(o[0]),n=a.height(o[0]),r=l(b,t,n);w!==r&&(w=r,o.removeClass(g).addClass("affix"+("middle"!==r?"-"+r:"")),"top"===r?(b=null,o.css("position",f.offsetParent?"":"relative"),m&&o.css("width",""),o.css("top","")):"bottom"===r?(b=f.offsetUnpin?-(1*f.offsetUnpin):t.top-e,m&&o.css("width",""),o.css("position",f.offsetParent?"":"relative"),o.css("top",f.offsetParent?"":i[0].offsetHeight-y-n-h+"px")):(b=null,m&&o.css("width",o[0].offsetWidth+"px"),o.css("position","fixed"),o.css("top",$+"px")))},d.$onResize=function(){d.$parseOffsets(),d.checkPosition()},d.$debouncedOnResize=n(d.$onResize,50),d.$parseOffsets=function(){var e=o.css("position");o.css("position",f.offsetParent?"":"relative"),f.offsetTop&&("auto"===f.offsetTop&&(f.offsetTop="+0"),f.offsetTop.match(/^[-+]\d+$/)?($=1*-f.offsetTop,v=f.offsetParent?a.offset(D[0]).top+1*f.offsetTop:a.offset(o[0]).top-a.css(o[0],"marginTop",!0)+1*f.offsetTop):v=1*f.offsetTop),f.offsetBottom&&(y=f.offsetParent&&f.offsetBottom.match(/^[-+]\d+$/)?c()-(a.offset(D[0]).top+a.height(D[0]))+1*f.offsetBottom+1:1*f.offsetBottom),o.css("position",e)},d.init(),d}var i=angular.element(t.document.body),r=angular.element(t);return o}]}).directive("bsAffix",["$affix","$window",function(e,t){return{restrict:"EAC",require:"^?bsAffixTarget",link:function(n,a,o,i){var r={scope:n,offsetTop:"auto",target:i?i.$element:angular.element(t)};angular.forEach(["offsetTop","offsetBottom","offsetParent","offsetUnpin"],function(e){angular.isDefined(o[e])&&(r[e]=o[e])});var s=e(a,r);n.$on("$destroy",function(){s&&s.destroy(),r=null,s=null})}}}]).directive("bsAffixTarget",function(){return{controller:["$element",function(e){this.$element=e}]}}),angular.module("mgcrea.ngStrap.alert",["mgcrea.ngStrap.modal"]).provider("$alert",function(){var e=this.defaults={animation:"am-fade",prefixClass:"alert",prefixEvent:"alert",placement:null,template:"alert/alert.tpl.html",container:!1,element:null,backdrop:!1,keyboard:!0,show:!0,duration:!1,type:!1,dismissable:!0};this.$get=["$modal","$timeout",function(t,n){function a(a){var o={},i=angular.extend({},e,a);o=t(i),o.$scope.dismissable=!!i.dismissable,i.type&&(o.$scope.type=i.type);var r=o.show;return i.duration&&(o.show=function(){r(),n(function(){o.hide()},1e3*i.duration)}),o}return a}]}).directive("bsAlert",["$window","$sce","$alert",function(e,t,n){e.requestAnimationFrame||e.setTimeout;return{restrict:"EAC",scope:!0,link:function(e,a,o){var i={scope:e,element:a,show:!1};angular.forEach(["template","placement","keyboard","html","container","animation","duration","dismissable"],function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),angular.forEach(["title","content","type"],function(n){o[n]&&o.$observe(n,function(a){e[n]=t.trustAsHtml(a)})}),o.bsAlert&&e.$watch(o.bsAlert,function(t){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var r=n(i);a.on(o.trigger||"click",r.toggle),e.$on("$destroy",function(){r&&r.destroy(),i=null,r=null})}}}]),angular.module("mgcrea.ngStrap.button",[]).provider("$button",function(){var e=this.defaults={activeClass:"active",toggleEvent:"click"};this.$get=function(){return{defaults:e}}}).directive("bsCheckboxGroup",function(){return{restrict:"A",require:"ngModel",compile:function(e,t){e.attr("data-toggle","buttons"),e.removeAttr("ng-model");var n=e[0].querySelectorAll('input[type="checkbox"]');angular.forEach(n,function(e){var n=angular.element(e);n.attr("bs-checkbox",""),n.attr("ng-model",t.ngModel+"."+n.attr("value"))})}}}).directive("bsCheckbox",["$button","$$rAF",function(e,t){var n=e.defaults,a=/^(true|false|\d+)$/;return{restrict:"A",require:"ngModel",link:function(e,o,i,r){var s=n,l="INPUT"===o[0].nodeName,u=l?o.parent():o,c=angular.isDefined(i.trueValue)?i.trueValue:!0;a.test(i.trueValue)&&(c=e.$eval(i.trueValue));var d=angular.isDefined(i.falseValue)?i.falseValue:!1;a.test(i.falseValue)&&(d=e.$eval(i.falseValue));var f="boolean"!=typeof c||"boolean"!=typeof d;f&&(r.$parsers.push(function(e){return e?c:d}),r.$formatters.push(function(e){return angular.equals(e,c)}),e.$watch(i.ngModel,function(){r.$render()})),r.$render=function(){var e=angular.equals(r.$modelValue,c);t(function(){l&&(o[0].checked=e),u.toggleClass(s.activeClass,e)})},o.bind(s.toggleEvent,function(){e.$apply(function(){l||r.$setViewValue(!u.hasClass("active")),f||r.$render()})})}}}]).directive("bsRadioGroup",function(){return{restrict:"A",require:"ngModel",compile:function(e,t){e.attr("data-toggle","buttons"),e.removeAttr("ng-model");var n=e[0].querySelectorAll('input[type="radio"]');angular.forEach(n,function(e){angular.element(e).attr("bs-radio",""),angular.element(e).attr("ng-model",t.ngModel)})}}}).directive("bsRadio",["$button","$$rAF",function(e,t){var n=e.defaults,a=/^(true|false|\d+)$/;return{restrict:"A",require:"ngModel",link:function(e,o,i,r){var s=n,l="INPUT"===o[0].nodeName,u=l?o.parent():o,c=a.test(i.value)?e.$eval(i.value):i.value;r.$render=function(){var e=angular.equals(r.$modelValue,c);t(function(){l&&(o[0].checked=e),u.toggleClass(s.activeClass,e)})},o.bind(s.toggleEvent,function(){e.$apply(function(){r.$setViewValue(c),r.$render()})})}}}]),angular.module("mgcrea.ngStrap.datepicker",["mgcrea.ngStrap.helpers.dateParser","mgcrea.ngStrap.helpers.dateFormatter","mgcrea.ngStrap.tooltip"]).provider("$datepicker",function(){var e=this.defaults={animation:"am-fade",prefixClass:"datepicker",placement:"bottom-left",template:"datepicker/datepicker.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,useNative:!1,dateType:"date",dateFormat:"shortDate",modelDateFormat:null,dayFormat:"dd",monthFormat:"MMM",yearFormat:"yyyy",monthTitleFormat:"MMMM yyyy",yearTitleFormat:"yyyy",strictFormat:!1,autoclose:!1,minDate:-1/0,maxDate:+1/0,startView:0,minView:0,startWeek:0,daysOfWeekDisabled:"",iconLeft:"glyphicon glyphicon-chevron-left",iconRight:"glyphicon glyphicon-chevron-right"};this.$get=["$window","$document","$rootScope","$sce","$dateFormatter","datepickerViews","$tooltip","$timeout",function(t,n,a,o,i,r,s,l){function u(t,n,a){function o(e){e.selected=u.$isSelected(e.date)}function i(){t[0].focus()}var u=s(t,angular.extend({},e,a)),f=a.scope,p=u.$options,g=u.$scope;p.startView&&(p.startView-=p.minView);var m=r(u);u.$views=m.views;var $=m.viewDate;g.$mode=p.startView,g.$iconLeft=p.iconLeft,g.$iconRight=p.iconRight;var h=u.$views[g.$mode];g.$select=function(e){u.select(e)},g.$selectPane=function(e){u.$selectPane(e)},g.$toggleMode=function(){u.setMode((g.$mode+1)%u.$views.length)},u.update=function(e){angular.isDate(e)&&!isNaN(e.getTime())&&(u.$date=e,h.update.call(h,e)),u.$build(!0)},u.updateDisabledDates=function(e){p.disabledDateRanges=e;for(var t=0,n=g.rows.length;n>t;t++)angular.forEach(g.rows[t],u.$setDisabledEl)},u.select=function(e,t){angular.isDate(n.$dateValue)||(n.$dateValue=new Date(e)),!g.$mode||t?(n.$setViewValue(angular.copy(e)),n.$render(),p.autoclose&&!t&&l(function(){u.hide(!0)})):(angular.extend($,{year:e.getFullYear(),month:e.getMonth(),date:e.getDate()}),u.setMode(g.$mode-1),u.$build())},u.setMode=function(e){g.$mode=e,h=u.$views[g.$mode],u.$build()},u.$build=function(e){e===!0&&h.built||(e!==!1||h.built)&&h.build.call(h)},u.$updateSelected=function(){for(var e=0,t=g.rows.length;t>e;e++)angular.forEach(g.rows[e],o)},u.$isSelected=function(e){return h.isSelected(e)},u.$setDisabledEl=function(e){e.disabled=h.isDisabled(e.date)},u.$selectPane=function(e){var t=h.steps,n=new Date(Date.UTC($.year+(t.year||0)*e,$.month+(t.month||0)*e,1));angular.extend($,{year:n.getUTCFullYear(),month:n.getUTCMonth(),date:n.getUTCDate()}),u.$build()},u.$onMouseDown=function(e){if(e.preventDefault(),e.stopPropagation(),d){var t=angular.element(e.target);"button"!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler("click")}},u.$onKeyDown=function(e){if(/(38|37|39|40|13)/.test(e.keyCode)&&!e.shiftKey&&!e.altKey){if(e.preventDefault(),e.stopPropagation(),13===e.keyCode)return g.$mode?g.$apply(function(){u.setMode(g.$mode-1)}):u.hide(!0);h.onKeyDown(e),f.$digest()}};var v=u.init;u.init=function(){return c&&p.useNative?(t.prop("type","date"),void t.css("-webkit-appearance","textfield")):(d&&(t.prop("type","text"),t.attr("readonly","true"),t.on("click",i)),void v())};var y=u.destroy;u.destroy=function(){c&&p.useNative&&t.off("click",i),y()};var w=u.show;u.show=function(){w(),l(function(){u.$element.on(d?"touchstart":"mousedown",u.$onMouseDown),p.keyboard&&t.on("keydown",u.$onKeyDown)},0,!1)};var b=u.hide;return u.hide=function(e){u.$isShown&&(u.$element.off(d?"touchstart":"mousedown",u.$onMouseDown),p.keyboard&&t.off("keydown",u.$onKeyDown),b(e))},u}var c=(angular.element(t.document.body),/(ip(a|o)d|iphone|android)/gi.test(t.navigator.userAgent)),d="createTouch"in t.document&&c;return e.lang||(e.lang=i.getDefaultLocale()),u.defaults=e,u}]}).directive("bsDatepicker",["$window","$parse","$q","$dateFormatter","$dateParser","$datepicker",function(e,t,n,a,o,i){var r=(i.defaults,/(ip(a|o)d|iphone|android)/gi.test(e.navigator.userAgent));return{restrict:"EAC",require:"ngModel",link:function(e,t,n,s){function l(e){return e&&e.length?e:null}function u(e){if(angular.isDate(e)){var t=isNaN(f.$options.minDate)||e.getTime()>=f.$options.minDate,n=isNaN(f.$options.maxDate)||e.getTime()<=f.$options.maxDate,a=t&&n;s.$setValidity("date",a),s.$setValidity("min",t),s.$setValidity("max",n),a&&(s.$dateValue=e)}}function c(){return!s.$dateValue||isNaN(s.$dateValue.getTime())?"":g(s.$dateValue,d.dateFormat)}var d={scope:e,controller:s};angular.forEach(["placement","container","delay","trigger","keyboard","html","animation","template","autoclose","dateType","dateFormat","modelDateFormat","dayFormat","strictFormat","startWeek","startDate","useNative","lang","startView","minView","iconLeft","iconRight","daysOfWeekDisabled"],function(e){angular.isDefined(n[e])&&(d[e]=n[e])}),n.bsShow&&e.$watch(n.bsShow,function(e){f&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(datepicker),?/i)),e===!0?f.show():f.hide())});var f=i(t,s,d);d=f.$options,r&&d.useNative&&(d.dateFormat="yyyy-MM-dd");var p=d.lang,g=function(e,t){return a.formatDate(e,t,p)},m=o({format:d.dateFormat,lang:p,strict:d.strictFormat});angular.forEach(["minDate","maxDate"],function(e){angular.isDefined(n[e])&&n.$observe(e,function(t){f.$options[e]=m.getDateForAttribute(e,t),!isNaN(f.$options[e])&&f.$build(!1),u(s.$dateValue)})}),e.$watch(n.ngModel,function(){f.update(s.$dateValue)},!0),angular.isDefined(n.disabledDates)&&e.$watch(n.disabledDates,function(e,t){e=l(e),t=l(t),e&&f.updateDisabledDates(e)}),s.$parsers.unshift(function(e){if(!e)return s.$setValidity("date",!0),null;var t=m.parse(e,s.$dateValue);return!t||isNaN(t.getTime())?void s.$setValidity("date",!1):(u(t),"string"===d.dateType?g(t,d.modelDateFormat||d.dateFormat):"number"===d.dateType?s.$dateValue.getTime():"unix"===d.dateType?s.$dateValue.getTime()/1e3:"iso"===d.dateType?s.$dateValue.toISOString():new Date(s.$dateValue))}),s.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:"string"===d.dateType?m.parse(e,null,d.modelDateFormat):new Date("unix"===d.dateType?1e3*e:e),s.$dateValue=t,c()}),s.$render=function(){t.val(c())},e.$on("$destroy",function(){f&&f.destroy(),d=null,f=null})}}}]).provider("datepickerViews",function(){function e(e,t){for(var n=[];e.length>0;)n.push(e.splice(0,t));return n}function t(e,t){return(e%t+t)%t}this.defaults={dayFormat:"dd",daySplit:7};this.$get=["$dateFormatter","$dateParser","$sce",function(n,a,o){return function(i){var r=i.$scope,s=i.$options,l=s.lang,u=function(e,t){return n.formatDate(e,t,l)},c=a({format:s.dateFormat,lang:l,strict:s.strictFormat}),d=n.weekdaysShort(l),f=d.slice(s.startWeek).concat(d.slice(0,s.startWeek)),p=o.trustAsHtml(''+f.join(' ')+" "),g=i.$date||(s.startDate?c.getDateForAttribute("startDate",s.startDate):new Date),m={year:g.getFullYear(),month:g.getMonth(),date:g.getDate()},$=(6e4*g.getTimezoneOffset(),[{format:s.dayFormat,split:7,steps:{month:1},update:function(e,t){!this.built||t||e.getFullYear()!==m.year||e.getMonth()!==m.month?(angular.extend(m,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$build()):e.getDate()!==m.date&&(m.date=i.$date.getDate(),i.$updateSelected())},build:function(){var n=new Date(m.year,m.month,1),a=n.getTimezoneOffset(),o=new Date(+n-864e5*t(n.getDay()-s.startWeek,7)),l=o.getTimezoneOffset(),d=(new Date).toDateString();l!==a&&(o=new Date(+o+6e4*(l-a)));for(var f,g=[],$=0;42>$;$++)f=c.daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth(),o.getDate()+$)),g.push({date:f,isToday:f.toDateString()===d,label:u(f,this.format),selected:i.$date&&this.isSelected(f),muted:f.getMonth()!==m.month,disabled:this.isDisabled(f)});r.title=u(n,s.monthTitleFormat),r.showLabels=!0,r.labels=p,r.rows=e(g,this.split),this.built=!0},isSelected:function(e){return i.$date&&e.getFullYear()===i.$date.getFullYear()&&e.getMonth()===i.$date.getMonth()&&e.getDate()===i.$date.getDate()},isDisabled:function(e){var t=e.getTime();if(ts.maxDate)return!0;if(-1!==s.daysOfWeekDisabled.indexOf(e.getDay()))return!0;if(s.disabledDateRanges)for(var n=0;n=s.disabledDateRanges[n].start&&t<=s.disabledDateRanges[n].end)return!0;return!1},onKeyDown:function(e){if(i.$date){var t,n=i.$date.getTime();37===e.keyCode?t=new Date(n-864e5):38===e.keyCode?t=new Date(n-6048e5):39===e.keyCode?t=new Date(n+864e5):40===e.keyCode&&(t=new Date(n+6048e5)),this.isDisabled(t)||i.select(t,!0)}}},{name:"month",format:s.monthFormat,split:4,steps:{year:1},update:function(e){this.built&&e.getFullYear()===m.year?e.getMonth()!==m.month&&(angular.extend(m,{month:i.$date.getMonth(),date:i.$date.getDate()}),i.$updateSelected()):(angular.extend(m,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$build())},build:function(){for(var t,n=(new Date(m.year,0,1),[]),a=0;12>a;a++)t=new Date(m.year,a,1),n.push({date:t,label:u(t,this.format),selected:i.$isSelected(t),disabled:this.isDisabled(t)});r.title=u(t,s.yearTitleFormat),r.showLabels=!1,r.rows=e(n,this.split),this.built=!0},isSelected:function(e){return i.$date&&e.getFullYear()===i.$date.getFullYear()&&e.getMonth()===i.$date.getMonth()},isDisabled:function(e){var t=+new Date(e.getFullYear(),e.getMonth()+1,0);return ts.maxDate},onKeyDown:function(e){if(i.$date){var t=i.$date.getMonth(),n=new Date(i.$date);37===e.keyCode?n.setMonth(t-1):38===e.keyCode?n.setMonth(t-4):39===e.keyCode?n.setMonth(t+1):40===e.keyCode&&n.setMonth(t+4),this.isDisabled(n)||i.select(n,!0)}}},{name:"year",format:s.yearFormat,split:4,steps:{year:12},update:function(e,t){!this.built||t||parseInt(e.getFullYear()/20,10)!==parseInt(m.year/20,10)?(angular.extend(m,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$build()):e.getFullYear()!==m.year&&(angular.extend(m,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$updateSelected())},build:function(){for(var t,n=m.year-m.year%(3*this.split),a=[],o=0;12>o;o++)t=new Date(n+o,0,1),a.push({date:t,label:u(t,this.format),selected:i.$isSelected(t),disabled:this.isDisabled(t)});r.title=a[0].label+"-"+a[a.length-1].label,r.showLabels=!1,r.rows=e(a,this.split),this.built=!0},isSelected:function(e){return i.$date&&e.getFullYear()===i.$date.getFullYear()},isDisabled:function(e){var t=+new Date(e.getFullYear()+1,0,0);return ts.maxDate},onKeyDown:function(e){if(i.$date){var t=i.$date.getFullYear(),n=new Date(i.$date);37===e.keyCode?n.setYear(t-1):38===e.keyCode?n.setYear(t-4):39===e.keyCode?n.setYear(t+1):40===e.keyCode&&n.setYear(t+4),this.isDisabled(n)||i.select(n,!0)}}}]);return{views:s.minView?Array.prototype.slice.call($,s.minView):$,viewDate:m}}}]}),angular.module("mgcrea.ngStrap.collapse",[]).provider("$collapse",function(){var e=this.defaults={animation:"am-collapse",disallowToggle:!1,activeClass:"in",startCollapsed:!1,allowMultiple:!1},t=this.controller=function(t,n,a){function o(e){for(var t=l.$targets.$active,n=0;n0?n--:40===e.keyCode&&no;o++)if(e[o].toLowerCase()===a)return o;return-1}e.prototype.setMilliseconds=function(e){this.milliseconds=e},e.prototype.setSeconds=function(e){this.seconds=e},e.prototype.setMinutes=function(e){this.minutes=e},e.prototype.setHours=function(e){this.hours=e},e.prototype.getHours=function(){return this.hours},e.prototype.setDate=function(e){this.day=e},e.prototype.setMonth=function(e){this.month=e},e.prototype.setFullYear=function(e){this.year=e},e.prototype.fromDate=function(e){return this.year=e.getFullYear(),this.month=e.getMonth(),this.day=e.getDate(),this.hours=e.getHours(),this.minutes=e.getMinutes(),this.seconds=e.getSeconds(),this.milliseconds=e.getMilliseconds(),this},e.prototype.toDate=function(){return new Date(this.year,this.month,this.day,this.hours,this.minutes,this.seconds,this.milliseconds)};var o=e.prototype,i=this.defaults={format:"shortDate",strict:!1};this.$get=["$locale","dateFilter",function(r,s){var l=function(l){function u(e){var t,n=Object.keys(h),a=[],o=[],i=e;for(t=0;t1){var r=i.search(n[t]);e=e.split(n[t]).join(""),h[n[t]]&&(a[r]=h[n[t]])}return angular.forEach(a,function(e){e&&o.push(e)}),o}function c(e){return e.replace(/\//g,"[\\/]").replace("/-/g","[-]").replace(/\./g,"[.]").replace(/\\s/g,"[\\s]")}function d(e){var t,n=Object.keys($),a=e;for(t=0;t12?e.getHours()+2:0),e):null},m.init(),m};return l}]}]),angular.module("mgcrea.ngStrap.helpers.debounce",[]).factory("debounce",["$timeout",function(e){return function(t,n,a){var o=null;return function(){var i=this,r=arguments,s=a&&!o;return o&&e.cancel(o),o=e(function(){o=null,a||t.apply(i,r)},n,!1),s&&t.apply(i,r),o}}}]).factory("throttle",["$timeout",function(e){return function(t,n,a){var o=null;return a||(a={}),function(){var i=this,r=arguments;o||(a.leading!==!1&&t.apply(i,r),o=e(function(){o=null,a.trailing!==!1&&t.apply(i,r)},n,!1))}}}]),angular.module("mgcrea.ngStrap.helpers.dimensions",[]).factory("dimensions",["$document","$window",function(){var t=(angular.element,{}),n=t.nodeName=function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()};t.css=function(t,n,a){var o;return o=t.currentStyle?t.currentStyle[n]:e.getComputedStyle?e.getComputedStyle(t)[n]:t.style[n],a===!0?parseFloat(o)||0:o},t.offset=function(t){var n=t.getBoundingClientRect(),a=t.ownerDocument;return{width:n.width||t.offsetWidth,height:n.height||t.offsetHeight,top:n.top+(e.pageYOffset||a.documentElement.scrollTop)-(a.documentElement.clientTop||0),left:n.left+(e.pageXOffset||a.documentElement.scrollLeft)-(a.documentElement.clientLeft||0)}},t.position=function(e){var o,i,r={top:0,left:0};return"fixed"===t.css(e,"position")?i=e.getBoundingClientRect():(o=a(e),i=t.offset(e),n(o,"html")||(r=t.offset(o)),r.top+=t.css(o,"borderTopWidth",!0),r.left+=t.css(o,"borderLeftWidth",!0)),{width:e.offsetWidth,height:e.offsetHeight,top:i.top-r.top-t.css(e,"marginTop",!0),left:i.left-r.left-t.css(e,"marginLeft",!0)}};var a=function(e){var a=e.ownerDocument,o=e.offsetParent||a;if(n(o,"#document"))return a.documentElement;for(;o&&!n(o,"html")&&"static"===t.css(o,"position");)o=o.offsetParent;return o||a.documentElement};return t.height=function(e,n){var a=e.offsetHeight;return n?a+=t.css(e,"marginTop",!0)+t.css(e,"marginBottom",!0):a-=t.css(e,"paddingTop",!0)+t.css(e,"paddingBottom",!0)+t.css(e,"borderTopWidth",!0)+t.css(e,"borderBottomWidth",!0),a},t.width=function(e,n){var a=e.offsetWidth;return n?a+=t.css(e,"marginLeft",!0)+t.css(e,"marginRight",!0):a-=t.css(e,"paddingLeft",!0)+t.css(e,"paddingRight",!0)+t.css(e,"borderLeftWidth",!0)+t.css(e,"borderRightWidth",!0),a},t}]),angular.module("mgcrea.ngStrap.helpers.parseOptions",[]).provider("$parseOptions",function(){var e=this.defaults={regexp:/^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/};this.$get=["$parse","$q",function(t,n){function a(a,o){function i(e,t){return e.map(function(e,n){var a,o,i={};return i[c]=e,a=u(t,i),o=p(t,i),{label:a,value:o,index:n}})}var r={},s=angular.extend({},e,o);r.$values=[];var l,u,c,d,f,p,g;return r.init=function(){r.$match=l=a.match(s.regexp),u=t(l[2]||l[1]),c=l[4]||l[6],d=l[5],f=t(l[3]||""),p=t(l[2]?l[1]:c),g=t(l[7])},r.valuesFn=function(e,t){return n.when(g(e,t)).then(function(t){return r.$values=t?i(t,e):{},r.$values})},r.displayValue=function(e){var t={};return t[c]=e,u(t)},r.init(),r}return a}]}),angular.version.minor<3&&angular.version.dot<14&&angular.module("ng").factory("$$rAF",["$window","$timeout",function(e,t){var n=e.requestAnimationFrame||e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame,a=e.cancelAnimationFrame||e.webkitCancelAnimationFrame||e.mozCancelAnimationFrame||e.webkitCancelRequestAnimationFrame,o=!!n,i=o?function(e){var t=n(e);return function(){a(t)}}:function(e){var n=t(e,16.66,!1);return function(){t.cancel(n)}};return i.supported=o,i}]),angular.module("mgcrea.ngStrap.aside",["mgcrea.ngStrap.modal"]).provider("$aside",function(){var e=this.defaults={animation:"am-fade-and-slide-right",prefixClass:"aside",prefixEvent:"aside",placement:"right",template:"aside/aside.tpl.html",contentTemplate:!1,container:!1,element:null,backdrop:!0,keyboard:!0,html:!1,show:!0};this.$get=["$modal",function(t){function n(n){var a={},o=angular.extend({},e,n);return a=t(o)}return n}]}).directive("bsAside",["$window","$sce","$aside",function(e,t,n){e.requestAnimationFrame||e.setTimeout;
-return{restrict:"EAC",scope:!0,link:function(e,a,o){var i={scope:e,element:a,show:!1};angular.forEach(["template","contentTemplate","placement","backdrop","keyboard","html","container","animation"],function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),angular.forEach(["title","content"],function(n){o[n]&&o.$observe(n,function(a){e[n]=t.trustAsHtml(a)})}),o.bsAside&&e.$watch(o.bsAside,function(t){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var r=n(i);a.on(o.trigger||"click",r.toggle),e.$on("$destroy",function(){r&&r.destroy(),i=null,r=null})}}}]),angular.module("mgcrea.ngStrap.modal",["mgcrea.ngStrap.helpers.dimensions"]).provider("$modal",function(){var e=this.defaults={animation:"am-fade",backdropAnimation:"am-fade",prefixClass:"modal",prefixEvent:"modal",placement:"top",template:"modal/modal.tpl.html",contentTemplate:!1,container:!1,element:null,backdrop:!0,keyboard:!0,html:!1,show:!0};this.$get=["$window","$rootScope","$compile","$q","$templateCache","$http","$animate","$timeout","$sce","dimensions",function(n,a,o,i,r,s,l,u,c){function d(t){function n(){w.$emit(d.prefixEvent+".show",u)}function i(){w.$emit(d.prefixEvent+".hide",u),v.removeClass(d.prefixClass+"-open"),d.animation&&v.removeClass(d.prefixClass+"-with-"+d.animation)}function r(e){e.target===e.currentTarget&&("static"===d.backdrop?u.focus():u.hide())}function s(e){e.preventDefault()}var u={},d=u.$options=angular.extend({},e,t);u.$promise=g(d.template);var w=u.$scope=d.scope&&d.scope.$new()||a.$new();d.element||d.container||(d.container="body"),m(["title","content"],function(e){d[e]&&(w[e]=c.trustAsHtml(d[e]))}),w.$hide=function(){w.$$postDigest(function(){u.hide()})},w.$show=function(){w.$$postDigest(function(){u.show()})},w.$toggle=function(){w.$$postDigest(function(){u.toggle()})},u.$isShown=w.$isShown=!1,d.contentTemplate&&(u.$promise=u.$promise.then(function(e){var n=angular.element(e);return g(d.contentTemplate).then(function(e){var a=p('[ng-bind="content"]',n[0]).removeAttr("ng-bind").html(e);return t.template||a.next().remove(),n[0].outerHTML})}));var b,D,k=angular.element('
');return u.$promise.then(function(e){angular.isObject(e)&&(e=e.data),d.html&&(e=e.replace(y,'ng-bind-html="')),e=$.apply(e),b=o(e),u.init()}),u.init=function(){d.show&&w.$$postDigest(function(){u.show()})},u.destroy=function(){D&&(D.remove(),D=null),k&&(k.remove(),k=null),w.$destroy()},u.show=function(){if(!u.$isShown&&!w.$emit(d.prefixEvent+".show.before",u).defaultPrevented){var e,t;angular.isElement(d.container)?(e=d.container,t=d.container[0].lastChild?angular.element(d.container[0].lastChild):null):d.container?(e=p(d.container),t=e[0].lastChild?angular.element(e[0].lastChild):null):(e=null,t=d.element),D=u.$element=b(w,function(){}),D.css({display:"block"}).addClass(d.placement),d.animation&&(d.backdrop&&k.addClass(d.backdropAnimation),D.addClass(d.animation)),d.backdrop&&l.enter(k,v,null);var a=l.enter(D,e,t,n);a&&a.then&&a.then(n),u.$isShown=w.$isShown=!0,f(w);var o=D[0];h(function(){o.focus()}),v.addClass(d.prefixClass+"-open"),d.animation&&v.addClass(d.prefixClass+"-with-"+d.animation),d.backdrop&&(D.on("click",r),k.on("click",r),k.on("wheel",s)),d.keyboard&&D.on("keyup",u.$onKeyUp)}},u.hide=function(){if(u.$isShown&&!w.$emit(d.prefixEvent+".hide.before",u).defaultPrevented){var e=l.leave(D,i);e&&e.then&&e.then(i),d.backdrop&&l.leave(k),u.$isShown=w.$isShown=!1,f(w),d.backdrop&&(D.off("click",r),k.off("click",r),k.off("wheel",s)),d.keyboard&&D.off("keyup",u.$onKeyUp)}},u.toggle=function(){u.$isShown?u.hide():u.show()},u.focus=function(){D[0].focus()},u.$onKeyUp=function(e){27===e.which&&u.$isShown&&(u.hide(),e.stopPropagation())},u}function f(e){e.$$phase||e.$root&&e.$root.$$phase||e.$digest()}function p(e,n){return angular.element((n||t).querySelectorAll(e))}function g(e){return w[e]?w[e]:w[e]=i.when(r.get(e)||s.get(e)).then(function(t){return angular.isObject(t)?(r.put(e,t.data),t.data):t})}var m=angular.forEach,$=String.prototype.trim,h=n.requestAnimationFrame||n.setTimeout,v=angular.element(n.document.body),y=/ng-bind="/gi,w={};return d}]}).directive("bsModal",["$window","$sce","$modal",function(e,t,n){return{restrict:"EAC",scope:!0,link:function(e,a,o){var i={scope:e,element:a,show:!1};angular.forEach(["template","contentTemplate","placement","backdrop","keyboard","html","container","animation"],function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),angular.forEach(["title","content"],function(n){o[n]&&o.$observe(n,function(a){e[n]=t.trustAsHtml(a)})}),o.bsModal&&e.$watch(o.bsModal,function(t){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var r=n(i);a.on(o.trigger||"click",r.toggle),e.$on("$destroy",function(){r&&r.destroy(),i=null,r=null})}}}]),angular.module("mgcrea.ngStrap.navbar",[]).provider("$navbar",function(){var e=this.defaults={activeClass:"active",routeAttr:"data-match-route",strict:!1};this.$get=function(){return{defaults:e}}}).directive("bsNavbar",["$window","$location","$navbar",function(e,t,n){var a=n.defaults;return{restrict:"A",link:function(e,n,o){var i=angular.copy(a);angular.forEach(Object.keys(a),function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),e.$watch(function(){return t.path()},function(e){var t=n[0].querySelectorAll("li["+i.routeAttr+"]");angular.forEach(t,function(t){var n=angular.element(t),a=n.attr(i.routeAttr).replace("/","\\/");i.strict&&(a="^"+a+"$");var o=new RegExp(a,["i"]);o.test(e)?n.addClass(i.activeClass):n.removeClass(i.activeClass)})})}}}]),angular.module("mgcrea.ngStrap.scrollspy",["mgcrea.ngStrap.helpers.debounce","mgcrea.ngStrap.helpers.dimensions"]).provider("$scrollspy",function(){var e=this.$$spies={},n=this.defaults={debounce:150,throttle:100,offset:100};this.$get=["$window","$document","$rootScope","dimensions","debounce","throttle",function(a,o,i,r,s,l){function u(e,t){return e[0].nodeName&&e[0].nodeName.toLowerCase()===t.toLowerCase()}function c(o){var c=angular.extend({},n,o);c.element||(c.element=p);var g=u(c.element,"body"),m=g?d:c.element,$=g?"window":c.id;if(e[$])return e[$].$$count++,e[$];var h,v,y,w,b,D,k,T,S={},x=S.$trackedElements=[],C=[];return S.init=function(){this.$$count=1,w=s(this.checkPosition,c.debounce),b=l(this.checkPosition,c.throttle),m.on("click",this.checkPositionWithEventLoop),d.on("resize",w),m.on("scroll",b),D=s(this.checkOffsets,c.debounce),h=i.$on("$viewContentLoaded",D),v=i.$on("$includeContentLoaded",D),D(),$&&(e[$]=S)},S.destroy=function(){this.$$count--,this.$$count>0||(m.off("click",this.checkPositionWithEventLoop),d.off("resize",w),m.off("scroll",b),h(),v(),$&&delete e[$])},S.checkPosition=function(){if(C.length){if(T=(g?a.pageYOffset:m.prop("scrollTop"))||0,k=Math.max(a.innerHeight,f.prop("clientHeight")),TC[e+1].offsetTop))return S.$activateElement(C[e])}},S.checkPositionWithEventLoop=function(){setTimeout(S.checkPosition,1)},S.$activateElement=function(e){if(y){var t=S.$getTrackedElement(y);t&&(t.source.removeClass("active"),u(t.source,"li")&&u(t.source.parent().parent(),"li")&&t.source.parent().parent().removeClass("active"))}y=e.target,e.source.addClass("active"),u(e.source,"li")&&u(e.source.parent().parent(),"li")&&e.source.parent().parent().addClass("active")},S.$getTrackedElement=function(e){return x.filter(function(t){return t.target===e})[0]},S.checkOffsets=function(){angular.forEach(x,function(e){var n=t.querySelector(e.target);e.offsetTop=n?r.offset(n).top:null,c.offset&&null!==e.offsetTop&&(e.offsetTop-=1*c.offset)}),C=x.filter(function(e){return null!==e.offsetTop}).sort(function(e,t){return e.offsetTop-t.offsetTop}),w()},S.trackElement=function(e,t){x.push({target:e,source:t})},S.untrackElement=function(e,t){for(var n,a=x.length;a--;)if(x[a].target===e&&x[a].source===t){n=a;break}x=x.splice(n,1)},S.activate=function(e){x[e].addClass("active")},S.init(),S}var d=angular.element(a),f=angular.element(o.prop("documentElement")),p=angular.element(a.document.body);return c}]}).directive("bsScrollspy",["$rootScope","debounce","dimensions","$scrollspy",function(e,t,n,a){return{restrict:"EAC",link:function(e,t,n){var o={scope:e};angular.forEach(["offset","target"],function(e){angular.isDefined(n[e])&&(o[e]=n[e])});var i=a(o);i.trackElement(o.target,t),e.$on("$destroy",function(){i&&(i.untrackElement(o.target,t),i.destroy()),o=null,i=null})}}}]).directive("bsScrollspyList",["$rootScope","debounce","dimensions","$scrollspy",function(){return{restrict:"A",compile:function(e){var t=e[0].querySelectorAll("li > a[href]");angular.forEach(t,function(e){var t=angular.element(e);t.parent().attr("bs-scrollspy","").attr("data-target",t.attr("href"))})}}}]),angular.module("mgcrea.ngStrap.progressbar",[]).provider("$progressbar",function(){var e={barType:"",animate:function(){return!0}};this.$get=function(){return{defaults:e}}}).directive("bsProgressbar",["$progressbar",function(e){return{restrict:"E",transclude:!0,replace:!0,templateUrl:"progressbar/progressbar.tpl.html",scope:{value:"=",type:"@",animate:"&"},link:function(t){t.type=t.type||e.defaults.barType,t.animate=angular.isDefined(t.animate())?t.animate:e.defaults.animate,console.log(t.animate(),e.defaults.animate,angular.isDefined(t.animate)),t.$watch("type",function(){t.barClass=t.type?"progress-bar-"+t.type:null})}}}]),angular.module("mgcrea.ngStrap.select",["mgcrea.ngStrap.tooltip","mgcrea.ngStrap.helpers.parseOptions"]).provider("$select",function(){var e=this.defaults={animation:"am-fade",prefixClass:"select",prefixEvent:"$select",placement:"bottom-left",template:"select/select.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,multiple:!1,allNoneButtons:!1,sort:!0,caretHtml:' ',placeholder:"Choose among the following...",allText:"All",noneText:"None",maxLength:3,maxLengthHtml:"selected",iconCheckmark:"glyphicon glyphicon-ok"};this.$get=["$window","$document","$rootScope","$tooltip","$timeout",function(t,n,a,o,i){function r(t,n,a){var r={},s=angular.extend({},e,a);r=o(t,s);var u=r.$scope;u.$matches=[],u.$activeIndex=0,u.$isMultiple=s.multiple,u.$showAllNoneButtons=s.allNoneButtons&&s.multiple,u.$iconCheckmark=s.iconCheckmark,u.$allText=s.allText,u.$noneText=s.noneText,u.$activate=function(e){u.$$postDigest(function(){r.activate(e)})},u.$select=function(e){u.$$postDigest(function(){r.select(e)})},u.$isVisible=function(){return r.$isVisible()},u.$isActive=function(e){return r.$isActive(e)},u.$selectAll=function(){for(var e=0;e=u.$matches.length&&(u.$activeIndex=s.multiple?[]:0)},r.$isVisible=function(){return s.minLength&&n?u.$matches.length&&n.$viewValue.length>=s.minLength:u.$matches.length},r.$isActive=function(e){return s.multiple?-1!==u.$activeIndex.indexOf(e):u.$activeIndex===e},r.$getIndex=function(e){var t=u.$matches.length,n=t;if(t){for(n=t;n--&&u.$matches[n].value!==e;);if(!(0>n))return n}},r.$onMouseDown=function(e){if(e.preventDefault(),e.stopPropagation(),l){var t=angular.element(e.target);t.triggerHandler("click")}},r.$onKeyDown=function(e){if(/(9|13|38|40)/.test(e.keyCode)){if(e.preventDefault(),e.stopPropagation(),!s.multiple&&(13===e.keyCode||9===e.keyCode))return r.select(u.$activeIndex);38===e.keyCode&&u.$activeIndex>0?u.$activeIndex--:40===e.keyCode&&u.$activeIndex'),l.after(t)}var u=o(n.ngOptions),c=a(t,r,s),d=u.$match[7].replace(/\|.+/,"").trim();e.$watch(d,function(){u.valuesFn(e,r).then(function(e){c.update(e),r.$render()})},!0),e.$watch(n.ngModel,function(){c.$updateActiveIndex(),r.$render()},!0),r.$render=function(){var e,n;s.multiple&&angular.isArray(r.$modelValue)?(e=r.$modelValue.map(function(e){return n=c.$getIndex(e),angular.isDefined(n)?c.$scope.$matches[n].label:!1}).filter(angular.isDefined),e=e.length>(s.maxLength||i.maxLength)?e.length+" "+(s.maxLengthHtml||i.maxLengthHtml):e.join(", ")):(n=c.$getIndex(r.$modelValue),e=angular.isDefined(n)?c.$scope.$matches[n].label:!1),t.html((e?e:s.placeholder)+i.caretHtml)},s.multiple&&(r.$isEmpty=function(e){return!e||0===e.length}),e.$on("$destroy",function(){c&&c.destroy(),s=null,c=null})}}}]),angular.module("mgcrea.ngStrap.tab",[]).provider("$tab",function(){var e=this.defaults={animation:"am-fade",template:"tab/tab.tpl.html",navClass:"nav-tabs",activeClass:"active"},t=this.controller=function(t,n,a){var o=this;o.$options=angular.copy(e),angular.forEach(["animation","navClass","activeClass"],function(e){angular.isDefined(a[e])&&(o.$options[e]=a[e])}),t.$navClass=o.$options.navClass,t.$activeClass=o.$options.activeClass,o.$panes=t.$panes=[],o.$activePaneChangeListeners=o.$viewChangeListeners=[],o.$push=function(e){o.$panes.push(e)},o.$remove=function(e){var t=o.$panes.indexOf(e),n=o.$panes.$active;o.$panes.splice(t,1),n>t?n--:t===n&&n===o.$panes.length&&n--,o.$setActive(n)},o.$panes.$active=0,o.$setActive=t.$setActive=function(e){o.$panes.$active=e,o.$activePaneChangeListeners.forEach(function(e){e()})}};this.$get=function(){var n={};return n.defaults=e,n.controller=t,n}}).directive("bsTabs",["$window","$animate","$tab","$parse",function(e,t,n,a){var o=n.defaults;return{require:["?ngModel","bsTabs"],transclude:!0,scope:!0,controller:["$scope","$element","$attrs",n.controller],templateUrl:function(e,t){return t.template||o.template},link:function(e,t,n,o){var i=o[0],r=o[1];if(i&&(console.warn("Usage of ngModel is deprecated, please use bsActivePane instead!"),r.$activePaneChangeListeners.push(function(){i.$setViewValue(r.$panes.$active)}),i.$formatters.push(function(e){return r.$setActive(1*e),e})),n.bsActivePane){var s=a(n.bsActivePane);r.$activePaneChangeListeners.push(function(){s.assign(e,r.$panes.$active)}),e.$watch(n.bsActivePane,function(e){r.$setActive(1*e)},!0)}}}}]).directive("bsPane",["$window","$animate","$sce",function(e,t,n){return{require:["^?ngModel","^bsTabs"],scope:!0,link:function(e,a,o,i){function r(){var n=s.$panes.indexOf(e),o=s.$panes.$active;t[n===o?"addClass":"removeClass"](a,s.$options.activeClass)}var s=(i[0],i[1]);a.addClass("tab-pane"),o.$observe("title",function(t){e.title=n.trustAsHtml(t)}),s.$options.animation&&a.addClass(s.$options.animation),s.$push(e),e.$on("$destroy",function(){s.$remove(e)}),s.$activePaneChangeListeners.push(function(){r()}),r()}}}]),angular.module("mgcrea.ngStrap.popover",["mgcrea.ngStrap.tooltip"]).provider("$popover",function(){var e=this.defaults={animation:"am-fade",customClass:"",container:!1,target:!1,placement:"right",template:"popover/popover.tpl.html",contentTemplate:!1,trigger:"click",keyboard:!0,html:!1,title:"",content:"",delay:0,autoClose:!1};this.$get=["$tooltip",function(t){function n(n,a){var o=angular.extend({},e,a),i=t(n,o);return o.content&&(i.$scope.content=o.content),i}return n}]}).directive("bsPopover",["$window","$sce","$popover",function(e,t,n){var a=e.requestAnimationFrame||e.setTimeout;return{restrict:"EAC",scope:!0,link:function(e,o,i){var r={scope:e};angular.forEach(["template","contentTemplate","placement","container","target","delay","trigger","keyboard","html","animation","customClass","autoClose"],function(e){angular.isDefined(i[e])&&(r[e]=i[e])}),angular.forEach(["title","content"],function(n){i[n]&&i.$observe(n,function(o,i){e[n]=t.trustAsHtml(o),angular.isDefined(i)&&a(function(){s&&s.$applyPlacement()})})}),i.bsPopover&&e.$watch(i.bsPopover,function(t,n){angular.isObject(t)?angular.extend(e,t):e.content=t,angular.isDefined(n)&&a(function(){s&&s.$applyPlacement()})},!0),i.bsShow&&e.$watch(i.bsShow,function(e){s&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(popover),?/i)),e===!0?s.show():s.hide())});var s=n(o,r);e.$on("$destroy",function(){s&&s.destroy(),r=null,s=null})}}}]),angular.module("mgcrea.ngStrap.tooltip",["mgcrea.ngStrap.helpers.dimensions"]).provider("$tooltip",function(){var e=this.defaults={animation:"am-fade",customClass:"",prefixClass:"tooltip",prefixEvent:"tooltip",container:!1,target:!1,placement:"top",template:"tooltip/tooltip.tpl.html",contentTemplate:!1,trigger:"hover focus",keyboard:!1,html:!1,show:!1,title:"",type:"",delay:0,autoClose:!1,bsEnabled:!0};this.$get=["$window","$rootScope","$compile","$q","$templateCache","$http","$animate","$sce","dimensions","$$rAF","$timeout",function(n,a,o,i,r,s,l,u,c,d,f){function p(n,i){function r(){O.$emit(P.prefixEvent+".show",F)}function s(){return O.$emit(P.prefixEvent+".hide",F),U&&"focus"===P.trigger?n[0].blur():void A()}function p(){var e=P.trigger.split(" ");angular.forEach(e,function(e){"click"===e?n.on("click",F.toggle):"manual"!==e&&(n.on("hover"===e?"mouseenter":"focus",F.enter),n.on("hover"===e?"mouseleave":"blur",F.leave),"button"===V&&"hover"!==e&&n.on(v?"touchstart":"mousedown",F.$onFocusElementMouseDown))})}function b(){for(var e=P.trigger.split(" "),t=e.length;t--;){var a=e[t];"click"===a?n.off("click",F.toggle):"manual"!==a&&(n.off("hover"===a?"mouseenter":"focus",F.enter),n.off("hover"===a?"mouseleave":"blur",F.leave),"button"===V&&"hover"!==a&&n.off(v?"touchstart":"mousedown",F.$onFocusElementMouseDown))}}function D(){"focus"!==P.trigger?R.on("keyup",F.$onKeyUp):n.on("keyup",F.$onFocusKeyUp)}function k(){"focus"!==P.trigger?R.off("keyup",F.$onKeyUp):n.off("keyup",F.$onFocusKeyUp)}function T(){f(function(){R.on("click",x),w.on("click",F.hide),W=!0},0,!1)}function S(){W&&(R.off("click",x),w.off("click",F.hide),W=!1)}function x(e){e.stopPropagation()}function C(e){e=e||P.target||n;var t=e[0],a=t.getBoundingClientRect();null===a.width&&(a=angular.extend({},a,{width:a.right-a.left,height:a.bottom-a.top}));var o;return o="body"===P.container?c.offset(t):c.position(t),angular.extend({},a,o)}function M(e,t,n,a){var o,i=e.split("-");switch(i[0]){case"right":o={top:t.top+t.height/2-a/2,left:t.left+t.width};break;case"bottom":o={top:t.top+t.height,left:t.left+t.width/2-n/2};break;case"left":o={top:t.top+t.height/2-a/2,left:t.left-n};break;default:o={top:t.top-a,left:t.left+t.width/2-n/2}}if(!i[1])return o;if("top"===i[0]||"bottom"===i[0])switch(i[1]){case"left":o.left=t.left;break;case"right":o.left=t.left+t.width-n}else if("left"===i[0]||"right"===i[0])switch(i[1]){case"top":o.top=t.top-a;break;case"bottom":o.top=t.top+t.height}return o}function E(e,t){R.css({top:e+"px",left:t+"px"})}function A(){clearTimeout(H),F.$isShown&&null!==R&&(P.autoClose&&S(),P.keyboard&&k()),K&&(K.$destroy(),K=null),R&&(R.remove(),R=F.$element=null)}var F={},V=n[0].nodeName.toLowerCase(),P=F.$options=angular.extend({},e,i);F.$promise=$(P.template);var O=F.$scope=P.scope&&P.scope.$new()||a.$new();if(P.delay&&angular.isString(P.delay)){var I=P.delay.split(",").map(parseFloat);P.delay=I.length>1?{show:I[0],hide:I[1]}:I[0]}P.title&&(O.title=u.trustAsHtml(P.title)),O.$setEnabled=function(e){O.$$postDigest(function(){F.setEnabled(e)})},O.$hide=function(){O.$$postDigest(function(){F.hide()})},O.$show=function(){O.$$postDigest(function(){F.show()})},O.$toggle=function(){O.$$postDigest(function(){F.toggle()})},F.$isShown=O.$isShown=!1;var H,N;P.contentTemplate&&(F.$promise=F.$promise.then(function(e){var t=angular.element(e);return $(P.contentTemplate).then(function(e){var n=m('[ng-bind="content"]',t[0]);return n.length||(n=m('[ng-bind="title"]',t[0])),n.removeAttr("ng-bind").html(e),t[0].outerHTML})}));var L,R,q,Y,K;F.$promise.then(function(e){angular.isObject(e)&&(e=e.data),P.html&&(e=e.replace(y,'ng-bind-html="')),e=h.apply(e),q=e,L=o(e),F.init()}),F.init=function(){P.delay&&angular.isNumber(P.delay)&&(P.delay={show:P.delay,hide:P.delay}),"self"===P.container?Y=n:angular.isElement(P.container)?Y=P.container:P.container&&(Y=m(P.container)),p(),P.target&&(P.target=angular.isElement(P.target)?P.target:m(P.target)),P.show&&O.$$postDigest(function(){"focus"===P.trigger?n[0].focus():F.show()})},F.destroy=function(){b(),A(),O.$destroy()},F.enter=function(){return clearTimeout(H),N="in",P.delay&&P.delay.show?void(H=setTimeout(function(){"in"===N&&F.show()},P.delay.show)):F.show()},F.show=function(){if(P.bsEnabled&&!F.$isShown){O.$emit(P.prefixEvent+".show.before",F);var e,t;P.container?(e=Y,t=Y[0].lastChild?angular.element(Y[0].lastChild):null):(e=null,t=n),R&&A(),K=F.$scope.$new(),R=F.$element=L(K,function(){}),R.css({top:"-9999px",left:"-9999px",display:"block",visibility:"hidden"}),P.animation&&R.addClass(P.animation),P.type&&R.addClass(P.prefixClass+"-"+P.type),P.customClass&&R.addClass(P.customClass);var a=l.enter(R,e,t,r);a&&a.then&&a.then(r),F.$isShown=O.$isShown=!0,g(O),d(function(){F.$applyPlacement(),R&&R.css({visibility:"visible"})}),P.keyboard&&("focus"!==P.trigger&&F.focus(),D()),P.autoClose&&T()}},F.leave=function(){return clearTimeout(H),N="out",P.delay&&P.delay.hide?void(H=setTimeout(function(){"out"===N&&F.hide()},P.delay.hide)):F.hide()};var U;F.hide=function(e){if(F.$isShown){O.$emit(P.prefixEvent+".hide.before",F),U=e;var t=l.leave(R,s);t&&t.then&&t.then(s),F.$isShown=O.$isShown=!1,g(O),P.keyboard&&null!==R&&k(),P.autoClose&&null!==R&&S()}},F.toggle=function(){F.$isShown?F.leave():F.enter()},F.focus=function(){R[0].focus()},F.setEnabled=function(e){P.bsEnabled=e},F.$applyPlacement=function(){if(R){var a=P.placement,o=/\s?auto?\s?/i,i=o.test(a);i&&(a=a.replace(o,"")||e.placement),R.addClass(P.placement);var r=C(),s=R.prop("offsetWidth"),l=R.prop("offsetHeight");if(i){var u=a,c=P.container?angular.element(t.querySelector(P.container)):n.parent(),d=C(c);u.indexOf("bottom")>=0&&r.bottom+l>d.bottom?a=u.replace("bottom","top"):u.indexOf("top")>=0&&r.top-ld.width?a="right"===u?"left":a.replace("left","right"):("left"===u||"bottom-right"===u||"top-right"===u)&&r.left-st?t+12:t-12),n.$setViewValue(angular.copy(n.$dateValue)),n.$render()}},d.$build=function(){var e,t,n=g.midIndex=parseInt(p.length/2,10),a=[];for(e=0;e1*p.maxTime},g.$arrowAction=function(e,t){"picker"===p.arrowBehavior?d.$setTimeByStep(e,t):d.$moveIndex(e,t)},d.$setTimeByStep=function(e,t){{var n=new Date(d.$date),a=n.getHours(),o=($(n,b).length,n.getMinutes());$(n,k).length}0===t?n.setHours(a-parseInt(p.hourStep,10)*e):n.setMinutes(o-parseInt(p.minuteStep,10)*e),d.select(n,t,!0)},d.$moveIndex=function(e,t){var n;0===t?(n=new Date(1970,0,1,y.hour+e*p.length,y.minute),angular.extend(y,{hour:n.getHours()})):1===t&&(n=new Date(1970,0,1,y.hour,y.minute+e*p.length*p.minuteStep),angular.extend(y,{minute:n.getMinutes()})),d.$build()},d.$onMouseDown=function(e){if("input"!==e.target.nodeName.toLowerCase()&&e.preventDefault(),e.stopPropagation(),c){var t=angular.element(e.target);"button"!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler("click")}},d.$onKeyDown=function(e){if(/(38|37|39|40|13)/.test(e.keyCode)&&!e.shiftKey&&!e.altKey){if(e.preventDefault(),e.stopPropagation(),13===e.keyCode)return d.hide(!0);var t=new Date(d.$date),n=t.getHours(),a=$(t,b).length,i=t.getMinutes(),r=$(t,k).length,s=/(37|39)/.test(e.keyCode),l=2+1*T;s&&(37===e.keyCode?h=1>h?l-1:h-1:39===e.keyCode&&(h=l-1>h?h+1:0));var u=[0,a];0===h?(38===e.keyCode?t.setHours(n-parseInt(p.hourStep,10)):40===e.keyCode&&t.setHours(n+parseInt(p.hourStep,10)),a=$(t,b).length,u=[0,a]):1===h?(38===e.keyCode?t.setMinutes(i-parseInt(p.minuteStep,10)):40===e.keyCode&&t.setMinutes(i+parseInt(p.minuteStep,10)),r=$(t,k).length,u=[a+1,a+1+r]):2===h&&(s||d.switchMeridian(),u=[a+1+r+1,a+1+r+3]),d.select(t,h,!0),o(u[0],u[1]),f.$digest()}};var S=d.init;d.init=function(){return u&&p.useNative?(t.prop("type","time"),void t.css("-webkit-appearance","textfield")):(c&&(t.prop("type","text"),t.attr("readonly","true"),t.on("click",l)),void S())};var x=d.destroy;d.destroy=function(){u&&p.useNative&&t.off("click",l),x()};var C=d.show;d.show=function(){C(),s(function(){d.$element.on(c?"touchstart":"mousedown",d.$onMouseDown),p.keyboard&&t.on("keydown",d.$onKeyDown)},0,!1)};var M=d.hide;return d.hide=function(e){d.$isShown&&(d.$element.off(c?"touchstart":"mousedown",d.$onMouseDown),p.keyboard&&t.off("keydown",d.$onKeyDown),M(e))},d}var u=(angular.element(t.document.body),/(ip(a|o)d|iphone|android)/gi.test(t.navigator.userAgent)),c="createTouch"in t.document&&u;return e.lang||(e.lang=i.getDefaultLocale()),l.defaults=e,l}]}).directive("bsTimepicker",["$window","$parse","$q","$dateFormatter","$dateParser","$timepicker",function(e,t,n,a,o,i){{var r=i.defaults,s=/(ip(a|o)d|iphone|android)/gi.test(e.navigator.userAgent);e.requestAnimationFrame||e.setTimeout}return{restrict:"EAC",require:"ngModel",link:function(e,t,n,l){function u(e){if(angular.isDate(e)){var t=isNaN(d.minTime)||new Date(e.getTime()).setFullYear(1970,0,1)>=d.minTime,n=isNaN(d.maxTime)||new Date(e.getTime()).setFullYear(1970,0,1)<=d.maxTime,a=t&&n;l.$setValidity("date",a),l.$setValidity("min",t),l.$setValidity("max",n),a&&(l.$dateValue=e)}}function c(){return!l.$dateValue||isNaN(l.$dateValue.getTime())?"":g(l.$dateValue,d.timeFormat)
-}var d={scope:e,controller:l};angular.forEach(["placement","container","delay","trigger","keyboard","html","animation","template","autoclose","timeType","timeFormat","modelTimeFormat","useNative","hourStep","minuteStep","length","arrowBehavior","iconUp","iconDown"],function(e){angular.isDefined(n[e])&&(d[e]=n[e])}),n.bsShow&&e.$watch(n.bsShow,function(e){f&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(timepicker),?/i)),e===!0?f.show():f.hide())}),s&&(d.useNative||r.useNative)&&(d.timeFormat="HH:mm");var f=i(t,l,d);d=f.$options;var p=d.lang,g=function(e,t){return a.formatDate(e,t,p)},m=o({format:d.timeFormat,lang:p});angular.forEach(["minTime","maxTime"],function(e){angular.isDefined(n[e])&&n.$observe(e,function(t){f.$options[e]=m.getTimeForAttribute(e,t),!isNaN(f.$options[e])&&f.$build(),u(l.$dateValue)})}),e.$watch(n.ngModel,function(){f.update(l.$dateValue)},!0),l.$parsers.unshift(function(e){if(!e)return l.$setValidity("date",!0),null;var t=angular.isDate(e)?e:m.parse(e,l.$dateValue);return!t||isNaN(t.getTime())?void l.$setValidity("date",!1):(u(t),"string"===d.timeType?g(t,d.modelTimeFormat||d.timeFormat):"number"===d.timeType?l.$dateValue.getTime():"unix"===d.timeType?l.$dateValue.getTime()/1e3:"iso"===d.timeType?l.$dateValue.toISOString():new Date(l.$dateValue))}),l.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:"string"===d.timeType?m.parse(e,null,d.modelTimeFormat):new Date("unix"===d.timeType?1e3*e:e),l.$dateValue=t,c()}),l.$render=function(){t.val(c())},e.$on("$destroy",function(){f&&f.destroy(),d=null,f=null})}}}]),angular.module("mgcrea.ngStrap.typeahead",["mgcrea.ngStrap.tooltip","mgcrea.ngStrap.helpers.parseOptions"]).provider("$typeahead",function(){var e=this.defaults={animation:"am-fade",prefixClass:"typeahead",prefixEvent:"$typeahead",placement:"bottom-left",template:"typeahead/typeahead.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,minLength:1,filter:"filter",limit:6,comparator:""};this.$get=["$window","$rootScope","$tooltip","$timeout",function(t,n,a,o){function i(t,n,i){var r={},s=angular.extend({},e,i);r=a(t,s);var l=i.scope,u=r.$scope;u.$resetMatches=function(){u.$matches=[],u.$activeIndex=0},u.$resetMatches(),u.$activate=function(e){u.$$postDigest(function(){r.activate(e)})},u.$select=function(e){u.$$postDigest(function(){r.select(e)})},u.$isVisible=function(){return r.$isVisible()},r.update=function(e){u.$matches=e,u.$activeIndex>=e.length&&(u.$activeIndex=0)},r.activate=function(e){u.$activeIndex=e},r.select=function(e){var t=u.$matches[e].value;n.$setViewValue(t),n.$render(),u.$resetMatches(),l&&l.$digest(),u.$emit(s.prefixEvent+".select",t,e)},r.$isVisible=function(){return s.minLength&&n?u.$matches.length&&angular.isString(n.$viewValue)&&n.$viewValue.length>=s.minLength:!!u.$matches.length},r.$getIndex=function(e){var t=u.$matches.length,n=t;if(t){for(n=t;n--&&u.$matches[n].value!==e;);if(!(0>n))return n}},r.$onMouseDown=function(e){e.preventDefault(),e.stopPropagation()},r.$onKeyDown=function(e){/(38|40|13)/.test(e.keyCode)&&(r.$isVisible()&&(e.preventDefault(),e.stopPropagation()),13===e.keyCode&&u.$matches.length?r.select(u.$activeIndex):38===e.keyCode&&u.$activeIndex>0?u.$activeIndex--:40===e.keyCode&&u.$activeIndex0)return void s.$setViewValue(s.$viewValue.substring(0,s.$viewValue.length-1));e.length>c&&(e=e.slice(0,c));var n=g.$isVisible();n&&g.update(e),(1!==e.length||e[0].value!==t)&&(!n&&g.update(e),s.$render())})}),s.$formatters.push(function(e){var t=p.displayValue(e);return t===n?"":t}),s.$render=function(){if(s.$isEmpty(s.$viewValue))return t.val("");var e=g.$getIndex(s.$modelValue),n=angular.isDefined(e)?g.$scope.$matches[e].label:s.$viewValue;n=angular.isObject(n)?p.displayValue(n):n,t.val(n?n.toString().replace(/<(?:.|\n)*?>/gm,"").trim():"")},e.$on("$destroy",function(){g&&g.destroy(),l=null,g=null})}}}])}(window,document);
+!function(e,t,n){"use strict";angular.module("mgcrea.ngStrap",["mgcrea.ngStrap.modal","mgcrea.ngStrap.aside","mgcrea.ngStrap.alert","mgcrea.ngStrap.button","mgcrea.ngStrap.select","mgcrea.ngStrap.datepicker","mgcrea.ngStrap.timepicker","mgcrea.ngStrap.navbar","mgcrea.ngStrap.tooltip","mgcrea.ngStrap.popover","mgcrea.ngStrap.dropdown","mgcrea.ngStrap.typeahead","mgcrea.ngStrap.scrollspy","mgcrea.ngStrap.affix","mgcrea.ngStrap.tab","mgcrea.ngStrap.collapse","mgcrea.ngStrap.progressbar"]),angular.module("mgcrea.ngStrap.affix",["mgcrea.ngStrap.helpers.dimensions","mgcrea.ngStrap.helpers.debounce"]).provider("$affix",function(){var e=this.defaults={offsetTop:"auto"};this.$get=["$window","debounce","dimensions",function(t,n,a){function o(o,s){function l(e,t,n){var a=u(),o=c();return v>=a?"top":null!==e&&a+e<=t.top?"middle":null!==y&&t.top+n+$>=o-y?"bottom":"middle"}function u(){return p[0]===t?t.pageYOffset:p[0].scrollTop}function c(){return p[0]===t?t.document.body.scrollHeight:p[0].scrollHeight}var d={},f=angular.extend({},e,s),p=f.target,g="affix affix-top affix-bottom",m=!1,$=0,h=0,v=0,y=0,w=null,b=null,D=o.parent();if(f.offsetParent)if(f.offsetParent.match(/^\d+$/))for(var k=0;k<1*f.offsetParent-1;k++)D=D.parent();else D=angular.element(f.offsetParent);return d.init=function(){this.$parseOffsets(),h=a.offset(o[0]).top+$,m=!o[0].style.width,p.on("scroll",this.checkPosition),p.on("click",this.checkPositionWithEventLoop),r.on("resize",this.$debouncedOnResize),this.checkPosition(),this.checkPositionWithEventLoop()},d.destroy=function(){p.off("scroll",this.checkPosition),p.off("click",this.checkPositionWithEventLoop),r.off("resize",this.$debouncedOnResize)},d.checkPositionWithEventLoop=function(){setTimeout(d.checkPosition,1)},d.checkPosition=function(){var e=u(),t=a.offset(o[0]),n=a.height(o[0]),r=l(b,t,n);w!==r&&(w=r,o.removeClass(g).addClass("affix"+("middle"!==r?"-"+r:"")),"top"===r?(b=null,o.css("position",f.offsetParent?"":"relative"),m&&o.css("width",""),o.css("top","")):"bottom"===r?(b=f.offsetUnpin?-(1*f.offsetUnpin):t.top-e,m&&o.css("width",""),o.css("position",f.offsetParent?"":"relative"),o.css("top",f.offsetParent?"":i[0].offsetHeight-y-n-h+"px")):(b=null,m&&o.css("width",o[0].offsetWidth+"px"),o.css("position","fixed"),o.css("top",$+"px")))},d.$onResize=function(){d.$parseOffsets(),d.checkPosition()},d.$debouncedOnResize=n(d.$onResize,50),d.$parseOffsets=function(){var e=o.css("position");o.css("position",f.offsetParent?"":"relative"),f.offsetTop&&("auto"===f.offsetTop&&(f.offsetTop="+0"),f.offsetTop.match(/^[-+]\d+$/)?($=1*-f.offsetTop,v=f.offsetParent?a.offset(D[0]).top+1*f.offsetTop:a.offset(o[0]).top-a.css(o[0],"marginTop",!0)+1*f.offsetTop):v=1*f.offsetTop),f.offsetBottom&&(y=f.offsetParent&&f.offsetBottom.match(/^[-+]\d+$/)?c()-(a.offset(D[0]).top+a.height(D[0]))+1*f.offsetBottom+1:1*f.offsetBottom),o.css("position",e)},d.init(),d}var i=angular.element(t.document.body),r=angular.element(t);return o}]}).directive("bsAffix",["$affix","$window",function(e,t){return{restrict:"EAC",require:"^?bsAffixTarget",link:function(n,a,o,i){var r={scope:n,offsetTop:"auto",target:i?i.$element:angular.element(t)};angular.forEach(["offsetTop","offsetBottom","offsetParent","offsetUnpin"],function(e){angular.isDefined(o[e])&&(r[e]=o[e])});var s=e(a,r);n.$on("$destroy",function(){s&&s.destroy(),r=null,s=null})}}}]).directive("bsAffixTarget",function(){return{controller:["$element",function(e){this.$element=e}]}}),angular.module("mgcrea.ngStrap.alert",["mgcrea.ngStrap.modal"]).provider("$alert",function(){var e=this.defaults={animation:"am-fade",prefixClass:"alert",prefixEvent:"alert",placement:null,template:"alert/alert.tpl.html",container:!1,element:null,backdrop:!1,keyboard:!0,show:!0,duration:!1,type:!1,dismissable:!0};this.$get=["$modal","$timeout",function(t,n){function a(a){var o={},i=angular.extend({},e,a);o=t(i),o.$scope.dismissable=!!i.dismissable,i.type&&(o.$scope.type=i.type);var r=o.show;return i.duration&&(o.show=function(){r(),n(function(){o.hide()},1e3*i.duration)}),o}return a}]}).directive("bsAlert",["$window","$sce","$alert",function(e,t,n){e.requestAnimationFrame||e.setTimeout;return{restrict:"EAC",scope:!0,link:function(e,a,o){var i={scope:e,element:a,show:!1};angular.forEach(["template","placement","keyboard","html","container","animation","duration","dismissable"],function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),angular.forEach(["title","content","type"],function(n){o[n]&&o.$observe(n,function(a){e[n]=t.trustAsHtml(a)})}),o.bsAlert&&e.$watch(o.bsAlert,function(t){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var r=n(i);a.on(o.trigger||"click",r.toggle),e.$on("$destroy",function(){r&&r.destroy(),i=null,r=null})}}}]),angular.module("mgcrea.ngStrap.aside",["mgcrea.ngStrap.modal"]).provider("$aside",function(){var e=this.defaults={animation:"am-fade-and-slide-right",prefixClass:"aside",prefixEvent:"aside",placement:"right",template:"aside/aside.tpl.html",contentTemplate:!1,container:!1,element:null,backdrop:!0,keyboard:!0,html:!1,show:!0};this.$get=["$modal",function(t){function n(n){var a={},o=angular.extend({},e,n);return a=t(o)}return n}]}).directive("bsAside",["$window","$sce","$aside",function(e,t,n){e.requestAnimationFrame||e.setTimeout;return{restrict:"EAC",scope:!0,link:function(e,a,o){var i={scope:e,element:a,show:!1};angular.forEach(["template","contentTemplate","placement","backdrop","keyboard","html","container","animation"],function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),angular.forEach(["title","content"],function(n){o[n]&&o.$observe(n,function(a){e[n]=t.trustAsHtml(a)})}),o.bsAside&&e.$watch(o.bsAside,function(t){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var r=n(i);a.on(o.trigger||"click",r.toggle),e.$on("$destroy",function(){r&&r.destroy(),i=null,r=null})}}}]),angular.module("mgcrea.ngStrap.button",[]).provider("$button",function(){var e=this.defaults={activeClass:"active",toggleEvent:"click"};this.$get=function(){return{defaults:e}}}).directive("bsCheckboxGroup",function(){return{restrict:"A",require:"ngModel",compile:function(e,t){e.attr("data-toggle","buttons"),e.removeAttr("ng-model");var n=e[0].querySelectorAll('input[type="checkbox"]');angular.forEach(n,function(e){var n=angular.element(e);n.attr("bs-checkbox",""),n.attr("ng-model",t.ngModel+"."+n.attr("value"))})}}}).directive("bsCheckbox",["$button","$$rAF",function(e,t){var n=e.defaults,a=/^(true|false|\d+)$/;return{restrict:"A",require:"ngModel",link:function(e,o,i,r){var s=n,l="INPUT"===o[0].nodeName,u=l?o.parent():o,c=angular.isDefined(i.trueValue)?i.trueValue:!0;a.test(i.trueValue)&&(c=e.$eval(i.trueValue));var d=angular.isDefined(i.falseValue)?i.falseValue:!1;a.test(i.falseValue)&&(d=e.$eval(i.falseValue));var f="boolean"!=typeof c||"boolean"!=typeof d;f&&(r.$parsers.push(function(e){return e?c:d}),r.$formatters.push(function(e){return angular.equals(e,c)}),e.$watch(i.ngModel,function(){r.$render()})),r.$render=function(){var e=angular.equals(r.$modelValue,c);t(function(){l&&(o[0].checked=e),u.toggleClass(s.activeClass,e)})},o.bind(s.toggleEvent,function(){e.$apply(function(){l||r.$setViewValue(!u.hasClass("active")),f||r.$render()})})}}}]).directive("bsRadioGroup",function(){return{restrict:"A",require:"ngModel",compile:function(e,t){e.attr("data-toggle","buttons"),e.removeAttr("ng-model");var n=e[0].querySelectorAll('input[type="radio"]');angular.forEach(n,function(e){angular.element(e).attr("bs-radio",""),angular.element(e).attr("ng-model",t.ngModel)})}}}).directive("bsRadio",["$button","$$rAF",function(e,t){var n=e.defaults,a=/^(true|false|\d+)$/;return{restrict:"A",require:"ngModel",link:function(e,o,i,r){var s=n,l="INPUT"===o[0].nodeName,u=l?o.parent():o,c=a.test(i.value)?e.$eval(i.value):i.value;r.$render=function(){var e=angular.equals(r.$modelValue,c);t(function(){l&&(o[0].checked=e),u.toggleClass(s.activeClass,e)})},o.bind(s.toggleEvent,function(){e.$apply(function(){r.$setViewValue(c),r.$render()})})}}}]),angular.module("mgcrea.ngStrap.collapse",[]).provider("$collapse",function(){var e=this.defaults={animation:"am-collapse",disallowToggle:!1,activeClass:"in",startCollapsed:!1,allowMultiple:!1},t=this.controller=function(t,n,a){function o(e){for(var t=l.$targets.$active,n=0;nt;t++)angular.forEach(g.rows[t],u.$setDisabledEl)},u.select=function(e,t){angular.isDate(n.$dateValue)||(n.$dateValue=new Date(e)),!g.$mode||t?(n.$setViewValue(angular.copy(e)),n.$render(),p.autoclose&&!t&&l(function(){u.hide(!0)})):(angular.extend($,{year:e.getFullYear(),month:e.getMonth(),date:e.getDate()}),u.setMode(g.$mode-1),u.$build())},u.setMode=function(e){g.$mode=e,h=u.$views[g.$mode],u.$build()},u.$build=function(e){e===!0&&h.built||(e!==!1||h.built)&&h.build.call(h)},u.$updateSelected=function(){for(var e=0,t=g.rows.length;t>e;e++)angular.forEach(g.rows[e],o)},u.$isSelected=function(e){return h.isSelected(e)},u.$setDisabledEl=function(e){e.disabled=h.isDisabled(e.date)},u.$selectPane=function(e){var t=h.steps,n=new Date(Date.UTC($.year+(t.year||0)*e,$.month+(t.month||0)*e,1));angular.extend($,{year:n.getUTCFullYear(),month:n.getUTCMonth(),date:n.getUTCDate()}),u.$build()},u.$onMouseDown=function(e){if(e.preventDefault(),e.stopPropagation(),d){var t=angular.element(e.target);"button"!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler("click")}},u.$onKeyDown=function(e){if(/(38|37|39|40|13)/.test(e.keyCode)&&!e.shiftKey&&!e.altKey){if(e.preventDefault(),e.stopPropagation(),13===e.keyCode)return g.$mode?g.$apply(function(){u.setMode(g.$mode-1)}):u.hide(!0);h.onKeyDown(e),f.$digest()}};var v=u.init;u.init=function(){return c&&p.useNative?(t.prop("type","date"),void t.css("-webkit-appearance","textfield")):(d&&(t.prop("type","text"),t.attr("readonly","true"),t.on("click",i)),void v())};var y=u.destroy;u.destroy=function(){c&&p.useNative&&t.off("click",i),y()};var w=u.show;u.show=function(){w(),l(function(){u.$element.on(d?"touchstart":"mousedown",u.$onMouseDown),p.keyboard&&t.on("keydown",u.$onKeyDown)},0,!1)};var b=u.hide;return u.hide=function(e){u.$isShown&&(u.$element.off(d?"touchstart":"mousedown",u.$onMouseDown),p.keyboard&&t.off("keydown",u.$onKeyDown),b(e))},u}var c=(angular.element(t.document.body),/(ip(a|o)d|iphone|android)/gi.test(t.navigator.userAgent)),d="createTouch"in t.document&&c;return e.lang||(e.lang=i.getDefaultLocale()),u.defaults=e,u}]}).directive("bsDatepicker",["$window","$parse","$q","$dateFormatter","$dateParser","$datepicker",function(e,t,n,a,o,i){var r=(i.defaults,/(ip(a|o)d|iphone|android)/gi.test(e.navigator.userAgent));return{restrict:"EAC",require:"ngModel",link:function(e,t,n,s){function l(e){return e&&e.length?e:null}function u(e){if(angular.isDate(e)){var t=isNaN(f.$options.minDate)||e.getTime()>=f.$options.minDate,n=isNaN(f.$options.maxDate)||e.getTime()<=f.$options.maxDate,a=t&&n;s.$setValidity("date",a),s.$setValidity("min",t),s.$setValidity("max",n),a&&(s.$dateValue=e)}}function c(){return!s.$dateValue||isNaN(s.$dateValue.getTime())?"":g(s.$dateValue,d.dateFormat)}var d={scope:e,controller:s};angular.forEach(["placement","container","delay","trigger","keyboard","html","animation","template","autoclose","dateType","dateFormat","modelDateFormat","dayFormat","strictFormat","startWeek","startDate","useNative","lang","startView","minView","iconLeft","iconRight","daysOfWeekDisabled"],function(e){angular.isDefined(n[e])&&(d[e]=n[e])}),n.bsShow&&e.$watch(n.bsShow,function(e){f&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(datepicker),?/i)),e===!0?f.show():f.hide())});var f=i(t,s,d);d=f.$options,r&&d.useNative&&(d.dateFormat="yyyy-MM-dd");var p=d.lang,g=function(e,t){return a.formatDate(e,t,p)},m=o({format:d.dateFormat,lang:p,strict:d.strictFormat});angular.forEach(["minDate","maxDate"],function(e){angular.isDefined(n[e])&&n.$observe(e,function(t){f.$options[e]=m.getDateForAttribute(e,t),!isNaN(f.$options[e])&&f.$build(!1),u(s.$dateValue)})}),e.$watch(n.ngModel,function(){f.update(s.$dateValue)},!0),angular.isDefined(n.disabledDates)&&e.$watch(n.disabledDates,function(e,t){e=l(e),t=l(t),e&&f.updateDisabledDates(e)}),s.$parsers.unshift(function(e){if(!e)return s.$setValidity("date",!0),null;var t=m.parse(e,s.$dateValue);return!t||isNaN(t.getTime())?void s.$setValidity("date",!1):(u(t),"string"===d.dateType?g(t,d.modelDateFormat||d.dateFormat):"number"===d.dateType?s.$dateValue.getTime():"unix"===d.dateType?s.$dateValue.getTime()/1e3:"iso"===d.dateType?s.$dateValue.toISOString():new Date(s.$dateValue))}),s.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:"string"===d.dateType?m.parse(e,null,d.modelDateFormat):new Date("unix"===d.dateType?1e3*e:e),s.$dateValue=t,c()}),s.$render=function(){t.val(c())},e.$on("$destroy",function(){f&&f.destroy(),d=null,f=null})}}}]).provider("datepickerViews",function(){function e(e,t){for(var n=[];e.length>0;)n.push(e.splice(0,t));return n}function t(e,t){return(e%t+t)%t}this.defaults={dayFormat:"dd",daySplit:7};this.$get=["$dateFormatter","$dateParser","$sce",function(n,a,o){return function(i){var r=i.$scope,s=i.$options,l=s.lang,u=function(e,t){return n.formatDate(e,t,l)},c=a({format:s.dateFormat,lang:l,strict:s.strictFormat}),d=n.weekdaysShort(l),f=d.slice(s.startWeek).concat(d.slice(0,s.startWeek)),p=o.trustAsHtml(''+f.join(' ')+" "),g=i.$date||(s.startDate?c.getDateForAttribute("startDate",s.startDate):new Date),m={year:g.getFullYear(),month:g.getMonth(),date:g.getDate()},$=(6e4*g.getTimezoneOffset(),[{format:s.dayFormat,split:7,steps:{month:1},update:function(e,t){!this.built||t||e.getFullYear()!==m.year||e.getMonth()!==m.month?(angular.extend(m,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$build()):e.getDate()!==m.date&&(m.date=i.$date.getDate(),i.$updateSelected())},build:function(){var n=new Date(m.year,m.month,1),a=n.getTimezoneOffset(),o=new Date(+n-864e5*t(n.getDay()-s.startWeek,7)),l=o.getTimezoneOffset(),d=(new Date).toDateString();l!==a&&(o=new Date(+o+6e4*(l-a)));for(var f,g=[],$=0;42>$;$++)f=c.daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth(),o.getDate()+$)),g.push({date:f,isToday:f.toDateString()===d,label:u(f,this.format),selected:i.$date&&this.isSelected(f),muted:f.getMonth()!==m.month,disabled:this.isDisabled(f)});r.title=u(n,s.monthTitleFormat),r.showLabels=!0,r.labels=p,r.rows=e(g,this.split),this.built=!0},isSelected:function(e){return i.$date&&e.getFullYear()===i.$date.getFullYear()&&e.getMonth()===i.$date.getMonth()&&e.getDate()===i.$date.getDate()},isDisabled:function(e){var t=e.getTime();if(ts.maxDate)return!0;if(-1!==s.daysOfWeekDisabled.indexOf(e.getDay()))return!0;if(s.disabledDateRanges)for(var n=0;n=s.disabledDateRanges[n].start&&t<=s.disabledDateRanges[n].end)return!0;return!1},onKeyDown:function(e){if(i.$date){var t,n=i.$date.getTime();37===e.keyCode?t=new Date(n-864e5):38===e.keyCode?t=new Date(n-6048e5):39===e.keyCode?t=new Date(n+864e5):40===e.keyCode&&(t=new Date(n+6048e5)),this.isDisabled(t)||i.select(t,!0)}}},{name:"month",format:s.monthFormat,split:4,steps:{year:1},update:function(e){this.built&&e.getFullYear()===m.year?e.getMonth()!==m.month&&(angular.extend(m,{month:i.$date.getMonth(),date:i.$date.getDate()}),i.$updateSelected()):(angular.extend(m,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$build())},build:function(){for(var t,n=(new Date(m.year,0,1),[]),a=0;12>a;a++)t=new Date(m.year,a,1),n.push({date:t,label:u(t,this.format),selected:i.$isSelected(t),disabled:this.isDisabled(t)});r.title=u(t,s.yearTitleFormat),r.showLabels=!1,r.rows=e(n,this.split),this.built=!0},isSelected:function(e){return i.$date&&e.getFullYear()===i.$date.getFullYear()&&e.getMonth()===i.$date.getMonth()},isDisabled:function(e){var t=+new Date(e.getFullYear(),e.getMonth()+1,0);return ts.maxDate},onKeyDown:function(e){if(i.$date){var t=i.$date.getMonth(),n=new Date(i.$date);37===e.keyCode?n.setMonth(t-1):38===e.keyCode?n.setMonth(t-4):39===e.keyCode?n.setMonth(t+1):40===e.keyCode&&n.setMonth(t+4),this.isDisabled(n)||i.select(n,!0)}}},{name:"year",format:s.yearFormat,split:4,steps:{year:12},update:function(e,t){!this.built||t||parseInt(e.getFullYear()/20,10)!==parseInt(m.year/20,10)?(angular.extend(m,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$build()):e.getFullYear()!==m.year&&(angular.extend(m,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$updateSelected())},build:function(){for(var t,n=m.year-m.year%(3*this.split),a=[],o=0;12>o;o++)t=new Date(n+o,0,1),a.push({date:t,label:u(t,this.format),selected:i.$isSelected(t),disabled:this.isDisabled(t)});r.title=a[0].label+"-"+a[a.length-1].label,r.showLabels=!1,r.rows=e(a,this.split),this.built=!0},isSelected:function(e){return i.$date&&e.getFullYear()===i.$date.getFullYear()},isDisabled:function(e){var t=+new Date(e.getFullYear()+1,0,0);return ts.maxDate},onKeyDown:function(e){if(i.$date){var t=i.$date.getFullYear(),n=new Date(i.$date);37===e.keyCode?n.setYear(t-1):38===e.keyCode?n.setYear(t-4):39===e.keyCode?n.setYear(t+1):40===e.keyCode&&n.setYear(t+4),this.isDisabled(n)||i.select(n,!0)}}}]);return{views:s.minView?Array.prototype.slice.call($,s.minView):$,viewDate:m}}}]}),angular.module("mgcrea.ngStrap.dropdown",["mgcrea.ngStrap.tooltip"]).provider("$dropdown",function(){var e=this.defaults={animation:"am-fade",prefixClass:"dropdown",placement:"bottom-left",template:"dropdown/dropdown.tpl.html",trigger:"click",container:!1,keyboard:!0,html:!1,delay:0};this.$get=["$window","$rootScope","$tooltip","$timeout",function(t,n,a,o){function i(t,i){function l(e){return e.target!==t[0]?e.target!==t[0]&&u.hide():void 0}{var u={},c=angular.extend({},e,i);u.$scope=c.scope&&c.scope.$new()||n.$new()}u=a(t,c);var d=t.parent();u.$onKeyDown=function(e){if(/(38|40)/.test(e.keyCode)){e.preventDefault(),e.stopPropagation();var t=angular.element(u.$element[0].querySelectorAll("li:not(.divider) a"));if(t.length){var n;angular.forEach(t,function(e,t){s&&s.call(e,":focus")&&(n=t)}),38===e.keyCode&&n>0?n--:40===e.keyCode&&n ');return u.$promise.then(function(e){angular.isObject(e)&&(e=e.data),d.html&&(e=e.replace(y,'ng-bind-html="')),e=$.apply(e),b=o(e),u.init()}),u.init=function(){d.show&&w.$$postDigest(function(){u.show()})},u.destroy=function(){D&&(D.remove(),D=null),k&&(k.remove(),k=null),w.$destroy()},u.show=function(){if(!u.$isShown&&!w.$emit(d.prefixEvent+".show.before",u).defaultPrevented){var e,t;angular.isElement(d.container)?(e=d.container,t=d.container[0].lastChild?angular.element(d.container[0].lastChild):null):d.container?(e=p(d.container),t=e[0].lastChild?angular.element(e[0].lastChild):null):(e=null,t=d.element),D=u.$element=b(w,function(){}),D.css({display:"block"}).addClass(d.placement),d.animation&&(d.backdrop&&k.addClass(d.backdropAnimation),D.addClass(d.animation)),d.backdrop&&l.enter(k,v,null);var a=l.enter(D,e,t,n);a&&a.then&&a.then(n),u.$isShown=w.$isShown=!0,f(w);var o=D[0];h(function(){o.focus()}),v.addClass(d.prefixClass+"-open"),d.animation&&v.addClass(d.prefixClass+"-with-"+d.animation),d.backdrop&&(D.on("click",r),k.on("click",r),k.on("wheel",s)),d.keyboard&&D.on("keyup",u.$onKeyUp)}},u.hide=function(){if(u.$isShown&&!w.$emit(d.prefixEvent+".hide.before",u).defaultPrevented){var e=l.leave(D,i);e&&e.then&&e.then(i),d.backdrop&&l.leave(k),u.$isShown=w.$isShown=!1,f(w),d.backdrop&&(D.off("click",r),k.off("click",r),k.off("wheel",s)),d.keyboard&&D.off("keyup",u.$onKeyUp)}},u.toggle=function(){u.$isShown?u.hide():u.show()},u.focus=function(){D[0].focus()},u.$onKeyUp=function(e){27===e.which&&u.$isShown&&(u.hide(),e.stopPropagation())},u}function f(e){e.$$phase||e.$root&&e.$root.$$phase||e.$digest()}function p(e,n){return angular.element((n||t).querySelectorAll(e))}function g(e){return w[e]?w[e]:w[e]=i.when(r.get(e)||s.get(e)).then(function(t){return angular.isObject(t)?(r.put(e,t.data),t.data):t})}var m=angular.forEach,$=String.prototype.trim,h=n.requestAnimationFrame||n.setTimeout,v=angular.element(n.document.body),y=/ng-bind="/gi,w={};return d}]}).directive("bsModal",["$window","$sce","$modal",function(e,t,n){return{restrict:"EAC",scope:!0,link:function(e,a,o){var i={scope:e,element:a,show:!1};angular.forEach(["template","contentTemplate","placement","backdrop","keyboard","html","container","animation"],function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),angular.forEach(["title","content"],function(n){o[n]&&o.$observe(n,function(a){e[n]=t.trustAsHtml(a)})}),o.bsModal&&e.$watch(o.bsModal,function(t){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var r=n(i);a.on(o.trigger||"click",r.toggle),e.$on("$destroy",function(){r&&r.destroy(),i=null,r=null})}}}]),angular.module("mgcrea.ngStrap.helpers.dateFormatter",[]).service("$dateFormatter",["$locale","dateFilter",function(e,t){function n(e){return/(h+)([:\.])?(m+)[ ]?(a?)/i.exec(e).slice(1)}this.getDefaultLocale=function(){return e.id},this.getDatetimeFormat=function(t){return e.DATETIME_FORMATS[t]||t},this.weekdaysShort=function(){return e.DATETIME_FORMATS.SHORTDAY},this.hoursFormat=function(e){return n(e)[0]},this.minutesFormat=function(e){return n(e)[2]},this.timeSeparator=function(e){return n(e)[1]},this.showAM=function(e){return!!n(e)[3]},this.formatDate=function(e,n){return t(e,n)}}]),angular.module("mgcrea.ngStrap.helpers.dateParser",[]).provider("$dateParser",["$localeProvider",function(){function e(){this.year=1970,this.month=0,this.day=1,this.hours=0,this.minutes=0,this.seconds=0,this.milliseconds=0}function t(){}function n(e){return!isNaN(parseFloat(e))&&isFinite(e)}function a(e,t){for(var n=e.length,a=t.toString().toLowerCase(),o=0;n>o;o++)if(e[o].toLowerCase()===a)return o;return-1}e.prototype.setMilliseconds=function(e){this.milliseconds=e},e.prototype.setSeconds=function(e){this.seconds=e},e.prototype.setMinutes=function(e){this.minutes=e},e.prototype.setHours=function(e){this.hours=e},e.prototype.getHours=function(){return this.hours},e.prototype.setDate=function(e){this.day=e},e.prototype.setMonth=function(e){this.month=e},e.prototype.setFullYear=function(e){this.year=e},e.prototype.fromDate=function(e){return this.year=e.getFullYear(),this.month=e.getMonth(),this.day=e.getDate(),this.hours=e.getHours(),this.minutes=e.getMinutes(),this.seconds=e.getSeconds(),this.milliseconds=e.getMilliseconds(),this},e.prototype.toDate=function(){return new Date(this.year,this.month,this.day,this.hours,this.minutes,this.seconds,this.milliseconds)};var o=e.prototype,i=this.defaults={format:"shortDate",strict:!1};this.$get=["$locale","dateFilter",function(r,s){var l=function(l){function u(e){var t,n=Object.keys(h),a=[],o=[],i=e;for(t=0;t1){var r=i.search(n[t]);e=e.split(n[t]).join(""),h[n[t]]&&(a[r]=h[n[t]])}return angular.forEach(a,function(e){e&&o.push(e)}),o}function c(e){return e.replace(/\//g,"[\\/]").replace("/-/g","[-]").replace(/\./g,"[.]").replace(/\\s/g,"[\\s]")}function d(e){var t,n=Object.keys($),a=e;for(t=0;t12?e.getHours()+2:0),e):null},m.init(),m};return l}]}]),angular.module("mgcrea.ngStrap.helpers.debounce",[]).factory("debounce",["$timeout",function(e){return function(t,n,a){var o=null;return function(){var i=this,r=arguments,s=a&&!o;return o&&e.cancel(o),o=e(function(){o=null,a||t.apply(i,r)},n,!1),s&&t.apply(i,r),o}}}]).factory("throttle",["$timeout",function(e){return function(t,n,a){var o=null;return a||(a={}),function(){var i=this,r=arguments;o||(a.leading!==!1&&t.apply(i,r),o=e(function(){o=null,a.trailing!==!1&&t.apply(i,r)},n,!1))}}}]),angular.module("mgcrea.ngStrap.helpers.dimensions",[]).factory("dimensions",["$document","$window",function(){var t=(angular.element,{}),n=t.nodeName=function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()};t.css=function(t,n,a){var o;return o=t.currentStyle?t.currentStyle[n]:e.getComputedStyle?e.getComputedStyle(t)[n]:t.style[n],a===!0?parseFloat(o)||0:o},t.offset=function(t){var n=t.getBoundingClientRect(),a=t.ownerDocument;return{width:n.width||t.offsetWidth,height:n.height||t.offsetHeight,top:n.top+(e.pageYOffset||a.documentElement.scrollTop)-(a.documentElement.clientTop||0),left:n.left+(e.pageXOffset||a.documentElement.scrollLeft)-(a.documentElement.clientLeft||0)}},t.position=function(e){var o,i,r={top:0,left:0};return"fixed"===t.css(e,"position")?i=e.getBoundingClientRect():(o=a(e),i=t.offset(e),n(o,"html")||(r=t.offset(o)),r.top+=t.css(o,"borderTopWidth",!0),r.left+=t.css(o,"borderLeftWidth",!0)),{width:e.offsetWidth,height:e.offsetHeight,top:i.top-r.top-t.css(e,"marginTop",!0),left:i.left-r.left-t.css(e,"marginLeft",!0)}};var a=function(e){var a=e.ownerDocument,o=e.offsetParent||a;if(n(o,"#document"))return a.documentElement;for(;o&&!n(o,"html")&&"static"===t.css(o,"position");)o=o.offsetParent;return o||a.documentElement};return t.height=function(e,n){var a=e.offsetHeight;return n?a+=t.css(e,"marginTop",!0)+t.css(e,"marginBottom",!0):a-=t.css(e,"paddingTop",!0)+t.css(e,"paddingBottom",!0)+t.css(e,"borderTopWidth",!0)+t.css(e,"borderBottomWidth",!0),a},t.width=function(e,n){var a=e.offsetWidth;return n?a+=t.css(e,"marginLeft",!0)+t.css(e,"marginRight",!0):a-=t.css(e,"paddingLeft",!0)+t.css(e,"paddingRight",!0)+t.css(e,"borderLeftWidth",!0)+t.css(e,"borderRightWidth",!0),a},t}]),angular.module("mgcrea.ngStrap.helpers.parseOptions",[]).provider("$parseOptions",function(){var e=this.defaults={regexp:/^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/};this.$get=["$parse","$q",function(t,n){function a(a,o){function i(e,t){return e.map(function(e,n){var a,o,i={};return i[c]=e,a=u(t,i),o=p(t,i),{label:a,value:o,index:n}})}var r={},s=angular.extend({},e,o);r.$values=[];var l,u,c,d,f,p,g;return r.init=function(){r.$match=l=a.match(s.regexp),u=t(l[2]||l[1]),c=l[4]||l[6],d=l[5],f=t(l[3]||""),p=t(l[2]?l[1]:c),g=t(l[7])},r.valuesFn=function(e,t){return n.when(g(e,t)).then(function(t){return r.$values=t?i(t,e):{},r.$values})},r.displayValue=function(e){var t={};return t[c]=e,u(t)},r.init(),r}return a}]}),angular.version.minor<3&&angular.version.dot<14&&angular.module("ng").factory("$$rAF",["$window","$timeout",function(e,t){var n=e.requestAnimationFrame||e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame,a=e.cancelAnimationFrame||e.webkitCancelAnimationFrame||e.mozCancelAnimationFrame||e.webkitCancelRequestAnimationFrame,o=!!n,i=o?function(e){var t=n(e);return function(){a(t)}}:function(e){var n=t(e,16.66,!1);return function(){t.cancel(n)}};return i.supported=o,i}]),angular.module("mgcrea.ngStrap.navbar",[]).provider("$navbar",function(){var e=this.defaults={activeClass:"active",routeAttr:"data-match-route",strict:!1};this.$get=function(){return{defaults:e}}}).directive("bsNavbar",["$window","$location","$navbar",function(e,t,n){var a=n.defaults;return{restrict:"A",link:function(e,n,o){var i=angular.copy(a);angular.forEach(Object.keys(a),function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),e.$watch(function(){return t.path()},function(e){var t=n[0].querySelectorAll("li["+i.routeAttr+"]");angular.forEach(t,function(t){var n=angular.element(t),a=n.attr(i.routeAttr).replace("/","\\/");i.strict&&(a="^"+a+"$");var o=new RegExp(a,["i"]);o.test(e)?n.addClass(i.activeClass):n.removeClass(i.activeClass)})})}}}]),angular.module("mgcrea.ngStrap.popover",["mgcrea.ngStrap.tooltip"]).provider("$popover",function(){var e=this.defaults={animation:"am-fade",customClass:"",container:!1,target:!1,placement:"right",template:"popover/popover.tpl.html",contentTemplate:!1,trigger:"click",keyboard:!0,html:!1,title:"",content:"",delay:0,autoClose:!1};this.$get=["$tooltip",function(t){function n(n,a){var o=angular.extend({},e,a),i=t(n,o);return o.content&&(i.$scope.content=o.content),i}return n}]}).directive("bsPopover",["$window","$sce","$popover",function(e,t,n){var a=e.requestAnimationFrame||e.setTimeout;return{restrict:"EAC",scope:!0,link:function(e,o,i){var r={scope:e};angular.forEach(["template","contentTemplate","placement","container","target","delay","trigger","keyboard","html","animation","customClass","autoClose"],function(e){angular.isDefined(i[e])&&(r[e]=i[e])}),angular.forEach(["title","content"],function(n){i[n]&&i.$observe(n,function(o,i){e[n]=t.trustAsHtml(o),angular.isDefined(i)&&a(function(){s&&s.$applyPlacement()})})}),i.bsPopover&&e.$watch(i.bsPopover,function(t,n){angular.isObject(t)?angular.extend(e,t):e.content=t,angular.isDefined(n)&&a(function(){s&&s.$applyPlacement()})},!0),i.bsShow&&e.$watch(i.bsShow,function(e){s&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(popover),?/i)),e===!0?s.show():s.hide())});var s=n(o,r);e.$on("$destroy",function(){s&&s.destroy(),r=null,s=null})}}}]),angular.module("mgcrea.ngStrap.progressbar",[]).provider("$progressbar",function(){var e={barType:"",animate:function(){return!0}};this.$get=function(){return{defaults:e}}}).directive("bsProgressbar",["$progressbar",function(e){return{restrict:"E",transclude:!0,replace:!0,templateUrl:"progressbar/progressbar.tpl.html",scope:{value:"=",type:"@",animate:"&"},link:function(t){t.type=t.type||e.defaults.barType,t.animate=angular.isDefined(t.animate())?t.animate:e.defaults.animate,t.$watch("type",function(){t.barClass=t.type?"progress-bar-"+t.type:null})}}}]),angular.module("mgcrea.ngStrap.scrollspy",["mgcrea.ngStrap.helpers.debounce","mgcrea.ngStrap.helpers.dimensions"]).provider("$scrollspy",function(){var e=this.$$spies={},n=this.defaults={debounce:150,throttle:100,offset:100};this.$get=["$window","$document","$rootScope","dimensions","debounce","throttle",function(a,o,i,r,s,l){function u(e,t){return e[0].nodeName&&e[0].nodeName.toLowerCase()===t.toLowerCase()}function c(o){var c=angular.extend({},n,o);c.element||(c.element=p);var g=u(c.element,"body"),m=g?d:c.element,$=g?"window":c.id;if(e[$])return e[$].$$count++,e[$];var h,v,y,w,b,D,k,T,S={},x=S.$trackedElements=[],C=[];return S.init=function(){this.$$count=1,w=s(this.checkPosition,c.debounce),b=l(this.checkPosition,c.throttle),m.on("click",this.checkPositionWithEventLoop),d.on("resize",w),m.on("scroll",b),D=s(this.checkOffsets,c.debounce),h=i.$on("$viewContentLoaded",D),v=i.$on("$includeContentLoaded",D),D(),$&&(e[$]=S)},S.destroy=function(){this.$$count--,this.$$count>0||(m.off("click",this.checkPositionWithEventLoop),d.off("resize",w),m.off("scroll",b),h(),v(),$&&delete e[$])},S.checkPosition=function(){if(C.length){if(T=(g?a.pageYOffset:m.prop("scrollTop"))||0,k=Math.max(a.innerHeight,f.prop("clientHeight")),TC[e+1].offsetTop))return S.$activateElement(C[e])}},S.checkPositionWithEventLoop=function(){setTimeout(S.checkPosition,1)},S.$activateElement=function(e){if(y){var t=S.$getTrackedElement(y);t&&(t.source.removeClass("active"),u(t.source,"li")&&u(t.source.parent().parent(),"li")&&t.source.parent().parent().removeClass("active"))}y=e.target,e.source.addClass("active"),u(e.source,"li")&&u(e.source.parent().parent(),"li")&&e.source.parent().parent().addClass("active")},S.$getTrackedElement=function(e){return x.filter(function(t){return t.target===e})[0]},S.checkOffsets=function(){angular.forEach(x,function(e){var n=t.querySelector(e.target);e.offsetTop=n?r.offset(n).top:null,c.offset&&null!==e.offsetTop&&(e.offsetTop-=1*c.offset)}),C=x.filter(function(e){return null!==e.offsetTop}).sort(function(e,t){return e.offsetTop-t.offsetTop}),w()},S.trackElement=function(e,t){x.push({target:e,source:t})},S.untrackElement=function(e,t){for(var n,a=x.length;a--;)if(x[a].target===e&&x[a].source===t){n=a;break}x=x.splice(n,1)},S.activate=function(e){x[e].addClass("active")},S.init(),S}var d=angular.element(a),f=angular.element(o.prop("documentElement")),p=angular.element(a.document.body);return c}]}).directive("bsScrollspy",["$rootScope","debounce","dimensions","$scrollspy",function(e,t,n,a){return{restrict:"EAC",link:function(e,t,n){var o={scope:e};angular.forEach(["offset","target"],function(e){angular.isDefined(n[e])&&(o[e]=n[e])});var i=a(o);i.trackElement(o.target,t),e.$on("$destroy",function(){i&&(i.untrackElement(o.target,t),i.destroy()),o=null,i=null})}}}]).directive("bsScrollspyList",["$rootScope","debounce","dimensions","$scrollspy",function(){return{restrict:"A",compile:function(e){var t=e[0].querySelectorAll("li > a[href]");angular.forEach(t,function(e){var t=angular.element(e);t.parent().attr("bs-scrollspy","").attr("data-target",t.attr("href"))})}}}]),angular.module("mgcrea.ngStrap.select",["mgcrea.ngStrap.tooltip","mgcrea.ngStrap.helpers.parseOptions"]).provider("$select",function(){var e=this.defaults={animation:"am-fade",prefixClass:"select",prefixEvent:"$select",placement:"bottom-left",template:"select/select.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,multiple:!1,allNoneButtons:!1,sort:!0,caretHtml:' ',placeholder:"Choose among the following...",allText:"All",noneText:"None",maxLength:3,maxLengthHtml:"selected",iconCheckmark:"glyphicon glyphicon-ok"};this.$get=["$window","$document","$rootScope","$tooltip","$timeout",function(t,n,a,o,i){function r(t,n,a){var r={},s=angular.extend({},e,a);r=o(t,s);var u=r.$scope;u.$matches=[],u.$activeIndex=0,u.$isMultiple=s.multiple,u.$showAllNoneButtons=s.allNoneButtons&&s.multiple,u.$iconCheckmark=s.iconCheckmark,u.$allText=s.allText,u.$noneText=s.noneText,u.$activate=function(e){u.$$postDigest(function(){r.activate(e)})},u.$select=function(e){u.$$postDigest(function(){r.select(e)})},u.$isVisible=function(){return r.$isVisible()},u.$isActive=function(e){return r.$isActive(e)},u.$selectAll=function(){for(var e=0;e=u.$matches.length&&(u.$activeIndex=s.multiple?[]:0)},r.$isVisible=function(){return s.minLength&&n?u.$matches.length&&n.$viewValue.length>=s.minLength:u.$matches.length},r.$isActive=function(e){return s.multiple?-1!==u.$activeIndex.indexOf(e):u.$activeIndex===e},r.$getIndex=function(e){var t=u.$matches.length,n=t;if(t){for(n=t;n--&&u.$matches[n].value!==e;);if(!(0>n))return n}},r.$onMouseDown=function(e){if(e.preventDefault(),e.stopPropagation(),l){var t=angular.element(e.target);t.triggerHandler("click")}},r.$onKeyDown=function(e){if(/(9|13|38|40)/.test(e.keyCode)){if(e.preventDefault(),e.stopPropagation(),!s.multiple&&(13===e.keyCode||9===e.keyCode))return r.select(u.$activeIndex);38===e.keyCode&&u.$activeIndex>0?u.$activeIndex--:40===e.keyCode&&u.$activeIndex'),l.after(t)}var u=o(n.ngOptions),c=a(t,r,s),d=u.$match[7].replace(/\|.+/,"").trim();e.$watch(d,function(){u.valuesFn(e,r).then(function(e){c.update(e),r.$render()})},!0),e.$watch(n.ngModel,function(){c.$updateActiveIndex(),r.$render()},!0),r.$render=function(){var e,n;s.multiple&&angular.isArray(r.$modelValue)?(e=r.$modelValue.map(function(e){return n=c.$getIndex(e),angular.isDefined(n)?c.$scope.$matches[n].label:!1}).filter(angular.isDefined),e=e.length>(s.maxLength||i.maxLength)?e.length+" "+(s.maxLengthHtml||i.maxLengthHtml):e.join(", ")):(n=c.$getIndex(r.$modelValue),e=angular.isDefined(n)?c.$scope.$matches[n].label:!1),t.html((e?e:s.placeholder)+i.caretHtml)},s.multiple&&(r.$isEmpty=function(e){return!e||0===e.length}),e.$on("$destroy",function(){c&&c.destroy(),s=null,c=null})}}}]),angular.module("mgcrea.ngStrap.tab",[]).provider("$tab",function(){var e=this.defaults={animation:"am-fade",template:"tab/tab.tpl.html",navClass:"nav-tabs",activeClass:"active"},t=this.controller=function(t,n,a){var o=this;o.$options=angular.copy(e),angular.forEach(["animation","navClass","activeClass"],function(e){angular.isDefined(a[e])&&(o.$options[e]=a[e])}),t.$navClass=o.$options.navClass,t.$activeClass=o.$options.activeClass,o.$panes=t.$panes=[],o.$activePaneChangeListeners=o.$viewChangeListeners=[],o.$push=function(e){o.$panes.push(e)},o.$remove=function(e){var t=o.$panes.indexOf(e),n=o.$panes.$active;o.$panes.splice(t,1),n>t?n--:t===n&&n===o.$panes.length&&n--,o.$setActive(n)},o.$panes.$active=0,o.$setActive=t.$setActive=function(e){o.$panes.$active=e,o.$activePaneChangeListeners.forEach(function(e){e()})}};this.$get=function(){var n={};return n.defaults=e,n.controller=t,n}}).directive("bsTabs",["$window","$animate","$tab","$parse",function(e,t,n,a){var o=n.defaults;return{require:["?ngModel","bsTabs"],transclude:!0,scope:!0,controller:["$scope","$element","$attrs",n.controller],templateUrl:function(e,t){return t.template||o.template},link:function(e,t,n,o){var i=o[0],r=o[1];if(i&&(console.warn("Usage of ngModel is deprecated, please use bsActivePane instead!"),r.$activePaneChangeListeners.push(function(){i.$setViewValue(r.$panes.$active)}),i.$formatters.push(function(e){return r.$setActive(1*e),e})),n.bsActivePane){var s=a(n.bsActivePane);r.$activePaneChangeListeners.push(function(){s.assign(e,r.$panes.$active)}),e.$watch(n.bsActivePane,function(e){r.$setActive(1*e)},!0)}}}}]).directive("bsPane",["$window","$animate","$sce",function(e,t,n){return{require:["^?ngModel","^bsTabs"],scope:!0,link:function(e,a,o,i){function r(){var n=s.$panes.indexOf(e),o=s.$panes.$active;t[n===o?"addClass":"removeClass"](a,s.$options.activeClass)}var s=(i[0],i[1]);a.addClass("tab-pane"),o.$observe("title",function(t){e.title=n.trustAsHtml(t)}),s.$options.animation&&a.addClass(s.$options.animation),s.$push(e),e.$on("$destroy",function(){s.$remove(e)}),s.$activePaneChangeListeners.push(function(){r()}),r()}}}]),angular.module("mgcrea.ngStrap.timepicker",["mgcrea.ngStrap.helpers.dateParser","mgcrea.ngStrap.helpers.dateFormatter","mgcrea.ngStrap.tooltip"]).provider("$timepicker",function(){var e=this.defaults={animation:"am-fade",prefixClass:"timepicker",placement:"bottom-left",template:"timepicker/timepicker.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,useNative:!0,timeType:"date",timeFormat:"shortTime",modelTimeFormat:null,autoclose:!1,minTime:-1/0,maxTime:+1/0,length:5,hourStep:1,minuteStep:5,iconUp:"glyphicon glyphicon-chevron-up",iconDown:"glyphicon glyphicon-chevron-down",arrowBehavior:"pager"};this.$get=["$window","$document","$rootScope","$sce","$dateFormatter","$tooltip","$timeout",function(t,n,a,o,i,r,s){function l(t,n,a){function o(e,n){if(t[0].createTextRange){var a=t[0].createTextRange();a.collapse(!0),a.moveStart("character",e),a.moveEnd("character",n),a.select()}else t[0].setSelectionRange?t[0].setSelectionRange(e,n):angular.isUndefined(t[0].selectionStart)&&(t[0].selectionStart=e,t[0].selectionEnd=n)}function l(){t[0].focus()}var d=r(t,angular.extend({},e,a)),f=a.scope,p=d.$options,g=d.$scope,m=p.lang,$=function(e,t){return i.formatDate(e,t,m)},h=0,v=n.$dateValue||new Date,y={hour:v.getHours(),meridian:v.getHours()<12,minute:v.getMinutes(),second:v.getSeconds(),millisecond:v.getMilliseconds()},w=i.getDatetimeFormat(p.timeFormat,m),b=i.hoursFormat(w),D=i.timeSeparator(w),k=i.minutesFormat(w),T=i.showAM(w);g.$iconUp=p.iconUp,g.$iconDown=p.iconDown,g.$select=function(e,t){d.select(e,t)},g.$moveIndex=function(e,t){d.$moveIndex(e,t)},g.$switchMeridian=function(e){d.switchMeridian(e)},d.update=function(e){angular.isDate(e)&&!isNaN(e.getTime())?(d.$date=e,angular.extend(y,{hour:e.getHours(),minute:e.getMinutes(),second:e.getSeconds(),millisecond:e.getMilliseconds()}),d.$build()):d.$isBuilt||d.$build()},d.select=function(e,t,a){(!n.$dateValue||isNaN(n.$dateValue.getTime()))&&(n.$dateValue=new Date(1970,0,1)),angular.isDate(e)||(e=new Date(e)),0===t?n.$dateValue.setHours(e.getHours()):1===t&&n.$dateValue.setMinutes(e.getMinutes()),n.$setViewValue(angular.copy(n.$dateValue)),n.$render(),p.autoclose&&!a&&s(function(){d.hide(!0)})},d.switchMeridian=function(e){if(n.$dateValue&&!isNaN(n.$dateValue.getTime())){var t=(e||n.$dateValue).getHours();n.$dateValue.setHours(12>t?t+12:t-12),n.$setViewValue(angular.copy(n.$dateValue)),n.$render()}},d.$build=function(){var e,t,n=g.midIndex=parseInt(p.length/2,10),a=[];for(e=0;e1*p.maxTime},g.$arrowAction=function(e,t){"picker"===p.arrowBehavior?d.$setTimeByStep(e,t):d.$moveIndex(e,t)},d.$setTimeByStep=function(e,t){{var n=new Date(d.$date),a=n.getHours(),o=($(n,b).length,n.getMinutes());$(n,k).length}0===t?n.setHours(a-parseInt(p.hourStep,10)*e):n.setMinutes(o-parseInt(p.minuteStep,10)*e),d.select(n,t,!0)},d.$moveIndex=function(e,t){var n;0===t?(n=new Date(1970,0,1,y.hour+e*p.length,y.minute),angular.extend(y,{hour:n.getHours()})):1===t&&(n=new Date(1970,0,1,y.hour,y.minute+e*p.length*p.minuteStep),angular.extend(y,{minute:n.getMinutes()})),d.$build()},d.$onMouseDown=function(e){if("input"!==e.target.nodeName.toLowerCase()&&e.preventDefault(),e.stopPropagation(),c){var t=angular.element(e.target);"button"!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler("click")}},d.$onKeyDown=function(e){if(/(38|37|39|40|13)/.test(e.keyCode)&&!e.shiftKey&&!e.altKey){if(e.preventDefault(),e.stopPropagation(),13===e.keyCode)return d.hide(!0);var t=new Date(d.$date),n=t.getHours(),a=$(t,b).length,i=t.getMinutes(),r=$(t,k).length,s=/(37|39)/.test(e.keyCode),l=2+1*T;s&&(37===e.keyCode?h=1>h?l-1:h-1:39===e.keyCode&&(h=l-1>h?h+1:0));var u=[0,a];0===h?(38===e.keyCode?t.setHours(n-parseInt(p.hourStep,10)):40===e.keyCode&&t.setHours(n+parseInt(p.hourStep,10)),a=$(t,b).length,u=[0,a]):1===h?(38===e.keyCode?t.setMinutes(i-parseInt(p.minuteStep,10)):40===e.keyCode&&t.setMinutes(i+parseInt(p.minuteStep,10)),r=$(t,k).length,u=[a+1,a+1+r]):2===h&&(s||d.switchMeridian(),u=[a+1+r+1,a+1+r+3]),d.select(t,h,!0),o(u[0],u[1]),f.$digest()}};var S=d.init;d.init=function(){return u&&p.useNative?(t.prop("type","time"),void t.css("-webkit-appearance","textfield")):(c&&(t.prop("type","text"),t.attr("readonly","true"),t.on("click",l)),void S())};var x=d.destroy;d.destroy=function(){u&&p.useNative&&t.off("click",l),x()};var C=d.show;d.show=function(){C(),s(function(){d.$element.on(c?"touchstart":"mousedown",d.$onMouseDown),p.keyboard&&t.on("keydown",d.$onKeyDown)},0,!1)};var M=d.hide;return d.hide=function(e){d.$isShown&&(d.$element.off(c?"touchstart":"mousedown",d.$onMouseDown),p.keyboard&&t.off("keydown",d.$onKeyDown),M(e))},d}var u=(angular.element(t.document.body),/(ip(a|o)d|iphone|android)/gi.test(t.navigator.userAgent)),c="createTouch"in t.document&&u;return e.lang||(e.lang=i.getDefaultLocale()),l.defaults=e,l}]}).directive("bsTimepicker",["$window","$parse","$q","$dateFormatter","$dateParser","$timepicker",function(e,t,n,a,o,i){{var r=i.defaults,s=/(ip(a|o)d|iphone|android)/gi.test(e.navigator.userAgent);e.requestAnimationFrame||e.setTimeout}return{restrict:"EAC",require:"ngModel",link:function(e,t,n,l){function u(e){if(angular.isDate(e)){var t=isNaN(d.minTime)||new Date(e.getTime()).setFullYear(1970,0,1)>=d.minTime,n=isNaN(d.maxTime)||new Date(e.getTime()).setFullYear(1970,0,1)<=d.maxTime,a=t&&n;l.$setValidity("date",a),l.$setValidity("min",t),l.$setValidity("max",n),a&&(l.$dateValue=e)}}function c(){return!l.$dateValue||isNaN(l.$dateValue.getTime())?"":g(l.$dateValue,d.timeFormat)}var d={scope:e,controller:l};angular.forEach(["placement","container","delay","trigger","keyboard","html","animation","template","autoclose","timeType","timeFormat","modelTimeFormat","useNative","hourStep","minuteStep","length","arrowBehavior","iconUp","iconDown"],function(e){angular.isDefined(n[e])&&(d[e]=n[e])}),n.bsShow&&e.$watch(n.bsShow,function(e){f&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(timepicker),?/i)),e===!0?f.show():f.hide())}),s&&(d.useNative||r.useNative)&&(d.timeFormat="HH:mm");var f=i(t,l,d);d=f.$options;var p=d.lang,g=function(e,t){return a.formatDate(e,t,p)},m=o({format:d.timeFormat,lang:p});angular.forEach(["minTime","maxTime"],function(e){angular.isDefined(n[e])&&n.$observe(e,function(t){f.$options[e]=m.getTimeForAttribute(e,t),!isNaN(f.$options[e])&&f.$build(),u(l.$dateValue)})}),e.$watch(n.ngModel,function(){f.update(l.$dateValue)},!0),l.$parsers.unshift(function(e){if(!e)return l.$setValidity("date",!0),null;var t=angular.isDate(e)?e:m.parse(e,l.$dateValue);return!t||isNaN(t.getTime())?void l.$setValidity("date",!1):(u(t),"string"===d.timeType?g(t,d.modelTimeFormat||d.timeFormat):"number"===d.timeType?l.$dateValue.getTime():"unix"===d.timeType?l.$dateValue.getTime()/1e3:"iso"===d.timeType?l.$dateValue.toISOString():new Date(l.$dateValue))}),l.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:"string"===d.timeType?m.parse(e,null,d.modelTimeFormat):new Date("unix"===d.timeType?1e3*e:e),l.$dateValue=t,c()}),l.$render=function(){t.val(c())},e.$on("$destroy",function(){f&&f.destroy(),d=null,f=null})}}}]),angular.module("mgcrea.ngStrap.tooltip",["mgcrea.ngStrap.helpers.dimensions"]).provider("$tooltip",function(){var e=this.defaults={animation:"am-fade",customClass:"",prefixClass:"tooltip",prefixEvent:"tooltip",container:!1,target:!1,placement:"top",template:"tooltip/tooltip.tpl.html",contentTemplate:!1,trigger:"hover focus",keyboard:!1,html:!1,show:!1,title:"",type:"",delay:0,autoClose:!1,bsEnabled:!0};this.$get=["$window","$rootScope","$compile","$q","$templateCache","$http","$animate","$sce","dimensions","$$rAF","$timeout",function(n,a,o,i,r,s,l,u,c,d,f){function p(n,i){function r(){O.$emit(P.prefixEvent+".show",F)}function s(){return O.$emit(P.prefixEvent+".hide",F),U&&"focus"===P.trigger?n[0].blur():void A()}function p(){var e=P.trigger.split(" ");angular.forEach(e,function(e){"click"===e?n.on("click",F.toggle):"manual"!==e&&(n.on("hover"===e?"mouseenter":"focus",F.enter),n.on("hover"===e?"mouseleave":"blur",F.leave),"button"===V&&"hover"!==e&&n.on(v?"touchstart":"mousedown",F.$onFocusElementMouseDown))})}function b(){for(var e=P.trigger.split(" "),t=e.length;t--;){var a=e[t];"click"===a?n.off("click",F.toggle):"manual"!==a&&(n.off("hover"===a?"mouseenter":"focus",F.enter),n.off("hover"===a?"mouseleave":"blur",F.leave),"button"===V&&"hover"!==a&&n.off(v?"touchstart":"mousedown",F.$onFocusElementMouseDown))}}function D(){"focus"!==P.trigger?R.on("keyup",F.$onKeyUp):n.on("keyup",F.$onFocusKeyUp)}function k(){"focus"!==P.trigger?R.off("keyup",F.$onKeyUp):n.off("keyup",F.$onFocusKeyUp)}function T(){f(function(){R.on("click",x),w.on("click",F.hide),W=!0},0,!1)}function S(){W&&(R.off("click",x),w.off("click",F.hide),W=!1)}function x(e){e.stopPropagation()}function C(e){e=e||P.target||n;var t=e[0],a=t.getBoundingClientRect();null===a.width&&(a=angular.extend({},a,{width:a.right-a.left,height:a.bottom-a.top}));var o;return o="body"===P.container?c.offset(t):c.position(t),angular.extend({},a,o)}function M(e,t,n,a){var o,i=e.split("-");switch(i[0]){case"right":o={top:t.top+t.height/2-a/2,left:t.left+t.width};break;case"bottom":o={top:t.top+t.height,left:t.left+t.width/2-n/2};break;case"left":o={top:t.top+t.height/2-a/2,left:t.left-n};break;default:o={top:t.top-a,left:t.left+t.width/2-n/2}}if(!i[1])return o;if("top"===i[0]||"bottom"===i[0])switch(i[1]){case"left":o.left=t.left;break;case"right":o.left=t.left+t.width-n}else if("left"===i[0]||"right"===i[0])switch(i[1]){case"top":o.top=t.top-a;break;case"bottom":o.top=t.top+t.height}return o}function E(e,t){R.css({top:e+"px",left:t+"px"})}function A(){clearTimeout(H),F.$isShown&&null!==R&&(P.autoClose&&S(),P.keyboard&&k()),K&&(K.$destroy(),K=null),R&&(R.remove(),R=F.$element=null)}var F={},V=n[0].nodeName.toLowerCase(),P=F.$options=angular.extend({},e,i);F.$promise=$(P.template);var O=F.$scope=P.scope&&P.scope.$new()||a.$new();if(P.delay&&angular.isString(P.delay)){var I=P.delay.split(",").map(parseFloat);P.delay=I.length>1?{show:I[0],hide:I[1]}:I[0]}P.title&&(O.title=u.trustAsHtml(P.title)),O.$setEnabled=function(e){O.$$postDigest(function(){F.setEnabled(e)})},O.$hide=function(){O.$$postDigest(function(){F.hide()})},O.$show=function(){O.$$postDigest(function(){F.show()})},O.$toggle=function(){O.$$postDigest(function(){F.toggle()})},F.$isShown=O.$isShown=!1;var H,N;P.contentTemplate&&(F.$promise=F.$promise.then(function(e){var t=angular.element(e);return $(P.contentTemplate).then(function(e){var n=m('[ng-bind="content"]',t[0]);return n.length||(n=m('[ng-bind="title"]',t[0])),n.removeAttr("ng-bind").html(e),t[0].outerHTML})}));var L,R,q,Y,K;F.$promise.then(function(e){angular.isObject(e)&&(e=e.data),P.html&&(e=e.replace(y,'ng-bind-html="')),e=h.apply(e),q=e,L=o(e),F.init()}),F.init=function(){P.delay&&angular.isNumber(P.delay)&&(P.delay={show:P.delay,hide:P.delay}),"self"===P.container?Y=n:angular.isElement(P.container)?Y=P.container:P.container&&(Y=m(P.container)),p(),P.target&&(P.target=angular.isElement(P.target)?P.target:m(P.target)),P.show&&O.$$postDigest(function(){"focus"===P.trigger?n[0].focus():F.show()})},F.destroy=function(){b(),A(),O.$destroy()},F.enter=function(){return clearTimeout(H),N="in",P.delay&&P.delay.show?void(H=setTimeout(function(){"in"===N&&F.show()},P.delay.show)):F.show()},F.show=function(){if(P.bsEnabled&&!F.$isShown){O.$emit(P.prefixEvent+".show.before",F);var e,t;P.container?(e=Y,t=Y[0].lastChild?angular.element(Y[0].lastChild):null):(e=null,t=n),R&&A(),K=F.$scope.$new(),R=F.$element=L(K,function(){}),R.css({top:"-9999px",left:"-9999px",display:"block",visibility:"hidden"}),P.animation&&R.addClass(P.animation),P.type&&R.addClass(P.prefixClass+"-"+P.type),P.customClass&&R.addClass(P.customClass);var a=l.enter(R,e,t,r);a&&a.then&&a.then(r),F.$isShown=O.$isShown=!0,g(O),d(function(){F.$applyPlacement(),R&&R.css({visibility:"visible"})}),P.keyboard&&("focus"!==P.trigger&&F.focus(),D()),P.autoClose&&T()}},F.leave=function(){return clearTimeout(H),N="out",P.delay&&P.delay.hide?void(H=setTimeout(function(){"out"===N&&F.hide()},P.delay.hide)):F.hide()};var U;F.hide=function(e){if(F.$isShown){O.$emit(P.prefixEvent+".hide.before",F),U=e;var t=l.leave(R,s);t&&t.then&&t.then(s),F.$isShown=O.$isShown=!1,g(O),P.keyboard&&null!==R&&k(),P.autoClose&&null!==R&&S()}},F.toggle=function(){F.$isShown?F.leave():F.enter()},F.focus=function(){R[0].focus()},F.setEnabled=function(e){P.bsEnabled=e},F.$applyPlacement=function(){if(R){var a=P.placement,o=/\s?auto?\s?/i,i=o.test(a);i&&(a=a.replace(o,"")||e.placement),R.addClass(P.placement);var r=C(),s=R.prop("offsetWidth"),l=R.prop("offsetHeight");if(i){var u=a,c=P.container?angular.element(t.querySelector(P.container)):n.parent(),d=C(c);u.indexOf("bottom")>=0&&r.bottom+l>d.bottom?a=u.replace("bottom","top"):u.indexOf("top")>=0&&r.top-ld.width?a="right"===u?"left":a.replace("left","right"):("left"===u||"bottom-right"===u||"top-right"===u)&&r.left-s=e.length&&(u.$activeIndex=0)},r.activate=function(e){u.$activeIndex=e},r.select=function(e){var t=u.$matches[e].value;n.$setViewValue(t),n.$render(),u.$resetMatches(),l&&l.$digest(),u.$emit(s.prefixEvent+".select",t,e)},r.$isVisible=function(){return s.minLength&&n?u.$matches.length&&angular.isString(n.$viewValue)&&n.$viewValue.length>=s.minLength:!!u.$matches.length},r.$getIndex=function(e){var t=u.$matches.length,n=t;if(t){for(n=t;n--&&u.$matches[n].value!==e;);if(!(0>n))return n}},r.$onMouseDown=function(e){e.preventDefault(),e.stopPropagation()},r.$onKeyDown=function(e){/(38|40|13)/.test(e.keyCode)&&(r.$isVisible()&&(e.preventDefault(),e.stopPropagation()),13===e.keyCode&&u.$matches.length?r.select(u.$activeIndex):38===e.keyCode&&u.$activeIndex>0?u.$activeIndex--:40===e.keyCode&&u.$activeIndex0)return void s.$setViewValue(s.$viewValue.substring(0,s.$viewValue.length-1));e.length>c&&(e=e.slice(0,c));var n=g.$isVisible();n&&g.update(e),(1!==e.length||e[0].value!==t)&&(!n&&g.update(e),s.$render())})}),s.$formatters.push(function(e){var t=p.displayValue(e);return t===n?"":t}),s.$render=function(){if(s.$isEmpty(s.$viewValue))return t.val("");var e=g.$getIndex(s.$modelValue),n=angular.isDefined(e)?g.$scope.$matches[e].label:s.$viewValue;n=angular.isObject(n)?p.displayValue(n):n,t.val(n?n.toString().replace(/<(?:.|\n)*?>/gm,"").trim():"")},e.$on("$destroy",function(){g&&g.destroy(),l=null,g=null})}}}])}(window,document);
//# sourceMappingURL=angular-strap.min.js.map
\ No newline at end of file
diff --git a/dist/angular-strap.min.js.map b/dist/angular-strap.min.js.map
index 06d365b38..2d084f419 100644
--- a/dist/angular-strap.min.js.map
+++ b/dist/angular-strap.min.js.map
@@ -1 +1 @@
-{"version":3,"sources":["module.js","affix/affix.js","alert/alert.js","button/button.js","datepicker/datepicker.js","collapse/collapse.js","dropdown/dropdown.js","helpers/date-formatter.js","helpers/date-parser.js","helpers/debounce.js","helpers/dimensions.js","helpers/parse-options.js","helpers/raf.js","aside/aside.js","modal/modal.js","navbar/navbar.js","scrollspy/scrollspy.js","progressbar/progressbar.js","select/select.js","tab/tab.js","popover/popover.js","tooltip/tooltip.js","timepicker/timepicker.js","typeahead/typeahead.js"],"names":[],"mappings":"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","file":"angular-strap.min.js","sourcesContent":["\nangular.module('mgcrea.ngStrap', [\n 'mgcrea.ngStrap.modal',\n 'mgcrea.ngStrap.aside',\n 'mgcrea.ngStrap.alert',\n 'mgcrea.ngStrap.button',\n 'mgcrea.ngStrap.select',\n 'mgcrea.ngStrap.datepicker',\n 'mgcrea.ngStrap.timepicker',\n 'mgcrea.ngStrap.navbar',\n 'mgcrea.ngStrap.tooltip',\n 'mgcrea.ngStrap.popover',\n 'mgcrea.ngStrap.dropdown',\n 'mgcrea.ngStrap.typeahead',\n 'mgcrea.ngStrap.scrollspy',\n 'mgcrea.ngStrap.affix',\n 'mgcrea.ngStrap.tab',\n 'mgcrea.ngStrap.collapse',\n 'mgcrea.ngStrap.progressbar'\n]);\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.affix', ['mgcrea.ngStrap.helpers.dimensions', 'mgcrea.ngStrap.helpers.debounce'])\r\n\r\n .provider('$affix', function() {\r\n\r\n var defaults = this.defaults = {\r\n offsetTop: 'auto'\r\n };\r\n\r\n this.$get = function($window, debounce, dimensions) {\r\n\r\n var bodyEl = angular.element($window.document.body);\r\n var windowEl = angular.element($window);\r\n\r\n function AffixFactory(element, config) {\r\n\r\n var $affix = {};\r\n\r\n // Common vars\r\n var options = angular.extend({}, defaults, config);\r\n var targetEl = options.target;\r\n\r\n // Initial private vars\r\n var reset = 'affix affix-top affix-bottom',\r\n setWidth = false,\r\n initialAffixTop = 0,\r\n initialOffsetTop = 0,\r\n offsetTop = 0,\r\n offsetBottom = 0,\r\n affixed = null,\r\n unpin = null;\r\n\r\n var parent = element.parent();\r\n // Options: custom parent\r\n if (options.offsetParent) {\r\n if (options.offsetParent.match(/^\\d+$/)) {\r\n for (var i = 0; i < (options.offsetParent * 1) - 1; i++) {\r\n parent = parent.parent();\r\n }\r\n }\r\n else {\r\n parent = angular.element(options.offsetParent);\r\n }\r\n }\r\n\r\n $affix.init = function() {\r\n\r\n this.$parseOffsets();\r\n initialOffsetTop = dimensions.offset(element[0]).top + initialAffixTop;\r\n setWidth = !element[0].style.width;\r\n\r\n // Bind events\r\n targetEl.on('scroll', this.checkPosition);\r\n targetEl.on('click', this.checkPositionWithEventLoop);\r\n windowEl.on('resize', this.$debouncedOnResize);\r\n\r\n // Both of these checkPosition() calls are necessary for the case where\r\n // the user hits refresh after scrolling to the bottom of the page.\r\n this.checkPosition();\r\n this.checkPositionWithEventLoop();\r\n\r\n };\r\n\r\n $affix.destroy = function() {\r\n\r\n // Unbind events\r\n targetEl.off('scroll', this.checkPosition);\r\n targetEl.off('click', this.checkPositionWithEventLoop);\r\n windowEl.off('resize', this.$debouncedOnResize);\r\n\r\n };\r\n\r\n $affix.checkPositionWithEventLoop = function() {\r\n\r\n // IE 9 throws an error if we use 'this' instead of '$affix'\r\n // in this setTimeout call\r\n setTimeout($affix.checkPosition, 1);\r\n\r\n };\r\n\r\n $affix.checkPosition = function() {\r\n // if (!this.$element.is(':visible')) return\r\n\r\n var scrollTop = getScrollTop();\r\n var position = dimensions.offset(element[0]);\r\n var elementHeight = dimensions.height(element[0]);\r\n\r\n // Get required affix class according to position\r\n var affix = getRequiredAffixClass(unpin, position, elementHeight);\r\n\r\n // Did affix status changed this last check?\r\n if(affixed === affix) return;\r\n affixed = affix;\r\n\r\n // Add proper affix class\r\n element.removeClass(reset).addClass('affix' + ((affix !== 'middle') ? '-' + affix : ''));\r\n\r\n if(affix === 'top') {\r\n unpin = null;\r\n element.css('position', (options.offsetParent) ? '' : 'relative');\r\n if(setWidth) {\r\n element.css('width', '');\r\n }\r\n element.css('top', '');\r\n } else if(affix === 'bottom') {\r\n if (options.offsetUnpin) {\r\n unpin = -(options.offsetUnpin * 1);\r\n }\r\n else {\r\n // Calculate unpin threshold when affixed to bottom.\r\n // Hopefully the browser scrolls pixel by pixel.\r\n unpin = position.top - scrollTop;\r\n }\r\n if(setWidth) {\r\n element.css('width', '');\r\n }\r\n element.css('position', (options.offsetParent) ? '' : 'relative');\r\n element.css('top', (options.offsetParent) ? '' : ((bodyEl[0].offsetHeight - offsetBottom - elementHeight - initialOffsetTop) + 'px'));\r\n } else { // affix === 'middle'\r\n unpin = null;\r\n if(setWidth) {\r\n element.css('width', element[0].offsetWidth + 'px');\r\n }\r\n element.css('position', 'fixed');\r\n element.css('top', initialAffixTop + 'px');\r\n }\r\n\r\n };\r\n\r\n $affix.$onResize = function() {\r\n $affix.$parseOffsets();\r\n $affix.checkPosition();\r\n };\r\n $affix.$debouncedOnResize = debounce($affix.$onResize, 50);\r\n\r\n $affix.$parseOffsets = function() {\r\n var initialPosition = element.css('position');\r\n // Reset position to calculate correct offsetTop\r\n element.css('position', (options.offsetParent) ? '' : 'relative');\r\n\r\n if(options.offsetTop) {\r\n if(options.offsetTop === 'auto') {\r\n options.offsetTop = '+0';\r\n }\r\n if(options.offsetTop.match(/^[-+]\\d+$/)) {\r\n initialAffixTop = - options.offsetTop * 1;\r\n if(options.offsetParent) {\r\n offsetTop = dimensions.offset(parent[0]).top + (options.offsetTop * 1);\r\n }\r\n else {\r\n offsetTop = dimensions.offset(element[0]).top - dimensions.css(element[0], 'marginTop', true) + (options.offsetTop * 1);\r\n }\r\n }\r\n else {\r\n offsetTop = options.offsetTop * 1;\r\n }\r\n }\r\n\r\n if(options.offsetBottom) {\r\n if(options.offsetParent && options.offsetBottom.match(/^[-+]\\d+$/)) {\r\n // add 1 pixel due to rounding problems...\r\n offsetBottom = getScrollHeight() - (dimensions.offset(parent[0]).top + dimensions.height(parent[0])) + (options.offsetBottom * 1) + 1;\r\n }\r\n else {\r\n offsetBottom = options.offsetBottom * 1;\r\n }\r\n }\r\n\r\n // Bring back the element's position after calculations\r\n element.css('position', initialPosition);\r\n };\r\n\r\n // Private methods\r\n\r\n function getRequiredAffixClass(unpin, position, elementHeight) {\r\n\r\n var scrollTop = getScrollTop();\r\n var scrollHeight = getScrollHeight();\r\n\r\n if(scrollTop <= offsetTop) {\r\n return 'top';\r\n } else if(unpin !== null && (scrollTop + unpin <= position.top)) {\r\n return 'middle';\r\n } else if(offsetBottom !== null && (position.top + elementHeight + initialAffixTop >= scrollHeight - offsetBottom)) {\r\n return 'bottom';\r\n } else {\r\n return 'middle';\r\n }\r\n\r\n }\r\n\r\n function getScrollTop() {\r\n return targetEl[0] === $window ? $window.pageYOffset : targetEl[0].scrollTop;\r\n }\r\n\r\n function getScrollHeight() {\r\n return targetEl[0] === $window ? $window.document.body.scrollHeight : targetEl[0].scrollHeight;\r\n }\r\n\r\n $affix.init();\r\n return $affix;\r\n\r\n }\r\n\r\n return AffixFactory;\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsAffix', function($affix, $window) {\r\n\r\n return {\r\n restrict: 'EAC',\r\n require: '^?bsAffixTarget',\r\n link: function postLink(scope, element, attr, affixTarget) {\r\n\r\n var options = {scope: scope, offsetTop: 'auto', target: affixTarget ? affixTarget.$element : angular.element($window)};\r\n angular.forEach(['offsetTop', 'offsetBottom', 'offsetParent', 'offsetUnpin'], function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n var affix = $affix(element, options);\r\n scope.$on('$destroy', function() {\r\n affix && affix.destroy();\r\n options = null;\r\n affix = null;\r\n });\r\n\r\n }\r\n };\r\n\r\n })\r\n\r\n .directive('bsAffixTarget', function() {\r\n return {\r\n controller: function($element) {\r\n this.$element = $element;\r\n }\r\n };\r\n });\r\n","'use strict';\r\n\r\n// @BUG: following snippet won't compile correctly\r\n// @TODO: submit issue to core\r\n// ' ' +\r\n\r\nangular.module('mgcrea.ngStrap.alert', ['mgcrea.ngStrap.modal'])\r\n\r\n .provider('$alert', function() {\r\n\r\n var defaults = this.defaults = {\r\n animation: 'am-fade',\r\n prefixClass: 'alert',\r\n prefixEvent: 'alert',\r\n placement: null,\r\n template: 'alert/alert.tpl.html',\r\n container: false,\r\n element: null,\r\n backdrop: false,\r\n keyboard: true,\r\n show: true,\r\n // Specific options\r\n duration: false,\r\n type: false,\r\n dismissable: true\r\n };\r\n\r\n this.$get = function($modal, $timeout) {\r\n\r\n function AlertFactory(config) {\r\n\r\n var $alert = {};\r\n\r\n // Common vars\r\n var options = angular.extend({}, defaults, config);\r\n\r\n $alert = $modal(options);\r\n\r\n // Support scope as string options [/*title, content, */ type, dismissable]\r\n $alert.$scope.dismissable = !!options.dismissable;\r\n if(options.type) {\r\n $alert.$scope.type = options.type;\r\n }\r\n\r\n // Support auto-close duration\r\n var show = $alert.show;\r\n if(options.duration) {\r\n $alert.show = function() {\r\n show();\r\n $timeout(function() {\r\n $alert.hide();\r\n }, options.duration * 1000);\r\n };\r\n }\r\n\r\n return $alert;\r\n\r\n }\r\n\r\n return AlertFactory;\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsAlert', function($window, $sce, $alert) {\r\n\r\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\r\n\r\n return {\r\n restrict: 'EAC',\r\n scope: true,\r\n link: function postLink(scope, element, attr, transclusion) {\r\n\r\n // Directive options\r\n var options = {scope: scope, element: element, show: false};\r\n angular.forEach(['template', 'placement', 'keyboard', 'html', 'container', 'animation', 'duration', 'dismissable'], function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n // Support scope as data-attrs\r\n angular.forEach(['title', 'content', 'type'], function(key) {\r\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\r\n scope[key] = $sce.trustAsHtml(newValue);\r\n });\r\n });\r\n\r\n // Support scope as an object\r\n attr.bsAlert && scope.$watch(attr.bsAlert, function(newValue, oldValue) {\r\n if(angular.isObject(newValue)) {\r\n angular.extend(scope, newValue);\r\n } else {\r\n scope.content = newValue;\r\n }\r\n }, true);\r\n\r\n // Initialize alert\r\n var alert = $alert(options);\r\n\r\n // Trigger\r\n element.on(attr.trigger || 'click', alert.toggle);\r\n\r\n // Garbage collection\r\n scope.$on('$destroy', function() {\r\n if (alert) alert.destroy();\r\n options = null;\r\n alert = null;\r\n });\r\n\r\n }\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.button', [])\r\n\r\n .provider('$button', function() {\r\n\r\n var defaults = this.defaults = {\r\n activeClass:'active',\r\n toggleEvent:'click'\r\n };\r\n\r\n this.$get = function() {\r\n return {defaults: defaults};\r\n };\r\n\r\n })\r\n\r\n .directive('bsCheckboxGroup', function() {\r\n\r\n return {\r\n restrict: 'A',\r\n require: 'ngModel',\r\n compile: function postLink(element, attr) {\r\n element.attr('data-toggle', 'buttons');\r\n element.removeAttr('ng-model');\r\n var children = element[0].querySelectorAll('input[type=\"checkbox\"]');\r\n angular.forEach(children, function(child) {\r\n var childEl = angular.element(child);\r\n childEl.attr('bs-checkbox', '');\r\n childEl.attr('ng-model', attr.ngModel + '.' + childEl.attr('value'));\r\n });\r\n }\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsCheckbox', function($button, $$rAF) {\r\n\r\n var defaults = $button.defaults;\r\n var constantValueRegExp = /^(true|false|\\d+)$/;\r\n\r\n return {\r\n restrict: 'A',\r\n require: 'ngModel',\r\n link: function postLink(scope, element, attr, controller) {\r\n\r\n var options = defaults;\r\n\r\n // Support label > input[type=\"checkbox\"]\r\n var isInput = element[0].nodeName === 'INPUT';\r\n var activeElement = isInput ? element.parent() : element;\r\n\r\n var trueValue = angular.isDefined(attr.trueValue) ? attr.trueValue : true;\r\n if(constantValueRegExp.test(attr.trueValue)) {\r\n trueValue = scope.$eval(attr.trueValue);\r\n }\r\n var falseValue = angular.isDefined(attr.falseValue) ? attr.falseValue : false;\r\n if(constantValueRegExp.test(attr.falseValue)) {\r\n falseValue = scope.$eval(attr.falseValue);\r\n }\r\n\r\n // Parse exotic values\r\n var hasExoticValues = typeof trueValue !== 'boolean' || typeof falseValue !== 'boolean';\r\n if(hasExoticValues) {\r\n controller.$parsers.push(function(viewValue) {\r\n // console.warn('$parser', element.attr('ng-model'), 'viewValue', viewValue);\r\n return viewValue ? trueValue : falseValue;\r\n });\r\n // modelValue -> $formatters -> viewValue\r\n controller.$formatters.push(function(modelValue) {\r\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\r\n return angular.equals(modelValue, trueValue);\r\n });\r\n // Fix rendering for exotic values\r\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\r\n controller.$render();\r\n });\r\n }\r\n\r\n // model -> view\r\n controller.$render = function () {\r\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\r\n var isActive = angular.equals(controller.$modelValue, trueValue);\r\n $$rAF(function() {\r\n if(isInput) element[0].checked = isActive;\r\n activeElement.toggleClass(options.activeClass, isActive);\r\n });\r\n };\r\n\r\n // view -> model\r\n element.bind(options.toggleEvent, function() {\r\n scope.$apply(function () {\r\n // console.warn('!click', element.attr('ng-model'), 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue, 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue);\r\n if(!isInput) {\r\n controller.$setViewValue(!activeElement.hasClass('active'));\r\n }\r\n if(!hasExoticValues) {\r\n controller.$render();\r\n }\r\n });\r\n });\r\n\r\n }\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsRadioGroup', function() {\r\n\r\n return {\r\n restrict: 'A',\r\n require: 'ngModel',\r\n compile: function postLink(element, attr) {\r\n element.attr('data-toggle', 'buttons');\r\n element.removeAttr('ng-model');\r\n var children = element[0].querySelectorAll('input[type=\"radio\"]');\r\n angular.forEach(children, function(child) {\r\n angular.element(child).attr('bs-radio', '');\r\n angular.element(child).attr('ng-model', attr.ngModel);\r\n });\r\n }\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsRadio', function($button, $$rAF) {\r\n\r\n var defaults = $button.defaults;\r\n var constantValueRegExp = /^(true|false|\\d+)$/;\r\n\r\n return {\r\n restrict: 'A',\r\n require: 'ngModel',\r\n link: function postLink(scope, element, attr, controller) {\r\n\r\n var options = defaults;\r\n\r\n // Support `label > input[type=\"radio\"]` markup\r\n var isInput = element[0].nodeName === 'INPUT';\r\n var activeElement = isInput ? element.parent() : element;\r\n\r\n var value = constantValueRegExp.test(attr.value) ? scope.$eval(attr.value) : attr.value;\r\n\r\n // model -> view\r\n controller.$render = function () {\r\n // console.warn('$render', element.attr('value'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\r\n var isActive = angular.equals(controller.$modelValue, value);\r\n $$rAF(function() {\r\n if(isInput) element[0].checked = isActive;\r\n activeElement.toggleClass(options.activeClass, isActive);\r\n });\r\n };\r\n\r\n // view -> model\r\n element.bind(options.toggleEvent, function() {\r\n scope.$apply(function () {\r\n // console.warn('!click', element.attr('value'), 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue, 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue);\r\n controller.$setViewValue(value);\r\n controller.$render();\r\n });\r\n });\r\n\r\n }\r\n\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.datepicker', [\r\n 'mgcrea.ngStrap.helpers.dateParser',\r\n 'mgcrea.ngStrap.helpers.dateFormatter',\r\n 'mgcrea.ngStrap.tooltip'])\r\n\r\n .provider('$datepicker', function() {\r\n\r\n var defaults = this.defaults = {\r\n animation: 'am-fade',\r\n prefixClass: 'datepicker',\r\n placement: 'bottom-left',\r\n template: 'datepicker/datepicker.tpl.html',\r\n trigger: 'focus',\r\n container: false,\r\n keyboard: true,\r\n html: false,\r\n delay: 0,\r\n // lang: $locale.id,\r\n useNative: false,\r\n dateType: 'date',\r\n dateFormat: 'shortDate',\r\n modelDateFormat: null,\r\n dayFormat: 'dd',\r\n monthFormat: 'MMM',\r\n yearFormat: 'yyyy',\r\n monthTitleFormat: 'MMMM yyyy',\r\n yearTitleFormat: 'yyyy',\r\n strictFormat: false,\r\n autoclose: false,\r\n minDate: -Infinity,\r\n maxDate: +Infinity,\r\n startView: 0,\r\n minView: 0,\r\n startWeek: 0,\r\n daysOfWeekDisabled: '',\r\n iconLeft: 'glyphicon glyphicon-chevron-left',\r\n iconRight: 'glyphicon glyphicon-chevron-right'\r\n };\r\n\r\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, datepickerViews, $tooltip, $timeout) {\r\n\r\n var bodyEl = angular.element($window.document.body);\r\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\r\n var isTouch = ('createTouch' in $window.document) && isNative;\r\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\r\n\r\n function DatepickerFactory(element, controller, config) {\r\n\r\n var $datepicker = $tooltip(element, angular.extend({}, defaults, config));\r\n var parentScope = config.scope;\r\n var options = $datepicker.$options;\r\n var scope = $datepicker.$scope;\r\n if(options.startView) options.startView -= options.minView;\r\n\r\n // View vars\r\n\r\n var pickerViews = datepickerViews($datepicker);\r\n $datepicker.$views = pickerViews.views;\r\n var viewDate = pickerViews.viewDate;\r\n scope.$mode = options.startView;\r\n scope.$iconLeft = options.iconLeft;\r\n scope.$iconRight = options.iconRight;\r\n var $picker = $datepicker.$views[scope.$mode];\r\n\r\n // Scope methods\r\n\r\n scope.$select = function(date) {\r\n $datepicker.select(date);\r\n };\r\n scope.$selectPane = function(value) {\r\n $datepicker.$selectPane(value);\r\n };\r\n scope.$toggleMode = function() {\r\n $datepicker.setMode((scope.$mode + 1) % $datepicker.$views.length);\r\n };\r\n\r\n // Public methods\r\n\r\n $datepicker.update = function(date) {\r\n // console.warn('$datepicker.update() newValue=%o', date);\r\n if(angular.isDate(date) && !isNaN(date.getTime())) {\r\n $datepicker.$date = date;\r\n $picker.update.call($picker, date);\r\n }\r\n // Build only if pristine\r\n $datepicker.$build(true);\r\n };\r\n\r\n $datepicker.updateDisabledDates = function(dateRanges) {\r\n options.disabledDateRanges = dateRanges;\r\n for(var i = 0, l = scope.rows.length; i < l; i++) {\r\n angular.forEach(scope.rows[i], $datepicker.$setDisabledEl);\r\n }\r\n };\r\n\r\n $datepicker.select = function(date, keep) {\r\n // console.warn('$datepicker.select', date, scope.$mode);\r\n if(!angular.isDate(controller.$dateValue)) controller.$dateValue = new Date(date);\r\n if(!scope.$mode || keep) {\r\n controller.$setViewValue(angular.copy(date));\r\n controller.$render();\r\n if(options.autoclose && !keep) {\r\n $timeout(function() { $datepicker.hide(true); });\r\n }\r\n } else {\r\n angular.extend(viewDate, {year: date.getFullYear(), month: date.getMonth(), date: date.getDate()});\r\n $datepicker.setMode(scope.$mode - 1);\r\n $datepicker.$build();\r\n }\r\n };\r\n\r\n $datepicker.setMode = function(mode) {\r\n // console.warn('$datepicker.setMode', mode);\r\n scope.$mode = mode;\r\n $picker = $datepicker.$views[scope.$mode];\r\n $datepicker.$build();\r\n };\r\n\r\n // Protected methods\r\n\r\n $datepicker.$build = function(pristine) {\r\n // console.warn('$datepicker.$build() viewDate=%o', viewDate);\r\n if(pristine === true && $picker.built) return;\r\n if(pristine === false && !$picker.built) return;\r\n $picker.build.call($picker);\r\n };\r\n\r\n $datepicker.$updateSelected = function() {\r\n for(var i = 0, l = scope.rows.length; i < l; i++) {\r\n angular.forEach(scope.rows[i], updateSelected);\r\n }\r\n };\r\n\r\n $datepicker.$isSelected = function(date) {\r\n return $picker.isSelected(date);\r\n };\r\n\r\n $datepicker.$setDisabledEl = function(el) {\r\n el.disabled = $picker.isDisabled(el.date);\r\n };\r\n\r\n $datepicker.$selectPane = function(value) {\r\n var steps = $picker.steps;\r\n // set targetDate to first day of month to avoid problems with\r\n // date values rollover. This assumes the viewDate does not\r\n // depend on the day of the month \r\n var targetDate = new Date(Date.UTC(viewDate.year + ((steps.year || 0) * value), viewDate.month + ((steps.month || 0) * value), 1));\r\n angular.extend(viewDate, {year: targetDate.getUTCFullYear(), month: targetDate.getUTCMonth(), date: targetDate.getUTCDate()});\r\n $datepicker.$build();\r\n };\r\n\r\n $datepicker.$onMouseDown = function(evt) {\r\n // Prevent blur on mousedown on .dropdown-menu\r\n evt.preventDefault();\r\n evt.stopPropagation();\r\n // Emulate click for mobile devices\r\n if(isTouch) {\r\n var targetEl = angular.element(evt.target);\r\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\r\n targetEl = targetEl.parent();\r\n }\r\n targetEl.triggerHandler('click');\r\n }\r\n };\r\n\r\n $datepicker.$onKeyDown = function(evt) {\r\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\r\n evt.preventDefault();\r\n evt.stopPropagation();\r\n\r\n if(evt.keyCode === 13) {\r\n if(!scope.$mode) {\r\n return $datepicker.hide(true);\r\n } else {\r\n return scope.$apply(function() { $datepicker.setMode(scope.$mode - 1); });\r\n }\r\n }\r\n\r\n // Navigate with keyboard\r\n $picker.onKeyDown(evt);\r\n parentScope.$digest();\r\n };\r\n\r\n // Private\r\n\r\n function updateSelected(el) {\r\n el.selected = $datepicker.$isSelected(el.date);\r\n }\r\n\r\n function focusElement() {\r\n element[0].focus();\r\n }\r\n\r\n // Overrides\r\n\r\n var _init = $datepicker.init;\r\n $datepicker.init = function() {\r\n if(isNative && options.useNative) {\r\n element.prop('type', 'date');\r\n element.css('-webkit-appearance', 'textfield');\r\n return;\r\n } else if(isTouch) {\r\n element.prop('type', 'text');\r\n element.attr('readonly', 'true');\r\n element.on('click', focusElement);\r\n }\r\n _init();\r\n };\r\n\r\n var _destroy = $datepicker.destroy;\r\n $datepicker.destroy = function() {\r\n if(isNative && options.useNative) {\r\n element.off('click', focusElement);\r\n }\r\n _destroy();\r\n };\r\n\r\n var _show = $datepicker.show;\r\n $datepicker.show = function() {\r\n _show();\r\n // use timeout to hookup the events to prevent \r\n // event bubbling from being processed imediately. \r\n $timeout(function() {\r\n $datepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);\r\n if(options.keyboard) {\r\n element.on('keydown', $datepicker.$onKeyDown);\r\n }\r\n }, 0, false);\r\n };\r\n\r\n var _hide = $datepicker.hide;\r\n $datepicker.hide = function(blur) {\r\n if(!$datepicker.$isShown) return;\r\n $datepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);\r\n if(options.keyboard) {\r\n element.off('keydown', $datepicker.$onKeyDown);\r\n }\r\n _hide(blur);\r\n };\r\n\r\n return $datepicker;\r\n\r\n }\r\n\r\n DatepickerFactory.defaults = defaults;\r\n return DatepickerFactory;\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsDatepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $datepicker) {\r\n\r\n var defaults = $datepicker.defaults;\r\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\r\n\r\n return {\r\n restrict: 'EAC',\r\n require: 'ngModel',\r\n link: function postLink(scope, element, attr, controller) {\r\n\r\n // Directive options\r\n var options = {scope: scope, controller: controller};\r\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'dateType', 'dateFormat', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled'], function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n // Visibility binding support\r\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\r\n if(!datepicker || !angular.isDefined(newValue)) return;\r\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(datepicker),?/i);\r\n newValue === true ? datepicker.show() : datepicker.hide();\r\n });\r\n\r\n // Initialize datepicker\r\n var datepicker = $datepicker(element, controller, options);\r\n options = datepicker.$options;\r\n // Set expected iOS format\r\n if(isNative && options.useNative) options.dateFormat = 'yyyy-MM-dd';\r\n\r\n var lang = options.lang;\r\n\r\n var formatDate = function(date, format) {\r\n return $dateFormatter.formatDate(date, format, lang);\r\n };\r\n \r\n var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});\r\n\r\n // Observe attributes for changes\r\n angular.forEach(['minDate', 'maxDate'], function(key) {\r\n // console.warn('attr.$observe(%s)', key, attr[key]);\r\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\r\n // console.warn('attr.$observe(%s)=%o', key, newValue);\r\n datepicker.$options[key] = dateParser.getDateForAttribute(key, newValue);\r\n // Build only if dirty\r\n !isNaN(datepicker.$options[key]) && datepicker.$build(false);\r\n validateAgainstMinMaxDate(controller.$dateValue);\r\n });\r\n });\r\n\r\n // Watch model for changes\r\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\r\n datepicker.update(controller.$dateValue);\r\n }, true);\r\n\r\n // Normalize undefined/null/empty array,\r\n // so that we don't treat changing from undefined->null as a change.\r\n function normalizeDateRanges(ranges) {\r\n if (!ranges || !ranges.length) return null;\r\n return ranges;\r\n }\r\n\r\n if (angular.isDefined(attr.disabledDates)) {\r\n scope.$watch(attr.disabledDates, function(disabledRanges, previousValue) {\r\n disabledRanges = normalizeDateRanges(disabledRanges);\r\n previousValue = normalizeDateRanges(previousValue);\r\n\r\n if (disabledRanges) {\r\n datepicker.updateDisabledDates(disabledRanges);\r\n }\r\n });\r\n }\r\n\r\n function validateAgainstMinMaxDate(parsedDate) {\r\n if (!angular.isDate(parsedDate)) return;\r\n var isMinValid = isNaN(datepicker.$options.minDate) || parsedDate.getTime() >= datepicker.$options.minDate;\r\n var isMaxValid = isNaN(datepicker.$options.maxDate) || parsedDate.getTime() <= datepicker.$options.maxDate;\r\n var isValid = isMinValid && isMaxValid;\r\n controller.$setValidity('date', isValid);\r\n controller.$setValidity('min', isMinValid);\r\n controller.$setValidity('max', isMaxValid);\r\n // Only update the model when we have a valid date\r\n if(isValid) controller.$dateValue = parsedDate;\r\n }\r\n\r\n // viewValue -> $parsers -> modelValue\r\n controller.$parsers.unshift(function(viewValue) {\r\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\r\n // Null values should correctly reset the model value & validity\r\n if(!viewValue) {\r\n controller.$setValidity('date', true);\r\n // BREAKING CHANGE:\r\n // return null (not undefined) when input value is empty, so angularjs 1.3 \r\n // ngModelController can go ahead and run validators, like ngRequired\r\n return null;\r\n }\r\n var parsedDate = dateParser.parse(viewValue, controller.$dateValue);\r\n if(!parsedDate || isNaN(parsedDate.getTime())) {\r\n controller.$setValidity('date', false);\r\n // return undefined, causes ngModelController to \r\n // invalidate model value \r\n return;\r\n } else {\r\n validateAgainstMinMaxDate(parsedDate);\r\n }\r\n if(options.dateType === 'string') {\r\n return formatDate(parsedDate, options.modelDateFormat || options.dateFormat);\r\n } else if(options.dateType === 'number') {\r\n return controller.$dateValue.getTime();\r\n } else if(options.dateType === 'unix') {\r\n return controller.$dateValue.getTime() / 1000;\r\n } else if(options.dateType === 'iso') {\r\n return controller.$dateValue.toISOString();\r\n } else {\r\n return new Date(controller.$dateValue);\r\n }\r\n });\r\n\r\n // modelValue -> $formatters -> viewValue\r\n controller.$formatters.push(function(modelValue) {\r\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\r\n var date;\r\n if(angular.isUndefined(modelValue) || modelValue === null) {\r\n date = NaN;\r\n } else if(angular.isDate(modelValue)) {\r\n date = modelValue;\r\n } else if(options.dateType === 'string') {\r\n date = dateParser.parse(modelValue, null, options.modelDateFormat);\r\n } else if(options.dateType === 'unix') {\r\n date = new Date(modelValue * 1000);\r\n } else {\r\n date = new Date(modelValue);\r\n }\r\n // Setup default value?\r\n // if(isNaN(date.getTime())) {\r\n // var today = new Date();\r\n // date = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0, 0);\r\n // }\r\n controller.$dateValue = date;\r\n return getDateFormattedString();\r\n });\r\n\r\n // viewValue -> element\r\n controller.$render = function() {\r\n // console.warn('$render(\"%s\"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);\r\n element.val(getDateFormattedString());\r\n };\r\n\r\n function getDateFormattedString() {\r\n return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.dateFormat);\r\n }\r\n\r\n // Garbage collection\r\n scope.$on('$destroy', function() {\r\n if(datepicker) datepicker.destroy();\r\n options = null;\r\n datepicker = null;\r\n });\r\n\r\n }\r\n };\r\n\r\n })\r\n\r\n .provider('datepickerViews', function() {\r\n\r\n var defaults = this.defaults = {\r\n dayFormat: 'dd',\r\n daySplit: 7\r\n };\r\n\r\n // Split array into smaller arrays\r\n function split(arr, size) {\r\n var arrays = [];\r\n while(arr.length > 0) {\r\n arrays.push(arr.splice(0, size));\r\n }\r\n return arrays;\r\n }\r\n\r\n // Modulus operator\r\n function mod(n, m) {\r\n return ((n % m) + m) % m;\r\n }\r\n\r\n this.$get = function($dateFormatter, $dateParser, $sce) {\r\n\r\n return function(picker) {\r\n\r\n var scope = picker.$scope;\r\n var options = picker.$options;\r\n\r\n var lang = options.lang;\r\n var formatDate = function(date, format) {\r\n return $dateFormatter.formatDate(date, format, lang);\r\n };\r\n var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});\r\n\r\n var weekDaysMin = $dateFormatter.weekdaysShort(lang);\r\n var weekDaysLabels = weekDaysMin.slice(options.startWeek).concat(weekDaysMin.slice(0, options.startWeek));\r\n var weekDaysLabelsHtml = $sce.trustAsHtml('' + weekDaysLabels.join(' ') + ' ');\r\n\r\n var startDate = picker.$date || (options.startDate ? dateParser.getDateForAttribute('startDate', options.startDate) : new Date());\r\n var viewDate = {year: startDate.getFullYear(), month: startDate.getMonth(), date: startDate.getDate()};\r\n var timezoneOffset = startDate.getTimezoneOffset() * 6e4;\r\n\r\n var views = [{\r\n format: options.dayFormat,\r\n split: 7,\r\n steps: { month: 1 },\r\n update: function(date, force) {\r\n if(!this.built || force || date.getFullYear() !== viewDate.year || date.getMonth() !== viewDate.month) {\r\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\r\n picker.$build();\r\n } else if(date.getDate() !== viewDate.date) {\r\n viewDate.date = picker.$date.getDate();\r\n picker.$updateSelected();\r\n }\r\n },\r\n build: function() {\r\n var firstDayOfMonth = new Date(viewDate.year, viewDate.month, 1), firstDayOfMonthOffset = firstDayOfMonth.getTimezoneOffset();\r\n var firstDate = new Date(+firstDayOfMonth - mod(firstDayOfMonth.getDay() - options.startWeek, 7) * 864e5), firstDateOffset = firstDate.getTimezoneOffset();\r\n var today = new Date().toDateString();\r\n // Handle daylight time switch\r\n if(firstDateOffset !== firstDayOfMonthOffset) firstDate = new Date(+firstDate + (firstDateOffset - firstDayOfMonthOffset) * 60e3);\r\n var days = [], day;\r\n for(var i = 0; i < 42; i++) { // < 7 * 6\r\n day = dateParser.daylightSavingAdjust(new Date(firstDate.getFullYear(), firstDate.getMonth(), firstDate.getDate() + i));\r\n days.push({date: day, isToday: day.toDateString() === today, label: formatDate(day, this.format), selected: picker.$date && this.isSelected(day), muted: day.getMonth() !== viewDate.month, disabled: this.isDisabled(day)});\r\n }\r\n scope.title = formatDate(firstDayOfMonth, options.monthTitleFormat);\r\n scope.showLabels = true;\r\n scope.labels = weekDaysLabelsHtml;\r\n scope.rows = split(days, this.split);\r\n this.built = true;\r\n },\r\n isSelected: function(date) {\r\n return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth() && date.getDate() === picker.$date.getDate();\r\n },\r\n isDisabled: function(date) {\r\n var time = date.getTime();\r\n\r\n // Disabled because of min/max date.\r\n if (time < options.minDate || time > options.maxDate) return true;\r\n\r\n // Disabled due to being a disabled day of the week\r\n if (options.daysOfWeekDisabled.indexOf(date.getDay()) !== -1) return true;\r\n\r\n // Disabled because of disabled date range.\r\n if (options.disabledDateRanges) {\r\n for (var i = 0; i < options.disabledDateRanges.length; i++) {\r\n if (time >= options.disabledDateRanges[i].start && time <= options.disabledDateRanges[i].end) {\r\n return true;\r\n }\r\n }\r\n }\r\n\r\n return false;\r\n },\r\n onKeyDown: function(evt) {\r\n if (!picker.$date) {\r\n return;\r\n }\r\n var actualTime = picker.$date.getTime();\r\n var newDate;\r\n\r\n if(evt.keyCode === 37) newDate = new Date(actualTime - 1 * 864e5);\r\n else if(evt.keyCode === 38) newDate = new Date(actualTime - 7 * 864e5);\r\n else if(evt.keyCode === 39) newDate = new Date(actualTime + 1 * 864e5);\r\n else if(evt.keyCode === 40) newDate = new Date(actualTime + 7 * 864e5);\r\n\r\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\r\n }\r\n }, {\r\n name: 'month',\r\n format: options.monthFormat,\r\n split: 4,\r\n steps: { year: 1 },\r\n update: function(date, force) {\r\n if(!this.built || date.getFullYear() !== viewDate.year) {\r\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\r\n picker.$build();\r\n } else if(date.getMonth() !== viewDate.month) {\r\n angular.extend(viewDate, {month: picker.$date.getMonth(), date: picker.$date.getDate()});\r\n picker.$updateSelected();\r\n }\r\n },\r\n build: function() {\r\n var firstMonth = new Date(viewDate.year, 0, 1);\r\n var months = [], month;\r\n for (var i = 0; i < 12; i++) {\r\n month = new Date(viewDate.year, i, 1);\r\n months.push({date: month, label: formatDate(month, this.format), selected: picker.$isSelected(month), disabled: this.isDisabled(month)});\r\n }\r\n scope.title = formatDate(month, options.yearTitleFormat);\r\n scope.showLabels = false;\r\n scope.rows = split(months, this.split);\r\n this.built = true;\r\n },\r\n isSelected: function(date) {\r\n return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth();\r\n },\r\n isDisabled: function(date) {\r\n var lastDate = +new Date(date.getFullYear(), date.getMonth() + 1, 0);\r\n return lastDate < options.minDate || date.getTime() > options.maxDate;\r\n },\r\n onKeyDown: function(evt) {\r\n if (!picker.$date) {\r\n return;\r\n }\r\n var actualMonth = picker.$date.getMonth();\r\n var newDate = new Date(picker.$date);\r\n\r\n if(evt.keyCode === 37) newDate.setMonth(actualMonth - 1);\r\n else if(evt.keyCode === 38) newDate.setMonth(actualMonth - 4);\r\n else if(evt.keyCode === 39) newDate.setMonth(actualMonth + 1);\r\n else if(evt.keyCode === 40) newDate.setMonth(actualMonth + 4);\r\n\r\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\r\n }\r\n }, {\r\n name: 'year',\r\n format: options.yearFormat,\r\n split: 4,\r\n steps: { year: 12 },\r\n update: function(date, force) {\r\n if(!this.built || force || parseInt(date.getFullYear()/20, 10) !== parseInt(viewDate.year/20, 10)) {\r\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\r\n picker.$build();\r\n } else if(date.getFullYear() !== viewDate.year) {\r\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\r\n picker.$updateSelected();\r\n }\r\n },\r\n build: function() {\r\n var firstYear = viewDate.year - viewDate.year % (this.split * 3);\r\n var years = [], year;\r\n for (var i = 0; i < 12; i++) {\r\n year = new Date(firstYear + i, 0, 1);\r\n years.push({date: year, label: formatDate(year, this.format), selected: picker.$isSelected(year), disabled: this.isDisabled(year)});\r\n }\r\n scope.title = years[0].label + '-' + years[years.length - 1].label;\r\n scope.showLabels = false;\r\n scope.rows = split(years, this.split);\r\n this.built = true;\r\n },\r\n isSelected: function(date) {\r\n return picker.$date && date.getFullYear() === picker.$date.getFullYear();\r\n },\r\n isDisabled: function(date) {\r\n var lastDate = +new Date(date.getFullYear() + 1, 0, 0);\r\n return lastDate < options.minDate || date.getTime() > options.maxDate;\r\n },\r\n onKeyDown: function(evt) {\r\n if (!picker.$date) {\r\n return;\r\n }\r\n var actualYear = picker.$date.getFullYear(),\r\n newDate = new Date(picker.$date);\r\n\r\n if(evt.keyCode === 37) newDate.setYear(actualYear - 1);\r\n else if(evt.keyCode === 38) newDate.setYear(actualYear - 4);\r\n else if(evt.keyCode === 39) newDate.setYear(actualYear + 1);\r\n else if(evt.keyCode === 40) newDate.setYear(actualYear + 4);\r\n\r\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\r\n }\r\n }];\r\n\r\n return {\r\n views: options.minView ? Array.prototype.slice.call(views, options.minView) : views,\r\n viewDate: viewDate\r\n };\r\n\r\n };\r\n\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.collapse', [])\r\n\r\n .provider('$collapse', function() {\r\n\r\n var defaults = this.defaults = {\r\n animation: 'am-collapse',\r\n disallowToggle: false,\r\n activeClass: 'in',\r\n startCollapsed: false,\r\n allowMultiple: false\r\n };\r\n\r\n var controller = this.controller = function($scope, $element, $attrs) {\r\n var self = this;\r\n\r\n // Attributes options\r\n self.$options = angular.copy(defaults);\r\n angular.forEach(['animation', 'disallowToggle', 'activeClass', 'startCollapsed', 'allowMultiple'], function (key) {\r\n if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];\r\n });\r\n\r\n self.$toggles = [];\r\n self.$targets = [];\r\n\r\n self.$viewChangeListeners = [];\r\n\r\n self.$registerToggle = function(element) {\r\n self.$toggles.push(element);\r\n };\r\n self.$registerTarget = function(element) {\r\n self.$targets.push(element);\r\n };\r\n\r\n self.$unregisterToggle = function(element) {\r\n var index = self.$toggles.indexOf(element);\r\n // remove toggle from $toggles array\r\n self.$toggles.splice(index, 1);\r\n };\r\n self.$unregisterTarget = function(element) {\r\n var index = self.$targets.indexOf(element);\r\n\r\n // remove element from $targets array\r\n self.$targets.splice(index, 1);\r\n\r\n if (self.$options.allowMultiple) {\r\n // remove target index from $active array values\r\n deactivateItem(element);\r\n }\r\n\r\n // fix active item indexes\r\n fixActiveItemIndexes(index);\r\n\r\n self.$viewChangeListeners.forEach(function(fn) {\r\n fn();\r\n });\r\n };\r\n\r\n // use array to store all the currently open panels\r\n self.$targets.$active = !self.$options.startCollapsed ? [0] : [];\r\n self.$setActive = $scope.$setActive = function(value) {\r\n if(angular.isArray(value)) {\r\n self.$targets.$active = angular.copy(value);\r\n }\r\n else if(!self.$options.disallowToggle) {\r\n // toogle element active status\r\n isActive(value) ? deactivateItem(value) : activateItem(value);\r\n } else {\r\n activateItem(value);\r\n }\r\n\r\n self.$viewChangeListeners.forEach(function(fn) {\r\n fn();\r\n });\r\n };\r\n\r\n self.$activeIndexes = function() {\r\n return self.$options.allowMultiple ? self.$targets.$active :\r\n self.$targets.$active.length === 1 ? self.$targets.$active[0] : -1;\r\n };\r\n\r\n function fixActiveItemIndexes(index) {\r\n // item with index was removed, so we\r\n // need to adjust other items index values\r\n var activeIndexes = self.$targets.$active;\r\n for(var i = 0; i < activeIndexes.length; i++) {\r\n if (index < activeIndexes[i]) {\r\n activeIndexes[i] = activeIndexes[i] - 1;\r\n }\r\n\r\n // the last item is active, so we need to\r\n // adjust its index\r\n if (activeIndexes[i] === self.$targets.length) {\r\n activeIndexes[i] = self.$targets.length - 1;\r\n }\r\n }\r\n }\r\n\r\n function isActive(value) {\r\n var activeItems = self.$targets.$active;\r\n return activeItems.indexOf(value) === -1 ? false : true;\r\n }\r\n\r\n function deactivateItem(value) {\r\n var index = self.$targets.$active.indexOf(value);\r\n if (index !== -1) {\r\n self.$targets.$active.splice(index, 1);\r\n }\r\n }\r\n\r\n function activateItem(value) {\r\n if (!self.$options.allowMultiple) {\r\n // remove current selected item\r\n self.$targets.$active.splice(0, 1);\r\n }\r\n\r\n if (self.$targets.$active.indexOf(value) === -1) {\r\n self.$targets.$active.push(value);\r\n }\r\n }\r\n\r\n };\r\n\r\n this.$get = function() {\r\n var $collapse = {};\r\n $collapse.defaults = defaults;\r\n $collapse.controller = controller;\r\n return $collapse;\r\n };\r\n\r\n })\r\n\r\n .directive('bsCollapse', function($window, $animate, $collapse) {\r\n\r\n var defaults = $collapse.defaults;\r\n\r\n return {\r\n require: ['?ngModel', 'bsCollapse'],\r\n controller: ['$scope', '$element', '$attrs', $collapse.controller],\r\n link: function postLink(scope, element, attrs, controllers) {\r\n\r\n var ngModelCtrl = controllers[0];\r\n var bsCollapseCtrl = controllers[1];\r\n\r\n if(ngModelCtrl) {\r\n\r\n // Update the modelValue following\r\n bsCollapseCtrl.$viewChangeListeners.push(function() {\r\n ngModelCtrl.$setViewValue(bsCollapseCtrl.$activeIndexes());\r\n });\r\n\r\n // modelValue -> $formatters -> viewValue\r\n ngModelCtrl.$formatters.push(function(modelValue) {\r\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\r\n if (angular.isArray(modelValue)) {\r\n // model value is an array, so just replace\r\n // the active items directly\r\n bsCollapseCtrl.$setActive(modelValue);\r\n }\r\n else {\r\n var activeIndexes = bsCollapseCtrl.$activeIndexes();\r\n\r\n if (angular.isArray(activeIndexes)) {\r\n // we have an array of selected indexes\r\n if (activeIndexes.indexOf(modelValue * 1) === -1) {\r\n // item with modelValue index is not active\r\n bsCollapseCtrl.$setActive(modelValue * 1);\r\n }\r\n }\r\n else if (activeIndexes !== modelValue * 1) {\r\n bsCollapseCtrl.$setActive(modelValue * 1);\r\n }\r\n }\r\n return modelValue;\r\n });\r\n\r\n }\r\n\r\n }\r\n };\r\n\r\n })\r\n\r\n .directive('bsCollapseToggle', function() {\r\n\r\n return {\r\n require: ['^?ngModel', '^bsCollapse'],\r\n link: function postLink(scope, element, attrs, controllers) {\r\n\r\n var ngModelCtrl = controllers[0];\r\n var bsCollapseCtrl = controllers[1];\r\n\r\n // Add base attr\r\n element.attr('data-toggle', 'collapse');\r\n\r\n // Push pane to parent bsCollapse controller\r\n bsCollapseCtrl.$registerToggle(element);\r\n\r\n // remove toggle from collapse controller when toggle is destroyed\r\n scope.$on('$destroy', function() {\r\n bsCollapseCtrl.$unregisterToggle(element);\r\n });\r\n\r\n element.on('click', function() {\r\n var index = attrs.bsCollapseToggle || bsCollapseCtrl.$toggles.indexOf(element);\r\n bsCollapseCtrl.$setActive(index * 1);\r\n scope.$apply();\r\n });\r\n\r\n }\r\n };\r\n\r\n })\r\n\r\n .directive('bsCollapseTarget', function($animate) {\r\n\r\n return {\r\n require: ['^?ngModel', '^bsCollapse'],\r\n // scope: true,\r\n link: function postLink(scope, element, attrs, controllers) {\r\n\r\n var ngModelCtrl = controllers[0];\r\n var bsCollapseCtrl = controllers[1];\r\n\r\n // Add base class\r\n element.addClass('collapse');\r\n\r\n // Add animation class\r\n if(bsCollapseCtrl.$options.animation) {\r\n element.addClass(bsCollapseCtrl.$options.animation);\r\n }\r\n\r\n // Push pane to parent bsCollapse controller\r\n bsCollapseCtrl.$registerTarget(element);\r\n\r\n // remove pane target from collapse controller when target is destroyed\r\n scope.$on('$destroy', function() {\r\n bsCollapseCtrl.$unregisterTarget(element);\r\n });\r\n\r\n function render() {\r\n var index = bsCollapseCtrl.$targets.indexOf(element);\r\n var active = bsCollapseCtrl.$activeIndexes();\r\n var action = 'removeClass';\r\n if (angular.isArray(active)) {\r\n if (active.indexOf(index) !== -1) {\r\n action = 'addClass';\r\n }\r\n }\r\n else if (index === active) {\r\n action = 'addClass';\r\n }\r\n\r\n $animate[action](element, bsCollapseCtrl.$options.activeClass);\r\n }\r\n\r\n bsCollapseCtrl.$viewChangeListeners.push(function() {\r\n render();\r\n });\r\n render();\r\n\r\n }\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.dropdown', ['mgcrea.ngStrap.tooltip'])\r\n\r\n .provider('$dropdown', function() {\r\n\r\n var defaults = this.defaults = {\r\n animation: 'am-fade',\r\n prefixClass: 'dropdown',\r\n placement: 'bottom-left',\r\n template: 'dropdown/dropdown.tpl.html',\r\n trigger: 'click',\r\n container: false,\r\n keyboard: true,\r\n html: false,\r\n delay: 0\r\n };\r\n\r\n this.$get = function($window, $rootScope, $tooltip, $timeout) {\r\n\r\n var bodyEl = angular.element($window.document.body);\r\n var matchesSelector = Element.prototype.matchesSelector || Element.prototype.webkitMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector;\r\n\r\n function DropdownFactory(element, config) {\r\n\r\n var $dropdown = {};\r\n\r\n // Common vars\r\n var options = angular.extend({}, defaults, config);\r\n var scope = $dropdown.$scope = options.scope && options.scope.$new() || $rootScope.$new();\r\n\r\n $dropdown = $tooltip(element, options);\r\n var parentEl = element.parent();\r\n\r\n // Protected methods\r\n\r\n $dropdown.$onKeyDown = function(evt) {\r\n if (!/(38|40)/.test(evt.keyCode)) return;\r\n evt.preventDefault();\r\n evt.stopPropagation();\r\n\r\n // Retrieve focused index\r\n var items = angular.element($dropdown.$element[0].querySelectorAll('li:not(.divider) a'));\r\n if(!items.length) return;\r\n var index;\r\n angular.forEach(items, function(el, i) {\r\n if(matchesSelector && matchesSelector.call(el, ':focus')) index = i;\r\n });\r\n\r\n // Navigate with keyboard\r\n if(evt.keyCode === 38 && index > 0) index--;\r\n else if(evt.keyCode === 40 && index < items.length - 1) index++;\r\n else if(angular.isUndefined(index)) index = 0;\r\n items.eq(index)[0].focus();\r\n\r\n };\r\n\r\n // Overrides\r\n\r\n var show = $dropdown.show;\r\n $dropdown.show = function() {\r\n show();\r\n // use timeout to hookup the events to prevent \r\n // event bubbling from being processed imediately. \r\n $timeout(function() {\r\n options.keyboard && $dropdown.$element.on('keydown', $dropdown.$onKeyDown);\r\n bodyEl.on('click', onBodyClick);\r\n }, 0, false);\r\n parentEl.hasClass('dropdown') && parentEl.addClass('open');\r\n };\r\n\r\n var hide = $dropdown.hide;\r\n $dropdown.hide = function() {\r\n if(!$dropdown.$isShown) return;\r\n options.keyboard && $dropdown.$element.off('keydown', $dropdown.$onKeyDown);\r\n bodyEl.off('click', onBodyClick);\r\n parentEl.hasClass('dropdown') && parentEl.removeClass('open');\r\n hide();\r\n };\r\n\r\n var destroy = $dropdown.destroy;\r\n $dropdown.destroy = function() {\r\n bodyEl.off('click', onBodyClick);\r\n destroy();\r\n };\r\n\r\n // Private functions\r\n\r\n function onBodyClick(evt) {\r\n if(evt.target === element[0]) return;\r\n return evt.target !== element[0] && $dropdown.hide();\r\n }\r\n\r\n return $dropdown;\r\n\r\n }\r\n\r\n return DropdownFactory;\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsDropdown', function($window, $sce, $dropdown) {\r\n\r\n return {\r\n restrict: 'EAC',\r\n scope: true,\r\n link: function postLink(scope, element, attr, transclusion) {\r\n\r\n // Directive options\r\n var options = {scope: scope};\r\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template'], function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n // Support scope as an object\r\n attr.bsDropdown && scope.$watch(attr.bsDropdown, function(newValue, oldValue) {\r\n scope.content = newValue;\r\n }, true);\r\n\r\n // Visibility binding support\r\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\r\n if(!dropdown || !angular.isDefined(newValue)) return;\r\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(dropdown),?/i);\r\n newValue === true ? dropdown.show() : dropdown.hide();\r\n });\r\n\r\n // Initialize dropdown\r\n var dropdown = $dropdown(element, options);\r\n\r\n // Garbage collection\r\n scope.$on('$destroy', function() {\r\n if (dropdown) dropdown.destroy();\r\n options = null;\r\n dropdown = null;\r\n });\r\n\r\n }\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.helpers.dateFormatter', [])\r\n\r\n .service('$dateFormatter', function($locale, dateFilter) {\r\n\r\n // The unused `lang` arguments are on purpose. The default implementation does not\r\n // use them and it always uses the locale loaded into the `$locale` service.\r\n // Custom implementations might use it, thus allowing different directives to\r\n // have different languages.\r\n\r\n this.getDefaultLocale = function() {\r\n return $locale.id;\r\n };\r\n\r\n // Format is either a data format name, e.g. \"shortTime\" or \"fullDate\", or a date format\r\n // Return either the corresponding date format or the given date format.\r\n this.getDatetimeFormat = function(format, lang) {\r\n return $locale.DATETIME_FORMATS[format] || format;\r\n };\r\n\r\n this.weekdaysShort = function(lang) {\r\n return $locale.DATETIME_FORMATS.SHORTDAY;\r\n };\r\n\r\n function splitTimeFormat(format) {\r\n return /(h+)([:\\.])?(m+)[ ]?(a?)/i.exec(format).slice(1);\r\n }\r\n\r\n // h:mm a => h\r\n this.hoursFormat = function(timeFormat) {\r\n return splitTimeFormat(timeFormat)[0];\r\n };\r\n\r\n // h:mm a => mm\r\n this.minutesFormat = function(timeFormat) {\r\n return splitTimeFormat(timeFormat)[2];\r\n };\r\n\r\n // h:mm a => :\r\n this.timeSeparator = function(timeFormat) {\r\n return splitTimeFormat(timeFormat)[1];\r\n };\r\n\r\n // h:mm a => true, H.mm => false\r\n this.showAM = function(timeFormat) {\r\n return !!splitTimeFormat(timeFormat)[3];\r\n };\r\n\r\n this.formatDate = function(date, format, lang){\r\n return dateFilter(date, format);\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.helpers.dateParser', [])\r\n\r\n.provider('$dateParser', function($localeProvider) {\r\n\r\n // define a custom ParseDate object to use instead of native Date\r\n // to avoid date values wrapping when setting date component values\r\n function ParseDate() {\r\n this.year = 1970;\r\n this.month = 0;\r\n this.day = 1;\r\n this.hours = 0;\r\n this.minutes = 0;\r\n this.seconds = 0;\r\n this.milliseconds = 0;\r\n }\r\n\r\n ParseDate.prototype.setMilliseconds = function(value) { this.milliseconds = value; };\r\n ParseDate.prototype.setSeconds = function(value) { this.seconds = value; };\r\n ParseDate.prototype.setMinutes = function(value) { this.minutes = value; };\r\n ParseDate.prototype.setHours = function(value) { this.hours = value; };\r\n ParseDate.prototype.getHours = function() { return this.hours; };\r\n ParseDate.prototype.setDate = function(value) { this.day = value; };\r\n ParseDate.prototype.setMonth = function(value) { this.month = value; };\r\n ParseDate.prototype.setFullYear = function(value) { this.year = value; };\r\n ParseDate.prototype.fromDate = function(value) {\r\n this.year = value.getFullYear();\r\n this.month = value.getMonth();\r\n this.day = value.getDate();\r\n this.hours = value.getHours();\r\n this.minutes = value.getMinutes();\r\n this.seconds = value.getSeconds();\r\n this.milliseconds = value.getMilliseconds();\r\n return this;\r\n };\r\n\r\n ParseDate.prototype.toDate = function() {\r\n return new Date(this.year, this.month, this.day, this.hours, this.minutes, this.seconds, this.milliseconds);\r\n };\r\n\r\n var proto = ParseDate.prototype;\r\n\r\n function noop() {\r\n }\r\n\r\n function isNumeric(n) {\r\n return !isNaN(parseFloat(n)) && isFinite(n);\r\n }\r\n\r\n function indexOfCaseInsensitive(array, value) {\r\n var len = array.length, str=value.toString().toLowerCase();\r\n for (var i=0; i 12 when midnight changeover, but then cannot generate\r\n * midnight datetime, so jump to 1AM, otherwise reset.\r\n * @param date (Date) the date to check\r\n * @return (Date) the corrected date\r\n *\r\n * __ copied from jquery ui datepicker __\r\n */\r\n $dateParser.daylightSavingAdjust = function(date) {\r\n if (!date) {\r\n return null;\r\n }\r\n date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);\r\n return date;\r\n };\r\n\r\n // Private functions\r\n\r\n function setMapForFormat(format) {\r\n var keys = Object.keys(setFnMap), i;\r\n var map = [], sortedMap = [];\r\n // Map to setFn\r\n var clonedFormat = format;\r\n for(i = 0; i < keys.length; i++) {\r\n if(format.split(keys[i]).length > 1) {\r\n var index = clonedFormat.search(keys[i]);\r\n format = format.split(keys[i]).join('');\r\n if(setFnMap[keys[i]]) {\r\n map[index] = setFnMap[keys[i]];\r\n }\r\n }\r\n }\r\n // Sort result map\r\n angular.forEach(map, function(v) {\r\n // conditional required since angular.forEach broke around v1.2.21\r\n // related pr: https://github.com/angular/angular.js/pull/8525\r\n if(v) sortedMap.push(v);\r\n });\r\n return sortedMap;\r\n }\r\n\r\n function escapeReservedSymbols(text) {\r\n return text.replace(/\\//g, '[\\\\/]').replace('/-/g', '[-]').replace(/\\./g, '[.]').replace(/\\\\s/g, '[\\\\s]');\r\n }\r\n\r\n function regExpForFormat(format) {\r\n var keys = Object.keys(regExpMap), i;\r\n\r\n var re = format;\r\n // Abstract replaces to avoid collisions\r\n for(i = 0; i < keys.length; i++) {\r\n re = re.split(keys[i]).join('${' + i + '}');\r\n }\r\n // Replace abstracted values\r\n for(i = 0; i < keys.length; i++) {\r\n re = re.split('${' + i + '}').join('(' + regExpMap[keys[i]] + ')');\r\n }\r\n format = escapeReservedSymbols(format);\r\n\r\n return new RegExp('^' + re + '$', ['i']);\r\n }\r\n\r\n $dateParser.init();\r\n return $dateParser;\r\n\r\n };\r\n\r\n return DateParserFactory;\r\n\r\n };\r\n\r\n});\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.helpers.debounce', [])\r\n\r\n// @source jashkenas/underscore\r\n// @url https://github.com/jashkenas/underscore/blob/1.5.2/underscore.js#L693\r\n.factory('debounce', function($timeout) {\r\n return function(func, wait, immediate) {\r\n var timeout = null;\r\n return function() {\r\n var context = this,\r\n args = arguments,\r\n callNow = immediate && !timeout;\r\n if(timeout) {\r\n $timeout.cancel(timeout);\r\n }\r\n timeout = $timeout(function later() {\r\n timeout = null;\r\n if(!immediate) {\r\n func.apply(context, args);\r\n }\r\n }, wait, false);\r\n if(callNow) {\r\n func.apply(context, args);\r\n }\r\n return timeout;\r\n };\r\n };\r\n})\r\n\r\n\r\n// @source jashkenas/underscore\r\n// @url https://github.com/jashkenas/underscore/blob/1.5.2/underscore.js#L661\r\n.factory('throttle', function($timeout) {\r\n return function(func, wait, options) {\r\n var timeout = null;\r\n options || (options = {});\r\n return function() {\r\n var context = this,\r\n args = arguments;\r\n if(!timeout) {\r\n if(options.leading !== false) {\r\n func.apply(context, args);\r\n }\r\n timeout = $timeout(function later() {\r\n timeout = null;\r\n if(options.trailing !== false) {\r\n func.apply(context, args);\r\n }\r\n }, wait, false);\r\n }\r\n };\r\n };\r\n});\r\n\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.helpers.dimensions', [])\r\n\r\n .factory('dimensions', function($document, $window) {\r\n\r\n var jqLite = angular.element;\r\n var fn = {};\r\n\r\n /**\r\n * Test the element nodeName\r\n * @param element\r\n * @param name\r\n */\r\n var nodeName = fn.nodeName = function(element, name) {\r\n return element.nodeName && element.nodeName.toLowerCase() === name.toLowerCase();\r\n };\r\n\r\n /**\r\n * Returns the element computed style\r\n * @param element\r\n * @param prop\r\n * @param extra\r\n */\r\n fn.css = function(element, prop, extra) {\r\n var value;\r\n if (element.currentStyle) { //IE\r\n value = element.currentStyle[prop];\r\n } else if (window.getComputedStyle) {\r\n value = window.getComputedStyle(element)[prop];\r\n } else {\r\n value = element.style[prop];\r\n }\r\n return extra === true ? parseFloat(value) || 0 : value;\r\n };\r\n\r\n /**\r\n * Provides read-only equivalent of jQuery's offset function:\r\n * @required-by bootstrap-tooltip, bootstrap-affix\r\n * @url http://api.jquery.com/offset/\r\n * @param element\r\n */\r\n fn.offset = function(element) {\r\n var boxRect = element.getBoundingClientRect();\r\n var docElement = element.ownerDocument;\r\n return {\r\n width: boxRect.width || element.offsetWidth,\r\n height: boxRect.height || element.offsetHeight,\r\n top: boxRect.top + (window.pageYOffset || docElement.documentElement.scrollTop) - (docElement.documentElement.clientTop || 0),\r\n left: boxRect.left + (window.pageXOffset || docElement.documentElement.scrollLeft) - (docElement.documentElement.clientLeft || 0)\r\n };\r\n };\r\n\r\n /**\r\n * Provides read-only equivalent of jQuery's position function\r\n * @required-by bootstrap-tooltip, bootstrap-affix\r\n * @url http://api.jquery.com/offset/\r\n * @param element\r\n */\r\n fn.position = function(element) {\r\n\r\n var offsetParentRect = {top: 0, left: 0},\r\n offsetParentElement,\r\n offset;\r\n\r\n // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent\r\n if (fn.css(element, 'position') === 'fixed') {\r\n\r\n // We assume that getBoundingClientRect is available when computed position is fixed\r\n offset = element.getBoundingClientRect();\r\n\r\n } else {\r\n\r\n // Get *real* offsetParentElement\r\n offsetParentElement = offsetParent(element);\r\n\r\n // Get correct offsets\r\n offset = fn.offset(element);\r\n if (!nodeName(offsetParentElement, 'html')) {\r\n offsetParentRect = fn.offset(offsetParentElement);\r\n }\r\n\r\n // Add offsetParent borders\r\n offsetParentRect.top += fn.css(offsetParentElement, 'borderTopWidth', true);\r\n offsetParentRect.left += fn.css(offsetParentElement, 'borderLeftWidth', true);\r\n }\r\n\r\n // Subtract parent offsets and element margins\r\n return {\r\n width: element.offsetWidth,\r\n height: element.offsetHeight,\r\n top: offset.top - offsetParentRect.top - fn.css(element, 'marginTop', true),\r\n left: offset.left - offsetParentRect.left - fn.css(element, 'marginLeft', true)\r\n };\r\n\r\n };\r\n\r\n /**\r\n * Returns the closest, non-statically positioned offsetParent of a given element\r\n * @required-by fn.position\r\n * @param element\r\n */\r\n var offsetParent = function offsetParentElement(element) {\r\n var docElement = element.ownerDocument;\r\n var offsetParent = element.offsetParent || docElement;\r\n if(nodeName(offsetParent, '#document')) return docElement.documentElement;\r\n while(offsetParent && !nodeName(offsetParent, 'html') && fn.css(offsetParent, 'position') === 'static') {\r\n offsetParent = offsetParent.offsetParent;\r\n }\r\n return offsetParent || docElement.documentElement;\r\n };\r\n\r\n /**\r\n * Provides equivalent of jQuery's height function\r\n * @required-by bootstrap-affix\r\n * @url http://api.jquery.com/height/\r\n * @param element\r\n * @param outer\r\n */\r\n fn.height = function(element, outer) {\r\n var value = element.offsetHeight;\r\n if(outer) {\r\n value += fn.css(element, 'marginTop', true) + fn.css(element, 'marginBottom', true);\r\n } else {\r\n value -= fn.css(element, 'paddingTop', true) + fn.css(element, 'paddingBottom', true) + fn.css(element, 'borderTopWidth', true) + fn.css(element, 'borderBottomWidth', true);\r\n }\r\n return value;\r\n };\r\n\r\n /**\r\n * Provides equivalent of jQuery's width function\r\n * @required-by bootstrap-affix\r\n * @url http://api.jquery.com/width/\r\n * @param element\r\n * @param outer\r\n */\r\n fn.width = function(element, outer) {\r\n var value = element.offsetWidth;\r\n if(outer) {\r\n value += fn.css(element, 'marginLeft', true) + fn.css(element, 'marginRight', true);\r\n } else {\r\n value -= fn.css(element, 'paddingLeft', true) + fn.css(element, 'paddingRight', true) + fn.css(element, 'borderLeftWidth', true) + fn.css(element, 'borderRightWidth', true);\r\n }\r\n return value;\r\n };\r\n\r\n return fn;\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.helpers.parseOptions', [])\r\n\r\n .provider('$parseOptions', function() {\r\n\r\n var defaults = this.defaults = {\r\n regexp: /^\\s*(.*?)(?:\\s+as\\s+(.*?))?(?:\\s+group\\s+by\\s+(.*))?\\s+for\\s+(?:([\\$\\w][\\$\\w]*)|(?:\\(\\s*([\\$\\w][\\$\\w]*)\\s*,\\s*([\\$\\w][\\$\\w]*)\\s*\\)))\\s+in\\s+(.*?)(?:\\s+track\\s+by\\s+(.*?))?$/\r\n };\r\n\r\n this.$get = function($parse, $q) {\r\n\r\n function ParseOptionsFactory(attr, config) {\r\n\r\n var $parseOptions = {};\r\n\r\n // Common vars\r\n var options = angular.extend({}, defaults, config);\r\n $parseOptions.$values = [];\r\n\r\n // Private vars\r\n var match, displayFn, valueName, keyName, groupByFn, valueFn, valuesFn;\r\n\r\n $parseOptions.init = function() {\r\n $parseOptions.$match = match = attr.match(options.regexp);\r\n displayFn = $parse(match[2] || match[1]),\r\n valueName = match[4] || match[6],\r\n keyName = match[5],\r\n groupByFn = $parse(match[3] || ''),\r\n valueFn = $parse(match[2] ? match[1] : valueName),\r\n valuesFn = $parse(match[7]);\r\n };\r\n\r\n $parseOptions.valuesFn = function(scope, controller) {\r\n return $q.when(valuesFn(scope, controller))\r\n .then(function(values) {\r\n $parseOptions.$values = values ? parseValues(values, scope) : {};\r\n return $parseOptions.$values;\r\n });\r\n };\r\n\r\n $parseOptions.displayValue = function(modelValue) {\r\n var scope = {};\r\n scope[valueName] = modelValue;\r\n return displayFn(scope);\r\n };\r\n\r\n // Private functions\r\n\r\n function parseValues(values, scope) {\r\n return values.map(function(match, index) {\r\n var locals = {}, label, value;\r\n locals[valueName] = match;\r\n label = displayFn(scope, locals);\r\n value = valueFn(scope, locals);\r\n return {label: label, value: value, index: index};\r\n });\r\n }\r\n\r\n $parseOptions.init();\r\n return $parseOptions;\r\n\r\n }\r\n\r\n return ParseOptionsFactory;\r\n\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\n(angular.version.minor < 3 && angular.version.dot < 14) && angular.module('ng')\r\n\r\n.factory('$$rAF', function($window, $timeout) {\r\n\r\n var requestAnimationFrame = $window.requestAnimationFrame ||\r\n $window.webkitRequestAnimationFrame ||\r\n $window.mozRequestAnimationFrame;\r\n\r\n var cancelAnimationFrame = $window.cancelAnimationFrame ||\r\n $window.webkitCancelAnimationFrame ||\r\n $window.mozCancelAnimationFrame ||\r\n $window.webkitCancelRequestAnimationFrame;\r\n\r\n var rafSupported = !!requestAnimationFrame;\r\n var raf = rafSupported ?\r\n function(fn) {\r\n var id = requestAnimationFrame(fn);\r\n return function() {\r\n cancelAnimationFrame(id);\r\n };\r\n } :\r\n function(fn) {\r\n var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666\r\n return function() {\r\n $timeout.cancel(timer);\r\n };\r\n };\r\n\r\n raf.supported = rafSupported;\r\n\r\n return raf;\r\n\r\n});\r\n\r\n// .factory('$$animateReflow', function($$rAF, $document) {\r\n\r\n// var bodyEl = $document[0].body;\r\n\r\n// return function(fn) {\r\n// //the returned function acts as the cancellation function\r\n// return $$rAF(function() {\r\n// //the line below will force the browser to perform a repaint\r\n// //so that all the animated elements within the animation frame\r\n// //will be properly updated and drawn on screen. This is\r\n// //required to perform multi-class CSS based animations with\r\n// //Firefox. DO NOT REMOVE THIS LINE.\r\n// var a = bodyEl.offsetWidth + 1;\r\n// fn();\r\n// });\r\n// };\r\n\r\n// });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.aside', ['mgcrea.ngStrap.modal'])\r\n\r\n .provider('$aside', function() {\r\n\r\n var defaults = this.defaults = {\r\n animation: 'am-fade-and-slide-right',\r\n prefixClass: 'aside',\r\n prefixEvent: 'aside',\r\n placement: 'right',\r\n template: 'aside/aside.tpl.html',\r\n contentTemplate: false,\r\n container: false,\r\n element: null,\r\n backdrop: true,\r\n keyboard: true,\r\n html: false,\r\n show: true\r\n };\r\n\r\n this.$get = function($modal) {\r\n\r\n function AsideFactory(config) {\r\n\r\n var $aside = {};\r\n\r\n // Common vars\r\n var options = angular.extend({}, defaults, config);\r\n\r\n $aside = $modal(options);\r\n\r\n return $aside;\r\n\r\n }\r\n\r\n return AsideFactory;\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsAside', function($window, $sce, $aside) {\r\n\r\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\r\n\r\n return {\r\n restrict: 'EAC',\r\n scope: true,\r\n link: function postLink(scope, element, attr, transclusion) {\r\n // Directive options\r\n var options = {scope: scope, element: element, show: false};\r\n angular.forEach(['template', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation'], function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n // Support scope as data-attrs\r\n angular.forEach(['title', 'content'], function(key) {\r\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\r\n scope[key] = $sce.trustAsHtml(newValue);\r\n });\r\n });\r\n\r\n // Support scope as an object\r\n attr.bsAside && scope.$watch(attr.bsAside, function(newValue, oldValue) {\r\n if(angular.isObject(newValue)) {\r\n angular.extend(scope, newValue);\r\n } else {\r\n scope.content = newValue;\r\n }\r\n }, true);\r\n\r\n // Initialize aside\r\n var aside = $aside(options);\r\n\r\n // Trigger\r\n element.on(attr.trigger || 'click', aside.toggle);\r\n\r\n // Garbage collection\r\n scope.$on('$destroy', function() {\r\n if (aside) aside.destroy();\r\n options = null;\r\n aside = null;\r\n });\r\n\r\n }\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.modal', ['mgcrea.ngStrap.helpers.dimensions'])\r\n\r\n .provider('$modal', function() {\r\n\r\n var defaults = this.defaults = {\r\n animation: 'am-fade',\r\n backdropAnimation: 'am-fade',\r\n prefixClass: 'modal',\r\n prefixEvent: 'modal',\r\n placement: 'top',\r\n template: 'modal/modal.tpl.html',\r\n contentTemplate: false,\r\n container: false,\r\n element: null,\r\n backdrop: true,\r\n keyboard: true,\r\n html: false,\r\n show: true\r\n };\r\n\r\n this.$get = function($window, $rootScope, $compile, $q, $templateCache, $http, $animate, $timeout, $sce, dimensions) {\r\n\r\n var forEach = angular.forEach;\r\n var trim = String.prototype.trim;\r\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\r\n var bodyElement = angular.element($window.document.body);\r\n var htmlReplaceRegExp = /ng-bind=\"/ig;\r\n\r\n function ModalFactory(config) {\r\n\r\n var $modal = {};\r\n\r\n // Common vars\r\n var options = $modal.$options = angular.extend({}, defaults, config);\r\n $modal.$promise = fetchTemplate(options.template);\r\n var scope = $modal.$scope = options.scope && options.scope.$new() || $rootScope.$new();\r\n if(!options.element && !options.container) {\r\n options.container = 'body';\r\n }\r\n\r\n // Support scope as string options\r\n forEach(['title', 'content'], function(key) {\r\n if(options[key]) scope[key] = $sce.trustAsHtml(options[key]);\r\n });\r\n\r\n // Provide scope helpers\r\n scope.$hide = function() {\r\n scope.$$postDigest(function() {\r\n $modal.hide();\r\n });\r\n };\r\n scope.$show = function() {\r\n scope.$$postDigest(function() {\r\n $modal.show();\r\n });\r\n };\r\n scope.$toggle = function() {\r\n scope.$$postDigest(function() {\r\n $modal.toggle();\r\n });\r\n };\r\n // Publish isShown as a protected var on scope\r\n $modal.$isShown = scope.$isShown = false;\r\n\r\n // Support contentTemplate option\r\n if(options.contentTemplate) {\r\n $modal.$promise = $modal.$promise.then(function(template) {\r\n var templateEl = angular.element(template);\r\n return fetchTemplate(options.contentTemplate)\r\n .then(function(contentTemplate) {\r\n var contentEl = findElement('[ng-bind=\"content\"]', templateEl[0]).removeAttr('ng-bind').html(contentTemplate);\r\n // Drop the default footer as you probably don't want it if you use a custom contentTemplate\r\n if(!config.template) contentEl.next().remove();\r\n return templateEl[0].outerHTML;\r\n });\r\n });\r\n }\r\n\r\n // Fetch, compile then initialize modal\r\n var modalLinker, modalElement;\r\n var backdropElement = angular.element('
');\r\n $modal.$promise.then(function(template) {\r\n if(angular.isObject(template)) template = template.data;\r\n if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html=\"');\r\n template = trim.apply(template);\r\n modalLinker = $compile(template);\r\n $modal.init();\r\n });\r\n\r\n $modal.init = function() {\r\n\r\n // Options: show\r\n if(options.show) {\r\n scope.$$postDigest(function() {\r\n $modal.show();\r\n });\r\n }\r\n\r\n };\r\n\r\n $modal.destroy = function() {\r\n\r\n // Remove element\r\n if(modalElement) {\r\n modalElement.remove();\r\n modalElement = null;\r\n }\r\n if(backdropElement) {\r\n backdropElement.remove();\r\n backdropElement = null;\r\n }\r\n\r\n // Destroy scope\r\n scope.$destroy();\r\n\r\n };\r\n\r\n $modal.show = function() {\r\n if($modal.$isShown) return;\r\n\r\n if(scope.$emit(options.prefixEvent + '.show.before', $modal).defaultPrevented) {\r\n return;\r\n }\r\n var parent, after;\r\n if(angular.isElement(options.container)) {\r\n parent = options.container;\r\n after = options.container[0].lastChild ? angular.element(options.container[0].lastChild) : null;\r\n } else {\r\n if (options.container) {\r\n parent = findElement(options.container);\r\n after = parent[0].lastChild ? angular.element(parent[0].lastChild) : null;\r\n } else {\r\n parent = null;\r\n after = options.element;\r\n }\r\n }\r\n\r\n // Fetch a cloned element linked from template\r\n modalElement = $modal.$element = modalLinker(scope, function(clonedElement, scope) {});\r\n\r\n // Set the initial positioning.\r\n modalElement.css({display: 'block'}).addClass(options.placement);\r\n\r\n // Options: animation\r\n if(options.animation) {\r\n if(options.backdrop) {\r\n backdropElement.addClass(options.backdropAnimation);\r\n }\r\n modalElement.addClass(options.animation);\r\n }\r\n\r\n if(options.backdrop) {\r\n $animate.enter(backdropElement, bodyElement, null);\r\n }\r\n // Support v1.3+ $animate\r\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\r\n var promise = $animate.enter(modalElement, parent, after, enterAnimateCallback);\r\n if(promise && promise.then) promise.then(enterAnimateCallback);\r\n\r\n $modal.$isShown = scope.$isShown = true;\r\n safeDigest(scope);\r\n // Focus once the enter-animation has started\r\n // Weird PhantomJS bug hack\r\n var el = modalElement[0];\r\n requestAnimationFrame(function() {\r\n el.focus();\r\n });\r\n\r\n bodyElement.addClass(options.prefixClass + '-open');\r\n if(options.animation) {\r\n bodyElement.addClass(options.prefixClass + '-with-' + options.animation);\r\n }\r\n\r\n // Bind events\r\n if(options.backdrop) {\r\n modalElement.on('click', hideOnBackdropClick);\r\n backdropElement.on('click', hideOnBackdropClick);\r\n backdropElement.on('wheel', preventEventDefault);\r\n }\r\n if(options.keyboard) {\r\n modalElement.on('keyup', $modal.$onKeyUp);\r\n }\r\n };\r\n\r\n function enterAnimateCallback() {\r\n scope.$emit(options.prefixEvent + '.show', $modal);\r\n }\r\n\r\n $modal.hide = function() {\r\n if(!$modal.$isShown) return;\r\n\r\n if(scope.$emit(options.prefixEvent + '.hide.before', $modal).defaultPrevented) {\r\n return;\r\n }\r\n var promise = $animate.leave(modalElement, leaveAnimateCallback);\r\n // Support v1.3+ $animate\r\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\r\n if(promise && promise.then) promise.then(leaveAnimateCallback);\r\n\r\n if(options.backdrop) {\r\n $animate.leave(backdropElement);\r\n }\r\n $modal.$isShown = scope.$isShown = false;\r\n safeDigest(scope);\r\n\r\n // Unbind events\r\n if(options.backdrop) {\r\n modalElement.off('click', hideOnBackdropClick);\r\n backdropElement.off('click', hideOnBackdropClick);\r\n backdropElement.off('wheel', preventEventDefault);\r\n }\r\n if(options.keyboard) {\r\n modalElement.off('keyup', $modal.$onKeyUp);\r\n }\r\n };\r\n\r\n function leaveAnimateCallback() {\r\n scope.$emit(options.prefixEvent + '.hide', $modal);\r\n bodyElement.removeClass(options.prefixClass + '-open');\r\n if(options.animation) {\r\n bodyElement.removeClass(options.prefixClass + '-with-' + options.animation);\r\n }\r\n }\r\n\r\n $modal.toggle = function() {\r\n\r\n $modal.$isShown ? $modal.hide() : $modal.show();\r\n\r\n };\r\n\r\n $modal.focus = function() {\r\n modalElement[0].focus();\r\n };\r\n\r\n // Protected methods\r\n\r\n $modal.$onKeyUp = function(evt) {\r\n\r\n if (evt.which === 27 && $modal.$isShown) {\r\n $modal.hide();\r\n evt.stopPropagation();\r\n }\r\n\r\n };\r\n\r\n // Private methods\r\n\r\n function hideOnBackdropClick(evt) {\r\n if(evt.target !== evt.currentTarget) return;\r\n options.backdrop === 'static' ? $modal.focus() : $modal.hide();\r\n }\r\n\r\n function preventEventDefault(evt) {\r\n evt.preventDefault();\r\n }\r\n\r\n return $modal;\r\n\r\n }\r\n\r\n // Helper functions\r\n\r\n function safeDigest(scope) {\r\n scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();\r\n }\r\n\r\n function findElement(query, element) {\r\n return angular.element((element || document).querySelectorAll(query));\r\n }\r\n\r\n var fetchPromises = {};\r\n function fetchTemplate(template) {\r\n if(fetchPromises[template]) return fetchPromises[template];\r\n return (fetchPromises[template] = $q.when($templateCache.get(template) || $http.get(template))\r\n .then(function(res) {\r\n if(angular.isObject(res)) {\r\n $templateCache.put(template, res.data);\r\n return res.data;\r\n }\r\n return res;\r\n }));\r\n }\r\n\r\n return ModalFactory;\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsModal', function($window, $sce, $modal) {\r\n\r\n return {\r\n restrict: 'EAC',\r\n scope: true,\r\n link: function postLink(scope, element, attr, transclusion) {\r\n\r\n // Directive options\r\n var options = {scope: scope, element: element, show: false};\r\n angular.forEach(['template', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation'], function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n // Support scope as data-attrs\r\n angular.forEach(['title', 'content'], function(key) {\r\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\r\n scope[key] = $sce.trustAsHtml(newValue);\r\n });\r\n });\r\n\r\n // Support scope as an object\r\n attr.bsModal && scope.$watch(attr.bsModal, function(newValue, oldValue) {\r\n if(angular.isObject(newValue)) {\r\n angular.extend(scope, newValue);\r\n } else {\r\n scope.content = newValue;\r\n }\r\n }, true);\r\n\r\n // Initialize modal\r\n var modal = $modal(options);\r\n\r\n // Trigger\r\n element.on(attr.trigger || 'click', modal.toggle);\r\n\r\n // Garbage collection\r\n scope.$on('$destroy', function() {\r\n if (modal) modal.destroy();\r\n options = null;\r\n modal = null;\r\n });\r\n\r\n }\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.navbar', [])\r\n\r\n .provider('$navbar', function() {\r\n\r\n var defaults = this.defaults = {\r\n activeClass: 'active',\r\n routeAttr: 'data-match-route',\r\n strict: false\r\n };\r\n\r\n this.$get = function() {\r\n return {defaults: defaults};\r\n };\r\n\r\n })\r\n\r\n .directive('bsNavbar', function($window, $location, $navbar) {\r\n\r\n var defaults = $navbar.defaults;\r\n\r\n return {\r\n restrict: 'A',\r\n link: function postLink(scope, element, attr, controller) {\r\n\r\n // Directive options\r\n var options = angular.copy(defaults);\r\n angular.forEach(Object.keys(defaults), function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n // Watch for the $location\r\n scope.$watch(function() {\r\n\r\n return $location.path();\r\n\r\n }, function(newValue, oldValue) {\r\n\r\n var liElements = element[0].querySelectorAll('li[' + options.routeAttr + ']');\r\n\r\n angular.forEach(liElements, function(li) {\r\n\r\n var liElement = angular.element(li);\r\n var pattern = liElement.attr(options.routeAttr).replace('/', '\\\\/');\r\n if(options.strict) {\r\n pattern = '^' + pattern + '$';\r\n }\r\n var regexp = new RegExp(pattern, ['i']);\r\n\r\n if(regexp.test(newValue)) {\r\n liElement.addClass(options.activeClass);\r\n } else {\r\n liElement.removeClass(options.activeClass);\r\n }\r\n\r\n });\r\n\r\n });\r\n\r\n }\r\n\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.scrollspy', ['mgcrea.ngStrap.helpers.debounce', 'mgcrea.ngStrap.helpers.dimensions'])\r\n\r\n .provider('$scrollspy', function() {\r\n\r\n // Pool of registered spies\r\n var spies = this.$$spies = {};\r\n\r\n var defaults = this.defaults = {\r\n debounce: 150,\r\n throttle: 100,\r\n offset: 100\r\n };\r\n\r\n this.$get = function($window, $document, $rootScope, dimensions, debounce, throttle) {\r\n\r\n var windowEl = angular.element($window);\r\n var docEl = angular.element($document.prop('documentElement'));\r\n var bodyEl = angular.element($window.document.body);\r\n\r\n // Helper functions\r\n\r\n function nodeName(element, name) {\r\n return element[0].nodeName && element[0].nodeName.toLowerCase() === name.toLowerCase();\r\n }\r\n\r\n function ScrollSpyFactory(config) {\r\n\r\n // Common vars\r\n var options = angular.extend({}, defaults, config);\r\n if(!options.element) options.element = bodyEl;\r\n var isWindowSpy = nodeName(options.element, 'body');\r\n var scrollEl = isWindowSpy ? windowEl : options.element;\r\n var scrollId = isWindowSpy ? 'window' : options.id;\r\n\r\n // Use existing spy\r\n if(spies[scrollId]) {\r\n spies[scrollId].$$count++;\r\n return spies[scrollId];\r\n }\r\n\r\n var $scrollspy = {};\r\n\r\n // Private vars\r\n var unbindViewContentLoaded, unbindIncludeContentLoaded;\r\n var trackedElements = $scrollspy.$trackedElements = [];\r\n var sortedElements = [];\r\n var activeTarget;\r\n var debouncedCheckPosition;\r\n var throttledCheckPosition;\r\n var debouncedCheckOffsets;\r\n var viewportHeight;\r\n var scrollTop;\r\n\r\n $scrollspy.init = function() {\r\n\r\n // Setup internal ref counter\r\n this.$$count = 1;\r\n\r\n // Bind events\r\n debouncedCheckPosition = debounce(this.checkPosition, options.debounce);\r\n throttledCheckPosition = throttle(this.checkPosition, options.throttle);\r\n scrollEl.on('click', this.checkPositionWithEventLoop);\r\n windowEl.on('resize', debouncedCheckPosition);\r\n scrollEl.on('scroll', throttledCheckPosition);\r\n\r\n debouncedCheckOffsets = debounce(this.checkOffsets, options.debounce);\r\n unbindViewContentLoaded = $rootScope.$on('$viewContentLoaded', debouncedCheckOffsets);\r\n unbindIncludeContentLoaded = $rootScope.$on('$includeContentLoaded', debouncedCheckOffsets);\r\n debouncedCheckOffsets();\r\n\r\n // Register spy for reuse\r\n if(scrollId) {\r\n spies[scrollId] = $scrollspy;\r\n }\r\n\r\n };\r\n\r\n $scrollspy.destroy = function() {\r\n\r\n // Check internal ref counter\r\n this.$$count--;\r\n if(this.$$count > 0) {\r\n return;\r\n }\r\n\r\n // Unbind events\r\n scrollEl.off('click', this.checkPositionWithEventLoop);\r\n windowEl.off('resize', debouncedCheckPosition);\r\n scrollEl.off('scroll', throttledCheckPosition);\r\n unbindViewContentLoaded();\r\n unbindIncludeContentLoaded();\r\n if (scrollId) {\r\n delete spies[scrollId];\r\n }\r\n };\r\n\r\n $scrollspy.checkPosition = function() {\r\n\r\n // Not ready yet\r\n if(!sortedElements.length) return;\r\n\r\n // Calculate the scroll position\r\n scrollTop = (isWindowSpy ? $window.pageYOffset : scrollEl.prop('scrollTop')) || 0;\r\n\r\n // Calculate the viewport height for use by the components\r\n viewportHeight = Math.max($window.innerHeight, docEl.prop('clientHeight'));\r\n\r\n // Activate first element if scroll is smaller\r\n if(scrollTop < sortedElements[0].offsetTop && activeTarget !== sortedElements[0].target) {\r\n return $scrollspy.$activateElement(sortedElements[0]);\r\n }\r\n\r\n // Activate proper element\r\n for (var i = sortedElements.length; i--;) {\r\n if(angular.isUndefined(sortedElements[i].offsetTop) || sortedElements[i].offsetTop === null) continue;\r\n if(activeTarget === sortedElements[i].target) continue;\r\n if(scrollTop < sortedElements[i].offsetTop) continue;\r\n if(sortedElements[i + 1] && scrollTop > sortedElements[i + 1].offsetTop) continue;\r\n return $scrollspy.$activateElement(sortedElements[i]);\r\n }\r\n\r\n };\r\n\r\n $scrollspy.checkPositionWithEventLoop = function() {\r\n // IE 9 throws an error if we use 'this' instead of '$scrollspy'\r\n // in this setTimeout call\r\n setTimeout($scrollspy.checkPosition, 1);\r\n };\r\n\r\n // Protected methods\r\n\r\n $scrollspy.$activateElement = function(element) {\r\n if(activeTarget) {\r\n var activeElement = $scrollspy.$getTrackedElement(activeTarget);\r\n if(activeElement) {\r\n activeElement.source.removeClass('active');\r\n if(nodeName(activeElement.source, 'li') && nodeName(activeElement.source.parent().parent(), 'li')) {\r\n activeElement.source.parent().parent().removeClass('active');\r\n }\r\n }\r\n }\r\n activeTarget = element.target;\r\n element.source.addClass('active');\r\n if(nodeName(element.source, 'li') && nodeName(element.source.parent().parent(), 'li')) {\r\n element.source.parent().parent().addClass('active');\r\n }\r\n };\r\n\r\n $scrollspy.$getTrackedElement = function(target) {\r\n return trackedElements.filter(function(obj) {\r\n return obj.target === target;\r\n })[0];\r\n };\r\n\r\n // Track offsets behavior\r\n\r\n $scrollspy.checkOffsets = function() {\r\n\r\n angular.forEach(trackedElements, function(trackedElement) {\r\n var targetElement = document.querySelector(trackedElement.target);\r\n trackedElement.offsetTop = targetElement ? dimensions.offset(targetElement).top : null;\r\n if(options.offset && trackedElement.offsetTop !== null) trackedElement.offsetTop -= options.offset * 1;\r\n });\r\n\r\n sortedElements = trackedElements\r\n .filter(function(el) {\r\n return el.offsetTop !== null;\r\n })\r\n .sort(function(a, b) {\r\n return a.offsetTop - b.offsetTop;\r\n });\r\n\r\n debouncedCheckPosition();\r\n\r\n };\r\n\r\n $scrollspy.trackElement = function(target, source) {\r\n trackedElements.push({target: target, source: source});\r\n };\r\n\r\n $scrollspy.untrackElement = function(target, source) {\r\n var toDelete;\r\n for (var i = trackedElements.length; i--;) {\r\n if(trackedElements[i].target === target && trackedElements[i].source === source) {\r\n toDelete = i;\r\n break;\r\n }\r\n }\r\n trackedElements = trackedElements.splice(toDelete, 1);\r\n };\r\n\r\n $scrollspy.activate = function(i) {\r\n trackedElements[i].addClass('active');\r\n };\r\n\r\n // Initialize plugin\r\n\r\n $scrollspy.init();\r\n return $scrollspy;\r\n\r\n }\r\n\r\n return ScrollSpyFactory;\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsScrollspy', function($rootScope, debounce, dimensions, $scrollspy) {\r\n\r\n return {\r\n restrict: 'EAC',\r\n link: function postLink(scope, element, attr) {\r\n\r\n var options = {scope: scope};\r\n angular.forEach(['offset', 'target'], function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n var scrollspy = $scrollspy(options);\r\n scrollspy.trackElement(options.target, element);\r\n\r\n scope.$on('$destroy', function() {\r\n if (scrollspy) {\r\n scrollspy.untrackElement(options.target, element);\r\n scrollspy.destroy();\r\n }\r\n options = null;\r\n scrollspy = null;\r\n });\r\n\r\n }\r\n };\r\n\r\n })\r\n\r\n\r\n .directive('bsScrollspyList', function($rootScope, debounce, dimensions, $scrollspy) {\r\n\r\n return {\r\n restrict: 'A',\r\n compile: function postLink(element, attr) {\r\n var children = element[0].querySelectorAll('li > a[href]');\r\n angular.forEach(children, function(child) {\r\n var childEl = angular.element(child);\r\n childEl.parent().attr('bs-scrollspy', '').attr('data-target', childEl.attr('href'));\r\n });\r\n }\r\n\r\n };\r\n\r\n });\r\n","'use strict';\n\nangular.module('mgcrea.ngStrap.progressbar', [])\n.provider('$progressbar', function (){\n var defaults = {\n barType: '',\n animate: function (){ return true;}\n };\n\n this.$get = function (){\n return {\n defaults: defaults\n };\n };\n })\n .directive('bsProgressbar', function ($progressbar){\n return {\n restrict: 'E',\n transclude: true,\n replace: true,\n templateUrl: 'progressbar/progressbar.tpl.html',\n scope:{\n value: '=',\n type: '@',\n animate: '&'\n },\n link: function (scope, element, attr){\n scope.type = scope.type || $progressbar.defaults.barType;\n scope.animate = angular.isDefined(scope.animate()) ? scope.animate : $progressbar.defaults.animate;\n console.log(scope.animate(), $progressbar.defaults.animate, angular.isDefined(scope.animate));\n scope.$watch('type', function (){\n if(scope.type) {\n scope.barClass = 'progress-bar-' + scope.type;\n }\n else{\n scope.barClass = null;\n }\n });\n }\n };\n });\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.select', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions'])\r\n\r\n .provider('$select', function() {\r\n\r\n var defaults = this.defaults = {\r\n animation: 'am-fade',\r\n prefixClass: 'select',\r\n prefixEvent: '$select',\r\n placement: 'bottom-left',\r\n template: 'select/select.tpl.html',\r\n trigger: 'focus',\r\n container: false,\r\n keyboard: true,\r\n html: false,\r\n delay: 0,\r\n multiple: false,\r\n allNoneButtons: false,\r\n sort: true,\r\n caretHtml: ' ',\r\n placeholder: 'Choose among the following...',\r\n allText: 'All',\r\n noneText: 'None',\r\n maxLength: 3,\r\n maxLengthHtml: 'selected',\r\n iconCheckmark: 'glyphicon glyphicon-ok'\r\n };\r\n\r\n this.$get = function($window, $document, $rootScope, $tooltip, $timeout) {\r\n\r\n var bodyEl = angular.element($window.document.body);\r\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\r\n var isTouch = ('createTouch' in $window.document) && isNative;\r\n\r\n function SelectFactory(element, controller, config) {\r\n\r\n var $select = {};\r\n\r\n // Common vars\r\n var options = angular.extend({}, defaults, config);\r\n\r\n $select = $tooltip(element, options);\r\n var scope = $select.$scope;\r\n\r\n scope.$matches = [];\r\n scope.$activeIndex = 0;\r\n scope.$isMultiple = options.multiple;\r\n scope.$showAllNoneButtons = options.allNoneButtons && options.multiple;\r\n scope.$iconCheckmark = options.iconCheckmark;\r\n scope.$allText = options.allText;\r\n scope.$noneText = options.noneText;\r\n\r\n scope.$activate = function(index) {\r\n scope.$$postDigest(function() {\r\n $select.activate(index);\r\n });\r\n };\r\n\r\n scope.$select = function(index, evt) {\r\n scope.$$postDigest(function() {\r\n $select.select(index);\r\n });\r\n };\r\n\r\n scope.$isVisible = function() {\r\n return $select.$isVisible();\r\n };\r\n\r\n scope.$isActive = function(index) {\r\n return $select.$isActive(index);\r\n };\r\n\r\n scope.$selectAll = function () {\r\n for (var i = 0; i < scope.$matches.length; i++) {\r\n if (!scope.$isActive(i)) {\r\n scope.$select(i);\r\n }\r\n }\r\n };\r\n\r\n scope.$selectNone = function () {\r\n for (var i = 0; i < scope.$matches.length; i++) {\r\n if (scope.$isActive(i)) {\r\n scope.$select(i);\r\n }\r\n }\r\n };\r\n\r\n // Public methods\r\n\r\n $select.update = function(matches) {\r\n scope.$matches = matches;\r\n $select.$updateActiveIndex();\r\n };\r\n\r\n $select.activate = function(index) {\r\n if(options.multiple) {\r\n scope.$activeIndex.sort();\r\n $select.$isActive(index) ? scope.$activeIndex.splice(scope.$activeIndex.indexOf(index), 1) : scope.$activeIndex.push(index);\r\n if(options.sort) scope.$activeIndex.sort();\r\n } else {\r\n scope.$activeIndex = index;\r\n }\r\n return scope.$activeIndex;\r\n };\r\n\r\n $select.select = function(index) {\r\n var value = scope.$matches[index].value;\r\n scope.$apply(function() {\r\n $select.activate(index);\r\n if(options.multiple) {\r\n controller.$setViewValue(scope.$activeIndex.map(function(index) {\r\n return scope.$matches[index].value;\r\n }));\r\n } else {\r\n controller.$setViewValue(value);\r\n // Hide if single select\r\n $select.hide();\r\n }\r\n });\r\n // Emit event\r\n scope.$emit(options.prefixEvent + '.select', value, index);\r\n };\r\n\r\n // Protected methods\r\n\r\n $select.$updateActiveIndex = function() {\r\n if(controller.$modelValue && scope.$matches.length) {\r\n if(options.multiple && angular.isArray(controller.$modelValue)) {\r\n scope.$activeIndex = controller.$modelValue.map(function(value) {\r\n return $select.$getIndex(value);\r\n });\r\n } else {\r\n scope.$activeIndex = $select.$getIndex(controller.$modelValue);\r\n }\r\n } else if(scope.$activeIndex >= scope.$matches.length) {\r\n scope.$activeIndex = options.multiple ? [] : 0;\r\n }\r\n };\r\n\r\n $select.$isVisible = function() {\r\n if(!options.minLength || !controller) {\r\n return scope.$matches.length;\r\n }\r\n // minLength support\r\n return scope.$matches.length && controller.$viewValue.length >= options.minLength;\r\n };\r\n\r\n $select.$isActive = function(index) {\r\n if(options.multiple) {\r\n return scope.$activeIndex.indexOf(index) !== -1;\r\n } else {\r\n return scope.$activeIndex === index;\r\n }\r\n };\r\n\r\n $select.$getIndex = function(value) {\r\n var l = scope.$matches.length, i = l;\r\n if(!l) return;\r\n for(i = l; i--;) {\r\n if(scope.$matches[i].value === value) break;\r\n }\r\n if(i < 0) return;\r\n return i;\r\n };\r\n\r\n $select.$onMouseDown = function(evt) {\r\n // Prevent blur on mousedown on .dropdown-menu\r\n evt.preventDefault();\r\n evt.stopPropagation();\r\n // Emulate click for mobile devices\r\n if(isTouch) {\r\n var targetEl = angular.element(evt.target);\r\n targetEl.triggerHandler('click');\r\n }\r\n };\r\n\r\n $select.$onKeyDown = function(evt) {\r\n if (!/(9|13|38|40)/.test(evt.keyCode)) return;\r\n evt.preventDefault();\r\n evt.stopPropagation();\r\n\r\n // Select with enter\r\n if(!options.multiple && (evt.keyCode === 13 || evt.keyCode === 9)) {\r\n return $select.select(scope.$activeIndex);\r\n }\r\n\r\n // Navigate with keyboard\r\n if(evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--;\r\n else if(evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++;\r\n else if(angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0;\r\n scope.$digest();\r\n };\r\n\r\n // Overrides\r\n\r\n var _show = $select.show;\r\n $select.show = function() {\r\n _show();\r\n if(options.multiple) {\r\n $select.$element.addClass('select-multiple');\r\n }\r\n // use timeout to hookup the events to prevent\r\n // event bubbling from being processed imediately.\r\n $timeout(function() {\r\n $select.$element.on(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown);\r\n if(options.keyboard) {\r\n element.on('keydown', $select.$onKeyDown);\r\n }\r\n }, 0, false);\r\n };\r\n\r\n var _hide = $select.hide;\r\n $select.hide = function() {\r\n $select.$element.off(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown);\r\n if(options.keyboard) {\r\n element.off('keydown', $select.$onKeyDown);\r\n }\r\n _hide(true);\r\n };\r\n\r\n return $select;\r\n\r\n }\r\n\r\n SelectFactory.defaults = defaults;\r\n return SelectFactory;\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsSelect', function($window, $parse, $q, $select, $parseOptions) {\r\n\r\n var defaults = $select.defaults;\r\n\r\n return {\r\n restrict: 'EAC',\r\n require: 'ngModel',\r\n link: function postLink(scope, element, attr, controller) {\r\n\r\n // Directive options\r\n var options = {scope: scope, placeholder: defaults.placeholder};\r\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'placeholder', 'multiple', 'allNoneButtons', 'maxLength', 'maxLengthHtml', 'allText', 'noneText'], function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n // Add support for select markup\r\n if(element[0].nodeName.toLowerCase() === 'select') {\r\n var inputEl = element;\r\n inputEl.css('display', 'none');\r\n element = angular.element(' ');\r\n inputEl.after(element);\r\n }\r\n\r\n // Build proper ngOptions\r\n var parsedOptions = $parseOptions(attr.ngOptions);\r\n\r\n // Initialize select\r\n var select = $select(element, controller, options);\r\n\r\n // Watch ngOptions values before filtering for changes\r\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').trim();\r\n scope.$watch(watchedOptions, function(newValue, oldValue) {\r\n // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue);\r\n parsedOptions.valuesFn(scope, controller)\r\n .then(function(values) {\r\n select.update(values);\r\n controller.$render();\r\n });\r\n }, true);\r\n\r\n // Watch model for changes\r\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\r\n // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue);\r\n select.$updateActiveIndex();\r\n controller.$render();\r\n }, true);\r\n\r\n // Model rendering in view\r\n controller.$render = function () {\r\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\r\n var selected, index;\r\n if(options.multiple && angular.isArray(controller.$modelValue)) {\r\n selected = controller.$modelValue.map(function(value) {\r\n index = select.$getIndex(value);\r\n return angular.isDefined(index) ? select.$scope.$matches[index].label : false;\r\n }).filter(angular.isDefined);\r\n if(selected.length > (options.maxLength || defaults.maxLength)) {\r\n selected = selected.length + ' ' + (options.maxLengthHtml || defaults.maxLengthHtml);\r\n } else {\r\n selected = selected.join(', ');\r\n }\r\n } else {\r\n index = select.$getIndex(controller.$modelValue);\r\n selected = angular.isDefined(index) ? select.$scope.$matches[index].label : false;\r\n }\r\n element.html((selected ? selected : options.placeholder) + defaults.caretHtml);\r\n };\r\n\r\n if(options.multiple){\r\n controller.$isEmpty = function(value){\r\n return !value || value.length === 0;\r\n };\r\n }\r\n\r\n // Garbage collection\r\n scope.$on('$destroy', function() {\r\n if (select) select.destroy();\r\n options = null;\r\n select = null;\r\n });\r\n\r\n }\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.tab', [])\r\n\r\n .provider('$tab', function() {\r\n\r\n var defaults = this.defaults = {\r\n animation: 'am-fade',\r\n template: 'tab/tab.tpl.html',\r\n navClass: 'nav-tabs',\r\n activeClass: 'active'\r\n };\r\n\r\n var controller = this.controller = function($scope, $element, $attrs) {\r\n var self = this;\r\n\r\n // Attributes options\r\n self.$options = angular.copy(defaults);\r\n angular.forEach(['animation', 'navClass', 'activeClass'], function(key) {\r\n if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];\r\n });\r\n\r\n // Publish options on scope\r\n $scope.$navClass = self.$options.navClass;\r\n $scope.$activeClass = self.$options.activeClass;\r\n\r\n self.$panes = $scope.$panes = [];\r\n\r\n // DEPRECATED: $viewChangeListeners, please use $activePaneChangeListeners\r\n // Because we deprecated ngModel usage, we rename viewChangeListeners to \r\n // activePaneChangeListeners to make more sense.\r\n self.$activePaneChangeListeners = self.$viewChangeListeners = [];\r\n\r\n self.$push = function(pane) {\r\n self.$panes.push(pane);\r\n };\r\n\r\n self.$remove = function(pane) {\r\n var index = self.$panes.indexOf(pane);\r\n var activeIndex = self.$panes.$active;\r\n\r\n // remove pane from $panes array\r\n self.$panes.splice(index, 1);\r\n\r\n if (index < activeIndex) {\r\n // we removed a pane before the active pane, so we need to \r\n // decrement the active pane index\r\n activeIndex--;\r\n }\r\n else if (index === activeIndex && activeIndex === self.$panes.length) {\r\n // we remove the active pane and it was the one at the end,\r\n // so select the previous one\r\n activeIndex--;\r\n }\r\n self.$setActive(activeIndex);\r\n };\r\n\r\n self.$panes.$active = 0;\r\n self.$setActive = $scope.$setActive = function(value) {\r\n self.$panes.$active = value;\r\n self.$activePaneChangeListeners.forEach(function(fn) {\r\n fn();\r\n });\r\n };\r\n\r\n };\r\n\r\n this.$get = function() {\r\n var $tab = {};\r\n $tab.defaults = defaults;\r\n $tab.controller = controller;\r\n return $tab;\r\n };\r\n\r\n })\r\n\r\n .directive('bsTabs', function($window, $animate, $tab, $parse) {\r\n\r\n var defaults = $tab.defaults;\r\n\r\n return {\r\n require: ['?ngModel', 'bsTabs'],\r\n transclude: true,\r\n scope: true,\r\n controller: ['$scope', '$element', '$attrs', $tab.controller],\r\n templateUrl: function(element, attr) {\r\n return attr.template || defaults.template;\r\n },\r\n link: function postLink(scope, element, attrs, controllers) {\r\n\r\n var ngModelCtrl = controllers[0];\r\n var bsTabsCtrl = controllers[1];\r\n\r\n // DEPRECATED: ngModel, please use bsActivePane\r\n // 'ngModel' is deprecated bacause if interferes with form validation\r\n // and status, so avoid using it here.\r\n if(ngModelCtrl) {\r\n console.warn('Usage of ngModel is deprecated, please use bsActivePane instead!');\r\n\r\n // Update the modelValue following\r\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\r\n ngModelCtrl.$setViewValue(bsTabsCtrl.$panes.$active);\r\n });\r\n\r\n // modelValue -> $formatters -> viewValue\r\n ngModelCtrl.$formatters.push(function(modelValue) {\r\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\r\n bsTabsCtrl.$setActive(modelValue * 1);\r\n return modelValue;\r\n });\r\n\r\n }\r\n\r\n if (attrs.bsActivePane) {\r\n // adapted from angularjs ngModelController bindings\r\n // https://github.com/angular/angular.js/blob/v1.3.1/src%2Fng%2Fdirective%2Finput.js#L1730\r\n var parsedBsActivePane = $parse(attrs.bsActivePane);\r\n\r\n // Update bsActivePane value with change\r\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\r\n parsedBsActivePane.assign(scope, bsTabsCtrl.$panes.$active);\r\n });\r\n\r\n // watch bsActivePane for value changes\r\n scope.$watch(attrs.bsActivePane, function(newValue, oldValue) {\r\n bsTabsCtrl.$setActive(newValue * 1);\r\n }, true);\r\n }\r\n }\r\n };\r\n\r\n })\r\n\r\n .directive('bsPane', function($window, $animate, $sce) {\r\n\r\n return {\r\n require: ['^?ngModel', '^bsTabs'],\r\n scope: true,\r\n link: function postLink(scope, element, attrs, controllers) {\r\n\r\n var ngModelCtrl = controllers[0];\r\n var bsTabsCtrl = controllers[1];\r\n\r\n // Add base class\r\n element.addClass('tab-pane');\r\n\r\n // Observe title attribute for change\r\n attrs.$observe('title', function(newValue, oldValue) {\r\n scope.title = $sce.trustAsHtml(newValue);\r\n });\r\n\r\n // Add animation class\r\n if(bsTabsCtrl.$options.animation) {\r\n element.addClass(bsTabsCtrl.$options.animation);\r\n }\r\n\r\n // Push pane to parent bsTabs controller\r\n bsTabsCtrl.$push(scope);\r\n\r\n // remove pane from tab controller when pane is destroyed\r\n scope.$on('$destroy', function() {\r\n bsTabsCtrl.$remove(scope);\r\n });\r\n\r\n function render() {\r\n var index = bsTabsCtrl.$panes.indexOf(scope);\r\n var active = bsTabsCtrl.$panes.$active;\r\n $animate[index === active ? 'addClass' : 'removeClass'](element, bsTabsCtrl.$options.activeClass);\r\n }\r\n\r\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\r\n render();\r\n });\r\n render();\r\n\r\n }\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.popover', ['mgcrea.ngStrap.tooltip'])\r\n\r\n .provider('$popover', function() {\r\n\r\n var defaults = this.defaults = {\r\n animation: 'am-fade',\r\n customClass: '',\r\n container: false,\r\n target: false,\r\n placement: 'right',\r\n template: 'popover/popover.tpl.html',\r\n contentTemplate: false,\r\n trigger: 'click',\r\n keyboard: true,\r\n html: false,\r\n title: '',\r\n content: '',\r\n delay: 0,\r\n autoClose: false\r\n };\r\n\r\n this.$get = function($tooltip) {\r\n\r\n function PopoverFactory(element, config) {\r\n\r\n // Common vars\r\n var options = angular.extend({}, defaults, config);\r\n\r\n var $popover = $tooltip(element, options);\r\n\r\n // Support scope as string options [/*title, */content]\r\n if(options.content) {\r\n $popover.$scope.content = options.content;\r\n }\r\n\r\n return $popover;\r\n\r\n }\r\n\r\n return PopoverFactory;\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsPopover', function($window, $sce, $popover) {\r\n\r\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\r\n\r\n return {\r\n restrict: 'EAC',\r\n scope: true,\r\n link: function postLink(scope, element, attr) {\r\n\r\n // Directive options\r\n var options = {scope: scope};\r\n angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'customClass', 'autoClose'], function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n // Support scope as data-attrs\r\n angular.forEach(['title', 'content'], function(key) {\r\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\r\n scope[key] = $sce.trustAsHtml(newValue);\r\n angular.isDefined(oldValue) && requestAnimationFrame(function() {\r\n popover && popover.$applyPlacement();\r\n });\r\n });\r\n });\r\n\r\n // Support scope as an object\r\n attr.bsPopover && scope.$watch(attr.bsPopover, function(newValue, oldValue) {\r\n if(angular.isObject(newValue)) {\r\n angular.extend(scope, newValue);\r\n } else {\r\n scope.content = newValue;\r\n }\r\n angular.isDefined(oldValue) && requestAnimationFrame(function() {\r\n popover && popover.$applyPlacement();\r\n });\r\n }, true);\r\n\r\n // Visibility binding support\r\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\r\n if(!popover || !angular.isDefined(newValue)) return;\r\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(popover),?/i);\r\n newValue === true ? popover.show() : popover.hide();\r\n });\r\n\r\n // Initialize popover\r\n var popover = $popover(element, options);\r\n\r\n // Garbage collection\r\n scope.$on('$destroy', function() {\r\n if (popover) popover.destroy();\r\n options = null;\r\n popover = null;\r\n });\r\n\r\n }\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions'])\r\n\r\n .provider('$tooltip', function() {\r\n\r\n var defaults = this.defaults = {\r\n animation: 'am-fade',\r\n customClass: '',\r\n prefixClass: 'tooltip',\r\n prefixEvent: 'tooltip',\r\n container: false,\r\n target: false,\r\n placement: 'top',\r\n template: 'tooltip/tooltip.tpl.html',\r\n contentTemplate: false,\r\n trigger: 'hover focus',\r\n keyboard: false,\r\n html: false,\r\n show: false,\r\n title: '',\r\n type: '',\r\n delay: 0,\r\n autoClose: false,\r\n bsEnabled: true\r\n };\r\n\r\n this.$get = function($window, $rootScope, $compile, $q, $templateCache, $http, $animate, $sce, dimensions, $$rAF, $timeout) {\r\n\r\n var trim = String.prototype.trim;\r\n var isTouch = 'createTouch' in $window.document;\r\n var htmlReplaceRegExp = /ng-bind=\"/ig;\r\n var $body = angular.element($window.document);\r\n\r\n function TooltipFactory(element, config) {\r\n\r\n var $tooltip = {};\r\n\r\n // Common vars\r\n var nodeName = element[0].nodeName.toLowerCase();\r\n var options = $tooltip.$options = angular.extend({}, defaults, config);\r\n $tooltip.$promise = fetchTemplate(options.template);\r\n var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new();\r\n if(options.delay && angular.isString(options.delay)) {\r\n var split = options.delay.split(',').map(parseFloat);\r\n options.delay = split.length > 1 ? {show: split[0], hide: split[1]} : split[0];\r\n }\r\n\r\n // Support scope as string options\r\n if(options.title) {\r\n scope.title = $sce.trustAsHtml(options.title);\r\n }\r\n\r\n // Provide scope helpers\r\n scope.$setEnabled = function(isEnabled) {\r\n scope.$$postDigest(function() {\r\n $tooltip.setEnabled(isEnabled);\r\n });\r\n };\r\n scope.$hide = function() {\r\n scope.$$postDigest(function() {\r\n $tooltip.hide();\r\n });\r\n };\r\n scope.$show = function() {\r\n scope.$$postDigest(function() {\r\n $tooltip.show();\r\n });\r\n };\r\n scope.$toggle = function() {\r\n scope.$$postDigest(function() {\r\n $tooltip.toggle();\r\n });\r\n };\r\n // Publish isShown as a protected var on scope\r\n $tooltip.$isShown = scope.$isShown = false;\r\n\r\n // Private vars\r\n var timeout, hoverState;\r\n\r\n // Support contentTemplate option\r\n if(options.contentTemplate) {\r\n $tooltip.$promise = $tooltip.$promise.then(function(template) {\r\n var templateEl = angular.element(template);\r\n return fetchTemplate(options.contentTemplate)\r\n .then(function(contentTemplate) {\r\n var contentEl = findElement('[ng-bind=\"content\"]', templateEl[0]);\r\n if(!contentEl.length) contentEl = findElement('[ng-bind=\"title\"]', templateEl[0]);\r\n contentEl.removeAttr('ng-bind').html(contentTemplate);\r\n return templateEl[0].outerHTML;\r\n });\r\n });\r\n }\r\n\r\n // Fetch, compile then initialize tooltip\r\n var tipLinker, tipElement, tipTemplate, tipContainer, tipScope;\r\n $tooltip.$promise.then(function(template) {\r\n if(angular.isObject(template)) template = template.data;\r\n if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html=\"');\r\n template = trim.apply(template);\r\n tipTemplate = template;\r\n tipLinker = $compile(template);\r\n $tooltip.init();\r\n });\r\n\r\n $tooltip.init = function() {\r\n\r\n // Options: delay\r\n if (options.delay && angular.isNumber(options.delay)) {\r\n options.delay = {\r\n show: options.delay,\r\n hide: options.delay\r\n };\r\n }\r\n\r\n // Replace trigger on touch devices ?\r\n // if(isTouch && options.trigger === defaults.trigger) {\r\n // options.trigger.replace(/hover/g, 'click');\r\n // }\r\n\r\n // Options : container\r\n if(options.container === 'self') {\r\n tipContainer = element;\r\n } else if(angular.isElement(options.container)) {\r\n tipContainer = options.container;\r\n } else if(options.container) {\r\n tipContainer = findElement(options.container);\r\n }\r\n\r\n // Options: trigger\r\n bindTriggerEvents();\r\n\r\n // Options: target\r\n if(options.target) {\r\n options.target = angular.isElement(options.target) ? options.target : findElement(options.target);\r\n }\r\n\r\n // Options: show\r\n if(options.show) {\r\n scope.$$postDigest(function() {\r\n options.trigger === 'focus' ? element[0].focus() : $tooltip.show();\r\n });\r\n }\r\n\r\n };\r\n\r\n $tooltip.destroy = function() {\r\n\r\n // Unbind events\r\n unbindTriggerEvents();\r\n\r\n // Remove element\r\n destroyTipElement();\r\n\r\n // Destroy scope\r\n scope.$destroy();\r\n\r\n };\r\n\r\n $tooltip.enter = function() {\r\n\r\n clearTimeout(timeout);\r\n hoverState = 'in';\r\n if (!options.delay || !options.delay.show) {\r\n return $tooltip.show();\r\n }\r\n\r\n timeout = setTimeout(function() {\r\n if (hoverState ==='in') $tooltip.show();\r\n }, options.delay.show);\r\n\r\n };\r\n\r\n $tooltip.show = function() {\r\n if (!options.bsEnabled || $tooltip.$isShown) return;\r\n\r\n scope.$emit(options.prefixEvent + '.show.before', $tooltip);\r\n var parent, after;\r\n if (options.container) {\r\n parent = tipContainer;\r\n if (tipContainer[0].lastChild) {\r\n after = angular.element(tipContainer[0].lastChild);\r\n } else {\r\n after = null;\r\n }\r\n } else {\r\n parent = null;\r\n after = element;\r\n }\r\n\r\n\r\n // Hide any existing tipElement\r\n if(tipElement) destroyTipElement();\r\n // Fetch a cloned element linked from template\r\n tipScope = $tooltip.$scope.$new();\r\n tipElement = $tooltip.$element = tipLinker(tipScope, function(clonedElement, scope) {});\r\n\r\n // Set the initial positioning. Make the tooltip invisible\r\n // so IE doesn't try to focus on it off screen.\r\n tipElement.css({top: '-9999px', left: '-9999px', display: 'block', visibility: 'hidden'});\r\n\r\n // Options: animation\r\n if(options.animation) tipElement.addClass(options.animation);\r\n // Options: type\r\n if(options.type) tipElement.addClass(options.prefixClass + '-' + options.type);\r\n // Options: custom classes\r\n if(options.customClass) tipElement.addClass(options.customClass);\r\n\r\n // Support v1.3+ $animate\r\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\r\n var promise = $animate.enter(tipElement, parent, after, enterAnimateCallback);\r\n if(promise && promise.then) promise.then(enterAnimateCallback);\r\n\r\n $tooltip.$isShown = scope.$isShown = true;\r\n safeDigest(scope);\r\n $$rAF(function () {\r\n $tooltip.$applyPlacement();\r\n\r\n // Once placed, make the tooltip visible\r\n if(tipElement) tipElement.css({visibility: 'visible'});\r\n }); // var a = bodyEl.offsetWidth + 1; ?\r\n\r\n // Bind events\r\n if(options.keyboard) {\r\n if(options.trigger !== 'focus') {\r\n $tooltip.focus();\r\n }\r\n bindKeyboardEvents();\r\n }\r\n\r\n if(options.autoClose) {\r\n bindAutoCloseEvents();\r\n }\r\n\r\n };\r\n\r\n function enterAnimateCallback() {\r\n scope.$emit(options.prefixEvent + '.show', $tooltip);\r\n }\r\n\r\n $tooltip.leave = function() {\r\n\r\n clearTimeout(timeout);\r\n hoverState = 'out';\r\n if (!options.delay || !options.delay.hide) {\r\n return $tooltip.hide();\r\n }\r\n timeout = setTimeout(function () {\r\n if (hoverState === 'out') {\r\n $tooltip.hide();\r\n }\r\n }, options.delay.hide);\r\n\r\n };\r\n\r\n var _blur;\r\n $tooltip.hide = function(blur) {\r\n\r\n if(!$tooltip.$isShown) return;\r\n scope.$emit(options.prefixEvent + '.hide.before', $tooltip);\r\n\r\n // store blur value for leaveAnimateCallback to use\r\n _blur = blur;\r\n\r\n // Support v1.3+ $animate\r\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\r\n var promise = $animate.leave(tipElement, leaveAnimateCallback);\r\n if(promise && promise.then) promise.then(leaveAnimateCallback);\r\n\r\n $tooltip.$isShown = scope.$isShown = false;\r\n safeDigest(scope);\r\n\r\n // Unbind events\r\n if(options.keyboard && tipElement !== null) {\r\n unbindKeyboardEvents();\r\n }\r\n\r\n if(options.autoClose && tipElement !== null) {\r\n unbindAutoCloseEvents();\r\n }\r\n };\r\n\r\n function leaveAnimateCallback() {\r\n scope.$emit(options.prefixEvent + '.hide', $tooltip);\r\n // Allow to blur the input when hidden, like when pressing enter key\r\n if(_blur && options.trigger === 'focus') {\r\n return element[0].blur();\r\n }\r\n\r\n // clean up child scopes\r\n destroyTipElement();\r\n }\r\n\r\n $tooltip.toggle = function() {\r\n $tooltip.$isShown ? $tooltip.leave() : $tooltip.enter();\r\n };\r\n\r\n $tooltip.focus = function() {\r\n tipElement[0].focus();\r\n };\r\n\r\n $tooltip.setEnabled = function(isEnabled) {\r\n options.bsEnabled = isEnabled;\r\n };\r\n\r\n // Protected methods\r\n\r\n $tooltip.$applyPlacement = function() {\r\n if(!tipElement) return;\r\n\r\n // Determine if we're doing an auto or normal placement\r\n var placement = options.placement,\r\n autoToken = /\\s?auto?\\s?/i,\r\n autoPlace = autoToken.test(placement);\r\n\r\n if (autoPlace) {\r\n placement = placement.replace(autoToken, '') || defaults.placement;\r\n }\r\n\r\n // Need to add the position class before we get\r\n // the offsets\r\n tipElement.addClass(options.placement);\r\n\r\n // Get the position of the target element\r\n // and the height and width of the tooltip so we can center it.\r\n var elementPosition = getPosition(),\r\n tipWidth = tipElement.prop('offsetWidth'),\r\n tipHeight = tipElement.prop('offsetHeight');\r\n\r\n // If we're auto placing, we need to check the positioning\r\n if (autoPlace) {\r\n var originalPlacement = placement;\r\n var container = options.container ? angular.element(document.querySelector(options.container)) : element.parent();\r\n var containerPosition = getPosition(container);\r\n\r\n // Determine if the vertical placement\r\n if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > containerPosition.bottom) {\r\n placement = originalPlacement.replace('bottom', 'top');\r\n } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < containerPosition.top) {\r\n placement = originalPlacement.replace('top', 'bottom');\r\n }\r\n\r\n // Determine the horizontal placement\r\n // The exotic placements of left and right are opposite of the standard placements. Their arrows are put on the left/right\r\n // and flow in the opposite direction of their placement.\r\n if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') &&\r\n elementPosition.right + tipWidth > containerPosition.width) {\r\n\r\n placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right');\r\n } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') &&\r\n elementPosition.left - tipWidth < containerPosition.left) {\r\n\r\n placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left');\r\n }\r\n\r\n tipElement.removeClass(originalPlacement).addClass(placement);\r\n }\r\n\r\n // Get the tooltip's top and left coordinates to center it with this directive.\r\n var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight);\r\n applyPlacementCss(tipPosition.top, tipPosition.left);\r\n };\r\n\r\n $tooltip.$onKeyUp = function(evt) {\r\n if (evt.which === 27 && $tooltip.$isShown) {\r\n $tooltip.hide();\r\n evt.stopPropagation();\r\n }\r\n };\r\n\r\n $tooltip.$onFocusKeyUp = function(evt) {\r\n if (evt.which === 27) {\r\n element[0].blur();\r\n evt.stopPropagation();\r\n }\r\n };\r\n\r\n $tooltip.$onFocusElementMouseDown = function(evt) {\r\n evt.preventDefault();\r\n evt.stopPropagation();\r\n // Some browsers do not auto-focus buttons (eg. Safari)\r\n $tooltip.$isShown ? element[0].blur() : element[0].focus();\r\n };\r\n\r\n // bind/unbind events\r\n function bindTriggerEvents() {\r\n var triggers = options.trigger.split(' ');\r\n angular.forEach(triggers, function(trigger) {\r\n if(trigger === 'click') {\r\n element.on('click', $tooltip.toggle);\r\n } else if(trigger !== 'manual') {\r\n element.on(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);\r\n element.on(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);\r\n nodeName === 'button' && trigger !== 'hover' && element.on(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);\r\n }\r\n });\r\n }\r\n\r\n function unbindTriggerEvents() {\r\n var triggers = options.trigger.split(' ');\r\n for (var i = triggers.length; i--;) {\r\n var trigger = triggers[i];\r\n if(trigger === 'click') {\r\n element.off('click', $tooltip.toggle);\r\n } else if(trigger !== 'manual') {\r\n element.off(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);\r\n element.off(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);\r\n nodeName === 'button' && trigger !== 'hover' && element.off(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);\r\n }\r\n }\r\n }\r\n\r\n function bindKeyboardEvents() {\r\n if(options.trigger !== 'focus') {\r\n tipElement.on('keyup', $tooltip.$onKeyUp);\r\n } else {\r\n element.on('keyup', $tooltip.$onFocusKeyUp);\r\n }\r\n }\r\n\r\n function unbindKeyboardEvents() {\r\n if(options.trigger !== 'focus') {\r\n tipElement.off('keyup', $tooltip.$onKeyUp);\r\n } else {\r\n element.off('keyup', $tooltip.$onFocusKeyUp);\r\n }\r\n }\r\n\r\n var _autoCloseEventsBinded = false;\r\n function bindAutoCloseEvents() {\r\n // use timeout to hookup the events to prevent\r\n // event bubbling from being processed imediately.\r\n $timeout(function() {\r\n // Stop propagation when clicking inside tooltip\r\n tipElement.on('click', stopEventPropagation);\r\n\r\n // Hide when clicking outside tooltip\r\n $body.on('click', $tooltip.hide);\r\n\r\n _autoCloseEventsBinded = true;\r\n }, 0, false);\r\n }\r\n\r\n function unbindAutoCloseEvents() {\r\n if (_autoCloseEventsBinded) {\r\n tipElement.off('click', stopEventPropagation);\r\n $body.off('click', $tooltip.hide);\r\n _autoCloseEventsBinded = false;\r\n }\r\n }\r\n\r\n function stopEventPropagation(event) {\r\n event.stopPropagation();\r\n }\r\n\r\n // Private methods\r\n\r\n function getPosition($element) {\r\n $element = $element || (options.target || element);\r\n\r\n var el = $element[0];\r\n\r\n var elRect = el.getBoundingClientRect();\r\n if (elRect.width === null) {\r\n // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093\r\n elRect = angular.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top });\r\n }\r\n\r\n var elPos;\r\n if (options.container === 'body') {\r\n elPos = dimensions.offset(el);\r\n } else {\r\n elPos = dimensions.position(el);\r\n }\r\n\r\n return angular.extend({}, elRect, elPos);\r\n }\r\n\r\n function getCalculatedOffset(placement, position, actualWidth, actualHeight) {\r\n var offset;\r\n var split = placement.split('-');\r\n\r\n switch (split[0]) {\r\n case 'right':\r\n offset = {\r\n top: position.top + position.height / 2 - actualHeight / 2,\r\n left: position.left + position.width\r\n };\r\n break;\r\n case 'bottom':\r\n offset = {\r\n top: position.top + position.height,\r\n left: position.left + position.width / 2 - actualWidth / 2\r\n };\r\n break;\r\n case 'left':\r\n offset = {\r\n top: position.top + position.height / 2 - actualHeight / 2,\r\n left: position.left - actualWidth\r\n };\r\n break;\r\n default:\r\n offset = {\r\n top: position.top - actualHeight,\r\n left: position.left + position.width / 2 - actualWidth / 2\r\n };\r\n break;\r\n }\r\n\r\n if(!split[1]) {\r\n return offset;\r\n }\r\n\r\n // Add support for corners @todo css\r\n if(split[0] === 'top' || split[0] === 'bottom') {\r\n switch (split[1]) {\r\n case 'left':\r\n offset.left = position.left;\r\n break;\r\n case 'right':\r\n offset.left = position.left + position.width - actualWidth;\r\n }\r\n } else if(split[0] === 'left' || split[0] === 'right') {\r\n switch (split[1]) {\r\n case 'top':\r\n offset.top = position.top - actualHeight;\r\n break;\r\n case 'bottom':\r\n offset.top = position.top + position.height;\r\n }\r\n }\r\n\r\n return offset;\r\n }\r\n\r\n function applyPlacementCss(top, left) {\r\n tipElement.css({ top: top + 'px', left: left + 'px' });\r\n }\r\n\r\n function destroyTipElement() {\r\n // Cancel pending callbacks\r\n clearTimeout(timeout);\r\n\r\n if($tooltip.$isShown && tipElement !== null) {\r\n if(options.autoClose) {\r\n unbindAutoCloseEvents();\r\n }\r\n\r\n if(options.keyboard) {\r\n unbindKeyboardEvents();\r\n }\r\n }\r\n\r\n if(tipScope) {\r\n tipScope.$destroy();\r\n tipScope = null;\r\n }\r\n\r\n if(tipElement) {\r\n tipElement.remove();\r\n tipElement = $tooltip.$element = null;\r\n }\r\n }\r\n\r\n return $tooltip;\r\n\r\n }\r\n\r\n // Helper functions\r\n\r\n function safeDigest(scope) {\r\n scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();\r\n }\r\n\r\n function findElement(query, element) {\r\n return angular.element((element || document).querySelectorAll(query));\r\n }\r\n\r\n var fetchPromises = {};\r\n function fetchTemplate(template) {\r\n if(fetchPromises[template]) return fetchPromises[template];\r\n return (fetchPromises[template] = $q.when($templateCache.get(template) || $http.get(template))\r\n .then(function(res) {\r\n if(angular.isObject(res)) {\r\n $templateCache.put(template, res.data);\r\n return res.data;\r\n }\r\n return res;\r\n }));\r\n }\r\n\r\n return TooltipFactory;\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsTooltip', function($window, $location, $sce, $tooltip, $$rAF) {\r\n\r\n return {\r\n restrict: 'EAC',\r\n scope: true,\r\n link: function postLink(scope, element, attr, transclusion) {\r\n\r\n // Directive options\r\n var options = {scope: scope};\r\n angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'backdropAnimation', 'type', 'customClass'], function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n // overwrite inherited title value when no value specified\r\n // fix for angular 1.3.1 531a8de72c439d8ddd064874bf364c00cedabb11\r\n if (!scope.hasOwnProperty('title')){\r\n scope.title = '';\r\n }\r\n\r\n // Observe scope attributes for change\r\n attr.$observe('title', function(newValue) {\r\n if (angular.isDefined(newValue) || !scope.hasOwnProperty('title')) {\r\n var oldValue = scope.title;\r\n scope.title = $sce.trustAsHtml(newValue);\r\n angular.isDefined(oldValue) && $$rAF(function() {\r\n tooltip && tooltip.$applyPlacement();\r\n });\r\n }\r\n });\r\n\r\n // Support scope as an object\r\n attr.bsTooltip && scope.$watch(attr.bsTooltip, function(newValue, oldValue) {\r\n if(angular.isObject(newValue)) {\r\n angular.extend(scope, newValue);\r\n } else {\r\n scope.title = newValue;\r\n }\r\n angular.isDefined(oldValue) && $$rAF(function() {\r\n tooltip && tooltip.$applyPlacement();\r\n });\r\n }, true);\r\n\r\n // Visibility binding support\r\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\r\n if(!tooltip || !angular.isDefined(newValue)) return;\r\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(tooltip),?/i);\r\n newValue === true ? tooltip.show() : tooltip.hide();\r\n });\r\n\r\n // Enabled binding support\r\n attr.bsEnabled && scope.$watch(attr.bsEnabled, function(newValue, oldValue) {\r\n // console.warn('scope.$watch(%s)', attr.bsEnabled, newValue, oldValue);\r\n if(!tooltip || !angular.isDefined(newValue)) return;\r\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|1|,?(tooltip),?/i);\r\n newValue === false ? tooltip.setEnabled(false) : tooltip.setEnabled(true);\r\n });\r\n\r\n // Initialize popover\r\n var tooltip = $tooltip(element, options);\r\n\r\n // Garbage collection\r\n scope.$on('$destroy', function() {\r\n if(tooltip) tooltip.destroy();\r\n options = null;\r\n tooltip = null;\r\n });\r\n\r\n }\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.timepicker', [\r\n 'mgcrea.ngStrap.helpers.dateParser',\r\n 'mgcrea.ngStrap.helpers.dateFormatter',\r\n 'mgcrea.ngStrap.tooltip'])\r\n\r\n .provider('$timepicker', function() {\r\n\r\n var defaults = this.defaults = {\r\n animation: 'am-fade',\r\n prefixClass: 'timepicker',\r\n placement: 'bottom-left',\r\n template: 'timepicker/timepicker.tpl.html',\r\n trigger: 'focus',\r\n container: false,\r\n keyboard: true,\r\n html: false,\r\n delay: 0,\r\n // lang: $locale.id,\r\n useNative: true,\r\n timeType: 'date',\r\n timeFormat: 'shortTime',\r\n modelTimeFormat: null,\r\n autoclose: false,\r\n minTime: -Infinity,\r\n maxTime: +Infinity,\r\n length: 5,\r\n hourStep: 1,\r\n minuteStep: 5,\r\n iconUp: 'glyphicon glyphicon-chevron-up',\r\n iconDown: 'glyphicon glyphicon-chevron-down',\r\n arrowBehavior: 'pager'\r\n };\r\n\r\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) {\r\n\r\n var bodyEl = angular.element($window.document.body);\r\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\r\n var isTouch = ('createTouch' in $window.document) && isNative;\r\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\r\n\r\n function timepickerFactory(element, controller, config) {\r\n\r\n var $timepicker = $tooltip(element, angular.extend({}, defaults, config));\r\n var parentScope = config.scope;\r\n var options = $timepicker.$options;\r\n var scope = $timepicker.$scope;\r\n\r\n var lang = options.lang;\r\n var formatDate = function(date, format) {\r\n return $dateFormatter.formatDate(date, format, lang);\r\n };\r\n\r\n // View vars\r\n\r\n var selectedIndex = 0;\r\n var startDate = controller.$dateValue || new Date();\r\n var viewDate = {hour: startDate.getHours(), meridian: startDate.getHours() < 12, minute: startDate.getMinutes(), second: startDate.getSeconds(), millisecond: startDate.getMilliseconds()};\r\n\r\n var format = $dateFormatter.getDatetimeFormat(options.timeFormat, lang);\r\n\r\n var hoursFormat = $dateFormatter.hoursFormat(format),\r\n timeSeparator = $dateFormatter.timeSeparator(format),\r\n minutesFormat = $dateFormatter.minutesFormat(format),\r\n showAM = $dateFormatter.showAM(format);\r\n\r\n scope.$iconUp = options.iconUp;\r\n scope.$iconDown = options.iconDown;\r\n\r\n // Scope methods\r\n\r\n scope.$select = function(date, index) {\r\n $timepicker.select(date, index);\r\n };\r\n scope.$moveIndex = function(value, index) {\r\n $timepicker.$moveIndex(value, index);\r\n };\r\n scope.$switchMeridian = function(date) {\r\n $timepicker.switchMeridian(date);\r\n };\r\n\r\n // Public methods\r\n\r\n $timepicker.update = function(date) {\r\n // console.warn('$timepicker.update() newValue=%o', date);\r\n if(angular.isDate(date) && !isNaN(date.getTime())) {\r\n $timepicker.$date = date;\r\n angular.extend(viewDate, {hour: date.getHours(), minute: date.getMinutes(), second: date.getSeconds(), millisecond: date.getMilliseconds()});\r\n $timepicker.$build();\r\n } else if(!$timepicker.$isBuilt) {\r\n $timepicker.$build();\r\n }\r\n };\r\n\r\n $timepicker.select = function(date, index, keep) {\r\n // console.warn('$timepicker.select', date, scope.$mode);\r\n if(!controller.$dateValue || isNaN(controller.$dateValue.getTime())) controller.$dateValue = new Date(1970, 0, 1);\r\n if(!angular.isDate(date)) date = new Date(date);\r\n if(index === 0) controller.$dateValue.setHours(date.getHours());\r\n else if(index === 1) controller.$dateValue.setMinutes(date.getMinutes());\r\n controller.$setViewValue(angular.copy(controller.$dateValue));\r\n controller.$render();\r\n if(options.autoclose && !keep) {\r\n $timeout(function() { $timepicker.hide(true); });\r\n }\r\n };\r\n\r\n $timepicker.switchMeridian = function(date) {\r\n if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) {\r\n return;\r\n }\r\n var hours = (date || controller.$dateValue).getHours();\r\n controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12);\r\n controller.$setViewValue(angular.copy(controller.$dateValue));\r\n controller.$render();\r\n };\r\n\r\n // Protected methods\r\n\r\n $timepicker.$build = function() {\r\n // console.warn('$timepicker.$build() viewDate=%o', viewDate);\r\n var i, midIndex = scope.midIndex = parseInt(options.length / 2, 10);\r\n var hours = [], hour;\r\n for(i = 0; i < options.length; i++) {\r\n hour = new Date(1970, 0, 1, viewDate.hour - (midIndex - i) * options.hourStep);\r\n hours.push({date: hour, label: formatDate(hour, hoursFormat), selected: $timepicker.$date && $timepicker.$isSelected(hour, 0), disabled: $timepicker.$isDisabled(hour, 0)});\r\n }\r\n var minutes = [], minute;\r\n for(i = 0; i < options.length; i++) {\r\n minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep);\r\n minutes.push({date: minute, label: formatDate(minute, minutesFormat), selected: $timepicker.$date && $timepicker.$isSelected(minute, 1), disabled: $timepicker.$isDisabled(minute, 1)});\r\n }\r\n\r\n var rows = [];\r\n for(i = 0; i < options.length; i++) {\r\n rows.push([hours[i], minutes[i]]);\r\n }\r\n scope.rows = rows;\r\n scope.showAM = showAM;\r\n scope.isAM = ($timepicker.$date || hours[midIndex].date).getHours() < 12;\r\n scope.timeSeparator = timeSeparator;\r\n $timepicker.$isBuilt = true;\r\n };\r\n\r\n $timepicker.$isSelected = function(date, index) {\r\n if(!$timepicker.$date) return false;\r\n else if(index === 0) {\r\n return date.getHours() === $timepicker.$date.getHours();\r\n } else if(index === 1) {\r\n return date.getMinutes() === $timepicker.$date.getMinutes();\r\n }\r\n };\r\n\r\n $timepicker.$isDisabled = function(date, index) {\r\n var selectedTime;\r\n if(index === 0) {\r\n selectedTime = date.getTime() + viewDate.minute * 6e4;\r\n } else if(index === 1) {\r\n selectedTime = date.getTime() + viewDate.hour * 36e5;\r\n }\r\n return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1;\r\n };\r\n\r\n scope.$arrowAction = function (value, index) {\r\n if (options.arrowBehavior === 'picker') {\r\n $timepicker.$setTimeByStep(value,index);\r\n } else {\r\n $timepicker.$moveIndex(value,index);\r\n }\r\n };\r\n\r\n $timepicker.$setTimeByStep = function(value, index) {\r\n var newDate = new Date($timepicker.$date);\r\n var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;\r\n var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;\r\n if (index === 0) {\r\n newDate.setHours(hours - (parseInt(options.hourStep, 10) * value));\r\n }\r\n else {\r\n newDate.setMinutes(minutes - (parseInt(options.minuteStep, 10) * value));\r\n }\r\n $timepicker.select(newDate, index, true);\r\n };\r\n\r\n $timepicker.$moveIndex = function(value, index) {\r\n var targetDate;\r\n if(index === 0) {\r\n targetDate = new Date(1970, 0, 1, viewDate.hour + (value * options.length), viewDate.minute);\r\n angular.extend(viewDate, {hour: targetDate.getHours()});\r\n } else if(index === 1) {\r\n targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + (value * options.length * options.minuteStep));\r\n angular.extend(viewDate, {minute: targetDate.getMinutes()});\r\n }\r\n $timepicker.$build();\r\n };\r\n\r\n $timepicker.$onMouseDown = function(evt) {\r\n // Prevent blur on mousedown on .dropdown-menu\r\n if(evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault();\r\n evt.stopPropagation();\r\n // Emulate click for mobile devices\r\n if(isTouch) {\r\n var targetEl = angular.element(evt.target);\r\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\r\n targetEl = targetEl.parent();\r\n }\r\n targetEl.triggerHandler('click');\r\n }\r\n };\r\n\r\n $timepicker.$onKeyDown = function(evt) {\r\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\r\n evt.preventDefault();\r\n evt.stopPropagation();\r\n\r\n // Close on enter\r\n if(evt.keyCode === 13) return $timepicker.hide(true);\r\n\r\n // Navigate with keyboard\r\n var newDate = new Date($timepicker.$date);\r\n var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;\r\n var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;\r\n var lateralMove = /(37|39)/.test(evt.keyCode);\r\n var count = 2 + showAM * 1;\r\n\r\n // Navigate indexes (left, right)\r\n if (lateralMove) {\r\n if(evt.keyCode === 37) selectedIndex = selectedIndex < 1 ? count - 1 : selectedIndex - 1;\r\n else if(evt.keyCode === 39) selectedIndex = selectedIndex < count - 1 ? selectedIndex + 1 : 0;\r\n }\r\n\r\n // Update values (up, down)\r\n var selectRange = [0, hoursLength];\r\n if(selectedIndex === 0) {\r\n if(evt.keyCode === 38) newDate.setHours(hours - parseInt(options.hourStep, 10));\r\n else if(evt.keyCode === 40) newDate.setHours(hours + parseInt(options.hourStep, 10));\r\n // re-calculate hours length because we have changed hours value\r\n hoursLength = formatDate(newDate, hoursFormat).length;\r\n selectRange = [0, hoursLength];\r\n } else if(selectedIndex === 1) {\r\n if(evt.keyCode === 38) newDate.setMinutes(minutes - parseInt(options.minuteStep, 10));\r\n else if(evt.keyCode === 40) newDate.setMinutes(minutes + parseInt(options.minuteStep, 10));\r\n // re-calculate minutes length because we have changes minutes value\r\n minutesLength = formatDate(newDate, minutesFormat).length;\r\n selectRange = [hoursLength + 1, hoursLength + 1 + minutesLength];\r\n } else if(selectedIndex === 2) {\r\n if(!lateralMove) $timepicker.switchMeridian();\r\n selectRange = [hoursLength + 1 + minutesLength + 1, hoursLength + 1 + minutesLength + 3];\r\n }\r\n $timepicker.select(newDate, selectedIndex, true);\r\n createSelection(selectRange[0], selectRange[1]);\r\n parentScope.$digest();\r\n };\r\n\r\n // Private\r\n\r\n function createSelection(start, end) {\r\n if(element[0].createTextRange) {\r\n var selRange = element[0].createTextRange();\r\n selRange.collapse(true);\r\n selRange.moveStart('character', start);\r\n selRange.moveEnd('character', end);\r\n selRange.select();\r\n } else if(element[0].setSelectionRange) {\r\n element[0].setSelectionRange(start, end);\r\n } else if(angular.isUndefined(element[0].selectionStart)) {\r\n element[0].selectionStart = start;\r\n element[0].selectionEnd = end;\r\n }\r\n }\r\n\r\n function focusElement() {\r\n element[0].focus();\r\n }\r\n\r\n // Overrides\r\n\r\n var _init = $timepicker.init;\r\n $timepicker.init = function() {\r\n if(isNative && options.useNative) {\r\n element.prop('type', 'time');\r\n element.css('-webkit-appearance', 'textfield');\r\n return;\r\n } else if(isTouch) {\r\n element.prop('type', 'text');\r\n element.attr('readonly', 'true');\r\n element.on('click', focusElement);\r\n }\r\n _init();\r\n };\r\n\r\n var _destroy = $timepicker.destroy;\r\n $timepicker.destroy = function() {\r\n if(isNative && options.useNative) {\r\n element.off('click', focusElement);\r\n }\r\n _destroy();\r\n };\r\n\r\n var _show = $timepicker.show;\r\n $timepicker.show = function() {\r\n _show();\r\n // use timeout to hookup the events to prevent \r\n // event bubbling from being processed imediately. \r\n $timeout(function() {\r\n $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\r\n if(options.keyboard) {\r\n element.on('keydown', $timepicker.$onKeyDown);\r\n }\r\n }, 0, false);\r\n };\r\n\r\n var _hide = $timepicker.hide;\r\n $timepicker.hide = function(blur) {\r\n if(!$timepicker.$isShown) return;\r\n $timepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\r\n if(options.keyboard) {\r\n element.off('keydown', $timepicker.$onKeyDown);\r\n }\r\n _hide(blur);\r\n };\r\n\r\n return $timepicker;\r\n\r\n }\r\n\r\n timepickerFactory.defaults = defaults;\r\n return timepickerFactory;\r\n\r\n };\r\n\r\n })\r\n\r\n\r\n .directive('bsTimepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) {\r\n\r\n var defaults = $timepicker.defaults;\r\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\r\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\r\n\r\n return {\r\n restrict: 'EAC',\r\n require: 'ngModel',\r\n link: function postLink(scope, element, attr, controller) {\r\n\r\n // Directive options\r\n var options = {scope: scope, controller: controller};\r\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'timeType', 'timeFormat', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown'], function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n // Visibility binding support\r\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\r\n if(!timepicker || !angular.isDefined(newValue)) return;\r\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(timepicker),?/i);\r\n newValue === true ? timepicker.show() : timepicker.hide();\r\n });\r\n\r\n // Initialize timepicker\r\n if(isNative && (options.useNative || defaults.useNative)) options.timeFormat = 'HH:mm';\r\n var timepicker = $timepicker(element, controller, options);\r\n options = timepicker.$options;\r\n\r\n var lang = options.lang;\r\n var formatDate = function(date, format) {\r\n return $dateFormatter.formatDate(date, format, lang);\r\n };\r\n\r\n // Initialize parser\r\n var dateParser = $dateParser({format: options.timeFormat, lang: lang});\r\n\r\n // Observe attributes for changes\r\n angular.forEach(['minTime', 'maxTime'], function(key) {\r\n // console.warn('attr.$observe(%s)', key, attr[key]);\r\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\r\n timepicker.$options[key] = dateParser.getTimeForAttribute(key, newValue);\r\n !isNaN(timepicker.$options[key]) && timepicker.$build();\r\n validateAgainstMinMaxTime(controller.$dateValue);\r\n });\r\n });\r\n\r\n // Watch model for changes\r\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\r\n // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue, controller.$dateValue);\r\n timepicker.update(controller.$dateValue);\r\n }, true);\r\n\r\n function validateAgainstMinMaxTime(parsedTime) {\r\n if (!angular.isDate(parsedTime)) return;\r\n var isMinValid = isNaN(options.minTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) >= options.minTime;\r\n var isMaxValid = isNaN(options.maxTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) <= options.maxTime;\r\n var isValid = isMinValid && isMaxValid;\r\n controller.$setValidity('date', isValid);\r\n controller.$setValidity('min', isMinValid);\r\n controller.$setValidity('max', isMaxValid);\r\n // Only update the model when we have a valid date\r\n if(!isValid) {\r\n return;\r\n }\r\n controller.$dateValue = parsedTime;\r\n }\r\n\r\n // viewValue -> $parsers -> modelValue\r\n controller.$parsers.unshift(function(viewValue) {\r\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\r\n // Null values should correctly reset the model value & validity\r\n if(!viewValue) {\r\n // BREAKING CHANGE:\r\n // return null (not undefined) when input value is empty, so angularjs 1.3 \r\n // ngModelController can go ahead and run validators, like ngRequired\r\n controller.$setValidity('date', true);\r\n return null;\r\n }\r\n var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue);\r\n if(!parsedTime || isNaN(parsedTime.getTime())) {\r\n controller.$setValidity('date', false);\r\n // return undefined, causes ngModelController to \r\n // invalidate model value \r\n return;\r\n } else {\r\n validateAgainstMinMaxTime(parsedTime);\r\n }\r\n if(options.timeType === 'string') {\r\n return formatDate(parsedTime, options.modelTimeFormat || options.timeFormat);\r\n } else if(options.timeType === 'number') {\r\n return controller.$dateValue.getTime();\r\n } else if(options.timeType === 'unix') {\r\n return controller.$dateValue.getTime() / 1000;\r\n } else if(options.timeType === 'iso') {\r\n return controller.$dateValue.toISOString();\r\n } else {\r\n return new Date(controller.$dateValue);\r\n }\r\n });\r\n\r\n // modelValue -> $formatters -> viewValue\r\n controller.$formatters.push(function(modelValue) {\r\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\r\n var date;\r\n if(angular.isUndefined(modelValue) || modelValue === null) {\r\n date = NaN;\r\n } else if(angular.isDate(modelValue)) {\r\n date = modelValue;\r\n } else if(options.timeType === 'string') {\r\n date = dateParser.parse(modelValue, null, options.modelTimeFormat);\r\n } else if(options.timeType === 'unix') {\r\n date = new Date(modelValue * 1000);\r\n } else {\r\n date = new Date(modelValue);\r\n }\r\n // Setup default value?\r\n // if(isNaN(date.getTime())) date = new Date(new Date().setMinutes(0) + 36e5);\r\n controller.$dateValue = date;\r\n return getTimeFormattedString();\r\n });\r\n\r\n // viewValue -> element\r\n controller.$render = function() {\r\n // console.warn('$render(\"%s\"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);\r\n element.val(getTimeFormattedString());\r\n };\r\n\r\n function getTimeFormattedString() {\r\n return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat);\r\n }\r\n\r\n // Garbage collection\r\n scope.$on('$destroy', function() {\r\n if (timepicker) timepicker.destroy();\r\n options = null;\r\n timepicker = null;\r\n });\r\n\r\n }\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.typeahead', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions'])\r\n\r\n .provider('$typeahead', function() {\r\n\r\n var defaults = this.defaults = {\r\n animation: 'am-fade',\r\n prefixClass: 'typeahead',\r\n prefixEvent: '$typeahead',\r\n placement: 'bottom-left',\r\n template: 'typeahead/typeahead.tpl.html',\r\n trigger: 'focus',\r\n container: false,\r\n keyboard: true,\r\n html: false,\r\n delay: 0,\r\n minLength: 1,\r\n filter: 'filter',\r\n limit: 6,\r\n comparator: ''\r\n };\r\n\r\n this.$get = function($window, $rootScope, $tooltip, $timeout) {\r\n\r\n var bodyEl = angular.element($window.document.body);\r\n\r\n function TypeaheadFactory(element, controller, config) {\r\n\r\n var $typeahead = {};\r\n\r\n // Common vars\r\n var options = angular.extend({}, defaults, config);\r\n\r\n $typeahead = $tooltip(element, options);\r\n var parentScope = config.scope;\r\n var scope = $typeahead.$scope;\r\n\r\n scope.$resetMatches = function(){\r\n scope.$matches = [];\r\n scope.$activeIndex = 0;\r\n };\r\n scope.$resetMatches();\r\n\r\n scope.$activate = function(index) {\r\n scope.$$postDigest(function() {\r\n $typeahead.activate(index);\r\n });\r\n };\r\n\r\n scope.$select = function(index, evt) {\r\n scope.$$postDigest(function() {\r\n $typeahead.select(index);\r\n });\r\n };\r\n\r\n scope.$isVisible = function() {\r\n return $typeahead.$isVisible();\r\n };\r\n\r\n // Public methods\r\n\r\n $typeahead.update = function(matches) {\r\n scope.$matches = matches;\r\n if(scope.$activeIndex >= matches.length) {\r\n scope.$activeIndex = 0;\r\n }\r\n };\r\n\r\n $typeahead.activate = function(index) {\r\n scope.$activeIndex = index;\r\n };\r\n\r\n $typeahead.select = function(index) {\r\n var value = scope.$matches[index].value;\r\n // console.log('$setViewValue', value);\r\n controller.$setViewValue(value);\r\n controller.$render();\r\n scope.$resetMatches();\r\n if(parentScope) parentScope.$digest();\r\n // Emit event\r\n scope.$emit(options.prefixEvent + '.select', value, index);\r\n };\r\n\r\n // Protected methods\r\n\r\n $typeahead.$isVisible = function() {\r\n if(!options.minLength || !controller) {\r\n return !!scope.$matches.length;\r\n }\r\n // minLength support\r\n return scope.$matches.length && angular.isString(controller.$viewValue) && controller.$viewValue.length >= options.minLength;\r\n };\r\n\r\n $typeahead.$getIndex = function(value) {\r\n var l = scope.$matches.length, i = l;\r\n if(!l) return;\r\n for(i = l; i--;) {\r\n if(scope.$matches[i].value === value) break;\r\n }\r\n if(i < 0) return;\r\n return i;\r\n };\r\n\r\n $typeahead.$onMouseDown = function(evt) {\r\n // Prevent blur on mousedown\r\n evt.preventDefault();\r\n evt.stopPropagation();\r\n };\r\n\r\n $typeahead.$onKeyDown = function(evt) {\r\n if(!/(38|40|13)/.test(evt.keyCode)) return;\r\n\r\n // Let ngSubmit pass if the typeahead tip is hidden\r\n if($typeahead.$isVisible()) {\r\n evt.preventDefault();\r\n evt.stopPropagation();\r\n }\r\n\r\n // Select with enter\r\n if(evt.keyCode === 13 && scope.$matches.length) {\r\n $typeahead.select(scope.$activeIndex);\r\n }\r\n\r\n // Navigate with keyboard\r\n else if(evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--;\r\n else if(evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++;\r\n else if(angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0;\r\n scope.$digest();\r\n };\r\n\r\n // Overrides\r\n\r\n var show = $typeahead.show;\r\n $typeahead.show = function() {\r\n show();\r\n // use timeout to hookup the events to prevent\r\n // event bubbling from being processed imediately.\r\n $timeout(function() {\r\n $typeahead.$element.on('mousedown', $typeahead.$onMouseDown);\r\n if(options.keyboard) {\r\n element.on('keydown', $typeahead.$onKeyDown);\r\n }\r\n }, 0, false);\r\n };\r\n\r\n var hide = $typeahead.hide;\r\n $typeahead.hide = function() {\r\n $typeahead.$element.off('mousedown', $typeahead.$onMouseDown);\r\n if(options.keyboard) {\r\n element.off('keydown', $typeahead.$onKeyDown);\r\n }\r\n hide();\r\n };\r\n\r\n return $typeahead;\r\n\r\n }\r\n\r\n TypeaheadFactory.defaults = defaults;\r\n return TypeaheadFactory;\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsTypeahead', function($window, $parse, $q, $typeahead, $parseOptions) {\r\n\r\n var defaults = $typeahead.defaults;\r\n\r\n return {\r\n restrict: 'EAC',\r\n require: 'ngModel',\r\n link: function postLink(scope, element, attr, controller) {\r\n\r\n // Directive options\r\n var options = {scope: scope};\r\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'filter', 'limit', 'minLength', 'watchOptions', 'selectMode', 'comparator'], function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n // Build proper ngOptions\r\n var filter = options.filter || defaults.filter;\r\n var limit = options.limit || defaults.limit;\r\n var comparator = options.comparator || defaults.comparator;\r\n\r\n var ngOptions = attr.ngOptions;\r\n if(filter) ngOptions += ' | ' + filter + ':$viewValue';\r\n if (comparator) ngOptions += ':' + comparator;\r\n if(limit) ngOptions += ' | limitTo:' + limit;\r\n var parsedOptions = $parseOptions(ngOptions);\r\n\r\n // Initialize typeahead\r\n var typeahead = $typeahead(element, controller, options);\r\n\r\n // Watch options on demand\r\n if(options.watchOptions) {\r\n // Watch ngOptions values before filtering for changes, drop function calls\r\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').replace(/\\(.*\\)/g, '').trim();\r\n scope.$watch(watchedOptions, function (newValue, oldValue) {\r\n // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue);\r\n parsedOptions.valuesFn(scope, controller).then(function (values) {\r\n typeahead.update(values);\r\n controller.$render();\r\n });\r\n }, true);\r\n }\r\n\r\n // Watch model for changes\r\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\r\n // console.warn('$watch', element.attr('ng-model'), newValue);\r\n scope.$modelValue = newValue; // Publish modelValue on scope for custom templates\r\n parsedOptions.valuesFn(scope, controller)\r\n .then(function(values) {\r\n // Prevent input with no future prospect if selectMode is truthy\r\n // @TODO test selectMode\r\n if(options.selectMode && !values.length && newValue.length > 0) {\r\n controller.$setViewValue(controller.$viewValue.substring(0, controller.$viewValue.length - 1));\r\n return;\r\n }\r\n if(values.length > limit) values = values.slice(0, limit);\r\n var isVisible = typeahead.$isVisible();\r\n isVisible && typeahead.update(values);\r\n // Do not re-queue an update if a correct value has been selected\r\n if(values.length === 1 && values[0].value === newValue) return;\r\n !isVisible && typeahead.update(values);\r\n // Queue a new rendering that will leverage collection loading\r\n controller.$render();\r\n });\r\n });\r\n\r\n // modelValue -> $formatters -> viewValue\r\n controller.$formatters.push(function(modelValue) {\r\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\r\n var displayValue = parsedOptions.displayValue(modelValue);\r\n return displayValue === undefined ? '' : displayValue;\r\n });\r\n\r\n // Model rendering in view\r\n controller.$render = function () {\r\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\r\n if(controller.$isEmpty(controller.$viewValue)) return element.val('');\r\n var index = typeahead.$getIndex(controller.$modelValue);\r\n var selected = angular.isDefined(index) ? typeahead.$scope.$matches[index].label : controller.$viewValue;\r\n selected = angular.isObject(selected) ? parsedOptions.displayValue(selected) : selected;\r\n element.val(selected ? selected.toString().replace(/<(?:.|\\n)*?>/gm, '').trim() : '');\r\n };\r\n\r\n // Garbage collection\r\n scope.$on('$destroy', function() {\r\n if (typeahead) typeahead.destroy();\r\n options = null;\r\n typeahead = null;\r\n });\r\n\r\n }\r\n };\r\n\r\n });\r\n"],"sourceRoot":"/source/"}
\ No newline at end of file
+{"version":3,"sources":["module.js","affix/affix.js","alert/alert.js","aside/aside.js","button/button.js","collapse/collapse.js","datepicker/datepicker.js","dropdown/dropdown.js","modal/modal.js","helpers/date-formatter.js","helpers/date-parser.js","helpers/debounce.js","helpers/dimensions.js","helpers/parse-options.js","helpers/raf.js","navbar/navbar.js","popover/popover.js","progressbar/progressbar.js","scrollspy/scrollspy.js","select/select.js","tab/tab.js","timepicker/timepicker.js","tooltip/tooltip.js","typeahead/typeahead.js"],"names":[],"mappings":"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","file":"angular-strap.min.js","sourcesContent":["\nangular.module('mgcrea.ngStrap', [\n 'mgcrea.ngStrap.modal',\n 'mgcrea.ngStrap.aside',\n 'mgcrea.ngStrap.alert',\n 'mgcrea.ngStrap.button',\n 'mgcrea.ngStrap.select',\n 'mgcrea.ngStrap.datepicker',\n 'mgcrea.ngStrap.timepicker',\n 'mgcrea.ngStrap.navbar',\n 'mgcrea.ngStrap.tooltip',\n 'mgcrea.ngStrap.popover',\n 'mgcrea.ngStrap.dropdown',\n 'mgcrea.ngStrap.typeahead',\n 'mgcrea.ngStrap.scrollspy',\n 'mgcrea.ngStrap.affix',\n 'mgcrea.ngStrap.tab',\n 'mgcrea.ngStrap.collapse',\n 'mgcrea.ngStrap.progressbar'\n]);\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.affix', ['mgcrea.ngStrap.helpers.dimensions', 'mgcrea.ngStrap.helpers.debounce'])\r\n\r\n .provider('$affix', function() {\r\n\r\n var defaults = this.defaults = {\r\n offsetTop: 'auto'\r\n };\r\n\r\n this.$get = function($window, debounce, dimensions) {\r\n\r\n var bodyEl = angular.element($window.document.body);\r\n var windowEl = angular.element($window);\r\n\r\n function AffixFactory(element, config) {\r\n\r\n var $affix = {};\r\n\r\n // Common vars\r\n var options = angular.extend({}, defaults, config);\r\n var targetEl = options.target;\r\n\r\n // Initial private vars\r\n var reset = 'affix affix-top affix-bottom',\r\n setWidth = false,\r\n initialAffixTop = 0,\r\n initialOffsetTop = 0,\r\n offsetTop = 0,\r\n offsetBottom = 0,\r\n affixed = null,\r\n unpin = null;\r\n\r\n var parent = element.parent();\r\n // Options: custom parent\r\n if (options.offsetParent) {\r\n if (options.offsetParent.match(/^\\d+$/)) {\r\n for (var i = 0; i < (options.offsetParent * 1) - 1; i++) {\r\n parent = parent.parent();\r\n }\r\n }\r\n else {\r\n parent = angular.element(options.offsetParent);\r\n }\r\n }\r\n\r\n $affix.init = function() {\r\n\r\n this.$parseOffsets();\r\n initialOffsetTop = dimensions.offset(element[0]).top + initialAffixTop;\r\n setWidth = !element[0].style.width;\r\n\r\n // Bind events\r\n targetEl.on('scroll', this.checkPosition);\r\n targetEl.on('click', this.checkPositionWithEventLoop);\r\n windowEl.on('resize', this.$debouncedOnResize);\r\n\r\n // Both of these checkPosition() calls are necessary for the case where\r\n // the user hits refresh after scrolling to the bottom of the page.\r\n this.checkPosition();\r\n this.checkPositionWithEventLoop();\r\n\r\n };\r\n\r\n $affix.destroy = function() {\r\n\r\n // Unbind events\r\n targetEl.off('scroll', this.checkPosition);\r\n targetEl.off('click', this.checkPositionWithEventLoop);\r\n windowEl.off('resize', this.$debouncedOnResize);\r\n\r\n };\r\n\r\n $affix.checkPositionWithEventLoop = function() {\r\n\r\n // IE 9 throws an error if we use 'this' instead of '$affix'\r\n // in this setTimeout call\r\n setTimeout($affix.checkPosition, 1);\r\n\r\n };\r\n\r\n $affix.checkPosition = function() {\r\n // if (!this.$element.is(':visible')) return\r\n\r\n var scrollTop = getScrollTop();\r\n var position = dimensions.offset(element[0]);\r\n var elementHeight = dimensions.height(element[0]);\r\n\r\n // Get required affix class according to position\r\n var affix = getRequiredAffixClass(unpin, position, elementHeight);\r\n\r\n // Did affix status changed this last check?\r\n if(affixed === affix) return;\r\n affixed = affix;\r\n\r\n // Add proper affix class\r\n element.removeClass(reset).addClass('affix' + ((affix !== 'middle') ? '-' + affix : ''));\r\n\r\n if(affix === 'top') {\r\n unpin = null;\r\n element.css('position', (options.offsetParent) ? '' : 'relative');\r\n if(setWidth) {\r\n element.css('width', '');\r\n }\r\n element.css('top', '');\r\n } else if(affix === 'bottom') {\r\n if (options.offsetUnpin) {\r\n unpin = -(options.offsetUnpin * 1);\r\n }\r\n else {\r\n // Calculate unpin threshold when affixed to bottom.\r\n // Hopefully the browser scrolls pixel by pixel.\r\n unpin = position.top - scrollTop;\r\n }\r\n if(setWidth) {\r\n element.css('width', '');\r\n }\r\n element.css('position', (options.offsetParent) ? '' : 'relative');\r\n element.css('top', (options.offsetParent) ? '' : ((bodyEl[0].offsetHeight - offsetBottom - elementHeight - initialOffsetTop) + 'px'));\r\n } else { // affix === 'middle'\r\n unpin = null;\r\n if(setWidth) {\r\n element.css('width', element[0].offsetWidth + 'px');\r\n }\r\n element.css('position', 'fixed');\r\n element.css('top', initialAffixTop + 'px');\r\n }\r\n\r\n };\r\n\r\n $affix.$onResize = function() {\r\n $affix.$parseOffsets();\r\n $affix.checkPosition();\r\n };\r\n $affix.$debouncedOnResize = debounce($affix.$onResize, 50);\r\n\r\n $affix.$parseOffsets = function() {\r\n var initialPosition = element.css('position');\r\n // Reset position to calculate correct offsetTop\r\n element.css('position', (options.offsetParent) ? '' : 'relative');\r\n\r\n if(options.offsetTop) {\r\n if(options.offsetTop === 'auto') {\r\n options.offsetTop = '+0';\r\n }\r\n if(options.offsetTop.match(/^[-+]\\d+$/)) {\r\n initialAffixTop = - options.offsetTop * 1;\r\n if(options.offsetParent) {\r\n offsetTop = dimensions.offset(parent[0]).top + (options.offsetTop * 1);\r\n }\r\n else {\r\n offsetTop = dimensions.offset(element[0]).top - dimensions.css(element[0], 'marginTop', true) + (options.offsetTop * 1);\r\n }\r\n }\r\n else {\r\n offsetTop = options.offsetTop * 1;\r\n }\r\n }\r\n\r\n if(options.offsetBottom) {\r\n if(options.offsetParent && options.offsetBottom.match(/^[-+]\\d+$/)) {\r\n // add 1 pixel due to rounding problems...\r\n offsetBottom = getScrollHeight() - (dimensions.offset(parent[0]).top + dimensions.height(parent[0])) + (options.offsetBottom * 1) + 1;\r\n }\r\n else {\r\n offsetBottom = options.offsetBottom * 1;\r\n }\r\n }\r\n\r\n // Bring back the element's position after calculations\r\n element.css('position', initialPosition);\r\n };\r\n\r\n // Private methods\r\n\r\n function getRequiredAffixClass(unpin, position, elementHeight) {\r\n\r\n var scrollTop = getScrollTop();\r\n var scrollHeight = getScrollHeight();\r\n\r\n if(scrollTop <= offsetTop) {\r\n return 'top';\r\n } else if(unpin !== null && (scrollTop + unpin <= position.top)) {\r\n return 'middle';\r\n } else if(offsetBottom !== null && (position.top + elementHeight + initialAffixTop >= scrollHeight - offsetBottom)) {\r\n return 'bottom';\r\n } else {\r\n return 'middle';\r\n }\r\n\r\n }\r\n\r\n function getScrollTop() {\r\n return targetEl[0] === $window ? $window.pageYOffset : targetEl[0].scrollTop;\r\n }\r\n\r\n function getScrollHeight() {\r\n return targetEl[0] === $window ? $window.document.body.scrollHeight : targetEl[0].scrollHeight;\r\n }\r\n\r\n $affix.init();\r\n return $affix;\r\n\r\n }\r\n\r\n return AffixFactory;\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsAffix', function($affix, $window) {\r\n\r\n return {\r\n restrict: 'EAC',\r\n require: '^?bsAffixTarget',\r\n link: function postLink(scope, element, attr, affixTarget) {\r\n\r\n var options = {scope: scope, offsetTop: 'auto', target: affixTarget ? affixTarget.$element : angular.element($window)};\r\n angular.forEach(['offsetTop', 'offsetBottom', 'offsetParent', 'offsetUnpin'], function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n var affix = $affix(element, options);\r\n scope.$on('$destroy', function() {\r\n affix && affix.destroy();\r\n options = null;\r\n affix = null;\r\n });\r\n\r\n }\r\n };\r\n\r\n })\r\n\r\n .directive('bsAffixTarget', function() {\r\n return {\r\n controller: function($element) {\r\n this.$element = $element;\r\n }\r\n };\r\n });\r\n","'use strict';\r\n\r\n// @BUG: following snippet won't compile correctly\r\n// @TODO: submit issue to core\r\n// ' ' +\r\n\r\nangular.module('mgcrea.ngStrap.alert', ['mgcrea.ngStrap.modal'])\r\n\r\n .provider('$alert', function() {\r\n\r\n var defaults = this.defaults = {\r\n animation: 'am-fade',\r\n prefixClass: 'alert',\r\n prefixEvent: 'alert',\r\n placement: null,\r\n template: 'alert/alert.tpl.html',\r\n container: false,\r\n element: null,\r\n backdrop: false,\r\n keyboard: true,\r\n show: true,\r\n // Specific options\r\n duration: false,\r\n type: false,\r\n dismissable: true\r\n };\r\n\r\n this.$get = function($modal, $timeout) {\r\n\r\n function AlertFactory(config) {\r\n\r\n var $alert = {};\r\n\r\n // Common vars\r\n var options = angular.extend({}, defaults, config);\r\n\r\n $alert = $modal(options);\r\n\r\n // Support scope as string options [/*title, content, */ type, dismissable]\r\n $alert.$scope.dismissable = !!options.dismissable;\r\n if(options.type) {\r\n $alert.$scope.type = options.type;\r\n }\r\n\r\n // Support auto-close duration\r\n var show = $alert.show;\r\n if(options.duration) {\r\n $alert.show = function() {\r\n show();\r\n $timeout(function() {\r\n $alert.hide();\r\n }, options.duration * 1000);\r\n };\r\n }\r\n\r\n return $alert;\r\n\r\n }\r\n\r\n return AlertFactory;\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsAlert', function($window, $sce, $alert) {\r\n\r\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\r\n\r\n return {\r\n restrict: 'EAC',\r\n scope: true,\r\n link: function postLink(scope, element, attr, transclusion) {\r\n\r\n // Directive options\r\n var options = {scope: scope, element: element, show: false};\r\n angular.forEach(['template', 'placement', 'keyboard', 'html', 'container', 'animation', 'duration', 'dismissable'], function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n // Support scope as data-attrs\r\n angular.forEach(['title', 'content', 'type'], function(key) {\r\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\r\n scope[key] = $sce.trustAsHtml(newValue);\r\n });\r\n });\r\n\r\n // Support scope as an object\r\n attr.bsAlert && scope.$watch(attr.bsAlert, function(newValue, oldValue) {\r\n if(angular.isObject(newValue)) {\r\n angular.extend(scope, newValue);\r\n } else {\r\n scope.content = newValue;\r\n }\r\n }, true);\r\n\r\n // Initialize alert\r\n var alert = $alert(options);\r\n\r\n // Trigger\r\n element.on(attr.trigger || 'click', alert.toggle);\r\n\r\n // Garbage collection\r\n scope.$on('$destroy', function() {\r\n if (alert) alert.destroy();\r\n options = null;\r\n alert = null;\r\n });\r\n\r\n }\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.aside', ['mgcrea.ngStrap.modal'])\r\n\r\n .provider('$aside', function() {\r\n\r\n var defaults = this.defaults = {\r\n animation: 'am-fade-and-slide-right',\r\n prefixClass: 'aside',\r\n prefixEvent: 'aside',\r\n placement: 'right',\r\n template: 'aside/aside.tpl.html',\r\n contentTemplate: false,\r\n container: false,\r\n element: null,\r\n backdrop: true,\r\n keyboard: true,\r\n html: false,\r\n show: true\r\n };\r\n\r\n this.$get = function($modal) {\r\n\r\n function AsideFactory(config) {\r\n\r\n var $aside = {};\r\n\r\n // Common vars\r\n var options = angular.extend({}, defaults, config);\r\n\r\n $aside = $modal(options);\r\n\r\n return $aside;\r\n\r\n }\r\n\r\n return AsideFactory;\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsAside', function($window, $sce, $aside) {\r\n\r\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\r\n\r\n return {\r\n restrict: 'EAC',\r\n scope: true,\r\n link: function postLink(scope, element, attr, transclusion) {\r\n // Directive options\r\n var options = {scope: scope, element: element, show: false};\r\n angular.forEach(['template', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation'], function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n // Support scope as data-attrs\r\n angular.forEach(['title', 'content'], function(key) {\r\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\r\n scope[key] = $sce.trustAsHtml(newValue);\r\n });\r\n });\r\n\r\n // Support scope as an object\r\n attr.bsAside && scope.$watch(attr.bsAside, function(newValue, oldValue) {\r\n if(angular.isObject(newValue)) {\r\n angular.extend(scope, newValue);\r\n } else {\r\n scope.content = newValue;\r\n }\r\n }, true);\r\n\r\n // Initialize aside\r\n var aside = $aside(options);\r\n\r\n // Trigger\r\n element.on(attr.trigger || 'click', aside.toggle);\r\n\r\n // Garbage collection\r\n scope.$on('$destroy', function() {\r\n if (aside) aside.destroy();\r\n options = null;\r\n aside = null;\r\n });\r\n\r\n }\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.button', [])\r\n\r\n .provider('$button', function() {\r\n\r\n var defaults = this.defaults = {\r\n activeClass:'active',\r\n toggleEvent:'click'\r\n };\r\n\r\n this.$get = function() {\r\n return {defaults: defaults};\r\n };\r\n\r\n })\r\n\r\n .directive('bsCheckboxGroup', function() {\r\n\r\n return {\r\n restrict: 'A',\r\n require: 'ngModel',\r\n compile: function postLink(element, attr) {\r\n element.attr('data-toggle', 'buttons');\r\n element.removeAttr('ng-model');\r\n var children = element[0].querySelectorAll('input[type=\"checkbox\"]');\r\n angular.forEach(children, function(child) {\r\n var childEl = angular.element(child);\r\n childEl.attr('bs-checkbox', '');\r\n childEl.attr('ng-model', attr.ngModel + '.' + childEl.attr('value'));\r\n });\r\n }\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsCheckbox', function($button, $$rAF) {\r\n\r\n var defaults = $button.defaults;\r\n var constantValueRegExp = /^(true|false|\\d+)$/;\r\n\r\n return {\r\n restrict: 'A',\r\n require: 'ngModel',\r\n link: function postLink(scope, element, attr, controller) {\r\n\r\n var options = defaults;\r\n\r\n // Support label > input[type=\"checkbox\"]\r\n var isInput = element[0].nodeName === 'INPUT';\r\n var activeElement = isInput ? element.parent() : element;\r\n\r\n var trueValue = angular.isDefined(attr.trueValue) ? attr.trueValue : true;\r\n if(constantValueRegExp.test(attr.trueValue)) {\r\n trueValue = scope.$eval(attr.trueValue);\r\n }\r\n var falseValue = angular.isDefined(attr.falseValue) ? attr.falseValue : false;\r\n if(constantValueRegExp.test(attr.falseValue)) {\r\n falseValue = scope.$eval(attr.falseValue);\r\n }\r\n\r\n // Parse exotic values\r\n var hasExoticValues = typeof trueValue !== 'boolean' || typeof falseValue !== 'boolean';\r\n if(hasExoticValues) {\r\n controller.$parsers.push(function(viewValue) {\r\n // console.warn('$parser', element.attr('ng-model'), 'viewValue', viewValue);\r\n return viewValue ? trueValue : falseValue;\r\n });\r\n // modelValue -> $formatters -> viewValue\r\n controller.$formatters.push(function(modelValue) {\r\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\r\n return angular.equals(modelValue, trueValue);\r\n });\r\n // Fix rendering for exotic values\r\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\r\n controller.$render();\r\n });\r\n }\r\n\r\n // model -> view\r\n controller.$render = function () {\r\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\r\n var isActive = angular.equals(controller.$modelValue, trueValue);\r\n $$rAF(function() {\r\n if(isInput) element[0].checked = isActive;\r\n activeElement.toggleClass(options.activeClass, isActive);\r\n });\r\n };\r\n\r\n // view -> model\r\n element.bind(options.toggleEvent, function() {\r\n scope.$apply(function () {\r\n // console.warn('!click', element.attr('ng-model'), 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue, 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue);\r\n if(!isInput) {\r\n controller.$setViewValue(!activeElement.hasClass('active'));\r\n }\r\n if(!hasExoticValues) {\r\n controller.$render();\r\n }\r\n });\r\n });\r\n\r\n }\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsRadioGroup', function() {\r\n\r\n return {\r\n restrict: 'A',\r\n require: 'ngModel',\r\n compile: function postLink(element, attr) {\r\n element.attr('data-toggle', 'buttons');\r\n element.removeAttr('ng-model');\r\n var children = element[0].querySelectorAll('input[type=\"radio\"]');\r\n angular.forEach(children, function(child) {\r\n angular.element(child).attr('bs-radio', '');\r\n angular.element(child).attr('ng-model', attr.ngModel);\r\n });\r\n }\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsRadio', function($button, $$rAF) {\r\n\r\n var defaults = $button.defaults;\r\n var constantValueRegExp = /^(true|false|\\d+)$/;\r\n\r\n return {\r\n restrict: 'A',\r\n require: 'ngModel',\r\n link: function postLink(scope, element, attr, controller) {\r\n\r\n var options = defaults;\r\n\r\n // Support `label > input[type=\"radio\"]` markup\r\n var isInput = element[0].nodeName === 'INPUT';\r\n var activeElement = isInput ? element.parent() : element;\r\n\r\n var value = constantValueRegExp.test(attr.value) ? scope.$eval(attr.value) : attr.value;\r\n\r\n // model -> view\r\n controller.$render = function () {\r\n // console.warn('$render', element.attr('value'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\r\n var isActive = angular.equals(controller.$modelValue, value);\r\n $$rAF(function() {\r\n if(isInput) element[0].checked = isActive;\r\n activeElement.toggleClass(options.activeClass, isActive);\r\n });\r\n };\r\n\r\n // view -> model\r\n element.bind(options.toggleEvent, function() {\r\n scope.$apply(function () {\r\n // console.warn('!click', element.attr('value'), 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue, 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue);\r\n controller.$setViewValue(value);\r\n controller.$render();\r\n });\r\n });\r\n\r\n }\r\n\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.collapse', [])\r\n\r\n .provider('$collapse', function() {\r\n\r\n var defaults = this.defaults = {\r\n animation: 'am-collapse',\r\n disallowToggle: false,\r\n activeClass: 'in',\r\n startCollapsed: false,\r\n allowMultiple: false\r\n };\r\n\r\n var controller = this.controller = function($scope, $element, $attrs) {\r\n var self = this;\r\n\r\n // Attributes options\r\n self.$options = angular.copy(defaults);\r\n angular.forEach(['animation', 'disallowToggle', 'activeClass', 'startCollapsed', 'allowMultiple'], function (key) {\r\n if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];\r\n });\r\n\r\n self.$toggles = [];\r\n self.$targets = [];\r\n\r\n self.$viewChangeListeners = [];\r\n\r\n self.$registerToggle = function(element) {\r\n self.$toggles.push(element);\r\n };\r\n self.$registerTarget = function(element) {\r\n self.$targets.push(element);\r\n };\r\n\r\n self.$unregisterToggle = function(element) {\r\n var index = self.$toggles.indexOf(element);\r\n // remove toggle from $toggles array\r\n self.$toggles.splice(index, 1);\r\n };\r\n self.$unregisterTarget = function(element) {\r\n var index = self.$targets.indexOf(element);\r\n\r\n // remove element from $targets array\r\n self.$targets.splice(index, 1);\r\n\r\n if (self.$options.allowMultiple) {\r\n // remove target index from $active array values\r\n deactivateItem(element);\r\n }\r\n\r\n // fix active item indexes\r\n fixActiveItemIndexes(index);\r\n\r\n self.$viewChangeListeners.forEach(function(fn) {\r\n fn();\r\n });\r\n };\r\n\r\n // use array to store all the currently open panels\r\n self.$targets.$active = !self.$options.startCollapsed ? [0] : [];\r\n self.$setActive = $scope.$setActive = function(value) {\r\n if(angular.isArray(value)) {\r\n self.$targets.$active = angular.copy(value);\r\n }\r\n else if(!self.$options.disallowToggle) {\r\n // toogle element active status\r\n isActive(value) ? deactivateItem(value) : activateItem(value);\r\n } else {\r\n activateItem(value);\r\n }\r\n\r\n self.$viewChangeListeners.forEach(function(fn) {\r\n fn();\r\n });\r\n };\r\n\r\n self.$activeIndexes = function() {\r\n return self.$options.allowMultiple ? self.$targets.$active :\r\n self.$targets.$active.length === 1 ? self.$targets.$active[0] : -1;\r\n };\r\n\r\n function fixActiveItemIndexes(index) {\r\n // item with index was removed, so we\r\n // need to adjust other items index values\r\n var activeIndexes = self.$targets.$active;\r\n for(var i = 0; i < activeIndexes.length; i++) {\r\n if (index < activeIndexes[i]) {\r\n activeIndexes[i] = activeIndexes[i] - 1;\r\n }\r\n\r\n // the last item is active, so we need to\r\n // adjust its index\r\n if (activeIndexes[i] === self.$targets.length) {\r\n activeIndexes[i] = self.$targets.length - 1;\r\n }\r\n }\r\n }\r\n\r\n function isActive(value) {\r\n var activeItems = self.$targets.$active;\r\n return activeItems.indexOf(value) === -1 ? false : true;\r\n }\r\n\r\n function deactivateItem(value) {\r\n var index = self.$targets.$active.indexOf(value);\r\n if (index !== -1) {\r\n self.$targets.$active.splice(index, 1);\r\n }\r\n }\r\n\r\n function activateItem(value) {\r\n if (!self.$options.allowMultiple) {\r\n // remove current selected item\r\n self.$targets.$active.splice(0, 1);\r\n }\r\n\r\n if (self.$targets.$active.indexOf(value) === -1) {\r\n self.$targets.$active.push(value);\r\n }\r\n }\r\n\r\n };\r\n\r\n this.$get = function() {\r\n var $collapse = {};\r\n $collapse.defaults = defaults;\r\n $collapse.controller = controller;\r\n return $collapse;\r\n };\r\n\r\n })\r\n\r\n .directive('bsCollapse', function($window, $animate, $collapse) {\r\n\r\n var defaults = $collapse.defaults;\r\n\r\n return {\r\n require: ['?ngModel', 'bsCollapse'],\r\n controller: ['$scope', '$element', '$attrs', $collapse.controller],\r\n link: function postLink(scope, element, attrs, controllers) {\r\n\r\n var ngModelCtrl = controllers[0];\r\n var bsCollapseCtrl = controllers[1];\r\n\r\n if(ngModelCtrl) {\r\n\r\n // Update the modelValue following\r\n bsCollapseCtrl.$viewChangeListeners.push(function() {\r\n ngModelCtrl.$setViewValue(bsCollapseCtrl.$activeIndexes());\r\n });\r\n\r\n // modelValue -> $formatters -> viewValue\r\n ngModelCtrl.$formatters.push(function(modelValue) {\r\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\r\n if (angular.isArray(modelValue)) {\r\n // model value is an array, so just replace\r\n // the active items directly\r\n bsCollapseCtrl.$setActive(modelValue);\r\n }\r\n else {\r\n var activeIndexes = bsCollapseCtrl.$activeIndexes();\r\n\r\n if (angular.isArray(activeIndexes)) {\r\n // we have an array of selected indexes\r\n if (activeIndexes.indexOf(modelValue * 1) === -1) {\r\n // item with modelValue index is not active\r\n bsCollapseCtrl.$setActive(modelValue * 1);\r\n }\r\n }\r\n else if (activeIndexes !== modelValue * 1) {\r\n bsCollapseCtrl.$setActive(modelValue * 1);\r\n }\r\n }\r\n return modelValue;\r\n });\r\n\r\n }\r\n\r\n }\r\n };\r\n\r\n })\r\n\r\n .directive('bsCollapseToggle', function() {\r\n\r\n return {\r\n require: ['^?ngModel', '^bsCollapse'],\r\n link: function postLink(scope, element, attrs, controllers) {\r\n\r\n var ngModelCtrl = controllers[0];\r\n var bsCollapseCtrl = controllers[1];\r\n\r\n // Add base attr\r\n element.attr('data-toggle', 'collapse');\r\n\r\n // Push pane to parent bsCollapse controller\r\n bsCollapseCtrl.$registerToggle(element);\r\n\r\n // remove toggle from collapse controller when toggle is destroyed\r\n scope.$on('$destroy', function() {\r\n bsCollapseCtrl.$unregisterToggle(element);\r\n });\r\n\r\n element.on('click', function() {\r\n var index = attrs.bsCollapseToggle || bsCollapseCtrl.$toggles.indexOf(element);\r\n bsCollapseCtrl.$setActive(index * 1);\r\n scope.$apply();\r\n });\r\n\r\n }\r\n };\r\n\r\n })\r\n\r\n .directive('bsCollapseTarget', function($animate) {\r\n\r\n return {\r\n require: ['^?ngModel', '^bsCollapse'],\r\n // scope: true,\r\n link: function postLink(scope, element, attrs, controllers) {\r\n\r\n var ngModelCtrl = controllers[0];\r\n var bsCollapseCtrl = controllers[1];\r\n\r\n // Add base class\r\n element.addClass('collapse');\r\n\r\n // Add animation class\r\n if(bsCollapseCtrl.$options.animation) {\r\n element.addClass(bsCollapseCtrl.$options.animation);\r\n }\r\n\r\n // Push pane to parent bsCollapse controller\r\n bsCollapseCtrl.$registerTarget(element);\r\n\r\n // remove pane target from collapse controller when target is destroyed\r\n scope.$on('$destroy', function() {\r\n bsCollapseCtrl.$unregisterTarget(element);\r\n });\r\n\r\n function render() {\r\n var index = bsCollapseCtrl.$targets.indexOf(element);\r\n var active = bsCollapseCtrl.$activeIndexes();\r\n var action = 'removeClass';\r\n if (angular.isArray(active)) {\r\n if (active.indexOf(index) !== -1) {\r\n action = 'addClass';\r\n }\r\n }\r\n else if (index === active) {\r\n action = 'addClass';\r\n }\r\n\r\n $animate[action](element, bsCollapseCtrl.$options.activeClass);\r\n }\r\n\r\n bsCollapseCtrl.$viewChangeListeners.push(function() {\r\n render();\r\n });\r\n render();\r\n\r\n }\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.datepicker', [\r\n 'mgcrea.ngStrap.helpers.dateParser',\r\n 'mgcrea.ngStrap.helpers.dateFormatter',\r\n 'mgcrea.ngStrap.tooltip'])\r\n\r\n .provider('$datepicker', function() {\r\n\r\n var defaults = this.defaults = {\r\n animation: 'am-fade',\r\n prefixClass: 'datepicker',\r\n placement: 'bottom-left',\r\n template: 'datepicker/datepicker.tpl.html',\r\n trigger: 'focus',\r\n container: false,\r\n keyboard: true,\r\n html: false,\r\n delay: 0,\r\n // lang: $locale.id,\r\n useNative: false,\r\n dateType: 'date',\r\n dateFormat: 'shortDate',\r\n modelDateFormat: null,\r\n dayFormat: 'dd',\r\n monthFormat: 'MMM',\r\n yearFormat: 'yyyy',\r\n monthTitleFormat: 'MMMM yyyy',\r\n yearTitleFormat: 'yyyy',\r\n strictFormat: false,\r\n autoclose: false,\r\n minDate: -Infinity,\r\n maxDate: +Infinity,\r\n startView: 0,\r\n minView: 0,\r\n startWeek: 0,\r\n daysOfWeekDisabled: '',\r\n iconLeft: 'glyphicon glyphicon-chevron-left',\r\n iconRight: 'glyphicon glyphicon-chevron-right'\r\n };\r\n\r\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, datepickerViews, $tooltip, $timeout) {\r\n\r\n var bodyEl = angular.element($window.document.body);\r\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\r\n var isTouch = ('createTouch' in $window.document) && isNative;\r\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\r\n\r\n function DatepickerFactory(element, controller, config) {\r\n\r\n var $datepicker = $tooltip(element, angular.extend({}, defaults, config));\r\n var parentScope = config.scope;\r\n var options = $datepicker.$options;\r\n var scope = $datepicker.$scope;\r\n if(options.startView) options.startView -= options.minView;\r\n\r\n // View vars\r\n\r\n var pickerViews = datepickerViews($datepicker);\r\n $datepicker.$views = pickerViews.views;\r\n var viewDate = pickerViews.viewDate;\r\n scope.$mode = options.startView;\r\n scope.$iconLeft = options.iconLeft;\r\n scope.$iconRight = options.iconRight;\r\n var $picker = $datepicker.$views[scope.$mode];\r\n\r\n // Scope methods\r\n\r\n scope.$select = function(date) {\r\n $datepicker.select(date);\r\n };\r\n scope.$selectPane = function(value) {\r\n $datepicker.$selectPane(value);\r\n };\r\n scope.$toggleMode = function() {\r\n $datepicker.setMode((scope.$mode + 1) % $datepicker.$views.length);\r\n };\r\n\r\n // Public methods\r\n\r\n $datepicker.update = function(date) {\r\n // console.warn('$datepicker.update() newValue=%o', date);\r\n if(angular.isDate(date) && !isNaN(date.getTime())) {\r\n $datepicker.$date = date;\r\n $picker.update.call($picker, date);\r\n }\r\n // Build only if pristine\r\n $datepicker.$build(true);\r\n };\r\n\r\n $datepicker.updateDisabledDates = function(dateRanges) {\r\n options.disabledDateRanges = dateRanges;\r\n for(var i = 0, l = scope.rows.length; i < l; i++) {\r\n angular.forEach(scope.rows[i], $datepicker.$setDisabledEl);\r\n }\r\n };\r\n\r\n $datepicker.select = function(date, keep) {\r\n // console.warn('$datepicker.select', date, scope.$mode);\r\n if(!angular.isDate(controller.$dateValue)) controller.$dateValue = new Date(date);\r\n if(!scope.$mode || keep) {\r\n controller.$setViewValue(angular.copy(date));\r\n controller.$render();\r\n if(options.autoclose && !keep) {\r\n $timeout(function() { $datepicker.hide(true); });\r\n }\r\n } else {\r\n angular.extend(viewDate, {year: date.getFullYear(), month: date.getMonth(), date: date.getDate()});\r\n $datepicker.setMode(scope.$mode - 1);\r\n $datepicker.$build();\r\n }\r\n };\r\n\r\n $datepicker.setMode = function(mode) {\r\n // console.warn('$datepicker.setMode', mode);\r\n scope.$mode = mode;\r\n $picker = $datepicker.$views[scope.$mode];\r\n $datepicker.$build();\r\n };\r\n\r\n // Protected methods\r\n\r\n $datepicker.$build = function(pristine) {\r\n // console.warn('$datepicker.$build() viewDate=%o', viewDate);\r\n if(pristine === true && $picker.built) return;\r\n if(pristine === false && !$picker.built) return;\r\n $picker.build.call($picker);\r\n };\r\n\r\n $datepicker.$updateSelected = function() {\r\n for(var i = 0, l = scope.rows.length; i < l; i++) {\r\n angular.forEach(scope.rows[i], updateSelected);\r\n }\r\n };\r\n\r\n $datepicker.$isSelected = function(date) {\r\n return $picker.isSelected(date);\r\n };\r\n\r\n $datepicker.$setDisabledEl = function(el) {\r\n el.disabled = $picker.isDisabled(el.date);\r\n };\r\n\r\n $datepicker.$selectPane = function(value) {\r\n var steps = $picker.steps;\r\n // set targetDate to first day of month to avoid problems with\r\n // date values rollover. This assumes the viewDate does not\r\n // depend on the day of the month \r\n var targetDate = new Date(Date.UTC(viewDate.year + ((steps.year || 0) * value), viewDate.month + ((steps.month || 0) * value), 1));\r\n angular.extend(viewDate, {year: targetDate.getUTCFullYear(), month: targetDate.getUTCMonth(), date: targetDate.getUTCDate()});\r\n $datepicker.$build();\r\n };\r\n\r\n $datepicker.$onMouseDown = function(evt) {\r\n // Prevent blur on mousedown on .dropdown-menu\r\n evt.preventDefault();\r\n evt.stopPropagation();\r\n // Emulate click for mobile devices\r\n if(isTouch) {\r\n var targetEl = angular.element(evt.target);\r\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\r\n targetEl = targetEl.parent();\r\n }\r\n targetEl.triggerHandler('click');\r\n }\r\n };\r\n\r\n $datepicker.$onKeyDown = function(evt) {\r\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\r\n evt.preventDefault();\r\n evt.stopPropagation();\r\n\r\n if(evt.keyCode === 13) {\r\n if(!scope.$mode) {\r\n return $datepicker.hide(true);\r\n } else {\r\n return scope.$apply(function() { $datepicker.setMode(scope.$mode - 1); });\r\n }\r\n }\r\n\r\n // Navigate with keyboard\r\n $picker.onKeyDown(evt);\r\n parentScope.$digest();\r\n };\r\n\r\n // Private\r\n\r\n function updateSelected(el) {\r\n el.selected = $datepicker.$isSelected(el.date);\r\n }\r\n\r\n function focusElement() {\r\n element[0].focus();\r\n }\r\n\r\n // Overrides\r\n\r\n var _init = $datepicker.init;\r\n $datepicker.init = function() {\r\n if(isNative && options.useNative) {\r\n element.prop('type', 'date');\r\n element.css('-webkit-appearance', 'textfield');\r\n return;\r\n } else if(isTouch) {\r\n element.prop('type', 'text');\r\n element.attr('readonly', 'true');\r\n element.on('click', focusElement);\r\n }\r\n _init();\r\n };\r\n\r\n var _destroy = $datepicker.destroy;\r\n $datepicker.destroy = function() {\r\n if(isNative && options.useNative) {\r\n element.off('click', focusElement);\r\n }\r\n _destroy();\r\n };\r\n\r\n var _show = $datepicker.show;\r\n $datepicker.show = function() {\r\n _show();\r\n // use timeout to hookup the events to prevent \r\n // event bubbling from being processed imediately. \r\n $timeout(function() {\r\n $datepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);\r\n if(options.keyboard) {\r\n element.on('keydown', $datepicker.$onKeyDown);\r\n }\r\n }, 0, false);\r\n };\r\n\r\n var _hide = $datepicker.hide;\r\n $datepicker.hide = function(blur) {\r\n if(!$datepicker.$isShown) return;\r\n $datepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);\r\n if(options.keyboard) {\r\n element.off('keydown', $datepicker.$onKeyDown);\r\n }\r\n _hide(blur);\r\n };\r\n\r\n return $datepicker;\r\n\r\n }\r\n\r\n DatepickerFactory.defaults = defaults;\r\n return DatepickerFactory;\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsDatepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $datepicker) {\r\n\r\n var defaults = $datepicker.defaults;\r\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\r\n\r\n return {\r\n restrict: 'EAC',\r\n require: 'ngModel',\r\n link: function postLink(scope, element, attr, controller) {\r\n\r\n // Directive options\r\n var options = {scope: scope, controller: controller};\r\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'dateType', 'dateFormat', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled'], function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n // Visibility binding support\r\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\r\n if(!datepicker || !angular.isDefined(newValue)) return;\r\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(datepicker),?/i);\r\n newValue === true ? datepicker.show() : datepicker.hide();\r\n });\r\n\r\n // Initialize datepicker\r\n var datepicker = $datepicker(element, controller, options);\r\n options = datepicker.$options;\r\n // Set expected iOS format\r\n if(isNative && options.useNative) options.dateFormat = 'yyyy-MM-dd';\r\n\r\n var lang = options.lang;\r\n\r\n var formatDate = function(date, format) {\r\n return $dateFormatter.formatDate(date, format, lang);\r\n };\r\n \r\n var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});\r\n\r\n // Observe attributes for changes\r\n angular.forEach(['minDate', 'maxDate'], function(key) {\r\n // console.warn('attr.$observe(%s)', key, attr[key]);\r\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\r\n // console.warn('attr.$observe(%s)=%o', key, newValue);\r\n datepicker.$options[key] = dateParser.getDateForAttribute(key, newValue);\r\n // Build only if dirty\r\n !isNaN(datepicker.$options[key]) && datepicker.$build(false);\r\n validateAgainstMinMaxDate(controller.$dateValue);\r\n });\r\n });\r\n\r\n // Watch model for changes\r\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\r\n datepicker.update(controller.$dateValue);\r\n }, true);\r\n\r\n // Normalize undefined/null/empty array,\r\n // so that we don't treat changing from undefined->null as a change.\r\n function normalizeDateRanges(ranges) {\r\n if (!ranges || !ranges.length) return null;\r\n return ranges;\r\n }\r\n\r\n if (angular.isDefined(attr.disabledDates)) {\r\n scope.$watch(attr.disabledDates, function(disabledRanges, previousValue) {\r\n disabledRanges = normalizeDateRanges(disabledRanges);\r\n previousValue = normalizeDateRanges(previousValue);\r\n\r\n if (disabledRanges) {\r\n datepicker.updateDisabledDates(disabledRanges);\r\n }\r\n });\r\n }\r\n\r\n function validateAgainstMinMaxDate(parsedDate) {\r\n if (!angular.isDate(parsedDate)) return;\r\n var isMinValid = isNaN(datepicker.$options.minDate) || parsedDate.getTime() >= datepicker.$options.minDate;\r\n var isMaxValid = isNaN(datepicker.$options.maxDate) || parsedDate.getTime() <= datepicker.$options.maxDate;\r\n var isValid = isMinValid && isMaxValid;\r\n controller.$setValidity('date', isValid);\r\n controller.$setValidity('min', isMinValid);\r\n controller.$setValidity('max', isMaxValid);\r\n // Only update the model when we have a valid date\r\n if(isValid) controller.$dateValue = parsedDate;\r\n }\r\n\r\n // viewValue -> $parsers -> modelValue\r\n controller.$parsers.unshift(function(viewValue) {\r\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\r\n // Null values should correctly reset the model value & validity\r\n if(!viewValue) {\r\n controller.$setValidity('date', true);\r\n // BREAKING CHANGE:\r\n // return null (not undefined) when input value is empty, so angularjs 1.3 \r\n // ngModelController can go ahead and run validators, like ngRequired\r\n return null;\r\n }\r\n var parsedDate = dateParser.parse(viewValue, controller.$dateValue);\r\n if(!parsedDate || isNaN(parsedDate.getTime())) {\r\n controller.$setValidity('date', false);\r\n // return undefined, causes ngModelController to \r\n // invalidate model value \r\n return;\r\n } else {\r\n validateAgainstMinMaxDate(parsedDate);\r\n }\r\n if(options.dateType === 'string') {\r\n return formatDate(parsedDate, options.modelDateFormat || options.dateFormat);\r\n } else if(options.dateType === 'number') {\r\n return controller.$dateValue.getTime();\r\n } else if(options.dateType === 'unix') {\r\n return controller.$dateValue.getTime() / 1000;\r\n } else if(options.dateType === 'iso') {\r\n return controller.$dateValue.toISOString();\r\n } else {\r\n return new Date(controller.$dateValue);\r\n }\r\n });\r\n\r\n // modelValue -> $formatters -> viewValue\r\n controller.$formatters.push(function(modelValue) {\r\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\r\n var date;\r\n if(angular.isUndefined(modelValue) || modelValue === null) {\r\n date = NaN;\r\n } else if(angular.isDate(modelValue)) {\r\n date = modelValue;\r\n } else if(options.dateType === 'string') {\r\n date = dateParser.parse(modelValue, null, options.modelDateFormat);\r\n } else if(options.dateType === 'unix') {\r\n date = new Date(modelValue * 1000);\r\n } else {\r\n date = new Date(modelValue);\r\n }\r\n // Setup default value?\r\n // if(isNaN(date.getTime())) {\r\n // var today = new Date();\r\n // date = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0, 0);\r\n // }\r\n controller.$dateValue = date;\r\n return getDateFormattedString();\r\n });\r\n\r\n // viewValue -> element\r\n controller.$render = function() {\r\n // console.warn('$render(\"%s\"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);\r\n element.val(getDateFormattedString());\r\n };\r\n\r\n function getDateFormattedString() {\r\n return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.dateFormat);\r\n }\r\n\r\n // Garbage collection\r\n scope.$on('$destroy', function() {\r\n if(datepicker) datepicker.destroy();\r\n options = null;\r\n datepicker = null;\r\n });\r\n\r\n }\r\n };\r\n\r\n })\r\n\r\n .provider('datepickerViews', function() {\r\n\r\n var defaults = this.defaults = {\r\n dayFormat: 'dd',\r\n daySplit: 7\r\n };\r\n\r\n // Split array into smaller arrays\r\n function split(arr, size) {\r\n var arrays = [];\r\n while(arr.length > 0) {\r\n arrays.push(arr.splice(0, size));\r\n }\r\n return arrays;\r\n }\r\n\r\n // Modulus operator\r\n function mod(n, m) {\r\n return ((n % m) + m) % m;\r\n }\r\n\r\n this.$get = function($dateFormatter, $dateParser, $sce) {\r\n\r\n return function(picker) {\r\n\r\n var scope = picker.$scope;\r\n var options = picker.$options;\r\n\r\n var lang = options.lang;\r\n var formatDate = function(date, format) {\r\n return $dateFormatter.formatDate(date, format, lang);\r\n };\r\n var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});\r\n\r\n var weekDaysMin = $dateFormatter.weekdaysShort(lang);\r\n var weekDaysLabels = weekDaysMin.slice(options.startWeek).concat(weekDaysMin.slice(0, options.startWeek));\r\n var weekDaysLabelsHtml = $sce.trustAsHtml('' + weekDaysLabels.join(' ') + ' ');\r\n\r\n var startDate = picker.$date || (options.startDate ? dateParser.getDateForAttribute('startDate', options.startDate) : new Date());\r\n var viewDate = {year: startDate.getFullYear(), month: startDate.getMonth(), date: startDate.getDate()};\r\n var timezoneOffset = startDate.getTimezoneOffset() * 6e4;\r\n\r\n var views = [{\r\n format: options.dayFormat,\r\n split: 7,\r\n steps: { month: 1 },\r\n update: function(date, force) {\r\n if(!this.built || force || date.getFullYear() !== viewDate.year || date.getMonth() !== viewDate.month) {\r\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\r\n picker.$build();\r\n } else if(date.getDate() !== viewDate.date) {\r\n viewDate.date = picker.$date.getDate();\r\n picker.$updateSelected();\r\n }\r\n },\r\n build: function() {\r\n var firstDayOfMonth = new Date(viewDate.year, viewDate.month, 1), firstDayOfMonthOffset = firstDayOfMonth.getTimezoneOffset();\r\n var firstDate = new Date(+firstDayOfMonth - mod(firstDayOfMonth.getDay() - options.startWeek, 7) * 864e5), firstDateOffset = firstDate.getTimezoneOffset();\r\n var today = new Date().toDateString();\r\n // Handle daylight time switch\r\n if(firstDateOffset !== firstDayOfMonthOffset) firstDate = new Date(+firstDate + (firstDateOffset - firstDayOfMonthOffset) * 60e3);\r\n var days = [], day;\r\n for(var i = 0; i < 42; i++) { // < 7 * 6\r\n day = dateParser.daylightSavingAdjust(new Date(firstDate.getFullYear(), firstDate.getMonth(), firstDate.getDate() + i));\r\n days.push({date: day, isToday: day.toDateString() === today, label: formatDate(day, this.format), selected: picker.$date && this.isSelected(day), muted: day.getMonth() !== viewDate.month, disabled: this.isDisabled(day)});\r\n }\r\n scope.title = formatDate(firstDayOfMonth, options.monthTitleFormat);\r\n scope.showLabels = true;\r\n scope.labels = weekDaysLabelsHtml;\r\n scope.rows = split(days, this.split);\r\n this.built = true;\r\n },\r\n isSelected: function(date) {\r\n return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth() && date.getDate() === picker.$date.getDate();\r\n },\r\n isDisabled: function(date) {\r\n var time = date.getTime();\r\n\r\n // Disabled because of min/max date.\r\n if (time < options.minDate || time > options.maxDate) return true;\r\n\r\n // Disabled due to being a disabled day of the week\r\n if (options.daysOfWeekDisabled.indexOf(date.getDay()) !== -1) return true;\r\n\r\n // Disabled because of disabled date range.\r\n if (options.disabledDateRanges) {\r\n for (var i = 0; i < options.disabledDateRanges.length; i++) {\r\n if (time >= options.disabledDateRanges[i].start && time <= options.disabledDateRanges[i].end) {\r\n return true;\r\n }\r\n }\r\n }\r\n\r\n return false;\r\n },\r\n onKeyDown: function(evt) {\r\n if (!picker.$date) {\r\n return;\r\n }\r\n var actualTime = picker.$date.getTime();\r\n var newDate;\r\n\r\n if(evt.keyCode === 37) newDate = new Date(actualTime - 1 * 864e5);\r\n else if(evt.keyCode === 38) newDate = new Date(actualTime - 7 * 864e5);\r\n else if(evt.keyCode === 39) newDate = new Date(actualTime + 1 * 864e5);\r\n else if(evt.keyCode === 40) newDate = new Date(actualTime + 7 * 864e5);\r\n\r\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\r\n }\r\n }, {\r\n name: 'month',\r\n format: options.monthFormat,\r\n split: 4,\r\n steps: { year: 1 },\r\n update: function(date, force) {\r\n if(!this.built || date.getFullYear() !== viewDate.year) {\r\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\r\n picker.$build();\r\n } else if(date.getMonth() !== viewDate.month) {\r\n angular.extend(viewDate, {month: picker.$date.getMonth(), date: picker.$date.getDate()});\r\n picker.$updateSelected();\r\n }\r\n },\r\n build: function() {\r\n var firstMonth = new Date(viewDate.year, 0, 1);\r\n var months = [], month;\r\n for (var i = 0; i < 12; i++) {\r\n month = new Date(viewDate.year, i, 1);\r\n months.push({date: month, label: formatDate(month, this.format), selected: picker.$isSelected(month), disabled: this.isDisabled(month)});\r\n }\r\n scope.title = formatDate(month, options.yearTitleFormat);\r\n scope.showLabels = false;\r\n scope.rows = split(months, this.split);\r\n this.built = true;\r\n },\r\n isSelected: function(date) {\r\n return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth();\r\n },\r\n isDisabled: function(date) {\r\n var lastDate = +new Date(date.getFullYear(), date.getMonth() + 1, 0);\r\n return lastDate < options.minDate || date.getTime() > options.maxDate;\r\n },\r\n onKeyDown: function(evt) {\r\n if (!picker.$date) {\r\n return;\r\n }\r\n var actualMonth = picker.$date.getMonth();\r\n var newDate = new Date(picker.$date);\r\n\r\n if(evt.keyCode === 37) newDate.setMonth(actualMonth - 1);\r\n else if(evt.keyCode === 38) newDate.setMonth(actualMonth - 4);\r\n else if(evt.keyCode === 39) newDate.setMonth(actualMonth + 1);\r\n else if(evt.keyCode === 40) newDate.setMonth(actualMonth + 4);\r\n\r\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\r\n }\r\n }, {\r\n name: 'year',\r\n format: options.yearFormat,\r\n split: 4,\r\n steps: { year: 12 },\r\n update: function(date, force) {\r\n if(!this.built || force || parseInt(date.getFullYear()/20, 10) !== parseInt(viewDate.year/20, 10)) {\r\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\r\n picker.$build();\r\n } else if(date.getFullYear() !== viewDate.year) {\r\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\r\n picker.$updateSelected();\r\n }\r\n },\r\n build: function() {\r\n var firstYear = viewDate.year - viewDate.year % (this.split * 3);\r\n var years = [], year;\r\n for (var i = 0; i < 12; i++) {\r\n year = new Date(firstYear + i, 0, 1);\r\n years.push({date: year, label: formatDate(year, this.format), selected: picker.$isSelected(year), disabled: this.isDisabled(year)});\r\n }\r\n scope.title = years[0].label + '-' + years[years.length - 1].label;\r\n scope.showLabels = false;\r\n scope.rows = split(years, this.split);\r\n this.built = true;\r\n },\r\n isSelected: function(date) {\r\n return picker.$date && date.getFullYear() === picker.$date.getFullYear();\r\n },\r\n isDisabled: function(date) {\r\n var lastDate = +new Date(date.getFullYear() + 1, 0, 0);\r\n return lastDate < options.minDate || date.getTime() > options.maxDate;\r\n },\r\n onKeyDown: function(evt) {\r\n if (!picker.$date) {\r\n return;\r\n }\r\n var actualYear = picker.$date.getFullYear(),\r\n newDate = new Date(picker.$date);\r\n\r\n if(evt.keyCode === 37) newDate.setYear(actualYear - 1);\r\n else if(evt.keyCode === 38) newDate.setYear(actualYear - 4);\r\n else if(evt.keyCode === 39) newDate.setYear(actualYear + 1);\r\n else if(evt.keyCode === 40) newDate.setYear(actualYear + 4);\r\n\r\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\r\n }\r\n }];\r\n\r\n return {\r\n views: options.minView ? Array.prototype.slice.call(views, options.minView) : views,\r\n viewDate: viewDate\r\n };\r\n\r\n };\r\n\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.dropdown', ['mgcrea.ngStrap.tooltip'])\r\n\r\n .provider('$dropdown', function() {\r\n\r\n var defaults = this.defaults = {\r\n animation: 'am-fade',\r\n prefixClass: 'dropdown',\r\n placement: 'bottom-left',\r\n template: 'dropdown/dropdown.tpl.html',\r\n trigger: 'click',\r\n container: false,\r\n keyboard: true,\r\n html: false,\r\n delay: 0\r\n };\r\n\r\n this.$get = function($window, $rootScope, $tooltip, $timeout) {\r\n\r\n var bodyEl = angular.element($window.document.body);\r\n var matchesSelector = Element.prototype.matchesSelector || Element.prototype.webkitMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector;\r\n\r\n function DropdownFactory(element, config) {\r\n\r\n var $dropdown = {};\r\n\r\n // Common vars\r\n var options = angular.extend({}, defaults, config);\r\n var scope = $dropdown.$scope = options.scope && options.scope.$new() || $rootScope.$new();\r\n\r\n $dropdown = $tooltip(element, options);\r\n var parentEl = element.parent();\r\n\r\n // Protected methods\r\n\r\n $dropdown.$onKeyDown = function(evt) {\r\n if (!/(38|40)/.test(evt.keyCode)) return;\r\n evt.preventDefault();\r\n evt.stopPropagation();\r\n\r\n // Retrieve focused index\r\n var items = angular.element($dropdown.$element[0].querySelectorAll('li:not(.divider) a'));\r\n if(!items.length) return;\r\n var index;\r\n angular.forEach(items, function(el, i) {\r\n if(matchesSelector && matchesSelector.call(el, ':focus')) index = i;\r\n });\r\n\r\n // Navigate with keyboard\r\n if(evt.keyCode === 38 && index > 0) index--;\r\n else if(evt.keyCode === 40 && index < items.length - 1) index++;\r\n else if(angular.isUndefined(index)) index = 0;\r\n items.eq(index)[0].focus();\r\n\r\n };\r\n\r\n // Overrides\r\n\r\n var show = $dropdown.show;\r\n $dropdown.show = function() {\r\n show();\r\n // use timeout to hookup the events to prevent \r\n // event bubbling from being processed imediately. \r\n $timeout(function() {\r\n options.keyboard && $dropdown.$element.on('keydown', $dropdown.$onKeyDown);\r\n bodyEl.on('click', onBodyClick);\r\n }, 0, false);\r\n parentEl.hasClass('dropdown') && parentEl.addClass('open');\r\n };\r\n\r\n var hide = $dropdown.hide;\r\n $dropdown.hide = function() {\r\n if(!$dropdown.$isShown) return;\r\n options.keyboard && $dropdown.$element.off('keydown', $dropdown.$onKeyDown);\r\n bodyEl.off('click', onBodyClick);\r\n parentEl.hasClass('dropdown') && parentEl.removeClass('open');\r\n hide();\r\n };\r\n\r\n var destroy = $dropdown.destroy;\r\n $dropdown.destroy = function() {\r\n bodyEl.off('click', onBodyClick);\r\n destroy();\r\n };\r\n\r\n // Private functions\r\n\r\n function onBodyClick(evt) {\r\n if(evt.target === element[0]) return;\r\n return evt.target !== element[0] && $dropdown.hide();\r\n }\r\n\r\n return $dropdown;\r\n\r\n }\r\n\r\n return DropdownFactory;\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsDropdown', function($window, $sce, $dropdown) {\r\n\r\n return {\r\n restrict: 'EAC',\r\n scope: true,\r\n link: function postLink(scope, element, attr, transclusion) {\r\n\r\n // Directive options\r\n var options = {scope: scope};\r\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template'], function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n // Support scope as an object\r\n attr.bsDropdown && scope.$watch(attr.bsDropdown, function(newValue, oldValue) {\r\n scope.content = newValue;\r\n }, true);\r\n\r\n // Visibility binding support\r\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\r\n if(!dropdown || !angular.isDefined(newValue)) return;\r\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(dropdown),?/i);\r\n newValue === true ? dropdown.show() : dropdown.hide();\r\n });\r\n\r\n // Initialize dropdown\r\n var dropdown = $dropdown(element, options);\r\n\r\n // Garbage collection\r\n scope.$on('$destroy', function() {\r\n if (dropdown) dropdown.destroy();\r\n options = null;\r\n dropdown = null;\r\n });\r\n\r\n }\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.modal', ['mgcrea.ngStrap.helpers.dimensions'])\r\n\r\n .provider('$modal', function() {\r\n\r\n var defaults = this.defaults = {\r\n animation: 'am-fade',\r\n backdropAnimation: 'am-fade',\r\n prefixClass: 'modal',\r\n prefixEvent: 'modal',\r\n placement: 'top',\r\n template: 'modal/modal.tpl.html',\r\n contentTemplate: false,\r\n container: false,\r\n element: null,\r\n backdrop: true,\r\n keyboard: true,\r\n html: false,\r\n show: true\r\n };\r\n\r\n this.$get = function($window, $rootScope, $compile, $q, $templateCache, $http, $animate, $timeout, $sce, dimensions) {\r\n\r\n var forEach = angular.forEach;\r\n var trim = String.prototype.trim;\r\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\r\n var bodyElement = angular.element($window.document.body);\r\n var htmlReplaceRegExp = /ng-bind=\"/ig;\r\n\r\n function ModalFactory(config) {\r\n\r\n var $modal = {};\r\n\r\n // Common vars\r\n var options = $modal.$options = angular.extend({}, defaults, config);\r\n $modal.$promise = fetchTemplate(options.template);\r\n var scope = $modal.$scope = options.scope && options.scope.$new() || $rootScope.$new();\r\n if(!options.element && !options.container) {\r\n options.container = 'body';\r\n }\r\n\r\n // Support scope as string options\r\n forEach(['title', 'content'], function(key) {\r\n if(options[key]) scope[key] = $sce.trustAsHtml(options[key]);\r\n });\r\n\r\n // Provide scope helpers\r\n scope.$hide = function() {\r\n scope.$$postDigest(function() {\r\n $modal.hide();\r\n });\r\n };\r\n scope.$show = function() {\r\n scope.$$postDigest(function() {\r\n $modal.show();\r\n });\r\n };\r\n scope.$toggle = function() {\r\n scope.$$postDigest(function() {\r\n $modal.toggle();\r\n });\r\n };\r\n // Publish isShown as a protected var on scope\r\n $modal.$isShown = scope.$isShown = false;\r\n\r\n // Support contentTemplate option\r\n if(options.contentTemplate) {\r\n $modal.$promise = $modal.$promise.then(function(template) {\r\n var templateEl = angular.element(template);\r\n return fetchTemplate(options.contentTemplate)\r\n .then(function(contentTemplate) {\r\n var contentEl = findElement('[ng-bind=\"content\"]', templateEl[0]).removeAttr('ng-bind').html(contentTemplate);\r\n // Drop the default footer as you probably don't want it if you use a custom contentTemplate\r\n if(!config.template) contentEl.next().remove();\r\n return templateEl[0].outerHTML;\r\n });\r\n });\r\n }\r\n\r\n // Fetch, compile then initialize modal\r\n var modalLinker, modalElement;\r\n var backdropElement = angular.element('
');\r\n $modal.$promise.then(function(template) {\r\n if(angular.isObject(template)) template = template.data;\r\n if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html=\"');\r\n template = trim.apply(template);\r\n modalLinker = $compile(template);\r\n $modal.init();\r\n });\r\n\r\n $modal.init = function() {\r\n\r\n // Options: show\r\n if(options.show) {\r\n scope.$$postDigest(function() {\r\n $modal.show();\r\n });\r\n }\r\n\r\n };\r\n\r\n $modal.destroy = function() {\r\n\r\n // Remove element\r\n if(modalElement) {\r\n modalElement.remove();\r\n modalElement = null;\r\n }\r\n if(backdropElement) {\r\n backdropElement.remove();\r\n backdropElement = null;\r\n }\r\n\r\n // Destroy scope\r\n scope.$destroy();\r\n\r\n };\r\n\r\n $modal.show = function() {\r\n if($modal.$isShown) return;\r\n\r\n if(scope.$emit(options.prefixEvent + '.show.before', $modal).defaultPrevented) {\r\n return;\r\n }\r\n var parent, after;\r\n if(angular.isElement(options.container)) {\r\n parent = options.container;\r\n after = options.container[0].lastChild ? angular.element(options.container[0].lastChild) : null;\r\n } else {\r\n if (options.container) {\r\n parent = findElement(options.container);\r\n after = parent[0].lastChild ? angular.element(parent[0].lastChild) : null;\r\n } else {\r\n parent = null;\r\n after = options.element;\r\n }\r\n }\r\n\r\n // Fetch a cloned element linked from template\r\n modalElement = $modal.$element = modalLinker(scope, function(clonedElement, scope) {});\r\n\r\n // Set the initial positioning.\r\n modalElement.css({display: 'block'}).addClass(options.placement);\r\n\r\n // Options: animation\r\n if(options.animation) {\r\n if(options.backdrop) {\r\n backdropElement.addClass(options.backdropAnimation);\r\n }\r\n modalElement.addClass(options.animation);\r\n }\r\n\r\n if(options.backdrop) {\r\n $animate.enter(backdropElement, bodyElement, null);\r\n }\r\n // Support v1.3+ $animate\r\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\r\n var promise = $animate.enter(modalElement, parent, after, enterAnimateCallback);\r\n if(promise && promise.then) promise.then(enterAnimateCallback);\r\n\r\n $modal.$isShown = scope.$isShown = true;\r\n safeDigest(scope);\r\n // Focus once the enter-animation has started\r\n // Weird PhantomJS bug hack\r\n var el = modalElement[0];\r\n requestAnimationFrame(function() {\r\n el.focus();\r\n });\r\n\r\n bodyElement.addClass(options.prefixClass + '-open');\r\n if(options.animation) {\r\n bodyElement.addClass(options.prefixClass + '-with-' + options.animation);\r\n }\r\n\r\n // Bind events\r\n if(options.backdrop) {\r\n modalElement.on('click', hideOnBackdropClick);\r\n backdropElement.on('click', hideOnBackdropClick);\r\n backdropElement.on('wheel', preventEventDefault);\r\n }\r\n if(options.keyboard) {\r\n modalElement.on('keyup', $modal.$onKeyUp);\r\n }\r\n };\r\n\r\n function enterAnimateCallback() {\r\n scope.$emit(options.prefixEvent + '.show', $modal);\r\n }\r\n\r\n $modal.hide = function() {\r\n if(!$modal.$isShown) return;\r\n\r\n if(scope.$emit(options.prefixEvent + '.hide.before', $modal).defaultPrevented) {\r\n return;\r\n }\r\n var promise = $animate.leave(modalElement, leaveAnimateCallback);\r\n // Support v1.3+ $animate\r\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\r\n if(promise && promise.then) promise.then(leaveAnimateCallback);\r\n\r\n if(options.backdrop) {\r\n $animate.leave(backdropElement);\r\n }\r\n $modal.$isShown = scope.$isShown = false;\r\n safeDigest(scope);\r\n\r\n // Unbind events\r\n if(options.backdrop) {\r\n modalElement.off('click', hideOnBackdropClick);\r\n backdropElement.off('click', hideOnBackdropClick);\r\n backdropElement.off('wheel', preventEventDefault);\r\n }\r\n if(options.keyboard) {\r\n modalElement.off('keyup', $modal.$onKeyUp);\r\n }\r\n };\r\n\r\n function leaveAnimateCallback() {\r\n scope.$emit(options.prefixEvent + '.hide', $modal);\r\n bodyElement.removeClass(options.prefixClass + '-open');\r\n if(options.animation) {\r\n bodyElement.removeClass(options.prefixClass + '-with-' + options.animation);\r\n }\r\n }\r\n\r\n $modal.toggle = function() {\r\n\r\n $modal.$isShown ? $modal.hide() : $modal.show();\r\n\r\n };\r\n\r\n $modal.focus = function() {\r\n modalElement[0].focus();\r\n };\r\n\r\n // Protected methods\r\n\r\n $modal.$onKeyUp = function(evt) {\r\n\r\n if (evt.which === 27 && $modal.$isShown) {\r\n $modal.hide();\r\n evt.stopPropagation();\r\n }\r\n\r\n };\r\n\r\n // Private methods\r\n\r\n function hideOnBackdropClick(evt) {\r\n if(evt.target !== evt.currentTarget) return;\r\n options.backdrop === 'static' ? $modal.focus() : $modal.hide();\r\n }\r\n\r\n function preventEventDefault(evt) {\r\n evt.preventDefault();\r\n }\r\n\r\n return $modal;\r\n\r\n }\r\n\r\n // Helper functions\r\n\r\n function safeDigest(scope) {\r\n scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();\r\n }\r\n\r\n function findElement(query, element) {\r\n return angular.element((element || document).querySelectorAll(query));\r\n }\r\n\r\n var fetchPromises = {};\r\n function fetchTemplate(template) {\r\n if(fetchPromises[template]) return fetchPromises[template];\r\n return (fetchPromises[template] = $q.when($templateCache.get(template) || $http.get(template))\r\n .then(function(res) {\r\n if(angular.isObject(res)) {\r\n $templateCache.put(template, res.data);\r\n return res.data;\r\n }\r\n return res;\r\n }));\r\n }\r\n\r\n return ModalFactory;\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsModal', function($window, $sce, $modal) {\r\n\r\n return {\r\n restrict: 'EAC',\r\n scope: true,\r\n link: function postLink(scope, element, attr, transclusion) {\r\n\r\n // Directive options\r\n var options = {scope: scope, element: element, show: false};\r\n angular.forEach(['template', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation'], function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n // Support scope as data-attrs\r\n angular.forEach(['title', 'content'], function(key) {\r\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\r\n scope[key] = $sce.trustAsHtml(newValue);\r\n });\r\n });\r\n\r\n // Support scope as an object\r\n attr.bsModal && scope.$watch(attr.bsModal, function(newValue, oldValue) {\r\n if(angular.isObject(newValue)) {\r\n angular.extend(scope, newValue);\r\n } else {\r\n scope.content = newValue;\r\n }\r\n }, true);\r\n\r\n // Initialize modal\r\n var modal = $modal(options);\r\n\r\n // Trigger\r\n element.on(attr.trigger || 'click', modal.toggle);\r\n\r\n // Garbage collection\r\n scope.$on('$destroy', function() {\r\n if (modal) modal.destroy();\r\n options = null;\r\n modal = null;\r\n });\r\n\r\n }\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.helpers.dateFormatter', [])\r\n\r\n .service('$dateFormatter', function($locale, dateFilter) {\r\n\r\n // The unused `lang` arguments are on purpose. The default implementation does not\r\n // use them and it always uses the locale loaded into the `$locale` service.\r\n // Custom implementations might use it, thus allowing different directives to\r\n // have different languages.\r\n\r\n this.getDefaultLocale = function() {\r\n return $locale.id;\r\n };\r\n\r\n // Format is either a data format name, e.g. \"shortTime\" or \"fullDate\", or a date format\r\n // Return either the corresponding date format or the given date format.\r\n this.getDatetimeFormat = function(format, lang) {\r\n return $locale.DATETIME_FORMATS[format] || format;\r\n };\r\n\r\n this.weekdaysShort = function(lang) {\r\n return $locale.DATETIME_FORMATS.SHORTDAY;\r\n };\r\n\r\n function splitTimeFormat(format) {\r\n return /(h+)([:\\.])?(m+)[ ]?(a?)/i.exec(format).slice(1);\r\n }\r\n\r\n // h:mm a => h\r\n this.hoursFormat = function(timeFormat) {\r\n return splitTimeFormat(timeFormat)[0];\r\n };\r\n\r\n // h:mm a => mm\r\n this.minutesFormat = function(timeFormat) {\r\n return splitTimeFormat(timeFormat)[2];\r\n };\r\n\r\n // h:mm a => :\r\n this.timeSeparator = function(timeFormat) {\r\n return splitTimeFormat(timeFormat)[1];\r\n };\r\n\r\n // h:mm a => true, H.mm => false\r\n this.showAM = function(timeFormat) {\r\n return !!splitTimeFormat(timeFormat)[3];\r\n };\r\n\r\n this.formatDate = function(date, format, lang){\r\n return dateFilter(date, format);\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.helpers.dateParser', [])\r\n\r\n.provider('$dateParser', function($localeProvider) {\r\n\r\n // define a custom ParseDate object to use instead of native Date\r\n // to avoid date values wrapping when setting date component values\r\n function ParseDate() {\r\n this.year = 1970;\r\n this.month = 0;\r\n this.day = 1;\r\n this.hours = 0;\r\n this.minutes = 0;\r\n this.seconds = 0;\r\n this.milliseconds = 0;\r\n }\r\n\r\n ParseDate.prototype.setMilliseconds = function(value) { this.milliseconds = value; };\r\n ParseDate.prototype.setSeconds = function(value) { this.seconds = value; };\r\n ParseDate.prototype.setMinutes = function(value) { this.minutes = value; };\r\n ParseDate.prototype.setHours = function(value) { this.hours = value; };\r\n ParseDate.prototype.getHours = function() { return this.hours; };\r\n ParseDate.prototype.setDate = function(value) { this.day = value; };\r\n ParseDate.prototype.setMonth = function(value) { this.month = value; };\r\n ParseDate.prototype.setFullYear = function(value) { this.year = value; };\r\n ParseDate.prototype.fromDate = function(value) {\r\n this.year = value.getFullYear();\r\n this.month = value.getMonth();\r\n this.day = value.getDate();\r\n this.hours = value.getHours();\r\n this.minutes = value.getMinutes();\r\n this.seconds = value.getSeconds();\r\n this.milliseconds = value.getMilliseconds();\r\n return this;\r\n };\r\n\r\n ParseDate.prototype.toDate = function() {\r\n return new Date(this.year, this.month, this.day, this.hours, this.minutes, this.seconds, this.milliseconds);\r\n };\r\n\r\n var proto = ParseDate.prototype;\r\n\r\n function noop() {\r\n }\r\n\r\n function isNumeric(n) {\r\n return !isNaN(parseFloat(n)) && isFinite(n);\r\n }\r\n\r\n function indexOfCaseInsensitive(array, value) {\r\n var len = array.length, str=value.toString().toLowerCase();\r\n for (var i=0; i 12 when midnight changeover, but then cannot generate\r\n * midnight datetime, so jump to 1AM, otherwise reset.\r\n * @param date (Date) the date to check\r\n * @return (Date) the corrected date\r\n *\r\n * __ copied from jquery ui datepicker __\r\n */\r\n $dateParser.daylightSavingAdjust = function(date) {\r\n if (!date) {\r\n return null;\r\n }\r\n date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);\r\n return date;\r\n };\r\n\r\n // Private functions\r\n\r\n function setMapForFormat(format) {\r\n var keys = Object.keys(setFnMap), i;\r\n var map = [], sortedMap = [];\r\n // Map to setFn\r\n var clonedFormat = format;\r\n for(i = 0; i < keys.length; i++) {\r\n if(format.split(keys[i]).length > 1) {\r\n var index = clonedFormat.search(keys[i]);\r\n format = format.split(keys[i]).join('');\r\n if(setFnMap[keys[i]]) {\r\n map[index] = setFnMap[keys[i]];\r\n }\r\n }\r\n }\r\n // Sort result map\r\n angular.forEach(map, function(v) {\r\n // conditional required since angular.forEach broke around v1.2.21\r\n // related pr: https://github.com/angular/angular.js/pull/8525\r\n if(v) sortedMap.push(v);\r\n });\r\n return sortedMap;\r\n }\r\n\r\n function escapeReservedSymbols(text) {\r\n return text.replace(/\\//g, '[\\\\/]').replace('/-/g', '[-]').replace(/\\./g, '[.]').replace(/\\\\s/g, '[\\\\s]');\r\n }\r\n\r\n function regExpForFormat(format) {\r\n var keys = Object.keys(regExpMap), i;\r\n\r\n var re = format;\r\n // Abstract replaces to avoid collisions\r\n for(i = 0; i < keys.length; i++) {\r\n re = re.split(keys[i]).join('${' + i + '}');\r\n }\r\n // Replace abstracted values\r\n for(i = 0; i < keys.length; i++) {\r\n re = re.split('${' + i + '}').join('(' + regExpMap[keys[i]] + ')');\r\n }\r\n format = escapeReservedSymbols(format);\r\n\r\n return new RegExp('^' + re + '$', ['i']);\r\n }\r\n\r\n $dateParser.init();\r\n return $dateParser;\r\n\r\n };\r\n\r\n return DateParserFactory;\r\n\r\n };\r\n\r\n});\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.helpers.debounce', [])\r\n\r\n// @source jashkenas/underscore\r\n// @url https://github.com/jashkenas/underscore/blob/1.5.2/underscore.js#L693\r\n.factory('debounce', function($timeout) {\r\n return function(func, wait, immediate) {\r\n var timeout = null;\r\n return function() {\r\n var context = this,\r\n args = arguments,\r\n callNow = immediate && !timeout;\r\n if(timeout) {\r\n $timeout.cancel(timeout);\r\n }\r\n timeout = $timeout(function later() {\r\n timeout = null;\r\n if(!immediate) {\r\n func.apply(context, args);\r\n }\r\n }, wait, false);\r\n if(callNow) {\r\n func.apply(context, args);\r\n }\r\n return timeout;\r\n };\r\n };\r\n})\r\n\r\n\r\n// @source jashkenas/underscore\r\n// @url https://github.com/jashkenas/underscore/blob/1.5.2/underscore.js#L661\r\n.factory('throttle', function($timeout) {\r\n return function(func, wait, options) {\r\n var timeout = null;\r\n options || (options = {});\r\n return function() {\r\n var context = this,\r\n args = arguments;\r\n if(!timeout) {\r\n if(options.leading !== false) {\r\n func.apply(context, args);\r\n }\r\n timeout = $timeout(function later() {\r\n timeout = null;\r\n if(options.trailing !== false) {\r\n func.apply(context, args);\r\n }\r\n }, wait, false);\r\n }\r\n };\r\n };\r\n});\r\n\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.helpers.dimensions', [])\r\n\r\n .factory('dimensions', function($document, $window) {\r\n\r\n var jqLite = angular.element;\r\n var fn = {};\r\n\r\n /**\r\n * Test the element nodeName\r\n * @param element\r\n * @param name\r\n */\r\n var nodeName = fn.nodeName = function(element, name) {\r\n return element.nodeName && element.nodeName.toLowerCase() === name.toLowerCase();\r\n };\r\n\r\n /**\r\n * Returns the element computed style\r\n * @param element\r\n * @param prop\r\n * @param extra\r\n */\r\n fn.css = function(element, prop, extra) {\r\n var value;\r\n if (element.currentStyle) { //IE\r\n value = element.currentStyle[prop];\r\n } else if (window.getComputedStyle) {\r\n value = window.getComputedStyle(element)[prop];\r\n } else {\r\n value = element.style[prop];\r\n }\r\n return extra === true ? parseFloat(value) || 0 : value;\r\n };\r\n\r\n /**\r\n * Provides read-only equivalent of jQuery's offset function:\r\n * @required-by bootstrap-tooltip, bootstrap-affix\r\n * @url http://api.jquery.com/offset/\r\n * @param element\r\n */\r\n fn.offset = function(element) {\r\n var boxRect = element.getBoundingClientRect();\r\n var docElement = element.ownerDocument;\r\n return {\r\n width: boxRect.width || element.offsetWidth,\r\n height: boxRect.height || element.offsetHeight,\r\n top: boxRect.top + (window.pageYOffset || docElement.documentElement.scrollTop) - (docElement.documentElement.clientTop || 0),\r\n left: boxRect.left + (window.pageXOffset || docElement.documentElement.scrollLeft) - (docElement.documentElement.clientLeft || 0)\r\n };\r\n };\r\n\r\n /**\r\n * Provides read-only equivalent of jQuery's position function\r\n * @required-by bootstrap-tooltip, bootstrap-affix\r\n * @url http://api.jquery.com/offset/\r\n * @param element\r\n */\r\n fn.position = function(element) {\r\n\r\n var offsetParentRect = {top: 0, left: 0},\r\n offsetParentElement,\r\n offset;\r\n\r\n // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent\r\n if (fn.css(element, 'position') === 'fixed') {\r\n\r\n // We assume that getBoundingClientRect is available when computed position is fixed\r\n offset = element.getBoundingClientRect();\r\n\r\n } else {\r\n\r\n // Get *real* offsetParentElement\r\n offsetParentElement = offsetParent(element);\r\n\r\n // Get correct offsets\r\n offset = fn.offset(element);\r\n if (!nodeName(offsetParentElement, 'html')) {\r\n offsetParentRect = fn.offset(offsetParentElement);\r\n }\r\n\r\n // Add offsetParent borders\r\n offsetParentRect.top += fn.css(offsetParentElement, 'borderTopWidth', true);\r\n offsetParentRect.left += fn.css(offsetParentElement, 'borderLeftWidth', true);\r\n }\r\n\r\n // Subtract parent offsets and element margins\r\n return {\r\n width: element.offsetWidth,\r\n height: element.offsetHeight,\r\n top: offset.top - offsetParentRect.top - fn.css(element, 'marginTop', true),\r\n left: offset.left - offsetParentRect.left - fn.css(element, 'marginLeft', true)\r\n };\r\n\r\n };\r\n\r\n /**\r\n * Returns the closest, non-statically positioned offsetParent of a given element\r\n * @required-by fn.position\r\n * @param element\r\n */\r\n var offsetParent = function offsetParentElement(element) {\r\n var docElement = element.ownerDocument;\r\n var offsetParent = element.offsetParent || docElement;\r\n if(nodeName(offsetParent, '#document')) return docElement.documentElement;\r\n while(offsetParent && !nodeName(offsetParent, 'html') && fn.css(offsetParent, 'position') === 'static') {\r\n offsetParent = offsetParent.offsetParent;\r\n }\r\n return offsetParent || docElement.documentElement;\r\n };\r\n\r\n /**\r\n * Provides equivalent of jQuery's height function\r\n * @required-by bootstrap-affix\r\n * @url http://api.jquery.com/height/\r\n * @param element\r\n * @param outer\r\n */\r\n fn.height = function(element, outer) {\r\n var value = element.offsetHeight;\r\n if(outer) {\r\n value += fn.css(element, 'marginTop', true) + fn.css(element, 'marginBottom', true);\r\n } else {\r\n value -= fn.css(element, 'paddingTop', true) + fn.css(element, 'paddingBottom', true) + fn.css(element, 'borderTopWidth', true) + fn.css(element, 'borderBottomWidth', true);\r\n }\r\n return value;\r\n };\r\n\r\n /**\r\n * Provides equivalent of jQuery's width function\r\n * @required-by bootstrap-affix\r\n * @url http://api.jquery.com/width/\r\n * @param element\r\n * @param outer\r\n */\r\n fn.width = function(element, outer) {\r\n var value = element.offsetWidth;\r\n if(outer) {\r\n value += fn.css(element, 'marginLeft', true) + fn.css(element, 'marginRight', true);\r\n } else {\r\n value -= fn.css(element, 'paddingLeft', true) + fn.css(element, 'paddingRight', true) + fn.css(element, 'borderLeftWidth', true) + fn.css(element, 'borderRightWidth', true);\r\n }\r\n return value;\r\n };\r\n\r\n return fn;\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.helpers.parseOptions', [])\r\n\r\n .provider('$parseOptions', function() {\r\n\r\n var defaults = this.defaults = {\r\n regexp: /^\\s*(.*?)(?:\\s+as\\s+(.*?))?(?:\\s+group\\s+by\\s+(.*))?\\s+for\\s+(?:([\\$\\w][\\$\\w]*)|(?:\\(\\s*([\\$\\w][\\$\\w]*)\\s*,\\s*([\\$\\w][\\$\\w]*)\\s*\\)))\\s+in\\s+(.*?)(?:\\s+track\\s+by\\s+(.*?))?$/\r\n };\r\n\r\n this.$get = function($parse, $q) {\r\n\r\n function ParseOptionsFactory(attr, config) {\r\n\r\n var $parseOptions = {};\r\n\r\n // Common vars\r\n var options = angular.extend({}, defaults, config);\r\n $parseOptions.$values = [];\r\n\r\n // Private vars\r\n var match, displayFn, valueName, keyName, groupByFn, valueFn, valuesFn;\r\n\r\n $parseOptions.init = function() {\r\n $parseOptions.$match = match = attr.match(options.regexp);\r\n displayFn = $parse(match[2] || match[1]),\r\n valueName = match[4] || match[6],\r\n keyName = match[5],\r\n groupByFn = $parse(match[3] || ''),\r\n valueFn = $parse(match[2] ? match[1] : valueName),\r\n valuesFn = $parse(match[7]);\r\n };\r\n\r\n $parseOptions.valuesFn = function(scope, controller) {\r\n return $q.when(valuesFn(scope, controller))\r\n .then(function(values) {\r\n $parseOptions.$values = values ? parseValues(values, scope) : {};\r\n return $parseOptions.$values;\r\n });\r\n };\r\n\r\n $parseOptions.displayValue = function(modelValue) {\r\n var scope = {};\r\n scope[valueName] = modelValue;\r\n return displayFn(scope);\r\n };\r\n\r\n // Private functions\r\n\r\n function parseValues(values, scope) {\r\n return values.map(function(match, index) {\r\n var locals = {}, label, value;\r\n locals[valueName] = match;\r\n label = displayFn(scope, locals);\r\n value = valueFn(scope, locals);\r\n return {label: label, value: value, index: index};\r\n });\r\n }\r\n\r\n $parseOptions.init();\r\n return $parseOptions;\r\n\r\n }\r\n\r\n return ParseOptionsFactory;\r\n\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\n(angular.version.minor < 3 && angular.version.dot < 14) && angular.module('ng')\r\n\r\n.factory('$$rAF', function($window, $timeout) {\r\n\r\n var requestAnimationFrame = $window.requestAnimationFrame ||\r\n $window.webkitRequestAnimationFrame ||\r\n $window.mozRequestAnimationFrame;\r\n\r\n var cancelAnimationFrame = $window.cancelAnimationFrame ||\r\n $window.webkitCancelAnimationFrame ||\r\n $window.mozCancelAnimationFrame ||\r\n $window.webkitCancelRequestAnimationFrame;\r\n\r\n var rafSupported = !!requestAnimationFrame;\r\n var raf = rafSupported ?\r\n function(fn) {\r\n var id = requestAnimationFrame(fn);\r\n return function() {\r\n cancelAnimationFrame(id);\r\n };\r\n } :\r\n function(fn) {\r\n var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666\r\n return function() {\r\n $timeout.cancel(timer);\r\n };\r\n };\r\n\r\n raf.supported = rafSupported;\r\n\r\n return raf;\r\n\r\n});\r\n\r\n// .factory('$$animateReflow', function($$rAF, $document) {\r\n\r\n// var bodyEl = $document[0].body;\r\n\r\n// return function(fn) {\r\n// //the returned function acts as the cancellation function\r\n// return $$rAF(function() {\r\n// //the line below will force the browser to perform a repaint\r\n// //so that all the animated elements within the animation frame\r\n// //will be properly updated and drawn on screen. This is\r\n// //required to perform multi-class CSS based animations with\r\n// //Firefox. DO NOT REMOVE THIS LINE.\r\n// var a = bodyEl.offsetWidth + 1;\r\n// fn();\r\n// });\r\n// };\r\n\r\n// });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.navbar', [])\r\n\r\n .provider('$navbar', function() {\r\n\r\n var defaults = this.defaults = {\r\n activeClass: 'active',\r\n routeAttr: 'data-match-route',\r\n strict: false\r\n };\r\n\r\n this.$get = function() {\r\n return {defaults: defaults};\r\n };\r\n\r\n })\r\n\r\n .directive('bsNavbar', function($window, $location, $navbar) {\r\n\r\n var defaults = $navbar.defaults;\r\n\r\n return {\r\n restrict: 'A',\r\n link: function postLink(scope, element, attr, controller) {\r\n\r\n // Directive options\r\n var options = angular.copy(defaults);\r\n angular.forEach(Object.keys(defaults), function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n // Watch for the $location\r\n scope.$watch(function() {\r\n\r\n return $location.path();\r\n\r\n }, function(newValue, oldValue) {\r\n\r\n var liElements = element[0].querySelectorAll('li[' + options.routeAttr + ']');\r\n\r\n angular.forEach(liElements, function(li) {\r\n\r\n var liElement = angular.element(li);\r\n var pattern = liElement.attr(options.routeAttr).replace('/', '\\\\/');\r\n if(options.strict) {\r\n pattern = '^' + pattern + '$';\r\n }\r\n var regexp = new RegExp(pattern, ['i']);\r\n\r\n if(regexp.test(newValue)) {\r\n liElement.addClass(options.activeClass);\r\n } else {\r\n liElement.removeClass(options.activeClass);\r\n }\r\n\r\n });\r\n\r\n });\r\n\r\n }\r\n\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.popover', ['mgcrea.ngStrap.tooltip'])\r\n\r\n .provider('$popover', function() {\r\n\r\n var defaults = this.defaults = {\r\n animation: 'am-fade',\r\n customClass: '',\r\n container: false,\r\n target: false,\r\n placement: 'right',\r\n template: 'popover/popover.tpl.html',\r\n contentTemplate: false,\r\n trigger: 'click',\r\n keyboard: true,\r\n html: false,\r\n title: '',\r\n content: '',\r\n delay: 0,\r\n autoClose: false\r\n };\r\n\r\n this.$get = function($tooltip) {\r\n\r\n function PopoverFactory(element, config) {\r\n\r\n // Common vars\r\n var options = angular.extend({}, defaults, config);\r\n\r\n var $popover = $tooltip(element, options);\r\n\r\n // Support scope as string options [/*title, */content]\r\n if(options.content) {\r\n $popover.$scope.content = options.content;\r\n }\r\n\r\n return $popover;\r\n\r\n }\r\n\r\n return PopoverFactory;\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsPopover', function($window, $sce, $popover) {\r\n\r\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\r\n\r\n return {\r\n restrict: 'EAC',\r\n scope: true,\r\n link: function postLink(scope, element, attr) {\r\n\r\n // Directive options\r\n var options = {scope: scope};\r\n angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'customClass', 'autoClose'], function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n // Support scope as data-attrs\r\n angular.forEach(['title', 'content'], function(key) {\r\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\r\n scope[key] = $sce.trustAsHtml(newValue);\r\n angular.isDefined(oldValue) && requestAnimationFrame(function() {\r\n popover && popover.$applyPlacement();\r\n });\r\n });\r\n });\r\n\r\n // Support scope as an object\r\n attr.bsPopover && scope.$watch(attr.bsPopover, function(newValue, oldValue) {\r\n if(angular.isObject(newValue)) {\r\n angular.extend(scope, newValue);\r\n } else {\r\n scope.content = newValue;\r\n }\r\n angular.isDefined(oldValue) && requestAnimationFrame(function() {\r\n popover && popover.$applyPlacement();\r\n });\r\n }, true);\r\n\r\n // Visibility binding support\r\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\r\n if(!popover || !angular.isDefined(newValue)) return;\r\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(popover),?/i);\r\n newValue === true ? popover.show() : popover.hide();\r\n });\r\n\r\n // Initialize popover\r\n var popover = $popover(element, options);\r\n\r\n // Garbage collection\r\n scope.$on('$destroy', function() {\r\n if (popover) popover.destroy();\r\n options = null;\r\n popover = null;\r\n });\r\n\r\n }\r\n };\r\n\r\n });\r\n","'use strict';\n\nangular.module('mgcrea.ngStrap.progressbar', [])\n.provider('$progressbar', function (){\n var defaults = {\n barType: '',\n animate: function (){ return true;}\n };\n\n this.$get = function (){\n return {\n defaults: defaults\n };\n };\n })\n .directive('bsProgressbar', function ($progressbar){\n return {\n restrict: 'E',\n transclude: true,\n replace: true,\n templateUrl: 'progressbar/progressbar.tpl.html',\n scope:{\n value: '=',\n type: '@',\n animate: '&'\n },\n link: function (scope, element, attr){\n scope.type = scope.type || $progressbar.defaults.barType;\n scope.animate = angular.isDefined(scope.animate()) ? scope.animate : $progressbar.defaults.animate;\n scope.$watch('type', function (){\n if(scope.type) {\n scope.barClass = 'progress-bar-' + scope.type;\n }\n else{\n scope.barClass = null;\n }\n });\n }\n };\n });\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.scrollspy', ['mgcrea.ngStrap.helpers.debounce', 'mgcrea.ngStrap.helpers.dimensions'])\r\n\r\n .provider('$scrollspy', function() {\r\n\r\n // Pool of registered spies\r\n var spies = this.$$spies = {};\r\n\r\n var defaults = this.defaults = {\r\n debounce: 150,\r\n throttle: 100,\r\n offset: 100\r\n };\r\n\r\n this.$get = function($window, $document, $rootScope, dimensions, debounce, throttle) {\r\n\r\n var windowEl = angular.element($window);\r\n var docEl = angular.element($document.prop('documentElement'));\r\n var bodyEl = angular.element($window.document.body);\r\n\r\n // Helper functions\r\n\r\n function nodeName(element, name) {\r\n return element[0].nodeName && element[0].nodeName.toLowerCase() === name.toLowerCase();\r\n }\r\n\r\n function ScrollSpyFactory(config) {\r\n\r\n // Common vars\r\n var options = angular.extend({}, defaults, config);\r\n if(!options.element) options.element = bodyEl;\r\n var isWindowSpy = nodeName(options.element, 'body');\r\n var scrollEl = isWindowSpy ? windowEl : options.element;\r\n var scrollId = isWindowSpy ? 'window' : options.id;\r\n\r\n // Use existing spy\r\n if(spies[scrollId]) {\r\n spies[scrollId].$$count++;\r\n return spies[scrollId];\r\n }\r\n\r\n var $scrollspy = {};\r\n\r\n // Private vars\r\n var unbindViewContentLoaded, unbindIncludeContentLoaded;\r\n var trackedElements = $scrollspy.$trackedElements = [];\r\n var sortedElements = [];\r\n var activeTarget;\r\n var debouncedCheckPosition;\r\n var throttledCheckPosition;\r\n var debouncedCheckOffsets;\r\n var viewportHeight;\r\n var scrollTop;\r\n\r\n $scrollspy.init = function() {\r\n\r\n // Setup internal ref counter\r\n this.$$count = 1;\r\n\r\n // Bind events\r\n debouncedCheckPosition = debounce(this.checkPosition, options.debounce);\r\n throttledCheckPosition = throttle(this.checkPosition, options.throttle);\r\n scrollEl.on('click', this.checkPositionWithEventLoop);\r\n windowEl.on('resize', debouncedCheckPosition);\r\n scrollEl.on('scroll', throttledCheckPosition);\r\n\r\n debouncedCheckOffsets = debounce(this.checkOffsets, options.debounce);\r\n unbindViewContentLoaded = $rootScope.$on('$viewContentLoaded', debouncedCheckOffsets);\r\n unbindIncludeContentLoaded = $rootScope.$on('$includeContentLoaded', debouncedCheckOffsets);\r\n debouncedCheckOffsets();\r\n\r\n // Register spy for reuse\r\n if(scrollId) {\r\n spies[scrollId] = $scrollspy;\r\n }\r\n\r\n };\r\n\r\n $scrollspy.destroy = function() {\r\n\r\n // Check internal ref counter\r\n this.$$count--;\r\n if(this.$$count > 0) {\r\n return;\r\n }\r\n\r\n // Unbind events\r\n scrollEl.off('click', this.checkPositionWithEventLoop);\r\n windowEl.off('resize', debouncedCheckPosition);\r\n scrollEl.off('scroll', throttledCheckPosition);\r\n unbindViewContentLoaded();\r\n unbindIncludeContentLoaded();\r\n if (scrollId) {\r\n delete spies[scrollId];\r\n }\r\n };\r\n\r\n $scrollspy.checkPosition = function() {\r\n\r\n // Not ready yet\r\n if(!sortedElements.length) return;\r\n\r\n // Calculate the scroll position\r\n scrollTop = (isWindowSpy ? $window.pageYOffset : scrollEl.prop('scrollTop')) || 0;\r\n\r\n // Calculate the viewport height for use by the components\r\n viewportHeight = Math.max($window.innerHeight, docEl.prop('clientHeight'));\r\n\r\n // Activate first element if scroll is smaller\r\n if(scrollTop < sortedElements[0].offsetTop && activeTarget !== sortedElements[0].target) {\r\n return $scrollspy.$activateElement(sortedElements[0]);\r\n }\r\n\r\n // Activate proper element\r\n for (var i = sortedElements.length; i--;) {\r\n if(angular.isUndefined(sortedElements[i].offsetTop) || sortedElements[i].offsetTop === null) continue;\r\n if(activeTarget === sortedElements[i].target) continue;\r\n if(scrollTop < sortedElements[i].offsetTop) continue;\r\n if(sortedElements[i + 1] && scrollTop > sortedElements[i + 1].offsetTop) continue;\r\n return $scrollspy.$activateElement(sortedElements[i]);\r\n }\r\n\r\n };\r\n\r\n $scrollspy.checkPositionWithEventLoop = function() {\r\n // IE 9 throws an error if we use 'this' instead of '$scrollspy'\r\n // in this setTimeout call\r\n setTimeout($scrollspy.checkPosition, 1);\r\n };\r\n\r\n // Protected methods\r\n\r\n $scrollspy.$activateElement = function(element) {\r\n if(activeTarget) {\r\n var activeElement = $scrollspy.$getTrackedElement(activeTarget);\r\n if(activeElement) {\r\n activeElement.source.removeClass('active');\r\n if(nodeName(activeElement.source, 'li') && nodeName(activeElement.source.parent().parent(), 'li')) {\r\n activeElement.source.parent().parent().removeClass('active');\r\n }\r\n }\r\n }\r\n activeTarget = element.target;\r\n element.source.addClass('active');\r\n if(nodeName(element.source, 'li') && nodeName(element.source.parent().parent(), 'li')) {\r\n element.source.parent().parent().addClass('active');\r\n }\r\n };\r\n\r\n $scrollspy.$getTrackedElement = function(target) {\r\n return trackedElements.filter(function(obj) {\r\n return obj.target === target;\r\n })[0];\r\n };\r\n\r\n // Track offsets behavior\r\n\r\n $scrollspy.checkOffsets = function() {\r\n\r\n angular.forEach(trackedElements, function(trackedElement) {\r\n var targetElement = document.querySelector(trackedElement.target);\r\n trackedElement.offsetTop = targetElement ? dimensions.offset(targetElement).top : null;\r\n if(options.offset && trackedElement.offsetTop !== null) trackedElement.offsetTop -= options.offset * 1;\r\n });\r\n\r\n sortedElements = trackedElements\r\n .filter(function(el) {\r\n return el.offsetTop !== null;\r\n })\r\n .sort(function(a, b) {\r\n return a.offsetTop - b.offsetTop;\r\n });\r\n\r\n debouncedCheckPosition();\r\n\r\n };\r\n\r\n $scrollspy.trackElement = function(target, source) {\r\n trackedElements.push({target: target, source: source});\r\n };\r\n\r\n $scrollspy.untrackElement = function(target, source) {\r\n var toDelete;\r\n for (var i = trackedElements.length; i--;) {\r\n if(trackedElements[i].target === target && trackedElements[i].source === source) {\r\n toDelete = i;\r\n break;\r\n }\r\n }\r\n trackedElements = trackedElements.splice(toDelete, 1);\r\n };\r\n\r\n $scrollspy.activate = function(i) {\r\n trackedElements[i].addClass('active');\r\n };\r\n\r\n // Initialize plugin\r\n\r\n $scrollspy.init();\r\n return $scrollspy;\r\n\r\n }\r\n\r\n return ScrollSpyFactory;\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsScrollspy', function($rootScope, debounce, dimensions, $scrollspy) {\r\n\r\n return {\r\n restrict: 'EAC',\r\n link: function postLink(scope, element, attr) {\r\n\r\n var options = {scope: scope};\r\n angular.forEach(['offset', 'target'], function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n var scrollspy = $scrollspy(options);\r\n scrollspy.trackElement(options.target, element);\r\n\r\n scope.$on('$destroy', function() {\r\n if (scrollspy) {\r\n scrollspy.untrackElement(options.target, element);\r\n scrollspy.destroy();\r\n }\r\n options = null;\r\n scrollspy = null;\r\n });\r\n\r\n }\r\n };\r\n\r\n })\r\n\r\n\r\n .directive('bsScrollspyList', function($rootScope, debounce, dimensions, $scrollspy) {\r\n\r\n return {\r\n restrict: 'A',\r\n compile: function postLink(element, attr) {\r\n var children = element[0].querySelectorAll('li > a[href]');\r\n angular.forEach(children, function(child) {\r\n var childEl = angular.element(child);\r\n childEl.parent().attr('bs-scrollspy', '').attr('data-target', childEl.attr('href'));\r\n });\r\n }\r\n\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.select', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions'])\r\n\r\n .provider('$select', function() {\r\n\r\n var defaults = this.defaults = {\r\n animation: 'am-fade',\r\n prefixClass: 'select',\r\n prefixEvent: '$select',\r\n placement: 'bottom-left',\r\n template: 'select/select.tpl.html',\r\n trigger: 'focus',\r\n container: false,\r\n keyboard: true,\r\n html: false,\r\n delay: 0,\r\n multiple: false,\r\n allNoneButtons: false,\r\n sort: true,\r\n caretHtml: ' ',\r\n placeholder: 'Choose among the following...',\r\n allText: 'All',\r\n noneText: 'None',\r\n maxLength: 3,\r\n maxLengthHtml: 'selected',\r\n iconCheckmark: 'glyphicon glyphicon-ok'\r\n };\r\n\r\n this.$get = function($window, $document, $rootScope, $tooltip, $timeout) {\r\n\r\n var bodyEl = angular.element($window.document.body);\r\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\r\n var isTouch = ('createTouch' in $window.document) && isNative;\r\n\r\n function SelectFactory(element, controller, config) {\r\n\r\n var $select = {};\r\n\r\n // Common vars\r\n var options = angular.extend({}, defaults, config);\r\n\r\n $select = $tooltip(element, options);\r\n var scope = $select.$scope;\r\n\r\n scope.$matches = [];\r\n scope.$activeIndex = 0;\r\n scope.$isMultiple = options.multiple;\r\n scope.$showAllNoneButtons = options.allNoneButtons && options.multiple;\r\n scope.$iconCheckmark = options.iconCheckmark;\r\n scope.$allText = options.allText;\r\n scope.$noneText = options.noneText;\r\n\r\n scope.$activate = function(index) {\r\n scope.$$postDigest(function() {\r\n $select.activate(index);\r\n });\r\n };\r\n\r\n scope.$select = function(index, evt) {\r\n scope.$$postDigest(function() {\r\n $select.select(index);\r\n });\r\n };\r\n\r\n scope.$isVisible = function() {\r\n return $select.$isVisible();\r\n };\r\n\r\n scope.$isActive = function(index) {\r\n return $select.$isActive(index);\r\n };\r\n\r\n scope.$selectAll = function () {\r\n for (var i = 0; i < scope.$matches.length; i++) {\r\n if (!scope.$isActive(i)) {\r\n scope.$select(i);\r\n }\r\n }\r\n };\r\n\r\n scope.$selectNone = function () {\r\n for (var i = 0; i < scope.$matches.length; i++) {\r\n if (scope.$isActive(i)) {\r\n scope.$select(i);\r\n }\r\n }\r\n };\r\n\r\n // Public methods\r\n\r\n $select.update = function(matches) {\r\n scope.$matches = matches;\r\n $select.$updateActiveIndex();\r\n };\r\n\r\n $select.activate = function(index) {\r\n if(options.multiple) {\r\n scope.$activeIndex.sort();\r\n $select.$isActive(index) ? scope.$activeIndex.splice(scope.$activeIndex.indexOf(index), 1) : scope.$activeIndex.push(index);\r\n if(options.sort) scope.$activeIndex.sort();\r\n } else {\r\n scope.$activeIndex = index;\r\n }\r\n return scope.$activeIndex;\r\n };\r\n\r\n $select.select = function(index) {\r\n var value = scope.$matches[index].value;\r\n scope.$apply(function() {\r\n $select.activate(index);\r\n if(options.multiple) {\r\n controller.$setViewValue(scope.$activeIndex.map(function(index) {\r\n return scope.$matches[index].value;\r\n }));\r\n } else {\r\n controller.$setViewValue(value);\r\n // Hide if single select\r\n $select.hide();\r\n }\r\n });\r\n // Emit event\r\n scope.$emit(options.prefixEvent + '.select', value, index);\r\n };\r\n\r\n // Protected methods\r\n\r\n $select.$updateActiveIndex = function() {\r\n if(controller.$modelValue && scope.$matches.length) {\r\n if(options.multiple && angular.isArray(controller.$modelValue)) {\r\n scope.$activeIndex = controller.$modelValue.map(function(value) {\r\n return $select.$getIndex(value);\r\n });\r\n } else {\r\n scope.$activeIndex = $select.$getIndex(controller.$modelValue);\r\n }\r\n } else if(scope.$activeIndex >= scope.$matches.length) {\r\n scope.$activeIndex = options.multiple ? [] : 0;\r\n }\r\n };\r\n\r\n $select.$isVisible = function() {\r\n if(!options.minLength || !controller) {\r\n return scope.$matches.length;\r\n }\r\n // minLength support\r\n return scope.$matches.length && controller.$viewValue.length >= options.minLength;\r\n };\r\n\r\n $select.$isActive = function(index) {\r\n if(options.multiple) {\r\n return scope.$activeIndex.indexOf(index) !== -1;\r\n } else {\r\n return scope.$activeIndex === index;\r\n }\r\n };\r\n\r\n $select.$getIndex = function(value) {\r\n var l = scope.$matches.length, i = l;\r\n if(!l) return;\r\n for(i = l; i--;) {\r\n if(scope.$matches[i].value === value) break;\r\n }\r\n if(i < 0) return;\r\n return i;\r\n };\r\n\r\n $select.$onMouseDown = function(evt) {\r\n // Prevent blur on mousedown on .dropdown-menu\r\n evt.preventDefault();\r\n evt.stopPropagation();\r\n // Emulate click for mobile devices\r\n if(isTouch) {\r\n var targetEl = angular.element(evt.target);\r\n targetEl.triggerHandler('click');\r\n }\r\n };\r\n\r\n $select.$onKeyDown = function(evt) {\r\n if (!/(9|13|38|40)/.test(evt.keyCode)) return;\r\n evt.preventDefault();\r\n evt.stopPropagation();\r\n\r\n // Select with enter\r\n if(!options.multiple && (evt.keyCode === 13 || evt.keyCode === 9)) {\r\n return $select.select(scope.$activeIndex);\r\n }\r\n\r\n // Navigate with keyboard\r\n if(evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--;\r\n else if(evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++;\r\n else if(angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0;\r\n scope.$digest();\r\n };\r\n\r\n // Overrides\r\n\r\n var _show = $select.show;\r\n $select.show = function() {\r\n _show();\r\n if(options.multiple) {\r\n $select.$element.addClass('select-multiple');\r\n }\r\n // use timeout to hookup the events to prevent\r\n // event bubbling from being processed imediately.\r\n $timeout(function() {\r\n $select.$element.on(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown);\r\n if(options.keyboard) {\r\n element.on('keydown', $select.$onKeyDown);\r\n }\r\n }, 0, false);\r\n };\r\n\r\n var _hide = $select.hide;\r\n $select.hide = function() {\r\n $select.$element.off(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown);\r\n if(options.keyboard) {\r\n element.off('keydown', $select.$onKeyDown);\r\n }\r\n _hide(true);\r\n };\r\n\r\n return $select;\r\n\r\n }\r\n\r\n SelectFactory.defaults = defaults;\r\n return SelectFactory;\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsSelect', function($window, $parse, $q, $select, $parseOptions) {\r\n\r\n var defaults = $select.defaults;\r\n\r\n return {\r\n restrict: 'EAC',\r\n require: 'ngModel',\r\n link: function postLink(scope, element, attr, controller) {\r\n\r\n // Directive options\r\n var options = {scope: scope, placeholder: defaults.placeholder};\r\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'placeholder', 'multiple', 'allNoneButtons', 'maxLength', 'maxLengthHtml', 'allText', 'noneText'], function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n // Add support for select markup\r\n if(element[0].nodeName.toLowerCase() === 'select') {\r\n var inputEl = element;\r\n inputEl.css('display', 'none');\r\n element = angular.element(' ');\r\n inputEl.after(element);\r\n }\r\n\r\n // Build proper ngOptions\r\n var parsedOptions = $parseOptions(attr.ngOptions);\r\n\r\n // Initialize select\r\n var select = $select(element, controller, options);\r\n\r\n // Watch ngOptions values before filtering for changes\r\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').trim();\r\n scope.$watch(watchedOptions, function(newValue, oldValue) {\r\n // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue);\r\n parsedOptions.valuesFn(scope, controller)\r\n .then(function(values) {\r\n select.update(values);\r\n controller.$render();\r\n });\r\n }, true);\r\n\r\n // Watch model for changes\r\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\r\n // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue);\r\n select.$updateActiveIndex();\r\n controller.$render();\r\n }, true);\r\n\r\n // Model rendering in view\r\n controller.$render = function () {\r\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\r\n var selected, index;\r\n if(options.multiple && angular.isArray(controller.$modelValue)) {\r\n selected = controller.$modelValue.map(function(value) {\r\n index = select.$getIndex(value);\r\n return angular.isDefined(index) ? select.$scope.$matches[index].label : false;\r\n }).filter(angular.isDefined);\r\n if(selected.length > (options.maxLength || defaults.maxLength)) {\r\n selected = selected.length + ' ' + (options.maxLengthHtml || defaults.maxLengthHtml);\r\n } else {\r\n selected = selected.join(', ');\r\n }\r\n } else {\r\n index = select.$getIndex(controller.$modelValue);\r\n selected = angular.isDefined(index) ? select.$scope.$matches[index].label : false;\r\n }\r\n element.html((selected ? selected : options.placeholder) + defaults.caretHtml);\r\n };\r\n\r\n if(options.multiple){\r\n controller.$isEmpty = function(value){\r\n return !value || value.length === 0;\r\n };\r\n }\r\n\r\n // Garbage collection\r\n scope.$on('$destroy', function() {\r\n if (select) select.destroy();\r\n options = null;\r\n select = null;\r\n });\r\n\r\n }\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.tab', [])\r\n\r\n .provider('$tab', function() {\r\n\r\n var defaults = this.defaults = {\r\n animation: 'am-fade',\r\n template: 'tab/tab.tpl.html',\r\n navClass: 'nav-tabs',\r\n activeClass: 'active'\r\n };\r\n\r\n var controller = this.controller = function($scope, $element, $attrs) {\r\n var self = this;\r\n\r\n // Attributes options\r\n self.$options = angular.copy(defaults);\r\n angular.forEach(['animation', 'navClass', 'activeClass'], function(key) {\r\n if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];\r\n });\r\n\r\n // Publish options on scope\r\n $scope.$navClass = self.$options.navClass;\r\n $scope.$activeClass = self.$options.activeClass;\r\n\r\n self.$panes = $scope.$panes = [];\r\n\r\n // DEPRECATED: $viewChangeListeners, please use $activePaneChangeListeners\r\n // Because we deprecated ngModel usage, we rename viewChangeListeners to \r\n // activePaneChangeListeners to make more sense.\r\n self.$activePaneChangeListeners = self.$viewChangeListeners = [];\r\n\r\n self.$push = function(pane) {\r\n self.$panes.push(pane);\r\n };\r\n\r\n self.$remove = function(pane) {\r\n var index = self.$panes.indexOf(pane);\r\n var activeIndex = self.$panes.$active;\r\n\r\n // remove pane from $panes array\r\n self.$panes.splice(index, 1);\r\n\r\n if (index < activeIndex) {\r\n // we removed a pane before the active pane, so we need to \r\n // decrement the active pane index\r\n activeIndex--;\r\n }\r\n else if (index === activeIndex && activeIndex === self.$panes.length) {\r\n // we remove the active pane and it was the one at the end,\r\n // so select the previous one\r\n activeIndex--;\r\n }\r\n self.$setActive(activeIndex);\r\n };\r\n\r\n self.$panes.$active = 0;\r\n self.$setActive = $scope.$setActive = function(value) {\r\n self.$panes.$active = value;\r\n self.$activePaneChangeListeners.forEach(function(fn) {\r\n fn();\r\n });\r\n };\r\n\r\n };\r\n\r\n this.$get = function() {\r\n var $tab = {};\r\n $tab.defaults = defaults;\r\n $tab.controller = controller;\r\n return $tab;\r\n };\r\n\r\n })\r\n\r\n .directive('bsTabs', function($window, $animate, $tab, $parse) {\r\n\r\n var defaults = $tab.defaults;\r\n\r\n return {\r\n require: ['?ngModel', 'bsTabs'],\r\n transclude: true,\r\n scope: true,\r\n controller: ['$scope', '$element', '$attrs', $tab.controller],\r\n templateUrl: function(element, attr) {\r\n return attr.template || defaults.template;\r\n },\r\n link: function postLink(scope, element, attrs, controllers) {\r\n\r\n var ngModelCtrl = controllers[0];\r\n var bsTabsCtrl = controllers[1];\r\n\r\n // DEPRECATED: ngModel, please use bsActivePane\r\n // 'ngModel' is deprecated bacause if interferes with form validation\r\n // and status, so avoid using it here.\r\n if(ngModelCtrl) {\r\n console.warn('Usage of ngModel is deprecated, please use bsActivePane instead!');\r\n\r\n // Update the modelValue following\r\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\r\n ngModelCtrl.$setViewValue(bsTabsCtrl.$panes.$active);\r\n });\r\n\r\n // modelValue -> $formatters -> viewValue\r\n ngModelCtrl.$formatters.push(function(modelValue) {\r\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\r\n bsTabsCtrl.$setActive(modelValue * 1);\r\n return modelValue;\r\n });\r\n\r\n }\r\n\r\n if (attrs.bsActivePane) {\r\n // adapted from angularjs ngModelController bindings\r\n // https://github.com/angular/angular.js/blob/v1.3.1/src%2Fng%2Fdirective%2Finput.js#L1730\r\n var parsedBsActivePane = $parse(attrs.bsActivePane);\r\n\r\n // Update bsActivePane value with change\r\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\r\n parsedBsActivePane.assign(scope, bsTabsCtrl.$panes.$active);\r\n });\r\n\r\n // watch bsActivePane for value changes\r\n scope.$watch(attrs.bsActivePane, function(newValue, oldValue) {\r\n bsTabsCtrl.$setActive(newValue * 1);\r\n }, true);\r\n }\r\n }\r\n };\r\n\r\n })\r\n\r\n .directive('bsPane', function($window, $animate, $sce) {\r\n\r\n return {\r\n require: ['^?ngModel', '^bsTabs'],\r\n scope: true,\r\n link: function postLink(scope, element, attrs, controllers) {\r\n\r\n var ngModelCtrl = controllers[0];\r\n var bsTabsCtrl = controllers[1];\r\n\r\n // Add base class\r\n element.addClass('tab-pane');\r\n\r\n // Observe title attribute for change\r\n attrs.$observe('title', function(newValue, oldValue) {\r\n scope.title = $sce.trustAsHtml(newValue);\r\n });\r\n\r\n // Add animation class\r\n if(bsTabsCtrl.$options.animation) {\r\n element.addClass(bsTabsCtrl.$options.animation);\r\n }\r\n\r\n // Push pane to parent bsTabs controller\r\n bsTabsCtrl.$push(scope);\r\n\r\n // remove pane from tab controller when pane is destroyed\r\n scope.$on('$destroy', function() {\r\n bsTabsCtrl.$remove(scope);\r\n });\r\n\r\n function render() {\r\n var index = bsTabsCtrl.$panes.indexOf(scope);\r\n var active = bsTabsCtrl.$panes.$active;\r\n $animate[index === active ? 'addClass' : 'removeClass'](element, bsTabsCtrl.$options.activeClass);\r\n }\r\n\r\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\r\n render();\r\n });\r\n render();\r\n\r\n }\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.timepicker', [\r\n 'mgcrea.ngStrap.helpers.dateParser',\r\n 'mgcrea.ngStrap.helpers.dateFormatter',\r\n 'mgcrea.ngStrap.tooltip'])\r\n\r\n .provider('$timepicker', function() {\r\n\r\n var defaults = this.defaults = {\r\n animation: 'am-fade',\r\n prefixClass: 'timepicker',\r\n placement: 'bottom-left',\r\n template: 'timepicker/timepicker.tpl.html',\r\n trigger: 'focus',\r\n container: false,\r\n keyboard: true,\r\n html: false,\r\n delay: 0,\r\n // lang: $locale.id,\r\n useNative: true,\r\n timeType: 'date',\r\n timeFormat: 'shortTime',\r\n modelTimeFormat: null,\r\n autoclose: false,\r\n minTime: -Infinity,\r\n maxTime: +Infinity,\r\n length: 5,\r\n hourStep: 1,\r\n minuteStep: 5,\r\n iconUp: 'glyphicon glyphicon-chevron-up',\r\n iconDown: 'glyphicon glyphicon-chevron-down',\r\n arrowBehavior: 'pager'\r\n };\r\n\r\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) {\r\n\r\n var bodyEl = angular.element($window.document.body);\r\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\r\n var isTouch = ('createTouch' in $window.document) && isNative;\r\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\r\n\r\n function timepickerFactory(element, controller, config) {\r\n\r\n var $timepicker = $tooltip(element, angular.extend({}, defaults, config));\r\n var parentScope = config.scope;\r\n var options = $timepicker.$options;\r\n var scope = $timepicker.$scope;\r\n\r\n var lang = options.lang;\r\n var formatDate = function(date, format) {\r\n return $dateFormatter.formatDate(date, format, lang);\r\n };\r\n\r\n // View vars\r\n\r\n var selectedIndex = 0;\r\n var startDate = controller.$dateValue || new Date();\r\n var viewDate = {hour: startDate.getHours(), meridian: startDate.getHours() < 12, minute: startDate.getMinutes(), second: startDate.getSeconds(), millisecond: startDate.getMilliseconds()};\r\n\r\n var format = $dateFormatter.getDatetimeFormat(options.timeFormat, lang);\r\n\r\n var hoursFormat = $dateFormatter.hoursFormat(format),\r\n timeSeparator = $dateFormatter.timeSeparator(format),\r\n minutesFormat = $dateFormatter.minutesFormat(format),\r\n showAM = $dateFormatter.showAM(format);\r\n\r\n scope.$iconUp = options.iconUp;\r\n scope.$iconDown = options.iconDown;\r\n\r\n // Scope methods\r\n\r\n scope.$select = function(date, index) {\r\n $timepicker.select(date, index);\r\n };\r\n scope.$moveIndex = function(value, index) {\r\n $timepicker.$moveIndex(value, index);\r\n };\r\n scope.$switchMeridian = function(date) {\r\n $timepicker.switchMeridian(date);\r\n };\r\n\r\n // Public methods\r\n\r\n $timepicker.update = function(date) {\r\n // console.warn('$timepicker.update() newValue=%o', date);\r\n if(angular.isDate(date) && !isNaN(date.getTime())) {\r\n $timepicker.$date = date;\r\n angular.extend(viewDate, {hour: date.getHours(), minute: date.getMinutes(), second: date.getSeconds(), millisecond: date.getMilliseconds()});\r\n $timepicker.$build();\r\n } else if(!$timepicker.$isBuilt) {\r\n $timepicker.$build();\r\n }\r\n };\r\n\r\n $timepicker.select = function(date, index, keep) {\r\n // console.warn('$timepicker.select', date, scope.$mode);\r\n if(!controller.$dateValue || isNaN(controller.$dateValue.getTime())) controller.$dateValue = new Date(1970, 0, 1);\r\n if(!angular.isDate(date)) date = new Date(date);\r\n if(index === 0) controller.$dateValue.setHours(date.getHours());\r\n else if(index === 1) controller.$dateValue.setMinutes(date.getMinutes());\r\n controller.$setViewValue(angular.copy(controller.$dateValue));\r\n controller.$render();\r\n if(options.autoclose && !keep) {\r\n $timeout(function() { $timepicker.hide(true); });\r\n }\r\n };\r\n\r\n $timepicker.switchMeridian = function(date) {\r\n if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) {\r\n return;\r\n }\r\n var hours = (date || controller.$dateValue).getHours();\r\n controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12);\r\n controller.$setViewValue(angular.copy(controller.$dateValue));\r\n controller.$render();\r\n };\r\n\r\n // Protected methods\r\n\r\n $timepicker.$build = function() {\r\n // console.warn('$timepicker.$build() viewDate=%o', viewDate);\r\n var i, midIndex = scope.midIndex = parseInt(options.length / 2, 10);\r\n var hours = [], hour;\r\n for(i = 0; i < options.length; i++) {\r\n hour = new Date(1970, 0, 1, viewDate.hour - (midIndex - i) * options.hourStep);\r\n hours.push({date: hour, label: formatDate(hour, hoursFormat), selected: $timepicker.$date && $timepicker.$isSelected(hour, 0), disabled: $timepicker.$isDisabled(hour, 0)});\r\n }\r\n var minutes = [], minute;\r\n for(i = 0; i < options.length; i++) {\r\n minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep);\r\n minutes.push({date: minute, label: formatDate(minute, minutesFormat), selected: $timepicker.$date && $timepicker.$isSelected(minute, 1), disabled: $timepicker.$isDisabled(minute, 1)});\r\n }\r\n\r\n var rows = [];\r\n for(i = 0; i < options.length; i++) {\r\n rows.push([hours[i], minutes[i]]);\r\n }\r\n scope.rows = rows;\r\n scope.showAM = showAM;\r\n scope.isAM = ($timepicker.$date || hours[midIndex].date).getHours() < 12;\r\n scope.timeSeparator = timeSeparator;\r\n $timepicker.$isBuilt = true;\r\n };\r\n\r\n $timepicker.$isSelected = function(date, index) {\r\n if(!$timepicker.$date) return false;\r\n else if(index === 0) {\r\n return date.getHours() === $timepicker.$date.getHours();\r\n } else if(index === 1) {\r\n return date.getMinutes() === $timepicker.$date.getMinutes();\r\n }\r\n };\r\n\r\n $timepicker.$isDisabled = function(date, index) {\r\n var selectedTime;\r\n if(index === 0) {\r\n selectedTime = date.getTime() + viewDate.minute * 6e4;\r\n } else if(index === 1) {\r\n selectedTime = date.getTime() + viewDate.hour * 36e5;\r\n }\r\n return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1;\r\n };\r\n\r\n scope.$arrowAction = function (value, index) {\r\n if (options.arrowBehavior === 'picker') {\r\n $timepicker.$setTimeByStep(value,index);\r\n } else {\r\n $timepicker.$moveIndex(value,index);\r\n }\r\n };\r\n\r\n $timepicker.$setTimeByStep = function(value, index) {\r\n var newDate = new Date($timepicker.$date);\r\n var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;\r\n var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;\r\n if (index === 0) {\r\n newDate.setHours(hours - (parseInt(options.hourStep, 10) * value));\r\n }\r\n else {\r\n newDate.setMinutes(minutes - (parseInt(options.minuteStep, 10) * value));\r\n }\r\n $timepicker.select(newDate, index, true);\r\n };\r\n\r\n $timepicker.$moveIndex = function(value, index) {\r\n var targetDate;\r\n if(index === 0) {\r\n targetDate = new Date(1970, 0, 1, viewDate.hour + (value * options.length), viewDate.minute);\r\n angular.extend(viewDate, {hour: targetDate.getHours()});\r\n } else if(index === 1) {\r\n targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + (value * options.length * options.minuteStep));\r\n angular.extend(viewDate, {minute: targetDate.getMinutes()});\r\n }\r\n $timepicker.$build();\r\n };\r\n\r\n $timepicker.$onMouseDown = function(evt) {\r\n // Prevent blur on mousedown on .dropdown-menu\r\n if(evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault();\r\n evt.stopPropagation();\r\n // Emulate click for mobile devices\r\n if(isTouch) {\r\n var targetEl = angular.element(evt.target);\r\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\r\n targetEl = targetEl.parent();\r\n }\r\n targetEl.triggerHandler('click');\r\n }\r\n };\r\n\r\n $timepicker.$onKeyDown = function(evt) {\r\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\r\n evt.preventDefault();\r\n evt.stopPropagation();\r\n\r\n // Close on enter\r\n if(evt.keyCode === 13) return $timepicker.hide(true);\r\n\r\n // Navigate with keyboard\r\n var newDate = new Date($timepicker.$date);\r\n var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;\r\n var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;\r\n var lateralMove = /(37|39)/.test(evt.keyCode);\r\n var count = 2 + showAM * 1;\r\n\r\n // Navigate indexes (left, right)\r\n if (lateralMove) {\r\n if(evt.keyCode === 37) selectedIndex = selectedIndex < 1 ? count - 1 : selectedIndex - 1;\r\n else if(evt.keyCode === 39) selectedIndex = selectedIndex < count - 1 ? selectedIndex + 1 : 0;\r\n }\r\n\r\n // Update values (up, down)\r\n var selectRange = [0, hoursLength];\r\n if(selectedIndex === 0) {\r\n if(evt.keyCode === 38) newDate.setHours(hours - parseInt(options.hourStep, 10));\r\n else if(evt.keyCode === 40) newDate.setHours(hours + parseInt(options.hourStep, 10));\r\n // re-calculate hours length because we have changed hours value\r\n hoursLength = formatDate(newDate, hoursFormat).length;\r\n selectRange = [0, hoursLength];\r\n } else if(selectedIndex === 1) {\r\n if(evt.keyCode === 38) newDate.setMinutes(minutes - parseInt(options.minuteStep, 10));\r\n else if(evt.keyCode === 40) newDate.setMinutes(minutes + parseInt(options.minuteStep, 10));\r\n // re-calculate minutes length because we have changes minutes value\r\n minutesLength = formatDate(newDate, minutesFormat).length;\r\n selectRange = [hoursLength + 1, hoursLength + 1 + minutesLength];\r\n } else if(selectedIndex === 2) {\r\n if(!lateralMove) $timepicker.switchMeridian();\r\n selectRange = [hoursLength + 1 + minutesLength + 1, hoursLength + 1 + minutesLength + 3];\r\n }\r\n $timepicker.select(newDate, selectedIndex, true);\r\n createSelection(selectRange[0], selectRange[1]);\r\n parentScope.$digest();\r\n };\r\n\r\n // Private\r\n\r\n function createSelection(start, end) {\r\n if(element[0].createTextRange) {\r\n var selRange = element[0].createTextRange();\r\n selRange.collapse(true);\r\n selRange.moveStart('character', start);\r\n selRange.moveEnd('character', end);\r\n selRange.select();\r\n } else if(element[0].setSelectionRange) {\r\n element[0].setSelectionRange(start, end);\r\n } else if(angular.isUndefined(element[0].selectionStart)) {\r\n element[0].selectionStart = start;\r\n element[0].selectionEnd = end;\r\n }\r\n }\r\n\r\n function focusElement() {\r\n element[0].focus();\r\n }\r\n\r\n // Overrides\r\n\r\n var _init = $timepicker.init;\r\n $timepicker.init = function() {\r\n if(isNative && options.useNative) {\r\n element.prop('type', 'time');\r\n element.css('-webkit-appearance', 'textfield');\r\n return;\r\n } else if(isTouch) {\r\n element.prop('type', 'text');\r\n element.attr('readonly', 'true');\r\n element.on('click', focusElement);\r\n }\r\n _init();\r\n };\r\n\r\n var _destroy = $timepicker.destroy;\r\n $timepicker.destroy = function() {\r\n if(isNative && options.useNative) {\r\n element.off('click', focusElement);\r\n }\r\n _destroy();\r\n };\r\n\r\n var _show = $timepicker.show;\r\n $timepicker.show = function() {\r\n _show();\r\n // use timeout to hookup the events to prevent \r\n // event bubbling from being processed imediately. \r\n $timeout(function() {\r\n $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\r\n if(options.keyboard) {\r\n element.on('keydown', $timepicker.$onKeyDown);\r\n }\r\n }, 0, false);\r\n };\r\n\r\n var _hide = $timepicker.hide;\r\n $timepicker.hide = function(blur) {\r\n if(!$timepicker.$isShown) return;\r\n $timepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\r\n if(options.keyboard) {\r\n element.off('keydown', $timepicker.$onKeyDown);\r\n }\r\n _hide(blur);\r\n };\r\n\r\n return $timepicker;\r\n\r\n }\r\n\r\n timepickerFactory.defaults = defaults;\r\n return timepickerFactory;\r\n\r\n };\r\n\r\n })\r\n\r\n\r\n .directive('bsTimepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) {\r\n\r\n var defaults = $timepicker.defaults;\r\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\r\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\r\n\r\n return {\r\n restrict: 'EAC',\r\n require: 'ngModel',\r\n link: function postLink(scope, element, attr, controller) {\r\n\r\n // Directive options\r\n var options = {scope: scope, controller: controller};\r\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'timeType', 'timeFormat', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown'], function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n // Visibility binding support\r\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\r\n if(!timepicker || !angular.isDefined(newValue)) return;\r\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(timepicker),?/i);\r\n newValue === true ? timepicker.show() : timepicker.hide();\r\n });\r\n\r\n // Initialize timepicker\r\n if(isNative && (options.useNative || defaults.useNative)) options.timeFormat = 'HH:mm';\r\n var timepicker = $timepicker(element, controller, options);\r\n options = timepicker.$options;\r\n\r\n var lang = options.lang;\r\n var formatDate = function(date, format) {\r\n return $dateFormatter.formatDate(date, format, lang);\r\n };\r\n\r\n // Initialize parser\r\n var dateParser = $dateParser({format: options.timeFormat, lang: lang});\r\n\r\n // Observe attributes for changes\r\n angular.forEach(['minTime', 'maxTime'], function(key) {\r\n // console.warn('attr.$observe(%s)', key, attr[key]);\r\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\r\n timepicker.$options[key] = dateParser.getTimeForAttribute(key, newValue);\r\n !isNaN(timepicker.$options[key]) && timepicker.$build();\r\n validateAgainstMinMaxTime(controller.$dateValue);\r\n });\r\n });\r\n\r\n // Watch model for changes\r\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\r\n // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue, controller.$dateValue);\r\n timepicker.update(controller.$dateValue);\r\n }, true);\r\n\r\n function validateAgainstMinMaxTime(parsedTime) {\r\n if (!angular.isDate(parsedTime)) return;\r\n var isMinValid = isNaN(options.minTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) >= options.minTime;\r\n var isMaxValid = isNaN(options.maxTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) <= options.maxTime;\r\n var isValid = isMinValid && isMaxValid;\r\n controller.$setValidity('date', isValid);\r\n controller.$setValidity('min', isMinValid);\r\n controller.$setValidity('max', isMaxValid);\r\n // Only update the model when we have a valid date\r\n if(!isValid) {\r\n return;\r\n }\r\n controller.$dateValue = parsedTime;\r\n }\r\n\r\n // viewValue -> $parsers -> modelValue\r\n controller.$parsers.unshift(function(viewValue) {\r\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\r\n // Null values should correctly reset the model value & validity\r\n if(!viewValue) {\r\n // BREAKING CHANGE:\r\n // return null (not undefined) when input value is empty, so angularjs 1.3 \r\n // ngModelController can go ahead and run validators, like ngRequired\r\n controller.$setValidity('date', true);\r\n return null;\r\n }\r\n var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue);\r\n if(!parsedTime || isNaN(parsedTime.getTime())) {\r\n controller.$setValidity('date', false);\r\n // return undefined, causes ngModelController to \r\n // invalidate model value \r\n return;\r\n } else {\r\n validateAgainstMinMaxTime(parsedTime);\r\n }\r\n if(options.timeType === 'string') {\r\n return formatDate(parsedTime, options.modelTimeFormat || options.timeFormat);\r\n } else if(options.timeType === 'number') {\r\n return controller.$dateValue.getTime();\r\n } else if(options.timeType === 'unix') {\r\n return controller.$dateValue.getTime() / 1000;\r\n } else if(options.timeType === 'iso') {\r\n return controller.$dateValue.toISOString();\r\n } else {\r\n return new Date(controller.$dateValue);\r\n }\r\n });\r\n\r\n // modelValue -> $formatters -> viewValue\r\n controller.$formatters.push(function(modelValue) {\r\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\r\n var date;\r\n if(angular.isUndefined(modelValue) || modelValue === null) {\r\n date = NaN;\r\n } else if(angular.isDate(modelValue)) {\r\n date = modelValue;\r\n } else if(options.timeType === 'string') {\r\n date = dateParser.parse(modelValue, null, options.modelTimeFormat);\r\n } else if(options.timeType === 'unix') {\r\n date = new Date(modelValue * 1000);\r\n } else {\r\n date = new Date(modelValue);\r\n }\r\n // Setup default value?\r\n // if(isNaN(date.getTime())) date = new Date(new Date().setMinutes(0) + 36e5);\r\n controller.$dateValue = date;\r\n return getTimeFormattedString();\r\n });\r\n\r\n // viewValue -> element\r\n controller.$render = function() {\r\n // console.warn('$render(\"%s\"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);\r\n element.val(getTimeFormattedString());\r\n };\r\n\r\n function getTimeFormattedString() {\r\n return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat);\r\n }\r\n\r\n // Garbage collection\r\n scope.$on('$destroy', function() {\r\n if (timepicker) timepicker.destroy();\r\n options = null;\r\n timepicker = null;\r\n });\r\n\r\n }\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions'])\r\n\r\n .provider('$tooltip', function() {\r\n\r\n var defaults = this.defaults = {\r\n animation: 'am-fade',\r\n customClass: '',\r\n prefixClass: 'tooltip',\r\n prefixEvent: 'tooltip',\r\n container: false,\r\n target: false,\r\n placement: 'top',\r\n template: 'tooltip/tooltip.tpl.html',\r\n contentTemplate: false,\r\n trigger: 'hover focus',\r\n keyboard: false,\r\n html: false,\r\n show: false,\r\n title: '',\r\n type: '',\r\n delay: 0,\r\n autoClose: false,\r\n bsEnabled: true\r\n };\r\n\r\n this.$get = function($window, $rootScope, $compile, $q, $templateCache, $http, $animate, $sce, dimensions, $$rAF, $timeout) {\r\n\r\n var trim = String.prototype.trim;\r\n var isTouch = 'createTouch' in $window.document;\r\n var htmlReplaceRegExp = /ng-bind=\"/ig;\r\n var $body = angular.element($window.document);\r\n\r\n function TooltipFactory(element, config) {\r\n\r\n var $tooltip = {};\r\n\r\n // Common vars\r\n var nodeName = element[0].nodeName.toLowerCase();\r\n var options = $tooltip.$options = angular.extend({}, defaults, config);\r\n $tooltip.$promise = fetchTemplate(options.template);\r\n var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new();\r\n if(options.delay && angular.isString(options.delay)) {\r\n var split = options.delay.split(',').map(parseFloat);\r\n options.delay = split.length > 1 ? {show: split[0], hide: split[1]} : split[0];\r\n }\r\n\r\n // Support scope as string options\r\n if(options.title) {\r\n scope.title = $sce.trustAsHtml(options.title);\r\n }\r\n\r\n // Provide scope helpers\r\n scope.$setEnabled = function(isEnabled) {\r\n scope.$$postDigest(function() {\r\n $tooltip.setEnabled(isEnabled);\r\n });\r\n };\r\n scope.$hide = function() {\r\n scope.$$postDigest(function() {\r\n $tooltip.hide();\r\n });\r\n };\r\n scope.$show = function() {\r\n scope.$$postDigest(function() {\r\n $tooltip.show();\r\n });\r\n };\r\n scope.$toggle = function() {\r\n scope.$$postDigest(function() {\r\n $tooltip.toggle();\r\n });\r\n };\r\n // Publish isShown as a protected var on scope\r\n $tooltip.$isShown = scope.$isShown = false;\r\n\r\n // Private vars\r\n var timeout, hoverState;\r\n\r\n // Support contentTemplate option\r\n if(options.contentTemplate) {\r\n $tooltip.$promise = $tooltip.$promise.then(function(template) {\r\n var templateEl = angular.element(template);\r\n return fetchTemplate(options.contentTemplate)\r\n .then(function(contentTemplate) {\r\n var contentEl = findElement('[ng-bind=\"content\"]', templateEl[0]);\r\n if(!contentEl.length) contentEl = findElement('[ng-bind=\"title\"]', templateEl[0]);\r\n contentEl.removeAttr('ng-bind').html(contentTemplate);\r\n return templateEl[0].outerHTML;\r\n });\r\n });\r\n }\r\n\r\n // Fetch, compile then initialize tooltip\r\n var tipLinker, tipElement, tipTemplate, tipContainer, tipScope;\r\n $tooltip.$promise.then(function(template) {\r\n if(angular.isObject(template)) template = template.data;\r\n if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html=\"');\r\n template = trim.apply(template);\r\n tipTemplate = template;\r\n tipLinker = $compile(template);\r\n $tooltip.init();\r\n });\r\n\r\n $tooltip.init = function() {\r\n\r\n // Options: delay\r\n if (options.delay && angular.isNumber(options.delay)) {\r\n options.delay = {\r\n show: options.delay,\r\n hide: options.delay\r\n };\r\n }\r\n\r\n // Replace trigger on touch devices ?\r\n // if(isTouch && options.trigger === defaults.trigger) {\r\n // options.trigger.replace(/hover/g, 'click');\r\n // }\r\n\r\n // Options : container\r\n if(options.container === 'self') {\r\n tipContainer = element;\r\n } else if(angular.isElement(options.container)) {\r\n tipContainer = options.container;\r\n } else if(options.container) {\r\n tipContainer = findElement(options.container);\r\n }\r\n\r\n // Options: trigger\r\n bindTriggerEvents();\r\n\r\n // Options: target\r\n if(options.target) {\r\n options.target = angular.isElement(options.target) ? options.target : findElement(options.target);\r\n }\r\n\r\n // Options: show\r\n if(options.show) {\r\n scope.$$postDigest(function() {\r\n options.trigger === 'focus' ? element[0].focus() : $tooltip.show();\r\n });\r\n }\r\n\r\n };\r\n\r\n $tooltip.destroy = function() {\r\n\r\n // Unbind events\r\n unbindTriggerEvents();\r\n\r\n // Remove element\r\n destroyTipElement();\r\n\r\n // Destroy scope\r\n scope.$destroy();\r\n\r\n };\r\n\r\n $tooltip.enter = function() {\r\n\r\n clearTimeout(timeout);\r\n hoverState = 'in';\r\n if (!options.delay || !options.delay.show) {\r\n return $tooltip.show();\r\n }\r\n\r\n timeout = setTimeout(function() {\r\n if (hoverState ==='in') $tooltip.show();\r\n }, options.delay.show);\r\n\r\n };\r\n\r\n $tooltip.show = function() {\r\n if (!options.bsEnabled || $tooltip.$isShown) return;\r\n\r\n scope.$emit(options.prefixEvent + '.show.before', $tooltip);\r\n var parent, after;\r\n if (options.container) {\r\n parent = tipContainer;\r\n if (tipContainer[0].lastChild) {\r\n after = angular.element(tipContainer[0].lastChild);\r\n } else {\r\n after = null;\r\n }\r\n } else {\r\n parent = null;\r\n after = element;\r\n }\r\n\r\n\r\n // Hide any existing tipElement\r\n if(tipElement) destroyTipElement();\r\n // Fetch a cloned element linked from template\r\n tipScope = $tooltip.$scope.$new();\r\n tipElement = $tooltip.$element = tipLinker(tipScope, function(clonedElement, scope) {});\r\n\r\n // Set the initial positioning. Make the tooltip invisible\r\n // so IE doesn't try to focus on it off screen.\r\n tipElement.css({top: '-9999px', left: '-9999px', display: 'block', visibility: 'hidden'});\r\n\r\n // Options: animation\r\n if(options.animation) tipElement.addClass(options.animation);\r\n // Options: type\r\n if(options.type) tipElement.addClass(options.prefixClass + '-' + options.type);\r\n // Options: custom classes\r\n if(options.customClass) tipElement.addClass(options.customClass);\r\n\r\n // Support v1.3+ $animate\r\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\r\n var promise = $animate.enter(tipElement, parent, after, enterAnimateCallback);\r\n if(promise && promise.then) promise.then(enterAnimateCallback);\r\n\r\n $tooltip.$isShown = scope.$isShown = true;\r\n safeDigest(scope);\r\n $$rAF(function () {\r\n $tooltip.$applyPlacement();\r\n\r\n // Once placed, make the tooltip visible\r\n if(tipElement) tipElement.css({visibility: 'visible'});\r\n }); // var a = bodyEl.offsetWidth + 1; ?\r\n\r\n // Bind events\r\n if(options.keyboard) {\r\n if(options.trigger !== 'focus') {\r\n $tooltip.focus();\r\n }\r\n bindKeyboardEvents();\r\n }\r\n\r\n if(options.autoClose) {\r\n bindAutoCloseEvents();\r\n }\r\n\r\n };\r\n\r\n function enterAnimateCallback() {\r\n scope.$emit(options.prefixEvent + '.show', $tooltip);\r\n }\r\n\r\n $tooltip.leave = function() {\r\n\r\n clearTimeout(timeout);\r\n hoverState = 'out';\r\n if (!options.delay || !options.delay.hide) {\r\n return $tooltip.hide();\r\n }\r\n timeout = setTimeout(function () {\r\n if (hoverState === 'out') {\r\n $tooltip.hide();\r\n }\r\n }, options.delay.hide);\r\n\r\n };\r\n\r\n var _blur;\r\n $tooltip.hide = function(blur) {\r\n\r\n if(!$tooltip.$isShown) return;\r\n scope.$emit(options.prefixEvent + '.hide.before', $tooltip);\r\n\r\n // store blur value for leaveAnimateCallback to use\r\n _blur = blur;\r\n\r\n // Support v1.3+ $animate\r\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\r\n var promise = $animate.leave(tipElement, leaveAnimateCallback);\r\n if(promise && promise.then) promise.then(leaveAnimateCallback);\r\n\r\n $tooltip.$isShown = scope.$isShown = false;\r\n safeDigest(scope);\r\n\r\n // Unbind events\r\n if(options.keyboard && tipElement !== null) {\r\n unbindKeyboardEvents();\r\n }\r\n\r\n if(options.autoClose && tipElement !== null) {\r\n unbindAutoCloseEvents();\r\n }\r\n };\r\n\r\n function leaveAnimateCallback() {\r\n scope.$emit(options.prefixEvent + '.hide', $tooltip);\r\n // Allow to blur the input when hidden, like when pressing enter key\r\n if(_blur && options.trigger === 'focus') {\r\n return element[0].blur();\r\n }\r\n\r\n // clean up child scopes\r\n destroyTipElement();\r\n }\r\n\r\n $tooltip.toggle = function() {\r\n $tooltip.$isShown ? $tooltip.leave() : $tooltip.enter();\r\n };\r\n\r\n $tooltip.focus = function() {\r\n tipElement[0].focus();\r\n };\r\n\r\n $tooltip.setEnabled = function(isEnabled) {\r\n options.bsEnabled = isEnabled;\r\n };\r\n\r\n // Protected methods\r\n\r\n $tooltip.$applyPlacement = function() {\r\n if(!tipElement) return;\r\n\r\n // Determine if we're doing an auto or normal placement\r\n var placement = options.placement,\r\n autoToken = /\\s?auto?\\s?/i,\r\n autoPlace = autoToken.test(placement);\r\n\r\n if (autoPlace) {\r\n placement = placement.replace(autoToken, '') || defaults.placement;\r\n }\r\n\r\n // Need to add the position class before we get\r\n // the offsets\r\n tipElement.addClass(options.placement);\r\n\r\n // Get the position of the target element\r\n // and the height and width of the tooltip so we can center it.\r\n var elementPosition = getPosition(),\r\n tipWidth = tipElement.prop('offsetWidth'),\r\n tipHeight = tipElement.prop('offsetHeight');\r\n\r\n // If we're auto placing, we need to check the positioning\r\n if (autoPlace) {\r\n var originalPlacement = placement;\r\n var container = options.container ? angular.element(document.querySelector(options.container)) : element.parent();\r\n var containerPosition = getPosition(container);\r\n\r\n // Determine if the vertical placement\r\n if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > containerPosition.bottom) {\r\n placement = originalPlacement.replace('bottom', 'top');\r\n } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < containerPosition.top) {\r\n placement = originalPlacement.replace('top', 'bottom');\r\n }\r\n\r\n // Determine the horizontal placement\r\n // The exotic placements of left and right are opposite of the standard placements. Their arrows are put on the left/right\r\n // and flow in the opposite direction of their placement.\r\n if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') &&\r\n elementPosition.right + tipWidth > containerPosition.width) {\r\n\r\n placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right');\r\n } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') &&\r\n elementPosition.left - tipWidth < containerPosition.left) {\r\n\r\n placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left');\r\n }\r\n\r\n tipElement.removeClass(originalPlacement).addClass(placement);\r\n }\r\n\r\n // Get the tooltip's top and left coordinates to center it with this directive.\r\n var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight);\r\n applyPlacementCss(tipPosition.top, tipPosition.left);\r\n };\r\n\r\n $tooltip.$onKeyUp = function(evt) {\r\n if (evt.which === 27 && $tooltip.$isShown) {\r\n $tooltip.hide();\r\n evt.stopPropagation();\r\n }\r\n };\r\n\r\n $tooltip.$onFocusKeyUp = function(evt) {\r\n if (evt.which === 27) {\r\n element[0].blur();\r\n evt.stopPropagation();\r\n }\r\n };\r\n\r\n $tooltip.$onFocusElementMouseDown = function(evt) {\r\n evt.preventDefault();\r\n evt.stopPropagation();\r\n // Some browsers do not auto-focus buttons (eg. Safari)\r\n $tooltip.$isShown ? element[0].blur() : element[0].focus();\r\n };\r\n\r\n // bind/unbind events\r\n function bindTriggerEvents() {\r\n var triggers = options.trigger.split(' ');\r\n angular.forEach(triggers, function(trigger) {\r\n if(trigger === 'click') {\r\n element.on('click', $tooltip.toggle);\r\n } else if(trigger !== 'manual') {\r\n element.on(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);\r\n element.on(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);\r\n nodeName === 'button' && trigger !== 'hover' && element.on(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);\r\n }\r\n });\r\n }\r\n\r\n function unbindTriggerEvents() {\r\n var triggers = options.trigger.split(' ');\r\n for (var i = triggers.length; i--;) {\r\n var trigger = triggers[i];\r\n if(trigger === 'click') {\r\n element.off('click', $tooltip.toggle);\r\n } else if(trigger !== 'manual') {\r\n element.off(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);\r\n element.off(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);\r\n nodeName === 'button' && trigger !== 'hover' && element.off(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);\r\n }\r\n }\r\n }\r\n\r\n function bindKeyboardEvents() {\r\n if(options.trigger !== 'focus') {\r\n tipElement.on('keyup', $tooltip.$onKeyUp);\r\n } else {\r\n element.on('keyup', $tooltip.$onFocusKeyUp);\r\n }\r\n }\r\n\r\n function unbindKeyboardEvents() {\r\n if(options.trigger !== 'focus') {\r\n tipElement.off('keyup', $tooltip.$onKeyUp);\r\n } else {\r\n element.off('keyup', $tooltip.$onFocusKeyUp);\r\n }\r\n }\r\n\r\n var _autoCloseEventsBinded = false;\r\n function bindAutoCloseEvents() {\r\n // use timeout to hookup the events to prevent\r\n // event bubbling from being processed imediately.\r\n $timeout(function() {\r\n // Stop propagation when clicking inside tooltip\r\n tipElement.on('click', stopEventPropagation);\r\n\r\n // Hide when clicking outside tooltip\r\n $body.on('click', $tooltip.hide);\r\n\r\n _autoCloseEventsBinded = true;\r\n }, 0, false);\r\n }\r\n\r\n function unbindAutoCloseEvents() {\r\n if (_autoCloseEventsBinded) {\r\n tipElement.off('click', stopEventPropagation);\r\n $body.off('click', $tooltip.hide);\r\n _autoCloseEventsBinded = false;\r\n }\r\n }\r\n\r\n function stopEventPropagation(event) {\r\n event.stopPropagation();\r\n }\r\n\r\n // Private methods\r\n\r\n function getPosition($element) {\r\n $element = $element || (options.target || element);\r\n\r\n var el = $element[0];\r\n\r\n var elRect = el.getBoundingClientRect();\r\n if (elRect.width === null) {\r\n // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093\r\n elRect = angular.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top });\r\n }\r\n\r\n var elPos;\r\n if (options.container === 'body') {\r\n elPos = dimensions.offset(el);\r\n } else {\r\n elPos = dimensions.position(el);\r\n }\r\n\r\n return angular.extend({}, elRect, elPos);\r\n }\r\n\r\n function getCalculatedOffset(placement, position, actualWidth, actualHeight) {\r\n var offset;\r\n var split = placement.split('-');\r\n\r\n switch (split[0]) {\r\n case 'right':\r\n offset = {\r\n top: position.top + position.height / 2 - actualHeight / 2,\r\n left: position.left + position.width\r\n };\r\n break;\r\n case 'bottom':\r\n offset = {\r\n top: position.top + position.height,\r\n left: position.left + position.width / 2 - actualWidth / 2\r\n };\r\n break;\r\n case 'left':\r\n offset = {\r\n top: position.top + position.height / 2 - actualHeight / 2,\r\n left: position.left - actualWidth\r\n };\r\n break;\r\n default:\r\n offset = {\r\n top: position.top - actualHeight,\r\n left: position.left + position.width / 2 - actualWidth / 2\r\n };\r\n break;\r\n }\r\n\r\n if(!split[1]) {\r\n return offset;\r\n }\r\n\r\n // Add support for corners @todo css\r\n if(split[0] === 'top' || split[0] === 'bottom') {\r\n switch (split[1]) {\r\n case 'left':\r\n offset.left = position.left;\r\n break;\r\n case 'right':\r\n offset.left = position.left + position.width - actualWidth;\r\n }\r\n } else if(split[0] === 'left' || split[0] === 'right') {\r\n switch (split[1]) {\r\n case 'top':\r\n offset.top = position.top - actualHeight;\r\n break;\r\n case 'bottom':\r\n offset.top = position.top + position.height;\r\n }\r\n }\r\n\r\n return offset;\r\n }\r\n\r\n function applyPlacementCss(top, left) {\r\n tipElement.css({ top: top + 'px', left: left + 'px' });\r\n }\r\n\r\n function destroyTipElement() {\r\n // Cancel pending callbacks\r\n clearTimeout(timeout);\r\n\r\n if($tooltip.$isShown && tipElement !== null) {\r\n if(options.autoClose) {\r\n unbindAutoCloseEvents();\r\n }\r\n\r\n if(options.keyboard) {\r\n unbindKeyboardEvents();\r\n }\r\n }\r\n\r\n if(tipScope) {\r\n tipScope.$destroy();\r\n tipScope = null;\r\n }\r\n\r\n if(tipElement) {\r\n tipElement.remove();\r\n tipElement = $tooltip.$element = null;\r\n }\r\n }\r\n\r\n return $tooltip;\r\n\r\n }\r\n\r\n // Helper functions\r\n\r\n function safeDigest(scope) {\r\n scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();\r\n }\r\n\r\n function findElement(query, element) {\r\n return angular.element((element || document).querySelectorAll(query));\r\n }\r\n\r\n var fetchPromises = {};\r\n function fetchTemplate(template) {\r\n if(fetchPromises[template]) return fetchPromises[template];\r\n return (fetchPromises[template] = $q.when($templateCache.get(template) || $http.get(template))\r\n .then(function(res) {\r\n if(angular.isObject(res)) {\r\n $templateCache.put(template, res.data);\r\n return res.data;\r\n }\r\n return res;\r\n }));\r\n }\r\n\r\n return TooltipFactory;\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsTooltip', function($window, $location, $sce, $tooltip, $$rAF) {\r\n\r\n return {\r\n restrict: 'EAC',\r\n scope: true,\r\n link: function postLink(scope, element, attr, transclusion) {\r\n\r\n // Directive options\r\n var options = {scope: scope};\r\n angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'backdropAnimation', 'type', 'customClass'], function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n // overwrite inherited title value when no value specified\r\n // fix for angular 1.3.1 531a8de72c439d8ddd064874bf364c00cedabb11\r\n if (!scope.hasOwnProperty('title')){\r\n scope.title = '';\r\n }\r\n\r\n // Observe scope attributes for change\r\n attr.$observe('title', function(newValue) {\r\n if (angular.isDefined(newValue) || !scope.hasOwnProperty('title')) {\r\n var oldValue = scope.title;\r\n scope.title = $sce.trustAsHtml(newValue);\r\n angular.isDefined(oldValue) && $$rAF(function() {\r\n tooltip && tooltip.$applyPlacement();\r\n });\r\n }\r\n });\r\n\r\n // Support scope as an object\r\n attr.bsTooltip && scope.$watch(attr.bsTooltip, function(newValue, oldValue) {\r\n if(angular.isObject(newValue)) {\r\n angular.extend(scope, newValue);\r\n } else {\r\n scope.title = newValue;\r\n }\r\n angular.isDefined(oldValue) && $$rAF(function() {\r\n tooltip && tooltip.$applyPlacement();\r\n });\r\n }, true);\r\n\r\n // Visibility binding support\r\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\r\n if(!tooltip || !angular.isDefined(newValue)) return;\r\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(tooltip),?/i);\r\n newValue === true ? tooltip.show() : tooltip.hide();\r\n });\r\n\r\n // Enabled binding support\r\n attr.bsEnabled && scope.$watch(attr.bsEnabled, function(newValue, oldValue) {\r\n // console.warn('scope.$watch(%s)', attr.bsEnabled, newValue, oldValue);\r\n if(!tooltip || !angular.isDefined(newValue)) return;\r\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|1|,?(tooltip),?/i);\r\n newValue === false ? tooltip.setEnabled(false) : tooltip.setEnabled(true);\r\n });\r\n\r\n // Initialize popover\r\n var tooltip = $tooltip(element, options);\r\n\r\n // Garbage collection\r\n scope.$on('$destroy', function() {\r\n if(tooltip) tooltip.destroy();\r\n options = null;\r\n tooltip = null;\r\n });\r\n\r\n }\r\n };\r\n\r\n });\r\n","'use strict';\r\n\r\nangular.module('mgcrea.ngStrap.typeahead', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions'])\r\n\r\n .provider('$typeahead', function() {\r\n\r\n var defaults = this.defaults = {\r\n animation: 'am-fade',\r\n prefixClass: 'typeahead',\r\n prefixEvent: '$typeahead',\r\n placement: 'bottom-left',\r\n template: 'typeahead/typeahead.tpl.html',\r\n trigger: 'focus',\r\n container: false,\r\n keyboard: true,\r\n html: false,\r\n delay: 0,\r\n minLength: 1,\r\n filter: 'filter',\r\n limit: 6,\r\n comparator: ''\r\n };\r\n\r\n this.$get = function($window, $rootScope, $tooltip, $timeout) {\r\n\r\n var bodyEl = angular.element($window.document.body);\r\n\r\n function TypeaheadFactory(element, controller, config) {\r\n\r\n var $typeahead = {};\r\n\r\n // Common vars\r\n var options = angular.extend({}, defaults, config);\r\n\r\n $typeahead = $tooltip(element, options);\r\n var parentScope = config.scope;\r\n var scope = $typeahead.$scope;\r\n\r\n scope.$resetMatches = function(){\r\n scope.$matches = [];\r\n scope.$activeIndex = 0;\r\n };\r\n scope.$resetMatches();\r\n\r\n scope.$activate = function(index) {\r\n scope.$$postDigest(function() {\r\n $typeahead.activate(index);\r\n });\r\n };\r\n\r\n scope.$select = function(index, evt) {\r\n scope.$$postDigest(function() {\r\n $typeahead.select(index);\r\n });\r\n };\r\n\r\n scope.$isVisible = function() {\r\n return $typeahead.$isVisible();\r\n };\r\n\r\n // Public methods\r\n\r\n $typeahead.update = function(matches) {\r\n scope.$matches = matches;\r\n if(scope.$activeIndex >= matches.length) {\r\n scope.$activeIndex = 0;\r\n }\r\n };\r\n\r\n $typeahead.activate = function(index) {\r\n scope.$activeIndex = index;\r\n };\r\n\r\n $typeahead.select = function(index) {\r\n var value = scope.$matches[index].value;\r\n // console.log('$setViewValue', value);\r\n controller.$setViewValue(value);\r\n controller.$render();\r\n scope.$resetMatches();\r\n if(parentScope) parentScope.$digest();\r\n // Emit event\r\n scope.$emit(options.prefixEvent + '.select', value, index);\r\n };\r\n\r\n // Protected methods\r\n\r\n $typeahead.$isVisible = function() {\r\n if(!options.minLength || !controller) {\r\n return !!scope.$matches.length;\r\n }\r\n // minLength support\r\n return scope.$matches.length && angular.isString(controller.$viewValue) && controller.$viewValue.length >= options.minLength;\r\n };\r\n\r\n $typeahead.$getIndex = function(value) {\r\n var l = scope.$matches.length, i = l;\r\n if(!l) return;\r\n for(i = l; i--;) {\r\n if(scope.$matches[i].value === value) break;\r\n }\r\n if(i < 0) return;\r\n return i;\r\n };\r\n\r\n $typeahead.$onMouseDown = function(evt) {\r\n // Prevent blur on mousedown\r\n evt.preventDefault();\r\n evt.stopPropagation();\r\n };\r\n\r\n $typeahead.$onKeyDown = function(evt) {\r\n if(!/(38|40|13)/.test(evt.keyCode)) return;\r\n\r\n // Let ngSubmit pass if the typeahead tip is hidden\r\n if($typeahead.$isVisible()) {\r\n evt.preventDefault();\r\n evt.stopPropagation();\r\n }\r\n\r\n // Select with enter\r\n if(evt.keyCode === 13 && scope.$matches.length) {\r\n $typeahead.select(scope.$activeIndex);\r\n }\r\n\r\n // Navigate with keyboard\r\n else if(evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--;\r\n else if(evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++;\r\n else if(angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0;\r\n scope.$digest();\r\n };\r\n\r\n // Overrides\r\n\r\n var show = $typeahead.show;\r\n $typeahead.show = function() {\r\n show();\r\n // use timeout to hookup the events to prevent\r\n // event bubbling from being processed imediately.\r\n $timeout(function() {\r\n $typeahead.$element.on('mousedown', $typeahead.$onMouseDown);\r\n if(options.keyboard) {\r\n element.on('keydown', $typeahead.$onKeyDown);\r\n }\r\n }, 0, false);\r\n };\r\n\r\n var hide = $typeahead.hide;\r\n $typeahead.hide = function() {\r\n $typeahead.$element.off('mousedown', $typeahead.$onMouseDown);\r\n if(options.keyboard) {\r\n element.off('keydown', $typeahead.$onKeyDown);\r\n }\r\n hide();\r\n };\r\n\r\n return $typeahead;\r\n\r\n }\r\n\r\n TypeaheadFactory.defaults = defaults;\r\n return TypeaheadFactory;\r\n\r\n };\r\n\r\n })\r\n\r\n .directive('bsTypeahead', function($window, $parse, $q, $typeahead, $parseOptions) {\r\n\r\n var defaults = $typeahead.defaults;\r\n\r\n return {\r\n restrict: 'EAC',\r\n require: 'ngModel',\r\n link: function postLink(scope, element, attr, controller) {\r\n\r\n // Directive options\r\n var options = {scope: scope};\r\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'filter', 'limit', 'minLength', 'watchOptions', 'selectMode', 'comparator'], function(key) {\r\n if(angular.isDefined(attr[key])) options[key] = attr[key];\r\n });\r\n\r\n // Build proper ngOptions\r\n var filter = options.filter || defaults.filter;\r\n var limit = options.limit || defaults.limit;\r\n var comparator = options.comparator || defaults.comparator;\r\n\r\n var ngOptions = attr.ngOptions;\r\n if(filter) ngOptions += ' | ' + filter + ':$viewValue';\r\n if (comparator) ngOptions += ':' + comparator;\r\n if(limit) ngOptions += ' | limitTo:' + limit;\r\n var parsedOptions = $parseOptions(ngOptions);\r\n\r\n // Initialize typeahead\r\n var typeahead = $typeahead(element, controller, options);\r\n\r\n // Watch options on demand\r\n if(options.watchOptions) {\r\n // Watch ngOptions values before filtering for changes, drop function calls\r\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').replace(/\\(.*\\)/g, '').trim();\r\n scope.$watch(watchedOptions, function (newValue, oldValue) {\r\n // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue);\r\n parsedOptions.valuesFn(scope, controller).then(function (values) {\r\n typeahead.update(values);\r\n controller.$render();\r\n });\r\n }, true);\r\n }\r\n\r\n // Watch model for changes\r\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\r\n // console.warn('$watch', element.attr('ng-model'), newValue);\r\n scope.$modelValue = newValue; // Publish modelValue on scope for custom templates\r\n parsedOptions.valuesFn(scope, controller)\r\n .then(function(values) {\r\n // Prevent input with no future prospect if selectMode is truthy\r\n // @TODO test selectMode\r\n if(options.selectMode && !values.length && newValue.length > 0) {\r\n controller.$setViewValue(controller.$viewValue.substring(0, controller.$viewValue.length - 1));\r\n return;\r\n }\r\n if(values.length > limit) values = values.slice(0, limit);\r\n var isVisible = typeahead.$isVisible();\r\n isVisible && typeahead.update(values);\r\n // Do not re-queue an update if a correct value has been selected\r\n if(values.length === 1 && values[0].value === newValue) return;\r\n !isVisible && typeahead.update(values);\r\n // Queue a new rendering that will leverage collection loading\r\n controller.$render();\r\n });\r\n });\r\n\r\n // modelValue -> $formatters -> viewValue\r\n controller.$formatters.push(function(modelValue) {\r\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\r\n var displayValue = parsedOptions.displayValue(modelValue);\r\n return displayValue === undefined ? '' : displayValue;\r\n });\r\n\r\n // Model rendering in view\r\n controller.$render = function () {\r\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\r\n if(controller.$isEmpty(controller.$viewValue)) return element.val('');\r\n var index = typeahead.$getIndex(controller.$modelValue);\r\n var selected = angular.isDefined(index) ? typeahead.$scope.$matches[index].label : controller.$viewValue;\r\n selected = angular.isObject(selected) ? parsedOptions.displayValue(selected) : selected;\r\n element.val(selected ? selected.toString().replace(/<(?:.|\\n)*?>/gm, '').trim() : '');\r\n };\r\n\r\n // Garbage collection\r\n scope.$on('$destroy', function() {\r\n if (typeahead) typeahead.destroy();\r\n options = null;\r\n typeahead = null;\r\n });\r\n\r\n }\r\n };\r\n\r\n });\r\n"],"sourceRoot":"/source/"}
\ No newline at end of file
diff --git a/dist/angular-strap.tpl.js b/dist/angular-strap.tpl.js
index 64194c02a..29790aa97 100644
--- a/dist/angular-strap.tpl.js
+++ b/dist/angular-strap.tpl.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
@@ -15,6 +15,13 @@ angular.module('mgcrea.ngStrap.alert').run(['$templateCache', function($template
}]);
+// Source: aside.tpl.js
+angular.module('mgcrea.ngStrap.aside').run(['$templateCache', function($templateCache) {
+
+ $templateCache.put('aside/aside.tpl.html', '');
+
+}]);
+
// Source: datepicker.tpl.js
angular.module('mgcrea.ngStrap.datepicker').run(['$templateCache', function($templateCache) {
@@ -29,17 +36,17 @@ angular.module('mgcrea.ngStrap.dropdown').run(['$templateCache', function($templ
}]);
-// Source: aside.tpl.js
-angular.module('mgcrea.ngStrap.aside').run(['$templateCache', function($templateCache) {
+// Source: modal.tpl.js
+angular.module('mgcrea.ngStrap.modal').run(['$templateCache', function($templateCache) {
- $templateCache.put('aside/aside.tpl.html', '');
+ $templateCache.put('modal/modal.tpl.html', '');
}]);
-// Source: modal.tpl.js
-angular.module('mgcrea.ngStrap.modal').run(['$templateCache', function($templateCache) {
+// Source: popover.tpl.js
+angular.module('mgcrea.ngStrap.popover').run(['$templateCache', function($templateCache) {
- $templateCache.put('modal/modal.tpl.html', '');
+ $templateCache.put('popover/popover.tpl.html', '');
}]);
@@ -64,10 +71,10 @@ angular.module('mgcrea.ngStrap.tab').run(['$templateCache', function($templateCa
}]);
-// Source: popover.tpl.js
-angular.module('mgcrea.ngStrap.popover').run(['$templateCache', function($templateCache) {
+// Source: timepicker.tpl.js
+angular.module('mgcrea.ngStrap.timepicker').run(['$templateCache', function($templateCache) {
- $templateCache.put('popover/popover.tpl.html', '');
+ $templateCache.put('timepicker/timepicker.tpl.html', '');
}]);
@@ -78,13 +85,6 @@ angular.module('mgcrea.ngStrap.tooltip').run(['$templateCache', function($templa
}]);
-// Source: timepicker.tpl.js
-angular.module('mgcrea.ngStrap.timepicker').run(['$templateCache', function($templateCache) {
-
- $templateCache.put('timepicker/timepicker.tpl.html', '');
-
-}]);
-
// Source: typeahead.tpl.js
angular.module('mgcrea.ngStrap.typeahead').run(['$templateCache', function($templateCache) {
diff --git a/dist/angular-strap.tpl.min.js b/dist/angular-strap.tpl.min.js
index 3f383c0f7..90cb55fbf 100644
--- a/dist/angular-strap.tpl.min.js
+++ b/dist/angular-strap.tpl.min.js
@@ -1,8 +1,8 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
*/
-!function(){"use strict";angular.module("mgcrea.ngStrap.alert").run(["$templateCache",function(t){t.put("alert/alert.tpl.html",'×
')}]),angular.module("mgcrea.ngStrap.datepicker").run(["$templateCache",function(t){t.put("datepicker/datepicker.tpl.html",'')}]),angular.module("mgcrea.ngStrap.dropdown").run(["$templateCache",function(t){t.put("dropdown/dropdown.tpl.html",'')}]),angular.module("mgcrea.ngStrap.aside").run(["$templateCache",function(t){t.put("aside/aside.tpl.html",'')}]),angular.module("mgcrea.ngStrap.modal").run(["$templateCache",function(t){t.put("modal/modal.tpl.html",'')}]),angular.module("mgcrea.ngStrap.progressbar").run(["$templateCache",function(t){t.put("progressbar/progressbar.tpl.html",'')}]),angular.module("mgcrea.ngStrap.select").run(["$templateCache",function(t){t.put("select/select.tpl.html",'')}]),angular.module("mgcrea.ngStrap.tab").run(["$templateCache",function(t){t.put("tab/tab.tpl.html",'
')}]),angular.module("mgcrea.ngStrap.popover").run(["$templateCache",function(t){t.put("popover/popover.tpl.html",'')}]),angular.module("mgcrea.ngStrap.tooltip").run(["$templateCache",function(t){t.put("tooltip/tooltip.tpl.html",'')}]),angular.module("mgcrea.ngStrap.timepicker").run(["$templateCache",function(t){t.put("timepicker/timepicker.tpl.html",'')}]),angular.module("mgcrea.ngStrap.typeahead").run(["$templateCache",function(t){t.put("typeahead/typeahead.tpl.html",'')}])}(window,document);
\ No newline at end of file
+!function(){"use strict";angular.module("mgcrea.ngStrap.alert").run(["$templateCache",function(t){t.put("alert/alert.tpl.html",'×
')}]),angular.module("mgcrea.ngStrap.aside").run(["$templateCache",function(t){t.put("aside/aside.tpl.html",'')}]),angular.module("mgcrea.ngStrap.datepicker").run(["$templateCache",function(t){t.put("datepicker/datepicker.tpl.html",'')}]),angular.module("mgcrea.ngStrap.dropdown").run(["$templateCache",function(t){t.put("dropdown/dropdown.tpl.html",'')}]),angular.module("mgcrea.ngStrap.modal").run(["$templateCache",function(t){t.put("modal/modal.tpl.html",'')}]),angular.module("mgcrea.ngStrap.popover").run(["$templateCache",function(t){t.put("popover/popover.tpl.html",'')}]),angular.module("mgcrea.ngStrap.progressbar").run(["$templateCache",function(t){t.put("progressbar/progressbar.tpl.html",'')}]),angular.module("mgcrea.ngStrap.select").run(["$templateCache",function(t){t.put("select/select.tpl.html",'')}]),angular.module("mgcrea.ngStrap.tab").run(["$templateCache",function(t){t.put("tab/tab.tpl.html",'
')}]),angular.module("mgcrea.ngStrap.timepicker").run(["$templateCache",function(t){t.put("timepicker/timepicker.tpl.html",'')}]),angular.module("mgcrea.ngStrap.tooltip").run(["$templateCache",function(t){t.put("tooltip/tooltip.tpl.html",'')}]),angular.module("mgcrea.ngStrap.typeahead").run(["$templateCache",function(t){t.put("typeahead/typeahead.tpl.html",'')}])}(window,document);
\ No newline at end of file
diff --git a/dist/modules/affix.js b/dist/modules/affix.js
index fd263bb07..4be8bea99 100644
--- a/dist/modules/affix.js
+++ b/dist/modules/affix.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/affix.min.js b/dist/modules/affix.min.js
index 3eb4a72f2..4efb5893f 100644
--- a/dist/modules/affix.min.js
+++ b/dist/modules/affix.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/alert.js b/dist/modules/alert.js
index ee8405b08..feaf99287 100644
--- a/dist/modules/alert.js
+++ b/dist/modules/alert.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/alert.min.js b/dist/modules/alert.min.js
index a97d81436..0279bba44 100644
--- a/dist/modules/alert.min.js
+++ b/dist/modules/alert.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/alert.tpl.js b/dist/modules/alert.tpl.js
index b0b22e80f..1c6ee2fb8 100644
--- a/dist/modules/alert.tpl.js
+++ b/dist/modules/alert.tpl.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/alert.tpl.min.js b/dist/modules/alert.tpl.min.js
index 6b94d2506..8c3316b40 100644
--- a/dist/modules/alert.tpl.min.js
+++ b/dist/modules/alert.tpl.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/aside.js b/dist/modules/aside.js
index c27f9e0e4..5d0502f57 100644
--- a/dist/modules/aside.js
+++ b/dist/modules/aside.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/aside.min.js b/dist/modules/aside.min.js
index a6ddd46db..c902a4dd9 100644
--- a/dist/modules/aside.min.js
+++ b/dist/modules/aside.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/aside.tpl.js b/dist/modules/aside.tpl.js
index 5eef71d55..de7a7491e 100644
--- a/dist/modules/aside.tpl.js
+++ b/dist/modules/aside.tpl.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/aside.tpl.min.js b/dist/modules/aside.tpl.min.js
index 2fb8712d5..0e926546b 100644
--- a/dist/modules/aside.tpl.min.js
+++ b/dist/modules/aside.tpl.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/button.js b/dist/modules/button.js
index 95b32ef5a..f871d3e67 100644
--- a/dist/modules/button.js
+++ b/dist/modules/button.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/button.min.js b/dist/modules/button.min.js
index f91204330..77fc65772 100644
--- a/dist/modules/button.min.js
+++ b/dist/modules/button.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/collapse.js b/dist/modules/collapse.js
index 11c9cfc7d..34e48bc0c 100644
--- a/dist/modules/collapse.js
+++ b/dist/modules/collapse.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/collapse.min.js b/dist/modules/collapse.min.js
index 11e96db87..168f5c218 100644
--- a/dist/modules/collapse.min.js
+++ b/dist/modules/collapse.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/date-formatter.js b/dist/modules/date-formatter.js
index 77bc9fa3d..90b74710c 100644
--- a/dist/modules/date-formatter.js
+++ b/dist/modules/date-formatter.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/date-formatter.min.js b/dist/modules/date-formatter.min.js
index 045dbcc88..261e0665e 100644
--- a/dist/modules/date-formatter.min.js
+++ b/dist/modules/date-formatter.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/date-parser.js b/dist/modules/date-parser.js
index 831a3c047..1ca6bcede 100644
--- a/dist/modules/date-parser.js
+++ b/dist/modules/date-parser.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/date-parser.min.js b/dist/modules/date-parser.min.js
index 2ffacfb03..409ed4174 100644
--- a/dist/modules/date-parser.min.js
+++ b/dist/modules/date-parser.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/datepicker.js b/dist/modules/datepicker.js
index 2679425e2..52434968a 100644
--- a/dist/modules/datepicker.js
+++ b/dist/modules/datepicker.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/datepicker.min.js b/dist/modules/datepicker.min.js
index df29ac861..8a2bbd564 100644
--- a/dist/modules/datepicker.min.js
+++ b/dist/modules/datepicker.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/datepicker.tpl.js b/dist/modules/datepicker.tpl.js
index ebc4e7dc5..fa26fe58f 100644
--- a/dist/modules/datepicker.tpl.js
+++ b/dist/modules/datepicker.tpl.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/datepicker.tpl.min.js b/dist/modules/datepicker.tpl.min.js
index b2ac89b6e..4b6747aca 100644
--- a/dist/modules/datepicker.tpl.min.js
+++ b/dist/modules/datepicker.tpl.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/debounce.js b/dist/modules/debounce.js
index 0e61ee2dd..35c4a4e32 100644
--- a/dist/modules/debounce.js
+++ b/dist/modules/debounce.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/debounce.min.js b/dist/modules/debounce.min.js
index c39e2f294..7248212c6 100644
--- a/dist/modules/debounce.min.js
+++ b/dist/modules/debounce.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/dimensions.js b/dist/modules/dimensions.js
index 9aa00d84e..90846bed0 100644
--- a/dist/modules/dimensions.js
+++ b/dist/modules/dimensions.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/dimensions.min.js b/dist/modules/dimensions.min.js
index 0538d7d3a..6a5db4000 100644
--- a/dist/modules/dimensions.min.js
+++ b/dist/modules/dimensions.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/dropdown.js b/dist/modules/dropdown.js
index 29b34df30..07db429e0 100644
--- a/dist/modules/dropdown.js
+++ b/dist/modules/dropdown.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/dropdown.min.js b/dist/modules/dropdown.min.js
index 565b4e1c4..291cbeece 100644
--- a/dist/modules/dropdown.min.js
+++ b/dist/modules/dropdown.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/dropdown.tpl.js b/dist/modules/dropdown.tpl.js
index a114c89f4..2165dfb5a 100644
--- a/dist/modules/dropdown.tpl.js
+++ b/dist/modules/dropdown.tpl.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/dropdown.tpl.min.js b/dist/modules/dropdown.tpl.min.js
index 0ad7ff835..d10f5d86b 100644
--- a/dist/modules/dropdown.tpl.min.js
+++ b/dist/modules/dropdown.tpl.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/modal.js b/dist/modules/modal.js
index 1f5bfec63..1b18c72fe 100644
--- a/dist/modules/modal.js
+++ b/dist/modules/modal.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/modal.min.js b/dist/modules/modal.min.js
index abd9f7395..e4d81c329 100644
--- a/dist/modules/modal.min.js
+++ b/dist/modules/modal.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/modal.tpl.js b/dist/modules/modal.tpl.js
index 3cbe11fd8..8fc233d41 100644
--- a/dist/modules/modal.tpl.js
+++ b/dist/modules/modal.tpl.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/modal.tpl.min.js b/dist/modules/modal.tpl.min.js
index aa5787791..bdfe60c38 100644
--- a/dist/modules/modal.tpl.min.js
+++ b/dist/modules/modal.tpl.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/navbar.js b/dist/modules/navbar.js
index ffa9824d7..66262d152 100644
--- a/dist/modules/navbar.js
+++ b/dist/modules/navbar.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/navbar.min.js b/dist/modules/navbar.min.js
index bc01cbe60..67069bc65 100644
--- a/dist/modules/navbar.min.js
+++ b/dist/modules/navbar.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/parse-options.js b/dist/modules/parse-options.js
index ce1f463a9..a7f435c20 100644
--- a/dist/modules/parse-options.js
+++ b/dist/modules/parse-options.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/parse-options.min.js b/dist/modules/parse-options.min.js
index a25cce835..d28d78de5 100644
--- a/dist/modules/parse-options.min.js
+++ b/dist/modules/parse-options.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/popover.js b/dist/modules/popover.js
index dc07244de..053aba414 100644
--- a/dist/modules/popover.js
+++ b/dist/modules/popover.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/popover.min.js b/dist/modules/popover.min.js
index 7133b586f..4304dafd1 100644
--- a/dist/modules/popover.min.js
+++ b/dist/modules/popover.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/popover.tpl.js b/dist/modules/popover.tpl.js
index 80528fa12..2cdaf1c02 100644
--- a/dist/modules/popover.tpl.js
+++ b/dist/modules/popover.tpl.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/popover.tpl.min.js b/dist/modules/popover.tpl.min.js
index 49a7b0cd2..05c4a0798 100644
--- a/dist/modules/popover.tpl.min.js
+++ b/dist/modules/popover.tpl.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/raf.js b/dist/modules/raf.js
index 140740b36..5a9116319 100644
--- a/dist/modules/raf.js
+++ b/dist/modules/raf.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/raf.min.js b/dist/modules/raf.min.js
index b46c114f4..8dfb92c55 100644
--- a/dist/modules/raf.min.js
+++ b/dist/modules/raf.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/scrollspy.js b/dist/modules/scrollspy.js
index 35dc60b6e..983b97d9b 100644
--- a/dist/modules/scrollspy.js
+++ b/dist/modules/scrollspy.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/scrollspy.min.js b/dist/modules/scrollspy.min.js
index 14aeb5b50..fa66ef5cd 100644
--- a/dist/modules/scrollspy.min.js
+++ b/dist/modules/scrollspy.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/select.js b/dist/modules/select.js
index 4c87370f5..ae305fa16 100644
--- a/dist/modules/select.js
+++ b/dist/modules/select.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/select.min.js b/dist/modules/select.min.js
index aa888a6b1..ec72c8a1e 100644
--- a/dist/modules/select.min.js
+++ b/dist/modules/select.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/select.tpl.js b/dist/modules/select.tpl.js
index c26f2dfff..f7f9d1f70 100644
--- a/dist/modules/select.tpl.js
+++ b/dist/modules/select.tpl.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/select.tpl.min.js b/dist/modules/select.tpl.min.js
index c9c73e01e..d282866aa 100644
--- a/dist/modules/select.tpl.min.js
+++ b/dist/modules/select.tpl.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/tab.js b/dist/modules/tab.js
index e3180a171..71e8401be 100644
--- a/dist/modules/tab.js
+++ b/dist/modules/tab.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/tab.min.js b/dist/modules/tab.min.js
index 23ef39508..7701fcc21 100644
--- a/dist/modules/tab.min.js
+++ b/dist/modules/tab.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/tab.tpl.js b/dist/modules/tab.tpl.js
index 112377bc9..05bd11424 100644
--- a/dist/modules/tab.tpl.js
+++ b/dist/modules/tab.tpl.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/tab.tpl.min.js b/dist/modules/tab.tpl.min.js
index ec5af653b..3dadaad92 100644
--- a/dist/modules/tab.tpl.min.js
+++ b/dist/modules/tab.tpl.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/timepicker.js b/dist/modules/timepicker.js
index 6b2f50f7d..21b5f08c3 100644
--- a/dist/modules/timepicker.js
+++ b/dist/modules/timepicker.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/timepicker.min.js b/dist/modules/timepicker.min.js
index b4d5003d2..6686436aa 100644
--- a/dist/modules/timepicker.min.js
+++ b/dist/modules/timepicker.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/timepicker.tpl.js b/dist/modules/timepicker.tpl.js
index 958687402..605bf765a 100644
--- a/dist/modules/timepicker.tpl.js
+++ b/dist/modules/timepicker.tpl.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/timepicker.tpl.min.js b/dist/modules/timepicker.tpl.min.js
index b8f1496e4..c30f4f71d 100644
--- a/dist/modules/timepicker.tpl.min.js
+++ b/dist/modules/timepicker.tpl.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/tooltip.js b/dist/modules/tooltip.js
index 9c85e4f7e..492e4befc 100644
--- a/dist/modules/tooltip.js
+++ b/dist/modules/tooltip.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/tooltip.min.js b/dist/modules/tooltip.min.js
index 8c6c73e3a..82d8cc65b 100644
--- a/dist/modules/tooltip.min.js
+++ b/dist/modules/tooltip.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/tooltip.tpl.js b/dist/modules/tooltip.tpl.js
index 965dcba58..bb3991eb3 100644
--- a/dist/modules/tooltip.tpl.js
+++ b/dist/modules/tooltip.tpl.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/tooltip.tpl.min.js b/dist/modules/tooltip.tpl.min.js
index e7356c9bc..5329b509e 100644
--- a/dist/modules/tooltip.tpl.min.js
+++ b/dist/modules/tooltip.tpl.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/typeahead.js b/dist/modules/typeahead.js
index 8417dcd5b..7b6942019 100644
--- a/dist/modules/typeahead.js
+++ b/dist/modules/typeahead.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/typeahead.min.js b/dist/modules/typeahead.min.js
index 0640140eb..bce2a9894 100644
--- a/dist/modules/typeahead.min.js
+++ b/dist/modules/typeahead.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/typeahead.tpl.js b/dist/modules/typeahead.tpl.js
index 97f6aaa38..51b3f6065 100644
--- a/dist/modules/typeahead.tpl.js
+++ b/dist/modules/typeahead.tpl.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/dist/modules/typeahead.tpl.min.js b/dist/modules/typeahead.tpl.min.js
index fc3566922..c90c61a5c 100644
--- a/dist/modules/typeahead.tpl.min.js
+++ b/dist/modules/typeahead.tpl.min.js
@@ -1,6 +1,6 @@
/**
* angular-strap
- * @version v2.1.5 - 2014-12-30
+ * @version v2.1.5 - 2014-12-31
* @link http://mgcrea.github.io/angular-strap
* @author Olivier Louvignes (olivier@mg-crea.com)
* @license MIT License, http://www.opensource.org/licenses/MIT
diff --git a/src/progressbar/progressbar.js b/src/progressbar/progressbar.js
index 9e162d632..27d509e43 100644
--- a/src/progressbar/progressbar.js
+++ b/src/progressbar/progressbar.js
@@ -27,7 +27,6 @@ angular.module('mgcrea.ngStrap.progressbar', [])
link: function (scope, element, attr){
scope.type = scope.type || $progressbar.defaults.barType;
scope.animate = angular.isDefined(scope.animate()) ? scope.animate : $progressbar.defaults.animate;
- console.log(scope.animate(), $progressbar.defaults.animate, angular.isDefined(scope.animate));
scope.$watch('type', function (){
if(scope.type) {
scope.barClass = 'progress-bar-' + scope.type;
diff --git a/src/progressbar/progressbar.tpl.html b/src/progressbar/progressbar.tpl.html
index 92d06cc16..ea75680e2 100644
--- a/src/progressbar/progressbar.tpl.html
+++ b/src/progressbar/progressbar.tpl.html
@@ -3,6 +3,6 @@
aria-valuemin="0" aria-valuemax="100"
ng-style="{width: value + '%', 'webkit-transition': animate() ? null : 'none', 'transition': animate() ? null : 'none'}">
{{value}}%
-
+