From 9195cabe8a9faf0a526953cb6a67614747d575b7 Mon Sep 17 00:00:00 2001 From: Olivier Louvignes Date: Sun, 19 Jul 2015 14:26:38 +0200 Subject: [PATCH] chore(release): cut the 2.3.1 release --- bower.json | 2 +- dist/angular-strap.js | 2530 ++++++++++++----------- dist/angular-strap.min.js | 8 +- dist/angular-strap.min.js.map | 2 +- dist/angular-strap.tpl.js | 18 +- dist/angular-strap.tpl.min.js | 4 +- dist/modules/affix.js | 2 +- dist/modules/affix.min.js | 2 +- dist/modules/alert.js | 2 +- dist/modules/alert.min.js | 2 +- dist/modules/alert.tpl.js | 2 +- dist/modules/alert.tpl.min.js | 2 +- dist/modules/aside.js | 2 +- dist/modules/aside.min.js | 2 +- dist/modules/aside.tpl.js | 2 +- dist/modules/aside.tpl.min.js | 2 +- dist/modules/button.js | 2 +- dist/modules/button.min.js | 2 +- dist/modules/collapse.js | 2 +- dist/modules/collapse.min.js | 2 +- dist/modules/compiler.js | 2 +- dist/modules/compiler.min.js | 2 +- dist/modules/date-formatter.js | 2 +- dist/modules/date-formatter.min.js | 2 +- dist/modules/date-parser.js | 2 +- dist/modules/date-parser.min.js | 2 +- dist/modules/datepicker.js | 3 +- dist/modules/datepicker.min.js | 4 +- dist/modules/datepicker.min.js.map | 2 +- dist/modules/datepicker.tpl.js | 2 +- dist/modules/datepicker.tpl.min.js | 2 +- dist/modules/debounce.js | 2 +- dist/modules/debounce.min.js | 2 +- dist/modules/dimensions.js | 2 +- dist/modules/dimensions.min.js | 2 +- dist/modules/dropdown.js | 2 +- dist/modules/dropdown.min.js | 2 +- dist/modules/dropdown.tpl.js | 2 +- dist/modules/dropdown.tpl.min.js | 2 +- dist/modules/modal.js | 2 +- dist/modules/modal.min.js | 2 +- dist/modules/modal.tpl.js | 2 +- dist/modules/modal.tpl.min.js | 2 +- dist/modules/navbar.js | 2 +- dist/modules/navbar.min.js | 2 +- dist/modules/parse-options.js | 10 +- dist/modules/parse-options.min.js | 4 +- dist/modules/parse-options.min.js.map | 2 +- dist/modules/popover.js | 2 +- dist/modules/popover.min.js | 2 +- dist/modules/popover.tpl.js | 2 +- dist/modules/popover.tpl.min.js | 2 +- dist/modules/raf.js | 2 +- dist/modules/raf.min.js | 2 +- dist/modules/scrollspy.js | 2 +- dist/modules/scrollspy.min.js | 2 +- dist/modules/select.js | 2 +- dist/modules/select.min.js | 2 +- dist/modules/select.tpl.js | 2 +- dist/modules/select.tpl.min.js | 2 +- dist/modules/tab.js | 2 +- dist/modules/tab.min.js | 2 +- dist/modules/tab.tpl.js | 2 +- dist/modules/tab.tpl.min.js | 2 +- dist/modules/timepicker.js | 24 +- dist/modules/timepicker.min.js | 4 +- dist/modules/timepicker.min.js.map | 2 +- dist/modules/timepicker.tpl.js | 2 +- dist/modules/timepicker.tpl.min.js | 2 +- dist/modules/tooltip.js | 31 +- dist/modules/tooltip.min.js | 4 +- dist/modules/tooltip.min.js.map | 2 +- dist/modules/tooltip.tpl.js | 2 +- dist/modules/tooltip.tpl.min.js | 2 +- dist/modules/typeahead.js | 24 +- dist/modules/typeahead.min.js | 4 +- dist/modules/typeahead.min.js.map | 2 +- dist/modules/typeahead.tpl.js | 2 +- dist/modules/typeahead.tpl.min.js | 2 +- docs/scripts/app.js | 2 +- docs/scripts/services/angular-plunkr.js | 2 +- package.json | 2 +- 82 files changed, 1418 insertions(+), 1390 deletions(-) diff --git a/bower.json b/bower.json index 3ff350d5c..72c47129b 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "angular-strap", "description": "AngularStrap - AngularJS directives for Bootstrap", - "version": "2.3.0", + "version": "2.3.1", "keywords": [ "angular", "bootstrap" diff --git a/dist/angular-strap.js b/dist/angular-strap.js index 540ee0ce8..5eabc2856 100644 --- a/dist/angular-strap.js +++ b/dist/angular-strap.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -802,6 +802,7 @@ }; var _show = $datepicker.show; $datepicker.show = function() { + if (!isTouch && element.attr('readonly') || element.attr('disabled')) return; _show(); $timeout(function() { if (!$datepicker.$isShown) return; @@ -1800,13 +1801,7 @@ valuesFn = $parse(match[7]); }; $parseOptions.valuesFn = function(scope, controller) { - var valuesPromise; - try { - valuesPromise = valuesFn(scope, controller); - } catch (err) { - valuesPromise = []; - } - return $q.when(valuesPromise).then(function(values) { + return $q.when(valuesFn(scope, controller)).then(function(values) { if (!angular.isArray(values)) { values = []; } @@ -2161,6 +2156,90 @@ } }; } ]); + 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', + templateUrl: '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) { + var options = angular.extend({}, defaults, config); + var $popover = $tooltip(element, options); + 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) { + var options = { + scope: scope + }; + angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'customClass', 'autoClose', 'id', 'prefixClass', 'prefixEvent' ], function(key) { + if (angular.isDefined(attr[key])) options[key] = attr[key]; + }); + var falseValueRegExp = /^(false|0|)$/i; + angular.forEach([ 'html', 'container', 'autoClose' ], function(key) { + if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false; + }); + var dataTarget = element.attr('data-target'); + if (angular.isDefined(dataTarget)) { + if (falseValueRegExp.test(dataTarget)) options.target = false; else options.target = dataTarget; + } + 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(); + }); + }); + }); + 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); + 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(); + }); + attr.viewport && scope.$watch(attr.viewport, function(newValue) { + if (!popover || !angular.isDefined(newValue)) return; + popover.setViewport(newValue); + }); + var popover = $popover(element, options); + scope.$on('$destroy', function() { + if (popover) popover.destroy(); + options = null; + popover = null; + }); + } + }; + } ]); angular.module('mgcrea.ngStrap.scrollspy', [ 'mgcrea.ngStrap.helpers.debounce', 'mgcrea.ngStrap.helpers.dimensions' ]).provider('$scrollspy', function() { var spies = this.$$spies = {}; var defaults = this.defaults = { @@ -2595,1422 +2674,1357 @@ } }; } ]); - angular.module('mgcrea.ngStrap.popover', [ 'mgcrea.ngStrap.tooltip' ]).provider('$popover', function() { + angular.module('mgcrea.ngStrap.timepicker', [ 'mgcrea.ngStrap.helpers.dateParser', 'mgcrea.ngStrap.helpers.dateFormatter', 'mgcrea.ngStrap.tooltip' ]).provider('$timepicker', function() { var defaults = this.defaults = { animation: 'am-fade', - customClass: '', + prefixClass: 'timepicker', + placement: 'bottom-left', + templateUrl: 'timepicker/timepicker.tpl.html', + trigger: 'focus', container: false, - target: false, - placement: 'right', - templateUrl: 'popover/popover.tpl.html', - contentTemplate: false, - trigger: 'click', keyboard: true, html: false, - title: '', - content: '', delay: 0, - autoClose: false + useNative: true, + timeType: 'date', + timeFormat: 'shortTime', + timezone: null, + modelTimeFormat: null, + autoclose: false, + minTime: -Infinity, + maxTime: +Infinity, + length: 5, + hourStep: 1, + minuteStep: 5, + secondStep: 5, + roundDisplay: false, + iconUp: 'glyphicon glyphicon-chevron-up', + iconDown: 'glyphicon glyphicon-chevron-down', + arrowBehavior: 'pager' }; - this.$get = [ '$tooltip', function($tooltip) { - function PopoverFactory(element, config) { - var options = angular.extend({}, defaults, config); - var $popover = $tooltip(element, options); - if (options.content) { - $popover.$scope.content = options.content; - } - return $popover; + this.$get = [ '$window', '$document', '$rootScope', '$sce', '$dateFormatter', '$tooltip', '$timeout', function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) { + var isNative = /(ip(a|o)d|iphone|android)/gi.test($window.navigator.userAgent); + var isTouch = 'createTouch' in $window.document && isNative; + if (!defaults.lang) { + defaults.lang = $dateFormatter.getDefaultLocale(); } - 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) { - var options = { - scope: scope + 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, timezone) { + return $dateFormatter.formatDate(date, format, lang, timezone); }; - angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'customClass', 'autoClose', 'id', 'prefixClass', 'prefixEvent' ], function(key) { - if (angular.isDefined(attr[key])) options[key] = attr[key]; - }); - var falseValueRegExp = /^(false|0|)$/i; - angular.forEach([ 'html', 'container', 'autoClose' ], function(key) { - if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false; - }); - var dataTarget = element.attr('data-target'); - if (angular.isDefined(dataTarget)) { - if (falseValueRegExp.test(dataTarget)) options.target = false; else options.target = dataTarget; + function floorMinutes(time) { + var coeff = 1e3 * 60 * options.minuteStep; + return new Date(Math.floor(time.getTime() / coeff) * coeff); } - 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(); + var selectedIndex = 0; + var defaultDate = options.roundDisplay ? floorMinutes(new Date()) : new Date(); + var startDate = controller.$dateValue || defaultDate; + 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); + var hoursFormat = $dateFormatter.hoursFormat(format), timeSeparator = $dateFormatter.timeSeparator(format), minutesFormat = $dateFormatter.minutesFormat(format), secondsFormat = $dateFormatter.secondsFormat(format), showSeconds = $dateFormatter.showSeconds(format), showAM = $dateFormatter.showAM(format); + scope.$iconUp = options.iconUp; + scope.$iconDown = options.iconDown; + 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); + }; + $timepicker.update = function(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() }); - }); - }); - attr.bsPopover && scope.$watch(attr.bsPopover, function(newValue, oldValue) { - if (angular.isObject(newValue)) { - angular.extend(scope, newValue); - } else { - scope.content = newValue; + $timepicker.$build(); + } else if (!$timepicker.$isBuilt) { + $timepicker.$build(); } - angular.isDefined(oldValue) && requestAnimationFrame(function() { - popover && popover.$applyPlacement(); - }); - }, true); - 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(); - }); - attr.viewport && scope.$watch(attr.viewport, function(newValue) { - if (!popover || !angular.isDefined(newValue)) return; - popover.setViewport(newValue); - }); - var popover = $popover(element, options); - scope.$on('$destroy', function() { - if (popover) popover.destroy(); - options = null; - popover = null; - }); - } - }; - } ]); - angular.module('mgcrea.ngStrap.tab', []).provider('$tab', function() { - var defaults = this.defaults = { - animation: 'am-fade', - template: 'tab/tab.tpl.html', - navClass: 'nav-tabs', - activeClass: 'active' - }; - var controller = this.controller = function($scope, $element, $attrs) { - var self = this; - self.$options = angular.copy(defaults); - angular.forEach([ 'animation', 'navClass', 'activeClass' ], function(key) { - if (angular.isDefined($attrs[key])) self.$options[key] = $attrs[key]; - }); - $scope.$navClass = self.$options.navClass; - $scope.$activeClass = self.$options.activeClass; - self.$panes = $scope.$panes = []; - self.$activePaneChangeListeners = self.$viewChangeListeners = []; - self.$push = function(pane) { - if (angular.isUndefined(self.$panes.$active)) { - $scope.$setActive(pane.name || 0); - } - self.$panes.push(pane); - }; - self.$remove = function(pane) { - var index = self.$panes.indexOf(pane); - var active = self.$panes.$active; - var activeIndex; - if (angular.isString(active)) { - activeIndex = self.$panes.map(function(pane) { - return pane.name; - }).indexOf(active); - } else { - activeIndex = self.$panes.$active; - } - self.$panes.splice(index, 1); - if (index < activeIndex) { - activeIndex--; - } else if (index === activeIndex && activeIndex === self.$panes.length) { - activeIndex--; - } - if (activeIndex >= 0 && activeIndex < self.$panes.length) { - self.$setActive(self.$panes[activeIndex].name || activeIndex); - } else { - self.$setActive(); - } - }; - self.$setActive = $scope.$setActive = function(value) { - self.$panes.$active = value; - self.$activePaneChangeListeners.forEach(function(fn) { - fn(); - }); - }; - self.$isActive = $scope.$isActive = function($pane, $index) { - return self.$panes.$active === $pane.name || self.$panes.$active === $index; - }; - }; - this.$get = function() { - var $tab = {}; - $tab.defaults = defaults; - $tab.controller = controller; - return $tab; - }; - }).directive('bsTabs', [ '$window', '$animate', '$tab', '$parse', function($window, $animate, $tab, $parse) { - var defaults = $tab.defaults; - return { - require: [ '?ngModel', 'bsTabs' ], - transclude: true, - scope: true, - controller: [ '$scope', '$element', '$attrs', $tab.controller ], - templateUrl: function(element, attr) { - return attr.template || defaults.template; - }, - link: function postLink(scope, element, attrs, controllers) { - var ngModelCtrl = controllers[0]; - var bsTabsCtrl = controllers[1]; - if (ngModelCtrl) { - bsTabsCtrl.$activePaneChangeListeners.push(function() { - ngModelCtrl.$setViewValue(bsTabsCtrl.$panes.$active); - }); - ngModelCtrl.$formatters.push(function(modelValue) { - bsTabsCtrl.$setActive(modelValue); - return modelValue; - }); - } - if (attrs.bsActivePane) { - var parsedBsActivePane = $parse(attrs.bsActivePane); - bsTabsCtrl.$activePaneChangeListeners.push(function() { - parsedBsActivePane.assign(scope, bsTabsCtrl.$panes.$active); - }); - scope.$watch(attrs.bsActivePane, function(newValue, oldValue) { - bsTabsCtrl.$setActive(newValue); - }, 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]; - element.addClass('tab-pane'); - attrs.$observe('title', function(newValue, oldValue) { - scope.title = $sce.trustAsHtml(newValue); - }); - scope.name = attrs.name; - if (bsTabsCtrl.$options.animation) { - element.addClass(bsTabsCtrl.$options.animation); - } - attrs.$observe('disabled', function(newValue, oldValue) { - scope.disabled = scope.$eval(newValue); - }); - bsTabsCtrl.$push(scope); - scope.$on('$destroy', function() { - bsTabsCtrl.$remove(scope); - }); - function render() { - var index = bsTabsCtrl.$panes.indexOf(scope); - $animate[bsTabsCtrl.$isActive(scope, index) ? 'addClass' : 'removeClass'](element, bsTabsCtrl.$options.activeClass); - } - bsTabsCtrl.$activePaneChangeListeners.push(function() { - render(); - }); - render(); - } - }; - } ]); - angular.module('mgcrea.ngStrap.tooltip', [ 'mgcrea.ngStrap.core', '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', - templateUrl: 'tooltip/tooltip.tpl.html', - template: '', - contentTemplate: false, - trigger: 'hover focus', - keyboard: false, - html: false, - show: false, - title: '', - type: '', - delay: 0, - autoClose: false, - bsEnabled: true, - viewport: { - selector: 'body', - padding: 0 - } - }; - this.$get = [ '$window', '$rootScope', '$bsCompiler', '$q', '$templateCache', '$http', '$animate', '$sce', 'dimensions', '$$rAF', '$timeout', function($window, $rootScope, $bsCompiler, $q, $templateCache, $http, $animate, $sce, dimensions, $$rAF, $timeout) { - var trim = String.prototype.trim; - var isTouch = 'createTouch' in $window.document; - var htmlReplaceRegExp = /ng-bind="/gi; - var $body = angular.element($window.document); - function TooltipFactory(element, config) { - var $tooltip = {}; - var options = $tooltip.$options = angular.extend({}, defaults, config); - var promise = $tooltip.$promise = $bsCompiler.compile(options); - var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new(); - var nodeName = element[0].nodeName.toLowerCase(); - 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]; - } - $tooltip.$id = options.id || element.attr('id') || ''; - if (options.title) { - scope.title = $sce.trustAsHtml(options.title); - } - 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(); - }); + $timepicker.select = function(date, index, keep) { + 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()); else if (index === 2) controller.$dateValue.setSeconds(date.getSeconds()); + controller.$setViewValue(angular.copy(controller.$dateValue)); + controller.$render(); + if (options.autoclose && !keep) { + $timeout(function() { + $timepicker.hide(true); + }); + } }; - $tooltip.$isShown = scope.$isShown = false; - var timeout, hoverState; - var compileData, tipElement, tipContainer, tipScope; - promise.then(function(data) { - compileData = data; - $tooltip.init(); - }); - $tooltip.init = function() { - if (options.delay && angular.isNumber(options.delay)) { - options.delay = { - show: options.delay, - hide: options.delay - }; + $timepicker.switchMeridian = function(date) { + if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) { + return; } - if (options.container === 'self') { - tipContainer = element; - } else if (angular.isElement(options.container)) { - tipContainer = options.container; - } else if (options.container) { - tipContainer = findElement(options.container); + var hours = (date || controller.$dateValue).getHours(); + controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12); + controller.$setViewValue(angular.copy(controller.$dateValue)); + controller.$render(); + }; + $timepicker.$build = function() { + 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) + }); } - bindTriggerEvents(); - if (options.target) { - options.target = angular.isElement(options.target) ? options.target : findElement(options.target); + 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) + }); } - if (options.show) { - scope.$$postDigest(function() { - options.trigger === 'focus' ? element[0].focus() : $tooltip.show(); + var seconds = [], second; + for (i = 0; i < options.length; i++) { + second = new Date(1970, 0, 1, 0, 0, viewDate.second - (midIndex - i) * options.secondStep); + seconds.push({ + date: second, + label: formatDate(second, secondsFormat), + selected: $timepicker.$date && $timepicker.$isSelected(second, 2), + disabled: $timepicker.$isDisabled(second, 2) }); } + var rows = []; + for (i = 0; i < options.length; i++) { + if (showSeconds) { + rows.push([ hours[i], minutes[i], seconds[i] ]); + } else { + rows.push([ hours[i], minutes[i] ]); + } + } + scope.rows = rows; + scope.showSeconds = showSeconds; + scope.showAM = showAM; + scope.isAM = ($timepicker.$date || hours[midIndex].date).getHours() < 12; + scope.timeSeparator = timeSeparator; + $timepicker.$isBuilt = true; }; - $tooltip.destroy = function() { - unbindTriggerEvents(); - destroyTipElement(); - scope.$destroy(); + $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(); + } else if (index === 2) { + return date.getSeconds() === $timepicker.$date.getSeconds(); + } }; - $tooltip.enter = function() { - clearTimeout(timeout); - hoverState = 'in'; - if (!options.delay || !options.delay.show) { - return $tooltip.show(); + $timepicker.$isDisabled = function(date, index) { + var selectedTime; + if (index === 0) { + selectedTime = date.getTime() + viewDate.minute * 6e4 + viewDate.second * 1e3; + } else if (index === 1) { + selectedTime = date.getTime() + viewDate.hour * 36e5 + viewDate.second * 1e3; + } else if (index === 2) { + selectedTime = date.getTime() + viewDate.hour * 36e5 + viewDate.minute * 6e4; } - timeout = setTimeout(function() { - if (hoverState === 'in') $tooltip.show(); - }, options.delay.show); + return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1; }; - $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; - } + scope.$arrowAction = function(value, index) { + if (options.arrowBehavior === 'picker') { + $timepicker.$setTimeByStep(value, index); } else { - parent = null; - after = element; + $timepicker.$moveIndex(value, index); } - if (tipElement) destroyTipElement(); - tipScope = $tooltip.$scope.$new(); - tipElement = $tooltip.$element = compileData.link(tipScope, function(clonedElement, scope) {}); - tipElement.css({ - top: '-9999px', - left: '-9999px', - right: 'auto', - display: 'block', - visibility: 'hidden' - }); - if (options.animation) tipElement.addClass(options.animation); - if (options.type) tipElement.addClass(options.prefixClass + '-' + options.type); - if (options.customClass) tipElement.addClass(options.customClass); - after ? after.after(tipElement) : parent.prepend(tipElement); - $tooltip.$isShown = scope.$isShown = true; - safeDigest(scope); - $tooltip.$applyPlacement(); - if (angular.version.minor <= 2) { - $animate.enter(tipElement, parent, after, enterAnimateCallback); - } else { - $animate.enter(tipElement, parent, after).then(enterAnimateCallback); + }; + $timepicker.$setTimeByStep = function(value, index) { + var newDate = new Date($timepicker.$date || startDate); + var hours = newDate.getHours(); + var minutes = newDate.getMinutes(); + var seconds = newDate.getSeconds(); + if (index === 0) { + newDate.setHours(hours - parseInt(options.hourStep, 10) * value); + } else if (index === 1) { + newDate.setMinutes(minutes - parseInt(options.minuteStep, 10) * value); + } else if (index === 2) { + newDate.setSeconds(seconds - parseInt(options.secondStep, 10) * value); } - safeDigest(scope); - $$rAF(function() { - if (tipElement) tipElement.css({ - visibility: 'visible' + $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, viewDate.second); + angular.extend(viewDate, { + hour: targetDate.getHours() }); - }); - if (options.keyboard) { - if (options.trigger !== 'focus') { - $tooltip.focus(); + } else if (index === 1) { + targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + value * options.length * options.minuteStep, viewDate.second); + angular.extend(viewDate, { + minute: targetDate.getMinutes() + }); + } else if (index === 2) { + targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute, viewDate.second + value * options.length * options.secondStep); + angular.extend(viewDate, { + second: targetDate.getSeconds() + }); + } + $timepicker.$build(); + }; + $timepicker.$onMouseDown = function(evt) { + if (evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault(); + evt.stopPropagation(); + if (isTouch) { + var targetEl = angular.element(evt.target); + if (targetEl[0].nodeName.toLowerCase() !== 'button') { + targetEl = targetEl.parent(); } - bindKeyboardEvents(); + targetEl.triggerHandler('click'); } - if (options.autoClose) { - bindAutoCloseEvents(); + }; + $timepicker.$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) { + $timepicker.hide(true); + return; + } + 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 seconds = newDate.getSeconds(), secondsLength = formatDate(newDate, secondsFormat).length; + var sepLength = 1; + var lateralMove = /(37|39)/.test(evt.keyCode); + var count = 2 + showSeconds * 1 + showAM * 1; + 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 selectRange = [ 0, hoursLength ]; + var incr = 0; + if (evt.keyCode === 38) incr = -1; + if (evt.keyCode === 40) incr = +1; + var isSeconds = selectedIndex === 2 && showSeconds; + var isMeridian = selectedIndex === 2 && !showSeconds || selectedIndex === 3 && showSeconds; + if (selectedIndex === 0) { + newDate.setHours(hours + incr * parseInt(options.hourStep, 10)); + hoursLength = formatDate(newDate, hoursFormat).length; + selectRange = [ 0, hoursLength ]; + } else if (selectedIndex === 1) { + newDate.setMinutes(minutes + incr * parseInt(options.minuteStep, 10)); + minutesLength = formatDate(newDate, minutesFormat).length; + selectRange = [ hoursLength + sepLength, minutesLength ]; + } else if (isSeconds) { + newDate.setSeconds(seconds + incr * parseInt(options.secondStep, 10)); + secondsLength = formatDate(newDate, secondsFormat).length; + selectRange = [ hoursLength + sepLength + minutesLength + sepLength, secondsLength ]; + } else if (isMeridian) { + if (!lateralMove) $timepicker.switchMeridian(); + selectRange = [ hoursLength + sepLength + minutesLength + sepLength + (secondsLength + sepLength) * showSeconds, 2 ]; + } + $timepicker.select(newDate, selectedIndex, true); + createSelection(selectRange[0], selectRange[1]); + parentScope.$digest(); + }; + function createSelection(start, length) { + var end = start + length; + 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 enterAnimateCallback() { - scope.$emit(options.prefixEvent + '.show', $tooltip); } - $tooltip.leave = function() { - clearTimeout(timeout); - hoverState = 'out'; - if (!options.delay || !options.delay.hide) { - return $tooltip.hide(); + function focusElement() { + element[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); } - timeout = setTimeout(function() { - if (hoverState === 'out') { - $tooltip.hide(); - } - }, options.delay.hide); + _init(); }; - var _blur; - var _tipToHide; - $tooltip.hide = function(blur) { - if (!$tooltip.$isShown) return; - scope.$emit(options.prefixEvent + '.hide.before', $tooltip); - _blur = blur; - _tipToHide = tipElement; - if (angular.version.minor <= 2) { - $animate.leave(tipElement, leaveAnimateCallback); - } else { - $animate.leave(tipElement).then(leaveAnimateCallback); - } - $tooltip.$isShown = scope.$isShown = false; - safeDigest(scope); - if (options.keyboard && tipElement !== null) { - unbindKeyboardEvents(); - } - if (options.autoClose && tipElement !== null) { - unbindAutoCloseEvents(); + var _destroy = $timepicker.destroy; + $timepicker.destroy = function() { + if (isNative && options.useNative) { + element.off('click', focusElement); } + _destroy(); }; - function leaveAnimateCallback() { - scope.$emit(options.prefixEvent + '.hide', $tooltip); - if (tipElement === _tipToHide) { - if (_blur && options.trigger === 'focus') { - return element[0].blur(); + var _show = $timepicker.show; + $timepicker.show = function() { + if (!isTouch && element.attr('readonly') || element.attr('disabled')) return; + _show(); + $timeout(function() { + $timepicker.$element && $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown); + if (options.keyboard) { + element && element.on('keydown', $timepicker.$onKeyDown); } - destroyTipElement(); - } - } - $tooltip.toggle = function() { - $tooltip.$isShown ? $tooltip.leave() : $tooltip.enter(); + }, 0, false); }; - $tooltip.focus = function() { - tipElement[0].focus(); + var _hide = $timepicker.hide; + $timepicker.hide = function(blur) { + if (!$timepicker.$isShown) return; + $timepicker.$element && $timepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown); + if (options.keyboard) { + element && element.off('keydown', $timepicker.$onKeyDown); + } + _hide(blur); }; - $tooltip.setEnabled = function(isEnabled) { - options.bsEnabled = isEnabled; + return $timepicker; + } + timepickerFactory.defaults = defaults; + return timepickerFactory; + } ]; + }).directive('bsTimepicker', [ '$window', '$parse', '$q', '$dateFormatter', '$dateParser', '$timepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) { + var defaults = $timepicker.defaults; + var isNative = /(ip(a|o)d|iphone|android)/gi.test($window.navigator.userAgent); + return { + restrict: 'EAC', + require: 'ngModel', + link: function postLink(scope, element, attr, controller) { + var options = { + scope: scope }; - $tooltip.setViewport = function(viewport) { - options.viewport = viewport; + angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'autoclose', 'timeType', 'timeFormat', 'timezone', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'secondStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown', 'roundDisplay', 'id', 'prefixClass', 'prefixEvent' ], function(key) { + if (angular.isDefined(attr[key])) options[key] = attr[key]; + }); + var falseValueRegExp = /^(false|0|)$/i; + angular.forEach([ 'html', 'container', 'autoclose', 'useNative', 'roundDisplay' ], function(key) { + if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false; + }); + 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(); + }); + 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, timezone) { + return $dateFormatter.formatDate(date, format, lang, timezone); }; - $tooltip.$applyPlacement = function() { - if (!tipElement) return; - var placement = options.placement, autoToken = /\s?auto?\s?/i, autoPlace = autoToken.test(placement); - if (autoPlace) { - placement = placement.replace(autoToken, '') || defaults.placement; + var dateParser = $dateParser({ + format: options.timeFormat, + lang: lang + }); + angular.forEach([ 'minTime', 'maxTime' ], function(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); + }); + }); + scope.$watch(attr.ngModel, function(newValue, oldValue) { + 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); + if (!isValid) { + return; } - tipElement.addClass(options.placement); - var elementPosition = getPosition(), tipWidth = tipElement.prop('offsetWidth'), tipHeight = tipElement.prop('offsetHeight'); - if (autoPlace) { - var originalPlacement = placement; - var container = options.container ? findElement(options.container) : element.parent(); - var containerPosition = getPosition(container); - 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'); - } - 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); + controller.$dateValue = parsedTime; + } + controller.$parsers.unshift(function(viewValue) { + var date; + if (!viewValue) { + controller.$setValidity('date', true); + return null; } - var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight); - applyPlacement(tipPosition, placement); - }; - $tooltip.$onKeyUp = function(evt) { - if (evt.which === 27 && $tooltip.$isShown) { - $tooltip.hide(); - evt.stopPropagation(); + var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue); + if (!parsedTime || isNaN(parsedTime.getTime())) { + controller.$setValidity('date', false); + return undefined; + } else { + validateAgainstMinMaxTime(parsedTime); } - }; - $tooltip.$onFocusKeyUp = function(evt) { - if (evt.which === 27) { - element[0].blur(); - evt.stopPropagation(); + if (options.timeType === 'string') { + date = dateParser.timezoneOffsetAdjust(parsedTime, options.timezone, true); + return formatDate(date, options.modelTimeFormat || options.timeFormat); } + date = dateParser.timezoneOffsetAdjust(controller.$dateValue, options.timezone, true); + if (options.timeType === 'number') { + return date.getTime(); + } else if (options.timeType === 'unix') { + return date.getTime() / 1e3; + } else if (options.timeType === 'iso') { + return date.toISOString(); + } else { + return new Date(date); + } + }); + controller.$formatters.push(function(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 * 1e3); + } else { + date = new Date(modelValue); + } + controller.$dateValue = dateParser.timezoneOffsetAdjust(date, options.timezone); + return getTimeFormattedString(); + }); + controller.$render = function() { + element.val(getTimeFormattedString()); }; - $tooltip.$onFocusElementMouseDown = function(evt) { - evt.preventDefault(); - evt.stopPropagation(); - $tooltip.$isShown ? element[0].blur() : element[0].focus(); - }; - 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 getTimeFormattedString() { + return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat); } - 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); - } - } + scope.$on('$destroy', function() { + if (timepicker) timepicker.destroy(); + options = null; + timepicker = null; + }); + } + }; + } ]); + angular.module('mgcrea.ngStrap.tab', []).provider('$tab', function() { + var defaults = this.defaults = { + animation: 'am-fade', + template: 'tab/tab.tpl.html', + navClass: 'nav-tabs', + activeClass: 'active' + }; + var controller = this.controller = function($scope, $element, $attrs) { + var self = this; + self.$options = angular.copy(defaults); + angular.forEach([ 'animation', 'navClass', 'activeClass' ], function(key) { + if (angular.isDefined($attrs[key])) self.$options[key] = $attrs[key]; + }); + $scope.$navClass = self.$options.navClass; + $scope.$activeClass = self.$options.activeClass; + self.$panes = $scope.$panes = []; + self.$activePaneChangeListeners = self.$viewChangeListeners = []; + self.$push = function(pane) { + if (angular.isUndefined(self.$panes.$active)) { + $scope.$setActive(pane.name || 0); } - function bindKeyboardEvents() { - if (options.trigger !== 'focus') { - tipElement.on('keyup', $tooltip.$onKeyUp); - } else { - element.on('keyup', $tooltip.$onFocusKeyUp); - } + self.$panes.push(pane); + }; + self.$remove = function(pane) { + var index = self.$panes.indexOf(pane); + var active = self.$panes.$active; + var activeIndex; + if (angular.isString(active)) { + activeIndex = self.$panes.map(function(pane) { + return pane.name; + }).indexOf(active); + } else { + activeIndex = self.$panes.$active; } - function unbindKeyboardEvents() { - if (options.trigger !== 'focus') { - tipElement.off('keyup', $tooltip.$onKeyUp); - } else { - element.off('keyup', $tooltip.$onFocusKeyUp); - } + self.$panes.splice(index, 1); + if (index < activeIndex) { + activeIndex--; + } else if (index === activeIndex && activeIndex === self.$panes.length) { + activeIndex--; } - var _autoCloseEventsBinded = false; - function bindAutoCloseEvents() { - $timeout(function() { - tipElement.on('click', stopEventPropagation); - $body.on('click', $tooltip.hide); - _autoCloseEventsBinded = true; - }, 0, false); + if (activeIndex >= 0 && activeIndex < self.$panes.length) { + self.$setActive(self.$panes[activeIndex].name || activeIndex); + } else { + self.$setActive(); } - function unbindAutoCloseEvents() { - if (_autoCloseEventsBinded) { - tipElement.off('click', stopEventPropagation); - $body.off('click', $tooltip.hide); - _autoCloseEventsBinded = false; - } + }; + self.$setActive = $scope.$setActive = function(value) { + self.$panes.$active = value; + self.$activePaneChangeListeners.forEach(function(fn) { + fn(); + }); + }; + self.$isActive = $scope.$isActive = function($pane, $index) { + return self.$panes.$active === $pane.name || self.$panes.$active === $index; + }; + }; + this.$get = function() { + var $tab = {}; + $tab.defaults = defaults; + $tab.controller = controller; + return $tab; + }; + }).directive('bsTabs', [ '$window', '$animate', '$tab', '$parse', function($window, $animate, $tab, $parse) { + var defaults = $tab.defaults; + return { + require: [ '?ngModel', 'bsTabs' ], + transclude: true, + scope: true, + controller: [ '$scope', '$element', '$attrs', $tab.controller ], + templateUrl: function(element, attr) { + return attr.template || defaults.template; + }, + link: function postLink(scope, element, attrs, controllers) { + var ngModelCtrl = controllers[0]; + var bsTabsCtrl = controllers[1]; + if (ngModelCtrl) { + bsTabsCtrl.$activePaneChangeListeners.push(function() { + ngModelCtrl.$setViewValue(bsTabsCtrl.$panes.$active); + }); + ngModelCtrl.$formatters.push(function(modelValue) { + bsTabsCtrl.$setActive(modelValue); + return modelValue; + }); } - function stopEventPropagation(event) { - event.stopPropagation(); + if (attrs.bsActivePane) { + var parsedBsActivePane = $parse(attrs.bsActivePane); + bsTabsCtrl.$activePaneChangeListeners.push(function() { + parsedBsActivePane.assign(scope, bsTabsCtrl.$panes.$active); + }); + scope.$watch(attrs.bsActivePane, function(newValue, oldValue) { + bsTabsCtrl.$setActive(newValue); + }, true); } - function getPosition($element) { - $element = $element || (options.target || element); - var el = $element[0], isBody = el.tagName === 'BODY'; - var elRect = el.getBoundingClientRect(); - var rect = {}; - for (var p in elRect) { - rect[p] = elRect[p]; - } - if (rect.width === null) { - rect = angular.extend({}, rect, { - width: elRect.right - elRect.left, - height: elRect.bottom - elRect.top - }); - } - var elOffset = isBody ? { - top: 0, - left: 0 - } : dimensions.offset(el), scroll = { - scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.prop('scrollTop') || 0 - }, outerDims = isBody ? { - width: document.documentElement.clientWidth, - height: $window.innerHeight - } : null; - return angular.extend({}, rect, scroll, outerDims, elOffset); + } + }; + } ]).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]; + element.addClass('tab-pane'); + attrs.$observe('title', function(newValue, oldValue) { + scope.title = $sce.trustAsHtml(newValue); + }); + scope.name = attrs.name; + if (bsTabsCtrl.$options.animation) { + element.addClass(bsTabsCtrl.$options.animation); } - 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; - } - 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; - } - } - return offset; + attrs.$observe('disabled', function(newValue, oldValue) { + scope.disabled = scope.$eval(newValue); + }); + bsTabsCtrl.$push(scope); + scope.$on('$destroy', function() { + bsTabsCtrl.$remove(scope); + }); + function render() { + var index = bsTabsCtrl.$panes.indexOf(scope); + $animate[bsTabsCtrl.$isActive(scope, index) ? 'addClass' : 'removeClass'](element, bsTabsCtrl.$options.activeClass); } - function applyPlacement(offset, placement) { - var tip = tipElement[0], width = tip.offsetWidth, height = tip.offsetHeight; - var marginTop = parseInt(dimensions.css(tip, 'margin-top'), 10), marginLeft = parseInt(dimensions.css(tip, 'margin-left'), 10); - if (isNaN(marginTop)) marginTop = 0; - if (isNaN(marginLeft)) marginLeft = 0; - offset.top = offset.top + marginTop; - offset.left = offset.left + marginLeft; - dimensions.setOffset(tip, angular.extend({ - using: function(props) { - tipElement.css({ - top: Math.round(props.top) + 'px', - left: Math.round(props.left) + 'px', - right: '' - }); - } - }, offset), 0); - var actualWidth = tip.offsetWidth, actualHeight = tip.offsetHeight; - if (placement === 'top' && actualHeight !== height) { - offset.top = offset.top + height - actualHeight; - } - if (/top-left|top-right|bottom-left|bottom-right/.test(placement)) return; - var delta = getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight); - if (delta.left) { - offset.left += delta.left; - } else { - offset.top += delta.top; + bsTabsCtrl.$activePaneChangeListeners.push(function() { + render(); + }); + render(); + } + }; + } ]); + angular.module('mgcrea.ngStrap.typeahead', [ 'mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions' ]).provider('$typeahead', function() { + var defaults = this.defaults = { + animation: 'am-fade', + prefixClass: 'typeahead', + prefixEvent: '$typeahead', + placement: 'bottom-left', + templateUrl: 'typeahead/typeahead.tpl.html', + trigger: 'focus', + container: false, + keyboard: true, + html: false, + delay: 0, + minLength: 1, + filter: 'bsAsyncFilter', + limit: 6, + autoSelect: false, + comparator: '', + trimValue: true + }; + this.$get = [ '$window', '$rootScope', '$tooltip', '$$rAF', '$timeout', function($window, $rootScope, $tooltip, $$rAF, $timeout) { + var bodyEl = angular.element($window.document.body); + function TypeaheadFactory(element, controller, config) { + var $typeahead = {}; + var options = angular.extend({}, defaults, config); + $typeahead = $tooltip(element, options); + var parentScope = config.scope; + var scope = $typeahead.$scope; + scope.$resetMatches = function() { + scope.$matches = []; + scope.$activeIndex = options.autoSelect ? 0 : -1; + }; + scope.$resetMatches(); + scope.$activate = function(index) { + scope.$$postDigest(function() { + $typeahead.activate(index); + }); + }; + scope.$select = function(index, evt) { + scope.$$postDigest(function() { + $typeahead.select(index); + }); + }; + scope.$isVisible = function() { + return $typeahead.$isVisible(); + }; + $typeahead.update = function(matches) { + scope.$matches = matches; + if (scope.$activeIndex >= matches.length) { + scope.$activeIndex = options.autoSelect ? 0 : -1; } - dimensions.setOffset(tip, offset); - if (/top|right|bottom|left/.test(placement)) { - var isVertical = /top|bottom/.test(placement), arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight, arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'; - replaceArrow(arrowDelta, tip[arrowOffsetPosition], isVertical); + safeDigest(scope); + $$rAF($typeahead.$applyPlacement); + }; + $typeahead.activate = function(index) { + scope.$activeIndex = index; + }; + $typeahead.select = function(index) { + if (index === -1) return; + var value = scope.$matches[index].value; + controller.$setViewValue(value); + controller.$render(); + scope.$resetMatches(); + if (parentScope) parentScope.$digest(); + scope.$emit(options.prefixEvent + '.select', value, index, $typeahead); + }; + $typeahead.$isVisible = function() { + if (!options.minLength || !controller) { + return !!scope.$matches.length; } - } - function getViewportAdjustedDelta(placement, position, actualWidth, actualHeight) { - var delta = { - top: 0, - left: 0 - }, $viewport = options.viewport && findElement(options.viewport.selector || options.viewport); - if (!$viewport) { - return delta; + return scope.$matches.length && angular.isString(controller.$viewValue) && controller.$viewValue.length >= options.minLength; + }; + $typeahead.$getIndex = function(value) { + var l = scope.$matches.length, i = l; + if (!l) return; + for (i = l; i--; ) { + if (scope.$matches[i].value === value) break; } - var viewportPadding = options.viewport && options.viewport.padding || 0, viewportDimensions = getPosition($viewport); - if (/right|left/.test(placement)) { - var topEdgeOffset = position.top - viewportPadding - viewportDimensions.scroll, bottomEdgeOffset = position.top + viewportPadding - viewportDimensions.scroll + actualHeight; - if (topEdgeOffset < viewportDimensions.top) { - delta.top = viewportDimensions.top - topEdgeOffset; - } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { - delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset; - } - } else { - var leftEdgeOffset = position.left - viewportPadding, rightEdgeOffset = position.left + viewportPadding + actualWidth; - if (leftEdgeOffset < viewportDimensions.left) { - delta.left = viewportDimensions.left - leftEdgeOffset; - } else if (rightEdgeOffset > viewportDimensions.width) { - delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset; - } + if (i < 0) return; + return i; + }; + $typeahead.$onMouseDown = function(evt) { + evt.preventDefault(); + evt.stopPropagation(); + }; + $typeahead.$onKeyDown = function(evt) { + if (!/(38|40|13)/.test(evt.keyCode)) return; + if ($typeahead.$isVisible() && !(evt.keyCode === 13 && scope.$activeIndex === -1)) { + evt.preventDefault(); + evt.stopPropagation(); } - return delta; - } - function replaceArrow(delta, dimension, isHorizontal) { - var $arrow = findElement('.tooltip-arrow, .arrow', tipElement[0]); - $arrow.css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%').css(isHorizontal ? 'top' : 'left', ''); - } - function destroyTipElement() { - clearTimeout(timeout); - if ($tooltip.$isShown && tipElement !== null) { - if (options.autoClose) { - unbindAutoCloseEvents(); - } + if (evt.keyCode === 13 && scope.$matches.length) { + $typeahead.select(scope.$activeIndex); + } else if (evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--; else if (evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++; else if (angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0; + scope.$digest(); + }; + var show = $typeahead.show; + $typeahead.show = function() { + show(); + $timeout(function() { + $typeahead.$element && $typeahead.$element.on('mousedown', $typeahead.$onMouseDown); if (options.keyboard) { - unbindKeyboardEvents(); + element && element.on('keydown', $typeahead.$onKeyDown); } + }, 0, false); + }; + var hide = $typeahead.hide; + $typeahead.hide = function() { + $typeahead.$element && $typeahead.$element.off('mousedown', $typeahead.$onMouseDown); + if (options.keyboard) { + element && element.off('keydown', $typeahead.$onKeyDown); } - if (tipScope) { - tipScope.$destroy(); - tipScope = null; - } - if (tipElement) { - tipElement.remove(); - tipElement = $tooltip.$element = null; - } - } - return $tooltip; + if (!options.autoSelect) $typeahead.activate(-1); + hide(); + }; + return $typeahead; } 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] = $http.get(template, { - cache: $templateCache - }).then(function(res) { - return res.data; + TypeaheadFactory.defaults = defaults; + return TypeaheadFactory; + } ]; + }).filter('bsAsyncFilter', [ '$filter', function($filter) { + return function(array, expression, comparator) { + if (array && angular.isFunction(array.then)) { + return array.then(function(results) { + return $filter('filter')(results, expression, comparator); }); + } else { + return $filter('filter')(array, expression, comparator); } - return TooltipFactory; - } ]; - }).directive('bsTooltip', [ '$window', '$location', '$sce', '$tooltip', '$$rAF', function($window, $location, $sce, $tooltip, $$rAF) { + }; + } ]).directive('bsTypeahead', [ '$window', '$parse', '$q', '$typeahead', '$parseOptions', function($window, $parse, $q, $typeahead, $parseOptions) { + var defaults = $typeahead.defaults; return { restrict: 'EAC', - scope: true, - link: function postLink(scope, element, attr, transclusion) { + require: 'ngModel', + link: function postLink(scope, element, attr, controller) { var options = { scope: scope }; - angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'backdropAnimation', 'type', 'customClass', 'id' ], function(key) { + angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'filter', 'limit', 'minLength', 'watchOptions', 'selectMode', 'autoSelect', 'comparator', 'id', 'prefixEvent', 'prefixClass' ], function(key) { if (angular.isDefined(attr[key])) options[key] = attr[key]; }); var falseValueRegExp = /^(false|0|)$/i; - angular.forEach([ 'html', 'container' ], function(key) { + angular.forEach([ 'html', 'container', 'trimValue' ], function(key) { if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false; }); - var dataTarget = element.attr('data-target'); - if (angular.isDefined(dataTarget)) { - if (falseValueRegExp.test(dataTarget)) options.target = false; else options.target = dataTarget; - } - if (!scope.hasOwnProperty('title')) { - scope.title = ''; - } - 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(); + element.attr('autocomplete', 'false'); + var filter = options.filter || defaults.filter; + var limit = options.limit || defaults.limit; + var comparator = options.comparator || defaults.comparator; + var bsOptions = attr.bsOptions; + if (filter) bsOptions += ' | ' + filter + ':$viewValue'; + if (comparator) bsOptions += ':' + comparator; + if (limit) bsOptions += ' | limitTo:' + limit; + var parsedOptions = $parseOptions(bsOptions); + var typeahead = $typeahead(element, controller, options); + if (options.watchOptions) { + var watchedOptions = parsedOptions.$match[7].replace(/\|.+/, '').replace(/\(.*\)/g, '').trim(); + scope.$watchCollection(watchedOptions, function(newValue, oldValue) { + parsedOptions.valuesFn(scope, controller).then(function(values) { + typeahead.update(values); + controller.$render(); }); - } - }); - 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); - 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(); - }); - attr.bsEnabled && scope.$watch(attr.bsEnabled, function(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); + } + scope.$watch(attr.ngModel, function(newValue, oldValue) { + scope.$modelValue = newValue; + parsedOptions.valuesFn(scope, controller).then(function(values) { + if (options.selectMode && !values.length && newValue.length > 0) { + controller.$setViewValue(controller.$viewValue.substring(0, controller.$viewValue.length - 1)); + return; + } + if (values.length > limit) values = values.slice(0, limit); + var isVisible = typeahead.$isVisible(); + isVisible && typeahead.update(values); + if (values.length === 1 && values[0].value === newValue) return; + !isVisible && typeahead.update(values); + controller.$render(); + }); }); - attr.viewport && scope.$watch(attr.viewport, function(newValue) { - if (!tooltip || !angular.isDefined(newValue)) return; - tooltip.setViewport(newValue); + controller.$formatters.push(function(modelValue) { + var displayValue = parsedOptions.displayValue(modelValue); + if (displayValue) { + return displayValue; + } + if (modelValue && typeof modelValue !== 'object') { + return modelValue; + } + return ''; }); - var tooltip = $tooltip(element, options); + controller.$render = function() { + if (controller.$isEmpty(controller.$viewValue)) { + return element.val(''); + } + var index = typeahead.$getIndex(controller.$modelValue); + var selected = angular.isDefined(index) ? typeahead.$scope.$matches[index].label : controller.$viewValue; + selected = angular.isObject(selected) ? parsedOptions.displayValue(selected) : selected; + var value = selected ? selected.toString().replace(/<(?:.|\n)*?>/gm, '') : ''; + element.val(options.trimValue === false ? value : value.trim()); + }; scope.$on('$destroy', function() { - if (tooltip) tooltip.destroy(); + if (typeahead) typeahead.destroy(); options = null; - tooltip = null; + typeahead = null; }); } }; } ]); - angular.module('mgcrea.ngStrap.timepicker', [ 'mgcrea.ngStrap.helpers.dateParser', 'mgcrea.ngStrap.helpers.dateFormatter', 'mgcrea.ngStrap.tooltip' ]).provider('$timepicker', function() { + angular.module('mgcrea.ngStrap.tooltip', [ 'mgcrea.ngStrap.core', 'mgcrea.ngStrap.helpers.dimensions' ]).provider('$tooltip', function() { var defaults = this.defaults = { animation: 'am-fade', - prefixClass: 'timepicker', - placement: 'bottom-left', - templateUrl: 'timepicker/timepicker.tpl.html', - trigger: 'focus', + customClass: '', + prefixClass: 'tooltip', + prefixEvent: 'tooltip', container: false, - keyboard: true, + target: false, + placement: 'top', + templateUrl: 'tooltip/tooltip.tpl.html', + template: '', + contentTemplate: false, + trigger: 'hover focus', + keyboard: false, html: false, + show: false, + title: '', + type: '', delay: 0, - useNative: true, - timeType: 'date', - timeFormat: 'shortTime', - timezone: null, - modelTimeFormat: null, - autoclose: false, - minTime: -Infinity, - maxTime: +Infinity, - length: 5, - hourStep: 1, - minuteStep: 5, - secondStep: 5, - roundDisplay: false, - iconUp: 'glyphicon glyphicon-chevron-up', - iconDown: 'glyphicon glyphicon-chevron-down', - arrowBehavior: 'pager' + autoClose: false, + bsEnabled: true, + viewport: { + selector: 'body', + padding: 0 + } }; - 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)/gi.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, timezone) { - return $dateFormatter.formatDate(date, format, lang, timezone); - }; - function floorMinutes(time) { - var coeff = 1e3 * 60 * options.minuteStep; - return new Date(Math.floor(time.getTime() / coeff) * coeff); + this.$get = [ '$window', '$rootScope', '$bsCompiler', '$q', '$templateCache', '$http', '$animate', '$sce', 'dimensions', '$$rAF', '$timeout', function($window, $rootScope, $bsCompiler, $q, $templateCache, $http, $animate, $sce, dimensions, $$rAF, $timeout) { + var trim = String.prototype.trim; + var isTouch = 'createTouch' in $window.document; + var htmlReplaceRegExp = /ng-bind="/gi; + var $body = angular.element($window.document); + function TooltipFactory(element, config) { + var $tooltip = {}; + var options = $tooltip.$options = angular.extend({}, defaults, config); + var promise = $tooltip.$promise = $bsCompiler.compile(options); + var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new(); + var nodeName = element[0].nodeName.toLowerCase(); + 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]; } - var selectedIndex = 0; - var defaultDate = options.roundDisplay ? floorMinutes(new Date()) : new Date(); - var startDate = controller.$dateValue || defaultDate; - 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); - var hoursFormat = $dateFormatter.hoursFormat(format), timeSeparator = $dateFormatter.timeSeparator(format), minutesFormat = $dateFormatter.minutesFormat(format), secondsFormat = $dateFormatter.secondsFormat(format), showSeconds = $dateFormatter.showSeconds(format), showAM = $dateFormatter.showAM(format); - scope.$iconUp = options.iconUp; - scope.$iconDown = options.iconDown; - scope.$select = function(date, index) { - $timepicker.select(date, index); + $tooltip.$id = options.id || element.attr('id') || ''; + if (options.title) { + scope.title = $sce.trustAsHtml(options.title); + } + scope.$setEnabled = function(isEnabled) { + scope.$$postDigest(function() { + $tooltip.setEnabled(isEnabled); + }); }; - scope.$moveIndex = function(value, index) { - $timepicker.$moveIndex(value, index); + scope.$hide = function() { + scope.$$postDigest(function() { + $tooltip.hide(); + }); }; - scope.$switchMeridian = function(date) { - $timepicker.switchMeridian(date); + scope.$show = function() { + scope.$$postDigest(function() { + $tooltip.show(); + }); }; - $timepicker.update = function(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(); - } + scope.$toggle = function() { + scope.$$postDigest(function() { + $tooltip.toggle(); + }); }; - $timepicker.select = function(date, index, keep) { - 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()); else if (index === 2) controller.$dateValue.setSeconds(date.getSeconds()); - controller.$setViewValue(angular.copy(controller.$dateValue)); - controller.$render(); - if (options.autoclose && !keep) { - $timeout(function() { - $timepicker.hide(true); - }); + $tooltip.$isShown = scope.$isShown = false; + var timeout, hoverState; + var compileData, tipElement, tipContainer, tipScope; + promise.then(function(data) { + compileData = data; + $tooltip.init(); + }); + $tooltip.init = function() { + if (options.delay && angular.isNumber(options.delay)) { + options.delay = { + show: options.delay, + hide: options.delay + }; } - }; - $timepicker.switchMeridian = function(date) { - if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) { - return; + if (options.container === 'self') { + tipContainer = element; + } else if (angular.isElement(options.container)) { + tipContainer = options.container; + } else if (options.container) { + tipContainer = findElement(options.container); } - var hours = (date || controller.$dateValue).getHours(); - controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12); - controller.$setViewValue(angular.copy(controller.$dateValue)); - controller.$render(); - }; - $timepicker.$build = function() { - 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) - }); + bindTriggerEvents(); + if (options.target) { + options.target = angular.isElement(options.target) ? options.target : findElement(options.target); } - 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) + if (options.show) { + scope.$$postDigest(function() { + options.trigger === 'focus' ? element[0].focus() : $tooltip.show(); }); } - var seconds = [], second; - for (i = 0; i < options.length; i++) { - second = new Date(1970, 0, 1, 0, 0, viewDate.second - (midIndex - i) * options.secondStep); - seconds.push({ - date: second, - label: formatDate(second, secondsFormat), - selected: $timepicker.$date && $timepicker.$isSelected(second, 2), - disabled: $timepicker.$isDisabled(second, 2) - }); + }; + $tooltip.destroy = function() { + unbindTriggerEvents(); + destroyTipElement(); + scope.$destroy(); + }; + $tooltip.enter = function() { + clearTimeout(timeout); + hoverState = 'in'; + if (!options.delay || !options.delay.show) { + return $tooltip.show(); } - var rows = []; - for (i = 0; i < options.length; i++) { - if (showSeconds) { - rows.push([ hours[i], minutes[i], seconds[i] ]); + timeout = setTimeout(function() { + if (hoverState === 'in') $tooltip.show(); + }, options.delay.show); + }; + $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 { - rows.push([ hours[i], minutes[i] ]); + after = null; + } + } else { + parent = null; + after = element; + } + if (tipElement) destroyTipElement(); + tipScope = $tooltip.$scope.$new(); + tipElement = $tooltip.$element = compileData.link(tipScope, function(clonedElement, scope) {}); + tipElement.css({ + top: '-9999px', + left: '-9999px', + right: 'auto', + display: 'block', + visibility: 'hidden' + }); + if (options.animation) tipElement.addClass(options.animation); + if (options.type) tipElement.addClass(options.prefixClass + '-' + options.type); + if (options.customClass) tipElement.addClass(options.customClass); + after ? after.after(tipElement) : parent.prepend(tipElement); + $tooltip.$isShown = scope.$isShown = true; + safeDigest(scope); + $tooltip.$applyPlacement(); + if (angular.version.minor <= 2) { + $animate.enter(tipElement, parent, after, enterAnimateCallback); + } else { + $animate.enter(tipElement, parent, after).then(enterAnimateCallback); + } + safeDigest(scope); + $$rAF(function() { + if (tipElement) tipElement.css({ + visibility: 'visible' + }); + }); + if (options.keyboard) { + if (options.trigger !== 'focus') { + $tooltip.focus(); } + bindKeyboardEvents(); } - scope.rows = rows; - scope.showSeconds = showSeconds; - scope.showAM = showAM; - scope.isAM = ($timepicker.$date || hours[midIndex].date).getHours() < 12; - scope.timeSeparator = timeSeparator; - $timepicker.$isBuilt = true; - }; - $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(); - } else if (index === 2) { - return date.getSeconds() === $timepicker.$date.getSeconds(); + if (options.autoClose) { + bindAutoCloseEvents(); } }; - $timepicker.$isDisabled = function(date, index) { - var selectedTime; - if (index === 0) { - selectedTime = date.getTime() + viewDate.minute * 6e4 + viewDate.second * 1e3; - } else if (index === 1) { - selectedTime = date.getTime() + viewDate.hour * 36e5 + viewDate.second * 1e3; - } else if (index === 2) { - selectedTime = date.getTime() + viewDate.hour * 36e5 + viewDate.minute * 6e4; + function enterAnimateCallback() { + scope.$emit(options.prefixEvent + '.show', $tooltip); + } + $tooltip.leave = function() { + clearTimeout(timeout); + hoverState = 'out'; + if (!options.delay || !options.delay.hide) { + return $tooltip.hide(); } - return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1; + timeout = setTimeout(function() { + if (hoverState === 'out') { + $tooltip.hide(); + } + }, options.delay.hide); }; - scope.$arrowAction = function(value, index) { - if (options.arrowBehavior === 'picker') { - $timepicker.$setTimeByStep(value, index); + var _blur; + var _tipToHide; + $tooltip.hide = function(blur) { + if (!$tooltip.$isShown) return; + scope.$emit(options.prefixEvent + '.hide.before', $tooltip); + _blur = blur; + _tipToHide = tipElement; + if (angular.version.minor <= 2) { + $animate.leave(tipElement, leaveAnimateCallback); } else { - $timepicker.$moveIndex(value, index); + $animate.leave(tipElement).then(leaveAnimateCallback); } - }; - $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; - var seconds = newDate.getSeconds(), secondsLength = formatDate(newDate, secondsFormat).length; - if (index === 0) { - newDate.setHours(hours - parseInt(options.hourStep, 10) * value); - } else if (index === 1) { - newDate.setMinutes(minutes - parseInt(options.minuteStep, 10) * value); - } else if (index === 2) { - newDate.setSeconds(seconds - parseInt(options.secondStep, 10) * value); + $tooltip.$isShown = scope.$isShown = false; + safeDigest(scope); + if (options.keyboard && tipElement !== null) { + unbindKeyboardEvents(); } - $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, viewDate.second); - 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, viewDate.second); - angular.extend(viewDate, { - minute: targetDate.getMinutes() - }); - } else if (index === 2) { - targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute, viewDate.second + value * options.length * options.secondStep); - angular.extend(viewDate, { - second: targetDate.getSeconds() - }); + if (options.autoClose && tipElement !== null) { + unbindAutoCloseEvents(); } - $timepicker.$build(); }; - $timepicker.$onMouseDown = function(evt) { - if (evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault(); - evt.stopPropagation(); - if (isTouch) { - var targetEl = angular.element(evt.target); - if (targetEl[0].nodeName.toLowerCase() !== 'button') { - targetEl = targetEl.parent(); + function leaveAnimateCallback() { + scope.$emit(options.prefixEvent + '.hide', $tooltip); + if (tipElement === _tipToHide) { + if (_blur && options.trigger === 'focus') { + return element[0].blur(); } - targetEl.triggerHandler('click'); + destroyTipElement(); } + } + $tooltip.toggle = function() { + $tooltip.$isShown ? $tooltip.leave() : $tooltip.enter(); }; - $timepicker.$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) return $timepicker.hide(true); - 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 seconds = newDate.getSeconds(), secondsLength = formatDate(newDate, secondsFormat).length; - var sepLength = 1; - var lateralMove = /(37|39)/.test(evt.keyCode); - var count = 2 + showSeconds * 1 + showAM * 1; - 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 selectRange = [ 0, hoursLength ]; - var incr = 0; - if (evt.keyCode === 38) incr = -1; - if (evt.keyCode === 40) incr = +1; - var isSeconds = selectedIndex === 2 && showSeconds; - var isMeridian = selectedIndex === 2 && !showSeconds || selectedIndex === 3 && showSeconds; - if (selectedIndex === 0) { - newDate.setHours(hours + incr * parseInt(options.hourStep, 10)); - hoursLength = formatDate(newDate, hoursFormat).length; - selectRange = [ 0, hoursLength ]; - } else if (selectedIndex === 1) { - newDate.setMinutes(minutes + incr * parseInt(options.minuteStep, 10)); - minutesLength = formatDate(newDate, minutesFormat).length; - selectRange = [ hoursLength + sepLength, minutesLength ]; - } else if (isSeconds) { - newDate.setSeconds(seconds + incr * parseInt(options.secondStep, 10)); - secondsLength = formatDate(newDate, secondsFormat).length; - selectRange = [ hoursLength + sepLength + minutesLength + sepLength, secondsLength ]; - } else if (isMeridian) { - if (!lateralMove) $timepicker.switchMeridian(); - selectRange = [ hoursLength + sepLength + minutesLength + sepLength + (secondsLength + sepLength) * showSeconds, 2 ]; - } - $timepicker.select(newDate, selectedIndex, true); - createSelection(selectRange[0], selectRange[1]); - parentScope.$digest(); + $tooltip.focus = function() { + tipElement[0].focus(); }; - function createSelection(start, length) { - var end = start + length; - 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 focusElement() { - element[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(); + $tooltip.setViewport = function(viewport) { + options.viewport = viewport; }; - var _show = $timepicker.show; - $timepicker.show = function() { - _show(); - $timeout(function() { - $timepicker.$element && $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown); - if (options.keyboard) { - element && element.on('keydown', $timepicker.$onKeyDown); + $tooltip.$applyPlacement = function() { + if (!tipElement) return; + var placement = options.placement, autoToken = /\s?auto?\s?/i, autoPlace = autoToken.test(placement); + if (autoPlace) { + placement = placement.replace(autoToken, '') || defaults.placement; + } + tipElement.addClass(options.placement); + var elementPosition = getPosition(), tipWidth = tipElement.prop('offsetWidth'), tipHeight = tipElement.prop('offsetHeight'); + $tooltip.$viewport = options.viewport && findElement(options.viewport.selector || options.viewport); + if (autoPlace) { + var originalPlacement = placement; + var viewportPosition = getPosition($tooltip.$viewport); + if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > viewportPosition.bottom) { + placement = originalPlacement.replace('bottom', 'top'); + } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < viewportPosition.top) { + placement = originalPlacement.replace('top', 'bottom'); } - }, 0, false); + if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') && elementPosition.right + tipWidth > viewportPosition.width) { + placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right'); + } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') && elementPosition.left - tipWidth < viewportPosition.left) { + placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left'); + } + tipElement.removeClass(originalPlacement).addClass(placement); + } + var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight); + applyPlacement(tipPosition, placement); }; - var _hide = $timepicker.hide; - $timepicker.hide = function(blur) { - if (!$timepicker.$isShown) return; - $timepicker.$element && $timepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown); - if (options.keyboard) { - element && element.off('keydown', $timepicker.$onKeyDown); + $tooltip.$onKeyUp = function(evt) { + if (evt.which === 27 && $tooltip.$isShown) { + $tooltip.hide(); + evt.stopPropagation(); } - _hide(blur); }; - return $timepicker; - } - timepickerFactory.defaults = defaults; - return timepickerFactory; - } ]; - }).directive('bsTimepicker', [ '$window', '$parse', '$q', '$dateFormatter', '$dateParser', '$timepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) { - var defaults = $timepicker.defaults; - var isNative = /(ip(a|o)d|iphone|android)/gi.test($window.navigator.userAgent); - var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout; - return { - restrict: 'EAC', - require: 'ngModel', - link: function postLink(scope, element, attr, controller) { - var options = { - scope: scope + $tooltip.$onFocusKeyUp = function(evt) { + if (evt.which === 27) { + element[0].blur(); + evt.stopPropagation(); + } }; - angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'autoclose', 'timeType', 'timeFormat', 'timezone', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'secondStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown', 'roundDisplay', 'id', 'prefixClass', 'prefixEvent' ], function(key) { - if (angular.isDefined(attr[key])) options[key] = attr[key]; - }); - var falseValueRegExp = /^(false|0|)$/i; - angular.forEach([ 'html', 'container', 'autoclose', 'useNative', 'roundDisplay' ], function(key) { - if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false; - }); - 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(); - }); - 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, timezone) { - return $dateFormatter.formatDate(date, format, lang, timezone); + $tooltip.$onFocusElementMouseDown = function(evt) { + evt.preventDefault(); + evt.stopPropagation(); + $tooltip.$isShown ? element[0].blur() : element[0].focus(); }; - var dateParser = $dateParser({ - format: options.timeFormat, - lang: lang - }); - angular.forEach([ 'minTime', 'maxTime' ], function(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 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); + } }); - }); - scope.$watch(attr.ngModel, function(newValue, oldValue) { - 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); - if (!isValid) { - return; + } + 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); + } } - controller.$dateValue = parsedTime; } - controller.$parsers.unshift(function(viewValue) { - var date; - if (!viewValue) { - controller.$setValidity('date', true); - return null; + function bindKeyboardEvents() { + if (options.trigger !== 'focus') { + tipElement.on('keyup', $tooltip.$onKeyUp); + } else { + element.on('keyup', $tooltip.$onFocusKeyUp); } - var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue); - if (!parsedTime || isNaN(parsedTime.getTime())) { - controller.$setValidity('date', false); - return; + } + function unbindKeyboardEvents() { + if (options.trigger !== 'focus') { + tipElement.off('keyup', $tooltip.$onKeyUp); } else { - validateAgainstMinMaxTime(parsedTime); + element.off('keyup', $tooltip.$onFocusKeyUp); } - if (options.timeType === 'string') { - date = dateParser.timezoneOffsetAdjust(parsedTime, options.timezone, true); - return formatDate(date, options.modelTimeFormat || options.timeFormat); + } + var _autoCloseEventsBinded = false; + function bindAutoCloseEvents() { + $timeout(function() { + tipElement.on('click', stopEventPropagation); + $body.on('click', $tooltip.hide); + _autoCloseEventsBinded = true; + }, 0, false); + } + function unbindAutoCloseEvents() { + if (_autoCloseEventsBinded) { + tipElement.off('click', stopEventPropagation); + $body.off('click', $tooltip.hide); + _autoCloseEventsBinded = false; } - date = dateParser.timezoneOffsetAdjust(controller.$dateValue, options.timezone, true); - if (options.timeType === 'number') { - return date.getTime(); - } else if (options.timeType === 'unix') { - return date.getTime() / 1e3; - } else if (options.timeType === 'iso') { - return date.toISOString(); - } else { - return new Date(date); + } + function stopEventPropagation(event) { + event.stopPropagation(); + } + function getPosition($element) { + $element = $element || (options.target || element); + var el = $element[0], isBody = el.tagName === 'BODY'; + var elRect = el.getBoundingClientRect(); + var rect = {}; + for (var p in elRect) { + rect[p] = elRect[p]; } - }); - controller.$formatters.push(function(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 * 1e3); - } else { - date = new Date(modelValue); + if (rect.width === null) { + rect = angular.extend({}, rect, { + width: elRect.right - elRect.left, + height: elRect.bottom - elRect.top + }); } - controller.$dateValue = dateParser.timezoneOffsetAdjust(date, options.timezone); - return getTimeFormattedString(); - }); - controller.$render = function() { - element.val(getTimeFormattedString()); - }; - function getTimeFormattedString() { - return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat); + var elOffset = isBody ? { + top: 0, + left: 0 + } : dimensions.offset(el), scroll = { + scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.prop('scrollTop') || 0 + }, outerDims = isBody ? { + width: document.documentElement.clientWidth, + height: $window.innerHeight + } : null; + return angular.extend({}, rect, scroll, outerDims, elOffset); } - scope.$on('$destroy', function() { - if (timepicker) timepicker.destroy(); - options = null; - timepicker = null; - }); - } - }; - } ]); - angular.module('mgcrea.ngStrap.typeahead', [ 'mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions' ]).provider('$typeahead', function() { - var defaults = this.defaults = { - animation: 'am-fade', - prefixClass: 'typeahead', - prefixEvent: '$typeahead', - placement: 'bottom-left', - templateUrl: 'typeahead/typeahead.tpl.html', - trigger: 'focus', - container: false, - keyboard: true, - html: false, - delay: 0, - minLength: 1, - filter: 'filter', - limit: 6, - autoSelect: false, - comparator: '', - trimValue: true - }; - this.$get = [ '$window', '$rootScope', '$tooltip', '$$rAF', '$timeout', function($window, $rootScope, $tooltip, $$rAF, $timeout) { - var bodyEl = angular.element($window.document.body); - function TypeaheadFactory(element, controller, config) { - var $typeahead = {}; - var options = angular.extend({}, defaults, config); - $typeahead = $tooltip(element, options); - var parentScope = config.scope; - var scope = $typeahead.$scope; - scope.$resetMatches = function() { - scope.$matches = []; - scope.$activeIndex = options.autoSelect ? 0 : -1; - }; - scope.$resetMatches(); - scope.$activate = function(index) { - scope.$$postDigest(function() { - $typeahead.activate(index); - }); - }; - scope.$select = function(index, evt) { - scope.$$postDigest(function() { - $typeahead.select(index); - }); - }; - scope.$isVisible = function() { - return $typeahead.$isVisible(); - }; - $typeahead.update = function(matches) { - scope.$matches = matches; - if (scope.$activeIndex >= matches.length) { - scope.$activeIndex = options.autoSelect ? 0 : -1; + 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; + } + 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; + } } - safeDigest(scope); - $$rAF($typeahead.$applyPlacement); - }; - $typeahead.activate = function(index) { - scope.$activeIndex = index; - }; - $typeahead.select = function(index) { - if (index === -1) return; - var value = scope.$matches[index].value; - controller.$setViewValue(value); - controller.$render(); - scope.$resetMatches(); - if (parentScope) parentScope.$digest(); - scope.$emit(options.prefixEvent + '.select', value, index, $typeahead); - }; - $typeahead.$isVisible = function() { - if (!options.minLength || !controller) { - return !!scope.$matches.length; + return offset; + } + function applyPlacement(offset, placement) { + var tip = tipElement[0], width = tip.offsetWidth, height = tip.offsetHeight; + var marginTop = parseInt(dimensions.css(tip, 'margin-top'), 10), marginLeft = parseInt(dimensions.css(tip, 'margin-left'), 10); + if (isNaN(marginTop)) marginTop = 0; + if (isNaN(marginLeft)) marginLeft = 0; + offset.top = offset.top + marginTop; + offset.left = offset.left + marginLeft; + dimensions.setOffset(tip, angular.extend({ + using: function(props) { + tipElement.css({ + top: Math.round(props.top) + 'px', + left: Math.round(props.left) + 'px', + right: '' + }); + } + }, offset), 0); + var actualWidth = tip.offsetWidth, actualHeight = tip.offsetHeight; + if (placement === 'top' && actualHeight !== height) { + offset.top = offset.top + height - actualHeight; } - return scope.$matches.length && angular.isString(controller.$viewValue) && controller.$viewValue.length >= options.minLength; - }; - $typeahead.$getIndex = function(value) { - var l = scope.$matches.length, i = l; - if (!l) return; - for (i = l; i--; ) { - if (scope.$matches[i].value === value) break; + if (/top-left|top-right|bottom-left|bottom-right/.test(placement)) return; + var delta = getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight); + if (delta.left) { + offset.left += delta.left; + } else { + offset.top += delta.top; } - if (i < 0) return; - return i; - }; - $typeahead.$onMouseDown = function(evt) { - evt.preventDefault(); - evt.stopPropagation(); - }; - $typeahead.$onKeyDown = function(evt) { - if (!/(38|40|13)/.test(evt.keyCode)) return; - if ($typeahead.$isVisible() && !(evt.keyCode === 13 && scope.$activeIndex === -1)) { - evt.preventDefault(); - evt.stopPropagation(); + dimensions.setOffset(tip, offset); + if (/top|right|bottom|left/.test(placement)) { + var isVertical = /top|bottom/.test(placement), arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight, arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'; + replaceArrow(arrowDelta, tip[arrowOffsetPosition], isVertical); } - if (evt.keyCode === 13 && scope.$matches.length) { - $typeahead.select(scope.$activeIndex); - } else if (evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--; else if (evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++; else if (angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0; - scope.$digest(); - }; - var show = $typeahead.show; - $typeahead.show = function() { - show(); - $timeout(function() { - $typeahead.$element && $typeahead.$element.on('mousedown', $typeahead.$onMouseDown); + } + function getViewportAdjustedDelta(placement, position, actualWidth, actualHeight) { + var delta = { + top: 0, + left: 0 + }; + if (!$tooltip.$viewport) return delta; + var viewportPadding = options.viewport && options.viewport.padding || 0; + var viewportDimensions = getPosition($tooltip.$viewport); + if (/right|left/.test(placement)) { + var topEdgeOffset = position.top - viewportPadding - viewportDimensions.scroll; + var bottomEdgeOffset = position.top + viewportPadding - viewportDimensions.scroll + actualHeight; + if (topEdgeOffset < viewportDimensions.top) { + delta.top = viewportDimensions.top - topEdgeOffset; + } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { + delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset; + } + } else { + var leftEdgeOffset = position.left - viewportPadding; + var rightEdgeOffset = position.left + viewportPadding + actualWidth; + if (leftEdgeOffset < viewportDimensions.left) { + delta.left = viewportDimensions.left - leftEdgeOffset; + } else if (rightEdgeOffset > viewportDimensions.right) { + delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset; + } + } + return delta; + } + function replaceArrow(delta, dimension, isHorizontal) { + var $arrow = findElement('.tooltip-arrow, .arrow', tipElement[0]); + $arrow.css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%').css(isHorizontal ? 'top' : 'left', ''); + } + function destroyTipElement() { + clearTimeout(timeout); + if ($tooltip.$isShown && tipElement !== null) { + if (options.autoClose) { + unbindAutoCloseEvents(); + } if (options.keyboard) { - element && element.on('keydown', $typeahead.$onKeyDown); + unbindKeyboardEvents(); } - }, 0, false); - }; - var hide = $typeahead.hide; - $typeahead.hide = function() { - $typeahead.$element && $typeahead.$element.off('mousedown', $typeahead.$onMouseDown); - if (options.keyboard) { - element && element.off('keydown', $typeahead.$onKeyDown); } - if (!options.autoSelect) $typeahead.activate(-1); - hide(); - }; - return $typeahead; + if (tipScope) { + tipScope.$destroy(); + tipScope = null; + } + if (tipElement) { + tipElement.remove(); + tipElement = $tooltip.$element = null; + } + } + return $tooltip; } function safeDigest(scope) { scope.$$phase || scope.$root && scope.$root.$$phase || scope.$digest(); } - TypeaheadFactory.defaults = defaults; - return TypeaheadFactory; + 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] = $http.get(template, { + cache: $templateCache + }).then(function(res) { + return res.data; + }); + } + return TooltipFactory; } ]; - }).directive('bsTypeahead', [ '$window', '$parse', '$q', '$typeahead', '$parseOptions', function($window, $parse, $q, $typeahead, $parseOptions) { - var defaults = $typeahead.defaults; + }).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) { var options = { scope: scope }; - angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'filter', 'limit', 'minLength', 'watchOptions', 'selectMode', 'autoSelect', 'comparator', 'id', 'prefixEvent', 'prefixClass' ], function(key) { + angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'backdropAnimation', 'type', 'customClass', 'id' ], function(key) { if (angular.isDefined(attr[key])) options[key] = attr[key]; }); var falseValueRegExp = /^(false|0|)$/i; - angular.forEach([ 'html', 'container', 'trimValue' ], function(key) { + angular.forEach([ 'html', 'container' ], function(key) { if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false; }); - element.attr('autocomplete', 'false'); - var filter = options.filter || defaults.filter; - var limit = options.limit || defaults.limit; - var comparator = options.comparator || defaults.comparator; - var bsOptions = attr.bsOptions; - if (filter) bsOptions += ' | ' + filter + ':$viewValue'; - if (comparator) bsOptions += ':' + comparator; - if (limit) bsOptions += ' | limitTo:' + limit; - var parsedOptions = $parseOptions(bsOptions); - var typeahead = $typeahead(element, controller, options); - if (options.watchOptions) { - var watchedOptions = parsedOptions.$match[7].replace(/\|.+/, '').replace(/\(.*\)/g, '').trim(); - scope.$watchCollection(watchedOptions, function(newValue, oldValue) { - parsedOptions.valuesFn(scope, controller).then(function(values) { - typeahead.update(values); - controller.$render(); - }); - }); + var dataTarget = element.attr('data-target'); + if (angular.isDefined(dataTarget)) { + if (falseValueRegExp.test(dataTarget)) options.target = false; else options.target = dataTarget; } - scope.$watch(attr.ngModel, function(newValue, oldValue) { - scope.$modelValue = newValue; - parsedOptions.valuesFn(scope, controller).then(function(values) { - if (options.selectMode && !values.length && newValue.length > 0) { - controller.$setViewValue(controller.$viewValue.substring(0, controller.$viewValue.length - 1)); - return; - } - if (values.length > limit) values = values.slice(0, limit); - var isVisible = typeahead.$isVisible(); - isVisible && typeahead.update(values); - if (values.length === 1 && values[0].value === newValue) return; - !isVisible && typeahead.update(values); - controller.$render(); - }); + if (!scope.hasOwnProperty('title')) { + scope.title = ''; + } + 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(); + }); + } }); - controller.$formatters.push(function(modelValue) { - var displayValue = parsedOptions.displayValue(modelValue); - if (displayValue) return displayValue; - if (modelValue && typeof modelValue !== 'object') { - return modelValue; + attr.bsTooltip && scope.$watch(attr.bsTooltip, function(newValue, oldValue) { + if (angular.isObject(newValue)) { + angular.extend(scope, newValue); + } else { + scope.title = newValue; } - return ''; + angular.isDefined(oldValue) && $$rAF(function() { + tooltip && tooltip.$applyPlacement(); + }); + }, true); + 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(); }); - controller.$render = function() { - if (controller.$isEmpty(controller.$viewValue)) return element.val(''); - var index = typeahead.$getIndex(controller.$modelValue); - var selected = angular.isDefined(index) ? typeahead.$scope.$matches[index].label : controller.$viewValue; - selected = angular.isObject(selected) ? parsedOptions.displayValue(selected) : selected; - var value = selected ? selected.toString().replace(/<(?:.|\n)*?>/gm, '') : ''; - element.val(options.trimValue === false ? value : value.trim()); - }; + attr.bsEnabled && scope.$watch(attr.bsEnabled, function(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); + }); + attr.viewport && scope.$watch(attr.viewport, function(newValue) { + if (!tooltip || !angular.isDefined(newValue)) return; + tooltip.setViewport(newValue); + }); + var tooltip = $tooltip(element, options); scope.$on('$destroy', function() { - if (typeahead) typeahead.destroy(); + if (tooltip) tooltip.destroy(); options = null; - typeahead = null; + tooltip = null; }); } }; diff --git a/dist/angular-strap.min.js b/dist/angular-strap.min.js index f62bc8a2f..36e53f859 100644 --- a/dist/angular-strap.min.js +++ b/dist/angular-strap.min.js @@ -1,12 +1,12 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT */ -!function(e,t,n){'use strict';function a(e,n,a,o,i,r){function s(e,n){return angular.element((n||t).querySelectorAll(e))}function l(e){return u[e]?u[e]:u[e]=n.get(e,{cache:r}).then(function(e){return e.data})}this.compile=function(t){t.template&&/\.html$/.test(t.template)&&(console.warn('Deprecated use of `template` option to pass a file. Please use the `templateUrl` option instead.'),t.templateUrl=t.template,t.template='');var n=t.templateUrl,r=t.template||'',u=t.controller,c=t.controllerAs,d=angular.copy(t.resolve||{}),f=angular.copy(t.locals||{}),p=t.transformTemplate||angular.identity,g=t.bindToController;return angular.forEach(d,function(e,t){d[t]=angular.isString(e)?a.get(e):a.invoke(e)}),angular.extend(d,f),d.$template=n?l(n):e.when(r),t.contentTemplate&&(d.$template=e.all([d.$template,l(t.contentTemplate)]).then(function(e){var n=angular.element(e[0]),a=s('[ng-bind="content"]',n[0]).removeAttr('ng-bind').html(e[1]);return t.templateUrl||a.next().remove(),n[0].outerHTML})),e.all(d).then(function(e){var n=p(e.$template);t.html&&(n=n.replace(/ng-bind="/gi,'ng-bind-html="'));var a=angular.element('
').html(n.trim()).contents(),r=o(a);return{locals:e,element:a,link:function(t){if(e.$scope=t,u){var n=i(u,e,!0);g&&angular.extend(n.instance,e);var o=angular.isObject(n)?n:n();a.data('$ngControllerController',o),a.children().data('$ngControllerController',o),c&&(t[c]=o)}return r.apply(null,arguments)}}})};var u={}}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']),angular.module('mgcrea.ngStrap.affix',['mgcrea.ngStrap.helpers.dimensions','mgcrea.ngStrap.helpers.debounce']).provider('$affix',function(){var e=this.defaults={offsetTop:'auto',inlineStyles:!0};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!==w&&t.top+n+$>=o-w?'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,w=0,y=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);y!==r&&(y=r,o.removeClass(g).addClass('affix'+('middle'!==r?'-'+r:'')),'top'===r?(b=null,m&&o.css('width',''),f.inlineStyles&&(o.css('position',f.offsetParent?'':'relative'),o.css('top',''))):'bottom'===r?(b=f.offsetUnpin?-(1*f.offsetUnpin):t.top-e,m&&o.css('width',''),f.inlineStyles&&(o.css('position',f.offsetParent?'':'relative'),o.css('top',f.offsetParent?'':i[0].offsetHeight-w-n-h+'px'))):(b=null,m&&o.css('width',o[0].offsetWidth+'px'),f.inlineStyles&&(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');f.inlineStyles&&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&&(w=f.offsetParent&&f.offsetBottom.match(/^[-+]\d+$/)?c()-(a.offset(D[0]).top+a.height(D[0]))+1*f.offsetBottom+1:1*f.offsetBottom),f.inlineStyles&&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,target:i?i.$element:angular.element(t)};angular.forEach(['offsetTop','offsetBottom','offsetParent','offsetUnpin','inlineStyles'],function(e){if(angular.isDefined(o[e])){var t=o[e];/true/i.test(t)&&(t=!0),/false/i.test(t)&&(t=!1),r[e]=t}});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,templateUrl:'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,i){var r={scope:e,element:a,show:!1};angular.forEach(['template','templateUrl','controller','controllerAs','placement','keyboard','html','container','animation','duration','dismissable'],function(e){angular.isDefined(o[e])&&(r[e]=o[e])});var s=/^(false|0|)$/i;angular.forEach(['keyboard','html','container','dismissable'],function(e){angular.isDefined(o[e])&&s.test(o[e])&&(r[e]=!1)}),e.hasOwnProperty('title')||(e.title=''),angular.forEach(['title','content','type'],function(n){o[n]&&o.$observe(n,function(a,o){e[n]=t.trustAsHtml(a)})}),o.bsAlert&&e.$watch(o.bsAlert,function(t,n){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var l=n(r);a.on(o.trigger||'click',l.toggle),e.$on('$destroy',function(){l&&l.destroy(),r=null,l=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',templateUrl:'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,i){var r={scope:e,element:a,show:!1};angular.forEach(['template','templateUrl','controller','controllerAs','contentTemplate','placement','backdrop','keyboard','html','container','animation'],function(e){angular.isDefined(o[e])&&(r[e]=o[e])});var s=/^(false|0|)$/i;angular.forEach(['backdrop','keyboard','html','container'],function(e){angular.isDefined(o[e])&&s.test(o[e])&&(r[e]=!1)}),angular.forEach(['title','content'],function(n){o[n]&&o.$observe(n,function(a,o){e[n]=t.trustAsHtml(a)})}),o.bsAside&&e.$watch(o.bsAside,function(t,n){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var l=n(r);a.on(o.trigger||'click',l.toggle),e.$on('$destroy',function(){l&&l.destroy(),r=null,l=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(e,t){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,l=n,u='INPUT'===o[0].nodeName,c=u?o.parent():o;i.$observe('value',function(t){s=a.test(t)?e.$eval(t):t,r.$render()}),r.$render=function(){var e=angular.equals(r.$modelValue,s);t(function(){u&&(o[0].checked=e),c.toggleClass(l.activeClass,e)})},o.bind(l.toggleEvent,function(){e.$apply(function(){r.$setViewValue(s),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 w=u.destroy;u.destroy=function(){c&&p.useNative&&t.off('click',i),w()};var y=u.show;u.show=function(){y(),l(function(){u.$isShown&&(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(p.$options.minDate)||e.getTime()>=p.$options.minDate,n=isNaN(p.$options.maxDate)||e.getTime()<=p.$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())?'':m(s.$dateValue,d.dateFormat)}var d={scope:e};angular.forEach(['template','templateUrl','controller','controllerAs','placement','container','delay','trigger','html','animation','autoclose','dateType','dateFormat','timezone','modelDateFormat','dayFormat','strictFormat','startWeek','startDate','useNative','lang','startView','minView','iconLeft','iconRight','daysOfWeekDisabled','id','prefixClass','prefixEvent'],function(e){angular.isDefined(n[e])&&(d[e]=n[e])});var f=/^(false|0|)$/i;angular.forEach(['html','container','autoclose','useNative'],function(e){angular.isDefined(n[e])&&f.test(n[e])&&(d[e]=!1)}),n.bsShow&&e.$watch(n.bsShow,function(e,t){p&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(datepicker),?/i)),e===!0?p.show():p.hide())});var p=i(t,s,d);d=p.$options,r&&d.useNative&&(d.dateFormat='yyyy-MM-dd');var g=d.lang,m=function(e,t){return a.formatDate(e,t,g)},$=o({format:d.dateFormat,lang:g,strict:d.strictFormat});angular.forEach(['minDate','maxDate'],function(e){angular.isDefined(n[e])&&n.$observe(e,function(t){p.$options[e]=$.getDateForAttribute(e,t),!isNaN(p.$options[e])&&p.$build(!1),u(s.$dateValue)})}),e.$watch(n.ngModel,function(e,t){p.update(s.$dateValue)},!0),angular.isDefined(n.disabledDates)&&e.$watch(n.disabledDates,function(e,t){e=l(e),t=l(t),e&&p.updateDisabledDates(e)}),s.$parsers.unshift(function(e){var t;if(!e)return s.$setValidity('date',!0),null;var n=$.parse(e,s.$dateValue);return!n||isNaN(n.getTime())?void s.$setValidity('date',!1):(u(n),'string'===d.dateType?(t=$.timezoneOffsetAdjust(n,d.timezone,!0),m(t,d.modelDateFormat||d.dateFormat)):(t=$.timezoneOffsetAdjust(s.$dateValue,d.timezone,!0),'number'===d.dateType?t.getTime():'unix'===d.dateType?t.getTime()/1e3:'iso'===d.dateType?t.toISOString():new Date(t)))}),s.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:'string'===d.dateType?$.parse(e,null,d.modelDateFormat):new Date('unix'===d.dateType?1e3*e:e),s.$dateValue=$.timezoneOffsetAdjust(t,d.timezone),c()}),s.$render=function(){t.val(c())},e.$on('$destroy',function(){p&&p.destroy(),d=null,p=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()},$=[{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||1===e.getDate())&&(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=c.timezoneOffsetAdjust(new Date,s.timezone).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,t){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',prefixEvent:'dropdown',placement:'bottom-left',templateUrl:'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&&no;o++)if(e[o].toLowerCase()===a)return o;return-1}t.prototype.setMilliseconds=function(e){this.milliseconds=e},t.prototype.setSeconds=function(e){this.seconds=e},t.prototype.setMinutes=function(e){this.minutes=e},t.prototype.setHours=function(e){this.hours=e},t.prototype.getHours=function(){return this.hours},t.prototype.setDate=function(e){this.day=e},t.prototype.setMonth=function(e){this.month=e},t.prototype.setFullYear=function(e){this.year=e},t.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},t.prototype.toDate=function(){return new Date(this.year,this.month,this.day,this.hours,this.minutes,this.seconds,this.milliseconds)};var i=t.prototype,r=this.defaults={format:'shortDate',strict:!1};this.$get=['$locale','dateFilter',function(e,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;t=1*e&&2===e.length?2e3+1*e:1*e)}};return m.init=function(){m.$format=e.DATETIME_FORMATS[g.format]||g.format,f=d(m.$format),p=u(m.$format)},m.isValid=function(e){return angular.isDate(e)?!isNaN(e.getTime()):f.test(e)},m.parse=function(n,a,o,i){o&&(o=e.DATETIME_FORMATS[o]||o),angular.isDate(n)&&(n=s(n,o||m.$format,i));var r=o?d(o):f,l=o?u(o):p,c=r.exec(n);if(!c)return!1;for(var g=(new t).fromDate(a&&!isNaN(a.getTime())?a:new Date(1970,0,1,0)),$=0;$').html(n.trim()).contents(),r=o(a);return{locals:e,element:a,link:function(t){if(e.$scope=t,u){var n=i(u,e,!0);g&&angular.extend(n.instance,e);var o=angular.isObject(n)?n:n();a.data('$ngControllerController',o),a.children().data('$ngControllerController',o),c&&(t[c]=o)}return r.apply(null,arguments)}}})};var u={}}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']),angular.module('mgcrea.ngStrap.affix',['mgcrea.ngStrap.helpers.dimensions','mgcrea.ngStrap.helpers.debounce']).provider('$affix',function(){var e=this.defaults={offsetTop:'auto',inlineStyles:!0};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!==w&&t.top+n+$>=o-w?'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,w=0,y=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);y!==r&&(y=r,o.removeClass(g).addClass('affix'+('middle'!==r?'-'+r:'')),'top'===r?(b=null,m&&o.css('width',''),f.inlineStyles&&(o.css('position',f.offsetParent?'':'relative'),o.css('top',''))):'bottom'===r?(b=f.offsetUnpin?-(1*f.offsetUnpin):t.top-e,m&&o.css('width',''),f.inlineStyles&&(o.css('position',f.offsetParent?'':'relative'),o.css('top',f.offsetParent?'':i[0].offsetHeight-w-n-h+'px'))):(b=null,m&&o.css('width',o[0].offsetWidth+'px'),f.inlineStyles&&(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');f.inlineStyles&&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&&(w=f.offsetParent&&f.offsetBottom.match(/^[-+]\d+$/)?c()-(a.offset(D[0]).top+a.height(D[0]))+1*f.offsetBottom+1:1*f.offsetBottom),f.inlineStyles&&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,target:i?i.$element:angular.element(t)};angular.forEach(['offsetTop','offsetBottom','offsetParent','offsetUnpin','inlineStyles'],function(e){if(angular.isDefined(o[e])){var t=o[e];/true/i.test(t)&&(t=!0),/false/i.test(t)&&(t=!1),r[e]=t}});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,templateUrl:'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,i){var r={scope:e,element:a,show:!1};angular.forEach(['template','templateUrl','controller','controllerAs','placement','keyboard','html','container','animation','duration','dismissable'],function(e){angular.isDefined(o[e])&&(r[e]=o[e])});var s=/^(false|0|)$/i;angular.forEach(['keyboard','html','container','dismissable'],function(e){angular.isDefined(o[e])&&s.test(o[e])&&(r[e]=!1)}),e.hasOwnProperty('title')||(e.title=''),angular.forEach(['title','content','type'],function(n){o[n]&&o.$observe(n,function(a,o){e[n]=t.trustAsHtml(a)})}),o.bsAlert&&e.$watch(o.bsAlert,function(t,n){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var l=n(r);a.on(o.trigger||'click',l.toggle),e.$on('$destroy',function(){l&&l.destroy(),r=null,l=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',templateUrl:'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,i){var r={scope:e,element:a,show:!1};angular.forEach(['template','templateUrl','controller','controllerAs','contentTemplate','placement','backdrop','keyboard','html','container','animation'],function(e){angular.isDefined(o[e])&&(r[e]=o[e])});var s=/^(false|0|)$/i;angular.forEach(['backdrop','keyboard','html','container'],function(e){angular.isDefined(o[e])&&s.test(o[e])&&(r[e]=!1)}),angular.forEach(['title','content'],function(n){o[n]&&o.$observe(n,function(a,o){e[n]=t.trustAsHtml(a)})}),o.bsAside&&e.$watch(o.bsAside,function(t,n){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var l=n(r);a.on(o.trigger||'click',l.toggle),e.$on('$destroy',function(){l&&l.destroy(),r=null,l=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(e,t){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,l=n,u='INPUT'===o[0].nodeName,c=u?o.parent():o;i.$observe('value',function(t){s=a.test(t)?e.$eval(t):t,r.$render()}),r.$render=function(){var e=angular.equals(r.$modelValue,s);t(function(){u&&(o[0].checked=e),c.toggleClass(l.activeClass,e)})},o.bind(l.toggleEvent,function(){e.$apply(function(){r.$setViewValue(s),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 w=u.destroy;u.destroy=function(){c&&p.useNative&&t.off('click',i),w()};var y=u.show;u.show=function(){!d&&t.attr('readonly')||t.attr('disabled')||(y(),l(function(){u.$isShown&&(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(p.$options.minDate)||e.getTime()>=p.$options.minDate,n=isNaN(p.$options.maxDate)||e.getTime()<=p.$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())?'':m(s.$dateValue,d.dateFormat)}var d={scope:e};angular.forEach(['template','templateUrl','controller','controllerAs','placement','container','delay','trigger','html','animation','autoclose','dateType','dateFormat','timezone','modelDateFormat','dayFormat','strictFormat','startWeek','startDate','useNative','lang','startView','minView','iconLeft','iconRight','daysOfWeekDisabled','id','prefixClass','prefixEvent'],function(e){angular.isDefined(n[e])&&(d[e]=n[e])});var f=/^(false|0|)$/i;angular.forEach(['html','container','autoclose','useNative'],function(e){angular.isDefined(n[e])&&f.test(n[e])&&(d[e]=!1)}),n.bsShow&&e.$watch(n.bsShow,function(e,t){p&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(datepicker),?/i)),e===!0?p.show():p.hide())});var p=i(t,s,d);d=p.$options,r&&d.useNative&&(d.dateFormat='yyyy-MM-dd');var g=d.lang,m=function(e,t){return a.formatDate(e,t,g)},$=o({format:d.dateFormat,lang:g,strict:d.strictFormat});angular.forEach(['minDate','maxDate'],function(e){angular.isDefined(n[e])&&n.$observe(e,function(t){p.$options[e]=$.getDateForAttribute(e,t),!isNaN(p.$options[e])&&p.$build(!1),u(s.$dateValue)})}),e.$watch(n.ngModel,function(e,t){p.update(s.$dateValue)},!0),angular.isDefined(n.disabledDates)&&e.$watch(n.disabledDates,function(e,t){e=l(e),t=l(t),e&&p.updateDisabledDates(e)}),s.$parsers.unshift(function(e){var t;if(!e)return s.$setValidity('date',!0),null;var n=$.parse(e,s.$dateValue);return!n||isNaN(n.getTime())?void s.$setValidity('date',!1):(u(n),'string'===d.dateType?(t=$.timezoneOffsetAdjust(n,d.timezone,!0),m(t,d.modelDateFormat||d.dateFormat)):(t=$.timezoneOffsetAdjust(s.$dateValue,d.timezone,!0),'number'===d.dateType?t.getTime():'unix'===d.dateType?t.getTime()/1e3:'iso'===d.dateType?t.toISOString():new Date(t)))}),s.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:'string'===d.dateType?$.parse(e,null,d.modelDateFormat):new Date('unix'===d.dateType?1e3*e:e),s.$dateValue=$.timezoneOffsetAdjust(t,d.timezone),c()}),s.$render=function(){t.val(c())},e.$on('$destroy',function(){p&&p.destroy(),d=null,p=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()},$=[{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||1===e.getDate())&&(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=c.timezoneOffsetAdjust(new Date,s.timezone).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,t){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',prefixEvent:'dropdown',placement:'bottom-left',templateUrl:'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&&no;o++)if(e[o].toLowerCase()===a)return o;return-1}t.prototype.setMilliseconds=function(e){this.milliseconds=e},t.prototype.setSeconds=function(e){this.seconds=e},t.prototype.setMinutes=function(e){this.minutes=e},t.prototype.setHours=function(e){this.hours=e},t.prototype.getHours=function(){return this.hours},t.prototype.setDate=function(e){this.day=e},t.prototype.setMonth=function(e){this.month=e},t.prototype.setFullYear=function(e){this.year=e},t.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},t.prototype.toDate=function(){return new Date(this.year,this.month,this.day,this.hours,this.minutes,this.seconds,this.milliseconds)};var i=t.prototype,r=this.defaults={format:'shortDate',strict:!1};this.$get=['$locale','dateFilter',function(e,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;t=1*e&&2===e.length?2e3+1*e:1*e)}};return m.init=function(){m.$format=e.DATETIME_FORMATS[g.format]||g.format,f=d(m.$format),p=u(m.$format)},m.isValid=function(e){return angular.isDate(e)?!isNaN(e.getTime()):f.test(e)},m.parse=function(n,a,o,i){o&&(o=e.DATETIME_FORMATS[o]||o),angular.isDate(n)&&(n=s(n,o||m.$format,i));var r=o?d(o):f,l=o?u(o):p,c=r.exec(n);if(!c)return!1;for(var g=(new t).fromDate(a&&!isNaN(a.getTime())?a:new Date(1970,0,1,0)),$=0;$12?e.getHours()+2:0),e):null},m.timezoneOffsetAdjust=function(e,t,n){return e?(t&&'UTC'===t&&(e=new Date(e.getTime()),e.setMinutes(e.getMinutes()+(n?-1:1)*e.getTimezoneOffset())),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(t,n){var a=(angular.element,{}),o=a.nodeName=function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()};a.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},a.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)}},a.setOffset=function(e,t,n){var o,i,r,s,l,u,c,d=a.css(e,'position'),f=angular.element(e),p={};'static'===d&&(e.style.position='relative'),l=a.offset(e),r=a.css(e,'top'),u=a.css(e,'left'),c=('absolute'===d||'fixed'===d)&&(r+u).indexOf('auto')>-1,c?(o=a.position(e),s=o.top,i=o.left):(s=parseFloat(r)||0,i=parseFloat(u)||0),angular.isFunction(t)&&(t=t.call(e,n,l)),null!==t.top&&(p.top=t.top-l.top+s),null!==t.left&&(p.left=t.left-l.left+i),'using'in t?t.using.call(f,p):f.css({top:p.top+'px',left:p.left+'px'})},a.position=function(e){var t,n,r={top:0,left:0};return'fixed'===a.css(e,'position')?n=e.getBoundingClientRect():(t=i(e),n=a.offset(e),o(t,'html')||(r=a.offset(t)),r.top+=a.css(t,'borderTopWidth',!0),r.left+=a.css(t,'borderLeftWidth',!0)),{width:e.offsetWidth,height:e.offsetHeight,top:n.top-r.top-a.css(e,'marginTop',!0),left:n.left-r.left-a.css(e,'marginLeft',!0)}};var i=function(e){var t=e.ownerDocument,n=e.offsetParent||t;if(o(n,'#document'))return t.documentElement;for(;n&&!o(n,'html')&&'static'===a.css(n,'position');)n=n.offsetParent;return n||t.documentElement};return a.height=function(e,t){var n=e.offsetHeight;return t?n+=a.css(e,'marginTop',!0)+a.css(e,'marginBottom',!0):n-=a.css(e,'paddingTop',!0)+a.css(e,'paddingBottom',!0)+a.css(e,'borderTopWidth',!0)+a.css(e,'borderBottomWidth',!0),n},a.width=function(e,t){var n=e.offsetWidth;return t?n+=a.css(e,'marginLeft',!0)+a.css(e,'marginRight',!0):n-=a.css(e,'paddingLeft',!0)+a.css(e,'paddingRight',!0)+a.css(e,'borderLeftWidth',!0)+a.css(e,'borderRightWidth',!0),n},a}]),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){var a;try{a=g(e,t)}catch(o){a=[]}return n.when(a).then(function(t){return angular.isArray(t)||(t=[]),r.$values=t.length?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.modal',['mgcrea.ngStrap.core','mgcrea.ngStrap.helpers.dimensions']).provider('$modal',function(){var e=this.defaults={animation:'am-fade',backdropAnimation:'am-fade',prefixClass:'modal',prefixEvent:'modal',placement:'top',templateUrl:'modal/modal.tpl.html',template:'',contentTemplate:!1,container:!1,element:null,backdrop:!0,keyboard:!0,html:!1,show:!0};this.$get=['$window','$rootScope','$bsCompiler','$q','$templateCache','$http','$animate','$timeout','$sce','dimensions',function(n,a,o,i,r,s,l,u,c,d){function f(t){function n(){k.$emit(b.prefixEvent+'.show',y)}function i(){k.$emit(b.prefixEvent+'.hide',y),h.removeClass(b.prefixClass+'-open'),b.animation&&h.removeClass(b.prefixClass+'-with-'+b.animation)}function r(){b.backdrop&&(x.on('click',f),C.on('click',f),C.on('wheel',v))}function s(){b.backdrop&&(x.off('click',f),C.off('click',f),C.off('wheel',v))}function u(){b.keyboard&&x.on('keyup',y.$onKeyUp)}function d(){b.keyboard&&x.off('keyup',y.$onKeyUp)}function f(e){e.target===e.currentTarget&&('static'===b.backdrop?y.focus():y.hide())}function v(e){e.preventDefault()}function w(){y.$isShown&&null!==x&&(s(),d()),T&&(T.$destroy(),T=null),x&&(x.remove(),x=y.$element=null)}var y={},b=y.$options=angular.extend({},e,t),D=y.$promise=o.compile(b),k=y.$scope=b.scope&&b.scope.$new()||a.$new();b.element||b.container||(b.container='body'),y.$id=b.id||b.element&&b.element.attr('id')||'',m(['title','content'],function(e){b[e]&&(k[e]=c.trustAsHtml(b[e]))}),k.$hide=function(){k.$$postDigest(function(){y.hide()})},k.$show=function(){k.$$postDigest(function(){y.show()})},k.$toggle=function(){k.$$postDigest(function(){y.toggle()})},y.$isShown=k.$isShown=!1;var S,x,T,C=angular.element('
');return C.css({position:'fixed',top:'0px',left:'0px',bottom:'0px',right:'0px','z-index':1038}),D.then(function(e){S=e,y.init()}),y.init=function(){b.show&&k.$$postDigest(function(){y.show()})},y.destroy=function(){w(),C&&(C.remove(),C=null),k.$destroy()},y.show=function(){if(!y.$isShown){var e,t;if(angular.isElement(b.container)?(e=b.container,t=b.container[0].lastChild?angular.element(b.container[0].lastChild):null):b.container?(e=g(b.container),t=e[0]&&e[0].lastChild?angular.element(e[0].lastChild):null):(e=null,t=b.element),x&&w(),T=y.$scope.$new(),x=y.$element=S.link(T,function(e,t){}),!k.$emit(b.prefixEvent+'.show.before',y).defaultPrevented){x.css({display:'block'}).addClass(b.placement),b.animation&&(b.backdrop&&C.addClass(b.backdropAnimation),x.addClass(b.animation)),b.backdrop&&l.enter(C,h,null),angular.version.minor<=2?l.enter(x,e,t,n):l.enter(x,e,t).then(n),y.$isShown=k.$isShown=!0,p(k);var a=x[0];$(function(){a.focus()}),h.addClass(b.prefixClass+'-open'),b.animation&&h.addClass(b.prefixClass+'-with-'+b.animation),r(),u()}}},y.hide=function(){y.$isShown&&(k.$emit(b.prefixEvent+'.hide.before',y).defaultPrevented||(angular.version.minor<=2?l.leave(x,i):l.leave(x).then(i),b.backdrop&&l.leave(C),y.$isShown=k.$isShown=!1,p(k),s(),d()))},y.toggle=function(){y.$isShown?y.hide():y.show()},y.focus=function(){x[0].focus()},y.$onKeyUp=function(e){27===e.which&&y.$isShown&&(y.hide(),e.stopPropagation())},y}function p(e){e.$$phase||e.$root&&e.$root.$$phase||e.$digest()}function g(e,n){return angular.element((n||t).querySelectorAll(e))}var m=angular.forEach,$=(String.prototype.trim,n.requestAnimationFrame||n.setTimeout),h=angular.element(n.document.body);return f}]}).directive('bsModal',['$window','$sce','$modal',function(e,t,n){return{restrict:'EAC',scope:!0,link:function(e,a,o,i){var r={scope:e,element:a,show:!1};angular.forEach(['template','templateUrl','controller','controllerAs','contentTemplate','controller','placement','backdrop','keyboard','html','container','animation','id','prefixEvent','prefixClass'],function(e){angular.isDefined(o[e])&&(r[e]=o[e])});var s=/^(false|0|)$/i;angular.forEach(['backdrop','keyboard','html','container'],function(e){angular.isDefined(o[e])&&s.test(o[e])&&(r[e]=!1)}),angular.forEach(['title','content'],function(n){o[n]&&o.$observe(n,function(a,o){e[n]=t.trustAsHtml(a)})}),o.bsModal&&e.$watch(o.bsModal,function(t,n){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var l=n(r);a.on(o.trigger||'click',l.toggle),e.$on('$destroy',function(){l&&l.destroy(),r=null,l=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,i){var r=angular.copy(a);angular.forEach(Object.keys(a),function(e){angular.isDefined(o[e])&&(r[e]=o[e])}),e.$watch(function(){return t.path()},function(e,t){var a=n[0].querySelectorAll('li['+r.routeAttr+']');angular.forEach(a,function(t){var n=angular.element(t),a=n.attr(r.routeAttr).replace('/','\\/');r.strict&&(a='^'+a+'$');var o=new RegExp(a,'i');o.test(e)?n.addClass(r.activeClass):n.removeClass(r.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,w,y,b,D,k,S,x={},T=x.$trackedElements=[],C=[];return x.init=function(){this.$$count=1,y=s(this.checkPosition,c.debounce),b=l(this.checkPosition,c.throttle),m.on('click',this.checkPositionWithEventLoop),d.on('resize',y),m.on('scroll',b),D=s(this.checkOffsets,c.debounce),h=i.$on('$viewContentLoaded',D),v=i.$on('$includeContentLoaded',D),D(),$&&(e[$]=x)},x.destroy=function(){this.$$count--,this.$$count>0||(m.off('click',this.checkPositionWithEventLoop),d.off('resize',y),m.off('scroll',b),h(),v(),$&&delete e[$])},x.checkPosition=function(){if(C.length){if(S=(g?a.pageYOffset:m.prop('scrollTop'))||0,k=Math.max(a.innerHeight,f.prop('clientHeight')),SC[e+1].offsetTop))return x.$activateElement(C[e])}},x.checkPositionWithEventLoop=function(){setTimeout(x.checkPosition,1)},x.$activateElement=function(e){if(w){var t=x.$getTrackedElement(w);t&&(t.source.removeClass('active'),u(t.source,'li')&&u(t.source.parent().parent(),'li')&&t.source.parent().parent().removeClass('active'))}w=e.target,e.source.addClass('active'),u(e.source,'li')&&u(e.source.parent().parent(),'li')&&e.source.parent().parent().addClass('active')},x.$getTrackedElement=function(e){return T.filter(function(t){return t.target===e})[0]},x.checkOffsets=function(){angular.forEach(T,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=T.filter(function(e){return null!==e.offsetTop}).sort(function(e,t){return e.offsetTop-t.offsetTop}),y()},x.trackElement=function(e,t){T.push({target:e,source:t})},x.untrackElement=function(e,t){for(var n,a=T.length;a--;)if(T[a].target===e&&T[a].source===t){n=a;break}T=T.splice(n,1)},x.activate=function(e){T[e].addClass('active')},x.init(),x}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(e,t,n,a){return{restrict:'A',compile:function(e,t){var n=e[0].querySelectorAll('li > a[href]');angular.forEach(n,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',templateUrl:'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=s.multiple?[]:-1,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,t){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){return/(9|13|38|40)/.test(e.keyCode)?(e.preventDefault(),e.stopPropagation(),s.multiple&&9===e.keyCode?r.hide():s.multiple||13!==e.keyCode&&9!==e.keyCode?void(s.multiple||(38===e.keyCode&&u.$activeIndex>0?u.$activeIndex--:38===e.keyCode&&u.$activeIndex<0?u.$activeIndex=u.$matches.length-1:40===e.keyCode&&u.$activeIndex'),c.after(t)}var d=o(n.bsOptions),f=a(t,r,s),p=d.$match[7].replace(/\|.+/,'').trim();e.$watchCollection(p,function(t,n){d.valuesFn(e,r).then(function(e){f.update(e),r.$render()})}),e.$watch(n.ngModel,function(e,t){f.$updateActiveIndex(),r.$render()},!0),r.$render=function(){var e,n;s.multiple&&angular.isArray(r.$modelValue)?(e=r.$modelValue.map(function(e){return n=f.$getIndex(e),angular.isDefined(n)?f.$scope.$matches[n].label:!1}).filter(angular.isDefined),e=e.length>(s.maxLength||i.maxLength)?e.length+' '+(s.maxLengthHtml||i.maxLengthHtml):e.join(', ')):(n=f.$getIndex(r.$modelValue),e=angular.isDefined(n)?f.$scope.$matches[n].label:!1),t.html((e?e:s.placeholder)+(s.caretHtml?s.caretHtml:i.caretHtml))},s.multiple&&(r.$isEmpty=function(e){return!e||0===e.length}),e.$on('$destroy',function(){f&&f.destroy(),s=null,f=null})}}}]),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',templateUrl:'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','templateUrl','controller','controllerAs','contentTemplate','placement','container','delay','trigger','html','animation','customClass','autoClose','id','prefixClass','prefixEvent'],function(e){angular.isDefined(i[e])&&(r[e]=i[e])});var s=/^(false|0|)$/i;angular.forEach(['html','container','autoClose'],function(e){angular.isDefined(i[e])&&s.test(i[e])&&(r[e]=!1)});var l=o.attr('data-target');angular.isDefined(l)&&(r.target=s.test(l)?!1:l),angular.forEach(['title','content'],function(n){i[n]&&i.$observe(n,function(o,i){e[n]=t.trustAsHtml(o),angular.isDefined(i)&&a(function(){u&&u.$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(){u&&u.$applyPlacement()})},!0),i.bsShow&&e.$watch(i.bsShow,function(e,t){u&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(popover),?/i)),e===!0?u.show():u.hide())}),i.viewport&&e.$watch(i.viewport,function(e){u&&angular.isDefined(e)&&u.setViewport(e)});var u=n(o,r);e.$on('$destroy',function(){u&&u.destroy(),r=null,u=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){angular.isUndefined(o.$panes.$active)&&t.$setActive(e.name||0),o.$panes.push(e)},o.$remove=function(e){var t,n=o.$panes.indexOf(e),a=o.$panes.$active;t=angular.isString(a)?o.$panes.map(function(e){return e.name}).indexOf(a):o.$panes.$active,o.$panes.splice(n,1),t>n?t--:n===t&&t===o.$panes.length&&t--,t>=0&&ts.top+s.height&&(o.top=s.top+s.height-u)}else{var c=t.left-r,d=t.left+r+n;cs.width&&(o.left=s.left+s.width-d)}return o}function E(e,t,n){var a=m('.tooltip-arrow, .arrow',R[0]);a.css(n?'left':'top',50*(1-e/t)+'%').css(n?'top':'left','')}function A(){clearTimeout(H),F.$isShown&&null!==R&&(V.autoClose&&k(),V.keyboard&&b()),Y&&(Y.$destroy(),Y=null),R&&(R.remove(),R=F.$element=null)}var F={},V=F.$options=angular.extend({},e,r),O=F.$promise=o.compile(V),P=F.$scope=V.scope&&V.scope.$new()||a.$new(),I=i[0].nodeName.toLowerCase();if(V.delay&&angular.isString(V.delay)){var N=V.delay.split(',').map(parseFloat);V.delay=N.length>1?{show:N[0],hide:N[1]}:N[0]}F.$id=V.id||i.attr('id')||'',V.title&&(P.title=u.trustAsHtml(V.title)),P.$setEnabled=function(e){P.$$postDigest(function(){F.setEnabled(e)})},P.$hide=function(){P.$$postDigest(function(){F.hide()})},P.$show=function(){P.$$postDigest(function(){F.show()})},P.$toggle=function(){P.$$postDigest(function(){F.toggle()})},F.$isShown=P.$isShown=!1;var H,L,U,R,q,Y;O.then(function(e){U=e,F.init()}),F.init=function(){V.delay&&angular.isNumber(V.delay)&&(V.delay={show:V.delay,hide:V.delay}),'self'===V.container?q=i:angular.isElement(V.container)?q=V.container:V.container&&(q=m(V.container)),v(),V.target&&(V.target=angular.isElement(V.target)?V.target:m(V.target)),V.show&&P.$$postDigest(function(){'focus'===V.trigger?i[0].focus():F.show()})},F.destroy=function(){w(),A(),P.$destroy()},F.enter=function(){return clearTimeout(H),L='in',V.delay&&V.delay.show?void(H=setTimeout(function(){'in'===L&&F.show()},V.delay.show)):F.show()},F.show=function(){if(V.bsEnabled&&!F.$isShown){P.$emit(V.prefixEvent+'.show.before',F);var e,t;V.container?(e=q,t=q[0].lastChild?angular.element(q[0].lastChild):null):(e=null,t=i),R&&A(),Y=F.$scope.$new(),R=F.$element=U.link(Y,function(e,t){}),R.css({top:'-9999px',left:'-9999px',right:'auto',display:'block',visibility:'hidden'}),V.animation&&R.addClass(V.animation),V.type&&R.addClass(V.prefixClass+'-'+V.type),V.customClass&&R.addClass(V.customClass),t?t.after(R):e.prepend(R),F.$isShown=P.$isShown=!0,g(P),F.$applyPlacement(),angular.version.minor<=2?l.enter(R,e,t,s):l.enter(R,e,t).then(s),g(P),d(function(){R&&R.css({visibility:'visible'})}),V.keyboard&&('focus'!==V.trigger&&F.focus(),y()),V.autoClose&&D()}},F.leave=function(){return clearTimeout(H),L='out',V.delay&&V.delay.hide?void(H=setTimeout(function(){'out'===L&&F.hide()},V.delay.hide)):F.hide()};var z,j;F.hide=function(e){F.$isShown&&(P.$emit(V.prefixEvent+'.hide.before',F),z=e,j=R,angular.version.minor<=2?l.leave(R,p):l.leave(R).then(p),F.$isShown=P.$isShown=!1,g(P),V.keyboard&&null!==R&&b(),V.autoClose&&null!==R&&k())},F.toggle=function(){F.$isShown?F.leave():F.enter()},F.focus=function(){R[0].focus()},F.setEnabled=function(e){V.bsEnabled=e},F.setViewport=function(e){V.viewport=e},F.$applyPlacement=function(){if(R){var t=V.placement,n=/\s?auto?\s?/i,a=n.test(t);a&&(t=t.replace(n,'')||e.placement),R.addClass(V.placement);var o=x(),r=R.prop('offsetWidth'),s=R.prop('offsetHeight');if(a){var l=t,u=V.container?m(V.container):i.parent(),c=x(u);l.indexOf('bottom')>=0&&o.bottom+s>c.bottom?t=l.replace('bottom','top'):l.indexOf('top')>=0&&o.top-sc.width?t='right'===l?'left':t.replace('left','right'):('left'===l||'bottom-right'===l||'top-right'===l)&&o.left-rt?t+12:t-12),n.$setViewValue(angular.copy(n.$dateValue)),n.$render()}},f.$build=function(){var e,t,n=m.midIndex=parseInt(g.length/2,10),a=[];for(e=0;e1*g.maxTime},m.$arrowAction=function(e,t){'picker'===g.arrowBehavior?f.$setTimeByStep(e,t):f.$moveIndex(e,t)},f.$setTimeByStep=function(e,t){{var n=new Date(f.$date),a=n.getHours(),o=(h(n,k).length,n.getMinutes()),i=(h(n,x).length,n.getSeconds());h(n,T).length}0===t?n.setHours(a-parseInt(g.hourStep,10)*e):1===t?n.setMinutes(o-parseInt(g.minuteStep,10)*e):2===t&&n.setSeconds(i-parseInt(g.secondStep,10)*e),f.select(n,t,!0)},f.$moveIndex=function(e,t){var n;0===t?(n=new Date(1970,0,1,b.hour+e*g.length,b.minute,b.second),angular.extend(b,{hour:n.getHours()})):1===t?(n=new Date(1970,0,1,b.hour,b.minute+e*g.length*g.minuteStep,b.second),angular.extend(b,{minute:n.getMinutes()})):2===t&&(n=new Date(1970,0,1,b.hour,b.minute,b.second+e*g.length*g.secondStep),angular.extend(b,{second:n.getSeconds()})),f.$build()},f.$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')}},f.$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 f.hide(!0);var t=new Date(f.$date),n=t.getHours(),a=h(t,k).length,o=t.getMinutes(),i=h(t,x).length,r=t.getSeconds(),s=h(t,T).length,u=1,c=/(37|39)/.test(e.keyCode),d=2+1*C+1*M;c&&(37===e.keyCode?v=1>v?d-1:v-1:39===e.keyCode&&(v=d-1>v?v+1:0));var m=[0,a],$=0;38===e.keyCode&&($=-1),40===e.keyCode&&($=1);var w=2===v&&C,y=2===v&&!C||3===v&&C;0===v?(t.setHours(n+$*parseInt(g.hourStep,10)),a=h(t,k).length,m=[0,a]):1===v?(t.setMinutes(o+$*parseInt(g.minuteStep,10)),i=h(t,x).length,m=[a+u,i]):w?(t.setSeconds(r+$*parseInt(g.secondStep,10)),s=h(t,T).length,m=[a+u+i+u,s]):y&&(c||f.switchMeridian(),m=[a+u+i+u+(s+u)*C,2]),f.select(t,v,!0),l(m[0],m[1]),p.$digest()}};var E=f.init;f.init=function(){return u&&g.useNative?(t.prop('type','time'),void t.css('-webkit-appearance','textfield')):(c&&(t.prop('type','text'),t.attr('readonly','true'),t.on('click',d)),void E())};var A=f.destroy;f.destroy=function(){u&&g.useNative&&t.off('click',d),A()};var F=f.show;f.show=function(){F(),s(function(){f.$element&&f.$element.on(c?'touchstart':'mousedown',f.$onMouseDown),g.keyboard&&t&&t.on('keydown',f.$onKeyDown)},0,!1)};var V=f.hide;return f.hide=function(e){f.$isShown&&(f.$element&&f.$element.off(c?'touchstart':'mousedown',f.$onMouseDown),g.keyboard&&t&&t.off('keydown',f.$onKeyDown),V(e))},f}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())?'':m(l.$dateValue,d.timeFormat)}var d={scope:e};angular.forEach(['template','templateUrl','controller','controllerAs','placement','container','delay','trigger','keyboard','html','animation','autoclose','timeType','timeFormat','timezone','modelTimeFormat','useNative','hourStep','minuteStep','secondStep','length','arrowBehavior','iconUp','iconDown','roundDisplay','id','prefixClass','prefixEvent'],function(e){angular.isDefined(n[e])&&(d[e]=n[e])});var f=/^(false|0|)$/i;angular.forEach(['html','container','autoclose','useNative','roundDisplay'],function(e){angular.isDefined(n[e])&&f.test(n[e])&&(d[e]=!1)}),n.bsShow&&e.$watch(n.bsShow,function(e,t){p&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(timepicker),?/i)),e===!0?p.show():p.hide())}),s&&(d.useNative||r.useNative)&&(d.timeFormat='HH:mm');var p=i(t,l,d);d=p.$options;var g=d.lang,m=function(e,t,n){return a.formatDate(e,t,g,n)},$=o({format:d.timeFormat,lang:g});angular.forEach(['minTime','maxTime'],function(e){angular.isDefined(n[e])&&n.$observe(e,function(t){p.$options[e]=$.getTimeForAttribute(e,t),!isNaN(p.$options[e])&&p.$build(),u(l.$dateValue)})}),e.$watch(n.ngModel,function(e,t){p.update(l.$dateValue)},!0),l.$parsers.unshift(function(e){var t;if(!e)return l.$setValidity('date',!0),null;var n=angular.isDate(e)?e:$.parse(e,l.$dateValue);return!n||isNaN(n.getTime())?void l.$setValidity('date',!1):(u(n),'string'===d.timeType?(t=$.timezoneOffsetAdjust(n,d.timezone,!0),m(t,d.modelTimeFormat||d.timeFormat)):(t=$.timezoneOffsetAdjust(l.$dateValue,d.timezone,!0),'number'===d.timeType?t.getTime():'unix'===d.timeType?t.getTime()/1e3:'iso'===d.timeType?t.toISOString():new Date(t)))}),l.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:'string'===d.timeType?$.parse(e,null,d.modelTimeFormat):new Date('unix'===d.timeType?1e3*e:e),l.$dateValue=$.timezoneOffsetAdjust(t,d.timezone),c()}),l.$render=function(){t.val(c())},e.$on('$destroy',function(){p&&p.destroy(),d=null,p=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',templateUrl:'typeahead/typeahead.tpl.html',trigger:'focus',container:!1,keyboard:!0,html:!1,delay:0,minLength:1,filter:'filter',limit:6,autoSelect:!1,comparator:'',trimValue:!0};this.$get=['$window','$rootScope','$tooltip','$$rAF','$timeout',function(t,n,a,o,i){function r(t,n,r){var l={},u=angular.extend({},e,r);l=a(t,u);var c=r.scope,d=l.$scope;d.$resetMatches=function(){d.$matches=[],d.$activeIndex=u.autoSelect?0:-1},d.$resetMatches(),d.$activate=function(e){d.$$postDigest(function(){l.activate(e)})},d.$select=function(e,t){d.$$postDigest(function(){l.select(e)})},d.$isVisible=function(){return l.$isVisible()},l.update=function(e){d.$matches=e,d.$activeIndex>=e.length&&(d.$activeIndex=u.autoSelect?0:-1),s(d),o(l.$applyPlacement)},l.activate=function(e){d.$activeIndex=e},l.select=function(e){if(-1!==e){var t=d.$matches[e].value;n.$setViewValue(t),n.$render(),d.$resetMatches(),c&&c.$digest(),d.$emit(u.prefixEvent+'.select',t,e,l)}},l.$isVisible=function(){return u.minLength&&n?d.$matches.length&&angular.isString(n.$viewValue)&&n.$viewValue.length>=u.minLength:!!d.$matches.length},l.$getIndex=function(e){var t=d.$matches.length,n=t;if(t){for(n=t;n--&&d.$matches[n].value!==e;);if(!(0>n))return n}},l.$onMouseDown=function(e){e.preventDefault(),e.stopPropagation()},l.$onKeyDown=function(e){/(38|40|13)/.test(e.keyCode)&&(!l.$isVisible()||13===e.keyCode&&-1===d.$activeIndex||(e.preventDefault(),e.stopPropagation()),13===e.keyCode&&d.$matches.length?l.select(d.$activeIndex):38===e.keyCode&&d.$activeIndex>0?d.$activeIndex--:40===e.keyCode&&d.$activeIndex0)return void r.$setViewValue(r.$viewValue.substring(0,r.$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),r.$render())})}),r.$formatters.push(function(e){var t=p.displayValue(e);return t?t:e&&'object'!=typeof e?e:''}),r.$render=function(){if(r.$isEmpty(r.$viewValue))return t.val('');var e=g.$getIndex(r.$modelValue),n=angular.isDefined(e)?g.$scope.$matches[e].label:r.$viewValue;n=angular.isObject(n)?p.displayValue(n):n;var a=n?n.toString().replace(/<(?:.|\n)*?>/gm,''):'';t.val(s.trimValue===!1?a:a.trim())},e.$on('$destroy',function(){g&&g.destroy(),s=null,g=null})}}}])}(window,document); +},m.daylightSavingAdjust=function(e){return e?(e.setHours(e.getHours()>12?e.getHours()+2:0),e):null},m.timezoneOffsetAdjust=function(e,t,n){return e?(t&&'UTC'===t&&(e=new Date(e.getTime()),e.setMinutes(e.getMinutes()+(n?-1:1)*e.getTimezoneOffset())),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(t,n){var a=(angular.element,{}),o=a.nodeName=function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()};a.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},a.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)}},a.setOffset=function(e,t,n){var o,i,r,s,l,u,c,d=a.css(e,'position'),f=angular.element(e),p={};'static'===d&&(e.style.position='relative'),l=a.offset(e),r=a.css(e,'top'),u=a.css(e,'left'),c=('absolute'===d||'fixed'===d)&&(r+u).indexOf('auto')>-1,c?(o=a.position(e),s=o.top,i=o.left):(s=parseFloat(r)||0,i=parseFloat(u)||0),angular.isFunction(t)&&(t=t.call(e,n,l)),null!==t.top&&(p.top=t.top-l.top+s),null!==t.left&&(p.left=t.left-l.left+i),'using'in t?t.using.call(f,p):f.css({top:p.top+'px',left:p.left+'px'})},a.position=function(e){var t,n,r={top:0,left:0};return'fixed'===a.css(e,'position')?n=e.getBoundingClientRect():(t=i(e),n=a.offset(e),o(t,'html')||(r=a.offset(t)),r.top+=a.css(t,'borderTopWidth',!0),r.left+=a.css(t,'borderLeftWidth',!0)),{width:e.offsetWidth,height:e.offsetHeight,top:n.top-r.top-a.css(e,'marginTop',!0),left:n.left-r.left-a.css(e,'marginLeft',!0)}};var i=function(e){var t=e.ownerDocument,n=e.offsetParent||t;if(o(n,'#document'))return t.documentElement;for(;n&&!o(n,'html')&&'static'===a.css(n,'position');)n=n.offsetParent;return n||t.documentElement};return a.height=function(e,t){var n=e.offsetHeight;return t?n+=a.css(e,'marginTop',!0)+a.css(e,'marginBottom',!0):n-=a.css(e,'paddingTop',!0)+a.css(e,'paddingBottom',!0)+a.css(e,'borderTopWidth',!0)+a.css(e,'borderBottomWidth',!0),n},a.width=function(e,t){var n=e.offsetWidth;return t?n+=a.css(e,'marginLeft',!0)+a.css(e,'marginRight',!0):n-=a.css(e,'paddingLeft',!0)+a.css(e,'paddingRight',!0)+a.css(e,'borderLeftWidth',!0)+a.css(e,'borderRightWidth',!0),n},a}]),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 angular.isArray(t)||(t=[]),r.$values=t.length?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.modal',['mgcrea.ngStrap.core','mgcrea.ngStrap.helpers.dimensions']).provider('$modal',function(){var e=this.defaults={animation:'am-fade',backdropAnimation:'am-fade',prefixClass:'modal',prefixEvent:'modal',placement:'top',templateUrl:'modal/modal.tpl.html',template:'',contentTemplate:!1,container:!1,element:null,backdrop:!0,keyboard:!0,html:!1,show:!0};this.$get=['$window','$rootScope','$bsCompiler','$q','$templateCache','$http','$animate','$timeout','$sce','dimensions',function(n,a,o,i,r,s,l,u,c,d){function f(t){function n(){k.$emit(b.prefixEvent+'.show',y)}function i(){k.$emit(b.prefixEvent+'.hide',y),h.removeClass(b.prefixClass+'-open'),b.animation&&h.removeClass(b.prefixClass+'-with-'+b.animation)}function r(){b.backdrop&&(x.on('click',f),C.on('click',f),C.on('wheel',v))}function s(){b.backdrop&&(x.off('click',f),C.off('click',f),C.off('wheel',v))}function u(){b.keyboard&&x.on('keyup',y.$onKeyUp)}function d(){b.keyboard&&x.off('keyup',y.$onKeyUp)}function f(e){e.target===e.currentTarget&&('static'===b.backdrop?y.focus():y.hide())}function v(e){e.preventDefault()}function w(){y.$isShown&&null!==x&&(s(),d()),T&&(T.$destroy(),T=null),x&&(x.remove(),x=y.$element=null)}var y={},b=y.$options=angular.extend({},e,t),D=y.$promise=o.compile(b),k=y.$scope=b.scope&&b.scope.$new()||a.$new();b.element||b.container||(b.container='body'),y.$id=b.id||b.element&&b.element.attr('id')||'',m(['title','content'],function(e){b[e]&&(k[e]=c.trustAsHtml(b[e]))}),k.$hide=function(){k.$$postDigest(function(){y.hide()})},k.$show=function(){k.$$postDigest(function(){y.show()})},k.$toggle=function(){k.$$postDigest(function(){y.toggle()})},y.$isShown=k.$isShown=!1;var S,x,T,C=angular.element('
');return C.css({position:'fixed',top:'0px',left:'0px',bottom:'0px',right:'0px','z-index':1038}),D.then(function(e){S=e,y.init()}),y.init=function(){b.show&&k.$$postDigest(function(){y.show()})},y.destroy=function(){w(),C&&(C.remove(),C=null),k.$destroy()},y.show=function(){if(!y.$isShown){var e,t;if(angular.isElement(b.container)?(e=b.container,t=b.container[0].lastChild?angular.element(b.container[0].lastChild):null):b.container?(e=g(b.container),t=e[0]&&e[0].lastChild?angular.element(e[0].lastChild):null):(e=null,t=b.element),x&&w(),T=y.$scope.$new(),x=y.$element=S.link(T,function(e,t){}),!k.$emit(b.prefixEvent+'.show.before',y).defaultPrevented){x.css({display:'block'}).addClass(b.placement),b.animation&&(b.backdrop&&C.addClass(b.backdropAnimation),x.addClass(b.animation)),b.backdrop&&l.enter(C,h,null),angular.version.minor<=2?l.enter(x,e,t,n):l.enter(x,e,t).then(n),y.$isShown=k.$isShown=!0,p(k);var a=x[0];$(function(){a.focus()}),h.addClass(b.prefixClass+'-open'),b.animation&&h.addClass(b.prefixClass+'-with-'+b.animation),r(),u()}}},y.hide=function(){y.$isShown&&(k.$emit(b.prefixEvent+'.hide.before',y).defaultPrevented||(angular.version.minor<=2?l.leave(x,i):l.leave(x).then(i),b.backdrop&&l.leave(C),y.$isShown=k.$isShown=!1,p(k),s(),d()))},y.toggle=function(){y.$isShown?y.hide():y.show()},y.focus=function(){x[0].focus()},y.$onKeyUp=function(e){27===e.which&&y.$isShown&&(y.hide(),e.stopPropagation())},y}function p(e){e.$$phase||e.$root&&e.$root.$$phase||e.$digest()}function g(e,n){return angular.element((n||t).querySelectorAll(e))}var m=angular.forEach,$=(String.prototype.trim,n.requestAnimationFrame||n.setTimeout),h=angular.element(n.document.body);return f}]}).directive('bsModal',['$window','$sce','$modal',function(e,t,n){return{restrict:'EAC',scope:!0,link:function(e,a,o,i){var r={scope:e,element:a,show:!1};angular.forEach(['template','templateUrl','controller','controllerAs','contentTemplate','controller','placement','backdrop','keyboard','html','container','animation','id','prefixEvent','prefixClass'],function(e){angular.isDefined(o[e])&&(r[e]=o[e])});var s=/^(false|0|)$/i;angular.forEach(['backdrop','keyboard','html','container'],function(e){angular.isDefined(o[e])&&s.test(o[e])&&(r[e]=!1)}),angular.forEach(['title','content'],function(n){o[n]&&o.$observe(n,function(a,o){e[n]=t.trustAsHtml(a)})}),o.bsModal&&e.$watch(o.bsModal,function(t,n){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var l=n(r);a.on(o.trigger||'click',l.toggle),e.$on('$destroy',function(){l&&l.destroy(),r=null,l=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,i){var r=angular.copy(a);angular.forEach(Object.keys(a),function(e){angular.isDefined(o[e])&&(r[e]=o[e])}),e.$watch(function(){return t.path()},function(e,t){var a=n[0].querySelectorAll('li['+r.routeAttr+']');angular.forEach(a,function(t){var n=angular.element(t),a=n.attr(r.routeAttr).replace('/','\\/');r.strict&&(a='^'+a+'$');var o=new RegExp(a,'i');o.test(e)?n.addClass(r.activeClass):n.removeClass(r.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',templateUrl:'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','templateUrl','controller','controllerAs','contentTemplate','placement','container','delay','trigger','html','animation','customClass','autoClose','id','prefixClass','prefixEvent'],function(e){angular.isDefined(i[e])&&(r[e]=i[e])});var s=/^(false|0|)$/i;angular.forEach(['html','container','autoClose'],function(e){angular.isDefined(i[e])&&s.test(i[e])&&(r[e]=!1)});var l=o.attr('data-target');angular.isDefined(l)&&(r.target=s.test(l)?!1:l),angular.forEach(['title','content'],function(n){i[n]&&i.$observe(n,function(o,i){e[n]=t.trustAsHtml(o),angular.isDefined(i)&&a(function(){u&&u.$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(){u&&u.$applyPlacement()})},!0),i.bsShow&&e.$watch(i.bsShow,function(e,t){u&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(popover),?/i)),e===!0?u.show():u.hide())}),i.viewport&&e.$watch(i.viewport,function(e){u&&angular.isDefined(e)&&u.setViewport(e)});var u=n(o,r);e.$on('$destroy',function(){u&&u.destroy(),r=null,u=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,w,y,b,D,k,S,x={},T=x.$trackedElements=[],C=[];return x.init=function(){this.$$count=1,y=s(this.checkPosition,c.debounce),b=l(this.checkPosition,c.throttle),m.on('click',this.checkPositionWithEventLoop),d.on('resize',y),m.on('scroll',b),D=s(this.checkOffsets,c.debounce),h=i.$on('$viewContentLoaded',D),v=i.$on('$includeContentLoaded',D),D(),$&&(e[$]=x)},x.destroy=function(){this.$$count--,this.$$count>0||(m.off('click',this.checkPositionWithEventLoop),d.off('resize',y),m.off('scroll',b),h(),v(),$&&delete e[$])},x.checkPosition=function(){if(C.length){if(S=(g?a.pageYOffset:m.prop('scrollTop'))||0,k=Math.max(a.innerHeight,f.prop('clientHeight')),SC[e+1].offsetTop))return x.$activateElement(C[e])}},x.checkPositionWithEventLoop=function(){setTimeout(x.checkPosition,1)},x.$activateElement=function(e){if(w){var t=x.$getTrackedElement(w);t&&(t.source.removeClass('active'),u(t.source,'li')&&u(t.source.parent().parent(),'li')&&t.source.parent().parent().removeClass('active'))}w=e.target,e.source.addClass('active'),u(e.source,'li')&&u(e.source.parent().parent(),'li')&&e.source.parent().parent().addClass('active')},x.$getTrackedElement=function(e){return T.filter(function(t){return t.target===e})[0]},x.checkOffsets=function(){angular.forEach(T,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=T.filter(function(e){return null!==e.offsetTop}).sort(function(e,t){return e.offsetTop-t.offsetTop}),y()},x.trackElement=function(e,t){T.push({target:e,source:t})},x.untrackElement=function(e,t){for(var n,a=T.length;a--;)if(T[a].target===e&&T[a].source===t){n=a;break}T=T.splice(n,1)},x.activate=function(e){T[e].addClass('active')},x.init(),x}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(e,t,n,a){return{restrict:'A',compile:function(e,t){var n=e[0].querySelectorAll('li > a[href]');angular.forEach(n,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',templateUrl:'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=s.multiple?[]:-1,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,t){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){return/(9|13|38|40)/.test(e.keyCode)?(e.preventDefault(),e.stopPropagation(),s.multiple&&9===e.keyCode?r.hide():s.multiple||13!==e.keyCode&&9!==e.keyCode?void(s.multiple||(38===e.keyCode&&u.$activeIndex>0?u.$activeIndex--:38===e.keyCode&&u.$activeIndex<0?u.$activeIndex=u.$matches.length-1:40===e.keyCode&&u.$activeIndex'),c.after(t)}var d=o(n.bsOptions),f=a(t,r,s),p=d.$match[7].replace(/\|.+/,'').trim();e.$watchCollection(p,function(t,n){d.valuesFn(e,r).then(function(e){f.update(e),r.$render()})}),e.$watch(n.ngModel,function(e,t){f.$updateActiveIndex(),r.$render()},!0),r.$render=function(){var e,n;s.multiple&&angular.isArray(r.$modelValue)?(e=r.$modelValue.map(function(e){return n=f.$getIndex(e),angular.isDefined(n)?f.$scope.$matches[n].label:!1}).filter(angular.isDefined),e=e.length>(s.maxLength||i.maxLength)?e.length+' '+(s.maxLengthHtml||i.maxLengthHtml):e.join(', ')):(n=f.$getIndex(r.$modelValue),e=angular.isDefined(n)?f.$scope.$matches[n].label:!1),t.html((e?e:s.placeholder)+(s.caretHtml?s.caretHtml:i.caretHtml))},s.multiple&&(r.$isEmpty=function(e){return!e||0===e.length}),e.$on('$destroy',function(){f&&f.destroy(),s=null,f=null})}}}]),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',templateUrl:'timepicker/timepicker.tpl.html',trigger:'focus',container:!1,keyboard:!0,html:!1,delay:0,useNative:!0,timeType:'date',timeFormat:'shortTime',timezone:null,modelTimeFormat:null,autoclose:!1,minTime:-(1/0),maxTime:+(1/0),length:5,hourStep:1,minuteStep:5,secondStep:5,roundDisplay:!1,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){var t=6e4*g.minuteStep;return new Date(Math.floor(e.getTime()/t)*t)}function l(e,n){var a=e+n;if(t[0].createTextRange){var o=t[0].createTextRange();o.collapse(!0),o.moveStart('character',e),o.moveEnd('character',a),o.select()}else t[0].setSelectionRange?t[0].setSelectionRange(e,a):angular.isUndefined(t[0].selectionStart)&&(t[0].selectionStart=e,t[0].selectionEnd=a)}function d(){t[0].focus()}var f=r(t,angular.extend({},e,a)),p=a.scope,g=f.$options,m=f.$scope,$=g.lang,h=function(e,t,n){return i.formatDate(e,t,$,n)},v=0,w=g.roundDisplay?o(new Date):new Date,y=n.$dateValue||w,b={hour:y.getHours(),meridian:y.getHours()<12,minute:y.getMinutes(),second:y.getSeconds(),millisecond:y.getMilliseconds()},D=i.getDatetimeFormat(g.timeFormat,$),k=i.hoursFormat(D),S=i.timeSeparator(D),x=i.minutesFormat(D),T=i.secondsFormat(D),C=i.showSeconds(D),M=i.showAM(D);m.$iconUp=g.iconUp,m.$iconDown=g.iconDown,m.$select=function(e,t){f.select(e,t)},m.$moveIndex=function(e,t){f.$moveIndex(e,t)},m.$switchMeridian=function(e){f.switchMeridian(e)},f.update=function(e){angular.isDate(e)&&!isNaN(e.getTime())?(f.$date=e,angular.extend(b,{hour:e.getHours(),minute:e.getMinutes(),second:e.getSeconds(),millisecond:e.getMilliseconds()}),f.$build()):f.$isBuilt||f.$build()},f.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()):2===t&&n.$dateValue.setSeconds(e.getSeconds()),n.$setViewValue(angular.copy(n.$dateValue)),n.$render(),g.autoclose&&!a&&s(function(){f.hide(!0)})},f.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()}},f.$build=function(){var e,t,n=m.midIndex=parseInt(g.length/2,10),a=[];for(e=0;e1*g.maxTime},m.$arrowAction=function(e,t){'picker'===g.arrowBehavior?f.$setTimeByStep(e,t):f.$moveIndex(e,t)},f.$setTimeByStep=function(e,t){var n=new Date(f.$date||y),a=n.getHours(),o=n.getMinutes(),i=n.getSeconds();0===t?n.setHours(a-parseInt(g.hourStep,10)*e):1===t?n.setMinutes(o-parseInt(g.minuteStep,10)*e):2===t&&n.setSeconds(i-parseInt(g.secondStep,10)*e),f.select(n,t,!0)},f.$moveIndex=function(e,t){var n;0===t?(n=new Date(1970,0,1,b.hour+e*g.length,b.minute,b.second),angular.extend(b,{hour:n.getHours()})):1===t?(n=new Date(1970,0,1,b.hour,b.minute+e*g.length*g.minuteStep,b.second),angular.extend(b,{minute:n.getMinutes()})):2===t&&(n=new Date(1970,0,1,b.hour,b.minute,b.second+e*g.length*g.secondStep),angular.extend(b,{second:n.getSeconds()})),f.$build()},f.$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')}},f.$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 void f.hide(!0);var t=new Date(f.$date),n=t.getHours(),a=h(t,k).length,o=t.getMinutes(),i=h(t,x).length,r=t.getSeconds(),s=h(t,T).length,u=1,c=/(37|39)/.test(e.keyCode),d=2+1*C+1*M;c&&(37===e.keyCode?v=1>v?d-1:v-1:39===e.keyCode&&(v=d-1>v?v+1:0));var m=[0,a],$=0;38===e.keyCode&&($=-1),40===e.keyCode&&($=1);var w=2===v&&C,y=2===v&&!C||3===v&&C;0===v?(t.setHours(n+$*parseInt(g.hourStep,10)),a=h(t,k).length,m=[0,a]):1===v?(t.setMinutes(o+$*parseInt(g.minuteStep,10)),i=h(t,x).length,m=[a+u,i]):w?(t.setSeconds(r+$*parseInt(g.secondStep,10)),s=h(t,T).length,m=[a+u+i+u,s]):y&&(c||f.switchMeridian(),m=[a+u+i+u+(s+u)*C,2]),f.select(t,v,!0),l(m[0],m[1]),p.$digest()}};var E=f.init;f.init=function(){return u&&g.useNative?(t.prop('type','time'),void t.css('-webkit-appearance','textfield')):(c&&(t.prop('type','text'),t.attr('readonly','true'),t.on('click',d)),void E())};var A=f.destroy;f.destroy=function(){u&&g.useNative&&t.off('click',d),A()};var F=f.show;f.show=function(){!c&&t.attr('readonly')||t.attr('disabled')||(F(),s(function(){f.$element&&f.$element.on(c?'touchstart':'mousedown',f.$onMouseDown),g.keyboard&&t&&t.on('keydown',f.$onKeyDown)},0,!1))};var V=f.hide;return f.hide=function(e){f.$isShown&&(f.$element&&f.$element.off(c?'touchstart':'mousedown',f.$onMouseDown),g.keyboard&&t&&t.off('keydown',f.$onKeyDown),V(e))},f}var u=/(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,a,o,i,r){var s=r.defaults,l=/(ip(a|o)d|iphone|android)/gi.test(e.navigator.userAgent);return{restrict:'EAC',require:'ngModel',link:function(e,t,a,u){function c(e){if(angular.isDate(e)){var t=isNaN(f.minTime)||new Date(e.getTime()).setFullYear(1970,0,1)>=f.minTime,n=isNaN(f.maxTime)||new Date(e.getTime()).setFullYear(1970,0,1)<=f.maxTime,a=t&&n;u.$setValidity('date',a),u.$setValidity('min',t),u.$setValidity('max',n),a&&(u.$dateValue=e)}}function d(){return!u.$dateValue||isNaN(u.$dateValue.getTime())?'':$(u.$dateValue,f.timeFormat)}var f={scope:e};angular.forEach(['template','templateUrl','controller','controllerAs','placement','container','delay','trigger','keyboard','html','animation','autoclose','timeType','timeFormat','timezone','modelTimeFormat','useNative','hourStep','minuteStep','secondStep','length','arrowBehavior','iconUp','iconDown','roundDisplay','id','prefixClass','prefixEvent'],function(e){angular.isDefined(a[e])&&(f[e]=a[e])});var p=/^(false|0|)$/i;angular.forEach(['html','container','autoclose','useNative','roundDisplay'],function(e){angular.isDefined(a[e])&&p.test(a[e])&&(f[e]=!1)}),a.bsShow&&e.$watch(a.bsShow,function(e,t){g&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(timepicker),?/i)),e===!0?g.show():g.hide())}),l&&(f.useNative||s.useNative)&&(f.timeFormat='HH:mm');var g=r(t,u,f);f=g.$options;var m=f.lang,$=function(e,t,n){return o.formatDate(e,t,m,n)},h=i({format:f.timeFormat,lang:m});angular.forEach(['minTime','maxTime'],function(e){angular.isDefined(a[e])&&a.$observe(e,function(t){g.$options[e]=h.getTimeForAttribute(e,t),!isNaN(g.$options[e])&&g.$build(),c(u.$dateValue)})}),e.$watch(a.ngModel,function(e,t){g.update(u.$dateValue)},!0),u.$parsers.unshift(function(e){var t;if(!e)return u.$setValidity('date',!0),null;var a=angular.isDate(e)?e:h.parse(e,u.$dateValue);return!a||isNaN(a.getTime())?(u.$setValidity('date',!1),n):(c(a),'string'===f.timeType?(t=h.timezoneOffsetAdjust(a,f.timezone,!0),$(t,f.modelTimeFormat||f.timeFormat)):(t=h.timezoneOffsetAdjust(u.$dateValue,f.timezone,!0),'number'===f.timeType?t.getTime():'unix'===f.timeType?t.getTime()/1e3:'iso'===f.timeType?t.toISOString():new Date(t)))}),u.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:'string'===f.timeType?h.parse(e,null,f.modelTimeFormat):new Date('unix'===f.timeType?1e3*e:e),u.$dateValue=h.timezoneOffsetAdjust(t,f.timezone),d()}),u.$render=function(){t.val(d())},e.$on('$destroy',function(){g&&g.destroy(),f=null,g=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){angular.isUndefined(o.$panes.$active)&&t.$setActive(e.name||0),o.$panes.push(e)},o.$remove=function(e){var t,n=o.$panes.indexOf(e),a=o.$panes.$active;t=angular.isString(a)?o.$panes.map(function(e){return e.name}).indexOf(a):o.$panes.$active,o.$panes.splice(n,1),t>n?t--:n===t&&t===o.$panes.length&&t--,t>=0&&t=e.length&&(d.$activeIndex=u.autoSelect?0:-1),s(d),o(l.$applyPlacement)},l.activate=function(e){d.$activeIndex=e},l.select=function(e){if(-1!==e){var t=d.$matches[e].value;n.$setViewValue(t),n.$render(),d.$resetMatches(),c&&c.$digest(),d.$emit(u.prefixEvent+'.select',t,e,l)}},l.$isVisible=function(){return u.minLength&&n?d.$matches.length&&angular.isString(n.$viewValue)&&n.$viewValue.length>=u.minLength:!!d.$matches.length},l.$getIndex=function(e){var t=d.$matches.length,n=t;if(t){for(n=t;n--&&d.$matches[n].value!==e;);if(!(0>n))return n}},l.$onMouseDown=function(e){e.preventDefault(),e.stopPropagation()},l.$onKeyDown=function(e){/(38|40|13)/.test(e.keyCode)&&(!l.$isVisible()||13===e.keyCode&&-1===d.$activeIndex||(e.preventDefault(),e.stopPropagation()),13===e.keyCode&&d.$matches.length?l.select(d.$activeIndex):38===e.keyCode&&d.$activeIndex>0?d.$activeIndex--:40===e.keyCode&&d.$activeIndex0)return void r.$setViewValue(r.$viewValue.substring(0,r.$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),r.$render())})}),r.$formatters.push(function(e){var t=p.displayValue(e);return t?t:e&&'object'!=typeof e?e:''}),r.$render=function(){if(r.$isEmpty(r.$viewValue))return t.val('');var e=g.$getIndex(r.$modelValue),n=angular.isDefined(e)?g.$scope.$matches[e].label:r.$viewValue;n=angular.isObject(n)?p.displayValue(n):n;var a=n?n.toString().replace(/<(?:.|\n)*?>/gm,''):'';t.val(s.trimValue===!1?a:a.trim())},e.$on('$destroy',function(){g&&g.destroy(),s=null,g=null})}}}]),angular.module('mgcrea.ngStrap.tooltip',['mgcrea.ngStrap.core','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',templateUrl:'tooltip/tooltip.tpl.html',template:'',contentTemplate:!1,trigger:'hover focus',keyboard:!1,html:!1,show:!1,title:'',type:'',delay:0,autoClose:!1,bsEnabled:!0,viewport:{selector:'body',padding:0}};this.$get=['$window','$rootScope','$bsCompiler','$q','$templateCache','$http','$animate','$sce','dimensions','$$rAF','$timeout',function(n,a,o,i,r,s,l,u,c,d,f){function p(i,r){function s(){P.$emit(V.prefixEvent+'.show',F)}function p(){if(P.$emit(V.prefixEvent+'.hide',F),R===j){if(z&&'focus'===V.trigger)return i[0].blur();A()}}function v(){var e=V.trigger.split(' ');angular.forEach(e,function(e){'click'===e?i.on('click',F.toggle):'manual'!==e&&(i.on('hover'===e?'mouseenter':'focus',F.enter),i.on('hover'===e?'mouseleave':'blur',F.leave),'button'===I&&'hover'!==e&&i.on($?'touchstart':'mousedown',F.$onFocusElementMouseDown))})}function w(){for(var e=V.trigger.split(' '),t=e.length;t--;){var n=e[t];'click'===n?i.off('click',F.toggle):'manual'!==n&&(i.off('hover'===n?'mouseenter':'focus',F.enter),i.off('hover'===n?'mouseleave':'blur',F.leave),'button'===I&&'hover'!==n&&i.off($?'touchstart':'mousedown',F.$onFocusElementMouseDown))}}function y(){'focus'!==V.trigger?R.on('keyup',F.$onKeyUp):i.on('keyup',F.$onFocusKeyUp)}function b(){'focus'!==V.trigger?R.off('keyup',F.$onKeyUp):i.off('keyup',F.$onFocusKeyUp)}function D(){f(function(){R.on('click',S),h.on('click',F.hide),K=!0},0,!1)}function k(){K&&(R.off('click',S),h.off('click',F.hide),K=!1)}function S(e){e.stopPropagation()}function x(e){e=e||V.target||i;var a=e[0],o='BODY'===a.tagName,r=a.getBoundingClientRect(),s={};for(var l in r)s[l]=r[l];null===s.width&&(s=angular.extend({},s,{width:r.right-r.left,height:r.bottom-r.top}));var u=o?{top:0,left:0}:c.offset(a),d={scroll:o?t.documentElement.scrollTop||t.body.scrollTop:e.prop('scrollTop')||0},f=o?{width:t.documentElement.clientWidth,height:n.innerHeight}:null;return angular.extend({},s,d,f,u)}function T(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 C(e,t){var n=R[0],a=n.offsetWidth,o=n.offsetHeight,i=parseInt(c.css(n,'margin-top'),10),r=parseInt(c.css(n,'margin-left'),10);isNaN(i)&&(i=0),isNaN(r)&&(r=0),e.top=e.top+i,e.left=e.left+r,c.setOffset(n,angular.extend({using:function(e){R.css({top:Math.round(e.top)+'px',left:Math.round(e.left)+'px',right:''})}},e),0);var s=n.offsetWidth,l=n.offsetHeight;if('top'===t&&l!==o&&(e.top=e.top+o-l),!/top-left|top-right|bottom-left|bottom-right/.test(t)){var u=M(t,e,s,l);if(u.left?e.left+=u.left:e.top+=u.top,c.setOffset(n,e),/top|right|bottom|left/.test(t)){var d=/top|bottom/.test(t),f=d?2*u.left-a+s:2*u.top-o+l,p=d?'offsetWidth':'offsetHeight';E(f,n[p],d)}}}function M(e,t,n,a){var o={top:0,left:0};if(!F.$viewport)return o;var i=V.viewport&&V.viewport.padding||0,r=x(F.$viewport);if(/right|left/.test(e)){var s=t.top-i-r.scroll,l=t.top+i-r.scroll+a;sr.top+r.height&&(o.top=r.top+r.height-l)}else{var u=t.left-i,c=t.left+i+n;ur.right&&(o.left=r.left+r.width-c)}return o}function E(e,t,n){var a=m('.tooltip-arrow, .arrow',R[0]);a.css(n?'left':'top',50*(1-e/t)+'%').css(n?'top':'left','')}function A(){clearTimeout(H),F.$isShown&&null!==R&&(V.autoClose&&k(),V.keyboard&&b()),Y&&(Y.$destroy(),Y=null),R&&(R.remove(),R=F.$element=null)}var F={},V=F.$options=angular.extend({},e,r),O=F.$promise=o.compile(V),P=F.$scope=V.scope&&V.scope.$new()||a.$new(),I=i[0].nodeName.toLowerCase();if(V.delay&&angular.isString(V.delay)){var N=V.delay.split(',').map(parseFloat);V.delay=N.length>1?{show:N[0],hide:N[1]}:N[0]}F.$id=V.id||i.attr('id')||'',V.title&&(P.title=u.trustAsHtml(V.title)),P.$setEnabled=function(e){P.$$postDigest(function(){F.setEnabled(e)})},P.$hide=function(){P.$$postDigest(function(){F.hide()})},P.$show=function(){P.$$postDigest(function(){F.show()})},P.$toggle=function(){P.$$postDigest(function(){F.toggle()})},F.$isShown=P.$isShown=!1;var H,L,U,R,q,Y;O.then(function(e){U=e,F.init()}),F.init=function(){V.delay&&angular.isNumber(V.delay)&&(V.delay={show:V.delay,hide:V.delay}),'self'===V.container?q=i:angular.isElement(V.container)?q=V.container:V.container&&(q=m(V.container)),v(),V.target&&(V.target=angular.isElement(V.target)?V.target:m(V.target)),V.show&&P.$$postDigest(function(){'focus'===V.trigger?i[0].focus():F.show()})},F.destroy=function(){w(),A(),P.$destroy()},F.enter=function(){return clearTimeout(H),L='in',V.delay&&V.delay.show?void(H=setTimeout(function(){'in'===L&&F.show()},V.delay.show)):F.show()},F.show=function(){if(V.bsEnabled&&!F.$isShown){P.$emit(V.prefixEvent+'.show.before',F);var e,t;V.container?(e=q,t=q[0].lastChild?angular.element(q[0].lastChild):null):(e=null,t=i),R&&A(),Y=F.$scope.$new(),R=F.$element=U.link(Y,function(e,t){}),R.css({top:'-9999px',left:'-9999px',right:'auto',display:'block',visibility:'hidden'}),V.animation&&R.addClass(V.animation),V.type&&R.addClass(V.prefixClass+'-'+V.type),V.customClass&&R.addClass(V.customClass),t?t.after(R):e.prepend(R),F.$isShown=P.$isShown=!0,g(P),F.$applyPlacement(),angular.version.minor<=2?l.enter(R,e,t,s):l.enter(R,e,t).then(s),g(P),d(function(){R&&R.css({visibility:'visible'})}),V.keyboard&&('focus'!==V.trigger&&F.focus(),y()),V.autoClose&&D()}},F.leave=function(){return clearTimeout(H),L='out',V.delay&&V.delay.hide?void(H=setTimeout(function(){'out'===L&&F.hide()},V.delay.hide)):F.hide()};var z,j;F.hide=function(e){F.$isShown&&(P.$emit(V.prefixEvent+'.hide.before',F),z=e,j=R,angular.version.minor<=2?l.leave(R,p):l.leave(R).then(p),F.$isShown=P.$isShown=!1,g(P),V.keyboard&&null!==R&&b(),V.autoClose&&null!==R&&k())},F.toggle=function(){F.$isShown?F.leave():F.enter()},F.focus=function(){R[0].focus()},F.setEnabled=function(e){V.bsEnabled=e},F.setViewport=function(e){V.viewport=e},F.$applyPlacement=function(){if(R){var t=V.placement,n=/\s?auto?\s?/i,a=n.test(t);a&&(t=t.replace(n,'')||e.placement),R.addClass(V.placement);var o=x(),i=R.prop('offsetWidth'),r=R.prop('offsetHeight');if(F.$viewport=V.viewport&&m(V.viewport.selector||V.viewport),a){var s=t,l=x(F.$viewport);s.indexOf('bottom')>=0&&o.bottom+r>l.bottom?t=s.replace('bottom','top'):s.indexOf('top')>=0&&o.top-rl.width?t='right'===s?'left':t.replace('left','right'):('left'===s||'bottom-right'===s||'top-right'===s)&&o.left-i= scrollHeight - offsetBottom)) {\n return 'bottom';\n } else {\n return 'middle';\n }\n\n }\n\n function getScrollTop() {\n return targetEl[0] === $window ? $window.pageYOffset : targetEl[0].scrollTop;\n }\n\n function getScrollHeight() {\n return targetEl[0] === $window ? $window.document.body.scrollHeight : targetEl[0].scrollHeight;\n }\n\n $affix.init();\n return $affix;\n\n }\n\n return AffixFactory;\n\n };\n\n })\n\n .directive('bsAffix', function($affix, $window) {\n\n return {\n restrict: 'EAC',\n require: '^?bsAffixTarget',\n link: function postLink(scope, element, attr, affixTarget) {\n\n var options = {scope: scope, target: affixTarget ? affixTarget.$element : angular.element($window)};\n angular.forEach(['offsetTop', 'offsetBottom', 'offsetParent', 'offsetUnpin', 'inlineStyles'], function(key) {\n if(angular.isDefined(attr[key])) {\n var option = attr[key];\n if (/true/i.test(option)) option = true;\n if (/false/i.test(option)) option = false;\n options[key] = option;\n }\n });\n\n var affix = $affix(element, options);\n scope.$on('$destroy', function() {\n affix && affix.destroy();\n options = null;\n affix = null;\n });\n\n }\n };\n\n })\n\n .directive('bsAffixTarget', function() {\n return {\n controller: function($element) {\n this.$element = $element;\n }\n };\n });\n\n// Source: alert/alert.js\n// @BUG: following snippet won't compile correctly\n// @TODO: submit issue to core\n// ' ' +\n\nangular.module('mgcrea.ngStrap.alert', ['mgcrea.ngStrap.modal'])\n\n .provider('$alert', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'alert',\n prefixEvent: 'alert',\n placement: null,\n templateUrl: 'alert/alert.tpl.html',\n container: false,\n element: null,\n backdrop: false,\n keyboard: true,\n show: true,\n // Specific options\n duration: false,\n type: false,\n dismissable: true\n };\n\n this.$get = function($modal, $timeout) {\n\n function AlertFactory(config) {\n\n var $alert = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $alert = $modal(options);\n\n // Support scope as string options [/*title, content, */ type, dismissable]\n $alert.$scope.dismissable = !!options.dismissable;\n if(options.type) {\n $alert.$scope.type = options.type;\n }\n\n // Support auto-close duration\n var show = $alert.show;\n if(options.duration) {\n $alert.show = function() {\n show();\n $timeout(function() {\n $alert.hide();\n }, options.duration * 1000);\n };\n }\n\n return $alert;\n\n }\n\n return AlertFactory;\n\n };\n\n })\n\n .directive('bsAlert', function($window, $sce, $alert) {\n\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope, element: element, show: false};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'keyboard', 'html', 'container', 'animation', 'duration', 'dismissable'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['keyboard', 'html', 'container', 'dismissable'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // overwrite inherited title value when no value specified\n // fix for angular 1.3.1 531a8de72c439d8ddd064874bf364c00cedabb11\n if (!scope.hasOwnProperty('title')){\n scope.title = '';\n }\n\n // Support scope as data-attrs\n angular.forEach(['title', 'content', 'type'], function(key) {\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\n scope[key] = $sce.trustAsHtml(newValue);\n });\n });\n\n // Support scope as an object\n attr.bsAlert && scope.$watch(attr.bsAlert, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.content = newValue;\n }\n }, true);\n\n // Initialize alert\n var alert = $alert(options);\n\n // Trigger\n element.on(attr.trigger || 'click', alert.toggle);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (alert) alert.destroy();\n options = null;\n alert = null;\n });\n\n }\n };\n\n });\n\n// Source: aside/aside.js\nangular.module('mgcrea.ngStrap.aside', ['mgcrea.ngStrap.modal'])\n\n .provider('$aside', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade-and-slide-right',\n prefixClass: 'aside',\n prefixEvent: 'aside',\n placement: 'right',\n templateUrl: 'aside/aside.tpl.html',\n contentTemplate: false,\n container: false,\n element: null,\n backdrop: true,\n keyboard: true,\n html: false,\n show: true\n };\n\n this.$get = function($modal) {\n\n function AsideFactory(config) {\n\n var $aside = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $aside = $modal(options);\n\n return $aside;\n\n }\n\n return AsideFactory;\n\n };\n\n })\n\n .directive('bsAside', function($window, $sce, $aside) {\n\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n // Directive options\n var options = {scope: scope, element: element, show: false};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['backdrop', 'keyboard', 'html', 'container'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Support scope as data-attrs\n angular.forEach(['title', 'content'], function(key) {\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\n scope[key] = $sce.trustAsHtml(newValue);\n });\n });\n\n // Support scope as an object\n attr.bsAside && scope.$watch(attr.bsAside, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.content = newValue;\n }\n }, true);\n\n // Initialize aside\n var aside = $aside(options);\n\n // Trigger\n element.on(attr.trigger || 'click', aside.toggle);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (aside) aside.destroy();\n options = null;\n aside = null;\n });\n\n }\n };\n\n });\n\n// Source: button/button.js\nangular.module('mgcrea.ngStrap.button', [])\n\n .provider('$button', function() {\n\n var defaults = this.defaults = {\n activeClass:'active',\n toggleEvent:'click'\n };\n\n this.$get = function() {\n return {defaults: defaults};\n };\n\n })\n\n .directive('bsCheckboxGroup', function() {\n\n return {\n restrict: 'A',\n require: 'ngModel',\n compile: function postLink(element, attr) {\n element.attr('data-toggle', 'buttons');\n element.removeAttr('ng-model');\n var children = element[0].querySelectorAll('input[type=\"checkbox\"]');\n angular.forEach(children, function(child) {\n var childEl = angular.element(child);\n childEl.attr('bs-checkbox', '');\n childEl.attr('ng-model', attr.ngModel + '.' + childEl.attr('value'));\n });\n }\n\n };\n\n })\n\n .directive('bsCheckbox', function($button, $$rAF) {\n\n var defaults = $button.defaults;\n var constantValueRegExp = /^(true|false|\\d+)$/;\n\n return {\n restrict: 'A',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n var options = defaults;\n\n // Support label > input[type=\"checkbox\"]\n var isInput = element[0].nodeName === 'INPUT';\n var activeElement = isInput ? element.parent() : element;\n\n var trueValue = angular.isDefined(attr.trueValue) ? attr.trueValue : true;\n if(constantValueRegExp.test(attr.trueValue)) {\n trueValue = scope.$eval(attr.trueValue);\n }\n var falseValue = angular.isDefined(attr.falseValue) ? attr.falseValue : false;\n if(constantValueRegExp.test(attr.falseValue)) {\n falseValue = scope.$eval(attr.falseValue);\n }\n\n // Parse exotic values\n var hasExoticValues = typeof trueValue !== 'boolean' || typeof falseValue !== 'boolean';\n if(hasExoticValues) {\n controller.$parsers.push(function(viewValue) {\n // console.warn('$parser', element.attr('ng-model'), 'viewValue', viewValue);\n return viewValue ? trueValue : falseValue;\n });\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n return angular.equals(modelValue, trueValue);\n });\n // Fix rendering for exotic values\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n controller.$render();\n });\n }\n\n // model -> view\n controller.$render = function () {\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n var isActive = angular.equals(controller.$modelValue, trueValue);\n $$rAF(function() {\n if(isInput) element[0].checked = isActive;\n activeElement.toggleClass(options.activeClass, isActive);\n });\n };\n\n // view -> model\n element.bind(options.toggleEvent, function() {\n scope.$apply(function () {\n // console.warn('!click', element.attr('ng-model'), 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue, 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue);\n if(!isInput) {\n controller.$setViewValue(!activeElement.hasClass('active'));\n }\n if(!hasExoticValues) {\n controller.$render();\n }\n });\n });\n\n }\n\n };\n\n })\n\n .directive('bsRadioGroup', function() {\n\n return {\n restrict: 'A',\n require: 'ngModel',\n compile: function postLink(element, attr) {\n element.attr('data-toggle', 'buttons');\n element.removeAttr('ng-model');\n var children = element[0].querySelectorAll('input[type=\"radio\"]');\n angular.forEach(children, function(child) {\n angular.element(child).attr('bs-radio', '');\n angular.element(child).attr('ng-model', attr.ngModel);\n });\n }\n\n };\n\n })\n\n .directive('bsRadio', function($button, $$rAF) {\n\n var defaults = $button.defaults;\n var constantValueRegExp = /^(true|false|\\d+)$/;\n\n return {\n restrict: 'A',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n var options = defaults;\n\n // Support `label > input[type=\"radio\"]` markup\n var isInput = element[0].nodeName === 'INPUT';\n var activeElement = isInput ? element.parent() : element;\n\n var value;\n attr.$observe('value', function(v) {\n value = constantValueRegExp.test(v) ? scope.$eval(v) : v;\n controller.$render();\n });\n\n // model -> view\n controller.$render = function () {\n // console.warn('$render', element.attr('value'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n var isActive = angular.equals(controller.$modelValue, value);\n $$rAF(function() {\n if(isInput) element[0].checked = isActive;\n activeElement.toggleClass(options.activeClass, isActive);\n });\n };\n\n // view -> model\n element.bind(options.toggleEvent, function() {\n scope.$apply(function () {\n // console.warn('!click', element.attr('value'), 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue, 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue);\n controller.$setViewValue(value);\n controller.$render();\n });\n });\n\n }\n\n };\n\n });\n\n// Source: collapse/collapse.js\nangular.module('mgcrea.ngStrap.collapse', [])\n\n .provider('$collapse', function() {\n\n var defaults = this.defaults = {\n animation: 'am-collapse',\n disallowToggle: false,\n activeClass: 'in',\n startCollapsed: false,\n allowMultiple: false\n };\n\n var controller = this.controller = function($scope, $element, $attrs) {\n var self = this;\n\n // Attributes options\n self.$options = angular.copy(defaults);\n angular.forEach(['animation', 'disallowToggle', 'activeClass', 'startCollapsed', 'allowMultiple'], function (key) {\n if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['disallowToggle', 'startCollapsed', 'allowMultiple'], function(key) {\n if(angular.isDefined($attrs[key]) && falseValueRegExp.test($attrs[key])) {\n self.$options[key] = false;\n }\n });\n\n self.$toggles = [];\n self.$targets = [];\n\n self.$viewChangeListeners = [];\n\n self.$registerToggle = function(element) {\n self.$toggles.push(element);\n };\n self.$registerTarget = function(element) {\n self.$targets.push(element);\n };\n\n self.$unregisterToggle = function(element) {\n var index = self.$toggles.indexOf(element);\n // remove toggle from $toggles array\n self.$toggles.splice(index, 1);\n };\n self.$unregisterTarget = function(element) {\n var index = self.$targets.indexOf(element);\n\n // remove element from $targets array\n self.$targets.splice(index, 1);\n\n if (self.$options.allowMultiple) {\n // remove target index from $active array values\n deactivateItem(element);\n }\n\n // fix active item indexes\n fixActiveItemIndexes(index);\n\n self.$viewChangeListeners.forEach(function(fn) {\n fn();\n });\n };\n\n // use array to store all the currently open panels\n self.$targets.$active = !self.$options.startCollapsed ? [0] : [];\n self.$setActive = $scope.$setActive = function(value) {\n if(angular.isArray(value)) {\n self.$targets.$active = value;\n }\n else if(!self.$options.disallowToggle) {\n // toogle element active status\n isActive(value) ? deactivateItem(value) : activateItem(value);\n } else {\n activateItem(value);\n }\n\n self.$viewChangeListeners.forEach(function(fn) {\n fn();\n });\n };\n\n self.$activeIndexes = function() {\n return self.$options.allowMultiple ? self.$targets.$active :\n self.$targets.$active.length === 1 ? self.$targets.$active[0] : -1;\n };\n\n function fixActiveItemIndexes(index) {\n // item with index was removed, so we\n // need to adjust other items index values\n var activeIndexes = self.$targets.$active;\n for(var i = 0; i < activeIndexes.length; i++) {\n if (index < activeIndexes[i]) {\n activeIndexes[i] = activeIndexes[i] - 1;\n }\n\n // the last item is active, so we need to\n // adjust its index\n if (activeIndexes[i] === self.$targets.length) {\n activeIndexes[i] = self.$targets.length - 1;\n }\n }\n }\n\n function isActive(value) {\n var activeItems = self.$targets.$active;\n return activeItems.indexOf(value) === -1 ? false : true;\n }\n\n function deactivateItem(value) {\n var index = self.$targets.$active.indexOf(value);\n if (index !== -1) {\n self.$targets.$active.splice(index, 1);\n }\n }\n\n function activateItem(value) {\n if (!self.$options.allowMultiple) {\n // remove current selected item\n self.$targets.$active.splice(0, 1);\n }\n\n if (self.$targets.$active.indexOf(value) === -1) {\n self.$targets.$active.push(value);\n }\n }\n\n };\n\n this.$get = function() {\n var $collapse = {};\n $collapse.defaults = defaults;\n $collapse.controller = controller;\n return $collapse;\n };\n\n })\n\n .directive('bsCollapse', function($window, $animate, $collapse) {\n\n var defaults = $collapse.defaults;\n\n return {\n require: ['?ngModel', 'bsCollapse'],\n controller: ['$scope', '$element', '$attrs', $collapse.controller],\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsCollapseCtrl = controllers[1];\n\n if(ngModelCtrl) {\n\n // Update the modelValue following\n bsCollapseCtrl.$viewChangeListeners.push(function() {\n ngModelCtrl.$setViewValue(bsCollapseCtrl.$activeIndexes());\n });\n\n // modelValue -> $formatters -> viewValue\n ngModelCtrl.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n if (angular.isArray(modelValue)) {\n // model value is an array, so just replace\n // the active items directly\n bsCollapseCtrl.$setActive(modelValue);\n }\n else {\n var activeIndexes = bsCollapseCtrl.$activeIndexes();\n\n if (angular.isArray(activeIndexes)) {\n // we have an array of selected indexes\n if (activeIndexes.indexOf(modelValue * 1) === -1) {\n // item with modelValue index is not active\n bsCollapseCtrl.$setActive(modelValue * 1);\n }\n }\n else if (activeIndexes !== modelValue * 1) {\n bsCollapseCtrl.$setActive(modelValue * 1);\n }\n }\n return modelValue;\n });\n\n }\n\n }\n };\n\n })\n\n .directive('bsCollapseToggle', function() {\n\n return {\n require: ['^?ngModel', '^bsCollapse'],\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsCollapseCtrl = controllers[1];\n\n // Add base attr\n element.attr('data-toggle', 'collapse');\n\n // Push pane to parent bsCollapse controller\n bsCollapseCtrl.$registerToggle(element);\n\n // remove toggle from collapse controller when toggle is destroyed\n scope.$on('$destroy', function() {\n bsCollapseCtrl.$unregisterToggle(element);\n });\n\n element.on('click', function() {\n var index = attrs.bsCollapseToggle && attrs.bsCollapseToggle !== 'bs-collapse-toggle' ? attrs.bsCollapseToggle : bsCollapseCtrl.$toggles.indexOf(element);\n bsCollapseCtrl.$setActive(index * 1);\n scope.$apply();\n });\n\n }\n };\n\n })\n\n .directive('bsCollapseTarget', function($animate) {\n\n return {\n require: ['^?ngModel', '^bsCollapse'],\n // scope: true,\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsCollapseCtrl = controllers[1];\n\n // Add base class\n element.addClass('collapse');\n\n // Add animation class\n if(bsCollapseCtrl.$options.animation) {\n element.addClass(bsCollapseCtrl.$options.animation);\n }\n\n // Push pane to parent bsCollapse controller\n bsCollapseCtrl.$registerTarget(element);\n\n // remove pane target from collapse controller when target is destroyed\n scope.$on('$destroy', function() {\n bsCollapseCtrl.$unregisterTarget(element);\n });\n\n function render() {\n var index = bsCollapseCtrl.$targets.indexOf(element);\n var active = bsCollapseCtrl.$activeIndexes();\n var action = 'removeClass';\n if (angular.isArray(active)) {\n if (active.indexOf(index) !== -1) {\n action = 'addClass';\n }\n }\n else if (index === active) {\n action = 'addClass';\n }\n\n $animate[action](element, bsCollapseCtrl.$options.activeClass);\n }\n\n bsCollapseCtrl.$viewChangeListeners.push(function() {\n render();\n });\n render();\n\n }\n };\n\n });\n\n// Source: datepicker/datepicker.js\nangular.module('mgcrea.ngStrap.datepicker', [\n 'mgcrea.ngStrap.helpers.dateParser',\n 'mgcrea.ngStrap.helpers.dateFormatter',\n 'mgcrea.ngStrap.tooltip'])\n\n .provider('$datepicker', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n //uncommenting the following line will break backwards compatability\n // prefixEvent: 'datepicker',\n prefixClass: 'datepicker',\n placement: 'bottom-left',\n templateUrl: 'datepicker/datepicker.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n // lang: $locale.id,\n useNative: false,\n dateType: 'date',\n dateFormat: 'shortDate',\n timezone: null,\n modelDateFormat: null,\n dayFormat: 'dd',\n monthFormat: 'MMM',\n yearFormat: 'yyyy',\n monthTitleFormat: 'MMMM yyyy',\n yearTitleFormat: 'yyyy',\n strictFormat: false,\n autoclose: false,\n minDate: -Infinity,\n maxDate: +Infinity,\n startView: 0,\n minView: 0,\n startWeek: 0,\n daysOfWeekDisabled: '',\n iconLeft: 'glyphicon glyphicon-chevron-left',\n iconRight: 'glyphicon glyphicon-chevron-right'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, datepickerViews, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\n\n function DatepickerFactory(element, controller, config) {\n\n var $datepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $datepicker.$options;\n var scope = $datepicker.$scope;\n if(options.startView) options.startView -= options.minView;\n\n // View vars\n\n var pickerViews = datepickerViews($datepicker);\n $datepicker.$views = pickerViews.views;\n var viewDate = pickerViews.viewDate;\n scope.$mode = options.startView;\n scope.$iconLeft = options.iconLeft;\n scope.$iconRight = options.iconRight;\n var $picker = $datepicker.$views[scope.$mode];\n\n // Scope methods\n\n scope.$select = function(date) {\n $datepicker.select(date);\n };\n scope.$selectPane = function(value) {\n $datepicker.$selectPane(value);\n };\n scope.$toggleMode = function() {\n $datepicker.setMode((scope.$mode + 1) % $datepicker.$views.length);\n };\n\n // Public methods\n\n $datepicker.update = function(date) {\n // console.warn('$datepicker.update() newValue=%o', date);\n if(angular.isDate(date) && !isNaN(date.getTime())) {\n $datepicker.$date = date;\n $picker.update.call($picker, date);\n }\n // Build only if pristine\n $datepicker.$build(true);\n };\n\n $datepicker.updateDisabledDates = function(dateRanges) {\n options.disabledDateRanges = dateRanges;\n for(var i = 0, l = scope.rows.length; i < l; i++) {\n angular.forEach(scope.rows[i], $datepicker.$setDisabledEl);\n }\n };\n\n $datepicker.select = function(date, keep) {\n // console.warn('$datepicker.select', date, scope.$mode);\n if(!angular.isDate(controller.$dateValue)) controller.$dateValue = new Date(date);\n if(!scope.$mode || keep) {\n controller.$setViewValue(angular.copy(date));\n controller.$render();\n if(options.autoclose && !keep) {\n $timeout(function() { $datepicker.hide(true); });\n }\n } else {\n angular.extend(viewDate, {year: date.getFullYear(), month: date.getMonth(), date: date.getDate()});\n $datepicker.setMode(scope.$mode - 1);\n $datepicker.$build();\n }\n };\n\n $datepicker.setMode = function(mode) {\n // console.warn('$datepicker.setMode', mode);\n scope.$mode = mode;\n $picker = $datepicker.$views[scope.$mode];\n $datepicker.$build();\n };\n\n // Protected methods\n\n $datepicker.$build = function(pristine) {\n // console.warn('$datepicker.$build() viewDate=%o', viewDate);\n if(pristine === true && $picker.built) return;\n if(pristine === false && !$picker.built) return;\n $picker.build.call($picker);\n };\n\n $datepicker.$updateSelected = function() {\n for(var i = 0, l = scope.rows.length; i < l; i++) {\n angular.forEach(scope.rows[i], updateSelected);\n }\n };\n\n $datepicker.$isSelected = function(date) {\n return $picker.isSelected(date);\n };\n\n $datepicker.$setDisabledEl = function(el) {\n el.disabled = $picker.isDisabled(el.date);\n };\n\n $datepicker.$selectPane = function(value) {\n var steps = $picker.steps;\n // set targetDate to first day of month to avoid problems with\n // date values rollover. This assumes the viewDate does not\n // depend on the day of the month\n var targetDate = new Date(Date.UTC(viewDate.year + ((steps.year || 0) * value), viewDate.month + ((steps.month || 0) * value), 1));\n angular.extend(viewDate, {year: targetDate.getUTCFullYear(), month: targetDate.getUTCMonth(), date: targetDate.getUTCDate()});\n $datepicker.$build();\n };\n\n $datepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $datepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n if(evt.keyCode === 13) {\n if(!scope.$mode) {\n return $datepicker.hide(true);\n } else {\n return scope.$apply(function() { $datepicker.setMode(scope.$mode - 1); });\n }\n }\n\n // Navigate with keyboard\n $picker.onKeyDown(evt);\n parentScope.$digest();\n };\n\n // Private\n\n function updateSelected(el) {\n el.selected = $datepicker.$isSelected(el.date);\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $datepicker.init;\n $datepicker.init = function() {\n if(isNative && options.useNative) {\n element.prop('type', 'date');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if(isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $datepicker.destroy;\n $datepicker.destroy = function() {\n if(isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $datepicker.show;\n $datepicker.show = function() {\n _show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n // if $datepicker is no longer showing, don't setup events\n if(!$datepicker.$isShown) return;\n $datepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $datepicker.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $datepicker.hide;\n $datepicker.hide = function(blur) {\n if(!$datepicker.$isShown) return;\n $datepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $datepicker.$onKeyDown);\n }\n _hide(blur);\n };\n\n return $datepicker;\n\n }\n\n DatepickerFactory.defaults = defaults;\n return DatepickerFactory;\n\n };\n\n })\n\n .directive('bsDatepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $datepicker) {\n\n var defaults = $datepicker.defaults;\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'autoclose', 'dateType', 'dateFormat', 'timezone', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled', 'id', 'prefixClass', 'prefixEvent'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'autoclose', 'useNative'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!datepicker || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(datepicker),?/i);\n newValue === true ? datepicker.show() : datepicker.hide();\n });\n\n // Initialize datepicker\n var datepicker = $datepicker(element, controller, options);\n options = datepicker.$options;\n // Set expected iOS format\n if(isNative && options.useNative) options.dateFormat = 'yyyy-MM-dd';\n\n var lang = options.lang;\n\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n\n var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});\n\n // Observe attributes for changes\n angular.forEach(['minDate', 'maxDate'], function(key) {\n // console.warn('attr.$observe(%s)', key, attr[key]);\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\n // console.warn('attr.$observe(%s)=%o', key, newValue);\n datepicker.$options[key] = dateParser.getDateForAttribute(key, newValue);\n // Build only if dirty\n !isNaN(datepicker.$options[key]) && datepicker.$build(false);\n validateAgainstMinMaxDate(controller.$dateValue);\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n datepicker.update(controller.$dateValue);\n }, true);\n\n // Normalize undefined/null/empty array,\n // so that we don't treat changing from undefined->null as a change.\n function normalizeDateRanges(ranges) {\n if (!ranges || !ranges.length) return null;\n return ranges;\n }\n\n if (angular.isDefined(attr.disabledDates)) {\n scope.$watch(attr.disabledDates, function(disabledRanges, previousValue) {\n disabledRanges = normalizeDateRanges(disabledRanges);\n previousValue = normalizeDateRanges(previousValue);\n\n if (disabledRanges) {\n datepicker.updateDisabledDates(disabledRanges);\n }\n });\n }\n\n function validateAgainstMinMaxDate(parsedDate) {\n if (!angular.isDate(parsedDate)) return;\n var isMinValid = isNaN(datepicker.$options.minDate) || parsedDate.getTime() >= datepicker.$options.minDate;\n var isMaxValid = isNaN(datepicker.$options.maxDate) || parsedDate.getTime() <= datepicker.$options.maxDate;\n var isValid = isMinValid && isMaxValid;\n controller.$setValidity('date', isValid);\n controller.$setValidity('min', isMinValid);\n controller.$setValidity('max', isMaxValid);\n // Only update the model when we have a valid date\n if(isValid) controller.$dateValue = parsedDate;\n }\n\n // viewValue -> $parsers -> modelValue\n controller.$parsers.unshift(function(viewValue) {\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\n var date;\n // Null values should correctly reset the model value & validity\n if(!viewValue) {\n controller.$setValidity('date', true);\n // BREAKING CHANGE:\n // return null (not undefined) when input value is empty, so angularjs 1.3\n // ngModelController can go ahead and run validators, like ngRequired\n return null;\n }\n var parsedDate = dateParser.parse(viewValue, controller.$dateValue);\n if(!parsedDate || isNaN(parsedDate.getTime())) {\n controller.$setValidity('date', false);\n // return undefined, causes ngModelController to\n // invalidate model value\n return;\n } else {\n validateAgainstMinMaxDate(parsedDate);\n }\n\n if(options.dateType === 'string') {\n date = dateParser.timezoneOffsetAdjust(parsedDate, options.timezone, true);\n return formatDate(date, options.modelDateFormat || options.dateFormat);\n }\n date = dateParser.timezoneOffsetAdjust(controller.$dateValue, options.timezone, true);\n if(options.dateType === 'number') {\n return date.getTime();\n } else if(options.dateType === 'unix') {\n return date.getTime() / 1000;\n } else if(options.dateType === 'iso') {\n return date.toISOString();\n } else {\n return new Date(date);\n }\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var date;\n if(angular.isUndefined(modelValue) || modelValue === null) {\n date = NaN;\n } else if(angular.isDate(modelValue)) {\n date = modelValue;\n } else if(options.dateType === 'string') {\n date = dateParser.parse(modelValue, null, options.modelDateFormat);\n } else if(options.dateType === 'unix') {\n date = new Date(modelValue * 1000);\n } else {\n date = new Date(modelValue);\n }\n // Setup default value?\n // if(isNaN(date.getTime())) {\n // var today = new Date();\n // date = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0, 0);\n // }\n controller.$dateValue = dateParser.timezoneOffsetAdjust(date, options.timezone);\n return getDateFormattedString();\n });\n\n // viewValue -> element\n controller.$render = function() {\n // console.warn('$render(\"%s\"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);\n element.val(getDateFormattedString());\n };\n\n function getDateFormattedString() {\n return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.dateFormat);\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if(datepicker) datepicker.destroy();\n options = null;\n datepicker = null;\n });\n\n }\n };\n\n })\n\n .provider('datepickerViews', function() {\n\n var defaults = this.defaults = {\n dayFormat: 'dd',\n daySplit: 7\n };\n\n // Split array into smaller arrays\n function split(arr, size) {\n var arrays = [];\n while(arr.length > 0) {\n arrays.push(arr.splice(0, size));\n }\n return arrays;\n }\n\n // Modulus operator\n function mod(n, m) {\n return ((n % m) + m) % m;\n }\n\n this.$get = function($dateFormatter, $dateParser, $sce) {\n\n return function(picker) {\n\n var scope = picker.$scope;\n var options = picker.$options;\n\n var lang = options.lang;\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});\n\n var weekDaysMin = $dateFormatter.weekdaysShort(lang);\n var weekDaysLabels = weekDaysMin.slice(options.startWeek).concat(weekDaysMin.slice(0, options.startWeek));\n var weekDaysLabelsHtml = $sce.trustAsHtml('' + weekDaysLabels.join('') + '');\n\n var startDate = picker.$date || (options.startDate ? dateParser.getDateForAttribute('startDate', options.startDate) : new Date());\n var viewDate = {year: startDate.getFullYear(), month: startDate.getMonth(), date: startDate.getDate()};\n\n var views = [{\n format: options.dayFormat,\n split: 7,\n steps: { month: 1 },\n update: function(date, force) {\n if(!this.built || force || date.getFullYear() !== viewDate.year || date.getMonth() !== viewDate.month) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getDate() !== viewDate.date || date.getDate() === 1) {\n // chaging picker current month will cause viewDate.date to be set to first day of the month,\n // in $datepicker.$selectPane, so picker would not update selected day display if\n // user picks first day of the new month.\n // As a workaround, we are always forcing update when picked date is first day of month.\n viewDate.date = picker.$date.getDate();\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstDayOfMonth = new Date(viewDate.year, viewDate.month, 1), firstDayOfMonthOffset = firstDayOfMonth.getTimezoneOffset();\n var firstDate = new Date(+firstDayOfMonth - mod(firstDayOfMonth.getDay() - options.startWeek, 7) * 864e5), firstDateOffset = firstDate.getTimezoneOffset();\n var today = dateParser.timezoneOffsetAdjust(new Date(), options.timezone).toDateString();\n // Handle daylight time switch\n if(firstDateOffset !== firstDayOfMonthOffset) firstDate = new Date(+firstDate + (firstDateOffset - firstDayOfMonthOffset) * 60e3);\n var days = [], day;\n for(var i = 0; i < 42; i++) { // < 7 * 6\n day = dateParser.daylightSavingAdjust(new Date(firstDate.getFullYear(), firstDate.getMonth(), firstDate.getDate() + i));\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)});\n }\n scope.title = formatDate(firstDayOfMonth, options.monthTitleFormat);\n scope.showLabels = true;\n scope.labels = weekDaysLabelsHtml;\n scope.rows = split(days, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth() && date.getDate() === picker.$date.getDate();\n },\n isDisabled: function(date) {\n var time = date.getTime();\n\n // Disabled because of min/max date.\n if (time < options.minDate || time > options.maxDate) return true;\n\n // Disabled due to being a disabled day of the week\n if (options.daysOfWeekDisabled.indexOf(date.getDay()) !== -1) return true;\n\n // Disabled because of disabled date range.\n if (options.disabledDateRanges) {\n for (var i = 0; i < options.disabledDateRanges.length; i++) {\n if (time >= options.disabledDateRanges[i].start && time <= options.disabledDateRanges[i].end) {\n return true;\n }\n }\n }\n\n return false;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualTime = picker.$date.getTime();\n var newDate;\n\n if(evt.keyCode === 37) newDate = new Date(actualTime - 1 * 864e5);\n else if(evt.keyCode === 38) newDate = new Date(actualTime - 7 * 864e5);\n else if(evt.keyCode === 39) newDate = new Date(actualTime + 1 * 864e5);\n else if(evt.keyCode === 40) newDate = new Date(actualTime + 7 * 864e5);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }, {\n name: 'month',\n format: options.monthFormat,\n split: 4,\n steps: { year: 1 },\n update: function(date, force) {\n if(!this.built || date.getFullYear() !== viewDate.year) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getMonth() !== viewDate.month) {\n angular.extend(viewDate, {month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstMonth = new Date(viewDate.year, 0, 1);\n var months = [], month;\n for (var i = 0; i < 12; i++) {\n month = new Date(viewDate.year, i, 1);\n months.push({date: month, label: formatDate(month, this.format), selected: picker.$isSelected(month), disabled: this.isDisabled(month)});\n }\n scope.title = formatDate(month, options.yearTitleFormat);\n scope.showLabels = false;\n scope.rows = split(months, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth();\n },\n isDisabled: function(date) {\n var lastDate = +new Date(date.getFullYear(), date.getMonth() + 1, 0);\n return lastDate < options.minDate || date.getTime() > options.maxDate;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualMonth = picker.$date.getMonth();\n var newDate = new Date(picker.$date);\n\n if(evt.keyCode === 37) newDate.setMonth(actualMonth - 1);\n else if(evt.keyCode === 38) newDate.setMonth(actualMonth - 4);\n else if(evt.keyCode === 39) newDate.setMonth(actualMonth + 1);\n else if(evt.keyCode === 40) newDate.setMonth(actualMonth + 4);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }, {\n name: 'year',\n format: options.yearFormat,\n split: 4,\n steps: { year: 12 },\n update: function(date, force) {\n if(!this.built || force || parseInt(date.getFullYear()/20, 10) !== parseInt(viewDate.year/20, 10)) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getFullYear() !== viewDate.year) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstYear = viewDate.year - viewDate.year % (this.split * 3);\n var years = [], year;\n for (var i = 0; i < 12; i++) {\n year = new Date(firstYear + i, 0, 1);\n years.push({date: year, label: formatDate(year, this.format), selected: picker.$isSelected(year), disabled: this.isDisabled(year)});\n }\n scope.title = years[0].label + '-' + years[years.length - 1].label;\n scope.showLabels = false;\n scope.rows = split(years, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear();\n },\n isDisabled: function(date) {\n var lastDate = +new Date(date.getFullYear() + 1, 0, 0);\n return lastDate < options.minDate || date.getTime() > options.maxDate;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualYear = picker.$date.getFullYear(),\n newDate = new Date(picker.$date);\n\n if(evt.keyCode === 37) newDate.setYear(actualYear - 1);\n else if(evt.keyCode === 38) newDate.setYear(actualYear - 4);\n else if(evt.keyCode === 39) newDate.setYear(actualYear + 1);\n else if(evt.keyCode === 40) newDate.setYear(actualYear + 4);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }];\n\n return {\n views: options.minView ? Array.prototype.slice.call(views, options.minView) : views,\n viewDate: viewDate\n };\n\n };\n\n };\n\n });\n\n// Source: dropdown/dropdown.js\nangular.module('mgcrea.ngStrap.dropdown', ['mgcrea.ngStrap.tooltip'])\n\n .provider('$dropdown', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'dropdown',\n prefixEvent: 'dropdown',\n placement: 'bottom-left',\n templateUrl: 'dropdown/dropdown.tpl.html',\n trigger: 'click',\n container: false,\n keyboard: true,\n html: false,\n delay: 0\n };\n\n this.$get = function($window, $rootScope, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var matchesSelector = Element.prototype.matchesSelector || Element.prototype.webkitMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector;\n\n function DropdownFactory(element, config) {\n\n var $dropdown = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n var scope = $dropdown.$scope = options.scope && options.scope.$new() || $rootScope.$new();\n\n $dropdown = $tooltip(element, options);\n var parentEl = element.parent();\n\n // Protected methods\n\n $dropdown.$onKeyDown = function(evt) {\n if (!/(38|40)/.test(evt.keyCode)) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // Retrieve focused index\n var items = angular.element($dropdown.$element[0].querySelectorAll('li:not(.divider) a'));\n if(!items.length) return;\n var index;\n angular.forEach(items, function(el, i) {\n if(matchesSelector && matchesSelector.call(el, ':focus')) index = i;\n });\n\n // Navigate with keyboard\n if(evt.keyCode === 38 && index > 0) index--;\n else if(evt.keyCode === 40 && index < items.length - 1) index++;\n else if(angular.isUndefined(index)) index = 0;\n items.eq(index)[0].focus();\n\n };\n\n // Overrides\n\n var show = $dropdown.show;\n $dropdown.show = function() {\n show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n options.keyboard && $dropdown.$element && $dropdown.$element.on('keydown', $dropdown.$onKeyDown);\n bodyEl.on('click', onBodyClick);\n }, 0, false);\n parentEl.hasClass('dropdown') && parentEl.addClass('open');\n };\n\n var hide = $dropdown.hide;\n $dropdown.hide = function() {\n if(!$dropdown.$isShown) return;\n options.keyboard && $dropdown.$element && $dropdown.$element.off('keydown', $dropdown.$onKeyDown);\n bodyEl.off('click', onBodyClick);\n parentEl.hasClass('dropdown') && parentEl.removeClass('open');\n hide();\n };\n\n var destroy = $dropdown.destroy;\n $dropdown.destroy = function() {\n bodyEl.off('click', onBodyClick);\n destroy();\n };\n\n // Private functions\n\n function onBodyClick(evt) {\n if(evt.target === element[0]) return;\n return evt.target !== element[0] && $dropdown.hide();\n }\n\n return $dropdown;\n\n }\n\n return DropdownFactory;\n\n };\n\n })\n\n .directive('bsDropdown', function($window, $sce, $dropdown) {\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Support scope as an object\n attr.bsDropdown && scope.$watch(attr.bsDropdown, function(newValue, oldValue) {\n scope.content = newValue;\n }, true);\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!dropdown || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(dropdown),?/i);\n newValue === true ? dropdown.show() : dropdown.hide();\n });\n\n // Initialize dropdown\n var dropdown = $dropdown(element, options);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (dropdown) dropdown.destroy();\n options = null;\n dropdown = null;\n });\n\n }\n };\n\n });\n\n// Source: helpers/compiler.js\n// NOTICE: This file was forked from the angular-material project (github.com/angular/material)\n// MIT Licensed - Copyright (c) 2014-2015 Google, Inc. http://angularjs.org\n\nangular.module('mgcrea.ngStrap.core', [])\n .service('$bsCompiler', bsCompilerService);\n\nfunction bsCompilerService($q, $http, $injector, $compile, $controller, $templateCache) {\n /* jshint validthis: true */\n\n /*\n * @ngdoc service\n * @name $bsCompiler\n * @module material.core\n * @description\n * The $bsCompiler service is an abstraction of angular's compiler, that allows the developer\n * to easily compile an element with a templateUrl, controller, and locals.\n *\n * @usage\n * \n * $bsCompiler.compile({\n * templateUrl: 'modal.html',\n * controller: 'ModalCtrl',\n * locals: {\n * modal: myModalInstance;\n * }\n * }).then(function(compileData) {\n * compileData.element; // modal.html's template in an element\n * compileData.link(myScope); //attach controller & scope to element\n * });\n * \n */\n\n /*\n * @ngdoc method\n * @name $bsCompiler#compile\n * @description A helper to compile an HTML template/templateUrl with a given controller,\n * locals, and scope.\n * @param {object} options An options object, with the following properties:\n *\n * - `controller` - `{(string=|function()=}` Controller fn that should be associated with\n * newly created scope or the name of a registered controller if passed as a string.\n * - `controllerAs` - `{string=}` A controller alias name. If present the controller will be\n * published to scope under the `controllerAs` name.\n * - `template` - `{string=}` An html template as a string.\n * - `templateUrl` - `{string=}` A path to an html template.\n * - `transformTemplate` - `{function(template)=}` A function which transforms the template after\n * it is loaded. It will be given the template string as a parameter, and should\n * return a a new string representing the transformed template.\n * - `resolve` - `{Object.=}` - An optional map of dependencies which should\n * be injected into the controller. If any of these dependencies are promises, the compiler\n * will wait for them all to be resolved, or if one is rejected before the controller is\n * instantiated `compile()` will fail..\n * * `key` - `{string}`: a name of a dependency to be injected into the controller.\n * * `factory` - `{string|function}`: If `string` then it is an alias for a service.\n * Otherwise if function, then it is injected and the return value is treated as the\n * dependency. If the result is a promise, it is resolved before its value is\n * injected into the controller.\n *\n * @returns {object=} promise A promise, which will be resolved with a `compileData` object.\n * `compileData` has the following properties:\n *\n * - `element` - `{element}`: an uncompiled element matching the provided template.\n * - `link` - `{function(scope)}`: A link function, which, when called, will compile\n * the element and instantiate the provided controller (if given).\n * - `locals` - `{object}`: The locals which will be passed into the controller once `link` is\n * called. If `bindToController` is true, they will be coppied to the ctrl instead\n * - `bindToController` - `bool`: bind the locals to the controller, instead of passing them in.\n */\n this.compile = function(options) {\n\n if(options.template && /\\.html$/.test(options.template)) {\n console.warn('Deprecated use of `template` option to pass a file. Please use the `templateUrl` option instead.');\n options.templateUrl = options.template;\n options.template = '';\n }\n\n var templateUrl = options.templateUrl;\n var template = options.template || '';\n var controller = options.controller;\n var controllerAs = options.controllerAs;\n var resolve = angular.copy(options.resolve || {});\n var locals = angular.copy(options.locals || {});\n var transformTemplate = options.transformTemplate || angular.identity;\n var bindToController = options.bindToController;\n\n // Take resolve values and invoke them.\n // Resolves can either be a string (value: 'MyRegisteredAngularConst'),\n // or an invokable 'factory' of sorts: (value: function ValueGetter($dependency) {})\n angular.forEach(resolve, function(value, key) {\n if (angular.isString(value)) {\n resolve[key] = $injector.get(value);\n } else {\n resolve[key] = $injector.invoke(value);\n }\n });\n // Add the locals, which are just straight values to inject\n // eg locals: { three: 3 }, will inject three into the controller\n angular.extend(resolve, locals);\n\n if (templateUrl) {\n resolve.$template = fetchTemplate(templateUrl);\n } else {\n resolve.$template = $q.when(template);\n }\n\n if (options.contentTemplate) {\n // TODO(mgcrea): deprecate?\n resolve.$template = $q.all([resolve.$template, fetchTemplate(options.contentTemplate)])\n .then(function(templates) {\n var templateEl = angular.element(templates[0]);\n var contentEl = findElement('[ng-bind=\"content\"]', templateEl[0]).removeAttr('ng-bind').html(templates[1]);\n // Drop the default footer as you probably don't want it if you use a custom contentTemplate\n if(!options.templateUrl) contentEl.next().remove();\n return templateEl[0].outerHTML;\n });\n }\n\n // Wait for all the resolves to finish if they are promises\n return $q.all(resolve).then(function(locals) {\n\n var template = transformTemplate(locals.$template);\n if (options.html) {\n template = template.replace(/ng-bind=\"/ig, 'ng-bind-html=\"');\n }\n // var element = options.element || angular.element('
').html(template.trim()).contents();\n var element = angular.element('
').html(template.trim()).contents();\n var linkFn = $compile(element);\n\n // Return a linking function that can be used later when the element is ready\n return {\n locals: locals,\n element: element,\n link: function link(scope) {\n locals.$scope = scope;\n\n // Instantiate controller if it exists, because we have scope\n if (controller) {\n var invokeCtrl = $controller(controller, locals, true);\n if (bindToController) {\n angular.extend(invokeCtrl.instance, locals);\n }\n // Support angular@~1.2 invokeCtrl\n var ctrl = angular.isObject(invokeCtrl) ? invokeCtrl : invokeCtrl();\n // See angular-route source for this logic\n element.data('$ngControllerController', ctrl);\n element.children().data('$ngControllerController', ctrl);\n\n if (controllerAs) {\n scope[controllerAs] = ctrl;\n }\n }\n\n return linkFn.apply(null, arguments);\n }\n };\n });\n\n };\n\n function findElement(query, element) {\n return angular.element((element || document).querySelectorAll(query));\n }\n\n var fetchPromises = {};\n function fetchTemplate(template) {\n if(fetchPromises[template]) return fetchPromises[template];\n return (fetchPromises[template] = $http.get(template, {cache: $templateCache})\n .then(function(res) {\n return res.data;\n }));\n }\n\n}\n\n// Source: helpers/date-formatter.js\nangular.module('mgcrea.ngStrap.helpers.dateFormatter', [])\n\n .service('$dateFormatter', function($locale, dateFilter) {\n\n // The unused `lang` arguments are on purpose. The default implementation does not\n // use them and it always uses the locale loaded into the `$locale` service.\n // Custom implementations might use it, thus allowing different directives to\n // have different languages.\n\n this.getDefaultLocale = function() {\n return $locale.id;\n };\n\n // Format is either a data format name, e.g. \"shortTime\" or \"fullDate\", or a date format\n // Return either the corresponding date format or the given date format.\n this.getDatetimeFormat = function(format, lang) {\n return $locale.DATETIME_FORMATS[format] || format;\n };\n\n this.weekdaysShort = function(lang) {\n return $locale.DATETIME_FORMATS.SHORTDAY;\n };\n\n function splitTimeFormat(format) {\n return /(h+)([:\\.])?(m+)([:\\.])?(s*)[ ]?(a?)/i.exec(format).slice(1);\n }\n\n // h:mm a => h\n this.hoursFormat = function(timeFormat) {\n return splitTimeFormat(timeFormat)[0];\n };\n\n // h:mm a => mm\n this.minutesFormat = function(timeFormat) {\n return splitTimeFormat(timeFormat)[2];\n };\n\n // h:mm:ss a => ss\n this.secondsFormat = function(timeFormat) {\n return splitTimeFormat(timeFormat)[4];\n };\n\n // h:mm a => :\n this.timeSeparator = function(timeFormat) {\n return splitTimeFormat(timeFormat)[1];\n };\n\n // h:mm:ss a => true, h:mm a => false\n this.showSeconds = function(timeFormat) {\n return !!splitTimeFormat(timeFormat)[4];\n };\n\n // h:mm a => true, H.mm => false\n this.showAM = function(timeFormat) {\n return !!splitTimeFormat(timeFormat)[5];\n };\n\n this.formatDate = function(date, format, lang, timezone){\n return dateFilter(date, format, timezone);\n };\n\n });\n\n// Source: helpers/date-parser.js\nangular.module('mgcrea.ngStrap.helpers.dateParser', [])\n\n.provider('$dateParser', function($localeProvider) {\n\n // define a custom ParseDate object to use instead of native Date\n // to avoid date values wrapping when setting date component values\n function ParseDate() {\n this.year = 1970;\n this.month = 0;\n this.day = 1;\n this.hours = 0;\n this.minutes = 0;\n this.seconds = 0;\n this.milliseconds = 0;\n }\n\n ParseDate.prototype.setMilliseconds = function(value) { this.milliseconds = value; };\n ParseDate.prototype.setSeconds = function(value) { this.seconds = value; };\n ParseDate.prototype.setMinutes = function(value) { this.minutes = value; };\n ParseDate.prototype.setHours = function(value) { this.hours = value; };\n ParseDate.prototype.getHours = function() { return this.hours; };\n ParseDate.prototype.setDate = function(value) { this.day = value; };\n ParseDate.prototype.setMonth = function(value) { this.month = value; };\n ParseDate.prototype.setFullYear = function(value) { this.year = value; };\n ParseDate.prototype.fromDate = function(value) {\n this.year = value.getFullYear();\n this.month = value.getMonth();\n this.day = value.getDate();\n this.hours = value.getHours();\n this.minutes = value.getMinutes();\n this.seconds = value.getSeconds();\n this.milliseconds = value.getMilliseconds();\n return this;\n };\n\n ParseDate.prototype.toDate = function() {\n return new Date(this.year, this.month, this.day, this.hours, this.minutes, this.seconds, this.milliseconds);\n };\n\n var proto = ParseDate.prototype;\n\n function noop() {\n }\n\n function isNumeric(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n }\n\n function indexOfCaseInsensitive(array, value) {\n var len = array.length, str=value.toString().toLowerCase();\n for (var i=0; i 12 when midnight changeover, but then cannot generate\n * midnight datetime, so jump to 1AM, otherwise reset.\n * @param date (Date) the date to check\n * @return (Date) the corrected date\n *\n * __ copied from jquery ui datepicker __\n */\n $dateParser.daylightSavingAdjust = function(date) {\n if (!date) {\n return null;\n }\n date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);\n return date;\n };\n\n /* Correct the date for timezone offset.\n * @param date (Date) the date to adjust\n * @param timezone (string) the timezone to adjust for\n * @param undo (boolean) to add or subtract timezone offset\n * @return (Date) the corrected date\n */\n $dateParser.timezoneOffsetAdjust = function(date, timezone, undo) {\n if (!date) {\n return null;\n }\n // Right now, only 'UTC' is supported.\n if (timezone && timezone === 'UTC') {\n date = new Date(date.getTime());\n date.setMinutes(date.getMinutes() + (undo?-1:1)*date.getTimezoneOffset());\n }\n return date;\n };\n\n // Private functions\n\n function setMapForFormat(format) {\n var keys = Object.keys(setFnMap), i;\n var map = [], sortedMap = [];\n // Map to setFn\n var clonedFormat = format;\n for(i = 0; i < keys.length; i++) {\n if(format.split(keys[i]).length > 1) {\n var index = clonedFormat.search(keys[i]);\n format = format.split(keys[i]).join('');\n if(setFnMap[keys[i]]) {\n map[index] = setFnMap[keys[i]];\n }\n }\n }\n // Sort result map\n angular.forEach(map, function(v) {\n // conditional required since angular.forEach broke around v1.2.21\n // related pr: https://github.com/angular/angular.js/pull/8525\n if(v) sortedMap.push(v);\n });\n return sortedMap;\n }\n\n function escapeReservedSymbols(text) {\n return text.replace(/\\//g, '[\\\\/]').replace('/-/g', '[-]').replace(/\\./g, '[.]').replace(/\\\\s/g, '[\\\\s]');\n }\n\n function regExpForFormat(format) {\n var keys = Object.keys(regExpMap), i;\n\n var re = format;\n // Abstract replaces to avoid collisions\n for(i = 0; i < keys.length; i++) {\n re = re.split(keys[i]).join('${' + i + '}');\n }\n // Replace abstracted values\n for(i = 0; i < keys.length; i++) {\n re = re.split('${' + i + '}').join('(' + regExpMap[keys[i]] + ')');\n }\n format = escapeReservedSymbols(format);\n\n return new RegExp('^' + re + '$', ['i']);\n }\n\n $dateParser.init();\n return $dateParser;\n\n };\n\n return DateParserFactory;\n\n };\n\n});\n\n// Source: helpers/debounce.js\nangular.module('mgcrea.ngStrap.helpers.debounce', [])\n\n// @source jashkenas/underscore\n// @url https://github.com/jashkenas/underscore/blob/1.5.2/underscore.js#L693\n.factory('debounce', function($timeout) {\n return function(func, wait, immediate) {\n var timeout = null;\n return function() {\n var context = this,\n args = arguments,\n callNow = immediate && !timeout;\n if(timeout) {\n $timeout.cancel(timeout);\n }\n timeout = $timeout(function later() {\n timeout = null;\n if(!immediate) {\n func.apply(context, args);\n }\n }, wait, false);\n if(callNow) {\n func.apply(context, args);\n }\n return timeout;\n };\n };\n})\n\n\n// @source jashkenas/underscore\n// @url https://github.com/jashkenas/underscore/blob/1.5.2/underscore.js#L661\n.factory('throttle', function($timeout) {\n return function(func, wait, options) {\n var timeout = null;\n options || (options = {});\n return function() {\n var context = this,\n args = arguments;\n if(!timeout) {\n if(options.leading !== false) {\n func.apply(context, args);\n }\n timeout = $timeout(function later() {\n timeout = null;\n if(options.trailing !== false) {\n func.apply(context, args);\n }\n }, wait, false);\n }\n };\n };\n});\n\n// Source: helpers/dimensions.js\nangular.module('mgcrea.ngStrap.helpers.dimensions', [])\n\n .factory('dimensions', function($document, $window) {\n\n var jqLite = angular.element;\n var fn = {};\n\n /**\n * Test the element nodeName\n * @param element\n * @param name\n */\n var nodeName = fn.nodeName = function(element, name) {\n return element.nodeName && element.nodeName.toLowerCase() === name.toLowerCase();\n };\n\n /**\n * Returns the element computed style\n * @param element\n * @param prop\n * @param extra\n */\n fn.css = function(element, prop, extra) {\n var value;\n if (element.currentStyle) { //IE\n value = element.currentStyle[prop];\n } else if (window.getComputedStyle) {\n value = window.getComputedStyle(element)[prop];\n } else {\n value = element.style[prop];\n }\n return extra === true ? parseFloat(value) || 0 : value;\n };\n\n /**\n * Provides read-only equivalent of jQuery's offset function:\n * @required-by bootstrap-tooltip, bootstrap-affix\n * @url http://api.jquery.com/offset/\n * @param element\n */\n fn.offset = function(element) {\n var boxRect = element.getBoundingClientRect();\n var docElement = element.ownerDocument;\n return {\n width: boxRect.width || element.offsetWidth,\n height: boxRect.height || element.offsetHeight,\n top: boxRect.top + (window.pageYOffset || docElement.documentElement.scrollTop) - (docElement.documentElement.clientTop || 0),\n left: boxRect.left + (window.pageXOffset || docElement.documentElement.scrollLeft) - (docElement.documentElement.clientLeft || 0)\n };\n };\n \n /**\n * Provides set equivalent of jQuery's offset function:\n * @required-by bootstrap-tooltip\n * @url http://api.jquery.com/offset/\n * @param element\n * @param options\n * @param i\n */\n fn.setOffset = function (element, options, i) {\n var curPosition,\n curLeft,\n curCSSTop,\n curTop,\n curOffset,\n curCSSLeft,\n calculatePosition,\n position = fn.css(element, 'position'),\n curElem = angular.element(element),\n props = {};\n \n // Set position first, in-case top/left are set even on static elem\n if (position === 'static') {\n element.style.position = 'relative';\n }\n \n curOffset = fn.offset(element);\n curCSSTop = fn.css(element, 'top');\n curCSSLeft = fn.css(element, 'left');\n calculatePosition = (position === 'absolute' || position === 'fixed') && \n (curCSSTop + curCSSLeft).indexOf('auto') > -1;\n \n // Need to be able to calculate position if either\n // top or left is auto and position is either absolute or fixed\n if (calculatePosition) {\n curPosition = fn.position(element);\n curTop = curPosition.top;\n curLeft = curPosition.left;\n } else {\n curTop = parseFloat(curCSSTop) || 0;\n curLeft = parseFloat(curCSSLeft) || 0;\n }\n \n if (angular.isFunction(options)) {\n options = options.call(element, i, curOffset);\n }\n \n if (options.top !== null ) {\n props.top = (options.top - curOffset.top) + curTop;\n }\n if ( options.left !== null ) {\n props.left = (options.left - curOffset.left) + curLeft;\n }\n\n if ('using' in options) {\n options.using.call(curElem, props);\n } else {\n curElem.css({\n top: props.top + 'px',\n left: props.left + 'px'\n });\n }\n };\n\n /**\n * Provides read-only equivalent of jQuery's position function\n * @required-by bootstrap-tooltip, bootstrap-affix\n * @url http://api.jquery.com/offset/\n * @param element\n */\n fn.position = function(element) {\n\n var offsetParentRect = {top: 0, left: 0},\n offsetParentElement,\n offset;\n\n // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent\n if (fn.css(element, 'position') === 'fixed') {\n\n // We assume that getBoundingClientRect is available when computed position is fixed\n offset = element.getBoundingClientRect();\n\n } else {\n\n // Get *real* offsetParentElement\n offsetParentElement = offsetParent(element);\n\n // Get correct offsets\n offset = fn.offset(element);\n if (!nodeName(offsetParentElement, 'html')) {\n offsetParentRect = fn.offset(offsetParentElement);\n }\n\n // Add offsetParent borders\n offsetParentRect.top += fn.css(offsetParentElement, 'borderTopWidth', true);\n offsetParentRect.left += fn.css(offsetParentElement, 'borderLeftWidth', true);\n }\n\n // Subtract parent offsets and element margins\n return {\n width: element.offsetWidth,\n height: element.offsetHeight,\n top: offset.top - offsetParentRect.top - fn.css(element, 'marginTop', true),\n left: offset.left - offsetParentRect.left - fn.css(element, 'marginLeft', true)\n };\n\n };\n\n /**\n * Returns the closest, non-statically positioned offsetParent of a given element\n * @required-by fn.position\n * @param element\n */\n var offsetParent = function offsetParentElement(element) {\n var docElement = element.ownerDocument;\n var offsetParent = element.offsetParent || docElement;\n if(nodeName(offsetParent, '#document')) return docElement.documentElement;\n while(offsetParent && !nodeName(offsetParent, 'html') && fn.css(offsetParent, 'position') === 'static') {\n offsetParent = offsetParent.offsetParent;\n }\n return offsetParent || docElement.documentElement;\n };\n\n /**\n * Provides equivalent of jQuery's height function\n * @required-by bootstrap-affix\n * @url http://api.jquery.com/height/\n * @param element\n * @param outer\n */\n fn.height = function(element, outer) {\n var value = element.offsetHeight;\n if(outer) {\n value += fn.css(element, 'marginTop', true) + fn.css(element, 'marginBottom', true);\n } else {\n value -= fn.css(element, 'paddingTop', true) + fn.css(element, 'paddingBottom', true) + fn.css(element, 'borderTopWidth', true) + fn.css(element, 'borderBottomWidth', true);\n }\n return value;\n };\n\n /**\n * Provides equivalent of jQuery's width function\n * @required-by bootstrap-affix\n * @url http://api.jquery.com/width/\n * @param element\n * @param outer\n */\n fn.width = function(element, outer) {\n var value = element.offsetWidth;\n if(outer) {\n value += fn.css(element, 'marginLeft', true) + fn.css(element, 'marginRight', true);\n } else {\n value -= fn.css(element, 'paddingLeft', true) + fn.css(element, 'paddingRight', true) + fn.css(element, 'borderLeftWidth', true) + fn.css(element, 'borderRightWidth', true);\n }\n return value;\n };\n\n return fn;\n\n });\n\n// Source: helpers/parse-options.js\nangular.module('mgcrea.ngStrap.helpers.parseOptions', [])\n\n .provider('$parseOptions', function() {\n\n var defaults = this.defaults = {\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+(.*?))?$/\n };\n\n this.$get = function($parse, $q) {\n\n function ParseOptionsFactory(attr, config) {\n\n var $parseOptions = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n $parseOptions.$values = [];\n\n // Private vars\n var match, displayFn, valueName, keyName, groupByFn, valueFn, valuesFn;\n\n $parseOptions.init = function() {\n $parseOptions.$match = match = attr.match(options.regexp);\n displayFn = $parse(match[2] || match[1]),\n valueName = match[4] || match[6],\n keyName = match[5],\n groupByFn = $parse(match[3] || ''),\n valueFn = $parse(match[2] ? match[1] : valueName),\n valuesFn = $parse(match[7]);\n };\n\n $parseOptions.valuesFn = function(scope, controller) {\n var valuesPromise;\n try {\n // Might throw 'notarray' error since cea8e75\n valuesPromise = valuesFn(scope, controller);\n } catch(err) {\n valuesPromise = [];\n }\n return $q.when(valuesPromise)\n .then(function(values) {\n if(!angular.isArray(values)) {\n values = [];\n }\n $parseOptions.$values = values.length ? parseValues(values, scope) : [];\n return $parseOptions.$values;\n });\n };\n\n $parseOptions.displayValue = function(modelValue) {\n var scope = {};\n scope[valueName] = modelValue;\n return displayFn(scope);\n };\n\n // Private functions\n\n function parseValues(values, scope) {\n return values.map(function(match, index) {\n var locals = {}, label, value;\n locals[valueName] = match;\n label = displayFn(scope, locals);\n value = valueFn(scope, locals);\n return {label: label, value: value, index: index};\n });\n }\n\n $parseOptions.init();\n return $parseOptions;\n\n }\n\n return ParseOptionsFactory;\n\n };\n\n });\n\n// Source: helpers/raf.js\n(angular.version.minor < 3 && angular.version.dot < 14) && angular.module('ng')\n\n.factory('$$rAF', function($window, $timeout) {\n\n var requestAnimationFrame = $window.requestAnimationFrame ||\n $window.webkitRequestAnimationFrame ||\n $window.mozRequestAnimationFrame;\n\n var cancelAnimationFrame = $window.cancelAnimationFrame ||\n $window.webkitCancelAnimationFrame ||\n $window.mozCancelAnimationFrame ||\n $window.webkitCancelRequestAnimationFrame;\n\n var rafSupported = !!requestAnimationFrame;\n var raf = rafSupported ?\n function(fn) {\n var id = requestAnimationFrame(fn);\n return function() {\n cancelAnimationFrame(id);\n };\n } :\n function(fn) {\n var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666\n return function() {\n $timeout.cancel(timer);\n };\n };\n\n raf.supported = rafSupported;\n\n return raf;\n\n});\n\n// .factory('$$animateReflow', function($$rAF, $document) {\n\n// var bodyEl = $document[0].body;\n\n// return function(fn) {\n// //the returned function acts as the cancellation function\n// return $$rAF(function() {\n// //the line below will force the browser to perform a repaint\n// //so that all the animated elements within the animation frame\n// //will be properly updated and drawn on screen. This is\n// //required to perform multi-class CSS based animations with\n// //Firefox. DO NOT REMOVE THIS LINE.\n// var a = bodyEl.offsetWidth + 1;\n// fn();\n// });\n// };\n\n// });\n\n// Source: modal/modal.js\nangular.module('mgcrea.ngStrap.modal', ['mgcrea.ngStrap.core', 'mgcrea.ngStrap.helpers.dimensions'])\n\n .provider('$modal', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n backdropAnimation: 'am-fade',\n prefixClass: 'modal',\n prefixEvent: 'modal',\n placement: 'top',\n templateUrl: 'modal/modal.tpl.html',\n template: '',\n contentTemplate: false,\n container: false,\n element: null,\n backdrop: true,\n keyboard: true,\n html: false,\n show: true\n };\n\n this.$get = function($window, $rootScope, $bsCompiler, $q, $templateCache, $http, $animate, $timeout, $sce, dimensions) {\n\n var forEach = angular.forEach;\n var trim = String.prototype.trim;\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n var bodyElement = angular.element($window.document.body);\n\n function ModalFactory(config) {\n\n var $modal = {};\n\n // Common vars\n var options = $modal.$options = angular.extend({}, defaults, config);\n var promise = $modal.$promise = $bsCompiler.compile(options);\n var scope = $modal.$scope = options.scope && options.scope.$new() || $rootScope.$new();\n\n if(!options.element && !options.container) {\n options.container = 'body';\n }\n\n // Store $id to identify the triggering element in events\n // give priority to options.id, otherwise, try to use\n // element id if defined\n $modal.$id = options.id || options.element && options.element.attr('id') || '';\n\n // Support scope as string options\n forEach(['title', 'content'], function(key) {\n if(options[key]) scope[key] = $sce.trustAsHtml(options[key]);\n });\n\n // Provide scope helpers\n scope.$hide = function() {\n scope.$$postDigest(function() {\n $modal.hide();\n });\n };\n scope.$show = function() {\n scope.$$postDigest(function() {\n $modal.show();\n });\n };\n scope.$toggle = function() {\n scope.$$postDigest(function() {\n $modal.toggle();\n });\n };\n // Publish isShown as a protected var on scope\n $modal.$isShown = scope.$isShown = false;\n\n // Fetch, compile then initialize modal\n var compileData, modalElement, modalScope;\n var backdropElement = angular.element('
');\n backdropElement.css({position:'fixed', top:'0px', left:'0px', bottom:'0px', right:'0px', 'z-index': 1038});\n promise.then(function(data) {\n compileData = data;\n $modal.init();\n });\n\n $modal.init = function() {\n\n // Options: show\n if(options.show) {\n scope.$$postDigest(function() {\n $modal.show();\n });\n }\n\n };\n\n $modal.destroy = function() {\n\n // Remove element\n destroyModalElement();\n\n // remove backdrop element\n if(backdropElement) {\n backdropElement.remove();\n backdropElement = null;\n }\n\n // Destroy scope\n scope.$destroy();\n };\n\n $modal.show = function() {\n if($modal.$isShown) return;\n\n var parent, after;\n if(angular.isElement(options.container)) {\n parent = options.container;\n after = options.container[0].lastChild ? angular.element(options.container[0].lastChild) : null;\n } else {\n if (options.container) {\n parent = findElement(options.container);\n after = parent[0] && parent[0].lastChild ? angular.element(parent[0].lastChild) : null;\n } else {\n parent = null;\n after = options.element;\n }\n }\n\n // destroy any existing modal elements\n if(modalElement) destroyModalElement();\n\n // create a new scope, so we can destroy it and all child scopes\n // when destroying the modal element\n modalScope = $modal.$scope.$new();\n // Fetch a cloned element linked from template (noop callback is required)\n modalElement = $modal.$element = compileData.link(modalScope, function(clonedElement, scope) {});\n\n if(scope.$emit(options.prefixEvent + '.show.before', $modal).defaultPrevented) {\n return;\n }\n\n // Set the initial positioning.\n modalElement.css({display: 'block'}).addClass(options.placement);\n\n // Options: animation\n if(options.animation) {\n if(options.backdrop) {\n backdropElement.addClass(options.backdropAnimation);\n }\n modalElement.addClass(options.animation);\n }\n\n if(options.backdrop) {\n $animate.enter(backdropElement, bodyElement, null);\n }\n\n // Support v1.2+ $animate\n // https://github.com/angular/angular.js/issues/11713\n if(angular.version.minor <= 2) {\n $animate.enter(modalElement, parent, after, enterAnimateCallback);\n } else {\n $animate.enter(modalElement, parent, after).then(enterAnimateCallback);\n }\n\n $modal.$isShown = scope.$isShown = true;\n safeDigest(scope);\n // Focus once the enter-animation has started\n // Weird PhantomJS bug hack\n var el = modalElement[0];\n requestAnimationFrame(function() {\n el.focus();\n });\n\n bodyElement.addClass(options.prefixClass + '-open');\n if(options.animation) {\n bodyElement.addClass(options.prefixClass + '-with-' + options.animation);\n }\n\n // Bind events\n bindBackdropEvents();\n bindKeyboardEvents();\n };\n\n function enterAnimateCallback() {\n scope.$emit(options.prefixEvent + '.show', $modal);\n }\n\n $modal.hide = function() {\n if(!$modal.$isShown) return;\n\n if(scope.$emit(options.prefixEvent + '.hide.before', $modal).defaultPrevented) {\n return;\n }\n\n // Support v1.2+ $animate\n // https://github.com/angular/angular.js/issues/11713\n if(angular.version.minor <= 2) {\n $animate.leave(modalElement, leaveAnimateCallback);\n } else {\n $animate.leave(modalElement).then(leaveAnimateCallback);\n }\n\n if(options.backdrop) {\n $animate.leave(backdropElement);\n }\n $modal.$isShown = scope.$isShown = false;\n safeDigest(scope);\n\n // Unbind events\n unbindBackdropEvents();\n unbindKeyboardEvents();\n };\n\n function leaveAnimateCallback() {\n scope.$emit(options.prefixEvent + '.hide', $modal);\n bodyElement.removeClass(options.prefixClass + '-open');\n if(options.animation) {\n bodyElement.removeClass(options.prefixClass + '-with-' + options.animation);\n }\n }\n\n $modal.toggle = function() {\n\n $modal.$isShown ? $modal.hide() : $modal.show();\n\n };\n\n $modal.focus = function() {\n modalElement[0].focus();\n };\n\n // Protected methods\n\n $modal.$onKeyUp = function(evt) {\n\n if (evt.which === 27 && $modal.$isShown) {\n $modal.hide();\n evt.stopPropagation();\n }\n\n };\n\n function bindBackdropEvents() {\n if(options.backdrop) {\n modalElement.on('click', hideOnBackdropClick);\n backdropElement.on('click', hideOnBackdropClick);\n backdropElement.on('wheel', preventEventDefault);\n }\n }\n\n function unbindBackdropEvents() {\n if(options.backdrop) {\n modalElement.off('click', hideOnBackdropClick);\n backdropElement.off('click', hideOnBackdropClick);\n backdropElement.off('wheel', preventEventDefault);\n }\n }\n\n function bindKeyboardEvents() {\n if(options.keyboard) {\n modalElement.on('keyup', $modal.$onKeyUp);\n }\n }\n\n function unbindKeyboardEvents() {\n if(options.keyboard) {\n modalElement.off('keyup', $modal.$onKeyUp);\n }\n }\n\n // Private methods\n\n function hideOnBackdropClick(evt) {\n if(evt.target !== evt.currentTarget) return;\n options.backdrop === 'static' ? $modal.focus() : $modal.hide();\n }\n\n function preventEventDefault(evt) {\n evt.preventDefault();\n }\n\n function destroyModalElement() {\n if($modal.$isShown && modalElement !== null) {\n // un-bind events\n unbindBackdropEvents();\n unbindKeyboardEvents();\n }\n\n if(modalScope) {\n modalScope.$destroy();\n modalScope = null;\n }\n\n if(modalElement) {\n modalElement.remove();\n modalElement = $modal.$element = null;\n }\n }\n\n return $modal;\n\n }\n\n // Helper functions\n\n function safeDigest(scope) {\n scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();\n }\n\n function findElement(query, element) {\n return angular.element((element || document).querySelectorAll(query));\n }\n\n return ModalFactory;\n\n };\n\n })\n\n .directive('bsModal', function($window, $sce, $modal) {\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope, element: element, show: false};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'controller', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation', 'id', 'prefixEvent', 'prefixClass'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['backdrop', 'keyboard', 'html', 'container'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Support scope as data-attrs\n angular.forEach(['title', 'content'], function(key) {\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\n scope[key] = $sce.trustAsHtml(newValue);\n });\n });\n\n // Support scope as an object\n attr.bsModal && scope.$watch(attr.bsModal, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.content = newValue;\n }\n }, true);\n\n // Initialize modal\n var modal = $modal(options);\n\n // Trigger\n element.on(attr.trigger || 'click', modal.toggle);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (modal) modal.destroy();\n options = null;\n modal = null;\n });\n\n }\n };\n\n });\n\n// Source: navbar/navbar.js\nangular.module('mgcrea.ngStrap.navbar', [])\n\n .provider('$navbar', function() {\n\n var defaults = this.defaults = {\n activeClass: 'active',\n routeAttr: 'data-match-route',\n strict: false\n };\n\n this.$get = function() {\n return {defaults: defaults};\n };\n\n })\n\n .directive('bsNavbar', function($window, $location, $navbar) {\n\n var defaults = $navbar.defaults;\n\n return {\n restrict: 'A',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = angular.copy(defaults);\n angular.forEach(Object.keys(defaults), function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Watch for the $location\n scope.$watch(function() {\n\n return $location.path();\n\n }, function(newValue, oldValue) {\n\n var liElements = element[0].querySelectorAll('li[' + options.routeAttr + ']');\n\n angular.forEach(liElements, function(li) {\n\n var liElement = angular.element(li);\n var pattern = liElement.attr(options.routeAttr).replace('/', '\\\\/');\n if(options.strict) {\n pattern = '^' + pattern + '$';\n }\n var regexp = new RegExp(pattern, 'i');\n\n if(regexp.test(newValue)) {\n liElement.addClass(options.activeClass);\n } else {\n liElement.removeClass(options.activeClass);\n }\n\n });\n\n });\n\n }\n\n };\n\n });\n\n// Source: scrollspy/scrollspy.js\nangular.module('mgcrea.ngStrap.scrollspy', ['mgcrea.ngStrap.helpers.debounce', 'mgcrea.ngStrap.helpers.dimensions'])\n\n .provider('$scrollspy', function() {\n\n // Pool of registered spies\n var spies = this.$$spies = {};\n\n var defaults = this.defaults = {\n debounce: 150,\n throttle: 100,\n offset: 100\n };\n\n this.$get = function($window, $document, $rootScope, dimensions, debounce, throttle) {\n\n var windowEl = angular.element($window);\n var docEl = angular.element($document.prop('documentElement'));\n var bodyEl = angular.element($window.document.body);\n\n // Helper functions\n\n function nodeName(element, name) {\n return element[0].nodeName && element[0].nodeName.toLowerCase() === name.toLowerCase();\n }\n\n function ScrollSpyFactory(config) {\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n if(!options.element) options.element = bodyEl;\n var isWindowSpy = nodeName(options.element, 'body');\n var scrollEl = isWindowSpy ? windowEl : options.element;\n var scrollId = isWindowSpy ? 'window' : options.id;\n\n // Use existing spy\n if(spies[scrollId]) {\n spies[scrollId].$$count++;\n return spies[scrollId];\n }\n\n var $scrollspy = {};\n\n // Private vars\n var unbindViewContentLoaded, unbindIncludeContentLoaded;\n var trackedElements = $scrollspy.$trackedElements = [];\n var sortedElements = [];\n var activeTarget;\n var debouncedCheckPosition;\n var throttledCheckPosition;\n var debouncedCheckOffsets;\n var viewportHeight;\n var scrollTop;\n\n $scrollspy.init = function() {\n\n // Setup internal ref counter\n this.$$count = 1;\n\n // Bind events\n debouncedCheckPosition = debounce(this.checkPosition, options.debounce);\n throttledCheckPosition = throttle(this.checkPosition, options.throttle);\n scrollEl.on('click', this.checkPositionWithEventLoop);\n windowEl.on('resize', debouncedCheckPosition);\n scrollEl.on('scroll', throttledCheckPosition);\n\n debouncedCheckOffsets = debounce(this.checkOffsets, options.debounce);\n unbindViewContentLoaded = $rootScope.$on('$viewContentLoaded', debouncedCheckOffsets);\n unbindIncludeContentLoaded = $rootScope.$on('$includeContentLoaded', debouncedCheckOffsets);\n debouncedCheckOffsets();\n\n // Register spy for reuse\n if(scrollId) {\n spies[scrollId] = $scrollspy;\n }\n\n };\n\n $scrollspy.destroy = function() {\n\n // Check internal ref counter\n this.$$count--;\n if(this.$$count > 0) {\n return;\n }\n\n // Unbind events\n scrollEl.off('click', this.checkPositionWithEventLoop);\n windowEl.off('resize', debouncedCheckPosition);\n scrollEl.off('scroll', throttledCheckPosition);\n unbindViewContentLoaded();\n unbindIncludeContentLoaded();\n if (scrollId) {\n delete spies[scrollId];\n }\n };\n\n $scrollspy.checkPosition = function() {\n\n // Not ready yet\n if(!sortedElements.length) return;\n\n // Calculate the scroll position\n scrollTop = (isWindowSpy ? $window.pageYOffset : scrollEl.prop('scrollTop')) || 0;\n\n // Calculate the viewport height for use by the components\n viewportHeight = Math.max($window.innerHeight, docEl.prop('clientHeight'));\n\n // Activate first element if scroll is smaller\n if(scrollTop < sortedElements[0].offsetTop && activeTarget !== sortedElements[0].target) {\n return $scrollspy.$activateElement(sortedElements[0]);\n }\n\n // Activate proper element\n for (var i = sortedElements.length; i--;) {\n if(angular.isUndefined(sortedElements[i].offsetTop) || sortedElements[i].offsetTop === null) continue;\n if(activeTarget === sortedElements[i].target) continue;\n if(scrollTop < sortedElements[i].offsetTop) continue;\n if(sortedElements[i + 1] && scrollTop > sortedElements[i + 1].offsetTop) continue;\n return $scrollspy.$activateElement(sortedElements[i]);\n }\n\n };\n\n $scrollspy.checkPositionWithEventLoop = function() {\n // IE 9 throws an error if we use 'this' instead of '$scrollspy'\n // in this setTimeout call\n setTimeout($scrollspy.checkPosition, 1);\n };\n\n // Protected methods\n\n $scrollspy.$activateElement = function(element) {\n if(activeTarget) {\n var activeElement = $scrollspy.$getTrackedElement(activeTarget);\n if(activeElement) {\n activeElement.source.removeClass('active');\n if(nodeName(activeElement.source, 'li') && nodeName(activeElement.source.parent().parent(), 'li')) {\n activeElement.source.parent().parent().removeClass('active');\n }\n }\n }\n activeTarget = element.target;\n element.source.addClass('active');\n if(nodeName(element.source, 'li') && nodeName(element.source.parent().parent(), 'li')) {\n element.source.parent().parent().addClass('active');\n }\n };\n\n $scrollspy.$getTrackedElement = function(target) {\n return trackedElements.filter(function(obj) {\n return obj.target === target;\n })[0];\n };\n\n // Track offsets behavior\n\n $scrollspy.checkOffsets = function() {\n\n angular.forEach(trackedElements, function(trackedElement) {\n var targetElement = document.querySelector(trackedElement.target);\n trackedElement.offsetTop = targetElement ? dimensions.offset(targetElement).top : null;\n if(options.offset && trackedElement.offsetTop !== null) trackedElement.offsetTop -= options.offset * 1;\n });\n\n sortedElements = trackedElements\n .filter(function(el) {\n return el.offsetTop !== null;\n })\n .sort(function(a, b) {\n return a.offsetTop - b.offsetTop;\n });\n\n debouncedCheckPosition();\n\n };\n\n $scrollspy.trackElement = function(target, source) {\n trackedElements.push({target: target, source: source});\n };\n\n $scrollspy.untrackElement = function(target, source) {\n var toDelete;\n for (var i = trackedElements.length; i--;) {\n if(trackedElements[i].target === target && trackedElements[i].source === source) {\n toDelete = i;\n break;\n }\n }\n trackedElements = trackedElements.splice(toDelete, 1);\n };\n\n $scrollspy.activate = function(i) {\n trackedElements[i].addClass('active');\n };\n\n // Initialize plugin\n\n $scrollspy.init();\n return $scrollspy;\n\n }\n\n return ScrollSpyFactory;\n\n };\n\n })\n\n .directive('bsScrollspy', function($rootScope, debounce, dimensions, $scrollspy) {\n\n return {\n restrict: 'EAC',\n link: function postLink(scope, element, attr) {\n\n var options = {scope: scope};\n angular.forEach(['offset', 'target'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n var scrollspy = $scrollspy(options);\n scrollspy.trackElement(options.target, element);\n\n scope.$on('$destroy', function() {\n if (scrollspy) {\n scrollspy.untrackElement(options.target, element);\n scrollspy.destroy();\n }\n options = null;\n scrollspy = null;\n });\n\n }\n };\n\n })\n\n\n .directive('bsScrollspyList', function($rootScope, debounce, dimensions, $scrollspy) {\n\n return {\n restrict: 'A',\n compile: function postLink(element, attr) {\n var children = element[0].querySelectorAll('li > a[href]');\n angular.forEach(children, function(child) {\n var childEl = angular.element(child);\n childEl.parent().attr('bs-scrollspy', '').attr('data-target', childEl.attr('href'));\n });\n }\n\n };\n\n });\n\n// Source: select/select.js\nangular.module('mgcrea.ngStrap.select', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions'])\n\n .provider('$select', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'select',\n prefixEvent: '$select',\n placement: 'bottom-left',\n templateUrl: 'select/select.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n multiple: false,\n allNoneButtons: false,\n sort: true,\n caretHtml: ' ',\n placeholder: 'Choose among the following...',\n allText: 'All',\n noneText: 'None',\n maxLength: 3,\n maxLengthHtml: 'selected',\n iconCheckmark: 'glyphicon glyphicon-ok'\n };\n\n this.$get = function($window, $document, $rootScope, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n\n function SelectFactory(element, controller, config) {\n\n var $select = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $select = $tooltip(element, options);\n var scope = $select.$scope;\n\n scope.$matches = [];\n if (options.multiple) {\n scope.$activeIndex = [];\n }\n else {\n scope.$activeIndex = -1;\n }\n scope.$isMultiple = options.multiple;\n scope.$showAllNoneButtons = options.allNoneButtons && options.multiple;\n scope.$iconCheckmark = options.iconCheckmark;\n scope.$allText = options.allText;\n scope.$noneText = options.noneText;\n\n scope.$activate = function(index) {\n scope.$$postDigest(function() {\n $select.activate(index);\n });\n };\n\n scope.$select = function(index, evt) {\n scope.$$postDigest(function() {\n $select.select(index);\n });\n };\n\n scope.$isVisible = function() {\n return $select.$isVisible();\n };\n\n scope.$isActive = function(index) {\n return $select.$isActive(index);\n };\n\n scope.$selectAll = function () {\n for (var i = 0; i < scope.$matches.length; i++) {\n if (!scope.$isActive(i)) {\n scope.$select(i);\n }\n }\n };\n\n scope.$selectNone = function () {\n for (var i = 0; i < scope.$matches.length; i++) {\n if (scope.$isActive(i)) {\n scope.$select(i);\n }\n }\n };\n\n // Public methods\n\n $select.update = function(matches) {\n scope.$matches = matches;\n $select.$updateActiveIndex();\n };\n\n $select.activate = function(index) {\n if(options.multiple) {\n $select.$isActive(index) ? scope.$activeIndex.splice(scope.$activeIndex.indexOf(index), 1) : scope.$activeIndex.push(index);\n if(options.sort) scope.$activeIndex.sort(function(a, b) { return a - b; }); // use numeric sort instead of default sort\n } else {\n scope.$activeIndex = index;\n }\n return scope.$activeIndex;\n };\n\n $select.select = function(index) {\n var value = scope.$matches[index].value;\n scope.$apply(function() {\n $select.activate(index);\n if(options.multiple) {\n controller.$setViewValue(scope.$activeIndex.map(function(index) {\n return scope.$matches[index].value;\n }));\n } else {\n controller.$setViewValue(value);\n // Hide if single select\n $select.hide();\n }\n });\n // Emit event\n scope.$emit(options.prefixEvent + '.select', value, index, $select);\n };\n\n // Protected methods\n\n $select.$updateActiveIndex = function() {\n if(controller.$modelValue && scope.$matches.length) {\n if(options.multiple && angular.isArray(controller.$modelValue)) {\n scope.$activeIndex = controller.$modelValue.map(function(value) {\n return $select.$getIndex(value);\n });\n } else {\n scope.$activeIndex = $select.$getIndex(controller.$modelValue);\n }\n } else if(scope.$activeIndex >= scope.$matches.length) {\n scope.$activeIndex = options.multiple ? [] : 0;\n }\n };\n\n $select.$isVisible = function() {\n if(!options.minLength || !controller) {\n return scope.$matches.length;\n }\n // minLength support\n return scope.$matches.length && controller.$viewValue.length >= options.minLength;\n };\n\n $select.$isActive = function(index) {\n if(options.multiple) {\n return scope.$activeIndex.indexOf(index) !== -1;\n } else {\n return scope.$activeIndex === index;\n }\n };\n\n $select.$getIndex = function(value) {\n var l = scope.$matches.length, i = l;\n if(!l) return;\n for(i = l; i--;) {\n if(scope.$matches[i].value === value) break;\n }\n if(i < 0) return;\n return i;\n };\n\n $select.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n targetEl.triggerHandler('click');\n }\n };\n\n $select.$onKeyDown = function(evt) {\n if (!/(9|13|38|40)/.test(evt.keyCode)) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // release focus on tab\n if (options.multiple && evt.keyCode === 9) {\n return $select.hide();\n }\n\n // Select with enter\n if(!options.multiple && (evt.keyCode === 13 || evt.keyCode === 9)) {\n return $select.select(scope.$activeIndex);\n }\n\n if (!options.multiple) {\n // Navigate with keyboard\n if(evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--;\n else if(evt.keyCode === 38 && scope.$activeIndex < 0) scope.$activeIndex = scope.$matches.length - 1;\n else if(evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++;\n else if(angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0;\n scope.$digest();\n }\n };\n\n // Overrides\n\n var _show = $select.show;\n $select.show = function() {\n _show();\n if(options.multiple) {\n $select.$element.addClass('select-multiple');\n }\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n $select.$element.on(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $select.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $select.hide;\n $select.hide = function() {\n if(!options.multiple && !controller.$modelValue) {\n scope.$activeIndex = -1;\n }\n $select.$element.off(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $select.$onKeyDown);\n }\n _hide(true);\n };\n\n return $select;\n\n }\n\n SelectFactory.defaults = defaults;\n return SelectFactory;\n\n };\n\n })\n\n .directive('bsSelect', function($window, $parse, $q, $select, $parseOptions) {\n\n var defaults = $select.defaults;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope, placeholder: defaults.placeholder};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'placeholder', 'allNoneButtons', 'maxLength', 'maxLengthHtml', 'allText', 'noneText', 'iconCheckmark', 'autoClose', 'id', 'sort', 'caretHtml', 'prefixClass', 'prefixEvent'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'allNoneButtons', 'sort'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Only parse data-multiple. Angular sets existence attributes to true (multiple/required/etc), they apply this\n // to data-multiple as well for some reason, so we'll parse this ourselves and disregard multiple\n var dataMultiple = element.attr('data-multiple');\n if(angular.isDefined(dataMultiple)) {\n if(falseValueRegExp.test(dataMultiple))\n options.multiple = false;\n else\n options.multiple = dataMultiple;\n }\n\n // Add support for select markup\n if(element[0].nodeName.toLowerCase() === 'select') {\n var inputEl = element;\n inputEl.css('display', 'none');\n element = angular.element('');\n inputEl.after(element);\n }\n\n // Build proper bsOptions\n var parsedOptions = $parseOptions(attr.bsOptions);\n\n // Initialize select\n var select = $select(element, controller, options);\n\n // Watch bsOptions values before filtering for changes\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').trim();\n scope.$watchCollection(watchedOptions, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue);\n parsedOptions.valuesFn(scope, controller)\n .then(function(values) {\n select.update(values);\n controller.$render();\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue);\n select.$updateActiveIndex();\n controller.$render();\n }, true);\n\n // Model rendering in view\n controller.$render = function () {\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n var selected, index;\n if(options.multiple && angular.isArray(controller.$modelValue)) {\n selected = controller.$modelValue.map(function(value) {\n index = select.$getIndex(value);\n return angular.isDefined(index) ? select.$scope.$matches[index].label : false;\n }).filter(angular.isDefined);\n if(selected.length > (options.maxLength || defaults.maxLength)) {\n selected = selected.length + ' ' + (options.maxLengthHtml || defaults.maxLengthHtml);\n } else {\n selected = selected.join(', ');\n }\n } else {\n index = select.$getIndex(controller.$modelValue);\n selected = angular.isDefined(index) ? select.$scope.$matches[index].label : false;\n }\n element.html((selected ? selected : options.placeholder) + (options.caretHtml ? options.caretHtml : defaults.caretHtml));\n };\n\n if(options.multiple){\n controller.$isEmpty = function(value){\n return !value || value.length === 0;\n };\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (select) select.destroy();\n options = null;\n select = null;\n });\n\n }\n };\n\n });\n\n// Source: popover/popover.js\nangular.module('mgcrea.ngStrap.popover', ['mgcrea.ngStrap.tooltip'])\n\n .provider('$popover', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n customClass: '',\n // uncommenting the next two lines will break backwards compatability\n // prefixClass: 'popover',\n // prefixEvent: 'popover',\n container: false,\n target: false,\n placement: 'right',\n templateUrl: 'popover/popover.tpl.html',\n contentTemplate: false,\n trigger: 'click',\n keyboard: true,\n html: false,\n title: '',\n content: '',\n delay: 0,\n autoClose: false\n };\n\n this.$get = function($tooltip) {\n\n function PopoverFactory(element, config) {\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n var $popover = $tooltip(element, options);\n\n // Support scope as string options [/*title, */content]\n if(options.content) {\n $popover.$scope.content = options.content;\n }\n\n return $popover;\n\n }\n\n return PopoverFactory;\n\n };\n\n })\n\n .directive('bsPopover', function($window, $sce, $popover) {\n\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'customClass', 'autoClose', 'id', 'prefixClass', 'prefixEvent'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'autoClose'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // should not parse target attribute (anchor tag), only data-target #1454\n var dataTarget = element.attr('data-target');\n if(angular.isDefined(dataTarget)) {\n if(falseValueRegExp.test(dataTarget))\n options.target = false;\n else\n options.target = dataTarget;\n }\n\n // Support scope as data-attrs\n angular.forEach(['title', 'content'], function(key) {\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\n scope[key] = $sce.trustAsHtml(newValue);\n angular.isDefined(oldValue) && requestAnimationFrame(function() {\n popover && popover.$applyPlacement();\n });\n });\n });\n\n // Support scope as an object\n attr.bsPopover && scope.$watch(attr.bsPopover, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.content = newValue;\n }\n angular.isDefined(oldValue) && requestAnimationFrame(function() {\n popover && popover.$applyPlacement();\n });\n }, true);\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!popover || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(popover),?/i);\n newValue === true ? popover.show() : popover.hide();\n });\n\n // Viewport support\n attr.viewport && scope.$watch(attr.viewport, function (newValue) {\n if(!popover || !angular.isDefined(newValue)) return;\n popover.setViewport(newValue);\n });\n\n // Initialize popover\n var popover = $popover(element, options);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (popover) popover.destroy();\n options = null;\n popover = null;\n });\n\n }\n };\n\n });\n\n// Source: tab/tab.js\nangular.module('mgcrea.ngStrap.tab', [])\n\n .provider('$tab', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n template: 'tab/tab.tpl.html',\n navClass: 'nav-tabs',\n activeClass: 'active'\n };\n\n var controller = this.controller = function($scope, $element, $attrs) {\n var self = this;\n\n // Attributes options\n self.$options = angular.copy(defaults);\n angular.forEach(['animation', 'navClass', 'activeClass'], function(key) {\n if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];\n });\n\n // Publish options on scope\n $scope.$navClass = self.$options.navClass;\n $scope.$activeClass = self.$options.activeClass;\n\n self.$panes = $scope.$panes = [];\n\n // Please use $activePaneChangeListeners if you use `bsActivePane`\n // Because we removed `ngModel` as default, we rename viewChangeListeners to\n // activePaneChangeListeners to make more sense.\n self.$activePaneChangeListeners = self.$viewChangeListeners = [];\n\n self.$push = function(pane) {\n if(angular.isUndefined(self.$panes.$active)) {\n $scope.$setActive(pane.name || 0);\n }\n self.$panes.push(pane);\n };\n\n self.$remove = function(pane) {\n var index = self.$panes.indexOf(pane);\n var active = self.$panes.$active;\n var activeIndex;\n if(angular.isString(active)) {\n activeIndex = self.$panes.map(function(pane) {\n return pane.name;\n }).indexOf(active);\n } else {\n activeIndex = self.$panes.$active;\n }\n\n // remove pane from $panes array\n self.$panes.splice(index, 1);\n\n if (index < activeIndex) {\n // we removed a pane before the active pane, so we need to\n // decrement the active pane index\n activeIndex--;\n }\n else if (index === activeIndex && activeIndex === self.$panes.length) {\n // we remove the active pane and it was the one at the end,\n // so select the previous one\n activeIndex--;\n }\n if(activeIndex >= 0 && activeIndex < self.$panes.length) {\n self.$setActive(self.$panes[activeIndex].name || activeIndex);\n } else {\n self.$setActive();\n }\n };\n\n self.$setActive = $scope.$setActive = function(value) {\n self.$panes.$active = value;\n self.$activePaneChangeListeners.forEach(function(fn) {\n fn();\n });\n };\n\n self.$isActive = $scope.$isActive = function($pane, $index) {\n return self.$panes.$active === $pane.name || self.$panes.$active === $index;\n };\n\n };\n\n this.$get = function() {\n var $tab = {};\n $tab.defaults = defaults;\n $tab.controller = controller;\n return $tab;\n };\n\n })\n\n .directive('bsTabs', function($window, $animate, $tab, $parse) {\n\n var defaults = $tab.defaults;\n\n return {\n require: ['?ngModel', 'bsTabs'],\n transclude: true,\n scope: true,\n controller: ['$scope', '$element', '$attrs', $tab.controller],\n templateUrl: function(element, attr) {\n return attr.template || defaults.template;\n },\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsTabsCtrl = controllers[1];\n\n // 'ngModel' does interfere with form validation\n // and status, use `bsActivePane` instead to avoid it\n if(ngModelCtrl) {\n\n // Update the modelValue following\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\n ngModelCtrl.$setViewValue(bsTabsCtrl.$panes.$active);\n });\n\n // modelValue -> $formatters -> viewValue\n ngModelCtrl.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n bsTabsCtrl.$setActive(modelValue);\n return modelValue;\n });\n\n }\n\n if (attrs.bsActivePane) {\n // adapted from angularjs ngModelController bindings\n // https://github.com/angular/angular.js/blob/v1.3.1/src%2Fng%2Fdirective%2Finput.js#L1730\n var parsedBsActivePane = $parse(attrs.bsActivePane);\n\n // Update bsActivePane value with change\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\n parsedBsActivePane.assign(scope, bsTabsCtrl.$panes.$active);\n });\n\n // watch bsActivePane for value changes\n scope.$watch(attrs.bsActivePane, function(newValue, oldValue) {\n bsTabsCtrl.$setActive(newValue);\n }, true);\n }\n }\n };\n\n })\n\n .directive('bsPane', function($window, $animate, $sce) {\n\n return {\n require: ['^?ngModel', '^bsTabs'],\n scope: true,\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsTabsCtrl = controllers[1];\n\n // Add base class\n element.addClass('tab-pane');\n\n // Observe title attribute for change\n attrs.$observe('title', function(newValue, oldValue) {\n scope.title = $sce.trustAsHtml(newValue);\n });\n\n // Save tab name into scope\n scope.name = attrs.name;\n\n // Add animation class\n if(bsTabsCtrl.$options.animation) {\n element.addClass(bsTabsCtrl.$options.animation);\n }\n\n attrs.$observe('disabled', function(newValue, oldValue) {\n scope.disabled = scope.$eval(newValue);\n });\n\n // Push pane to parent bsTabs controller\n bsTabsCtrl.$push(scope);\n\n // remove pane from tab controller when pane is destroyed\n scope.$on('$destroy', function() {\n bsTabsCtrl.$remove(scope);\n });\n\n function render() {\n var index = bsTabsCtrl.$panes.indexOf(scope);\n $animate[bsTabsCtrl.$isActive(scope, index) ? 'addClass' : 'removeClass'](element, bsTabsCtrl.$options.activeClass);\n }\n\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\n render();\n });\n render();\n\n }\n };\n\n });\n\n// Source: tooltip/tooltip.js\nangular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.core', 'mgcrea.ngStrap.helpers.dimensions'])\n\n .provider('$tooltip', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n customClass: '',\n prefixClass: 'tooltip',\n prefixEvent: 'tooltip',\n container: false,\n target: false,\n placement: 'top',\n templateUrl: 'tooltip/tooltip.tpl.html',\n template: '',\n contentTemplate: false,\n trigger: 'hover focus',\n keyboard: false,\n html: false,\n show: false,\n title: '',\n type: '',\n delay: 0,\n autoClose: false,\n bsEnabled: true,\n viewport: {\n selector: 'body',\n padding: 0\n }\n };\n\n this.$get = function($window, $rootScope, $bsCompiler, $q, $templateCache, $http, $animate, $sce, dimensions, $$rAF, $timeout) {\n\n var trim = String.prototype.trim;\n var isTouch = 'createTouch' in $window.document;\n var htmlReplaceRegExp = /ng-bind=\"/ig;\n var $body = angular.element($window.document);\n\n function TooltipFactory(element, config) {\n\n var $tooltip = {};\n\n // Common vars\n var options = $tooltip.$options = angular.extend({}, defaults, config);\n var promise = $tooltip.$promise = $bsCompiler.compile(options);\n var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new();\n\n var nodeName = element[0].nodeName.toLowerCase();\n if(options.delay && angular.isString(options.delay)) {\n var split = options.delay.split(',').map(parseFloat);\n options.delay = split.length > 1 ? {show: split[0], hide: split[1]} : split[0];\n }\n\n // Store $id to identify the triggering element in events\n // give priority to options.id, otherwise, try to use\n // element id if defined\n $tooltip.$id = options.id || element.attr('id') || '';\n\n // Support scope as string options\n if(options.title) {\n scope.title = $sce.trustAsHtml(options.title);\n }\n\n // Provide scope helpers\n scope.$setEnabled = function(isEnabled) {\n scope.$$postDigest(function() {\n $tooltip.setEnabled(isEnabled);\n });\n };\n scope.$hide = function() {\n scope.$$postDigest(function() {\n $tooltip.hide();\n });\n };\n scope.$show = function() {\n scope.$$postDigest(function() {\n $tooltip.show();\n });\n };\n scope.$toggle = function() {\n scope.$$postDigest(function() {\n $tooltip.toggle();\n });\n };\n // Publish isShown as a protected var on scope\n $tooltip.$isShown = scope.$isShown = false;\n\n // Private vars\n var timeout, hoverState;\n\n // Fetch, compile then initialize tooltip\n var compileData, tipElement, tipContainer, tipScope;\n promise.then(function(data) {\n compileData = data;\n $tooltip.init();\n });\n\n $tooltip.init = function() {\n\n // Options: delay\n if (options.delay && angular.isNumber(options.delay)) {\n options.delay = {\n show: options.delay,\n hide: options.delay\n };\n }\n\n // Replace trigger on touch devices ?\n // if(isTouch && options.trigger === defaults.trigger) {\n // options.trigger.replace(/hover/g, 'click');\n // }\n\n // Options : container\n if(options.container === 'self') {\n tipContainer = element;\n } else if(angular.isElement(options.container)) {\n tipContainer = options.container;\n } else if(options.container) {\n tipContainer = findElement(options.container);\n }\n\n // Options: trigger\n bindTriggerEvents();\n\n // Options: target\n if(options.target) {\n options.target = angular.isElement(options.target) ? options.target : findElement(options.target);\n }\n\n // Options: show\n if(options.show) {\n scope.$$postDigest(function() {\n options.trigger === 'focus' ? element[0].focus() : $tooltip.show();\n });\n }\n\n };\n\n $tooltip.destroy = function() {\n\n // Unbind events\n unbindTriggerEvents();\n\n // Remove element\n destroyTipElement();\n\n // Destroy scope\n scope.$destroy();\n\n };\n\n $tooltip.enter = function() {\n\n clearTimeout(timeout);\n hoverState = 'in';\n if (!options.delay || !options.delay.show) {\n return $tooltip.show();\n }\n\n timeout = setTimeout(function() {\n if (hoverState ==='in') $tooltip.show();\n }, options.delay.show);\n\n };\n\n $tooltip.show = function() {\n if (!options.bsEnabled || $tooltip.$isShown) return;\n\n scope.$emit(options.prefixEvent + '.show.before', $tooltip);\n var parent, after;\n if (options.container) {\n parent = tipContainer;\n if (tipContainer[0].lastChild) {\n after = angular.element(tipContainer[0].lastChild);\n } else {\n after = null;\n }\n } else {\n parent = null;\n after = element;\n }\n\n\n // Hide any existing tipElement\n if(tipElement) destroyTipElement();\n // Fetch a cloned element linked from template\n tipScope = $tooltip.$scope.$new();\n tipElement = $tooltip.$element = compileData.link(tipScope, function(clonedElement, scope) {});\n\n // Set the initial positioning. Make the tooltip invisible\n // so IE doesn't try to focus on it off screen.\n tipElement.css({top: '-9999px', left: '-9999px', right: 'auto', display: 'block', visibility: 'hidden'});\n\n // Options: animation\n if(options.animation) tipElement.addClass(options.animation);\n // Options: type\n if(options.type) tipElement.addClass(options.prefixClass + '-' + options.type);\n // Options: custom classes\n if(options.customClass) tipElement.addClass(options.customClass);\n\n // Append the element, without any animations. If we append\n // using $animate.enter, some of the animations cause the placement\n // to be off due to the transforms.\n after ? after.after(tipElement) : parent.prepend(tipElement);\n\n $tooltip.$isShown = scope.$isShown = true;\n safeDigest(scope);\n\n // Now, apply placement\n $tooltip.$applyPlacement();\n\n // Once placed, animate it.\n // Support v1.2+ $animate\n // https://github.com/angular/angular.js/issues/11713\n if(angular.version.minor <= 2) {\n $animate.enter(tipElement, parent, after, enterAnimateCallback);\n } else {\n $animate.enter(tipElement, parent, after).then(enterAnimateCallback);\n }\n safeDigest(scope);\n\n $$rAF(function () {\n // Once the tooltip is placed and the animation starts, make the tooltip visible\n if(tipElement) tipElement.css({visibility: 'visible'});\n });\n\n // Bind events\n if(options.keyboard) {\n if(options.trigger !== 'focus') {\n $tooltip.focus();\n }\n bindKeyboardEvents();\n }\n\n if(options.autoClose) {\n bindAutoCloseEvents();\n }\n\n };\n\n function enterAnimateCallback() {\n scope.$emit(options.prefixEvent + '.show', $tooltip);\n }\n\n $tooltip.leave = function() {\n\n clearTimeout(timeout);\n hoverState = 'out';\n if (!options.delay || !options.delay.hide) {\n return $tooltip.hide();\n }\n timeout = setTimeout(function () {\n if (hoverState === 'out') {\n $tooltip.hide();\n }\n }, options.delay.hide);\n\n };\n\n var _blur;\n var _tipToHide;\n $tooltip.hide = function(blur) {\n\n if(!$tooltip.$isShown) return;\n scope.$emit(options.prefixEvent + '.hide.before', $tooltip);\n\n // store blur value for leaveAnimateCallback to use\n _blur = blur;\n\n // store current tipElement reference to use\n // in leaveAnimateCallback\n _tipToHide = tipElement;\n\n // Support v1.2+ $animate\n // https://github.com/angular/angular.js/issues/11713\n if(angular.version.minor <= 2) {\n $animate.leave(tipElement, leaveAnimateCallback);\n } else {\n $animate.leave(tipElement).then(leaveAnimateCallback);\n }\n\n $tooltip.$isShown = scope.$isShown = false;\n safeDigest(scope);\n\n // Unbind events\n if(options.keyboard && tipElement !== null) {\n unbindKeyboardEvents();\n }\n\n if(options.autoClose && tipElement !== null) {\n unbindAutoCloseEvents();\n }\n };\n\n function leaveAnimateCallback() {\n scope.$emit(options.prefixEvent + '.hide', $tooltip);\n\n // check if current tipElement still references\n // the same element when hide was called\n if (tipElement === _tipToHide) {\n // Allow to blur the input when hidden, like when pressing enter key\n if(_blur && options.trigger === 'focus') {\n return element[0].blur();\n }\n\n // clean up child scopes\n destroyTipElement();\n }\n }\n\n $tooltip.toggle = function() {\n $tooltip.$isShown ? $tooltip.leave() : $tooltip.enter();\n };\n\n $tooltip.focus = function() {\n tipElement[0].focus();\n };\n\n $tooltip.setEnabled = function(isEnabled) {\n options.bsEnabled = isEnabled;\n };\n\n $tooltip.setViewport = function(viewport) {\n options.viewport = viewport;\n };\n\n // Protected methods\n\n $tooltip.$applyPlacement = function() {\n if(!tipElement) return;\n\n // Determine if we're doing an auto or normal placement\n var placement = options.placement,\n autoToken = /\\s?auto?\\s?/i,\n autoPlace = autoToken.test(placement);\n\n if (autoPlace) {\n placement = placement.replace(autoToken, '') || defaults.placement;\n }\n\n // Need to add the position class before we get\n // the offsets\n tipElement.addClass(options.placement);\n\n // Get the position of the target element\n // and the height and width of the tooltip so we can center it.\n var elementPosition = getPosition(),\n tipWidth = tipElement.prop('offsetWidth'),\n tipHeight = tipElement.prop('offsetHeight');\n\n // If we're auto placing, we need to check the positioning\n if (autoPlace) {\n var originalPlacement = placement;\n var container = options.container ? findElement(options.container) : element.parent();\n var containerPosition = getPosition(container);\n\n // Determine if the vertical placement\n if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > containerPosition.bottom) {\n placement = originalPlacement.replace('bottom', 'top');\n } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < containerPosition.top) {\n placement = originalPlacement.replace('top', 'bottom');\n }\n\n // Determine the horizontal placement\n // The exotic placements of left and right are opposite of the standard placements. Their arrows are put on the left/right\n // and flow in the opposite direction of their placement.\n if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') &&\n elementPosition.right + tipWidth > containerPosition.width) {\n\n placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right');\n } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') &&\n elementPosition.left - tipWidth < containerPosition.left) {\n\n placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left');\n }\n\n tipElement.removeClass(originalPlacement).addClass(placement);\n }\n\n // Get the tooltip's top and left coordinates to center it with this directive.\n var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight);\n applyPlacement(tipPosition, placement);\n };\n\n $tooltip.$onKeyUp = function(evt) {\n if (evt.which === 27 && $tooltip.$isShown) {\n $tooltip.hide();\n evt.stopPropagation();\n }\n };\n\n $tooltip.$onFocusKeyUp = function(evt) {\n if (evt.which === 27) {\n element[0].blur();\n evt.stopPropagation();\n }\n };\n\n $tooltip.$onFocusElementMouseDown = function(evt) {\n evt.preventDefault();\n evt.stopPropagation();\n // Some browsers do not auto-focus buttons (eg. Safari)\n $tooltip.$isShown ? element[0].blur() : element[0].focus();\n };\n\n // bind/unbind events\n function bindTriggerEvents() {\n var triggers = options.trigger.split(' ');\n angular.forEach(triggers, function(trigger) {\n if(trigger === 'click') {\n element.on('click', $tooltip.toggle);\n } else if(trigger !== 'manual') {\n element.on(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);\n element.on(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);\n nodeName === 'button' && trigger !== 'hover' && element.on(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);\n }\n });\n }\n\n function unbindTriggerEvents() {\n var triggers = options.trigger.split(' ');\n for (var i = triggers.length; i--;) {\n var trigger = triggers[i];\n if(trigger === 'click') {\n element.off('click', $tooltip.toggle);\n } else if(trigger !== 'manual') {\n element.off(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);\n element.off(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);\n nodeName === 'button' && trigger !== 'hover' && element.off(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);\n }\n }\n }\n\n function bindKeyboardEvents() {\n if(options.trigger !== 'focus') {\n tipElement.on('keyup', $tooltip.$onKeyUp);\n } else {\n element.on('keyup', $tooltip.$onFocusKeyUp);\n }\n }\n\n function unbindKeyboardEvents() {\n if(options.trigger !== 'focus') {\n tipElement.off('keyup', $tooltip.$onKeyUp);\n } else {\n element.off('keyup', $tooltip.$onFocusKeyUp);\n }\n }\n\n var _autoCloseEventsBinded = false;\n function bindAutoCloseEvents() {\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n // Stop propagation when clicking inside tooltip\n tipElement.on('click', stopEventPropagation);\n\n // Hide when clicking outside tooltip\n $body.on('click', $tooltip.hide);\n\n _autoCloseEventsBinded = true;\n }, 0, false);\n }\n\n function unbindAutoCloseEvents() {\n if (_autoCloseEventsBinded) {\n tipElement.off('click', stopEventPropagation);\n $body.off('click', $tooltip.hide);\n _autoCloseEventsBinded = false;\n }\n }\n\n function stopEventPropagation(event) {\n event.stopPropagation();\n }\n\n // Private methods\n\n function getPosition($element) {\n $element = $element || (options.target || element);\n\n var el = $element[0],\n isBody = el.tagName === 'BODY';\n\n var elRect = el.getBoundingClientRect();\n var rect = {};\n\n // IE8 has issues with angular.extend and using elRect directly.\n // By coping the values of elRect into a new object, we can continue to use extend\n for (var p in elRect) {\n // DO NOT use hasOwnProperty when inspecting the return of getBoundingClientRect.\n rect[p] = elRect[p];\n }\n\n if (rect.width === null) {\n // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093\n rect = angular.extend({}, rect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top });\n }\n var elOffset = isBody ? { top: 0, left: 0 } : dimensions.offset(el),\n scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.prop('scrollTop') || 0 },\n outerDims = isBody ? { width: document.documentElement.clientWidth, height: $window.innerHeight } : null;\n\n return angular.extend({}, rect, scroll, outerDims, elOffset);\n }\n\n function getCalculatedOffset(placement, position, actualWidth, actualHeight) {\n var offset;\n var split = placement.split('-');\n\n switch (split[0]) {\n case 'right':\n offset = {\n top: position.top + position.height / 2 - actualHeight / 2,\n left: position.left + position.width\n };\n break;\n case 'bottom':\n offset = {\n top: position.top + position.height,\n left: position.left + position.width / 2 - actualWidth / 2\n };\n break;\n case 'left':\n offset = {\n top: position.top + position.height / 2 - actualHeight / 2,\n left: position.left - actualWidth\n };\n break;\n default:\n offset = {\n top: position.top - actualHeight,\n left: position.left + position.width / 2 - actualWidth / 2\n };\n break;\n }\n\n if(!split[1]) {\n return offset;\n }\n\n // Add support for corners @todo css\n if(split[0] === 'top' || split[0] === 'bottom') {\n switch (split[1]) {\n case 'left':\n offset.left = position.left;\n break;\n case 'right':\n offset.left = position.left + position.width - actualWidth;\n }\n } else if(split[0] === 'left' || split[0] === 'right') {\n switch (split[1]) {\n case 'top':\n offset.top = position.top - actualHeight;\n break;\n case 'bottom':\n offset.top = position.top + position.height;\n }\n }\n\n return offset;\n }\n\n function applyPlacement(offset, placement) {\n var tip = tipElement[0],\n width = tip.offsetWidth,\n height = tip.offsetHeight;\n\n // manually read margins because getBoundingClientRect includes difference\n var marginTop = parseInt(dimensions.css(tip, 'margin-top'), 10),\n marginLeft = parseInt(dimensions.css(tip, 'margin-left'), 10);\n\n // we must check for NaN for ie 8/9\n if (isNaN(marginTop)) marginTop = 0;\n if (isNaN(marginLeft)) marginLeft = 0;\n\n offset.top = offset.top + marginTop;\n offset.left = offset.left + marginLeft;\n\n // dimensions setOffset doesn't round pixel values\n // so we use setOffset directly with our own function\n dimensions.setOffset(tip, angular.extend({\n using: function (props) {\n tipElement.css({\n top: Math.round(props.top) + 'px',\n left: Math.round(props.left) + 'px',\n right: ''\n });\n }\n }, offset), 0);\n\n // check to see if placing tip in new offset caused the tip to resize itself\n var actualWidth = tip.offsetWidth,\n actualHeight = tip.offsetHeight;\n\n if (placement === 'top' && actualHeight !== height) {\n offset.top = offset.top + height - actualHeight;\n }\n\n // If it's an exotic placement, exit now instead of\n // applying a delta and changing the arrow\n if (/top-left|top-right|bottom-left|bottom-right/.test(placement)) return;\n\n var delta = getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight);\n\n if (delta.left) {\n offset.left += delta.left;\n } else {\n offset.top += delta.top;\n }\n\n dimensions.setOffset(tip, offset);\n\n if (/top|right|bottom|left/.test(placement)) {\n var isVertical = /top|bottom/.test(placement),\n arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight,\n arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight';\n\n replaceArrow(arrowDelta, tip[arrowOffsetPosition], isVertical);\n }\n }\n\n function getViewportAdjustedDelta(placement, position, actualWidth, actualHeight) {\n var delta = { top: 0, left: 0 },\n $viewport = options.viewport && findElement(options.viewport.selector || options.viewport);\n\n if (!$viewport) {\n return delta;\n }\n\n var viewportPadding = options.viewport && options.viewport.padding || 0,\n viewportDimensions = getPosition($viewport);\n\n if (/right|left/.test(placement)) {\n var topEdgeOffset = position.top - viewportPadding - viewportDimensions.scroll,\n bottomEdgeOffset = position.top + viewportPadding - viewportDimensions.scroll + actualHeight;\n if (topEdgeOffset < viewportDimensions.top) { // top overflow\n delta.top = viewportDimensions.top - topEdgeOffset;\n } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow\n delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset;\n }\n } else {\n var leftEdgeOffset = position.left - viewportPadding,\n rightEdgeOffset = position.left + viewportPadding + actualWidth;\n if (leftEdgeOffset < viewportDimensions.left) { // left overflow\n delta.left = viewportDimensions.left - leftEdgeOffset;\n } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow\n delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset;\n }\n }\n\n return delta;\n }\n\n function replaceArrow(delta, dimension, isHorizontal) {\n var $arrow = findElement('.tooltip-arrow, .arrow', tipElement[0]);\n\n $arrow.css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')\n .css(isHorizontal ? 'top' : 'left', '');\n }\n\n function destroyTipElement() {\n // Cancel pending callbacks\n clearTimeout(timeout);\n\n if($tooltip.$isShown && tipElement !== null) {\n if(options.autoClose) {\n unbindAutoCloseEvents();\n }\n\n if(options.keyboard) {\n unbindKeyboardEvents();\n }\n }\n\n if(tipScope) {\n tipScope.$destroy();\n tipScope = null;\n }\n\n if(tipElement) {\n tipElement.remove();\n tipElement = $tooltip.$element = null;\n }\n }\n\n return $tooltip;\n\n }\n\n // Helper functions\n\n function safeDigest(scope) {\n scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();\n }\n\n function findElement(query, element) {\n return angular.element((element || document).querySelectorAll(query));\n }\n\n var fetchPromises = {};\n function fetchTemplate(template) {\n if(fetchPromises[template]) return fetchPromises[template];\n return (fetchPromises[template] = $http.get(template, {cache: $templateCache}).then(function(res) {\n return res.data;\n }));\n }\n\n return TooltipFactory;\n\n };\n\n })\n\n .directive('bsTooltip', function($window, $location, $sce, $tooltip, $$rAF) {\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'backdropAnimation', 'type', 'customClass', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // should not parse target attribute (anchor tag), only data-target #1454\n var dataTarget = element.attr('data-target');\n if(angular.isDefined(dataTarget)) {\n if(falseValueRegExp.test(dataTarget))\n options.target = false;\n else\n options.target = dataTarget;\n }\n\n // overwrite inherited title value when no value specified\n // fix for angular 1.3.1 531a8de72c439d8ddd064874bf364c00cedabb11\n if (!scope.hasOwnProperty('title')){\n scope.title = '';\n }\n\n // Observe scope attributes for change\n attr.$observe('title', function(newValue) {\n if (angular.isDefined(newValue) || !scope.hasOwnProperty('title')) {\n var oldValue = scope.title;\n scope.title = $sce.trustAsHtml(newValue);\n angular.isDefined(oldValue) && $$rAF(function() {\n tooltip && tooltip.$applyPlacement();\n });\n }\n });\n\n // Support scope as an object\n attr.bsTooltip && scope.$watch(attr.bsTooltip, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.title = newValue;\n }\n angular.isDefined(oldValue) && $$rAF(function() {\n tooltip && tooltip.$applyPlacement();\n });\n }, true);\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!tooltip || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(tooltip),?/i);\n newValue === true ? tooltip.show() : tooltip.hide();\n });\n\n // Enabled binding support\n attr.bsEnabled && scope.$watch(attr.bsEnabled, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.bsEnabled, newValue, oldValue);\n if(!tooltip || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|1|,?(tooltip),?/i);\n newValue === false ? tooltip.setEnabled(false) : tooltip.setEnabled(true);\n });\n\n // Viewport support\n attr.viewport && scope.$watch(attr.viewport, function (newValue) {\n if(!tooltip || !angular.isDefined(newValue)) return;\n tooltip.setViewport(newValue);\n });\n\n // Initialize popover\n var tooltip = $tooltip(element, options);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if(tooltip) tooltip.destroy();\n options = null;\n tooltip = null;\n });\n\n }\n };\n\n });\n\n// Source: timepicker/timepicker.js\nangular.module('mgcrea.ngStrap.timepicker', [\n 'mgcrea.ngStrap.helpers.dateParser',\n 'mgcrea.ngStrap.helpers.dateFormatter',\n 'mgcrea.ngStrap.tooltip'])\n\n .provider('$timepicker', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n //uncommenting the following line will break backwards compatability\n // prefixEvent: 'timepicker',\n prefixClass: 'timepicker',\n placement: 'bottom-left',\n templateUrl: 'timepicker/timepicker.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n // lang: $locale.id,\n useNative: true,\n timeType: 'date',\n timeFormat: 'shortTime',\n timezone: null,\n modelTimeFormat: null,\n autoclose: false,\n minTime: -Infinity,\n maxTime: +Infinity,\n length: 5,\n hourStep: 1,\n minuteStep: 5,\n secondStep: 5,\n roundDisplay: false,\n iconUp: 'glyphicon glyphicon-chevron-up',\n iconDown: 'glyphicon glyphicon-chevron-down',\n arrowBehavior: 'pager'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\n\n function timepickerFactory(element, controller, config) {\n\n var $timepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $timepicker.$options;\n var scope = $timepicker.$scope;\n\n var lang = options.lang;\n var formatDate = function(date, format, timezone) {\n return $dateFormatter.formatDate(date, format, lang, timezone);\n };\n\n function floorMinutes(time)\n {\n // coeff used to floor current time to nearest minuteStep interval\n var coeff = 1000 * 60 * options.minuteStep;\n return new Date(Math.floor(time.getTime() / coeff) * coeff);\n }\n\n // View vars\n\n var selectedIndex = 0;\n var defaultDate = options.roundDisplay ? floorMinutes(new Date()) : new Date();\n var startDate = controller.$dateValue || defaultDate;\n var viewDate = {hour: startDate.getHours(), meridian: startDate.getHours() < 12, minute: startDate.getMinutes(), second: startDate.getSeconds(), millisecond: startDate.getMilliseconds()};\n\n var format = $dateFormatter.getDatetimeFormat(options.timeFormat, lang);\n\n var hoursFormat = $dateFormatter.hoursFormat(format),\n timeSeparator = $dateFormatter.timeSeparator(format),\n minutesFormat = $dateFormatter.minutesFormat(format),\n secondsFormat = $dateFormatter.secondsFormat(format),\n showSeconds = $dateFormatter.showSeconds(format),\n showAM = $dateFormatter.showAM(format);\n\n scope.$iconUp = options.iconUp;\n scope.$iconDown = options.iconDown;\n\n // Scope methods\n\n scope.$select = function(date, index) {\n $timepicker.select(date, index);\n };\n scope.$moveIndex = function(value, index) {\n $timepicker.$moveIndex(value, index);\n };\n scope.$switchMeridian = function(date) {\n $timepicker.switchMeridian(date);\n };\n\n // Public methods\n\n $timepicker.update = function(date) {\n // console.warn('$timepicker.update() newValue=%o', date);\n if(angular.isDate(date) && !isNaN(date.getTime())) {\n $timepicker.$date = date;\n angular.extend(viewDate, {hour: date.getHours(), minute: date.getMinutes(), second: date.getSeconds(), millisecond: date.getMilliseconds()});\n $timepicker.$build();\n } else if(!$timepicker.$isBuilt) {\n $timepicker.$build();\n }\n };\n\n $timepicker.select = function(date, index, keep) {\n // console.warn('$timepicker.select', date, scope.$mode);\n if(!controller.$dateValue || isNaN(controller.$dateValue.getTime())) controller.$dateValue = new Date(1970, 0, 1);\n if(!angular.isDate(date)) date = new Date(date);\n if(index === 0) controller.$dateValue.setHours(date.getHours());\n else if(index === 1) controller.$dateValue.setMinutes(date.getMinutes());\n else if(index === 2) controller.$dateValue.setSeconds(date.getSeconds());\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n if(options.autoclose && !keep) {\n $timeout(function() { $timepicker.hide(true); });\n }\n };\n\n $timepicker.switchMeridian = function(date) {\n if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) {\n return;\n }\n var hours = (date || controller.$dateValue).getHours();\n controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12);\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n };\n\n // Protected methods\n\n $timepicker.$build = function() {\n // console.warn('$timepicker.$build() viewDate=%o', viewDate);\n var i, midIndex = scope.midIndex = parseInt(options.length / 2, 10);\n var hours = [], hour;\n for(i = 0; i < options.length; i++) {\n hour = new Date(1970, 0, 1, viewDate.hour - (midIndex - i) * options.hourStep);\n hours.push({date: hour, label: formatDate(hour, hoursFormat), selected: $timepicker.$date && $timepicker.$isSelected(hour, 0), disabled: $timepicker.$isDisabled(hour, 0)});\n }\n var minutes = [], minute;\n for(i = 0; i < options.length; i++) {\n minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep);\n minutes.push({date: minute, label: formatDate(minute, minutesFormat), selected: $timepicker.$date && $timepicker.$isSelected(minute, 1), disabled: $timepicker.$isDisabled(minute, 1)});\n }\n var seconds = [], second;\n for(i = 0; i < options.length; i++) {\n second = new Date(1970, 0, 1, 0, 0, viewDate.second - (midIndex - i) * options.secondStep);\n seconds.push({date: second, label: formatDate(second, secondsFormat), selected: $timepicker.$date && $timepicker.$isSelected(second, 2), disabled: $timepicker.$isDisabled(second, 2)});\n }\n\n var rows = [];\n for(i = 0; i < options.length; i++) {\n if (showSeconds) {\n rows.push([hours[i], minutes[i], seconds[i]]);\n } else {\n rows.push([hours[i], minutes[i]]);\n }\n }\n scope.rows = rows;\n scope.showSeconds = showSeconds;\n scope.showAM = showAM;\n scope.isAM = ($timepicker.$date || hours[midIndex].date).getHours() < 12;\n scope.timeSeparator = timeSeparator;\n $timepicker.$isBuilt = true;\n };\n\n $timepicker.$isSelected = function(date, index) {\n if(!$timepicker.$date) return false;\n else if(index === 0) {\n return date.getHours() === $timepicker.$date.getHours();\n } else if(index === 1) {\n return date.getMinutes() === $timepicker.$date.getMinutes();\n } else if(index === 2) {\n return date.getSeconds() === $timepicker.$date.getSeconds();\n }\n };\n\n $timepicker.$isDisabled = function(date, index) {\n var selectedTime;\n if(index === 0) {\n selectedTime = date.getTime() + viewDate.minute * 6e4 + viewDate.second * 1e3;\n } else if(index === 1) {\n selectedTime = date.getTime() + viewDate.hour * 36e5 + viewDate.second * 1e3;\n } else if(index === 2) {\n selectedTime = date.getTime() + viewDate.hour * 36e5 + viewDate.minute * 6e4;\n }\n return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1;\n };\n\n scope.$arrowAction = function (value, index) {\n if (options.arrowBehavior === 'picker') {\n $timepicker.$setTimeByStep(value,index);\n } else {\n $timepicker.$moveIndex(value,index);\n }\n };\n\n $timepicker.$setTimeByStep = function(value, index) {\n var newDate = new Date($timepicker.$date);\n var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;\n var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;\n var seconds = newDate.getSeconds(), secondsLength = formatDate(newDate, secondsFormat).length;\n if (index === 0) {\n newDate.setHours(hours - (parseInt(options.hourStep, 10) * value));\n }\n else if (index === 1) {\n newDate.setMinutes(minutes - (parseInt(options.minuteStep, 10) * value));\n }\n else if (index === 2) {\n newDate.setSeconds(seconds - (parseInt(options.secondStep, 10) * value));\n }\n $timepicker.select(newDate, index, true);\n };\n\n $timepicker.$moveIndex = function(value, index) {\n var targetDate;\n if(index === 0) {\n targetDate = new Date(1970, 0, 1, viewDate.hour + (value * options.length), viewDate.minute, viewDate.second);\n angular.extend(viewDate, {hour: targetDate.getHours()});\n } else if(index === 1) {\n targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + (value * options.length * options.minuteStep), viewDate.second);\n angular.extend(viewDate, {minute: targetDate.getMinutes()});\n } else if(index === 2) {\n targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute, viewDate.second + (value * options.length * options.secondStep));\n angular.extend(viewDate, {second: targetDate.getSeconds()});\n }\n $timepicker.$build();\n };\n\n $timepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n if(evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $timepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // Close on enter\n if(evt.keyCode === 13) return $timepicker.hide(true);\n\n // Navigate with keyboard\n var newDate = new Date($timepicker.$date);\n var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;\n var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;\n var seconds = newDate.getSeconds(), secondsLength = formatDate(newDate, secondsFormat).length;\n var sepLength = 1;\n var lateralMove = /(37|39)/.test(evt.keyCode);\n var count = 2 + showSeconds * 1 + showAM * 1;\n\n // Navigate indexes (left, right)\n if (lateralMove) {\n if(evt.keyCode === 37) selectedIndex = selectedIndex < 1 ? count - 1 : selectedIndex - 1;\n else if(evt.keyCode === 39) selectedIndex = selectedIndex < count - 1 ? selectedIndex + 1 : 0;\n }\n\n // Update values (up, down)\n var selectRange = [0, hoursLength];\n var incr = 0;\n if (evt.keyCode === 38) incr = -1;\n if (evt.keyCode === 40) incr = +1;\n var isSeconds = selectedIndex === 2 && showSeconds;\n var isMeridian = selectedIndex === 2 && !showSeconds || selectedIndex === 3 && showSeconds;\n if(selectedIndex === 0) {\n newDate.setHours(hours + incr*parseInt(options.hourStep, 10));\n // re-calculate hours length because we have changed hours value\n hoursLength = formatDate(newDate, hoursFormat).length;\n selectRange = [0, hoursLength];\n } else if(selectedIndex === 1) {\n newDate.setMinutes(minutes + incr*parseInt(options.minuteStep, 10));\n // re-calculate minutes length because we have changes minutes value\n minutesLength = formatDate(newDate, minutesFormat).length;\n selectRange = [hoursLength + sepLength, minutesLength];\n } else if(isSeconds) {\n newDate.setSeconds(seconds + incr*parseInt(options.secondStep, 10));\n // re-calculate seconds length because we have changes seconds value\n secondsLength = formatDate(newDate, secondsFormat).length;\n selectRange = [hoursLength + sepLength + minutesLength + sepLength, secondsLength];\n } else if(isMeridian) {\n if(!lateralMove) $timepicker.switchMeridian();\n selectRange = [hoursLength + sepLength + minutesLength + sepLength + (secondsLength + sepLength)*showSeconds, 2];\n }\n $timepicker.select(newDate, selectedIndex, true);\n createSelection(selectRange[0], selectRange[1]);\n parentScope.$digest();\n };\n\n // Private\n\n function createSelection(start, length) {\n var end = start + length;\n if(element[0].createTextRange) {\n var selRange = element[0].createTextRange();\n selRange.collapse(true);\n selRange.moveStart('character', start);\n selRange.moveEnd('character', end);\n selRange.select();\n } else if(element[0].setSelectionRange) {\n element[0].setSelectionRange(start, end);\n } else if(angular.isUndefined(element[0].selectionStart)) {\n element[0].selectionStart = start;\n element[0].selectionEnd = end;\n }\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $timepicker.init;\n $timepicker.init = function() {\n if(isNative && options.useNative) {\n element.prop('type', 'time');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if(isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $timepicker.destroy;\n $timepicker.destroy = function() {\n if(isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $timepicker.show;\n $timepicker.show = function() {\n _show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n $timepicker.$element && $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if(options.keyboard) {\n element && element.on('keydown', $timepicker.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $timepicker.hide;\n $timepicker.hide = function(blur) {\n if(!$timepicker.$isShown) return;\n $timepicker.$element && $timepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if(options.keyboard) {\n element && element.off('keydown', $timepicker.$onKeyDown);\n }\n _hide(blur);\n };\n\n return $timepicker;\n\n }\n\n timepickerFactory.defaults = defaults;\n return timepickerFactory;\n\n };\n\n })\n\n\n .directive('bsTimepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) {\n\n var defaults = $timepicker.defaults;\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'autoclose', 'timeType', 'timeFormat', 'timezone', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'secondStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown', 'roundDisplay', 'id', 'prefixClass', 'prefixEvent'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'autoclose', 'useNative', 'roundDisplay'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!timepicker || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(timepicker),?/i);\n newValue === true ? timepicker.show() : timepicker.hide();\n });\n\n // Initialize timepicker\n if(isNative && (options.useNative || defaults.useNative)) options.timeFormat = 'HH:mm';\n var timepicker = $timepicker(element, controller, options);\n options = timepicker.$options;\n\n var lang = options.lang;\n var formatDate = function(date, format, timezone) {\n return $dateFormatter.formatDate(date, format, lang, timezone);\n };\n\n // Initialize parser\n var dateParser = $dateParser({format: options.timeFormat, lang: lang});\n\n // Observe attributes for changes\n angular.forEach(['minTime', 'maxTime'], function(key) {\n // console.warn('attr.$observe(%s)', key, attr[key]);\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\n timepicker.$options[key] = dateParser.getTimeForAttribute(key, newValue);\n !isNaN(timepicker.$options[key]) && timepicker.$build();\n validateAgainstMinMaxTime(controller.$dateValue);\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue, controller.$dateValue);\n timepicker.update(controller.$dateValue);\n }, true);\n\n function validateAgainstMinMaxTime(parsedTime) {\n if (!angular.isDate(parsedTime)) return;\n var isMinValid = isNaN(options.minTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) >= options.minTime;\n var isMaxValid = isNaN(options.maxTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) <= options.maxTime;\n var isValid = isMinValid && isMaxValid;\n controller.$setValidity('date', isValid);\n controller.$setValidity('min', isMinValid);\n controller.$setValidity('max', isMaxValid);\n // Only update the model when we have a valid date\n if(!isValid) {\n return;\n }\n controller.$dateValue = parsedTime;\n }\n\n // viewValue -> $parsers -> modelValue\n controller.$parsers.unshift(function(viewValue) {\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\n var date;\n // Null values should correctly reset the model value & validity\n if(!viewValue) {\n // BREAKING CHANGE:\n // return null (not undefined) when input value is empty, so angularjs 1.3\n // ngModelController can go ahead and run validators, like ngRequired\n controller.$setValidity('date', true);\n return null;\n }\n var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue);\n if(!parsedTime || isNaN(parsedTime.getTime())) {\n controller.$setValidity('date', false);\n // return undefined, causes ngModelController to\n // invalidate model value\n return;\n } else {\n validateAgainstMinMaxTime(parsedTime);\n }\n\n if(options.timeType === 'string') {\n date = dateParser.timezoneOffsetAdjust(parsedTime, options.timezone, true);\n return formatDate(date, options.modelTimeFormat || options.timeFormat);\n }\n date = dateParser.timezoneOffsetAdjust(controller.$dateValue, options.timezone, true);\n if(options.timeType === 'number') {\n return date.getTime();\n } else if(options.timeType === 'unix') {\n return date.getTime() / 1000;\n } else if(options.timeType === 'iso') {\n return date.toISOString();\n } else {\n return new Date(date);\n }\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var date;\n if(angular.isUndefined(modelValue) || modelValue === null) {\n date = NaN;\n } else if(angular.isDate(modelValue)) {\n date = modelValue;\n } else if(options.timeType === 'string') {\n date = dateParser.parse(modelValue, null, options.modelTimeFormat);\n } else if(options.timeType === 'unix') {\n date = new Date(modelValue * 1000);\n } else {\n date = new Date(modelValue);\n }\n // Setup default value?\n // if(isNaN(date.getTime())) date = new Date(new Date().setMinutes(0) + 36e5);\n controller.$dateValue = dateParser.timezoneOffsetAdjust(date, options.timezone);\n return getTimeFormattedString();\n });\n\n // viewValue -> element\n controller.$render = function() {\n // console.warn('$render(\"%s\"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);\n element.val(getTimeFormattedString());\n };\n\n function getTimeFormattedString() {\n return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat);\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (timepicker) timepicker.destroy();\n options = null;\n timepicker = null;\n });\n\n }\n };\n\n });\n\n// Source: typeahead/typeahead.js\nangular.module('mgcrea.ngStrap.typeahead', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions'])\n\n .provider('$typeahead', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'typeahead',\n prefixEvent: '$typeahead',\n placement: 'bottom-left',\n templateUrl: 'typeahead/typeahead.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n minLength: 1,\n filter: 'filter',\n limit: 6,\n autoSelect: false,\n comparator: '',\n trimValue: true\n };\n\n this.$get = function($window, $rootScope, $tooltip, $$rAF, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n\n function TypeaheadFactory(element, controller, config) {\n\n var $typeahead = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $typeahead = $tooltip(element, options);\n var parentScope = config.scope;\n var scope = $typeahead.$scope;\n\n scope.$resetMatches = function(){\n scope.$matches = [];\n scope.$activeIndex = options.autoSelect ? 0 : -1; // If set to 0, the first match will be highlighted\n };\n scope.$resetMatches();\n\n scope.$activate = function(index) {\n scope.$$postDigest(function() {\n $typeahead.activate(index);\n });\n };\n\n scope.$select = function(index, evt) {\n scope.$$postDigest(function() {\n $typeahead.select(index);\n });\n };\n\n scope.$isVisible = function() {\n return $typeahead.$isVisible();\n };\n\n // Public methods\n\n $typeahead.update = function(matches) {\n scope.$matches = matches;\n if(scope.$activeIndex >= matches.length) {\n scope.$activeIndex = options.autoSelect ? 0: -1;\n }\n\n // wrap in a $timeout so the results are updated\n // before repositioning\n safeDigest(scope);\n $$rAF($typeahead.$applyPlacement);\n };\n\n $typeahead.activate = function(index) {\n scope.$activeIndex = index;\n };\n\n $typeahead.select = function(index) {\n if(index === -1) return;\n var value = scope.$matches[index].value;\n // console.log('$setViewValue', value);\n controller.$setViewValue(value);\n controller.$render();\n scope.$resetMatches();\n if(parentScope) parentScope.$digest();\n // Emit event\n scope.$emit(options.prefixEvent + '.select', value, index, $typeahead);\n };\n\n // Protected methods\n\n $typeahead.$isVisible = function() {\n if(!options.minLength || !controller) {\n return !!scope.$matches.length;\n }\n // minLength support\n return scope.$matches.length && angular.isString(controller.$viewValue) && controller.$viewValue.length >= options.minLength;\n };\n\n $typeahead.$getIndex = function(value) {\n var l = scope.$matches.length, i = l;\n if(!l) return;\n for(i = l; i--;) {\n if(scope.$matches[i].value === value) break;\n }\n if(i < 0) return;\n return i;\n };\n\n $typeahead.$onMouseDown = function(evt) {\n // Prevent blur on mousedown\n evt.preventDefault();\n evt.stopPropagation();\n };\n\n $typeahead.$onKeyDown = function(evt) {\n if(!/(38|40|13)/.test(evt.keyCode)) return;\n\n // Let ngSubmit pass if the typeahead tip is hidden or no option is selected\n if($typeahead.$isVisible() && !(evt.keyCode === 13 && scope.$activeIndex === -1)) {\n evt.preventDefault();\n evt.stopPropagation();\n }\n\n // Select with enter\n if(evt.keyCode === 13 && scope.$matches.length) {\n $typeahead.select(scope.$activeIndex);\n }\n\n // Navigate with keyboard\n else if(evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--;\n else if(evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++;\n else if(angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0;\n scope.$digest();\n };\n\n // Overrides\n\n var show = $typeahead.show;\n $typeahead.show = function() {\n show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed immediately.\n $timeout(function() {\n $typeahead.$element && $typeahead.$element.on('mousedown', $typeahead.$onMouseDown);\n if(options.keyboard) {\n element && element.on('keydown', $typeahead.$onKeyDown);\n }\n }, 0, false);\n };\n\n var hide = $typeahead.hide;\n $typeahead.hide = function() {\n $typeahead.$element && $typeahead.$element.off('mousedown', $typeahead.$onMouseDown);\n if(options.keyboard) {\n element && element.off('keydown', $typeahead.$onKeyDown);\n }\n if(!options.autoSelect)\n $typeahead.activate(-1);\n hide();\n };\n\n return $typeahead;\n\n }\n\n // Helper functions\n\n function safeDigest(scope) {\n scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();\n }\n\n TypeaheadFactory.defaults = defaults;\n return TypeaheadFactory;\n\n };\n\n })\n\n .directive('bsTypeahead', function($window, $parse, $q, $typeahead, $parseOptions) {\n\n var defaults = $typeahead.defaults;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'filter', 'limit', 'minLength', 'watchOptions', 'selectMode', 'autoSelect', 'comparator', 'id', 'prefixEvent', 'prefixClass'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'trimValue'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false;\n });\n\n // Disable browser autocompletion\n element.attr('autocomplete' ,'false');\n\n // Build proper bsOptions\n var filter = options.filter || defaults.filter;\n var limit = options.limit || defaults.limit;\n var comparator = options.comparator || defaults.comparator;\n\n var bsOptions = attr.bsOptions;\n if(filter) bsOptions += ' | ' + filter + ':$viewValue';\n if (comparator) bsOptions += ':' + comparator;\n if(limit) bsOptions += ' | limitTo:' + limit;\n var parsedOptions = $parseOptions(bsOptions);\n\n // Initialize typeahead\n var typeahead = $typeahead(element, controller, options);\n\n // Watch options on demand\n if(options.watchOptions) {\n // Watch bsOptions values before filtering for changes, drop function calls\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').replace(/\\(.*\\)/g, '').trim();\n scope.$watchCollection(watchedOptions, function (newValue, oldValue) {\n // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue);\n parsedOptions.valuesFn(scope, controller).then(function (values) {\n typeahead.update(values);\n controller.$render();\n });\n });\n }\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('$watch', element.attr('ng-model'), newValue);\n scope.$modelValue = newValue; // Publish modelValue on scope for custom templates\n parsedOptions.valuesFn(scope, controller)\n .then(function(values) {\n // Prevent input with no future prospect if selectMode is truthy\n // @TODO test selectMode\n if(options.selectMode && !values.length && newValue.length > 0) {\n controller.$setViewValue(controller.$viewValue.substring(0, controller.$viewValue.length - 1));\n return;\n }\n if(values.length > limit) values = values.slice(0, limit);\n var isVisible = typeahead.$isVisible();\n isVisible && typeahead.update(values);\n // Do not re-queue an update if a correct value has been selected\n if(values.length === 1 && values[0].value === newValue) return;\n !isVisible && typeahead.update(values);\n // Queue a new rendering that will leverage collection loading\n controller.$render();\n });\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var displayValue = parsedOptions.displayValue(modelValue);\n\n // If we can determine the displayValue, use that\n if (displayValue) return displayValue;\n\n // If there's no display value, attempt to use the modelValue.\n // If the model is an object not much we can do\n if (modelValue && typeof modelValue !== 'object') {\n return modelValue;\n }\n return '';\n });\n\n // Model rendering in view\n controller.$render = function () {\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n if(controller.$isEmpty(controller.$viewValue)) return element.val('');\n var index = typeahead.$getIndex(controller.$modelValue);\n var selected = angular.isDefined(index) ? typeahead.$scope.$matches[index].label : controller.$viewValue;\n selected = angular.isObject(selected) ? parsedOptions.displayValue(selected) : selected;\n var value = selected ? selected.toString().replace(/<(?:.|\\n)*?>/gm, '') : '';\n element.val(options.trimValue === false ? value : value.trim());\n };\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (typeahead) typeahead.destroy();\n options = null;\n typeahead = null;\n });\n\n }\n };\n\n });\n\n})(window, document);\n","'use strict';\n\n// NOTICE: This file was forked from the angular-material project (github.com/angular/material)\n// MIT Licensed - Copyright (c) 2014-2015 Google, Inc. http://angularjs.org\n\nangular.module('mgcrea.ngStrap.core', [])\n .service('$bsCompiler', bsCompilerService);\n\nfunction bsCompilerService($q, $http, $injector, $compile, $controller, $templateCache) {\n /* jshint validthis: true */\n\n /*\n * @ngdoc service\n * @name $bsCompiler\n * @module material.core\n * @description\n * The $bsCompiler service is an abstraction of angular's compiler, that allows the developer\n * to easily compile an element with a templateUrl, controller, and locals.\n *\n * @usage\n * \n * $bsCompiler.compile({\n * templateUrl: 'modal.html',\n * controller: 'ModalCtrl',\n * locals: {\n * modal: myModalInstance;\n * }\n * }).then(function(compileData) {\n * compileData.element; // modal.html's template in an element\n * compileData.link(myScope); //attach controller & scope to element\n * });\n * \n */\n\n /*\n * @ngdoc method\n * @name $bsCompiler#compile\n * @description A helper to compile an HTML template/templateUrl with a given controller,\n * locals, and scope.\n * @param {object} options An options object, with the following properties:\n *\n * - `controller` - `{(string=|function()=}` Controller fn that should be associated with\n * newly created scope or the name of a registered controller if passed as a string.\n * - `controllerAs` - `{string=}` A controller alias name. If present the controller will be\n * published to scope under the `controllerAs` name.\n * - `template` - `{string=}` An html template as a string.\n * - `templateUrl` - `{string=}` A path to an html template.\n * - `transformTemplate` - `{function(template)=}` A function which transforms the template after\n * it is loaded. It will be given the template string as a parameter, and should\n * return a a new string representing the transformed template.\n * - `resolve` - `{Object.=}` - An optional map of dependencies which should\n * be injected into the controller. If any of these dependencies are promises, the compiler\n * will wait for them all to be resolved, or if one is rejected before the controller is\n * instantiated `compile()` will fail..\n * * `key` - `{string}`: a name of a dependency to be injected into the controller.\n * * `factory` - `{string|function}`: If `string` then it is an alias for a service.\n * Otherwise if function, then it is injected and the return value is treated as the\n * dependency. If the result is a promise, it is resolved before its value is\n * injected into the controller.\n *\n * @returns {object=} promise A promise, which will be resolved with a `compileData` object.\n * `compileData` has the following properties:\n *\n * - `element` - `{element}`: an uncompiled element matching the provided template.\n * - `link` - `{function(scope)}`: A link function, which, when called, will compile\n * the element and instantiate the provided controller (if given).\n * - `locals` - `{object}`: The locals which will be passed into the controller once `link` is\n * called. If `bindToController` is true, they will be coppied to the ctrl instead\n * - `bindToController` - `bool`: bind the locals to the controller, instead of passing them in.\n */\n this.compile = function(options) {\n\n if(options.template && /\\.html$/.test(options.template)) {\n console.warn('Deprecated use of `template` option to pass a file. Please use the `templateUrl` option instead.');\n options.templateUrl = options.template;\n options.template = '';\n }\n\n var templateUrl = options.templateUrl;\n var template = options.template || '';\n var controller = options.controller;\n var controllerAs = options.controllerAs;\n var resolve = angular.copy(options.resolve || {});\n var locals = angular.copy(options.locals || {});\n var transformTemplate = options.transformTemplate || angular.identity;\n var bindToController = options.bindToController;\n\n // Take resolve values and invoke them.\n // Resolves can either be a string (value: 'MyRegisteredAngularConst'),\n // or an invokable 'factory' of sorts: (value: function ValueGetter($dependency) {})\n angular.forEach(resolve, function(value, key) {\n if (angular.isString(value)) {\n resolve[key] = $injector.get(value);\n } else {\n resolve[key] = $injector.invoke(value);\n }\n });\n // Add the locals, which are just straight values to inject\n // eg locals: { three: 3 }, will inject three into the controller\n angular.extend(resolve, locals);\n\n if (templateUrl) {\n resolve.$template = fetchTemplate(templateUrl);\n } else {\n resolve.$template = $q.when(template);\n }\n\n if (options.contentTemplate) {\n // TODO(mgcrea): deprecate?\n resolve.$template = $q.all([resolve.$template, fetchTemplate(options.contentTemplate)])\n .then(function(templates) {\n var templateEl = angular.element(templates[0]);\n var contentEl = findElement('[ng-bind=\"content\"]', templateEl[0]).removeAttr('ng-bind').html(templates[1]);\n // Drop the default footer as you probably don't want it if you use a custom contentTemplate\n if(!options.templateUrl) contentEl.next().remove();\n return templateEl[0].outerHTML;\n });\n }\n\n // Wait for all the resolves to finish if they are promises\n return $q.all(resolve).then(function(locals) {\n\n var template = transformTemplate(locals.$template);\n if (options.html) {\n template = template.replace(/ng-bind=\"/ig, 'ng-bind-html=\"');\n }\n // var element = options.element || angular.element('
').html(template.trim()).contents();\n var element = angular.element('
').html(template.trim()).contents();\n var linkFn = $compile(element);\n\n // Return a linking function that can be used later when the element is ready\n return {\n locals: locals,\n element: element,\n link: function link(scope) {\n locals.$scope = scope;\n\n // Instantiate controller if it exists, because we have scope\n if (controller) {\n var invokeCtrl = $controller(controller, locals, true);\n if (bindToController) {\n angular.extend(invokeCtrl.instance, locals);\n }\n // Support angular@~1.2 invokeCtrl\n var ctrl = angular.isObject(invokeCtrl) ? invokeCtrl : invokeCtrl();\n // See angular-route source for this logic\n element.data('$ngControllerController', ctrl);\n element.children().data('$ngControllerController', ctrl);\n\n if (controllerAs) {\n scope[controllerAs] = ctrl;\n }\n }\n\n return linkFn.apply(null, arguments);\n }\n };\n });\n\n };\n\n function findElement(query, element) {\n return angular.element((element || document).querySelectorAll(query));\n }\n\n var fetchPromises = {};\n function fetchTemplate(template) {\n if(fetchPromises[template]) return fetchPromises[template];\n return (fetchPromises[template] = $http.get(template, {cache: $templateCache})\n .then(function(res) {\n return res.data;\n }));\n }\n\n}\n","'use strict';\n\nangular.module('mgcrea.ngStrap.helpers.dateFormatter', [])\n\n .service('$dateFormatter', function($locale, dateFilter) {\n\n // The unused `lang` arguments are on purpose. The default implementation does not\n // use them and it always uses the locale loaded into the `$locale` service.\n // Custom implementations might use it, thus allowing different directives to\n // have different languages.\n\n this.getDefaultLocale = function() {\n return $locale.id;\n };\n\n // Format is either a data format name, e.g. \"shortTime\" or \"fullDate\", or a date format\n // Return either the corresponding date format or the given date format.\n this.getDatetimeFormat = function(format, lang) {\n return $locale.DATETIME_FORMATS[format] || format;\n };\n\n this.weekdaysShort = function(lang) {\n return $locale.DATETIME_FORMATS.SHORTDAY;\n };\n\n function splitTimeFormat(format) {\n return /(h+)([:\\.])?(m+)([:\\.])?(s*)[ ]?(a?)/i.exec(format).slice(1);\n }\n\n // h:mm a => h\n this.hoursFormat = function(timeFormat) {\n return splitTimeFormat(timeFormat)[0];\n };\n\n // h:mm a => mm\n this.minutesFormat = function(timeFormat) {\n return splitTimeFormat(timeFormat)[2];\n };\n\n // h:mm:ss a => ss\n this.secondsFormat = function(timeFormat) {\n return splitTimeFormat(timeFormat)[4];\n };\n\n // h:mm a => :\n this.timeSeparator = function(timeFormat) {\n return splitTimeFormat(timeFormat)[1];\n };\n\n // h:mm:ss a => true, h:mm a => false\n this.showSeconds = function(timeFormat) {\n return !!splitTimeFormat(timeFormat)[4];\n };\n\n // h:mm a => true, H.mm => false\n this.showAM = function(timeFormat) {\n return !!splitTimeFormat(timeFormat)[5];\n };\n\n this.formatDate = function(date, format, lang, timezone){\n return dateFilter(date, format, timezone);\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.affix', ['mgcrea.ngStrap.helpers.dimensions', 'mgcrea.ngStrap.helpers.debounce'])\n\n .provider('$affix', function() {\n\n var defaults = this.defaults = {\n offsetTop: 'auto',\n inlineStyles: true\n };\n\n this.$get = function($window, debounce, dimensions) {\n\n var bodyEl = angular.element($window.document.body);\n var windowEl = angular.element($window);\n\n function AffixFactory(element, config) {\n\n var $affix = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n var targetEl = options.target;\n\n // Initial private vars\n var reset = 'affix affix-top affix-bottom',\n setWidth = false,\n initialAffixTop = 0,\n initialOffsetTop = 0,\n offsetTop = 0,\n offsetBottom = 0,\n affixed = null,\n unpin = null;\n\n var parent = element.parent();\n // Options: custom parent\n if (options.offsetParent) {\n if (options.offsetParent.match(/^\\d+$/)) {\n for (var i = 0; i < (options.offsetParent * 1) - 1; i++) {\n parent = parent.parent();\n }\n }\n else {\n parent = angular.element(options.offsetParent);\n }\n }\n\n $affix.init = function() {\n\n this.$parseOffsets();\n initialOffsetTop = dimensions.offset(element[0]).top + initialAffixTop;\n setWidth = !element[0].style.width;\n\n // Bind events\n targetEl.on('scroll', this.checkPosition);\n targetEl.on('click', this.checkPositionWithEventLoop);\n windowEl.on('resize', this.$debouncedOnResize);\n\n // Both of these checkPosition() calls are necessary for the case where\n // the user hits refresh after scrolling to the bottom of the page.\n this.checkPosition();\n this.checkPositionWithEventLoop();\n\n };\n\n $affix.destroy = function() {\n\n // Unbind events\n targetEl.off('scroll', this.checkPosition);\n targetEl.off('click', this.checkPositionWithEventLoop);\n windowEl.off('resize', this.$debouncedOnResize);\n\n };\n\n $affix.checkPositionWithEventLoop = function() {\n\n // IE 9 throws an error if we use 'this' instead of '$affix'\n // in this setTimeout call\n setTimeout($affix.checkPosition, 1);\n\n };\n\n $affix.checkPosition = function() {\n // if (!this.$element.is(':visible')) return\n\n var scrollTop = getScrollTop();\n var position = dimensions.offset(element[0]);\n var elementHeight = dimensions.height(element[0]);\n\n // Get required affix class according to position\n var affix = getRequiredAffixClass(unpin, position, elementHeight);\n\n // Did affix status changed this last check?\n if(affixed === affix) return;\n affixed = affix;\n\n // Add proper affix class\n element.removeClass(reset).addClass('affix' + ((affix !== 'middle') ? '-' + affix : ''));\n\n if(affix === 'top') {\n unpin = null;\n if(setWidth) {\n element.css('width', '');\n }\n if (options.inlineStyles) {\n element.css('position', (options.offsetParent) ? '' : 'relative');\n element.css('top', '');\n }\n } else if(affix === 'bottom') {\n if (options.offsetUnpin) {\n unpin = -(options.offsetUnpin * 1);\n }\n else {\n // Calculate unpin threshold when affixed to bottom.\n // Hopefully the browser scrolls pixel by pixel.\n unpin = position.top - scrollTop;\n }\n if(setWidth) {\n element.css('width', '');\n }\n if (options.inlineStyles) {\n element.css('position', (options.offsetParent) ? '' : 'relative');\n element.css('top', (options.offsetParent) ? '' : ((bodyEl[0].offsetHeight - offsetBottom - elementHeight - initialOffsetTop) + 'px'));\n }\n } else { // affix === 'middle'\n unpin = null;\n if(setWidth) {\n element.css('width', element[0].offsetWidth + 'px');\n }\n if (options.inlineStyles) {\n element.css('position', 'fixed');\n element.css('top', initialAffixTop + 'px');\n }\n }\n\n };\n\n $affix.$onResize = function() {\n $affix.$parseOffsets();\n $affix.checkPosition();\n };\n $affix.$debouncedOnResize = debounce($affix.$onResize, 50);\n\n $affix.$parseOffsets = function() {\n var initialPosition = element.css('position');\n // Reset position to calculate correct offsetTop\n if (options.inlineStyles){\n element.css('position', (options.offsetParent) ? '' : 'relative');\n }\n\n if(options.offsetTop) {\n if(options.offsetTop === 'auto') {\n options.offsetTop = '+0';\n }\n if(options.offsetTop.match(/^[-+]\\d+$/)) {\n initialAffixTop = - options.offsetTop * 1;\n if(options.offsetParent) {\n offsetTop = dimensions.offset(parent[0]).top + (options.offsetTop * 1);\n }\n else {\n offsetTop = dimensions.offset(element[0]).top - dimensions.css(element[0], 'marginTop', true) + (options.offsetTop * 1);\n }\n }\n else {\n offsetTop = options.offsetTop * 1;\n }\n }\n\n if(options.offsetBottom) {\n if(options.offsetParent && options.offsetBottom.match(/^[-+]\\d+$/)) {\n // add 1 pixel due to rounding problems...\n offsetBottom = getScrollHeight() - (dimensions.offset(parent[0]).top + dimensions.height(parent[0])) + (options.offsetBottom * 1) + 1;\n }\n else {\n offsetBottom = options.offsetBottom * 1;\n }\n }\n\n // Bring back the element's position after calculations\n if (options.inlineStyles){\n element.css('position', initialPosition);\n }\n };\n\n // Private methods\n\n function getRequiredAffixClass(unpin, position, elementHeight) {\n\n var scrollTop = getScrollTop();\n var scrollHeight = getScrollHeight();\n\n if(scrollTop <= offsetTop) {\n return 'top';\n } else if(unpin !== null && (scrollTop + unpin <= position.top)) {\n return 'middle';\n } else if(offsetBottom !== null && (position.top + elementHeight + initialAffixTop >= scrollHeight - offsetBottom)) {\n return 'bottom';\n } else {\n return 'middle';\n }\n\n }\n\n function getScrollTop() {\n return targetEl[0] === $window ? $window.pageYOffset : targetEl[0].scrollTop;\n }\n\n function getScrollHeight() {\n return targetEl[0] === $window ? $window.document.body.scrollHeight : targetEl[0].scrollHeight;\n }\n\n $affix.init();\n return $affix;\n\n }\n\n return AffixFactory;\n\n };\n\n })\n\n .directive('bsAffix', function($affix, $window) {\n\n return {\n restrict: 'EAC',\n require: '^?bsAffixTarget',\n link: function postLink(scope, element, attr, affixTarget) {\n\n var options = {scope: scope, target: affixTarget ? affixTarget.$element : angular.element($window)};\n angular.forEach(['offsetTop', 'offsetBottom', 'offsetParent', 'offsetUnpin', 'inlineStyles'], function(key) {\n if(angular.isDefined(attr[key])) {\n var option = attr[key];\n if (/true/i.test(option)) option = true;\n if (/false/i.test(option)) option = false;\n options[key] = option;\n }\n });\n\n var affix = $affix(element, options);\n scope.$on('$destroy', function() {\n affix && affix.destroy();\n options = null;\n affix = null;\n });\n\n }\n };\n\n })\n\n .directive('bsAffixTarget', function() {\n return {\n controller: function($element) {\n this.$element = $element;\n }\n };\n });\n","'use strict';\n\n// @BUG: following snippet won't compile correctly\n// @TODO: submit issue to core\n// ' ' +\n\nangular.module('mgcrea.ngStrap.alert', ['mgcrea.ngStrap.modal'])\n\n .provider('$alert', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'alert',\n prefixEvent: 'alert',\n placement: null,\n templateUrl: 'alert/alert.tpl.html',\n container: false,\n element: null,\n backdrop: false,\n keyboard: true,\n show: true,\n // Specific options\n duration: false,\n type: false,\n dismissable: true\n };\n\n this.$get = function($modal, $timeout) {\n\n function AlertFactory(config) {\n\n var $alert = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $alert = $modal(options);\n\n // Support scope as string options [/*title, content, */ type, dismissable]\n $alert.$scope.dismissable = !!options.dismissable;\n if(options.type) {\n $alert.$scope.type = options.type;\n }\n\n // Support auto-close duration\n var show = $alert.show;\n if(options.duration) {\n $alert.show = function() {\n show();\n $timeout(function() {\n $alert.hide();\n }, options.duration * 1000);\n };\n }\n\n return $alert;\n\n }\n\n return AlertFactory;\n\n };\n\n })\n\n .directive('bsAlert', function($window, $sce, $alert) {\n\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope, element: element, show: false};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'keyboard', 'html', 'container', 'animation', 'duration', 'dismissable'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['keyboard', 'html', 'container', 'dismissable'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // overwrite inherited title value when no value specified\n // fix for angular 1.3.1 531a8de72c439d8ddd064874bf364c00cedabb11\n if (!scope.hasOwnProperty('title')){\n scope.title = '';\n }\n\n // Support scope as data-attrs\n angular.forEach(['title', 'content', 'type'], function(key) {\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\n scope[key] = $sce.trustAsHtml(newValue);\n });\n });\n\n // Support scope as an object\n attr.bsAlert && scope.$watch(attr.bsAlert, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.content = newValue;\n }\n }, true);\n\n // Initialize alert\n var alert = $alert(options);\n\n // Trigger\n element.on(attr.trigger || 'click', alert.toggle);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (alert) alert.destroy();\n options = null;\n alert = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.aside', ['mgcrea.ngStrap.modal'])\n\n .provider('$aside', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade-and-slide-right',\n prefixClass: 'aside',\n prefixEvent: 'aside',\n placement: 'right',\n templateUrl: 'aside/aside.tpl.html',\n contentTemplate: false,\n container: false,\n element: null,\n backdrop: true,\n keyboard: true,\n html: false,\n show: true\n };\n\n this.$get = function($modal) {\n\n function AsideFactory(config) {\n\n var $aside = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $aside = $modal(options);\n\n return $aside;\n\n }\n\n return AsideFactory;\n\n };\n\n })\n\n .directive('bsAside', function($window, $sce, $aside) {\n\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n // Directive options\n var options = {scope: scope, element: element, show: false};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['backdrop', 'keyboard', 'html', 'container'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Support scope as data-attrs\n angular.forEach(['title', 'content'], function(key) {\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\n scope[key] = $sce.trustAsHtml(newValue);\n });\n });\n\n // Support scope as an object\n attr.bsAside && scope.$watch(attr.bsAside, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.content = newValue;\n }\n }, true);\n\n // Initialize aside\n var aside = $aside(options);\n\n // Trigger\n element.on(attr.trigger || 'click', aside.toggle);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (aside) aside.destroy();\n options = null;\n aside = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.button', [])\n\n .provider('$button', function() {\n\n var defaults = this.defaults = {\n activeClass:'active',\n toggleEvent:'click'\n };\n\n this.$get = function() {\n return {defaults: defaults};\n };\n\n })\n\n .directive('bsCheckboxGroup', function() {\n\n return {\n restrict: 'A',\n require: 'ngModel',\n compile: function postLink(element, attr) {\n element.attr('data-toggle', 'buttons');\n element.removeAttr('ng-model');\n var children = element[0].querySelectorAll('input[type=\"checkbox\"]');\n angular.forEach(children, function(child) {\n var childEl = angular.element(child);\n childEl.attr('bs-checkbox', '');\n childEl.attr('ng-model', attr.ngModel + '.' + childEl.attr('value'));\n });\n }\n\n };\n\n })\n\n .directive('bsCheckbox', function($button, $$rAF) {\n\n var defaults = $button.defaults;\n var constantValueRegExp = /^(true|false|\\d+)$/;\n\n return {\n restrict: 'A',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n var options = defaults;\n\n // Support label > input[type=\"checkbox\"]\n var isInput = element[0].nodeName === 'INPUT';\n var activeElement = isInput ? element.parent() : element;\n\n var trueValue = angular.isDefined(attr.trueValue) ? attr.trueValue : true;\n if(constantValueRegExp.test(attr.trueValue)) {\n trueValue = scope.$eval(attr.trueValue);\n }\n var falseValue = angular.isDefined(attr.falseValue) ? attr.falseValue : false;\n if(constantValueRegExp.test(attr.falseValue)) {\n falseValue = scope.$eval(attr.falseValue);\n }\n\n // Parse exotic values\n var hasExoticValues = typeof trueValue !== 'boolean' || typeof falseValue !== 'boolean';\n if(hasExoticValues) {\n controller.$parsers.push(function(viewValue) {\n // console.warn('$parser', element.attr('ng-model'), 'viewValue', viewValue);\n return viewValue ? trueValue : falseValue;\n });\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n return angular.equals(modelValue, trueValue);\n });\n // Fix rendering for exotic values\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n controller.$render();\n });\n }\n\n // model -> view\n controller.$render = function () {\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n var isActive = angular.equals(controller.$modelValue, trueValue);\n $$rAF(function() {\n if(isInput) element[0].checked = isActive;\n activeElement.toggleClass(options.activeClass, isActive);\n });\n };\n\n // view -> model\n element.bind(options.toggleEvent, function() {\n scope.$apply(function () {\n // console.warn('!click', element.attr('ng-model'), 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue, 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue);\n if(!isInput) {\n controller.$setViewValue(!activeElement.hasClass('active'));\n }\n if(!hasExoticValues) {\n controller.$render();\n }\n });\n });\n\n }\n\n };\n\n })\n\n .directive('bsRadioGroup', function() {\n\n return {\n restrict: 'A',\n require: 'ngModel',\n compile: function postLink(element, attr) {\n element.attr('data-toggle', 'buttons');\n element.removeAttr('ng-model');\n var children = element[0].querySelectorAll('input[type=\"radio\"]');\n angular.forEach(children, function(child) {\n angular.element(child).attr('bs-radio', '');\n angular.element(child).attr('ng-model', attr.ngModel);\n });\n }\n\n };\n\n })\n\n .directive('bsRadio', function($button, $$rAF) {\n\n var defaults = $button.defaults;\n var constantValueRegExp = /^(true|false|\\d+)$/;\n\n return {\n restrict: 'A',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n var options = defaults;\n\n // Support `label > input[type=\"radio\"]` markup\n var isInput = element[0].nodeName === 'INPUT';\n var activeElement = isInput ? element.parent() : element;\n\n var value;\n attr.$observe('value', function(v) {\n value = constantValueRegExp.test(v) ? scope.$eval(v) : v;\n controller.$render();\n });\n\n // model -> view\n controller.$render = function () {\n // console.warn('$render', element.attr('value'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n var isActive = angular.equals(controller.$modelValue, value);\n $$rAF(function() {\n if(isInput) element[0].checked = isActive;\n activeElement.toggleClass(options.activeClass, isActive);\n });\n };\n\n // view -> model\n element.bind(options.toggleEvent, function() {\n scope.$apply(function () {\n // console.warn('!click', element.attr('value'), 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue, 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue);\n controller.$setViewValue(value);\n controller.$render();\n });\n });\n\n }\n\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.collapse', [])\n\n .provider('$collapse', function() {\n\n var defaults = this.defaults = {\n animation: 'am-collapse',\n disallowToggle: false,\n activeClass: 'in',\n startCollapsed: false,\n allowMultiple: false\n };\n\n var controller = this.controller = function($scope, $element, $attrs) {\n var self = this;\n\n // Attributes options\n self.$options = angular.copy(defaults);\n angular.forEach(['animation', 'disallowToggle', 'activeClass', 'startCollapsed', 'allowMultiple'], function (key) {\n if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['disallowToggle', 'startCollapsed', 'allowMultiple'], function(key) {\n if(angular.isDefined($attrs[key]) && falseValueRegExp.test($attrs[key])) {\n self.$options[key] = false;\n }\n });\n\n self.$toggles = [];\n self.$targets = [];\n\n self.$viewChangeListeners = [];\n\n self.$registerToggle = function(element) {\n self.$toggles.push(element);\n };\n self.$registerTarget = function(element) {\n self.$targets.push(element);\n };\n\n self.$unregisterToggle = function(element) {\n var index = self.$toggles.indexOf(element);\n // remove toggle from $toggles array\n self.$toggles.splice(index, 1);\n };\n self.$unregisterTarget = function(element) {\n var index = self.$targets.indexOf(element);\n\n // remove element from $targets array\n self.$targets.splice(index, 1);\n\n if (self.$options.allowMultiple) {\n // remove target index from $active array values\n deactivateItem(element);\n }\n\n // fix active item indexes\n fixActiveItemIndexes(index);\n\n self.$viewChangeListeners.forEach(function(fn) {\n fn();\n });\n };\n\n // use array to store all the currently open panels\n self.$targets.$active = !self.$options.startCollapsed ? [0] : [];\n self.$setActive = $scope.$setActive = function(value) {\n if(angular.isArray(value)) {\n self.$targets.$active = value;\n }\n else if(!self.$options.disallowToggle) {\n // toogle element active status\n isActive(value) ? deactivateItem(value) : activateItem(value);\n } else {\n activateItem(value);\n }\n\n self.$viewChangeListeners.forEach(function(fn) {\n fn();\n });\n };\n\n self.$activeIndexes = function() {\n return self.$options.allowMultiple ? self.$targets.$active :\n self.$targets.$active.length === 1 ? self.$targets.$active[0] : -1;\n };\n\n function fixActiveItemIndexes(index) {\n // item with index was removed, so we\n // need to adjust other items index values\n var activeIndexes = self.$targets.$active;\n for(var i = 0; i < activeIndexes.length; i++) {\n if (index < activeIndexes[i]) {\n activeIndexes[i] = activeIndexes[i] - 1;\n }\n\n // the last item is active, so we need to\n // adjust its index\n if (activeIndexes[i] === self.$targets.length) {\n activeIndexes[i] = self.$targets.length - 1;\n }\n }\n }\n\n function isActive(value) {\n var activeItems = self.$targets.$active;\n return activeItems.indexOf(value) === -1 ? false : true;\n }\n\n function deactivateItem(value) {\n var index = self.$targets.$active.indexOf(value);\n if (index !== -1) {\n self.$targets.$active.splice(index, 1);\n }\n }\n\n function activateItem(value) {\n if (!self.$options.allowMultiple) {\n // remove current selected item\n self.$targets.$active.splice(0, 1);\n }\n\n if (self.$targets.$active.indexOf(value) === -1) {\n self.$targets.$active.push(value);\n }\n }\n\n };\n\n this.$get = function() {\n var $collapse = {};\n $collapse.defaults = defaults;\n $collapse.controller = controller;\n return $collapse;\n };\n\n })\n\n .directive('bsCollapse', function($window, $animate, $collapse) {\n\n var defaults = $collapse.defaults;\n\n return {\n require: ['?ngModel', 'bsCollapse'],\n controller: ['$scope', '$element', '$attrs', $collapse.controller],\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsCollapseCtrl = controllers[1];\n\n if(ngModelCtrl) {\n\n // Update the modelValue following\n bsCollapseCtrl.$viewChangeListeners.push(function() {\n ngModelCtrl.$setViewValue(bsCollapseCtrl.$activeIndexes());\n });\n\n // modelValue -> $formatters -> viewValue\n ngModelCtrl.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n if (angular.isArray(modelValue)) {\n // model value is an array, so just replace\n // the active items directly\n bsCollapseCtrl.$setActive(modelValue);\n }\n else {\n var activeIndexes = bsCollapseCtrl.$activeIndexes();\n\n if (angular.isArray(activeIndexes)) {\n // we have an array of selected indexes\n if (activeIndexes.indexOf(modelValue * 1) === -1) {\n // item with modelValue index is not active\n bsCollapseCtrl.$setActive(modelValue * 1);\n }\n }\n else if (activeIndexes !== modelValue * 1) {\n bsCollapseCtrl.$setActive(modelValue * 1);\n }\n }\n return modelValue;\n });\n\n }\n\n }\n };\n\n })\n\n .directive('bsCollapseToggle', function() {\n\n return {\n require: ['^?ngModel', '^bsCollapse'],\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsCollapseCtrl = controllers[1];\n\n // Add base attr\n element.attr('data-toggle', 'collapse');\n\n // Push pane to parent bsCollapse controller\n bsCollapseCtrl.$registerToggle(element);\n\n // remove toggle from collapse controller when toggle is destroyed\n scope.$on('$destroy', function() {\n bsCollapseCtrl.$unregisterToggle(element);\n });\n\n element.on('click', function() {\n var index = attrs.bsCollapseToggle && attrs.bsCollapseToggle !== 'bs-collapse-toggle' ? attrs.bsCollapseToggle : bsCollapseCtrl.$toggles.indexOf(element);\n bsCollapseCtrl.$setActive(index * 1);\n scope.$apply();\n });\n\n }\n };\n\n })\n\n .directive('bsCollapseTarget', function($animate) {\n\n return {\n require: ['^?ngModel', '^bsCollapse'],\n // scope: true,\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsCollapseCtrl = controllers[1];\n\n // Add base class\n element.addClass('collapse');\n\n // Add animation class\n if(bsCollapseCtrl.$options.animation) {\n element.addClass(bsCollapseCtrl.$options.animation);\n }\n\n // Push pane to parent bsCollapse controller\n bsCollapseCtrl.$registerTarget(element);\n\n // remove pane target from collapse controller when target is destroyed\n scope.$on('$destroy', function() {\n bsCollapseCtrl.$unregisterTarget(element);\n });\n\n function render() {\n var index = bsCollapseCtrl.$targets.indexOf(element);\n var active = bsCollapseCtrl.$activeIndexes();\n var action = 'removeClass';\n if (angular.isArray(active)) {\n if (active.indexOf(index) !== -1) {\n action = 'addClass';\n }\n }\n else if (index === active) {\n action = 'addClass';\n }\n\n $animate[action](element, bsCollapseCtrl.$options.activeClass);\n }\n\n bsCollapseCtrl.$viewChangeListeners.push(function() {\n render();\n });\n render();\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.datepicker', [\n 'mgcrea.ngStrap.helpers.dateParser',\n 'mgcrea.ngStrap.helpers.dateFormatter',\n 'mgcrea.ngStrap.tooltip'])\n\n .provider('$datepicker', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n //uncommenting the following line will break backwards compatability\n // prefixEvent: 'datepicker',\n prefixClass: 'datepicker',\n placement: 'bottom-left',\n templateUrl: 'datepicker/datepicker.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n // lang: $locale.id,\n useNative: false,\n dateType: 'date',\n dateFormat: 'shortDate',\n timezone: null,\n modelDateFormat: null,\n dayFormat: 'dd',\n monthFormat: 'MMM',\n yearFormat: 'yyyy',\n monthTitleFormat: 'MMMM yyyy',\n yearTitleFormat: 'yyyy',\n strictFormat: false,\n autoclose: false,\n minDate: -Infinity,\n maxDate: +Infinity,\n startView: 0,\n minView: 0,\n startWeek: 0,\n daysOfWeekDisabled: '',\n iconLeft: 'glyphicon glyphicon-chevron-left',\n iconRight: 'glyphicon glyphicon-chevron-right'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, datepickerViews, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\n\n function DatepickerFactory(element, controller, config) {\n\n var $datepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $datepicker.$options;\n var scope = $datepicker.$scope;\n if(options.startView) options.startView -= options.minView;\n\n // View vars\n\n var pickerViews = datepickerViews($datepicker);\n $datepicker.$views = pickerViews.views;\n var viewDate = pickerViews.viewDate;\n scope.$mode = options.startView;\n scope.$iconLeft = options.iconLeft;\n scope.$iconRight = options.iconRight;\n var $picker = $datepicker.$views[scope.$mode];\n\n // Scope methods\n\n scope.$select = function(date) {\n $datepicker.select(date);\n };\n scope.$selectPane = function(value) {\n $datepicker.$selectPane(value);\n };\n scope.$toggleMode = function() {\n $datepicker.setMode((scope.$mode + 1) % $datepicker.$views.length);\n };\n\n // Public methods\n\n $datepicker.update = function(date) {\n // console.warn('$datepicker.update() newValue=%o', date);\n if(angular.isDate(date) && !isNaN(date.getTime())) {\n $datepicker.$date = date;\n $picker.update.call($picker, date);\n }\n // Build only if pristine\n $datepicker.$build(true);\n };\n\n $datepicker.updateDisabledDates = function(dateRanges) {\n options.disabledDateRanges = dateRanges;\n for(var i = 0, l = scope.rows.length; i < l; i++) {\n angular.forEach(scope.rows[i], $datepicker.$setDisabledEl);\n }\n };\n\n $datepicker.select = function(date, keep) {\n // console.warn('$datepicker.select', date, scope.$mode);\n if(!angular.isDate(controller.$dateValue)) controller.$dateValue = new Date(date);\n if(!scope.$mode || keep) {\n controller.$setViewValue(angular.copy(date));\n controller.$render();\n if(options.autoclose && !keep) {\n $timeout(function() { $datepicker.hide(true); });\n }\n } else {\n angular.extend(viewDate, {year: date.getFullYear(), month: date.getMonth(), date: date.getDate()});\n $datepicker.setMode(scope.$mode - 1);\n $datepicker.$build();\n }\n };\n\n $datepicker.setMode = function(mode) {\n // console.warn('$datepicker.setMode', mode);\n scope.$mode = mode;\n $picker = $datepicker.$views[scope.$mode];\n $datepicker.$build();\n };\n\n // Protected methods\n\n $datepicker.$build = function(pristine) {\n // console.warn('$datepicker.$build() viewDate=%o', viewDate);\n if(pristine === true && $picker.built) return;\n if(pristine === false && !$picker.built) return;\n $picker.build.call($picker);\n };\n\n $datepicker.$updateSelected = function() {\n for(var i = 0, l = scope.rows.length; i < l; i++) {\n angular.forEach(scope.rows[i], updateSelected);\n }\n };\n\n $datepicker.$isSelected = function(date) {\n return $picker.isSelected(date);\n };\n\n $datepicker.$setDisabledEl = function(el) {\n el.disabled = $picker.isDisabled(el.date);\n };\n\n $datepicker.$selectPane = function(value) {\n var steps = $picker.steps;\n // set targetDate to first day of month to avoid problems with\n // date values rollover. This assumes the viewDate does not\n // depend on the day of the month\n var targetDate = new Date(Date.UTC(viewDate.year + ((steps.year || 0) * value), viewDate.month + ((steps.month || 0) * value), 1));\n angular.extend(viewDate, {year: targetDate.getUTCFullYear(), month: targetDate.getUTCMonth(), date: targetDate.getUTCDate()});\n $datepicker.$build();\n };\n\n $datepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $datepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n if(evt.keyCode === 13) {\n if(!scope.$mode) {\n return $datepicker.hide(true);\n } else {\n return scope.$apply(function() { $datepicker.setMode(scope.$mode - 1); });\n }\n }\n\n // Navigate with keyboard\n $picker.onKeyDown(evt);\n parentScope.$digest();\n };\n\n // Private\n\n function updateSelected(el) {\n el.selected = $datepicker.$isSelected(el.date);\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $datepicker.init;\n $datepicker.init = function() {\n if(isNative && options.useNative) {\n element.prop('type', 'date');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if(isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $datepicker.destroy;\n $datepicker.destroy = function() {\n if(isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $datepicker.show;\n $datepicker.show = function() {\n _show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n // if $datepicker is no longer showing, don't setup events\n if(!$datepicker.$isShown) return;\n $datepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $datepicker.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $datepicker.hide;\n $datepicker.hide = function(blur) {\n if(!$datepicker.$isShown) return;\n $datepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $datepicker.$onKeyDown);\n }\n _hide(blur);\n };\n\n return $datepicker;\n\n }\n\n DatepickerFactory.defaults = defaults;\n return DatepickerFactory;\n\n };\n\n })\n\n .directive('bsDatepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $datepicker) {\n\n var defaults = $datepicker.defaults;\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'autoclose', 'dateType', 'dateFormat', 'timezone', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled', 'id', 'prefixClass', 'prefixEvent'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'autoclose', 'useNative'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!datepicker || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(datepicker),?/i);\n newValue === true ? datepicker.show() : datepicker.hide();\n });\n\n // Initialize datepicker\n var datepicker = $datepicker(element, controller, options);\n options = datepicker.$options;\n // Set expected iOS format\n if(isNative && options.useNative) options.dateFormat = 'yyyy-MM-dd';\n\n var lang = options.lang;\n\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n\n var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});\n\n // Observe attributes for changes\n angular.forEach(['minDate', 'maxDate'], function(key) {\n // console.warn('attr.$observe(%s)', key, attr[key]);\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\n // console.warn('attr.$observe(%s)=%o', key, newValue);\n datepicker.$options[key] = dateParser.getDateForAttribute(key, newValue);\n // Build only if dirty\n !isNaN(datepicker.$options[key]) && datepicker.$build(false);\n validateAgainstMinMaxDate(controller.$dateValue);\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n datepicker.update(controller.$dateValue);\n }, true);\n\n // Normalize undefined/null/empty array,\n // so that we don't treat changing from undefined->null as a change.\n function normalizeDateRanges(ranges) {\n if (!ranges || !ranges.length) return null;\n return ranges;\n }\n\n if (angular.isDefined(attr.disabledDates)) {\n scope.$watch(attr.disabledDates, function(disabledRanges, previousValue) {\n disabledRanges = normalizeDateRanges(disabledRanges);\n previousValue = normalizeDateRanges(previousValue);\n\n if (disabledRanges) {\n datepicker.updateDisabledDates(disabledRanges);\n }\n });\n }\n\n function validateAgainstMinMaxDate(parsedDate) {\n if (!angular.isDate(parsedDate)) return;\n var isMinValid = isNaN(datepicker.$options.minDate) || parsedDate.getTime() >= datepicker.$options.minDate;\n var isMaxValid = isNaN(datepicker.$options.maxDate) || parsedDate.getTime() <= datepicker.$options.maxDate;\n var isValid = isMinValid && isMaxValid;\n controller.$setValidity('date', isValid);\n controller.$setValidity('min', isMinValid);\n controller.$setValidity('max', isMaxValid);\n // Only update the model when we have a valid date\n if(isValid) controller.$dateValue = parsedDate;\n }\n\n // viewValue -> $parsers -> modelValue\n controller.$parsers.unshift(function(viewValue) {\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\n var date;\n // Null values should correctly reset the model value & validity\n if(!viewValue) {\n controller.$setValidity('date', true);\n // BREAKING CHANGE:\n // return null (not undefined) when input value is empty, so angularjs 1.3\n // ngModelController can go ahead and run validators, like ngRequired\n return null;\n }\n var parsedDate = dateParser.parse(viewValue, controller.$dateValue);\n if(!parsedDate || isNaN(parsedDate.getTime())) {\n controller.$setValidity('date', false);\n // return undefined, causes ngModelController to\n // invalidate model value\n return;\n } else {\n validateAgainstMinMaxDate(parsedDate);\n }\n\n if(options.dateType === 'string') {\n date = dateParser.timezoneOffsetAdjust(parsedDate, options.timezone, true);\n return formatDate(date, options.modelDateFormat || options.dateFormat);\n }\n date = dateParser.timezoneOffsetAdjust(controller.$dateValue, options.timezone, true);\n if(options.dateType === 'number') {\n return date.getTime();\n } else if(options.dateType === 'unix') {\n return date.getTime() / 1000;\n } else if(options.dateType === 'iso') {\n return date.toISOString();\n } else {\n return new Date(date);\n }\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var date;\n if(angular.isUndefined(modelValue) || modelValue === null) {\n date = NaN;\n } else if(angular.isDate(modelValue)) {\n date = modelValue;\n } else if(options.dateType === 'string') {\n date = dateParser.parse(modelValue, null, options.modelDateFormat);\n } else if(options.dateType === 'unix') {\n date = new Date(modelValue * 1000);\n } else {\n date = new Date(modelValue);\n }\n // Setup default value?\n // if(isNaN(date.getTime())) {\n // var today = new Date();\n // date = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0, 0);\n // }\n controller.$dateValue = dateParser.timezoneOffsetAdjust(date, options.timezone);\n return getDateFormattedString();\n });\n\n // viewValue -> element\n controller.$render = function() {\n // console.warn('$render(\"%s\"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);\n element.val(getDateFormattedString());\n };\n\n function getDateFormattedString() {\n return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.dateFormat);\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if(datepicker) datepicker.destroy();\n options = null;\n datepicker = null;\n });\n\n }\n };\n\n })\n\n .provider('datepickerViews', function() {\n\n var defaults = this.defaults = {\n dayFormat: 'dd',\n daySplit: 7\n };\n\n // Split array into smaller arrays\n function split(arr, size) {\n var arrays = [];\n while(arr.length > 0) {\n arrays.push(arr.splice(0, size));\n }\n return arrays;\n }\n\n // Modulus operator\n function mod(n, m) {\n return ((n % m) + m) % m;\n }\n\n this.$get = function($dateFormatter, $dateParser, $sce) {\n\n return function(picker) {\n\n var scope = picker.$scope;\n var options = picker.$options;\n\n var lang = options.lang;\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});\n\n var weekDaysMin = $dateFormatter.weekdaysShort(lang);\n var weekDaysLabels = weekDaysMin.slice(options.startWeek).concat(weekDaysMin.slice(0, options.startWeek));\n var weekDaysLabelsHtml = $sce.trustAsHtml('' + weekDaysLabels.join('') + '');\n\n var startDate = picker.$date || (options.startDate ? dateParser.getDateForAttribute('startDate', options.startDate) : new Date());\n var viewDate = {year: startDate.getFullYear(), month: startDate.getMonth(), date: startDate.getDate()};\n\n var views = [{\n format: options.dayFormat,\n split: 7,\n steps: { month: 1 },\n update: function(date, force) {\n if(!this.built || force || date.getFullYear() !== viewDate.year || date.getMonth() !== viewDate.month) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getDate() !== viewDate.date || date.getDate() === 1) {\n // chaging picker current month will cause viewDate.date to be set to first day of the month,\n // in $datepicker.$selectPane, so picker would not update selected day display if\n // user picks first day of the new month.\n // As a workaround, we are always forcing update when picked date is first day of month.\n viewDate.date = picker.$date.getDate();\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstDayOfMonth = new Date(viewDate.year, viewDate.month, 1), firstDayOfMonthOffset = firstDayOfMonth.getTimezoneOffset();\n var firstDate = new Date(+firstDayOfMonth - mod(firstDayOfMonth.getDay() - options.startWeek, 7) * 864e5), firstDateOffset = firstDate.getTimezoneOffset();\n var today = dateParser.timezoneOffsetAdjust(new Date(), options.timezone).toDateString();\n // Handle daylight time switch\n if(firstDateOffset !== firstDayOfMonthOffset) firstDate = new Date(+firstDate + (firstDateOffset - firstDayOfMonthOffset) * 60e3);\n var days = [], day;\n for(var i = 0; i < 42; i++) { // < 7 * 6\n day = dateParser.daylightSavingAdjust(new Date(firstDate.getFullYear(), firstDate.getMonth(), firstDate.getDate() + i));\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)});\n }\n scope.title = formatDate(firstDayOfMonth, options.monthTitleFormat);\n scope.showLabels = true;\n scope.labels = weekDaysLabelsHtml;\n scope.rows = split(days, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth() && date.getDate() === picker.$date.getDate();\n },\n isDisabled: function(date) {\n var time = date.getTime();\n\n // Disabled because of min/max date.\n if (time < options.minDate || time > options.maxDate) return true;\n\n // Disabled due to being a disabled day of the week\n if (options.daysOfWeekDisabled.indexOf(date.getDay()) !== -1) return true;\n\n // Disabled because of disabled date range.\n if (options.disabledDateRanges) {\n for (var i = 0; i < options.disabledDateRanges.length; i++) {\n if (time >= options.disabledDateRanges[i].start && time <= options.disabledDateRanges[i].end) {\n return true;\n }\n }\n }\n\n return false;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualTime = picker.$date.getTime();\n var newDate;\n\n if(evt.keyCode === 37) newDate = new Date(actualTime - 1 * 864e5);\n else if(evt.keyCode === 38) newDate = new Date(actualTime - 7 * 864e5);\n else if(evt.keyCode === 39) newDate = new Date(actualTime + 1 * 864e5);\n else if(evt.keyCode === 40) newDate = new Date(actualTime + 7 * 864e5);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }, {\n name: 'month',\n format: options.monthFormat,\n split: 4,\n steps: { year: 1 },\n update: function(date, force) {\n if(!this.built || date.getFullYear() !== viewDate.year) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getMonth() !== viewDate.month) {\n angular.extend(viewDate, {month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstMonth = new Date(viewDate.year, 0, 1);\n var months = [], month;\n for (var i = 0; i < 12; i++) {\n month = new Date(viewDate.year, i, 1);\n months.push({date: month, label: formatDate(month, this.format), selected: picker.$isSelected(month), disabled: this.isDisabled(month)});\n }\n scope.title = formatDate(month, options.yearTitleFormat);\n scope.showLabels = false;\n scope.rows = split(months, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth();\n },\n isDisabled: function(date) {\n var lastDate = +new Date(date.getFullYear(), date.getMonth() + 1, 0);\n return lastDate < options.minDate || date.getTime() > options.maxDate;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualMonth = picker.$date.getMonth();\n var newDate = new Date(picker.$date);\n\n if(evt.keyCode === 37) newDate.setMonth(actualMonth - 1);\n else if(evt.keyCode === 38) newDate.setMonth(actualMonth - 4);\n else if(evt.keyCode === 39) newDate.setMonth(actualMonth + 1);\n else if(evt.keyCode === 40) newDate.setMonth(actualMonth + 4);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }, {\n name: 'year',\n format: options.yearFormat,\n split: 4,\n steps: { year: 12 },\n update: function(date, force) {\n if(!this.built || force || parseInt(date.getFullYear()/20, 10) !== parseInt(viewDate.year/20, 10)) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getFullYear() !== viewDate.year) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstYear = viewDate.year - viewDate.year % (this.split * 3);\n var years = [], year;\n for (var i = 0; i < 12; i++) {\n year = new Date(firstYear + i, 0, 1);\n years.push({date: year, label: formatDate(year, this.format), selected: picker.$isSelected(year), disabled: this.isDisabled(year)});\n }\n scope.title = years[0].label + '-' + years[years.length - 1].label;\n scope.showLabels = false;\n scope.rows = split(years, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear();\n },\n isDisabled: function(date) {\n var lastDate = +new Date(date.getFullYear() + 1, 0, 0);\n return lastDate < options.minDate || date.getTime() > options.maxDate;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualYear = picker.$date.getFullYear(),\n newDate = new Date(picker.$date);\n\n if(evt.keyCode === 37) newDate.setYear(actualYear - 1);\n else if(evt.keyCode === 38) newDate.setYear(actualYear - 4);\n else if(evt.keyCode === 39) newDate.setYear(actualYear + 1);\n else if(evt.keyCode === 40) newDate.setYear(actualYear + 4);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }];\n\n return {\n views: options.minView ? Array.prototype.slice.call(views, options.minView) : views,\n viewDate: viewDate\n };\n\n };\n\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.dropdown', ['mgcrea.ngStrap.tooltip'])\n\n .provider('$dropdown', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'dropdown',\n prefixEvent: 'dropdown',\n placement: 'bottom-left',\n templateUrl: 'dropdown/dropdown.tpl.html',\n trigger: 'click',\n container: false,\n keyboard: true,\n html: false,\n delay: 0\n };\n\n this.$get = function($window, $rootScope, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var matchesSelector = Element.prototype.matchesSelector || Element.prototype.webkitMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector;\n\n function DropdownFactory(element, config) {\n\n var $dropdown = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n var scope = $dropdown.$scope = options.scope && options.scope.$new() || $rootScope.$new();\n\n $dropdown = $tooltip(element, options);\n var parentEl = element.parent();\n\n // Protected methods\n\n $dropdown.$onKeyDown = function(evt) {\n if (!/(38|40)/.test(evt.keyCode)) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // Retrieve focused index\n var items = angular.element($dropdown.$element[0].querySelectorAll('li:not(.divider) a'));\n if(!items.length) return;\n var index;\n angular.forEach(items, function(el, i) {\n if(matchesSelector && matchesSelector.call(el, ':focus')) index = i;\n });\n\n // Navigate with keyboard\n if(evt.keyCode === 38 && index > 0) index--;\n else if(evt.keyCode === 40 && index < items.length - 1) index++;\n else if(angular.isUndefined(index)) index = 0;\n items.eq(index)[0].focus();\n\n };\n\n // Overrides\n\n var show = $dropdown.show;\n $dropdown.show = function() {\n show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n options.keyboard && $dropdown.$element && $dropdown.$element.on('keydown', $dropdown.$onKeyDown);\n bodyEl.on('click', onBodyClick);\n }, 0, false);\n parentEl.hasClass('dropdown') && parentEl.addClass('open');\n };\n\n var hide = $dropdown.hide;\n $dropdown.hide = function() {\n if(!$dropdown.$isShown) return;\n options.keyboard && $dropdown.$element && $dropdown.$element.off('keydown', $dropdown.$onKeyDown);\n bodyEl.off('click', onBodyClick);\n parentEl.hasClass('dropdown') && parentEl.removeClass('open');\n hide();\n };\n\n var destroy = $dropdown.destroy;\n $dropdown.destroy = function() {\n bodyEl.off('click', onBodyClick);\n destroy();\n };\n\n // Private functions\n\n function onBodyClick(evt) {\n if(evt.target === element[0]) return;\n return evt.target !== element[0] && $dropdown.hide();\n }\n\n return $dropdown;\n\n }\n\n return DropdownFactory;\n\n };\n\n })\n\n .directive('bsDropdown', function($window, $sce, $dropdown) {\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Support scope as an object\n attr.bsDropdown && scope.$watch(attr.bsDropdown, function(newValue, oldValue) {\n scope.content = newValue;\n }, true);\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!dropdown || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(dropdown),?/i);\n newValue === true ? dropdown.show() : dropdown.hide();\n });\n\n // Initialize dropdown\n var dropdown = $dropdown(element, options);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (dropdown) dropdown.destroy();\n options = null;\n dropdown = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.helpers.dateParser', [])\n\n.provider('$dateParser', function($localeProvider) {\n\n // define a custom ParseDate object to use instead of native Date\n // to avoid date values wrapping when setting date component values\n function ParseDate() {\n this.year = 1970;\n this.month = 0;\n this.day = 1;\n this.hours = 0;\n this.minutes = 0;\n this.seconds = 0;\n this.milliseconds = 0;\n }\n\n ParseDate.prototype.setMilliseconds = function(value) { this.milliseconds = value; };\n ParseDate.prototype.setSeconds = function(value) { this.seconds = value; };\n ParseDate.prototype.setMinutes = function(value) { this.minutes = value; };\n ParseDate.prototype.setHours = function(value) { this.hours = value; };\n ParseDate.prototype.getHours = function() { return this.hours; };\n ParseDate.prototype.setDate = function(value) { this.day = value; };\n ParseDate.prototype.setMonth = function(value) { this.month = value; };\n ParseDate.prototype.setFullYear = function(value) { this.year = value; };\n ParseDate.prototype.fromDate = function(value) {\n this.year = value.getFullYear();\n this.month = value.getMonth();\n this.day = value.getDate();\n this.hours = value.getHours();\n this.minutes = value.getMinutes();\n this.seconds = value.getSeconds();\n this.milliseconds = value.getMilliseconds();\n return this;\n };\n\n ParseDate.prototype.toDate = function() {\n return new Date(this.year, this.month, this.day, this.hours, this.minutes, this.seconds, this.milliseconds);\n };\n\n var proto = ParseDate.prototype;\n\n function noop() {\n }\n\n function isNumeric(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n }\n\n function indexOfCaseInsensitive(array, value) {\n var len = array.length, str=value.toString().toLowerCase();\n for (var i=0; i 12 when midnight changeover, but then cannot generate\n * midnight datetime, so jump to 1AM, otherwise reset.\n * @param date (Date) the date to check\n * @return (Date) the corrected date\n *\n * __ copied from jquery ui datepicker __\n */\n $dateParser.daylightSavingAdjust = function(date) {\n if (!date) {\n return null;\n }\n date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);\n return date;\n };\n\n /* Correct the date for timezone offset.\n * @param date (Date) the date to adjust\n * @param timezone (string) the timezone to adjust for\n * @param undo (boolean) to add or subtract timezone offset\n * @return (Date) the corrected date\n */\n $dateParser.timezoneOffsetAdjust = function(date, timezone, undo) {\n if (!date) {\n return null;\n }\n // Right now, only 'UTC' is supported.\n if (timezone && timezone === 'UTC') {\n date = new Date(date.getTime());\n date.setMinutes(date.getMinutes() + (undo?-1:1)*date.getTimezoneOffset());\n }\n return date;\n };\n\n // Private functions\n\n function setMapForFormat(format) {\n var keys = Object.keys(setFnMap), i;\n var map = [], sortedMap = [];\n // Map to setFn\n var clonedFormat = format;\n for(i = 0; i < keys.length; i++) {\n if(format.split(keys[i]).length > 1) {\n var index = clonedFormat.search(keys[i]);\n format = format.split(keys[i]).join('');\n if(setFnMap[keys[i]]) {\n map[index] = setFnMap[keys[i]];\n }\n }\n }\n // Sort result map\n angular.forEach(map, function(v) {\n // conditional required since angular.forEach broke around v1.2.21\n // related pr: https://github.com/angular/angular.js/pull/8525\n if(v) sortedMap.push(v);\n });\n return sortedMap;\n }\n\n function escapeReservedSymbols(text) {\n return text.replace(/\\//g, '[\\\\/]').replace('/-/g', '[-]').replace(/\\./g, '[.]').replace(/\\\\s/g, '[\\\\s]');\n }\n\n function regExpForFormat(format) {\n var keys = Object.keys(regExpMap), i;\n\n var re = format;\n // Abstract replaces to avoid collisions\n for(i = 0; i < keys.length; i++) {\n re = re.split(keys[i]).join('${' + i + '}');\n }\n // Replace abstracted values\n for(i = 0; i < keys.length; i++) {\n re = re.split('${' + i + '}').join('(' + regExpMap[keys[i]] + ')');\n }\n format = escapeReservedSymbols(format);\n\n return new RegExp('^' + re + '$', ['i']);\n }\n\n $dateParser.init();\n return $dateParser;\n\n };\n\n return DateParserFactory;\n\n };\n\n});\n","'use strict';\n\nangular.module('mgcrea.ngStrap.helpers.debounce', [])\n\n// @source jashkenas/underscore\n// @url https://github.com/jashkenas/underscore/blob/1.5.2/underscore.js#L693\n.factory('debounce', function($timeout) {\n return function(func, wait, immediate) {\n var timeout = null;\n return function() {\n var context = this,\n args = arguments,\n callNow = immediate && !timeout;\n if(timeout) {\n $timeout.cancel(timeout);\n }\n timeout = $timeout(function later() {\n timeout = null;\n if(!immediate) {\n func.apply(context, args);\n }\n }, wait, false);\n if(callNow) {\n func.apply(context, args);\n }\n return timeout;\n };\n };\n})\n\n\n// @source jashkenas/underscore\n// @url https://github.com/jashkenas/underscore/blob/1.5.2/underscore.js#L661\n.factory('throttle', function($timeout) {\n return function(func, wait, options) {\n var timeout = null;\n options || (options = {});\n return function() {\n var context = this,\n args = arguments;\n if(!timeout) {\n if(options.leading !== false) {\n func.apply(context, args);\n }\n timeout = $timeout(function later() {\n timeout = null;\n if(options.trailing !== false) {\n func.apply(context, args);\n }\n }, wait, false);\n }\n };\n };\n});\n\n","'use strict';\n\nangular.module('mgcrea.ngStrap.helpers.dimensions', [])\n\n .factory('dimensions', function($document, $window) {\n\n var jqLite = angular.element;\n var fn = {};\n\n /**\n * Test the element nodeName\n * @param element\n * @param name\n */\n var nodeName = fn.nodeName = function(element, name) {\n return element.nodeName && element.nodeName.toLowerCase() === name.toLowerCase();\n };\n\n /**\n * Returns the element computed style\n * @param element\n * @param prop\n * @param extra\n */\n fn.css = function(element, prop, extra) {\n var value;\n if (element.currentStyle) { //IE\n value = element.currentStyle[prop];\n } else if (window.getComputedStyle) {\n value = window.getComputedStyle(element)[prop];\n } else {\n value = element.style[prop];\n }\n return extra === true ? parseFloat(value) || 0 : value;\n };\n\n /**\n * Provides read-only equivalent of jQuery's offset function:\n * @required-by bootstrap-tooltip, bootstrap-affix\n * @url http://api.jquery.com/offset/\n * @param element\n */\n fn.offset = function(element) {\n var boxRect = element.getBoundingClientRect();\n var docElement = element.ownerDocument;\n return {\n width: boxRect.width || element.offsetWidth,\n height: boxRect.height || element.offsetHeight,\n top: boxRect.top + (window.pageYOffset || docElement.documentElement.scrollTop) - (docElement.documentElement.clientTop || 0),\n left: boxRect.left + (window.pageXOffset || docElement.documentElement.scrollLeft) - (docElement.documentElement.clientLeft || 0)\n };\n };\n \n /**\n * Provides set equivalent of jQuery's offset function:\n * @required-by bootstrap-tooltip\n * @url http://api.jquery.com/offset/\n * @param element\n * @param options\n * @param i\n */\n fn.setOffset = function (element, options, i) {\n var curPosition,\n curLeft,\n curCSSTop,\n curTop,\n curOffset,\n curCSSLeft,\n calculatePosition,\n position = fn.css(element, 'position'),\n curElem = angular.element(element),\n props = {};\n \n // Set position first, in-case top/left are set even on static elem\n if (position === 'static') {\n element.style.position = 'relative';\n }\n \n curOffset = fn.offset(element);\n curCSSTop = fn.css(element, 'top');\n curCSSLeft = fn.css(element, 'left');\n calculatePosition = (position === 'absolute' || position === 'fixed') && \n (curCSSTop + curCSSLeft).indexOf('auto') > -1;\n \n // Need to be able to calculate position if either\n // top or left is auto and position is either absolute or fixed\n if (calculatePosition) {\n curPosition = fn.position(element);\n curTop = curPosition.top;\n curLeft = curPosition.left;\n } else {\n curTop = parseFloat(curCSSTop) || 0;\n curLeft = parseFloat(curCSSLeft) || 0;\n }\n \n if (angular.isFunction(options)) {\n options = options.call(element, i, curOffset);\n }\n \n if (options.top !== null ) {\n props.top = (options.top - curOffset.top) + curTop;\n }\n if ( options.left !== null ) {\n props.left = (options.left - curOffset.left) + curLeft;\n }\n\n if ('using' in options) {\n options.using.call(curElem, props);\n } else {\n curElem.css({\n top: props.top + 'px',\n left: props.left + 'px'\n });\n }\n };\n\n /**\n * Provides read-only equivalent of jQuery's position function\n * @required-by bootstrap-tooltip, bootstrap-affix\n * @url http://api.jquery.com/offset/\n * @param element\n */\n fn.position = function(element) {\n\n var offsetParentRect = {top: 0, left: 0},\n offsetParentElement,\n offset;\n\n // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent\n if (fn.css(element, 'position') === 'fixed') {\n\n // We assume that getBoundingClientRect is available when computed position is fixed\n offset = element.getBoundingClientRect();\n\n } else {\n\n // Get *real* offsetParentElement\n offsetParentElement = offsetParent(element);\n\n // Get correct offsets\n offset = fn.offset(element);\n if (!nodeName(offsetParentElement, 'html')) {\n offsetParentRect = fn.offset(offsetParentElement);\n }\n\n // Add offsetParent borders\n offsetParentRect.top += fn.css(offsetParentElement, 'borderTopWidth', true);\n offsetParentRect.left += fn.css(offsetParentElement, 'borderLeftWidth', true);\n }\n\n // Subtract parent offsets and element margins\n return {\n width: element.offsetWidth,\n height: element.offsetHeight,\n top: offset.top - offsetParentRect.top - fn.css(element, 'marginTop', true),\n left: offset.left - offsetParentRect.left - fn.css(element, 'marginLeft', true)\n };\n\n };\n\n /**\n * Returns the closest, non-statically positioned offsetParent of a given element\n * @required-by fn.position\n * @param element\n */\n var offsetParent = function offsetParentElement(element) {\n var docElement = element.ownerDocument;\n var offsetParent = element.offsetParent || docElement;\n if(nodeName(offsetParent, '#document')) return docElement.documentElement;\n while(offsetParent && !nodeName(offsetParent, 'html') && fn.css(offsetParent, 'position') === 'static') {\n offsetParent = offsetParent.offsetParent;\n }\n return offsetParent || docElement.documentElement;\n };\n\n /**\n * Provides equivalent of jQuery's height function\n * @required-by bootstrap-affix\n * @url http://api.jquery.com/height/\n * @param element\n * @param outer\n */\n fn.height = function(element, outer) {\n var value = element.offsetHeight;\n if(outer) {\n value += fn.css(element, 'marginTop', true) + fn.css(element, 'marginBottom', true);\n } else {\n value -= fn.css(element, 'paddingTop', true) + fn.css(element, 'paddingBottom', true) + fn.css(element, 'borderTopWidth', true) + fn.css(element, 'borderBottomWidth', true);\n }\n return value;\n };\n\n /**\n * Provides equivalent of jQuery's width function\n * @required-by bootstrap-affix\n * @url http://api.jquery.com/width/\n * @param element\n * @param outer\n */\n fn.width = function(element, outer) {\n var value = element.offsetWidth;\n if(outer) {\n value += fn.css(element, 'marginLeft', true) + fn.css(element, 'marginRight', true);\n } else {\n value -= fn.css(element, 'paddingLeft', true) + fn.css(element, 'paddingRight', true) + fn.css(element, 'borderLeftWidth', true) + fn.css(element, 'borderRightWidth', true);\n }\n return value;\n };\n\n return fn;\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.helpers.parseOptions', [])\n\n .provider('$parseOptions', function() {\n\n var defaults = this.defaults = {\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+(.*?))?$/\n };\n\n this.$get = function($parse, $q) {\n\n function ParseOptionsFactory(attr, config) {\n\n var $parseOptions = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n $parseOptions.$values = [];\n\n // Private vars\n var match, displayFn, valueName, keyName, groupByFn, valueFn, valuesFn;\n\n $parseOptions.init = function() {\n $parseOptions.$match = match = attr.match(options.regexp);\n displayFn = $parse(match[2] || match[1]),\n valueName = match[4] || match[6],\n keyName = match[5],\n groupByFn = $parse(match[3] || ''),\n valueFn = $parse(match[2] ? match[1] : valueName),\n valuesFn = $parse(match[7]);\n };\n\n $parseOptions.valuesFn = function(scope, controller) {\n var valuesPromise;\n try {\n // Might throw 'notarray' error since cea8e75\n valuesPromise = valuesFn(scope, controller);\n } catch(err) {\n valuesPromise = [];\n }\n return $q.when(valuesPromise)\n .then(function(values) {\n if(!angular.isArray(values)) {\n values = [];\n }\n $parseOptions.$values = values.length ? parseValues(values, scope) : [];\n return $parseOptions.$values;\n });\n };\n\n $parseOptions.displayValue = function(modelValue) {\n var scope = {};\n scope[valueName] = modelValue;\n return displayFn(scope);\n };\n\n // Private functions\n\n function parseValues(values, scope) {\n return values.map(function(match, index) {\n var locals = {}, label, value;\n locals[valueName] = match;\n label = displayFn(scope, locals);\n value = valueFn(scope, locals);\n return {label: label, value: value, index: index};\n });\n }\n\n $parseOptions.init();\n return $parseOptions;\n\n }\n\n return ParseOptionsFactory;\n\n };\n\n });\n","'use strict';\n\n(angular.version.minor < 3 && angular.version.dot < 14) && angular.module('ng')\n\n.factory('$$rAF', function($window, $timeout) {\n\n var requestAnimationFrame = $window.requestAnimationFrame ||\n $window.webkitRequestAnimationFrame ||\n $window.mozRequestAnimationFrame;\n\n var cancelAnimationFrame = $window.cancelAnimationFrame ||\n $window.webkitCancelAnimationFrame ||\n $window.mozCancelAnimationFrame ||\n $window.webkitCancelRequestAnimationFrame;\n\n var rafSupported = !!requestAnimationFrame;\n var raf = rafSupported ?\n function(fn) {\n var id = requestAnimationFrame(fn);\n return function() {\n cancelAnimationFrame(id);\n };\n } :\n function(fn) {\n var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666\n return function() {\n $timeout.cancel(timer);\n };\n };\n\n raf.supported = rafSupported;\n\n return raf;\n\n});\n\n// .factory('$$animateReflow', function($$rAF, $document) {\n\n// var bodyEl = $document[0].body;\n\n// return function(fn) {\n// //the returned function acts as the cancellation function\n// return $$rAF(function() {\n// //the line below will force the browser to perform a repaint\n// //so that all the animated elements within the animation frame\n// //will be properly updated and drawn on screen. This is\n// //required to perform multi-class CSS based animations with\n// //Firefox. DO NOT REMOVE THIS LINE.\n// var a = bodyEl.offsetWidth + 1;\n// fn();\n// });\n// };\n\n// });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.modal', ['mgcrea.ngStrap.core', 'mgcrea.ngStrap.helpers.dimensions'])\n\n .provider('$modal', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n backdropAnimation: 'am-fade',\n prefixClass: 'modal',\n prefixEvent: 'modal',\n placement: 'top',\n templateUrl: 'modal/modal.tpl.html',\n template: '',\n contentTemplate: false,\n container: false,\n element: null,\n backdrop: true,\n keyboard: true,\n html: false,\n show: true\n };\n\n this.$get = function($window, $rootScope, $bsCompiler, $q, $templateCache, $http, $animate, $timeout, $sce, dimensions) {\n\n var forEach = angular.forEach;\n var trim = String.prototype.trim;\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n var bodyElement = angular.element($window.document.body);\n\n function ModalFactory(config) {\n\n var $modal = {};\n\n // Common vars\n var options = $modal.$options = angular.extend({}, defaults, config);\n var promise = $modal.$promise = $bsCompiler.compile(options);\n var scope = $modal.$scope = options.scope && options.scope.$new() || $rootScope.$new();\n\n if(!options.element && !options.container) {\n options.container = 'body';\n }\n\n // Store $id to identify the triggering element in events\n // give priority to options.id, otherwise, try to use\n // element id if defined\n $modal.$id = options.id || options.element && options.element.attr('id') || '';\n\n // Support scope as string options\n forEach(['title', 'content'], function(key) {\n if(options[key]) scope[key] = $sce.trustAsHtml(options[key]);\n });\n\n // Provide scope helpers\n scope.$hide = function() {\n scope.$$postDigest(function() {\n $modal.hide();\n });\n };\n scope.$show = function() {\n scope.$$postDigest(function() {\n $modal.show();\n });\n };\n scope.$toggle = function() {\n scope.$$postDigest(function() {\n $modal.toggle();\n });\n };\n // Publish isShown as a protected var on scope\n $modal.$isShown = scope.$isShown = false;\n\n // Fetch, compile then initialize modal\n var compileData, modalElement, modalScope;\n var backdropElement = angular.element('
');\n backdropElement.css({position:'fixed', top:'0px', left:'0px', bottom:'0px', right:'0px', 'z-index': 1038});\n promise.then(function(data) {\n compileData = data;\n $modal.init();\n });\n\n $modal.init = function() {\n\n // Options: show\n if(options.show) {\n scope.$$postDigest(function() {\n $modal.show();\n });\n }\n\n };\n\n $modal.destroy = function() {\n\n // Remove element\n destroyModalElement();\n\n // remove backdrop element\n if(backdropElement) {\n backdropElement.remove();\n backdropElement = null;\n }\n\n // Destroy scope\n scope.$destroy();\n };\n\n $modal.show = function() {\n if($modal.$isShown) return;\n\n var parent, after;\n if(angular.isElement(options.container)) {\n parent = options.container;\n after = options.container[0].lastChild ? angular.element(options.container[0].lastChild) : null;\n } else {\n if (options.container) {\n parent = findElement(options.container);\n after = parent[0] && parent[0].lastChild ? angular.element(parent[0].lastChild) : null;\n } else {\n parent = null;\n after = options.element;\n }\n }\n\n // destroy any existing modal elements\n if(modalElement) destroyModalElement();\n\n // create a new scope, so we can destroy it and all child scopes\n // when destroying the modal element\n modalScope = $modal.$scope.$new();\n // Fetch a cloned element linked from template (noop callback is required)\n modalElement = $modal.$element = compileData.link(modalScope, function(clonedElement, scope) {});\n\n if(scope.$emit(options.prefixEvent + '.show.before', $modal).defaultPrevented) {\n return;\n }\n\n // Set the initial positioning.\n modalElement.css({display: 'block'}).addClass(options.placement);\n\n // Options: animation\n if(options.animation) {\n if(options.backdrop) {\n backdropElement.addClass(options.backdropAnimation);\n }\n modalElement.addClass(options.animation);\n }\n\n if(options.backdrop) {\n $animate.enter(backdropElement, bodyElement, null);\n }\n\n // Support v1.2+ $animate\n // https://github.com/angular/angular.js/issues/11713\n if(angular.version.minor <= 2) {\n $animate.enter(modalElement, parent, after, enterAnimateCallback);\n } else {\n $animate.enter(modalElement, parent, after).then(enterAnimateCallback);\n }\n\n $modal.$isShown = scope.$isShown = true;\n safeDigest(scope);\n // Focus once the enter-animation has started\n // Weird PhantomJS bug hack\n var el = modalElement[0];\n requestAnimationFrame(function() {\n el.focus();\n });\n\n bodyElement.addClass(options.prefixClass + '-open');\n if(options.animation) {\n bodyElement.addClass(options.prefixClass + '-with-' + options.animation);\n }\n\n // Bind events\n bindBackdropEvents();\n bindKeyboardEvents();\n };\n\n function enterAnimateCallback() {\n scope.$emit(options.prefixEvent + '.show', $modal);\n }\n\n $modal.hide = function() {\n if(!$modal.$isShown) return;\n\n if(scope.$emit(options.prefixEvent + '.hide.before', $modal).defaultPrevented) {\n return;\n }\n\n // Support v1.2+ $animate\n // https://github.com/angular/angular.js/issues/11713\n if(angular.version.minor <= 2) {\n $animate.leave(modalElement, leaveAnimateCallback);\n } else {\n $animate.leave(modalElement).then(leaveAnimateCallback);\n }\n\n if(options.backdrop) {\n $animate.leave(backdropElement);\n }\n $modal.$isShown = scope.$isShown = false;\n safeDigest(scope);\n\n // Unbind events\n unbindBackdropEvents();\n unbindKeyboardEvents();\n };\n\n function leaveAnimateCallback() {\n scope.$emit(options.prefixEvent + '.hide', $modal);\n bodyElement.removeClass(options.prefixClass + '-open');\n if(options.animation) {\n bodyElement.removeClass(options.prefixClass + '-with-' + options.animation);\n }\n }\n\n $modal.toggle = function() {\n\n $modal.$isShown ? $modal.hide() : $modal.show();\n\n };\n\n $modal.focus = function() {\n modalElement[0].focus();\n };\n\n // Protected methods\n\n $modal.$onKeyUp = function(evt) {\n\n if (evt.which === 27 && $modal.$isShown) {\n $modal.hide();\n evt.stopPropagation();\n }\n\n };\n\n function bindBackdropEvents() {\n if(options.backdrop) {\n modalElement.on('click', hideOnBackdropClick);\n backdropElement.on('click', hideOnBackdropClick);\n backdropElement.on('wheel', preventEventDefault);\n }\n }\n\n function unbindBackdropEvents() {\n if(options.backdrop) {\n modalElement.off('click', hideOnBackdropClick);\n backdropElement.off('click', hideOnBackdropClick);\n backdropElement.off('wheel', preventEventDefault);\n }\n }\n\n function bindKeyboardEvents() {\n if(options.keyboard) {\n modalElement.on('keyup', $modal.$onKeyUp);\n }\n }\n\n function unbindKeyboardEvents() {\n if(options.keyboard) {\n modalElement.off('keyup', $modal.$onKeyUp);\n }\n }\n\n // Private methods\n\n function hideOnBackdropClick(evt) {\n if(evt.target !== evt.currentTarget) return;\n options.backdrop === 'static' ? $modal.focus() : $modal.hide();\n }\n\n function preventEventDefault(evt) {\n evt.preventDefault();\n }\n\n function destroyModalElement() {\n if($modal.$isShown && modalElement !== null) {\n // un-bind events\n unbindBackdropEvents();\n unbindKeyboardEvents();\n }\n\n if(modalScope) {\n modalScope.$destroy();\n modalScope = null;\n }\n\n if(modalElement) {\n modalElement.remove();\n modalElement = $modal.$element = null;\n }\n }\n\n return $modal;\n\n }\n\n // Helper functions\n\n function safeDigest(scope) {\n scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();\n }\n\n function findElement(query, element) {\n return angular.element((element || document).querySelectorAll(query));\n }\n\n return ModalFactory;\n\n };\n\n })\n\n .directive('bsModal', function($window, $sce, $modal) {\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope, element: element, show: false};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'controller', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation', 'id', 'prefixEvent', 'prefixClass'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['backdrop', 'keyboard', 'html', 'container'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Support scope as data-attrs\n angular.forEach(['title', 'content'], function(key) {\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\n scope[key] = $sce.trustAsHtml(newValue);\n });\n });\n\n // Support scope as an object\n attr.bsModal && scope.$watch(attr.bsModal, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.content = newValue;\n }\n }, true);\n\n // Initialize modal\n var modal = $modal(options);\n\n // Trigger\n element.on(attr.trigger || 'click', modal.toggle);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (modal) modal.destroy();\n options = null;\n modal = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.navbar', [])\n\n .provider('$navbar', function() {\n\n var defaults = this.defaults = {\n activeClass: 'active',\n routeAttr: 'data-match-route',\n strict: false\n };\n\n this.$get = function() {\n return {defaults: defaults};\n };\n\n })\n\n .directive('bsNavbar', function($window, $location, $navbar) {\n\n var defaults = $navbar.defaults;\n\n return {\n restrict: 'A',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = angular.copy(defaults);\n angular.forEach(Object.keys(defaults), function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Watch for the $location\n scope.$watch(function() {\n\n return $location.path();\n\n }, function(newValue, oldValue) {\n\n var liElements = element[0].querySelectorAll('li[' + options.routeAttr + ']');\n\n angular.forEach(liElements, function(li) {\n\n var liElement = angular.element(li);\n var pattern = liElement.attr(options.routeAttr).replace('/', '\\\\/');\n if(options.strict) {\n pattern = '^' + pattern + '$';\n }\n var regexp = new RegExp(pattern, 'i');\n\n if(regexp.test(newValue)) {\n liElement.addClass(options.activeClass);\n } else {\n liElement.removeClass(options.activeClass);\n }\n\n });\n\n });\n\n }\n\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.scrollspy', ['mgcrea.ngStrap.helpers.debounce', 'mgcrea.ngStrap.helpers.dimensions'])\n\n .provider('$scrollspy', function() {\n\n // Pool of registered spies\n var spies = this.$$spies = {};\n\n var defaults = this.defaults = {\n debounce: 150,\n throttle: 100,\n offset: 100\n };\n\n this.$get = function($window, $document, $rootScope, dimensions, debounce, throttle) {\n\n var windowEl = angular.element($window);\n var docEl = angular.element($document.prop('documentElement'));\n var bodyEl = angular.element($window.document.body);\n\n // Helper functions\n\n function nodeName(element, name) {\n return element[0].nodeName && element[0].nodeName.toLowerCase() === name.toLowerCase();\n }\n\n function ScrollSpyFactory(config) {\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n if(!options.element) options.element = bodyEl;\n var isWindowSpy = nodeName(options.element, 'body');\n var scrollEl = isWindowSpy ? windowEl : options.element;\n var scrollId = isWindowSpy ? 'window' : options.id;\n\n // Use existing spy\n if(spies[scrollId]) {\n spies[scrollId].$$count++;\n return spies[scrollId];\n }\n\n var $scrollspy = {};\n\n // Private vars\n var unbindViewContentLoaded, unbindIncludeContentLoaded;\n var trackedElements = $scrollspy.$trackedElements = [];\n var sortedElements = [];\n var activeTarget;\n var debouncedCheckPosition;\n var throttledCheckPosition;\n var debouncedCheckOffsets;\n var viewportHeight;\n var scrollTop;\n\n $scrollspy.init = function() {\n\n // Setup internal ref counter\n this.$$count = 1;\n\n // Bind events\n debouncedCheckPosition = debounce(this.checkPosition, options.debounce);\n throttledCheckPosition = throttle(this.checkPosition, options.throttle);\n scrollEl.on('click', this.checkPositionWithEventLoop);\n windowEl.on('resize', debouncedCheckPosition);\n scrollEl.on('scroll', throttledCheckPosition);\n\n debouncedCheckOffsets = debounce(this.checkOffsets, options.debounce);\n unbindViewContentLoaded = $rootScope.$on('$viewContentLoaded', debouncedCheckOffsets);\n unbindIncludeContentLoaded = $rootScope.$on('$includeContentLoaded', debouncedCheckOffsets);\n debouncedCheckOffsets();\n\n // Register spy for reuse\n if(scrollId) {\n spies[scrollId] = $scrollspy;\n }\n\n };\n\n $scrollspy.destroy = function() {\n\n // Check internal ref counter\n this.$$count--;\n if(this.$$count > 0) {\n return;\n }\n\n // Unbind events\n scrollEl.off('click', this.checkPositionWithEventLoop);\n windowEl.off('resize', debouncedCheckPosition);\n scrollEl.off('scroll', throttledCheckPosition);\n unbindViewContentLoaded();\n unbindIncludeContentLoaded();\n if (scrollId) {\n delete spies[scrollId];\n }\n };\n\n $scrollspy.checkPosition = function() {\n\n // Not ready yet\n if(!sortedElements.length) return;\n\n // Calculate the scroll position\n scrollTop = (isWindowSpy ? $window.pageYOffset : scrollEl.prop('scrollTop')) || 0;\n\n // Calculate the viewport height for use by the components\n viewportHeight = Math.max($window.innerHeight, docEl.prop('clientHeight'));\n\n // Activate first element if scroll is smaller\n if(scrollTop < sortedElements[0].offsetTop && activeTarget !== sortedElements[0].target) {\n return $scrollspy.$activateElement(sortedElements[0]);\n }\n\n // Activate proper element\n for (var i = sortedElements.length; i--;) {\n if(angular.isUndefined(sortedElements[i].offsetTop) || sortedElements[i].offsetTop === null) continue;\n if(activeTarget === sortedElements[i].target) continue;\n if(scrollTop < sortedElements[i].offsetTop) continue;\n if(sortedElements[i + 1] && scrollTop > sortedElements[i + 1].offsetTop) continue;\n return $scrollspy.$activateElement(sortedElements[i]);\n }\n\n };\n\n $scrollspy.checkPositionWithEventLoop = function() {\n // IE 9 throws an error if we use 'this' instead of '$scrollspy'\n // in this setTimeout call\n setTimeout($scrollspy.checkPosition, 1);\n };\n\n // Protected methods\n\n $scrollspy.$activateElement = function(element) {\n if(activeTarget) {\n var activeElement = $scrollspy.$getTrackedElement(activeTarget);\n if(activeElement) {\n activeElement.source.removeClass('active');\n if(nodeName(activeElement.source, 'li') && nodeName(activeElement.source.parent().parent(), 'li')) {\n activeElement.source.parent().parent().removeClass('active');\n }\n }\n }\n activeTarget = element.target;\n element.source.addClass('active');\n if(nodeName(element.source, 'li') && nodeName(element.source.parent().parent(), 'li')) {\n element.source.parent().parent().addClass('active');\n }\n };\n\n $scrollspy.$getTrackedElement = function(target) {\n return trackedElements.filter(function(obj) {\n return obj.target === target;\n })[0];\n };\n\n // Track offsets behavior\n\n $scrollspy.checkOffsets = function() {\n\n angular.forEach(trackedElements, function(trackedElement) {\n var targetElement = document.querySelector(trackedElement.target);\n trackedElement.offsetTop = targetElement ? dimensions.offset(targetElement).top : null;\n if(options.offset && trackedElement.offsetTop !== null) trackedElement.offsetTop -= options.offset * 1;\n });\n\n sortedElements = trackedElements\n .filter(function(el) {\n return el.offsetTop !== null;\n })\n .sort(function(a, b) {\n return a.offsetTop - b.offsetTop;\n });\n\n debouncedCheckPosition();\n\n };\n\n $scrollspy.trackElement = function(target, source) {\n trackedElements.push({target: target, source: source});\n };\n\n $scrollspy.untrackElement = function(target, source) {\n var toDelete;\n for (var i = trackedElements.length; i--;) {\n if(trackedElements[i].target === target && trackedElements[i].source === source) {\n toDelete = i;\n break;\n }\n }\n trackedElements = trackedElements.splice(toDelete, 1);\n };\n\n $scrollspy.activate = function(i) {\n trackedElements[i].addClass('active');\n };\n\n // Initialize plugin\n\n $scrollspy.init();\n return $scrollspy;\n\n }\n\n return ScrollSpyFactory;\n\n };\n\n })\n\n .directive('bsScrollspy', function($rootScope, debounce, dimensions, $scrollspy) {\n\n return {\n restrict: 'EAC',\n link: function postLink(scope, element, attr) {\n\n var options = {scope: scope};\n angular.forEach(['offset', 'target'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n var scrollspy = $scrollspy(options);\n scrollspy.trackElement(options.target, element);\n\n scope.$on('$destroy', function() {\n if (scrollspy) {\n scrollspy.untrackElement(options.target, element);\n scrollspy.destroy();\n }\n options = null;\n scrollspy = null;\n });\n\n }\n };\n\n })\n\n\n .directive('bsScrollspyList', function($rootScope, debounce, dimensions, $scrollspy) {\n\n return {\n restrict: 'A',\n compile: function postLink(element, attr) {\n var children = element[0].querySelectorAll('li > a[href]');\n angular.forEach(children, function(child) {\n var childEl = angular.element(child);\n childEl.parent().attr('bs-scrollspy', '').attr('data-target', childEl.attr('href'));\n });\n }\n\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.select', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions'])\n\n .provider('$select', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'select',\n prefixEvent: '$select',\n placement: 'bottom-left',\n templateUrl: 'select/select.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n multiple: false,\n allNoneButtons: false,\n sort: true,\n caretHtml: ' ',\n placeholder: 'Choose among the following...',\n allText: 'All',\n noneText: 'None',\n maxLength: 3,\n maxLengthHtml: 'selected',\n iconCheckmark: 'glyphicon glyphicon-ok'\n };\n\n this.$get = function($window, $document, $rootScope, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n\n function SelectFactory(element, controller, config) {\n\n var $select = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $select = $tooltip(element, options);\n var scope = $select.$scope;\n\n scope.$matches = [];\n if (options.multiple) {\n scope.$activeIndex = [];\n }\n else {\n scope.$activeIndex = -1;\n }\n scope.$isMultiple = options.multiple;\n scope.$showAllNoneButtons = options.allNoneButtons && options.multiple;\n scope.$iconCheckmark = options.iconCheckmark;\n scope.$allText = options.allText;\n scope.$noneText = options.noneText;\n\n scope.$activate = function(index) {\n scope.$$postDigest(function() {\n $select.activate(index);\n });\n };\n\n scope.$select = function(index, evt) {\n scope.$$postDigest(function() {\n $select.select(index);\n });\n };\n\n scope.$isVisible = function() {\n return $select.$isVisible();\n };\n\n scope.$isActive = function(index) {\n return $select.$isActive(index);\n };\n\n scope.$selectAll = function () {\n for (var i = 0; i < scope.$matches.length; i++) {\n if (!scope.$isActive(i)) {\n scope.$select(i);\n }\n }\n };\n\n scope.$selectNone = function () {\n for (var i = 0; i < scope.$matches.length; i++) {\n if (scope.$isActive(i)) {\n scope.$select(i);\n }\n }\n };\n\n // Public methods\n\n $select.update = function(matches) {\n scope.$matches = matches;\n $select.$updateActiveIndex();\n };\n\n $select.activate = function(index) {\n if(options.multiple) {\n $select.$isActive(index) ? scope.$activeIndex.splice(scope.$activeIndex.indexOf(index), 1) : scope.$activeIndex.push(index);\n if(options.sort) scope.$activeIndex.sort(function(a, b) { return a - b; }); // use numeric sort instead of default sort\n } else {\n scope.$activeIndex = index;\n }\n return scope.$activeIndex;\n };\n\n $select.select = function(index) {\n var value = scope.$matches[index].value;\n scope.$apply(function() {\n $select.activate(index);\n if(options.multiple) {\n controller.$setViewValue(scope.$activeIndex.map(function(index) {\n return scope.$matches[index].value;\n }));\n } else {\n controller.$setViewValue(value);\n // Hide if single select\n $select.hide();\n }\n });\n // Emit event\n scope.$emit(options.prefixEvent + '.select', value, index, $select);\n };\n\n // Protected methods\n\n $select.$updateActiveIndex = function() {\n if(controller.$modelValue && scope.$matches.length) {\n if(options.multiple && angular.isArray(controller.$modelValue)) {\n scope.$activeIndex = controller.$modelValue.map(function(value) {\n return $select.$getIndex(value);\n });\n } else {\n scope.$activeIndex = $select.$getIndex(controller.$modelValue);\n }\n } else if(scope.$activeIndex >= scope.$matches.length) {\n scope.$activeIndex = options.multiple ? [] : 0;\n }\n };\n\n $select.$isVisible = function() {\n if(!options.minLength || !controller) {\n return scope.$matches.length;\n }\n // minLength support\n return scope.$matches.length && controller.$viewValue.length >= options.minLength;\n };\n\n $select.$isActive = function(index) {\n if(options.multiple) {\n return scope.$activeIndex.indexOf(index) !== -1;\n } else {\n return scope.$activeIndex === index;\n }\n };\n\n $select.$getIndex = function(value) {\n var l = scope.$matches.length, i = l;\n if(!l) return;\n for(i = l; i--;) {\n if(scope.$matches[i].value === value) break;\n }\n if(i < 0) return;\n return i;\n };\n\n $select.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n targetEl.triggerHandler('click');\n }\n };\n\n $select.$onKeyDown = function(evt) {\n if (!/(9|13|38|40)/.test(evt.keyCode)) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // release focus on tab\n if (options.multiple && evt.keyCode === 9) {\n return $select.hide();\n }\n\n // Select with enter\n if(!options.multiple && (evt.keyCode === 13 || evt.keyCode === 9)) {\n return $select.select(scope.$activeIndex);\n }\n\n if (!options.multiple) {\n // Navigate with keyboard\n if(evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--;\n else if(evt.keyCode === 38 && scope.$activeIndex < 0) scope.$activeIndex = scope.$matches.length - 1;\n else if(evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++;\n else if(angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0;\n scope.$digest();\n }\n };\n\n // Overrides\n\n var _show = $select.show;\n $select.show = function() {\n _show();\n if(options.multiple) {\n $select.$element.addClass('select-multiple');\n }\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n $select.$element.on(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $select.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $select.hide;\n $select.hide = function() {\n if(!options.multiple && !controller.$modelValue) {\n scope.$activeIndex = -1;\n }\n $select.$element.off(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $select.$onKeyDown);\n }\n _hide(true);\n };\n\n return $select;\n\n }\n\n SelectFactory.defaults = defaults;\n return SelectFactory;\n\n };\n\n })\n\n .directive('bsSelect', function($window, $parse, $q, $select, $parseOptions) {\n\n var defaults = $select.defaults;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope, placeholder: defaults.placeholder};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'placeholder', 'allNoneButtons', 'maxLength', 'maxLengthHtml', 'allText', 'noneText', 'iconCheckmark', 'autoClose', 'id', 'sort', 'caretHtml', 'prefixClass', 'prefixEvent'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'allNoneButtons', 'sort'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Only parse data-multiple. Angular sets existence attributes to true (multiple/required/etc), they apply this\n // to data-multiple as well for some reason, so we'll parse this ourselves and disregard multiple\n var dataMultiple = element.attr('data-multiple');\n if(angular.isDefined(dataMultiple)) {\n if(falseValueRegExp.test(dataMultiple))\n options.multiple = false;\n else\n options.multiple = dataMultiple;\n }\n\n // Add support for select markup\n if(element[0].nodeName.toLowerCase() === 'select') {\n var inputEl = element;\n inputEl.css('display', 'none');\n element = angular.element('');\n inputEl.after(element);\n }\n\n // Build proper bsOptions\n var parsedOptions = $parseOptions(attr.bsOptions);\n\n // Initialize select\n var select = $select(element, controller, options);\n\n // Watch bsOptions values before filtering for changes\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').trim();\n scope.$watchCollection(watchedOptions, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue);\n parsedOptions.valuesFn(scope, controller)\n .then(function(values) {\n select.update(values);\n controller.$render();\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue);\n select.$updateActiveIndex();\n controller.$render();\n }, true);\n\n // Model rendering in view\n controller.$render = function () {\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n var selected, index;\n if(options.multiple && angular.isArray(controller.$modelValue)) {\n selected = controller.$modelValue.map(function(value) {\n index = select.$getIndex(value);\n return angular.isDefined(index) ? select.$scope.$matches[index].label : false;\n }).filter(angular.isDefined);\n if(selected.length > (options.maxLength || defaults.maxLength)) {\n selected = selected.length + ' ' + (options.maxLengthHtml || defaults.maxLengthHtml);\n } else {\n selected = selected.join(', ');\n }\n } else {\n index = select.$getIndex(controller.$modelValue);\n selected = angular.isDefined(index) ? select.$scope.$matches[index].label : false;\n }\n element.html((selected ? selected : options.placeholder) + (options.caretHtml ? options.caretHtml : defaults.caretHtml));\n };\n\n if(options.multiple){\n controller.$isEmpty = function(value){\n return !value || value.length === 0;\n };\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (select) select.destroy();\n options = null;\n select = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.popover', ['mgcrea.ngStrap.tooltip'])\n\n .provider('$popover', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n customClass: '',\n // uncommenting the next two lines will break backwards compatability\n // prefixClass: 'popover',\n // prefixEvent: 'popover',\n container: false,\n target: false,\n placement: 'right',\n templateUrl: 'popover/popover.tpl.html',\n contentTemplate: false,\n trigger: 'click',\n keyboard: true,\n html: false,\n title: '',\n content: '',\n delay: 0,\n autoClose: false\n };\n\n this.$get = function($tooltip) {\n\n function PopoverFactory(element, config) {\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n var $popover = $tooltip(element, options);\n\n // Support scope as string options [/*title, */content]\n if(options.content) {\n $popover.$scope.content = options.content;\n }\n\n return $popover;\n\n }\n\n return PopoverFactory;\n\n };\n\n })\n\n .directive('bsPopover', function($window, $sce, $popover) {\n\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'customClass', 'autoClose', 'id', 'prefixClass', 'prefixEvent'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'autoClose'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // should not parse target attribute (anchor tag), only data-target #1454\n var dataTarget = element.attr('data-target');\n if(angular.isDefined(dataTarget)) {\n if(falseValueRegExp.test(dataTarget))\n options.target = false;\n else\n options.target = dataTarget;\n }\n\n // Support scope as data-attrs\n angular.forEach(['title', 'content'], function(key) {\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\n scope[key] = $sce.trustAsHtml(newValue);\n angular.isDefined(oldValue) && requestAnimationFrame(function() {\n popover && popover.$applyPlacement();\n });\n });\n });\n\n // Support scope as an object\n attr.bsPopover && scope.$watch(attr.bsPopover, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.content = newValue;\n }\n angular.isDefined(oldValue) && requestAnimationFrame(function() {\n popover && popover.$applyPlacement();\n });\n }, true);\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!popover || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(popover),?/i);\n newValue === true ? popover.show() : popover.hide();\n });\n\n // Viewport support\n attr.viewport && scope.$watch(attr.viewport, function (newValue) {\n if(!popover || !angular.isDefined(newValue)) return;\n popover.setViewport(newValue);\n });\n\n // Initialize popover\n var popover = $popover(element, options);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (popover) popover.destroy();\n options = null;\n popover = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.tab', [])\n\n .provider('$tab', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n template: 'tab/tab.tpl.html',\n navClass: 'nav-tabs',\n activeClass: 'active'\n };\n\n var controller = this.controller = function($scope, $element, $attrs) {\n var self = this;\n\n // Attributes options\n self.$options = angular.copy(defaults);\n angular.forEach(['animation', 'navClass', 'activeClass'], function(key) {\n if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];\n });\n\n // Publish options on scope\n $scope.$navClass = self.$options.navClass;\n $scope.$activeClass = self.$options.activeClass;\n\n self.$panes = $scope.$panes = [];\n\n // Please use $activePaneChangeListeners if you use `bsActivePane`\n // Because we removed `ngModel` as default, we rename viewChangeListeners to\n // activePaneChangeListeners to make more sense.\n self.$activePaneChangeListeners = self.$viewChangeListeners = [];\n\n self.$push = function(pane) {\n if(angular.isUndefined(self.$panes.$active)) {\n $scope.$setActive(pane.name || 0);\n }\n self.$panes.push(pane);\n };\n\n self.$remove = function(pane) {\n var index = self.$panes.indexOf(pane);\n var active = self.$panes.$active;\n var activeIndex;\n if(angular.isString(active)) {\n activeIndex = self.$panes.map(function(pane) {\n return pane.name;\n }).indexOf(active);\n } else {\n activeIndex = self.$panes.$active;\n }\n\n // remove pane from $panes array\n self.$panes.splice(index, 1);\n\n if (index < activeIndex) {\n // we removed a pane before the active pane, so we need to\n // decrement the active pane index\n activeIndex--;\n }\n else if (index === activeIndex && activeIndex === self.$panes.length) {\n // we remove the active pane and it was the one at the end,\n // so select the previous one\n activeIndex--;\n }\n if(activeIndex >= 0 && activeIndex < self.$panes.length) {\n self.$setActive(self.$panes[activeIndex].name || activeIndex);\n } else {\n self.$setActive();\n }\n };\n\n self.$setActive = $scope.$setActive = function(value) {\n self.$panes.$active = value;\n self.$activePaneChangeListeners.forEach(function(fn) {\n fn();\n });\n };\n\n self.$isActive = $scope.$isActive = function($pane, $index) {\n return self.$panes.$active === $pane.name || self.$panes.$active === $index;\n };\n\n };\n\n this.$get = function() {\n var $tab = {};\n $tab.defaults = defaults;\n $tab.controller = controller;\n return $tab;\n };\n\n })\n\n .directive('bsTabs', function($window, $animate, $tab, $parse) {\n\n var defaults = $tab.defaults;\n\n return {\n require: ['?ngModel', 'bsTabs'],\n transclude: true,\n scope: true,\n controller: ['$scope', '$element', '$attrs', $tab.controller],\n templateUrl: function(element, attr) {\n return attr.template || defaults.template;\n },\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsTabsCtrl = controllers[1];\n\n // 'ngModel' does interfere with form validation\n // and status, use `bsActivePane` instead to avoid it\n if(ngModelCtrl) {\n\n // Update the modelValue following\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\n ngModelCtrl.$setViewValue(bsTabsCtrl.$panes.$active);\n });\n\n // modelValue -> $formatters -> viewValue\n ngModelCtrl.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n bsTabsCtrl.$setActive(modelValue);\n return modelValue;\n });\n\n }\n\n if (attrs.bsActivePane) {\n // adapted from angularjs ngModelController bindings\n // https://github.com/angular/angular.js/blob/v1.3.1/src%2Fng%2Fdirective%2Finput.js#L1730\n var parsedBsActivePane = $parse(attrs.bsActivePane);\n\n // Update bsActivePane value with change\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\n parsedBsActivePane.assign(scope, bsTabsCtrl.$panes.$active);\n });\n\n // watch bsActivePane for value changes\n scope.$watch(attrs.bsActivePane, function(newValue, oldValue) {\n bsTabsCtrl.$setActive(newValue);\n }, true);\n }\n }\n };\n\n })\n\n .directive('bsPane', function($window, $animate, $sce) {\n\n return {\n require: ['^?ngModel', '^bsTabs'],\n scope: true,\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsTabsCtrl = controllers[1];\n\n // Add base class\n element.addClass('tab-pane');\n\n // Observe title attribute for change\n attrs.$observe('title', function(newValue, oldValue) {\n scope.title = $sce.trustAsHtml(newValue);\n });\n\n // Save tab name into scope\n scope.name = attrs.name;\n\n // Add animation class\n if(bsTabsCtrl.$options.animation) {\n element.addClass(bsTabsCtrl.$options.animation);\n }\n\n attrs.$observe('disabled', function(newValue, oldValue) {\n scope.disabled = scope.$eval(newValue);\n });\n\n // Push pane to parent bsTabs controller\n bsTabsCtrl.$push(scope);\n\n // remove pane from tab controller when pane is destroyed\n scope.$on('$destroy', function() {\n bsTabsCtrl.$remove(scope);\n });\n\n function render() {\n var index = bsTabsCtrl.$panes.indexOf(scope);\n $animate[bsTabsCtrl.$isActive(scope, index) ? 'addClass' : 'removeClass'](element, bsTabsCtrl.$options.activeClass);\n }\n\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\n render();\n });\n render();\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.core', 'mgcrea.ngStrap.helpers.dimensions'])\n\n .provider('$tooltip', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n customClass: '',\n prefixClass: 'tooltip',\n prefixEvent: 'tooltip',\n container: false,\n target: false,\n placement: 'top',\n templateUrl: 'tooltip/tooltip.tpl.html',\n template: '',\n contentTemplate: false,\n trigger: 'hover focus',\n keyboard: false,\n html: false,\n show: false,\n title: '',\n type: '',\n delay: 0,\n autoClose: false,\n bsEnabled: true,\n viewport: {\n selector: 'body',\n padding: 0\n }\n };\n\n this.$get = function($window, $rootScope, $bsCompiler, $q, $templateCache, $http, $animate, $sce, dimensions, $$rAF, $timeout) {\n\n var trim = String.prototype.trim;\n var isTouch = 'createTouch' in $window.document;\n var htmlReplaceRegExp = /ng-bind=\"/ig;\n var $body = angular.element($window.document);\n\n function TooltipFactory(element, config) {\n\n var $tooltip = {};\n\n // Common vars\n var options = $tooltip.$options = angular.extend({}, defaults, config);\n var promise = $tooltip.$promise = $bsCompiler.compile(options);\n var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new();\n\n var nodeName = element[0].nodeName.toLowerCase();\n if(options.delay && angular.isString(options.delay)) {\n var split = options.delay.split(',').map(parseFloat);\n options.delay = split.length > 1 ? {show: split[0], hide: split[1]} : split[0];\n }\n\n // Store $id to identify the triggering element in events\n // give priority to options.id, otherwise, try to use\n // element id if defined\n $tooltip.$id = options.id || element.attr('id') || '';\n\n // Support scope as string options\n if(options.title) {\n scope.title = $sce.trustAsHtml(options.title);\n }\n\n // Provide scope helpers\n scope.$setEnabled = function(isEnabled) {\n scope.$$postDigest(function() {\n $tooltip.setEnabled(isEnabled);\n });\n };\n scope.$hide = function() {\n scope.$$postDigest(function() {\n $tooltip.hide();\n });\n };\n scope.$show = function() {\n scope.$$postDigest(function() {\n $tooltip.show();\n });\n };\n scope.$toggle = function() {\n scope.$$postDigest(function() {\n $tooltip.toggle();\n });\n };\n // Publish isShown as a protected var on scope\n $tooltip.$isShown = scope.$isShown = false;\n\n // Private vars\n var timeout, hoverState;\n\n // Fetch, compile then initialize tooltip\n var compileData, tipElement, tipContainer, tipScope;\n promise.then(function(data) {\n compileData = data;\n $tooltip.init();\n });\n\n $tooltip.init = function() {\n\n // Options: delay\n if (options.delay && angular.isNumber(options.delay)) {\n options.delay = {\n show: options.delay,\n hide: options.delay\n };\n }\n\n // Replace trigger on touch devices ?\n // if(isTouch && options.trigger === defaults.trigger) {\n // options.trigger.replace(/hover/g, 'click');\n // }\n\n // Options : container\n if(options.container === 'self') {\n tipContainer = element;\n } else if(angular.isElement(options.container)) {\n tipContainer = options.container;\n } else if(options.container) {\n tipContainer = findElement(options.container);\n }\n\n // Options: trigger\n bindTriggerEvents();\n\n // Options: target\n if(options.target) {\n options.target = angular.isElement(options.target) ? options.target : findElement(options.target);\n }\n\n // Options: show\n if(options.show) {\n scope.$$postDigest(function() {\n options.trigger === 'focus' ? element[0].focus() : $tooltip.show();\n });\n }\n\n };\n\n $tooltip.destroy = function() {\n\n // Unbind events\n unbindTriggerEvents();\n\n // Remove element\n destroyTipElement();\n\n // Destroy scope\n scope.$destroy();\n\n };\n\n $tooltip.enter = function() {\n\n clearTimeout(timeout);\n hoverState = 'in';\n if (!options.delay || !options.delay.show) {\n return $tooltip.show();\n }\n\n timeout = setTimeout(function() {\n if (hoverState ==='in') $tooltip.show();\n }, options.delay.show);\n\n };\n\n $tooltip.show = function() {\n if (!options.bsEnabled || $tooltip.$isShown) return;\n\n scope.$emit(options.prefixEvent + '.show.before', $tooltip);\n var parent, after;\n if (options.container) {\n parent = tipContainer;\n if (tipContainer[0].lastChild) {\n after = angular.element(tipContainer[0].lastChild);\n } else {\n after = null;\n }\n } else {\n parent = null;\n after = element;\n }\n\n\n // Hide any existing tipElement\n if(tipElement) destroyTipElement();\n // Fetch a cloned element linked from template\n tipScope = $tooltip.$scope.$new();\n tipElement = $tooltip.$element = compileData.link(tipScope, function(clonedElement, scope) {});\n\n // Set the initial positioning. Make the tooltip invisible\n // so IE doesn't try to focus on it off screen.\n tipElement.css({top: '-9999px', left: '-9999px', right: 'auto', display: 'block', visibility: 'hidden'});\n\n // Options: animation\n if(options.animation) tipElement.addClass(options.animation);\n // Options: type\n if(options.type) tipElement.addClass(options.prefixClass + '-' + options.type);\n // Options: custom classes\n if(options.customClass) tipElement.addClass(options.customClass);\n\n // Append the element, without any animations. If we append\n // using $animate.enter, some of the animations cause the placement\n // to be off due to the transforms.\n after ? after.after(tipElement) : parent.prepend(tipElement);\n\n $tooltip.$isShown = scope.$isShown = true;\n safeDigest(scope);\n\n // Now, apply placement\n $tooltip.$applyPlacement();\n\n // Once placed, animate it.\n // Support v1.2+ $animate\n // https://github.com/angular/angular.js/issues/11713\n if(angular.version.minor <= 2) {\n $animate.enter(tipElement, parent, after, enterAnimateCallback);\n } else {\n $animate.enter(tipElement, parent, after).then(enterAnimateCallback);\n }\n safeDigest(scope);\n\n $$rAF(function () {\n // Once the tooltip is placed and the animation starts, make the tooltip visible\n if(tipElement) tipElement.css({visibility: 'visible'});\n });\n\n // Bind events\n if(options.keyboard) {\n if(options.trigger !== 'focus') {\n $tooltip.focus();\n }\n bindKeyboardEvents();\n }\n\n if(options.autoClose) {\n bindAutoCloseEvents();\n }\n\n };\n\n function enterAnimateCallback() {\n scope.$emit(options.prefixEvent + '.show', $tooltip);\n }\n\n $tooltip.leave = function() {\n\n clearTimeout(timeout);\n hoverState = 'out';\n if (!options.delay || !options.delay.hide) {\n return $tooltip.hide();\n }\n timeout = setTimeout(function () {\n if (hoverState === 'out') {\n $tooltip.hide();\n }\n }, options.delay.hide);\n\n };\n\n var _blur;\n var _tipToHide;\n $tooltip.hide = function(blur) {\n\n if(!$tooltip.$isShown) return;\n scope.$emit(options.prefixEvent + '.hide.before', $tooltip);\n\n // store blur value for leaveAnimateCallback to use\n _blur = blur;\n\n // store current tipElement reference to use\n // in leaveAnimateCallback\n _tipToHide = tipElement;\n\n // Support v1.2+ $animate\n // https://github.com/angular/angular.js/issues/11713\n if(angular.version.minor <= 2) {\n $animate.leave(tipElement, leaveAnimateCallback);\n } else {\n $animate.leave(tipElement).then(leaveAnimateCallback);\n }\n\n $tooltip.$isShown = scope.$isShown = false;\n safeDigest(scope);\n\n // Unbind events\n if(options.keyboard && tipElement !== null) {\n unbindKeyboardEvents();\n }\n\n if(options.autoClose && tipElement !== null) {\n unbindAutoCloseEvents();\n }\n };\n\n function leaveAnimateCallback() {\n scope.$emit(options.prefixEvent + '.hide', $tooltip);\n\n // check if current tipElement still references\n // the same element when hide was called\n if (tipElement === _tipToHide) {\n // Allow to blur the input when hidden, like when pressing enter key\n if(_blur && options.trigger === 'focus') {\n return element[0].blur();\n }\n\n // clean up child scopes\n destroyTipElement();\n }\n }\n\n $tooltip.toggle = function() {\n $tooltip.$isShown ? $tooltip.leave() : $tooltip.enter();\n };\n\n $tooltip.focus = function() {\n tipElement[0].focus();\n };\n\n $tooltip.setEnabled = function(isEnabled) {\n options.bsEnabled = isEnabled;\n };\n\n $tooltip.setViewport = function(viewport) {\n options.viewport = viewport;\n };\n\n // Protected methods\n\n $tooltip.$applyPlacement = function() {\n if(!tipElement) return;\n\n // Determine if we're doing an auto or normal placement\n var placement = options.placement,\n autoToken = /\\s?auto?\\s?/i,\n autoPlace = autoToken.test(placement);\n\n if (autoPlace) {\n placement = placement.replace(autoToken, '') || defaults.placement;\n }\n\n // Need to add the position class before we get\n // the offsets\n tipElement.addClass(options.placement);\n\n // Get the position of the target element\n // and the height and width of the tooltip so we can center it.\n var elementPosition = getPosition(),\n tipWidth = tipElement.prop('offsetWidth'),\n tipHeight = tipElement.prop('offsetHeight');\n\n // If we're auto placing, we need to check the positioning\n if (autoPlace) {\n var originalPlacement = placement;\n var container = options.container ? findElement(options.container) : element.parent();\n var containerPosition = getPosition(container);\n\n // Determine if the vertical placement\n if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > containerPosition.bottom) {\n placement = originalPlacement.replace('bottom', 'top');\n } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < containerPosition.top) {\n placement = originalPlacement.replace('top', 'bottom');\n }\n\n // Determine the horizontal placement\n // The exotic placements of left and right are opposite of the standard placements. Their arrows are put on the left/right\n // and flow in the opposite direction of their placement.\n if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') &&\n elementPosition.right + tipWidth > containerPosition.width) {\n\n placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right');\n } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') &&\n elementPosition.left - tipWidth < containerPosition.left) {\n\n placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left');\n }\n\n tipElement.removeClass(originalPlacement).addClass(placement);\n }\n\n // Get the tooltip's top and left coordinates to center it with this directive.\n var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight);\n applyPlacement(tipPosition, placement);\n };\n\n $tooltip.$onKeyUp = function(evt) {\n if (evt.which === 27 && $tooltip.$isShown) {\n $tooltip.hide();\n evt.stopPropagation();\n }\n };\n\n $tooltip.$onFocusKeyUp = function(evt) {\n if (evt.which === 27) {\n element[0].blur();\n evt.stopPropagation();\n }\n };\n\n $tooltip.$onFocusElementMouseDown = function(evt) {\n evt.preventDefault();\n evt.stopPropagation();\n // Some browsers do not auto-focus buttons (eg. Safari)\n $tooltip.$isShown ? element[0].blur() : element[0].focus();\n };\n\n // bind/unbind events\n function bindTriggerEvents() {\n var triggers = options.trigger.split(' ');\n angular.forEach(triggers, function(trigger) {\n if(trigger === 'click') {\n element.on('click', $tooltip.toggle);\n } else if(trigger !== 'manual') {\n element.on(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);\n element.on(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);\n nodeName === 'button' && trigger !== 'hover' && element.on(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);\n }\n });\n }\n\n function unbindTriggerEvents() {\n var triggers = options.trigger.split(' ');\n for (var i = triggers.length; i--;) {\n var trigger = triggers[i];\n if(trigger === 'click') {\n element.off('click', $tooltip.toggle);\n } else if(trigger !== 'manual') {\n element.off(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);\n element.off(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);\n nodeName === 'button' && trigger !== 'hover' && element.off(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);\n }\n }\n }\n\n function bindKeyboardEvents() {\n if(options.trigger !== 'focus') {\n tipElement.on('keyup', $tooltip.$onKeyUp);\n } else {\n element.on('keyup', $tooltip.$onFocusKeyUp);\n }\n }\n\n function unbindKeyboardEvents() {\n if(options.trigger !== 'focus') {\n tipElement.off('keyup', $tooltip.$onKeyUp);\n } else {\n element.off('keyup', $tooltip.$onFocusKeyUp);\n }\n }\n\n var _autoCloseEventsBinded = false;\n function bindAutoCloseEvents() {\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n // Stop propagation when clicking inside tooltip\n tipElement.on('click', stopEventPropagation);\n\n // Hide when clicking outside tooltip\n $body.on('click', $tooltip.hide);\n\n _autoCloseEventsBinded = true;\n }, 0, false);\n }\n\n function unbindAutoCloseEvents() {\n if (_autoCloseEventsBinded) {\n tipElement.off('click', stopEventPropagation);\n $body.off('click', $tooltip.hide);\n _autoCloseEventsBinded = false;\n }\n }\n\n function stopEventPropagation(event) {\n event.stopPropagation();\n }\n\n // Private methods\n\n function getPosition($element) {\n $element = $element || (options.target || element);\n\n var el = $element[0],\n isBody = el.tagName === 'BODY';\n\n var elRect = el.getBoundingClientRect();\n var rect = {};\n\n // IE8 has issues with angular.extend and using elRect directly.\n // By coping the values of elRect into a new object, we can continue to use extend\n for (var p in elRect) {\n // DO NOT use hasOwnProperty when inspecting the return of getBoundingClientRect.\n rect[p] = elRect[p];\n }\n\n if (rect.width === null) {\n // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093\n rect = angular.extend({}, rect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top });\n }\n var elOffset = isBody ? { top: 0, left: 0 } : dimensions.offset(el),\n scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.prop('scrollTop') || 0 },\n outerDims = isBody ? { width: document.documentElement.clientWidth, height: $window.innerHeight } : null;\n\n return angular.extend({}, rect, scroll, outerDims, elOffset);\n }\n\n function getCalculatedOffset(placement, position, actualWidth, actualHeight) {\n var offset;\n var split = placement.split('-');\n\n switch (split[0]) {\n case 'right':\n offset = {\n top: position.top + position.height / 2 - actualHeight / 2,\n left: position.left + position.width\n };\n break;\n case 'bottom':\n offset = {\n top: position.top + position.height,\n left: position.left + position.width / 2 - actualWidth / 2\n };\n break;\n case 'left':\n offset = {\n top: position.top + position.height / 2 - actualHeight / 2,\n left: position.left - actualWidth\n };\n break;\n default:\n offset = {\n top: position.top - actualHeight,\n left: position.left + position.width / 2 - actualWidth / 2\n };\n break;\n }\n\n if(!split[1]) {\n return offset;\n }\n\n // Add support for corners @todo css\n if(split[0] === 'top' || split[0] === 'bottom') {\n switch (split[1]) {\n case 'left':\n offset.left = position.left;\n break;\n case 'right':\n offset.left = position.left + position.width - actualWidth;\n }\n } else if(split[0] === 'left' || split[0] === 'right') {\n switch (split[1]) {\n case 'top':\n offset.top = position.top - actualHeight;\n break;\n case 'bottom':\n offset.top = position.top + position.height;\n }\n }\n\n return offset;\n }\n\n function applyPlacement(offset, placement) {\n var tip = tipElement[0],\n width = tip.offsetWidth,\n height = tip.offsetHeight;\n\n // manually read margins because getBoundingClientRect includes difference\n var marginTop = parseInt(dimensions.css(tip, 'margin-top'), 10),\n marginLeft = parseInt(dimensions.css(tip, 'margin-left'), 10);\n\n // we must check for NaN for ie 8/9\n if (isNaN(marginTop)) marginTop = 0;\n if (isNaN(marginLeft)) marginLeft = 0;\n\n offset.top = offset.top + marginTop;\n offset.left = offset.left + marginLeft;\n\n // dimensions setOffset doesn't round pixel values\n // so we use setOffset directly with our own function\n dimensions.setOffset(tip, angular.extend({\n using: function (props) {\n tipElement.css({\n top: Math.round(props.top) + 'px',\n left: Math.round(props.left) + 'px',\n right: ''\n });\n }\n }, offset), 0);\n\n // check to see if placing tip in new offset caused the tip to resize itself\n var actualWidth = tip.offsetWidth,\n actualHeight = tip.offsetHeight;\n\n if (placement === 'top' && actualHeight !== height) {\n offset.top = offset.top + height - actualHeight;\n }\n\n // If it's an exotic placement, exit now instead of\n // applying a delta and changing the arrow\n if (/top-left|top-right|bottom-left|bottom-right/.test(placement)) return;\n\n var delta = getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight);\n\n if (delta.left) {\n offset.left += delta.left;\n } else {\n offset.top += delta.top;\n }\n\n dimensions.setOffset(tip, offset);\n\n if (/top|right|bottom|left/.test(placement)) {\n var isVertical = /top|bottom/.test(placement),\n arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight,\n arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight';\n\n replaceArrow(arrowDelta, tip[arrowOffsetPosition], isVertical);\n }\n }\n\n function getViewportAdjustedDelta(placement, position, actualWidth, actualHeight) {\n var delta = { top: 0, left: 0 },\n $viewport = options.viewport && findElement(options.viewport.selector || options.viewport);\n\n if (!$viewport) {\n return delta;\n }\n\n var viewportPadding = options.viewport && options.viewport.padding || 0,\n viewportDimensions = getPosition($viewport);\n\n if (/right|left/.test(placement)) {\n var topEdgeOffset = position.top - viewportPadding - viewportDimensions.scroll,\n bottomEdgeOffset = position.top + viewportPadding - viewportDimensions.scroll + actualHeight;\n if (topEdgeOffset < viewportDimensions.top) { // top overflow\n delta.top = viewportDimensions.top - topEdgeOffset;\n } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow\n delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset;\n }\n } else {\n var leftEdgeOffset = position.left - viewportPadding,\n rightEdgeOffset = position.left + viewportPadding + actualWidth;\n if (leftEdgeOffset < viewportDimensions.left) { // left overflow\n delta.left = viewportDimensions.left - leftEdgeOffset;\n } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow\n delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset;\n }\n }\n\n return delta;\n }\n\n function replaceArrow(delta, dimension, isHorizontal) {\n var $arrow = findElement('.tooltip-arrow, .arrow', tipElement[0]);\n\n $arrow.css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')\n .css(isHorizontal ? 'top' : 'left', '');\n }\n\n function destroyTipElement() {\n // Cancel pending callbacks\n clearTimeout(timeout);\n\n if($tooltip.$isShown && tipElement !== null) {\n if(options.autoClose) {\n unbindAutoCloseEvents();\n }\n\n if(options.keyboard) {\n unbindKeyboardEvents();\n }\n }\n\n if(tipScope) {\n tipScope.$destroy();\n tipScope = null;\n }\n\n if(tipElement) {\n tipElement.remove();\n tipElement = $tooltip.$element = null;\n }\n }\n\n return $tooltip;\n\n }\n\n // Helper functions\n\n function safeDigest(scope) {\n scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();\n }\n\n function findElement(query, element) {\n return angular.element((element || document).querySelectorAll(query));\n }\n\n var fetchPromises = {};\n function fetchTemplate(template) {\n if(fetchPromises[template]) return fetchPromises[template];\n return (fetchPromises[template] = $http.get(template, {cache: $templateCache}).then(function(res) {\n return res.data;\n }));\n }\n\n return TooltipFactory;\n\n };\n\n })\n\n .directive('bsTooltip', function($window, $location, $sce, $tooltip, $$rAF) {\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'backdropAnimation', 'type', 'customClass', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // should not parse target attribute (anchor tag), only data-target #1454\n var dataTarget = element.attr('data-target');\n if(angular.isDefined(dataTarget)) {\n if(falseValueRegExp.test(dataTarget))\n options.target = false;\n else\n options.target = dataTarget;\n }\n\n // overwrite inherited title value when no value specified\n // fix for angular 1.3.1 531a8de72c439d8ddd064874bf364c00cedabb11\n if (!scope.hasOwnProperty('title')){\n scope.title = '';\n }\n\n // Observe scope attributes for change\n attr.$observe('title', function(newValue) {\n if (angular.isDefined(newValue) || !scope.hasOwnProperty('title')) {\n var oldValue = scope.title;\n scope.title = $sce.trustAsHtml(newValue);\n angular.isDefined(oldValue) && $$rAF(function() {\n tooltip && tooltip.$applyPlacement();\n });\n }\n });\n\n // Support scope as an object\n attr.bsTooltip && scope.$watch(attr.bsTooltip, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.title = newValue;\n }\n angular.isDefined(oldValue) && $$rAF(function() {\n tooltip && tooltip.$applyPlacement();\n });\n }, true);\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!tooltip || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(tooltip),?/i);\n newValue === true ? tooltip.show() : tooltip.hide();\n });\n\n // Enabled binding support\n attr.bsEnabled && scope.$watch(attr.bsEnabled, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.bsEnabled, newValue, oldValue);\n if(!tooltip || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|1|,?(tooltip),?/i);\n newValue === false ? tooltip.setEnabled(false) : tooltip.setEnabled(true);\n });\n\n // Viewport support\n attr.viewport && scope.$watch(attr.viewport, function (newValue) {\n if(!tooltip || !angular.isDefined(newValue)) return;\n tooltip.setViewport(newValue);\n });\n\n // Initialize popover\n var tooltip = $tooltip(element, options);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if(tooltip) tooltip.destroy();\n options = null;\n tooltip = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.timepicker', [\n 'mgcrea.ngStrap.helpers.dateParser',\n 'mgcrea.ngStrap.helpers.dateFormatter',\n 'mgcrea.ngStrap.tooltip'])\n\n .provider('$timepicker', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n //uncommenting the following line will break backwards compatability\n // prefixEvent: 'timepicker',\n prefixClass: 'timepicker',\n placement: 'bottom-left',\n templateUrl: 'timepicker/timepicker.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n // lang: $locale.id,\n useNative: true,\n timeType: 'date',\n timeFormat: 'shortTime',\n timezone: null,\n modelTimeFormat: null,\n autoclose: false,\n minTime: -Infinity,\n maxTime: +Infinity,\n length: 5,\n hourStep: 1,\n minuteStep: 5,\n secondStep: 5,\n roundDisplay: false,\n iconUp: 'glyphicon glyphicon-chevron-up',\n iconDown: 'glyphicon glyphicon-chevron-down',\n arrowBehavior: 'pager'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\n\n function timepickerFactory(element, controller, config) {\n\n var $timepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $timepicker.$options;\n var scope = $timepicker.$scope;\n\n var lang = options.lang;\n var formatDate = function(date, format, timezone) {\n return $dateFormatter.formatDate(date, format, lang, timezone);\n };\n\n function floorMinutes(time)\n {\n // coeff used to floor current time to nearest minuteStep interval\n var coeff = 1000 * 60 * options.minuteStep;\n return new Date(Math.floor(time.getTime() / coeff) * coeff);\n }\n\n // View vars\n\n var selectedIndex = 0;\n var defaultDate = options.roundDisplay ? floorMinutes(new Date()) : new Date();\n var startDate = controller.$dateValue || defaultDate;\n var viewDate = {hour: startDate.getHours(), meridian: startDate.getHours() < 12, minute: startDate.getMinutes(), second: startDate.getSeconds(), millisecond: startDate.getMilliseconds()};\n\n var format = $dateFormatter.getDatetimeFormat(options.timeFormat, lang);\n\n var hoursFormat = $dateFormatter.hoursFormat(format),\n timeSeparator = $dateFormatter.timeSeparator(format),\n minutesFormat = $dateFormatter.minutesFormat(format),\n secondsFormat = $dateFormatter.secondsFormat(format),\n showSeconds = $dateFormatter.showSeconds(format),\n showAM = $dateFormatter.showAM(format);\n\n scope.$iconUp = options.iconUp;\n scope.$iconDown = options.iconDown;\n\n // Scope methods\n\n scope.$select = function(date, index) {\n $timepicker.select(date, index);\n };\n scope.$moveIndex = function(value, index) {\n $timepicker.$moveIndex(value, index);\n };\n scope.$switchMeridian = function(date) {\n $timepicker.switchMeridian(date);\n };\n\n // Public methods\n\n $timepicker.update = function(date) {\n // console.warn('$timepicker.update() newValue=%o', date);\n if(angular.isDate(date) && !isNaN(date.getTime())) {\n $timepicker.$date = date;\n angular.extend(viewDate, {hour: date.getHours(), minute: date.getMinutes(), second: date.getSeconds(), millisecond: date.getMilliseconds()});\n $timepicker.$build();\n } else if(!$timepicker.$isBuilt) {\n $timepicker.$build();\n }\n };\n\n $timepicker.select = function(date, index, keep) {\n // console.warn('$timepicker.select', date, scope.$mode);\n if(!controller.$dateValue || isNaN(controller.$dateValue.getTime())) controller.$dateValue = new Date(1970, 0, 1);\n if(!angular.isDate(date)) date = new Date(date);\n if(index === 0) controller.$dateValue.setHours(date.getHours());\n else if(index === 1) controller.$dateValue.setMinutes(date.getMinutes());\n else if(index === 2) controller.$dateValue.setSeconds(date.getSeconds());\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n if(options.autoclose && !keep) {\n $timeout(function() { $timepicker.hide(true); });\n }\n };\n\n $timepicker.switchMeridian = function(date) {\n if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) {\n return;\n }\n var hours = (date || controller.$dateValue).getHours();\n controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12);\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n };\n\n // Protected methods\n\n $timepicker.$build = function() {\n // console.warn('$timepicker.$build() viewDate=%o', viewDate);\n var i, midIndex = scope.midIndex = parseInt(options.length / 2, 10);\n var hours = [], hour;\n for(i = 0; i < options.length; i++) {\n hour = new Date(1970, 0, 1, viewDate.hour - (midIndex - i) * options.hourStep);\n hours.push({date: hour, label: formatDate(hour, hoursFormat), selected: $timepicker.$date && $timepicker.$isSelected(hour, 0), disabled: $timepicker.$isDisabled(hour, 0)});\n }\n var minutes = [], minute;\n for(i = 0; i < options.length; i++) {\n minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep);\n minutes.push({date: minute, label: formatDate(minute, minutesFormat), selected: $timepicker.$date && $timepicker.$isSelected(minute, 1), disabled: $timepicker.$isDisabled(minute, 1)});\n }\n var seconds = [], second;\n for(i = 0; i < options.length; i++) {\n second = new Date(1970, 0, 1, 0, 0, viewDate.second - (midIndex - i) * options.secondStep);\n seconds.push({date: second, label: formatDate(second, secondsFormat), selected: $timepicker.$date && $timepicker.$isSelected(second, 2), disabled: $timepicker.$isDisabled(second, 2)});\n }\n\n var rows = [];\n for(i = 0; i < options.length; i++) {\n if (showSeconds) {\n rows.push([hours[i], minutes[i], seconds[i]]);\n } else {\n rows.push([hours[i], minutes[i]]);\n }\n }\n scope.rows = rows;\n scope.showSeconds = showSeconds;\n scope.showAM = showAM;\n scope.isAM = ($timepicker.$date || hours[midIndex].date).getHours() < 12;\n scope.timeSeparator = timeSeparator;\n $timepicker.$isBuilt = true;\n };\n\n $timepicker.$isSelected = function(date, index) {\n if(!$timepicker.$date) return false;\n else if(index === 0) {\n return date.getHours() === $timepicker.$date.getHours();\n } else if(index === 1) {\n return date.getMinutes() === $timepicker.$date.getMinutes();\n } else if(index === 2) {\n return date.getSeconds() === $timepicker.$date.getSeconds();\n }\n };\n\n $timepicker.$isDisabled = function(date, index) {\n var selectedTime;\n if(index === 0) {\n selectedTime = date.getTime() + viewDate.minute * 6e4 + viewDate.second * 1e3;\n } else if(index === 1) {\n selectedTime = date.getTime() + viewDate.hour * 36e5 + viewDate.second * 1e3;\n } else if(index === 2) {\n selectedTime = date.getTime() + viewDate.hour * 36e5 + viewDate.minute * 6e4;\n }\n return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1;\n };\n\n scope.$arrowAction = function (value, index) {\n if (options.arrowBehavior === 'picker') {\n $timepicker.$setTimeByStep(value,index);\n } else {\n $timepicker.$moveIndex(value,index);\n }\n };\n\n $timepicker.$setTimeByStep = function(value, index) {\n var newDate = new Date($timepicker.$date);\n var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;\n var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;\n var seconds = newDate.getSeconds(), secondsLength = formatDate(newDate, secondsFormat).length;\n if (index === 0) {\n newDate.setHours(hours - (parseInt(options.hourStep, 10) * value));\n }\n else if (index === 1) {\n newDate.setMinutes(minutes - (parseInt(options.minuteStep, 10) * value));\n }\n else if (index === 2) {\n newDate.setSeconds(seconds - (parseInt(options.secondStep, 10) * value));\n }\n $timepicker.select(newDate, index, true);\n };\n\n $timepicker.$moveIndex = function(value, index) {\n var targetDate;\n if(index === 0) {\n targetDate = new Date(1970, 0, 1, viewDate.hour + (value * options.length), viewDate.minute, viewDate.second);\n angular.extend(viewDate, {hour: targetDate.getHours()});\n } else if(index === 1) {\n targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + (value * options.length * options.minuteStep), viewDate.second);\n angular.extend(viewDate, {minute: targetDate.getMinutes()});\n } else if(index === 2) {\n targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute, viewDate.second + (value * options.length * options.secondStep));\n angular.extend(viewDate, {second: targetDate.getSeconds()});\n }\n $timepicker.$build();\n };\n\n $timepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n if(evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $timepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // Close on enter\n if(evt.keyCode === 13) return $timepicker.hide(true);\n\n // Navigate with keyboard\n var newDate = new Date($timepicker.$date);\n var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;\n var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;\n var seconds = newDate.getSeconds(), secondsLength = formatDate(newDate, secondsFormat).length;\n var sepLength = 1;\n var lateralMove = /(37|39)/.test(evt.keyCode);\n var count = 2 + showSeconds * 1 + showAM * 1;\n\n // Navigate indexes (left, right)\n if (lateralMove) {\n if(evt.keyCode === 37) selectedIndex = selectedIndex < 1 ? count - 1 : selectedIndex - 1;\n else if(evt.keyCode === 39) selectedIndex = selectedIndex < count - 1 ? selectedIndex + 1 : 0;\n }\n\n // Update values (up, down)\n var selectRange = [0, hoursLength];\n var incr = 0;\n if (evt.keyCode === 38) incr = -1;\n if (evt.keyCode === 40) incr = +1;\n var isSeconds = selectedIndex === 2 && showSeconds;\n var isMeridian = selectedIndex === 2 && !showSeconds || selectedIndex === 3 && showSeconds;\n if(selectedIndex === 0) {\n newDate.setHours(hours + incr*parseInt(options.hourStep, 10));\n // re-calculate hours length because we have changed hours value\n hoursLength = formatDate(newDate, hoursFormat).length;\n selectRange = [0, hoursLength];\n } else if(selectedIndex === 1) {\n newDate.setMinutes(minutes + incr*parseInt(options.minuteStep, 10));\n // re-calculate minutes length because we have changes minutes value\n minutesLength = formatDate(newDate, minutesFormat).length;\n selectRange = [hoursLength + sepLength, minutesLength];\n } else if(isSeconds) {\n newDate.setSeconds(seconds + incr*parseInt(options.secondStep, 10));\n // re-calculate seconds length because we have changes seconds value\n secondsLength = formatDate(newDate, secondsFormat).length;\n selectRange = [hoursLength + sepLength + minutesLength + sepLength, secondsLength];\n } else if(isMeridian) {\n if(!lateralMove) $timepicker.switchMeridian();\n selectRange = [hoursLength + sepLength + minutesLength + sepLength + (secondsLength + sepLength)*showSeconds, 2];\n }\n $timepicker.select(newDate, selectedIndex, true);\n createSelection(selectRange[0], selectRange[1]);\n parentScope.$digest();\n };\n\n // Private\n\n function createSelection(start, length) {\n var end = start + length;\n if(element[0].createTextRange) {\n var selRange = element[0].createTextRange();\n selRange.collapse(true);\n selRange.moveStart('character', start);\n selRange.moveEnd('character', end);\n selRange.select();\n } else if(element[0].setSelectionRange) {\n element[0].setSelectionRange(start, end);\n } else if(angular.isUndefined(element[0].selectionStart)) {\n element[0].selectionStart = start;\n element[0].selectionEnd = end;\n }\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $timepicker.init;\n $timepicker.init = function() {\n if(isNative && options.useNative) {\n element.prop('type', 'time');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if(isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $timepicker.destroy;\n $timepicker.destroy = function() {\n if(isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $timepicker.show;\n $timepicker.show = function() {\n _show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n $timepicker.$element && $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if(options.keyboard) {\n element && element.on('keydown', $timepicker.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $timepicker.hide;\n $timepicker.hide = function(blur) {\n if(!$timepicker.$isShown) return;\n $timepicker.$element && $timepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if(options.keyboard) {\n element && element.off('keydown', $timepicker.$onKeyDown);\n }\n _hide(blur);\n };\n\n return $timepicker;\n\n }\n\n timepickerFactory.defaults = defaults;\n return timepickerFactory;\n\n };\n\n })\n\n\n .directive('bsTimepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) {\n\n var defaults = $timepicker.defaults;\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'autoclose', 'timeType', 'timeFormat', 'timezone', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'secondStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown', 'roundDisplay', 'id', 'prefixClass', 'prefixEvent'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'autoclose', 'useNative', 'roundDisplay'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!timepicker || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(timepicker),?/i);\n newValue === true ? timepicker.show() : timepicker.hide();\n });\n\n // Initialize timepicker\n if(isNative && (options.useNative || defaults.useNative)) options.timeFormat = 'HH:mm';\n var timepicker = $timepicker(element, controller, options);\n options = timepicker.$options;\n\n var lang = options.lang;\n var formatDate = function(date, format, timezone) {\n return $dateFormatter.formatDate(date, format, lang, timezone);\n };\n\n // Initialize parser\n var dateParser = $dateParser({format: options.timeFormat, lang: lang});\n\n // Observe attributes for changes\n angular.forEach(['minTime', 'maxTime'], function(key) {\n // console.warn('attr.$observe(%s)', key, attr[key]);\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\n timepicker.$options[key] = dateParser.getTimeForAttribute(key, newValue);\n !isNaN(timepicker.$options[key]) && timepicker.$build();\n validateAgainstMinMaxTime(controller.$dateValue);\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue, controller.$dateValue);\n timepicker.update(controller.$dateValue);\n }, true);\n\n function validateAgainstMinMaxTime(parsedTime) {\n if (!angular.isDate(parsedTime)) return;\n var isMinValid = isNaN(options.minTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) >= options.minTime;\n var isMaxValid = isNaN(options.maxTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) <= options.maxTime;\n var isValid = isMinValid && isMaxValid;\n controller.$setValidity('date', isValid);\n controller.$setValidity('min', isMinValid);\n controller.$setValidity('max', isMaxValid);\n // Only update the model when we have a valid date\n if(!isValid) {\n return;\n }\n controller.$dateValue = parsedTime;\n }\n\n // viewValue -> $parsers -> modelValue\n controller.$parsers.unshift(function(viewValue) {\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\n var date;\n // Null values should correctly reset the model value & validity\n if(!viewValue) {\n // BREAKING CHANGE:\n // return null (not undefined) when input value is empty, so angularjs 1.3\n // ngModelController can go ahead and run validators, like ngRequired\n controller.$setValidity('date', true);\n return null;\n }\n var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue);\n if(!parsedTime || isNaN(parsedTime.getTime())) {\n controller.$setValidity('date', false);\n // return undefined, causes ngModelController to\n // invalidate model value\n return;\n } else {\n validateAgainstMinMaxTime(parsedTime);\n }\n\n if(options.timeType === 'string') {\n date = dateParser.timezoneOffsetAdjust(parsedTime, options.timezone, true);\n return formatDate(date, options.modelTimeFormat || options.timeFormat);\n }\n date = dateParser.timezoneOffsetAdjust(controller.$dateValue, options.timezone, true);\n if(options.timeType === 'number') {\n return date.getTime();\n } else if(options.timeType === 'unix') {\n return date.getTime() / 1000;\n } else if(options.timeType === 'iso') {\n return date.toISOString();\n } else {\n return new Date(date);\n }\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var date;\n if(angular.isUndefined(modelValue) || modelValue === null) {\n date = NaN;\n } else if(angular.isDate(modelValue)) {\n date = modelValue;\n } else if(options.timeType === 'string') {\n date = dateParser.parse(modelValue, null, options.modelTimeFormat);\n } else if(options.timeType === 'unix') {\n date = new Date(modelValue * 1000);\n } else {\n date = new Date(modelValue);\n }\n // Setup default value?\n // if(isNaN(date.getTime())) date = new Date(new Date().setMinutes(0) + 36e5);\n controller.$dateValue = dateParser.timezoneOffsetAdjust(date, options.timezone);\n return getTimeFormattedString();\n });\n\n // viewValue -> element\n controller.$render = function() {\n // console.warn('$render(\"%s\"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);\n element.val(getTimeFormattedString());\n };\n\n function getTimeFormattedString() {\n return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat);\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (timepicker) timepicker.destroy();\n options = null;\n timepicker = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.typeahead', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions'])\n\n .provider('$typeahead', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'typeahead',\n prefixEvent: '$typeahead',\n placement: 'bottom-left',\n templateUrl: 'typeahead/typeahead.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n minLength: 1,\n filter: 'filter',\n limit: 6,\n autoSelect: false,\n comparator: '',\n trimValue: true\n };\n\n this.$get = function($window, $rootScope, $tooltip, $$rAF, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n\n function TypeaheadFactory(element, controller, config) {\n\n var $typeahead = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $typeahead = $tooltip(element, options);\n var parentScope = config.scope;\n var scope = $typeahead.$scope;\n\n scope.$resetMatches = function(){\n scope.$matches = [];\n scope.$activeIndex = options.autoSelect ? 0 : -1; // If set to 0, the first match will be highlighted\n };\n scope.$resetMatches();\n\n scope.$activate = function(index) {\n scope.$$postDigest(function() {\n $typeahead.activate(index);\n });\n };\n\n scope.$select = function(index, evt) {\n scope.$$postDigest(function() {\n $typeahead.select(index);\n });\n };\n\n scope.$isVisible = function() {\n return $typeahead.$isVisible();\n };\n\n // Public methods\n\n $typeahead.update = function(matches) {\n scope.$matches = matches;\n if(scope.$activeIndex >= matches.length) {\n scope.$activeIndex = options.autoSelect ? 0: -1;\n }\n\n // wrap in a $timeout so the results are updated\n // before repositioning\n safeDigest(scope);\n $$rAF($typeahead.$applyPlacement);\n };\n\n $typeahead.activate = function(index) {\n scope.$activeIndex = index;\n };\n\n $typeahead.select = function(index) {\n if(index === -1) return;\n var value = scope.$matches[index].value;\n // console.log('$setViewValue', value);\n controller.$setViewValue(value);\n controller.$render();\n scope.$resetMatches();\n if(parentScope) parentScope.$digest();\n // Emit event\n scope.$emit(options.prefixEvent + '.select', value, index, $typeahead);\n };\n\n // Protected methods\n\n $typeahead.$isVisible = function() {\n if(!options.minLength || !controller) {\n return !!scope.$matches.length;\n }\n // minLength support\n return scope.$matches.length && angular.isString(controller.$viewValue) && controller.$viewValue.length >= options.minLength;\n };\n\n $typeahead.$getIndex = function(value) {\n var l = scope.$matches.length, i = l;\n if(!l) return;\n for(i = l; i--;) {\n if(scope.$matches[i].value === value) break;\n }\n if(i < 0) return;\n return i;\n };\n\n $typeahead.$onMouseDown = function(evt) {\n // Prevent blur on mousedown\n evt.preventDefault();\n evt.stopPropagation();\n };\n\n $typeahead.$onKeyDown = function(evt) {\n if(!/(38|40|13)/.test(evt.keyCode)) return;\n\n // Let ngSubmit pass if the typeahead tip is hidden or no option is selected\n if($typeahead.$isVisible() && !(evt.keyCode === 13 && scope.$activeIndex === -1)) {\n evt.preventDefault();\n evt.stopPropagation();\n }\n\n // Select with enter\n if(evt.keyCode === 13 && scope.$matches.length) {\n $typeahead.select(scope.$activeIndex);\n }\n\n // Navigate with keyboard\n else if(evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--;\n else if(evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++;\n else if(angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0;\n scope.$digest();\n };\n\n // Overrides\n\n var show = $typeahead.show;\n $typeahead.show = function() {\n show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed immediately.\n $timeout(function() {\n $typeahead.$element && $typeahead.$element.on('mousedown', $typeahead.$onMouseDown);\n if(options.keyboard) {\n element && element.on('keydown', $typeahead.$onKeyDown);\n }\n }, 0, false);\n };\n\n var hide = $typeahead.hide;\n $typeahead.hide = function() {\n $typeahead.$element && $typeahead.$element.off('mousedown', $typeahead.$onMouseDown);\n if(options.keyboard) {\n element && element.off('keydown', $typeahead.$onKeyDown);\n }\n if(!options.autoSelect)\n $typeahead.activate(-1);\n hide();\n };\n\n return $typeahead;\n\n }\n\n // Helper functions\n\n function safeDigest(scope) {\n scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();\n }\n\n TypeaheadFactory.defaults = defaults;\n return TypeaheadFactory;\n\n };\n\n })\n\n .directive('bsTypeahead', function($window, $parse, $q, $typeahead, $parseOptions) {\n\n var defaults = $typeahead.defaults;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'filter', 'limit', 'minLength', 'watchOptions', 'selectMode', 'autoSelect', 'comparator', 'id', 'prefixEvent', 'prefixClass'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'trimValue'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false;\n });\n\n // Disable browser autocompletion\n element.attr('autocomplete' ,'false');\n\n // Build proper bsOptions\n var filter = options.filter || defaults.filter;\n var limit = options.limit || defaults.limit;\n var comparator = options.comparator || defaults.comparator;\n\n var bsOptions = attr.bsOptions;\n if(filter) bsOptions += ' | ' + filter + ':$viewValue';\n if (comparator) bsOptions += ':' + comparator;\n if(limit) bsOptions += ' | limitTo:' + limit;\n var parsedOptions = $parseOptions(bsOptions);\n\n // Initialize typeahead\n var typeahead = $typeahead(element, controller, options);\n\n // Watch options on demand\n if(options.watchOptions) {\n // Watch bsOptions values before filtering for changes, drop function calls\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').replace(/\\(.*\\)/g, '').trim();\n scope.$watchCollection(watchedOptions, function (newValue, oldValue) {\n // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue);\n parsedOptions.valuesFn(scope, controller).then(function (values) {\n typeahead.update(values);\n controller.$render();\n });\n });\n }\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('$watch', element.attr('ng-model'), newValue);\n scope.$modelValue = newValue; // Publish modelValue on scope for custom templates\n parsedOptions.valuesFn(scope, controller)\n .then(function(values) {\n // Prevent input with no future prospect if selectMode is truthy\n // @TODO test selectMode\n if(options.selectMode && !values.length && newValue.length > 0) {\n controller.$setViewValue(controller.$viewValue.substring(0, controller.$viewValue.length - 1));\n return;\n }\n if(values.length > limit) values = values.slice(0, limit);\n var isVisible = typeahead.$isVisible();\n isVisible && typeahead.update(values);\n // Do not re-queue an update if a correct value has been selected\n if(values.length === 1 && values[0].value === newValue) return;\n !isVisible && typeahead.update(values);\n // Queue a new rendering that will leverage collection loading\n controller.$render();\n });\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var displayValue = parsedOptions.displayValue(modelValue);\n\n // If we can determine the displayValue, use that\n if (displayValue) return displayValue;\n\n // If there's no display value, attempt to use the modelValue.\n // If the model is an object not much we can do\n if (modelValue && typeof modelValue !== 'object') {\n return modelValue;\n }\n return '';\n });\n\n // Model rendering in view\n controller.$render = function () {\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n if(controller.$isEmpty(controller.$viewValue)) return element.val('');\n var index = typeahead.$getIndex(controller.$modelValue);\n var selected = angular.isDefined(index) ? typeahead.$scope.$matches[index].label : controller.$viewValue;\n selected = angular.isObject(selected) ? parsedOptions.displayValue(selected) : selected;\n var value = selected ? selected.toString().replace(/<(?:.|\\n)*?>/gm, '') : '';\n element.val(options.trimValue === false ? value : value.trim());\n };\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (typeahead) typeahead.destroy();\n options = null;\n typeahead = null;\n });\n\n }\n };\n\n });\n"],"sourceRoot":"/source/"} \ No newline at end of file +{"version":3,"sources":["angular-strap.js","helpers/compiler.js","helpers/date-formatter.js","affix/affix.js","alert/alert.js","aside/aside.js","button/button.js","collapse/collapse.js","datepicker/datepicker.js","dropdown/dropdown.js","helpers/date-parser.js","helpers/debounce.js","helpers/dimensions.js","helpers/parse-options.js","helpers/raf.js","modal/modal.js","navbar/navbar.js","popover/popover.js","scrollspy/scrollspy.js","select/select.js","timepicker/timepicker.js","tab/tab.js","typeahead/typeahead.js","tooltip/tooltip.js"],"names":["window","document","undefined","templateUrl","options","cache","$templateCache","then","element","res","fetchTemplate","template","fetchPromises","bsCompilerService","$inject","$http","get","angular","module","getDefaultLocale","$locale","this","compile","controller","console","controllerAs","resolve","copy","locals","bindToController","forEach","value","isString","$injector","key","invoke","transformTemplate","identity","extend","$template","when","$q","contentEl","findElement","outerHTML","contentTemplate","all","templateEl","removeAttr","html","templates","replace","next","remove","link","scope","trim","contents","linkFn","invokeCtrl","children","instance","ctrl","isObject","arguments","data","apply","bodyEl","$window","body","windowEl","defaults","AffixFactory","offsetTop","$affix","inlineStyles","$get","reset","setWidth","initialAffixTop","offsetParent","match","getRequiredAffixClass","unpin","position","top","scrollTop","getScrollTop","scrollHeight","getScrollHeight","targetEl","pageYOffset","directive","parent","target","initialOffsetTop","offsetBottom","affixed","init","i","$parseOffsets","on","checkPosition","require","checkPositionWithEventLoop","dimensions","offset","destroy","style","width","off","affix","setTimeout","elementHeight","height","css","addClass","offsetUnpin","offsetHeight","offsetWidth","$debouncedOnResize","$onResize","initialPosition","restrict","affixTarget","$element","option","$on","attr","test","animation","prefixClass","container","provider","backdrop","keyboard","show","duration","type","dismissable","AlertFactory","$alert","$scope","config","$timeout","hide","isDefined","falseValueRegExp","hasOwnProperty","title","newValue","oldValue","trustAsHtml","bsAlert","$observe","content","alert","trigger","toggle","AsideFactory","$aside","requestAnimationFrame","$modal","bsAside","$watch","aside","activeClass","querySelectorAll","childEl","ngModel","child","$button","constantValueRegExp","isInput","trueValue","falseValue","hasExoticValues","viewValue","$formatters","push","$render","modelValue","isActive","equals","checked","activeElement","bind","toggleEvent","$modelValue","$$rAF","$setViewValue","toggleClass","$apply","hasClass","nodeName","self","startCollapsed","allowMultiple","$attrs","activeIndexes","$targets","$active","length","index","indexOf","activeItems","splice","activateItem","$options","$collapse","$viewChangeListeners","$registerToggle","$toggles","$unregisterToggle","$unregisterTarget","deactivateItem","fn","fixActiveItemIndexes","$setActive","disallowToggle","$activeIndexes","bsCollapseCtrl","controllers","$animate","ngModelCtrl","attrs","isArray","bsCollapseToggle","$registerTarget","render","active","action","delay","useNative","dateType","dateFormat","timezone","modelDateFormat","dayFormat","monthFormat","yearFormat","monthTitleFormat","yearTitleFormat","strictFormat","autoclose","minDate","Infinity","maxDate","startView","minView","startWeek","daysOfWeekDisabled","iconLeft","iconRight","isNative","DatepickerFactory","parentScope","$datepicker","pickerViews","views","el","selected","date","focus","viewDate","$iconLeft","$iconRight","$picker","$views","$mode","datepickerViews","$selectPane","$toggleMode","setMode","select","isDate","$build","updateDisabledDates","disabledDateRanges","dateRanges","$date","$dateValue","keep","Date","year","getFullYear","month","getDate","mode","pristine","call","$updateSelected","rows","built","$isSelected","$setDisabledEl","disabled","isDisabled","steps","targetDate","getUTCFullYear","getUTCMonth","UTC","$onMouseDown","evt","preventDefault","stopPropagation","isTouch","getUTCDate","$onKeyDown","keyCode","shiftKey","altKey","updateSelected","onKeyDown","$digest","prop","focusElement","_init","_destroy","_show","_hide","blur","navigator","userAgent","previousValue","normalizeDateRanges","ranges","disabledRanges","datepicker","isMaxValid","isValid","isMinValid","isNaN","parsedDate","getTime","$parsers","unshift","$setValidity","getDateFormattedString","formatDate","bsShow","lang","format","$dateFormatter","dateParser","$dateParser","strict","validateAgainstMinMaxDate","getDateForAttribute","disabledDates","parse","timezoneOffsetAdjust","isUndefined","NaN","daySplit","arr","mod","n","m","arrays","size","$sce","weekDaysMin","weekdaysShort","weekDaysLabelsHtml","startDate","picker","weekDaysLabels","slice","concat","split","getMonth","update","firstDayOfMonth","firstDate","getDay","today","firstDateOffset","build","day","days","isToday","toDateString","label","muted","showLabels","labels","time","isSelected","newDate","name","firstMonth","months","lastDate","actualMonth","parseInt","firstYear","years","actualYear","setYear","placement","matchesSelector","DropdownFactory","$dropdown","onBodyClick","items","$rootScope","$new","parentEl","$isShown","removeClass","prototype","transclusion","bsDropdown","dropdown","service","splitTimeFormat","timeFormat","exec","DATETIME_FORMATS","id","getDatetimeFormat","SHORTDAY","hoursFormat","minutesFormat","secondsFormat","timeSeparator","showSeconds","dateFilter","ParseDate","seconds","$localeProvider","milliseconds","hours","array","isNumeric","parseFloat","isFinite","indexOfCaseInsensitive","len","str","toString","toLowerCase","DateParserFactory","minutes","getHours","getMilliseconds","getMinutes","proto","noop","toDate","regExpMap","sss","mm","keys","setFnMap","map","clonedFormat","search","v","sortedMap","regExpForFormat","re","join","text","Object","escapeReservedSymbols","RegExp","regex","HH","H","hh","h","a","EEEE","EEE","dd","d","MMMM","MMM","SHORTMONTH","MM","M","DAY","yyyy","yy","y","MONTH","ss","setSeconds","s","setMinutes","setHours","setDate","setMonth","setFullYear","setMap","$format","setMapForFormat","baseDate","formatRegex","formatSetMap","matches","fromDate","substr","getTimeForAttribute","daylightSavingAdjust","undo","func","timeout","context","factory","immediate","args","cancel","callNow","leading","trailing","wait","currentStyle","getComputedStyle","extra","boxRect","getBoundingClientRect","left","docElement","ownerDocument","curPosition","curLeft","curCSSTop","documentElement","clientTop","pageXOffset","scrollLeft","clientLeft","curCSSLeft","calculatePosition","curTop","curOffset","curElem","props","isFunction","using","offsetParentRect","offsetParentElement","outer","$parseOptions","$values","regexp","$match","displayFn","valueName","valueFn","ParseOptionsFactory","groupByFn","valuesFn","$parse","keyName","cancelAnimationFrame","values","displayValue","raf","webkitRequestAnimationFrame","mozRequestAnimationFrame","rafSupported","timer","prefixEvent","bodyElement","ModalFactory","enterAnimateCallback","version","minor","modalElement","unbindBackdropEvents","hideOnBackdropClick","backdropElement","preventEventDefault","bindKeyboardEvents","$onKeyUp","destroyModalElement","modalScope","$destroy","promise","$hide","$$postDigest","$id","$show","bottom","right","z-index","compileData","after","isElement","$emit","display","clonedElement","defaultPrevented","enter","backdropAnimation","safeDigest","bindBackdropEvents","leave","leaveAnimateCallback","unbindKeyboardEvents","which","$root","$$phase","query","bsModal","modal","routeAttr","$navbar","liElements","li","liElement","pattern","path","autoClose","$popover","PopoverFactory","$tooltip","dataTarget","popover","bsPopover","$applyPlacement","setViewport","viewport","spies","$document","debounce","throttle","ScrollSpyFactory","scrollEl","isWindowSpy","scrollId","$$count","$scrollspy","unbindViewContentLoaded","unbindIncludeContentLoaded","trackedElements","$trackedElements","sortedElements","activeTarget","debouncedCheckPosition","viewportHeight","throttledCheckPosition","debouncedCheckOffsets","checkOffsets","docEl","$activateElement","source","$getTrackedElement","filter","targetElement","querySelector","trackedElement","b","trackElement","toDelete","untrackElement","activate","scrollspy","multiple","allNoneButtons","sort","caretHtml","placeholder","allText","noneText","maxLength","maxLengthHtml","iconCheckmark","SelectFactory","$select","$activeIndex","$isMultiple","$showAllNoneButtons","$allText","$iconCheckmark","$isActive","$isVisible","$selectNone","$matches","$updateActiveIndex","$getIndex","minLength","$viewValue","l","dataMultiple","inputEl","watchedOptions","$watchCollection","parsedOptions","bsOptions","$isEmpty","timeType","modelTimeFormat","minTime","maxTime","hourStep","minuteStep","secondStep","roundDisplay","iconUp","iconDown","arrowBehavior","$timepicker","timepickerFactory","hour","meridian","coeff","selRange","end","start","setSelectionRange","collapse","selectionStart","moveStart","selectionEnd","moveEnd","floorMinutes","floor","selectedIndex","defaultDate","second","getSeconds","millisecond","$iconUp","$iconDown","$moveIndex","$switchMeridian","switchMeridian","minute","midIndex","$isDisabled","showAM","isAM","selectedTime","$arrowAction","$setTimeByStep","triggerHandler","sepLength","lateralMove","count","minutesLength","selectRange","hoursLength","incr","isSeconds","isMeridian","secondsLength","createSelection","createTextRange","parsedTime","getTimeFormattedString","timepicker","validateAgainstMinMaxTime","navClass","$activeClass","$panes","$activePaneChangeListeners","$push","pane","$navClass","$remove","activeIndex","$pane","$tab","transclude","postLink","bsTabsCtrl","bsActivePane","parsedBsActivePane","assign","limit","autoSelect","comparator","trimValue","$typeahead","$resetMatches","TypeaheadFactory","$filter","expression","results","typeahead","watchOptions","selectMode","isVisible","val","bsEnabled","selector","padding","String","htmlReplaceRegExp","$body","_tipToHide","tipElement","triggers","unbindTriggerEvents","$onFocusElementMouseDown","_autoCloseEventsBinded","bindAutoCloseEvents","unbindAutoCloseEvents","stopEventPropagation","event","getPosition","rect","elRect","p","scroll","isBody","getCalculatedOffset","actualWidth","actualHeight","outerDims","clientWidth","innerHeight","tip","marginTop","marginLeft","setOffset","delta","getViewportAdjustedDelta","isVertical","replaceArrow","arrowDelta","arrowOffsetPosition","viewportDimensions","$viewport","topEdgeOffset","bottomEdgeOffset","viewportPadding","leftEdgeOffset","rightEdgeOffset","dimension","isHorizontal","$arrow","clearTimeout","tipScope","$promise","$bsCompiler","$setEnabled","setEnabled","isEnabled","tipContainer","bindTriggerEvents","destroyTipElement","hoverState","lastChild","visibility","customClass","_blur","elementPosition","autoPlace","autoToken","viewportPosition","originalPlacement","tipHeight","tipPosition","applyPlacement","tipWidth","$location","tooltip","bsTooltip"],"mappings":"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","file":"angular-strap.min.js","sourcesContent":["(function(window, document, undefined) {\n'use strict';\n\n// Source: module.js\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]);\n\n// Source: affix/affix.js\nangular.module('mgcrea.ngStrap.affix', ['mgcrea.ngStrap.helpers.dimensions', 'mgcrea.ngStrap.helpers.debounce'])\n\n .provider('$affix', function() {\n\n var defaults = this.defaults = {\n offsetTop: 'auto',\n inlineStyles: true\n };\n\n this.$get = function($window, debounce, dimensions) {\n\n var bodyEl = angular.element($window.document.body);\n var windowEl = angular.element($window);\n\n function AffixFactory(element, config) {\n\n var $affix = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n var targetEl = options.target;\n\n // Initial private vars\n var reset = 'affix affix-top affix-bottom',\n setWidth = false,\n initialAffixTop = 0,\n initialOffsetTop = 0,\n offsetTop = 0,\n offsetBottom = 0,\n affixed = null,\n unpin = null;\n\n var parent = element.parent();\n // Options: custom parent\n if (options.offsetParent) {\n if (options.offsetParent.match(/^\\d+$/)) {\n for (var i = 0; i < (options.offsetParent * 1) - 1; i++) {\n parent = parent.parent();\n }\n }\n else {\n parent = angular.element(options.offsetParent);\n }\n }\n\n $affix.init = function() {\n\n this.$parseOffsets();\n initialOffsetTop = dimensions.offset(element[0]).top + initialAffixTop;\n setWidth = !element[0].style.width;\n\n // Bind events\n targetEl.on('scroll', this.checkPosition);\n targetEl.on('click', this.checkPositionWithEventLoop);\n windowEl.on('resize', this.$debouncedOnResize);\n\n // Both of these checkPosition() calls are necessary for the case where\n // the user hits refresh after scrolling to the bottom of the page.\n this.checkPosition();\n this.checkPositionWithEventLoop();\n\n };\n\n $affix.destroy = function() {\n\n // Unbind events\n targetEl.off('scroll', this.checkPosition);\n targetEl.off('click', this.checkPositionWithEventLoop);\n windowEl.off('resize', this.$debouncedOnResize);\n\n };\n\n $affix.checkPositionWithEventLoop = function() {\n\n // IE 9 throws an error if we use 'this' instead of '$affix'\n // in this setTimeout call\n setTimeout($affix.checkPosition, 1);\n\n };\n\n $affix.checkPosition = function() {\n // if (!this.$element.is(':visible')) return\n\n var scrollTop = getScrollTop();\n var position = dimensions.offset(element[0]);\n var elementHeight = dimensions.height(element[0]);\n\n // Get required affix class according to position\n var affix = getRequiredAffixClass(unpin, position, elementHeight);\n\n // Did affix status changed this last check?\n if(affixed === affix) return;\n affixed = affix;\n\n // Add proper affix class\n element.removeClass(reset).addClass('affix' + ((affix !== 'middle') ? '-' + affix : ''));\n\n if(affix === 'top') {\n unpin = null;\n if(setWidth) {\n element.css('width', '');\n }\n if (options.inlineStyles) {\n element.css('position', (options.offsetParent) ? '' : 'relative');\n element.css('top', '');\n }\n } else if(affix === 'bottom') {\n if (options.offsetUnpin) {\n unpin = -(options.offsetUnpin * 1);\n }\n else {\n // Calculate unpin threshold when affixed to bottom.\n // Hopefully the browser scrolls pixel by pixel.\n unpin = position.top - scrollTop;\n }\n if(setWidth) {\n element.css('width', '');\n }\n if (options.inlineStyles) {\n element.css('position', (options.offsetParent) ? '' : 'relative');\n element.css('top', (options.offsetParent) ? '' : ((bodyEl[0].offsetHeight - offsetBottom - elementHeight - initialOffsetTop) + 'px'));\n }\n } else { // affix === 'middle'\n unpin = null;\n if(setWidth) {\n element.css('width', element[0].offsetWidth + 'px');\n }\n if (options.inlineStyles) {\n element.css('position', 'fixed');\n element.css('top', initialAffixTop + 'px');\n }\n }\n\n };\n\n $affix.$onResize = function() {\n $affix.$parseOffsets();\n $affix.checkPosition();\n };\n $affix.$debouncedOnResize = debounce($affix.$onResize, 50);\n\n $affix.$parseOffsets = function() {\n var initialPosition = element.css('position');\n // Reset position to calculate correct offsetTop\n if (options.inlineStyles){\n element.css('position', (options.offsetParent) ? '' : 'relative');\n }\n\n if(options.offsetTop) {\n if(options.offsetTop === 'auto') {\n options.offsetTop = '+0';\n }\n if(options.offsetTop.match(/^[-+]\\d+$/)) {\n initialAffixTop = - options.offsetTop * 1;\n if(options.offsetParent) {\n offsetTop = dimensions.offset(parent[0]).top + (options.offsetTop * 1);\n }\n else {\n offsetTop = dimensions.offset(element[0]).top - dimensions.css(element[0], 'marginTop', true) + (options.offsetTop * 1);\n }\n }\n else {\n offsetTop = options.offsetTop * 1;\n }\n }\n\n if(options.offsetBottom) {\n if(options.offsetParent && options.offsetBottom.match(/^[-+]\\d+$/)) {\n // add 1 pixel due to rounding problems...\n offsetBottom = getScrollHeight() - (dimensions.offset(parent[0]).top + dimensions.height(parent[0])) + (options.offsetBottom * 1) + 1;\n }\n else {\n offsetBottom = options.offsetBottom * 1;\n }\n }\n\n // Bring back the element's position after calculations\n if (options.inlineStyles){\n element.css('position', initialPosition);\n }\n };\n\n // Private methods\n\n function getRequiredAffixClass(unpin, position, elementHeight) {\n\n var scrollTop = getScrollTop();\n var scrollHeight = getScrollHeight();\n\n if(scrollTop <= offsetTop) {\n return 'top';\n } else if(unpin !== null && (scrollTop + unpin <= position.top)) {\n return 'middle';\n } else if(offsetBottom !== null && (position.top + elementHeight + initialAffixTop >= scrollHeight - offsetBottom)) {\n return 'bottom';\n } else {\n return 'middle';\n }\n\n }\n\n function getScrollTop() {\n return targetEl[0] === $window ? $window.pageYOffset : targetEl[0].scrollTop;\n }\n\n function getScrollHeight() {\n return targetEl[0] === $window ? $window.document.body.scrollHeight : targetEl[0].scrollHeight;\n }\n\n $affix.init();\n return $affix;\n\n }\n\n return AffixFactory;\n\n };\n\n })\n\n .directive('bsAffix', function($affix, $window) {\n\n return {\n restrict: 'EAC',\n require: '^?bsAffixTarget',\n link: function postLink(scope, element, attr, affixTarget) {\n\n var options = {scope: scope, target: affixTarget ? affixTarget.$element : angular.element($window)};\n angular.forEach(['offsetTop', 'offsetBottom', 'offsetParent', 'offsetUnpin', 'inlineStyles'], function(key) {\n if(angular.isDefined(attr[key])) {\n var option = attr[key];\n if (/true/i.test(option)) option = true;\n if (/false/i.test(option)) option = false;\n options[key] = option;\n }\n });\n\n var affix = $affix(element, options);\n scope.$on('$destroy', function() {\n affix && affix.destroy();\n options = null;\n affix = null;\n });\n\n }\n };\n\n })\n\n .directive('bsAffixTarget', function() {\n return {\n controller: function($element) {\n this.$element = $element;\n }\n };\n });\n\n// Source: alert/alert.js\n// @BUG: following snippet won't compile correctly\n// @TODO: submit issue to core\n// ' ' +\n\nangular.module('mgcrea.ngStrap.alert', ['mgcrea.ngStrap.modal'])\n\n .provider('$alert', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'alert',\n prefixEvent: 'alert',\n placement: null,\n templateUrl: 'alert/alert.tpl.html',\n container: false,\n element: null,\n backdrop: false,\n keyboard: true,\n show: true,\n // Specific options\n duration: false,\n type: false,\n dismissable: true\n };\n\n this.$get = function($modal, $timeout) {\n\n function AlertFactory(config) {\n\n var $alert = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $alert = $modal(options);\n\n // Support scope as string options [/*title, content, */ type, dismissable]\n $alert.$scope.dismissable = !!options.dismissable;\n if(options.type) {\n $alert.$scope.type = options.type;\n }\n\n // Support auto-close duration\n var show = $alert.show;\n if(options.duration) {\n $alert.show = function() {\n show();\n $timeout(function() {\n $alert.hide();\n }, options.duration * 1000);\n };\n }\n\n return $alert;\n\n }\n\n return AlertFactory;\n\n };\n\n })\n\n .directive('bsAlert', function($window, $sce, $alert) {\n\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope, element: element, show: false};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'keyboard', 'html', 'container', 'animation', 'duration', 'dismissable'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['keyboard', 'html', 'container', 'dismissable'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // overwrite inherited title value when no value specified\n // fix for angular 1.3.1 531a8de72c439d8ddd064874bf364c00cedabb11\n if (!scope.hasOwnProperty('title')){\n scope.title = '';\n }\n\n // Support scope as data-attrs\n angular.forEach(['title', 'content', 'type'], function(key) {\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\n scope[key] = $sce.trustAsHtml(newValue);\n });\n });\n\n // Support scope as an object\n attr.bsAlert && scope.$watch(attr.bsAlert, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.content = newValue;\n }\n }, true);\n\n // Initialize alert\n var alert = $alert(options);\n\n // Trigger\n element.on(attr.trigger || 'click', alert.toggle);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (alert) alert.destroy();\n options = null;\n alert = null;\n });\n\n }\n };\n\n });\n\n// Source: aside/aside.js\nangular.module('mgcrea.ngStrap.aside', ['mgcrea.ngStrap.modal'])\n\n .provider('$aside', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade-and-slide-right',\n prefixClass: 'aside',\n prefixEvent: 'aside',\n placement: 'right',\n templateUrl: 'aside/aside.tpl.html',\n contentTemplate: false,\n container: false,\n element: null,\n backdrop: true,\n keyboard: true,\n html: false,\n show: true\n };\n\n this.$get = function($modal) {\n\n function AsideFactory(config) {\n\n var $aside = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $aside = $modal(options);\n\n return $aside;\n\n }\n\n return AsideFactory;\n\n };\n\n })\n\n .directive('bsAside', function($window, $sce, $aside) {\n\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n // Directive options\n var options = {scope: scope, element: element, show: false};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['backdrop', 'keyboard', 'html', 'container'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Support scope as data-attrs\n angular.forEach(['title', 'content'], function(key) {\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\n scope[key] = $sce.trustAsHtml(newValue);\n });\n });\n\n // Support scope as an object\n attr.bsAside && scope.$watch(attr.bsAside, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.content = newValue;\n }\n }, true);\n\n // Initialize aside\n var aside = $aside(options);\n\n // Trigger\n element.on(attr.trigger || 'click', aside.toggle);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (aside) aside.destroy();\n options = null;\n aside = null;\n });\n\n }\n };\n\n });\n\n// Source: button/button.js\nangular.module('mgcrea.ngStrap.button', [])\n\n .provider('$button', function() {\n\n var defaults = this.defaults = {\n activeClass:'active',\n toggleEvent:'click'\n };\n\n this.$get = function() {\n return {defaults: defaults};\n };\n\n })\n\n .directive('bsCheckboxGroup', function() {\n\n return {\n restrict: 'A',\n require: 'ngModel',\n compile: function postLink(element, attr) {\n element.attr('data-toggle', 'buttons');\n element.removeAttr('ng-model');\n var children = element[0].querySelectorAll('input[type=\"checkbox\"]');\n angular.forEach(children, function(child) {\n var childEl = angular.element(child);\n childEl.attr('bs-checkbox', '');\n childEl.attr('ng-model', attr.ngModel + '.' + childEl.attr('value'));\n });\n }\n\n };\n\n })\n\n .directive('bsCheckbox', function($button, $$rAF) {\n\n var defaults = $button.defaults;\n var constantValueRegExp = /^(true|false|\\d+)$/;\n\n return {\n restrict: 'A',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n var options = defaults;\n\n // Support label > input[type=\"checkbox\"]\n var isInput = element[0].nodeName === 'INPUT';\n var activeElement = isInput ? element.parent() : element;\n\n var trueValue = angular.isDefined(attr.trueValue) ? attr.trueValue : true;\n if(constantValueRegExp.test(attr.trueValue)) {\n trueValue = scope.$eval(attr.trueValue);\n }\n var falseValue = angular.isDefined(attr.falseValue) ? attr.falseValue : false;\n if(constantValueRegExp.test(attr.falseValue)) {\n falseValue = scope.$eval(attr.falseValue);\n }\n\n // Parse exotic values\n var hasExoticValues = typeof trueValue !== 'boolean' || typeof falseValue !== 'boolean';\n if(hasExoticValues) {\n controller.$parsers.push(function(viewValue) {\n // console.warn('$parser', element.attr('ng-model'), 'viewValue', viewValue);\n return viewValue ? trueValue : falseValue;\n });\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n return angular.equals(modelValue, trueValue);\n });\n // Fix rendering for exotic values\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n controller.$render();\n });\n }\n\n // model -> view\n controller.$render = function () {\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n var isActive = angular.equals(controller.$modelValue, trueValue);\n $$rAF(function() {\n if(isInput) element[0].checked = isActive;\n activeElement.toggleClass(options.activeClass, isActive);\n });\n };\n\n // view -> model\n element.bind(options.toggleEvent, function() {\n scope.$apply(function () {\n // console.warn('!click', element.attr('ng-model'), 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue, 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue);\n if(!isInput) {\n controller.$setViewValue(!activeElement.hasClass('active'));\n }\n if(!hasExoticValues) {\n controller.$render();\n }\n });\n });\n\n }\n\n };\n\n })\n\n .directive('bsRadioGroup', function() {\n\n return {\n restrict: 'A',\n require: 'ngModel',\n compile: function postLink(element, attr) {\n element.attr('data-toggle', 'buttons');\n element.removeAttr('ng-model');\n var children = element[0].querySelectorAll('input[type=\"radio\"]');\n angular.forEach(children, function(child) {\n angular.element(child).attr('bs-radio', '');\n angular.element(child).attr('ng-model', attr.ngModel);\n });\n }\n\n };\n\n })\n\n .directive('bsRadio', function($button, $$rAF) {\n\n var defaults = $button.defaults;\n var constantValueRegExp = /^(true|false|\\d+)$/;\n\n return {\n restrict: 'A',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n var options = defaults;\n\n // Support `label > input[type=\"radio\"]` markup\n var isInput = element[0].nodeName === 'INPUT';\n var activeElement = isInput ? element.parent() : element;\n\n var value;\n attr.$observe('value', function(v) {\n value = constantValueRegExp.test(v) ? scope.$eval(v) : v;\n controller.$render();\n });\n\n // model -> view\n controller.$render = function () {\n // console.warn('$render', element.attr('value'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n var isActive = angular.equals(controller.$modelValue, value);\n $$rAF(function() {\n if(isInput) element[0].checked = isActive;\n activeElement.toggleClass(options.activeClass, isActive);\n });\n };\n\n // view -> model\n element.bind(options.toggleEvent, function() {\n scope.$apply(function () {\n // console.warn('!click', element.attr('value'), 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue, 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue);\n controller.$setViewValue(value);\n controller.$render();\n });\n });\n\n }\n\n };\n\n });\n\n// Source: collapse/collapse.js\nangular.module('mgcrea.ngStrap.collapse', [])\n\n .provider('$collapse', function() {\n\n var defaults = this.defaults = {\n animation: 'am-collapse',\n disallowToggle: false,\n activeClass: 'in',\n startCollapsed: false,\n allowMultiple: false\n };\n\n var controller = this.controller = function($scope, $element, $attrs) {\n var self = this;\n\n // Attributes options\n self.$options = angular.copy(defaults);\n angular.forEach(['animation', 'disallowToggle', 'activeClass', 'startCollapsed', 'allowMultiple'], function (key) {\n if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['disallowToggle', 'startCollapsed', 'allowMultiple'], function(key) {\n if(angular.isDefined($attrs[key]) && falseValueRegExp.test($attrs[key])) {\n self.$options[key] = false;\n }\n });\n\n self.$toggles = [];\n self.$targets = [];\n\n self.$viewChangeListeners = [];\n\n self.$registerToggle = function(element) {\n self.$toggles.push(element);\n };\n self.$registerTarget = function(element) {\n self.$targets.push(element);\n };\n\n self.$unregisterToggle = function(element) {\n var index = self.$toggles.indexOf(element);\n // remove toggle from $toggles array\n self.$toggles.splice(index, 1);\n };\n self.$unregisterTarget = function(element) {\n var index = self.$targets.indexOf(element);\n\n // remove element from $targets array\n self.$targets.splice(index, 1);\n\n if (self.$options.allowMultiple) {\n // remove target index from $active array values\n deactivateItem(element);\n }\n\n // fix active item indexes\n fixActiveItemIndexes(index);\n\n self.$viewChangeListeners.forEach(function(fn) {\n fn();\n });\n };\n\n // use array to store all the currently open panels\n self.$targets.$active = !self.$options.startCollapsed ? [0] : [];\n self.$setActive = $scope.$setActive = function(value) {\n if(angular.isArray(value)) {\n self.$targets.$active = value;\n }\n else if(!self.$options.disallowToggle) {\n // toogle element active status\n isActive(value) ? deactivateItem(value) : activateItem(value);\n } else {\n activateItem(value);\n }\n\n self.$viewChangeListeners.forEach(function(fn) {\n fn();\n });\n };\n\n self.$activeIndexes = function() {\n return self.$options.allowMultiple ? self.$targets.$active :\n self.$targets.$active.length === 1 ? self.$targets.$active[0] : -1;\n };\n\n function fixActiveItemIndexes(index) {\n // item with index was removed, so we\n // need to adjust other items index values\n var activeIndexes = self.$targets.$active;\n for(var i = 0; i < activeIndexes.length; i++) {\n if (index < activeIndexes[i]) {\n activeIndexes[i] = activeIndexes[i] - 1;\n }\n\n // the last item is active, so we need to\n // adjust its index\n if (activeIndexes[i] === self.$targets.length) {\n activeIndexes[i] = self.$targets.length - 1;\n }\n }\n }\n\n function isActive(value) {\n var activeItems = self.$targets.$active;\n return activeItems.indexOf(value) === -1 ? false : true;\n }\n\n function deactivateItem(value) {\n var index = self.$targets.$active.indexOf(value);\n if (index !== -1) {\n self.$targets.$active.splice(index, 1);\n }\n }\n\n function activateItem(value) {\n if (!self.$options.allowMultiple) {\n // remove current selected item\n self.$targets.$active.splice(0, 1);\n }\n\n if (self.$targets.$active.indexOf(value) === -1) {\n self.$targets.$active.push(value);\n }\n }\n\n };\n\n this.$get = function() {\n var $collapse = {};\n $collapse.defaults = defaults;\n $collapse.controller = controller;\n return $collapse;\n };\n\n })\n\n .directive('bsCollapse', function($window, $animate, $collapse) {\n\n var defaults = $collapse.defaults;\n\n return {\n require: ['?ngModel', 'bsCollapse'],\n controller: ['$scope', '$element', '$attrs', $collapse.controller],\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsCollapseCtrl = controllers[1];\n\n if(ngModelCtrl) {\n\n // Update the modelValue following\n bsCollapseCtrl.$viewChangeListeners.push(function() {\n ngModelCtrl.$setViewValue(bsCollapseCtrl.$activeIndexes());\n });\n\n // modelValue -> $formatters -> viewValue\n ngModelCtrl.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n if (angular.isArray(modelValue)) {\n // model value is an array, so just replace\n // the active items directly\n bsCollapseCtrl.$setActive(modelValue);\n }\n else {\n var activeIndexes = bsCollapseCtrl.$activeIndexes();\n\n if (angular.isArray(activeIndexes)) {\n // we have an array of selected indexes\n if (activeIndexes.indexOf(modelValue * 1) === -1) {\n // item with modelValue index is not active\n bsCollapseCtrl.$setActive(modelValue * 1);\n }\n }\n else if (activeIndexes !== modelValue * 1) {\n bsCollapseCtrl.$setActive(modelValue * 1);\n }\n }\n return modelValue;\n });\n\n }\n\n }\n };\n\n })\n\n .directive('bsCollapseToggle', function() {\n\n return {\n require: ['^?ngModel', '^bsCollapse'],\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsCollapseCtrl = controllers[1];\n\n // Add base attr\n element.attr('data-toggle', 'collapse');\n\n // Push pane to parent bsCollapse controller\n bsCollapseCtrl.$registerToggle(element);\n\n // remove toggle from collapse controller when toggle is destroyed\n scope.$on('$destroy', function() {\n bsCollapseCtrl.$unregisterToggle(element);\n });\n\n element.on('click', function() {\n var index = attrs.bsCollapseToggle && attrs.bsCollapseToggle !== 'bs-collapse-toggle' ? attrs.bsCollapseToggle : bsCollapseCtrl.$toggles.indexOf(element);\n bsCollapseCtrl.$setActive(index * 1);\n scope.$apply();\n });\n\n }\n };\n\n })\n\n .directive('bsCollapseTarget', function($animate) {\n\n return {\n require: ['^?ngModel', '^bsCollapse'],\n // scope: true,\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsCollapseCtrl = controllers[1];\n\n // Add base class\n element.addClass('collapse');\n\n // Add animation class\n if(bsCollapseCtrl.$options.animation) {\n element.addClass(bsCollapseCtrl.$options.animation);\n }\n\n // Push pane to parent bsCollapse controller\n bsCollapseCtrl.$registerTarget(element);\n\n // remove pane target from collapse controller when target is destroyed\n scope.$on('$destroy', function() {\n bsCollapseCtrl.$unregisterTarget(element);\n });\n\n function render() {\n var index = bsCollapseCtrl.$targets.indexOf(element);\n var active = bsCollapseCtrl.$activeIndexes();\n var action = 'removeClass';\n if (angular.isArray(active)) {\n if (active.indexOf(index) !== -1) {\n action = 'addClass';\n }\n }\n else if (index === active) {\n action = 'addClass';\n }\n\n $animate[action](element, bsCollapseCtrl.$options.activeClass);\n }\n\n bsCollapseCtrl.$viewChangeListeners.push(function() {\n render();\n });\n render();\n\n }\n };\n\n });\n\n// Source: datepicker/datepicker.js\nangular.module('mgcrea.ngStrap.datepicker', [\n 'mgcrea.ngStrap.helpers.dateParser',\n 'mgcrea.ngStrap.helpers.dateFormatter',\n 'mgcrea.ngStrap.tooltip'])\n\n .provider('$datepicker', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n //uncommenting the following line will break backwards compatability\n // prefixEvent: 'datepicker',\n prefixClass: 'datepicker',\n placement: 'bottom-left',\n templateUrl: 'datepicker/datepicker.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n // lang: $locale.id,\n useNative: false,\n dateType: 'date',\n dateFormat: 'shortDate',\n timezone: null,\n modelDateFormat: null,\n dayFormat: 'dd',\n monthFormat: 'MMM',\n yearFormat: 'yyyy',\n monthTitleFormat: 'MMMM yyyy',\n yearTitleFormat: 'yyyy',\n strictFormat: false,\n autoclose: false,\n minDate: -Infinity,\n maxDate: +Infinity,\n startView: 0,\n minView: 0,\n startWeek: 0,\n daysOfWeekDisabled: '',\n iconLeft: 'glyphicon glyphicon-chevron-left',\n iconRight: 'glyphicon glyphicon-chevron-right'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, datepickerViews, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\n\n function DatepickerFactory(element, controller, config) {\n\n var $datepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $datepicker.$options;\n var scope = $datepicker.$scope;\n if(options.startView) options.startView -= options.minView;\n\n // View vars\n\n var pickerViews = datepickerViews($datepicker);\n $datepicker.$views = pickerViews.views;\n var viewDate = pickerViews.viewDate;\n scope.$mode = options.startView;\n scope.$iconLeft = options.iconLeft;\n scope.$iconRight = options.iconRight;\n var $picker = $datepicker.$views[scope.$mode];\n\n // Scope methods\n\n scope.$select = function(date) {\n $datepicker.select(date);\n };\n scope.$selectPane = function(value) {\n $datepicker.$selectPane(value);\n };\n scope.$toggleMode = function() {\n $datepicker.setMode((scope.$mode + 1) % $datepicker.$views.length);\n };\n\n // Public methods\n\n $datepicker.update = function(date) {\n // console.warn('$datepicker.update() newValue=%o', date);\n if(angular.isDate(date) && !isNaN(date.getTime())) {\n $datepicker.$date = date;\n $picker.update.call($picker, date);\n }\n // Build only if pristine\n $datepicker.$build(true);\n };\n\n $datepicker.updateDisabledDates = function(dateRanges) {\n options.disabledDateRanges = dateRanges;\n for(var i = 0, l = scope.rows.length; i < l; i++) {\n angular.forEach(scope.rows[i], $datepicker.$setDisabledEl);\n }\n };\n\n $datepicker.select = function(date, keep) {\n // console.warn('$datepicker.select', date, scope.$mode);\n if(!angular.isDate(controller.$dateValue)) controller.$dateValue = new Date(date);\n if(!scope.$mode || keep) {\n controller.$setViewValue(angular.copy(date));\n controller.$render();\n if(options.autoclose && !keep) {\n $timeout(function() { $datepicker.hide(true); });\n }\n } else {\n angular.extend(viewDate, {year: date.getFullYear(), month: date.getMonth(), date: date.getDate()});\n $datepicker.setMode(scope.$mode - 1);\n $datepicker.$build();\n }\n };\n\n $datepicker.setMode = function(mode) {\n // console.warn('$datepicker.setMode', mode);\n scope.$mode = mode;\n $picker = $datepicker.$views[scope.$mode];\n $datepicker.$build();\n };\n\n // Protected methods\n\n $datepicker.$build = function(pristine) {\n // console.warn('$datepicker.$build() viewDate=%o', viewDate);\n if(pristine === true && $picker.built) return;\n if(pristine === false && !$picker.built) return;\n $picker.build.call($picker);\n };\n\n $datepicker.$updateSelected = function() {\n for(var i = 0, l = scope.rows.length; i < l; i++) {\n angular.forEach(scope.rows[i], updateSelected);\n }\n };\n\n $datepicker.$isSelected = function(date) {\n return $picker.isSelected(date);\n };\n\n $datepicker.$setDisabledEl = function(el) {\n el.disabled = $picker.isDisabled(el.date);\n };\n\n $datepicker.$selectPane = function(value) {\n var steps = $picker.steps;\n // set targetDate to first day of month to avoid problems with\n // date values rollover. This assumes the viewDate does not\n // depend on the day of the month\n var targetDate = new Date(Date.UTC(viewDate.year + ((steps.year || 0) * value), viewDate.month + ((steps.month || 0) * value), 1));\n angular.extend(viewDate, {year: targetDate.getUTCFullYear(), month: targetDate.getUTCMonth(), date: targetDate.getUTCDate()});\n $datepicker.$build();\n };\n\n $datepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $datepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n if(evt.keyCode === 13) {\n if(!scope.$mode) {\n return $datepicker.hide(true);\n } else {\n return scope.$apply(function() { $datepicker.setMode(scope.$mode - 1); });\n }\n }\n\n // Navigate with keyboard\n $picker.onKeyDown(evt);\n parentScope.$digest();\n };\n\n // Private\n\n function updateSelected(el) {\n el.selected = $datepicker.$isSelected(el.date);\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $datepicker.init;\n $datepicker.init = function() {\n if(isNative && options.useNative) {\n element.prop('type', 'date');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if(isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $datepicker.destroy;\n $datepicker.destroy = function() {\n if(isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $datepicker.show;\n $datepicker.show = function() {\n if((!isTouch && element.attr('readonly')) || element.attr('disabled')) return;\n _show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n // if $datepicker is no longer showing, don't setup events\n if(!$datepicker.$isShown) return;\n $datepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $datepicker.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $datepicker.hide;\n $datepicker.hide = function(blur) {\n if(!$datepicker.$isShown) return;\n $datepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $datepicker.$onKeyDown);\n }\n _hide(blur);\n };\n\n return $datepicker;\n\n }\n\n DatepickerFactory.defaults = defaults;\n return DatepickerFactory;\n\n };\n\n })\n\n .directive('bsDatepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $datepicker) {\n\n var defaults = $datepicker.defaults;\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'autoclose', 'dateType', 'dateFormat', 'timezone', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled', 'id', 'prefixClass', 'prefixEvent'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'autoclose', 'useNative'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!datepicker || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(datepicker),?/i);\n newValue === true ? datepicker.show() : datepicker.hide();\n });\n\n // Initialize datepicker\n var datepicker = $datepicker(element, controller, options);\n options = datepicker.$options;\n // Set expected iOS format\n if(isNative && options.useNative) options.dateFormat = 'yyyy-MM-dd';\n\n var lang = options.lang;\n\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n\n var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});\n\n // Observe attributes for changes\n angular.forEach(['minDate', 'maxDate'], function(key) {\n // console.warn('attr.$observe(%s)', key, attr[key]);\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\n // console.warn('attr.$observe(%s)=%o', key, newValue);\n datepicker.$options[key] = dateParser.getDateForAttribute(key, newValue);\n // Build only if dirty\n !isNaN(datepicker.$options[key]) && datepicker.$build(false);\n validateAgainstMinMaxDate(controller.$dateValue);\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n datepicker.update(controller.$dateValue);\n }, true);\n\n // Normalize undefined/null/empty array,\n // so that we don't treat changing from undefined->null as a change.\n function normalizeDateRanges(ranges) {\n if (!ranges || !ranges.length) return null;\n return ranges;\n }\n\n if (angular.isDefined(attr.disabledDates)) {\n scope.$watch(attr.disabledDates, function(disabledRanges, previousValue) {\n disabledRanges = normalizeDateRanges(disabledRanges);\n previousValue = normalizeDateRanges(previousValue);\n\n if (disabledRanges) {\n datepicker.updateDisabledDates(disabledRanges);\n }\n });\n }\n\n function validateAgainstMinMaxDate(parsedDate) {\n if (!angular.isDate(parsedDate)) return;\n var isMinValid = isNaN(datepicker.$options.minDate) || parsedDate.getTime() >= datepicker.$options.minDate;\n var isMaxValid = isNaN(datepicker.$options.maxDate) || parsedDate.getTime() <= datepicker.$options.maxDate;\n var isValid = isMinValid && isMaxValid;\n controller.$setValidity('date', isValid);\n controller.$setValidity('min', isMinValid);\n controller.$setValidity('max', isMaxValid);\n // Only update the model when we have a valid date\n if(isValid) controller.$dateValue = parsedDate;\n }\n\n // viewValue -> $parsers -> modelValue\n controller.$parsers.unshift(function(viewValue) {\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\n var date;\n // Null values should correctly reset the model value & validity\n if(!viewValue) {\n controller.$setValidity('date', true);\n // BREAKING CHANGE:\n // return null (not undefined) when input value is empty, so angularjs 1.3\n // ngModelController can go ahead and run validators, like ngRequired\n return null;\n }\n var parsedDate = dateParser.parse(viewValue, controller.$dateValue);\n if(!parsedDate || isNaN(parsedDate.getTime())) {\n controller.$setValidity('date', false);\n // return undefined, causes ngModelController to\n // invalidate model value\n return;\n } else {\n validateAgainstMinMaxDate(parsedDate);\n }\n\n if(options.dateType === 'string') {\n date = dateParser.timezoneOffsetAdjust(parsedDate, options.timezone, true);\n return formatDate(date, options.modelDateFormat || options.dateFormat);\n }\n date = dateParser.timezoneOffsetAdjust(controller.$dateValue, options.timezone, true);\n if(options.dateType === 'number') {\n return date.getTime();\n } else if(options.dateType === 'unix') {\n return date.getTime() / 1000;\n } else if(options.dateType === 'iso') {\n return date.toISOString();\n } else {\n return new Date(date);\n }\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var date;\n if(angular.isUndefined(modelValue) || modelValue === null) {\n date = NaN;\n } else if(angular.isDate(modelValue)) {\n date = modelValue;\n } else if(options.dateType === 'string') {\n date = dateParser.parse(modelValue, null, options.modelDateFormat);\n } else if(options.dateType === 'unix') {\n date = new Date(modelValue * 1000);\n } else {\n date = new Date(modelValue);\n }\n // Setup default value?\n // if(isNaN(date.getTime())) {\n // var today = new Date();\n // date = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0, 0);\n // }\n controller.$dateValue = dateParser.timezoneOffsetAdjust(date, options.timezone);\n return getDateFormattedString();\n });\n\n // viewValue -> element\n controller.$render = function() {\n // console.warn('$render(\"%s\"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);\n element.val(getDateFormattedString());\n };\n\n function getDateFormattedString() {\n return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.dateFormat);\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if(datepicker) datepicker.destroy();\n options = null;\n datepicker = null;\n });\n\n }\n };\n\n })\n\n .provider('datepickerViews', function() {\n\n var defaults = this.defaults = {\n dayFormat: 'dd',\n daySplit: 7\n };\n\n // Split array into smaller arrays\n function split(arr, size) {\n var arrays = [];\n while(arr.length > 0) {\n arrays.push(arr.splice(0, size));\n }\n return arrays;\n }\n\n // Modulus operator\n function mod(n, m) {\n return ((n % m) + m) % m;\n }\n\n this.$get = function($dateFormatter, $dateParser, $sce) {\n\n return function(picker) {\n\n var scope = picker.$scope;\n var options = picker.$options;\n\n var lang = options.lang;\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});\n\n var weekDaysMin = $dateFormatter.weekdaysShort(lang);\n var weekDaysLabels = weekDaysMin.slice(options.startWeek).concat(weekDaysMin.slice(0, options.startWeek));\n var weekDaysLabelsHtml = $sce.trustAsHtml('' + weekDaysLabels.join('') + '');\n\n var startDate = picker.$date || (options.startDate ? dateParser.getDateForAttribute('startDate', options.startDate) : new Date());\n var viewDate = {year: startDate.getFullYear(), month: startDate.getMonth(), date: startDate.getDate()};\n\n var views = [{\n format: options.dayFormat,\n split: 7,\n steps: { month: 1 },\n update: function(date, force) {\n if(!this.built || force || date.getFullYear() !== viewDate.year || date.getMonth() !== viewDate.month) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getDate() !== viewDate.date || date.getDate() === 1) {\n // chaging picker current month will cause viewDate.date to be set to first day of the month,\n // in $datepicker.$selectPane, so picker would not update selected day display if\n // user picks first day of the new month.\n // As a workaround, we are always forcing update when picked date is first day of month.\n viewDate.date = picker.$date.getDate();\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstDayOfMonth = new Date(viewDate.year, viewDate.month, 1), firstDayOfMonthOffset = firstDayOfMonth.getTimezoneOffset();\n var firstDate = new Date(+firstDayOfMonth - mod(firstDayOfMonth.getDay() - options.startWeek, 7) * 864e5), firstDateOffset = firstDate.getTimezoneOffset();\n var today = dateParser.timezoneOffsetAdjust(new Date(), options.timezone).toDateString();\n // Handle daylight time switch\n if(firstDateOffset !== firstDayOfMonthOffset) firstDate = new Date(+firstDate + (firstDateOffset - firstDayOfMonthOffset) * 60e3);\n var days = [], day;\n for(var i = 0; i < 42; i++) { // < 7 * 6\n day = dateParser.daylightSavingAdjust(new Date(firstDate.getFullYear(), firstDate.getMonth(), firstDate.getDate() + i));\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)});\n }\n scope.title = formatDate(firstDayOfMonth, options.monthTitleFormat);\n scope.showLabels = true;\n scope.labels = weekDaysLabelsHtml;\n scope.rows = split(days, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth() && date.getDate() === picker.$date.getDate();\n },\n isDisabled: function(date) {\n var time = date.getTime();\n\n // Disabled because of min/max date.\n if (time < options.minDate || time > options.maxDate) return true;\n\n // Disabled due to being a disabled day of the week\n if (options.daysOfWeekDisabled.indexOf(date.getDay()) !== -1) return true;\n\n // Disabled because of disabled date range.\n if (options.disabledDateRanges) {\n for (var i = 0; i < options.disabledDateRanges.length; i++) {\n if (time >= options.disabledDateRanges[i].start && time <= options.disabledDateRanges[i].end) {\n return true;\n }\n }\n }\n\n return false;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualTime = picker.$date.getTime();\n var newDate;\n\n if(evt.keyCode === 37) newDate = new Date(actualTime - 1 * 864e5);\n else if(evt.keyCode === 38) newDate = new Date(actualTime - 7 * 864e5);\n else if(evt.keyCode === 39) newDate = new Date(actualTime + 1 * 864e5);\n else if(evt.keyCode === 40) newDate = new Date(actualTime + 7 * 864e5);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }, {\n name: 'month',\n format: options.monthFormat,\n split: 4,\n steps: { year: 1 },\n update: function(date, force) {\n if(!this.built || date.getFullYear() !== viewDate.year) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getMonth() !== viewDate.month) {\n angular.extend(viewDate, {month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstMonth = new Date(viewDate.year, 0, 1);\n var months = [], month;\n for (var i = 0; i < 12; i++) {\n month = new Date(viewDate.year, i, 1);\n months.push({date: month, label: formatDate(month, this.format), selected: picker.$isSelected(month), disabled: this.isDisabled(month)});\n }\n scope.title = formatDate(month, options.yearTitleFormat);\n scope.showLabels = false;\n scope.rows = split(months, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth();\n },\n isDisabled: function(date) {\n var lastDate = +new Date(date.getFullYear(), date.getMonth() + 1, 0);\n return lastDate < options.minDate || date.getTime() > options.maxDate;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualMonth = picker.$date.getMonth();\n var newDate = new Date(picker.$date);\n\n if(evt.keyCode === 37) newDate.setMonth(actualMonth - 1);\n else if(evt.keyCode === 38) newDate.setMonth(actualMonth - 4);\n else if(evt.keyCode === 39) newDate.setMonth(actualMonth + 1);\n else if(evt.keyCode === 40) newDate.setMonth(actualMonth + 4);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }, {\n name: 'year',\n format: options.yearFormat,\n split: 4,\n steps: { year: 12 },\n update: function(date, force) {\n if(!this.built || force || parseInt(date.getFullYear()/20, 10) !== parseInt(viewDate.year/20, 10)) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getFullYear() !== viewDate.year) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstYear = viewDate.year - viewDate.year % (this.split * 3);\n var years = [], year;\n for (var i = 0; i < 12; i++) {\n year = new Date(firstYear + i, 0, 1);\n years.push({date: year, label: formatDate(year, this.format), selected: picker.$isSelected(year), disabled: this.isDisabled(year)});\n }\n scope.title = years[0].label + '-' + years[years.length - 1].label;\n scope.showLabels = false;\n scope.rows = split(years, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear();\n },\n isDisabled: function(date) {\n var lastDate = +new Date(date.getFullYear() + 1, 0, 0);\n return lastDate < options.minDate || date.getTime() > options.maxDate;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualYear = picker.$date.getFullYear(),\n newDate = new Date(picker.$date);\n\n if(evt.keyCode === 37) newDate.setYear(actualYear - 1);\n else if(evt.keyCode === 38) newDate.setYear(actualYear - 4);\n else if(evt.keyCode === 39) newDate.setYear(actualYear + 1);\n else if(evt.keyCode === 40) newDate.setYear(actualYear + 4);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }];\n\n return {\n views: options.minView ? Array.prototype.slice.call(views, options.minView) : views,\n viewDate: viewDate\n };\n\n };\n\n };\n\n });\n\n// Source: dropdown/dropdown.js\nangular.module('mgcrea.ngStrap.dropdown', ['mgcrea.ngStrap.tooltip'])\n\n .provider('$dropdown', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'dropdown',\n prefixEvent: 'dropdown',\n placement: 'bottom-left',\n templateUrl: 'dropdown/dropdown.tpl.html',\n trigger: 'click',\n container: false,\n keyboard: true,\n html: false,\n delay: 0\n };\n\n this.$get = function($window, $rootScope, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var matchesSelector = Element.prototype.matchesSelector || Element.prototype.webkitMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector;\n\n function DropdownFactory(element, config) {\n\n var $dropdown = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n var scope = $dropdown.$scope = options.scope && options.scope.$new() || $rootScope.$new();\n\n $dropdown = $tooltip(element, options);\n var parentEl = element.parent();\n\n // Protected methods\n\n $dropdown.$onKeyDown = function(evt) {\n if (!/(38|40)/.test(evt.keyCode)) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // Retrieve focused index\n var items = angular.element($dropdown.$element[0].querySelectorAll('li:not(.divider) a'));\n if(!items.length) return;\n var index;\n angular.forEach(items, function(el, i) {\n if(matchesSelector && matchesSelector.call(el, ':focus')) index = i;\n });\n\n // Navigate with keyboard\n if(evt.keyCode === 38 && index > 0) index--;\n else if(evt.keyCode === 40 && index < items.length - 1) index++;\n else if(angular.isUndefined(index)) index = 0;\n items.eq(index)[0].focus();\n\n };\n\n // Overrides\n\n var show = $dropdown.show;\n $dropdown.show = function() {\n show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n options.keyboard && $dropdown.$element && $dropdown.$element.on('keydown', $dropdown.$onKeyDown);\n bodyEl.on('click', onBodyClick);\n }, 0, false);\n parentEl.hasClass('dropdown') && parentEl.addClass('open');\n };\n\n var hide = $dropdown.hide;\n $dropdown.hide = function() {\n if(!$dropdown.$isShown) return;\n options.keyboard && $dropdown.$element && $dropdown.$element.off('keydown', $dropdown.$onKeyDown);\n bodyEl.off('click', onBodyClick);\n parentEl.hasClass('dropdown') && parentEl.removeClass('open');\n hide();\n };\n\n var destroy = $dropdown.destroy;\n $dropdown.destroy = function() {\n bodyEl.off('click', onBodyClick);\n destroy();\n };\n\n // Private functions\n\n function onBodyClick(evt) {\n if(evt.target === element[0]) return;\n return evt.target !== element[0] && $dropdown.hide();\n }\n\n return $dropdown;\n\n }\n\n return DropdownFactory;\n\n };\n\n })\n\n .directive('bsDropdown', function($window, $sce, $dropdown) {\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Support scope as an object\n attr.bsDropdown && scope.$watch(attr.bsDropdown, function(newValue, oldValue) {\n scope.content = newValue;\n }, true);\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!dropdown || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(dropdown),?/i);\n newValue === true ? dropdown.show() : dropdown.hide();\n });\n\n // Initialize dropdown\n var dropdown = $dropdown(element, options);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (dropdown) dropdown.destroy();\n options = null;\n dropdown = null;\n });\n\n }\n };\n\n });\n\n// Source: helpers/compiler.js\n// NOTICE: This file was forked from the angular-material project (github.com/angular/material)\n// MIT Licensed - Copyright (c) 2014-2015 Google, Inc. http://angularjs.org\n\nangular.module('mgcrea.ngStrap.core', [])\n .service('$bsCompiler', bsCompilerService);\n\nfunction bsCompilerService($q, $http, $injector, $compile, $controller, $templateCache) {\n /* jshint validthis: true */\n\n /*\n * @ngdoc service\n * @name $bsCompiler\n * @module material.core\n * @description\n * The $bsCompiler service is an abstraction of angular's compiler, that allows the developer\n * to easily compile an element with a templateUrl, controller, and locals.\n *\n * @usage\n * \n * $bsCompiler.compile({\n * templateUrl: 'modal.html',\n * controller: 'ModalCtrl',\n * locals: {\n * modal: myModalInstance;\n * }\n * }).then(function(compileData) {\n * compileData.element; // modal.html's template in an element\n * compileData.link(myScope); //attach controller & scope to element\n * });\n * \n */\n\n /*\n * @ngdoc method\n * @name $bsCompiler#compile\n * @description A helper to compile an HTML template/templateUrl with a given controller,\n * locals, and scope.\n * @param {object} options An options object, with the following properties:\n *\n * - `controller` - `{(string=|function()=}` Controller fn that should be associated with\n * newly created scope or the name of a registered controller if passed as a string.\n * - `controllerAs` - `{string=}` A controller alias name. If present the controller will be\n * published to scope under the `controllerAs` name.\n * - `template` - `{string=}` An html template as a string.\n * - `templateUrl` - `{string=}` A path to an html template.\n * - `transformTemplate` - `{function(template)=}` A function which transforms the template after\n * it is loaded. It will be given the template string as a parameter, and should\n * return a a new string representing the transformed template.\n * - `resolve` - `{Object.=}` - An optional map of dependencies which should\n * be injected into the controller. If any of these dependencies are promises, the compiler\n * will wait for them all to be resolved, or if one is rejected before the controller is\n * instantiated `compile()` will fail..\n * * `key` - `{string}`: a name of a dependency to be injected into the controller.\n * * `factory` - `{string|function}`: If `string` then it is an alias for a service.\n * Otherwise if function, then it is injected and the return value is treated as the\n * dependency. If the result is a promise, it is resolved before its value is\n * injected into the controller.\n *\n * @returns {object=} promise A promise, which will be resolved with a `compileData` object.\n * `compileData` has the following properties:\n *\n * - `element` - `{element}`: an uncompiled element matching the provided template.\n * - `link` - `{function(scope)}`: A link function, which, when called, will compile\n * the element and instantiate the provided controller (if given).\n * - `locals` - `{object}`: The locals which will be passed into the controller once `link` is\n * called. If `bindToController` is true, they will be coppied to the ctrl instead\n * - `bindToController` - `bool`: bind the locals to the controller, instead of passing them in.\n */\n this.compile = function(options) {\n\n if(options.template && /\\.html$/.test(options.template)) {\n console.warn('Deprecated use of `template` option to pass a file. Please use the `templateUrl` option instead.');\n options.templateUrl = options.template;\n options.template = '';\n }\n\n var templateUrl = options.templateUrl;\n var template = options.template || '';\n var controller = options.controller;\n var controllerAs = options.controllerAs;\n var resolve = angular.copy(options.resolve || {});\n var locals = angular.copy(options.locals || {});\n var transformTemplate = options.transformTemplate || angular.identity;\n var bindToController = options.bindToController;\n\n // Take resolve values and invoke them.\n // Resolves can either be a string (value: 'MyRegisteredAngularConst'),\n // or an invokable 'factory' of sorts: (value: function ValueGetter($dependency) {})\n angular.forEach(resolve, function(value, key) {\n if (angular.isString(value)) {\n resolve[key] = $injector.get(value);\n } else {\n resolve[key] = $injector.invoke(value);\n }\n });\n // Add the locals, which are just straight values to inject\n // eg locals: { three: 3 }, will inject three into the controller\n angular.extend(resolve, locals);\n\n if (templateUrl) {\n resolve.$template = fetchTemplate(templateUrl);\n } else {\n resolve.$template = $q.when(template);\n }\n\n if (options.contentTemplate) {\n // TODO(mgcrea): deprecate?\n resolve.$template = $q.all([resolve.$template, fetchTemplate(options.contentTemplate)])\n .then(function(templates) {\n var templateEl = angular.element(templates[0]);\n var contentEl = findElement('[ng-bind=\"content\"]', templateEl[0]).removeAttr('ng-bind').html(templates[1]);\n // Drop the default footer as you probably don't want it if you use a custom contentTemplate\n if(!options.templateUrl) contentEl.next().remove();\n return templateEl[0].outerHTML;\n });\n }\n\n // Wait for all the resolves to finish if they are promises\n return $q.all(resolve).then(function(locals) {\n\n var template = transformTemplate(locals.$template);\n if (options.html) {\n template = template.replace(/ng-bind=\"/ig, 'ng-bind-html=\"');\n }\n // var element = options.element || angular.element('
').html(template.trim()).contents();\n var element = angular.element('
').html(template.trim()).contents();\n var linkFn = $compile(element);\n\n // Return a linking function that can be used later when the element is ready\n return {\n locals: locals,\n element: element,\n link: function link(scope) {\n locals.$scope = scope;\n\n // Instantiate controller if it exists, because we have scope\n if (controller) {\n var invokeCtrl = $controller(controller, locals, true);\n if (bindToController) {\n angular.extend(invokeCtrl.instance, locals);\n }\n // Support angular@~1.2 invokeCtrl\n var ctrl = angular.isObject(invokeCtrl) ? invokeCtrl : invokeCtrl();\n // See angular-route source for this logic\n element.data('$ngControllerController', ctrl);\n element.children().data('$ngControllerController', ctrl);\n\n if (controllerAs) {\n scope[controllerAs] = ctrl;\n }\n }\n\n return linkFn.apply(null, arguments);\n }\n };\n });\n\n };\n\n function findElement(query, element) {\n return angular.element((element || document).querySelectorAll(query));\n }\n\n var fetchPromises = {};\n function fetchTemplate(template) {\n if(fetchPromises[template]) return fetchPromises[template];\n return (fetchPromises[template] = $http.get(template, {cache: $templateCache})\n .then(function(res) {\n return res.data;\n }));\n }\n\n}\n\n// Source: helpers/date-formatter.js\nangular.module('mgcrea.ngStrap.helpers.dateFormatter', [])\n\n .service('$dateFormatter', function($locale, dateFilter) {\n\n // The unused `lang` arguments are on purpose. The default implementation does not\n // use them and it always uses the locale loaded into the `$locale` service.\n // Custom implementations might use it, thus allowing different directives to\n // have different languages.\n\n this.getDefaultLocale = function() {\n return $locale.id;\n };\n\n // Format is either a data format name, e.g. \"shortTime\" or \"fullDate\", or a date format\n // Return either the corresponding date format or the given date format.\n this.getDatetimeFormat = function(format, lang) {\n return $locale.DATETIME_FORMATS[format] || format;\n };\n\n this.weekdaysShort = function(lang) {\n return $locale.DATETIME_FORMATS.SHORTDAY;\n };\n\n function splitTimeFormat(format) {\n return /(h+)([:\\.])?(m+)([:\\.])?(s*)[ ]?(a?)/i.exec(format).slice(1);\n }\n\n // h:mm a => h\n this.hoursFormat = function(timeFormat) {\n return splitTimeFormat(timeFormat)[0];\n };\n\n // h:mm a => mm\n this.minutesFormat = function(timeFormat) {\n return splitTimeFormat(timeFormat)[2];\n };\n\n // h:mm:ss a => ss\n this.secondsFormat = function(timeFormat) {\n return splitTimeFormat(timeFormat)[4];\n };\n\n // h:mm a => :\n this.timeSeparator = function(timeFormat) {\n return splitTimeFormat(timeFormat)[1];\n };\n\n // h:mm:ss a => true, h:mm a => false\n this.showSeconds = function(timeFormat) {\n return !!splitTimeFormat(timeFormat)[4];\n };\n\n // h:mm a => true, H.mm => false\n this.showAM = function(timeFormat) {\n return !!splitTimeFormat(timeFormat)[5];\n };\n\n this.formatDate = function(date, format, lang, timezone){\n return dateFilter(date, format, timezone);\n };\n\n });\n\n// Source: helpers/date-parser.js\nangular.module('mgcrea.ngStrap.helpers.dateParser', [])\n\n.provider('$dateParser', function($localeProvider) {\n\n // define a custom ParseDate object to use instead of native Date\n // to avoid date values wrapping when setting date component values\n function ParseDate() {\n this.year = 1970;\n this.month = 0;\n this.day = 1;\n this.hours = 0;\n this.minutes = 0;\n this.seconds = 0;\n this.milliseconds = 0;\n }\n\n ParseDate.prototype.setMilliseconds = function(value) { this.milliseconds = value; };\n ParseDate.prototype.setSeconds = function(value) { this.seconds = value; };\n ParseDate.prototype.setMinutes = function(value) { this.minutes = value; };\n ParseDate.prototype.setHours = function(value) { this.hours = value; };\n ParseDate.prototype.getHours = function() { return this.hours; };\n ParseDate.prototype.setDate = function(value) { this.day = value; };\n ParseDate.prototype.setMonth = function(value) { this.month = value; };\n ParseDate.prototype.setFullYear = function(value) { this.year = value; };\n ParseDate.prototype.fromDate = function(value) {\n this.year = value.getFullYear();\n this.month = value.getMonth();\n this.day = value.getDate();\n this.hours = value.getHours();\n this.minutes = value.getMinutes();\n this.seconds = value.getSeconds();\n this.milliseconds = value.getMilliseconds();\n return this;\n };\n\n ParseDate.prototype.toDate = function() {\n return new Date(this.year, this.month, this.day, this.hours, this.minutes, this.seconds, this.milliseconds);\n };\n\n var proto = ParseDate.prototype;\n\n function noop() {\n }\n\n function isNumeric(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n }\n\n function indexOfCaseInsensitive(array, value) {\n var len = array.length, str=value.toString().toLowerCase();\n for (var i=0; i 12 when midnight changeover, but then cannot generate\n * midnight datetime, so jump to 1AM, otherwise reset.\n * @param date (Date) the date to check\n * @return (Date) the corrected date\n *\n * __ copied from jquery ui datepicker __\n */\n $dateParser.daylightSavingAdjust = function(date) {\n if (!date) {\n return null;\n }\n date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);\n return date;\n };\n\n /* Correct the date for timezone offset.\n * @param date (Date) the date to adjust\n * @param timezone (string) the timezone to adjust for\n * @param undo (boolean) to add or subtract timezone offset\n * @return (Date) the corrected date\n */\n $dateParser.timezoneOffsetAdjust = function(date, timezone, undo) {\n if (!date) {\n return null;\n }\n // Right now, only 'UTC' is supported.\n if (timezone && timezone === 'UTC') {\n date = new Date(date.getTime());\n date.setMinutes(date.getMinutes() + (undo?-1:1)*date.getTimezoneOffset());\n }\n return date;\n };\n\n // Private functions\n\n function setMapForFormat(format) {\n var keys = Object.keys(setFnMap), i;\n var map = [], sortedMap = [];\n // Map to setFn\n var clonedFormat = format;\n for(i = 0; i < keys.length; i++) {\n if(format.split(keys[i]).length > 1) {\n var index = clonedFormat.search(keys[i]);\n format = format.split(keys[i]).join('');\n if(setFnMap[keys[i]]) {\n map[index] = setFnMap[keys[i]];\n }\n }\n }\n // Sort result map\n angular.forEach(map, function(v) {\n // conditional required since angular.forEach broke around v1.2.21\n // related pr: https://github.com/angular/angular.js/pull/8525\n if(v) sortedMap.push(v);\n });\n return sortedMap;\n }\n\n function escapeReservedSymbols(text) {\n return text.replace(/\\//g, '[\\\\/]').replace('/-/g', '[-]').replace(/\\./g, '[.]').replace(/\\\\s/g, '[\\\\s]');\n }\n\n function regExpForFormat(format) {\n var keys = Object.keys(regExpMap), i;\n\n var re = format;\n // Abstract replaces to avoid collisions\n for(i = 0; i < keys.length; i++) {\n re = re.split(keys[i]).join('${' + i + '}');\n }\n // Replace abstracted values\n for(i = 0; i < keys.length; i++) {\n re = re.split('${' + i + '}').join('(' + regExpMap[keys[i]] + ')');\n }\n format = escapeReservedSymbols(format);\n\n return new RegExp('^' + re + '$', ['i']);\n }\n\n $dateParser.init();\n return $dateParser;\n\n };\n\n return DateParserFactory;\n\n };\n\n});\n\n// Source: helpers/debounce.js\nangular.module('mgcrea.ngStrap.helpers.debounce', [])\n\n// @source jashkenas/underscore\n// @url https://github.com/jashkenas/underscore/blob/1.5.2/underscore.js#L693\n.factory('debounce', function($timeout) {\n return function(func, wait, immediate) {\n var timeout = null;\n return function() {\n var context = this,\n args = arguments,\n callNow = immediate && !timeout;\n if(timeout) {\n $timeout.cancel(timeout);\n }\n timeout = $timeout(function later() {\n timeout = null;\n if(!immediate) {\n func.apply(context, args);\n }\n }, wait, false);\n if(callNow) {\n func.apply(context, args);\n }\n return timeout;\n };\n };\n})\n\n\n// @source jashkenas/underscore\n// @url https://github.com/jashkenas/underscore/blob/1.5.2/underscore.js#L661\n.factory('throttle', function($timeout) {\n return function(func, wait, options) {\n var timeout = null;\n options || (options = {});\n return function() {\n var context = this,\n args = arguments;\n if(!timeout) {\n if(options.leading !== false) {\n func.apply(context, args);\n }\n timeout = $timeout(function later() {\n timeout = null;\n if(options.trailing !== false) {\n func.apply(context, args);\n }\n }, wait, false);\n }\n };\n };\n});\n\n// Source: helpers/dimensions.js\nangular.module('mgcrea.ngStrap.helpers.dimensions', [])\n\n .factory('dimensions', function($document, $window) {\n\n var jqLite = angular.element;\n var fn = {};\n\n /**\n * Test the element nodeName\n * @param element\n * @param name\n */\n var nodeName = fn.nodeName = function(element, name) {\n return element.nodeName && element.nodeName.toLowerCase() === name.toLowerCase();\n };\n\n /**\n * Returns the element computed style\n * @param element\n * @param prop\n * @param extra\n */\n fn.css = function(element, prop, extra) {\n var value;\n if (element.currentStyle) { //IE\n value = element.currentStyle[prop];\n } else if (window.getComputedStyle) {\n value = window.getComputedStyle(element)[prop];\n } else {\n value = element.style[prop];\n }\n return extra === true ? parseFloat(value) || 0 : value;\n };\n\n /**\n * Provides read-only equivalent of jQuery's offset function:\n * @required-by bootstrap-tooltip, bootstrap-affix\n * @url http://api.jquery.com/offset/\n * @param element\n */\n fn.offset = function(element) {\n var boxRect = element.getBoundingClientRect();\n var docElement = element.ownerDocument;\n return {\n width: boxRect.width || element.offsetWidth,\n height: boxRect.height || element.offsetHeight,\n top: boxRect.top + (window.pageYOffset || docElement.documentElement.scrollTop) - (docElement.documentElement.clientTop || 0),\n left: boxRect.left + (window.pageXOffset || docElement.documentElement.scrollLeft) - (docElement.documentElement.clientLeft || 0)\n };\n };\n \n /**\n * Provides set equivalent of jQuery's offset function:\n * @required-by bootstrap-tooltip\n * @url http://api.jquery.com/offset/\n * @param element\n * @param options\n * @param i\n */\n fn.setOffset = function (element, options, i) {\n var curPosition,\n curLeft,\n curCSSTop,\n curTop,\n curOffset,\n curCSSLeft,\n calculatePosition,\n position = fn.css(element, 'position'),\n curElem = angular.element(element),\n props = {};\n \n // Set position first, in-case top/left are set even on static elem\n if (position === 'static') {\n element.style.position = 'relative';\n }\n \n curOffset = fn.offset(element);\n curCSSTop = fn.css(element, 'top');\n curCSSLeft = fn.css(element, 'left');\n calculatePosition = (position === 'absolute' || position === 'fixed') && \n (curCSSTop + curCSSLeft).indexOf('auto') > -1;\n \n // Need to be able to calculate position if either\n // top or left is auto and position is either absolute or fixed\n if (calculatePosition) {\n curPosition = fn.position(element);\n curTop = curPosition.top;\n curLeft = curPosition.left;\n } else {\n curTop = parseFloat(curCSSTop) || 0;\n curLeft = parseFloat(curCSSLeft) || 0;\n }\n \n if (angular.isFunction(options)) {\n options = options.call(element, i, curOffset);\n }\n \n if (options.top !== null ) {\n props.top = (options.top - curOffset.top) + curTop;\n }\n if ( options.left !== null ) {\n props.left = (options.left - curOffset.left) + curLeft;\n }\n\n if ('using' in options) {\n options.using.call(curElem, props);\n } else {\n curElem.css({\n top: props.top + 'px',\n left: props.left + 'px'\n });\n }\n };\n\n /**\n * Provides read-only equivalent of jQuery's position function\n * @required-by bootstrap-tooltip, bootstrap-affix\n * @url http://api.jquery.com/offset/\n * @param element\n */\n fn.position = function(element) {\n\n var offsetParentRect = {top: 0, left: 0},\n offsetParentElement,\n offset;\n\n // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent\n if (fn.css(element, 'position') === 'fixed') {\n\n // We assume that getBoundingClientRect is available when computed position is fixed\n offset = element.getBoundingClientRect();\n\n } else {\n\n // Get *real* offsetParentElement\n offsetParentElement = offsetParent(element);\n\n // Get correct offsets\n offset = fn.offset(element);\n if (!nodeName(offsetParentElement, 'html')) {\n offsetParentRect = fn.offset(offsetParentElement);\n }\n\n // Add offsetParent borders\n offsetParentRect.top += fn.css(offsetParentElement, 'borderTopWidth', true);\n offsetParentRect.left += fn.css(offsetParentElement, 'borderLeftWidth', true);\n }\n\n // Subtract parent offsets and element margins\n return {\n width: element.offsetWidth,\n height: element.offsetHeight,\n top: offset.top - offsetParentRect.top - fn.css(element, 'marginTop', true),\n left: offset.left - offsetParentRect.left - fn.css(element, 'marginLeft', true)\n };\n\n };\n\n /**\n * Returns the closest, non-statically positioned offsetParent of a given element\n * @required-by fn.position\n * @param element\n */\n var offsetParent = function offsetParentElement(element) {\n var docElement = element.ownerDocument;\n var offsetParent = element.offsetParent || docElement;\n if(nodeName(offsetParent, '#document')) return docElement.documentElement;\n while(offsetParent && !nodeName(offsetParent, 'html') && fn.css(offsetParent, 'position') === 'static') {\n offsetParent = offsetParent.offsetParent;\n }\n return offsetParent || docElement.documentElement;\n };\n\n /**\n * Provides equivalent of jQuery's height function\n * @required-by bootstrap-affix\n * @url http://api.jquery.com/height/\n * @param element\n * @param outer\n */\n fn.height = function(element, outer) {\n var value = element.offsetHeight;\n if(outer) {\n value += fn.css(element, 'marginTop', true) + fn.css(element, 'marginBottom', true);\n } else {\n value -= fn.css(element, 'paddingTop', true) + fn.css(element, 'paddingBottom', true) + fn.css(element, 'borderTopWidth', true) + fn.css(element, 'borderBottomWidth', true);\n }\n return value;\n };\n\n /**\n * Provides equivalent of jQuery's width function\n * @required-by bootstrap-affix\n * @url http://api.jquery.com/width/\n * @param element\n * @param outer\n */\n fn.width = function(element, outer) {\n var value = element.offsetWidth;\n if(outer) {\n value += fn.css(element, 'marginLeft', true) + fn.css(element, 'marginRight', true);\n } else {\n value -= fn.css(element, 'paddingLeft', true) + fn.css(element, 'paddingRight', true) + fn.css(element, 'borderLeftWidth', true) + fn.css(element, 'borderRightWidth', true);\n }\n return value;\n };\n\n return fn;\n\n });\n\n// Source: helpers/parse-options.js\nangular.module('mgcrea.ngStrap.helpers.parseOptions', [])\n\n .provider('$parseOptions', function() {\n\n var defaults = this.defaults = {\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+(.*?))?$/\n };\n\n this.$get = function($parse, $q) {\n\n function ParseOptionsFactory(attr, config) {\n\n var $parseOptions = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n $parseOptions.$values = [];\n\n // Private vars\n var match, displayFn, valueName, keyName, groupByFn, valueFn, valuesFn;\n\n $parseOptions.init = function() {\n $parseOptions.$match = match = attr.match(options.regexp);\n displayFn = $parse(match[2] || match[1]),\n valueName = match[4] || match[6],\n keyName = match[5],\n groupByFn = $parse(match[3] || ''),\n valueFn = $parse(match[2] ? match[1] : valueName),\n valuesFn = $parse(match[7]);\n };\n\n $parseOptions.valuesFn = function(scope, controller) {\n return $q.when(valuesFn(scope, controller))\n .then(function(values) {\n if(!angular.isArray(values)) {\n values = [];\n }\n $parseOptions.$values = values.length ? parseValues(values, scope) : [];\n return $parseOptions.$values;\n });\n };\n\n $parseOptions.displayValue = function(modelValue) {\n var scope = {};\n scope[valueName] = modelValue;\n return displayFn(scope);\n };\n\n // Private functions\n\n function parseValues(values, scope) {\n return values.map(function(match, index) {\n var locals = {}, label, value;\n locals[valueName] = match;\n label = displayFn(scope, locals);\n value = valueFn(scope, locals);\n return {label: label, value: value, index: index};\n });\n }\n\n $parseOptions.init();\n return $parseOptions;\n\n }\n\n return ParseOptionsFactory;\n\n };\n\n });\n\n// Source: helpers/raf.js\n(angular.version.minor < 3 && angular.version.dot < 14) && angular.module('ng')\n\n.factory('$$rAF', function($window, $timeout) {\n\n var requestAnimationFrame = $window.requestAnimationFrame ||\n $window.webkitRequestAnimationFrame ||\n $window.mozRequestAnimationFrame;\n\n var cancelAnimationFrame = $window.cancelAnimationFrame ||\n $window.webkitCancelAnimationFrame ||\n $window.mozCancelAnimationFrame ||\n $window.webkitCancelRequestAnimationFrame;\n\n var rafSupported = !!requestAnimationFrame;\n var raf = rafSupported ?\n function(fn) {\n var id = requestAnimationFrame(fn);\n return function() {\n cancelAnimationFrame(id);\n };\n } :\n function(fn) {\n var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666\n return function() {\n $timeout.cancel(timer);\n };\n };\n\n raf.supported = rafSupported;\n\n return raf;\n\n});\n\n// .factory('$$animateReflow', function($$rAF, $document) {\n\n// var bodyEl = $document[0].body;\n\n// return function(fn) {\n// //the returned function acts as the cancellation function\n// return $$rAF(function() {\n// //the line below will force the browser to perform a repaint\n// //so that all the animated elements within the animation frame\n// //will be properly updated and drawn on screen. This is\n// //required to perform multi-class CSS based animations with\n// //Firefox. DO NOT REMOVE THIS LINE.\n// var a = bodyEl.offsetWidth + 1;\n// fn();\n// });\n// };\n\n// });\n\n// Source: modal/modal.js\nangular.module('mgcrea.ngStrap.modal', ['mgcrea.ngStrap.core', 'mgcrea.ngStrap.helpers.dimensions'])\n\n .provider('$modal', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n backdropAnimation: 'am-fade',\n prefixClass: 'modal',\n prefixEvent: 'modal',\n placement: 'top',\n templateUrl: 'modal/modal.tpl.html',\n template: '',\n contentTemplate: false,\n container: false,\n element: null,\n backdrop: true,\n keyboard: true,\n html: false,\n show: true\n };\n\n this.$get = function($window, $rootScope, $bsCompiler, $q, $templateCache, $http, $animate, $timeout, $sce, dimensions) {\n\n var forEach = angular.forEach;\n var trim = String.prototype.trim;\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n var bodyElement = angular.element($window.document.body);\n\n function ModalFactory(config) {\n\n var $modal = {};\n\n // Common vars\n var options = $modal.$options = angular.extend({}, defaults, config);\n var promise = $modal.$promise = $bsCompiler.compile(options);\n var scope = $modal.$scope = options.scope && options.scope.$new() || $rootScope.$new();\n\n if(!options.element && !options.container) {\n options.container = 'body';\n }\n\n // Store $id to identify the triggering element in events\n // give priority to options.id, otherwise, try to use\n // element id if defined\n $modal.$id = options.id || options.element && options.element.attr('id') || '';\n\n // Support scope as string options\n forEach(['title', 'content'], function(key) {\n if(options[key]) scope[key] = $sce.trustAsHtml(options[key]);\n });\n\n // Provide scope helpers\n scope.$hide = function() {\n scope.$$postDigest(function() {\n $modal.hide();\n });\n };\n scope.$show = function() {\n scope.$$postDigest(function() {\n $modal.show();\n });\n };\n scope.$toggle = function() {\n scope.$$postDigest(function() {\n $modal.toggle();\n });\n };\n // Publish isShown as a protected var on scope\n $modal.$isShown = scope.$isShown = false;\n\n // Fetch, compile then initialize modal\n var compileData, modalElement, modalScope;\n var backdropElement = angular.element('
');\n backdropElement.css({position:'fixed', top:'0px', left:'0px', bottom:'0px', right:'0px', 'z-index': 1038});\n promise.then(function(data) {\n compileData = data;\n $modal.init();\n });\n\n $modal.init = function() {\n\n // Options: show\n if(options.show) {\n scope.$$postDigest(function() {\n $modal.show();\n });\n }\n\n };\n\n $modal.destroy = function() {\n\n // Remove element\n destroyModalElement();\n\n // remove backdrop element\n if(backdropElement) {\n backdropElement.remove();\n backdropElement = null;\n }\n\n // Destroy scope\n scope.$destroy();\n };\n\n $modal.show = function() {\n if($modal.$isShown) return;\n\n var parent, after;\n if(angular.isElement(options.container)) {\n parent = options.container;\n after = options.container[0].lastChild ? angular.element(options.container[0].lastChild) : null;\n } else {\n if (options.container) {\n parent = findElement(options.container);\n after = parent[0] && parent[0].lastChild ? angular.element(parent[0].lastChild) : null;\n } else {\n parent = null;\n after = options.element;\n }\n }\n\n // destroy any existing modal elements\n if(modalElement) destroyModalElement();\n\n // create a new scope, so we can destroy it and all child scopes\n // when destroying the modal element\n modalScope = $modal.$scope.$new();\n // Fetch a cloned element linked from template (noop callback is required)\n modalElement = $modal.$element = compileData.link(modalScope, function(clonedElement, scope) {});\n\n if(scope.$emit(options.prefixEvent + '.show.before', $modal).defaultPrevented) {\n return;\n }\n\n // Set the initial positioning.\n modalElement.css({display: 'block'}).addClass(options.placement);\n\n // Options: animation\n if(options.animation) {\n if(options.backdrop) {\n backdropElement.addClass(options.backdropAnimation);\n }\n modalElement.addClass(options.animation);\n }\n\n if(options.backdrop) {\n $animate.enter(backdropElement, bodyElement, null);\n }\n\n // Support v1.2+ $animate\n // https://github.com/angular/angular.js/issues/11713\n if(angular.version.minor <= 2) {\n $animate.enter(modalElement, parent, after, enterAnimateCallback);\n } else {\n $animate.enter(modalElement, parent, after).then(enterAnimateCallback);\n }\n\n $modal.$isShown = scope.$isShown = true;\n safeDigest(scope);\n // Focus once the enter-animation has started\n // Weird PhantomJS bug hack\n var el = modalElement[0];\n requestAnimationFrame(function() {\n el.focus();\n });\n\n bodyElement.addClass(options.prefixClass + '-open');\n if(options.animation) {\n bodyElement.addClass(options.prefixClass + '-with-' + options.animation);\n }\n\n // Bind events\n bindBackdropEvents();\n bindKeyboardEvents();\n };\n\n function enterAnimateCallback() {\n scope.$emit(options.prefixEvent + '.show', $modal);\n }\n\n $modal.hide = function() {\n if(!$modal.$isShown) return;\n\n if(scope.$emit(options.prefixEvent + '.hide.before', $modal).defaultPrevented) {\n return;\n }\n\n // Support v1.2+ $animate\n // https://github.com/angular/angular.js/issues/11713\n if(angular.version.minor <= 2) {\n $animate.leave(modalElement, leaveAnimateCallback);\n } else {\n $animate.leave(modalElement).then(leaveAnimateCallback);\n }\n\n if(options.backdrop) {\n $animate.leave(backdropElement);\n }\n $modal.$isShown = scope.$isShown = false;\n safeDigest(scope);\n\n // Unbind events\n unbindBackdropEvents();\n unbindKeyboardEvents();\n };\n\n function leaveAnimateCallback() {\n scope.$emit(options.prefixEvent + '.hide', $modal);\n bodyElement.removeClass(options.prefixClass + '-open');\n if(options.animation) {\n bodyElement.removeClass(options.prefixClass + '-with-' + options.animation);\n }\n }\n\n $modal.toggle = function() {\n\n $modal.$isShown ? $modal.hide() : $modal.show();\n\n };\n\n $modal.focus = function() {\n modalElement[0].focus();\n };\n\n // Protected methods\n\n $modal.$onKeyUp = function(evt) {\n\n if (evt.which === 27 && $modal.$isShown) {\n $modal.hide();\n evt.stopPropagation();\n }\n\n };\n\n function bindBackdropEvents() {\n if(options.backdrop) {\n modalElement.on('click', hideOnBackdropClick);\n backdropElement.on('click', hideOnBackdropClick);\n backdropElement.on('wheel', preventEventDefault);\n }\n }\n\n function unbindBackdropEvents() {\n if(options.backdrop) {\n modalElement.off('click', hideOnBackdropClick);\n backdropElement.off('click', hideOnBackdropClick);\n backdropElement.off('wheel', preventEventDefault);\n }\n }\n\n function bindKeyboardEvents() {\n if(options.keyboard) {\n modalElement.on('keyup', $modal.$onKeyUp);\n }\n }\n\n function unbindKeyboardEvents() {\n if(options.keyboard) {\n modalElement.off('keyup', $modal.$onKeyUp);\n }\n }\n\n // Private methods\n\n function hideOnBackdropClick(evt) {\n if(evt.target !== evt.currentTarget) return;\n options.backdrop === 'static' ? $modal.focus() : $modal.hide();\n }\n\n function preventEventDefault(evt) {\n evt.preventDefault();\n }\n\n function destroyModalElement() {\n if($modal.$isShown && modalElement !== null) {\n // un-bind events\n unbindBackdropEvents();\n unbindKeyboardEvents();\n }\n\n if(modalScope) {\n modalScope.$destroy();\n modalScope = null;\n }\n\n if(modalElement) {\n modalElement.remove();\n modalElement = $modal.$element = null;\n }\n }\n\n return $modal;\n\n }\n\n // Helper functions\n\n function safeDigest(scope) {\n scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();\n }\n\n function findElement(query, element) {\n return angular.element((element || document).querySelectorAll(query));\n }\n\n return ModalFactory;\n\n };\n\n })\n\n .directive('bsModal', function($window, $sce, $modal) {\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope, element: element, show: false};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'controller', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation', 'id', 'prefixEvent', 'prefixClass'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['backdrop', 'keyboard', 'html', 'container'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Support scope as data-attrs\n angular.forEach(['title', 'content'], function(key) {\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\n scope[key] = $sce.trustAsHtml(newValue);\n });\n });\n\n // Support scope as an object\n attr.bsModal && scope.$watch(attr.bsModal, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.content = newValue;\n }\n }, true);\n\n // Initialize modal\n var modal = $modal(options);\n\n // Trigger\n element.on(attr.trigger || 'click', modal.toggle);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (modal) modal.destroy();\n options = null;\n modal = null;\n });\n\n }\n };\n\n });\n\n// Source: navbar/navbar.js\nangular.module('mgcrea.ngStrap.navbar', [])\n\n .provider('$navbar', function() {\n\n var defaults = this.defaults = {\n activeClass: 'active',\n routeAttr: 'data-match-route',\n strict: false\n };\n\n this.$get = function() {\n return {defaults: defaults};\n };\n\n })\n\n .directive('bsNavbar', function($window, $location, $navbar) {\n\n var defaults = $navbar.defaults;\n\n return {\n restrict: 'A',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = angular.copy(defaults);\n angular.forEach(Object.keys(defaults), function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Watch for the $location\n scope.$watch(function() {\n\n return $location.path();\n\n }, function(newValue, oldValue) {\n\n var liElements = element[0].querySelectorAll('li[' + options.routeAttr + ']');\n\n angular.forEach(liElements, function(li) {\n\n var liElement = angular.element(li);\n var pattern = liElement.attr(options.routeAttr).replace('/', '\\\\/');\n if(options.strict) {\n pattern = '^' + pattern + '$';\n }\n var regexp = new RegExp(pattern, 'i');\n\n if(regexp.test(newValue)) {\n liElement.addClass(options.activeClass);\n } else {\n liElement.removeClass(options.activeClass);\n }\n\n });\n\n });\n\n }\n\n };\n\n });\n\n// Source: popover/popover.js\nangular.module('mgcrea.ngStrap.popover', ['mgcrea.ngStrap.tooltip'])\n\n .provider('$popover', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n customClass: '',\n // uncommenting the next two lines will break backwards compatability\n // prefixClass: 'popover',\n // prefixEvent: 'popover',\n container: false,\n target: false,\n placement: 'right',\n templateUrl: 'popover/popover.tpl.html',\n contentTemplate: false,\n trigger: 'click',\n keyboard: true,\n html: false,\n title: '',\n content: '',\n delay: 0,\n autoClose: false\n };\n\n this.$get = function($tooltip) {\n\n function PopoverFactory(element, config) {\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n var $popover = $tooltip(element, options);\n\n // Support scope as string options [/*title, */content]\n if(options.content) {\n $popover.$scope.content = options.content;\n }\n\n return $popover;\n\n }\n\n return PopoverFactory;\n\n };\n\n })\n\n .directive('bsPopover', function($window, $sce, $popover) {\n\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'customClass', 'autoClose', 'id', 'prefixClass', 'prefixEvent'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'autoClose'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // should not parse target attribute (anchor tag), only data-target #1454\n var dataTarget = element.attr('data-target');\n if(angular.isDefined(dataTarget)) {\n if(falseValueRegExp.test(dataTarget))\n options.target = false;\n else\n options.target = dataTarget;\n }\n\n // Support scope as data-attrs\n angular.forEach(['title', 'content'], function(key) {\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\n scope[key] = $sce.trustAsHtml(newValue);\n angular.isDefined(oldValue) && requestAnimationFrame(function() {\n popover && popover.$applyPlacement();\n });\n });\n });\n\n // Support scope as an object\n attr.bsPopover && scope.$watch(attr.bsPopover, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.content = newValue;\n }\n angular.isDefined(oldValue) && requestAnimationFrame(function() {\n popover && popover.$applyPlacement();\n });\n }, true);\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!popover || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(popover),?/i);\n newValue === true ? popover.show() : popover.hide();\n });\n\n // Viewport support\n attr.viewport && scope.$watch(attr.viewport, function (newValue) {\n if(!popover || !angular.isDefined(newValue)) return;\n popover.setViewport(newValue);\n });\n\n // Initialize popover\n var popover = $popover(element, options);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (popover) popover.destroy();\n options = null;\n popover = null;\n });\n\n }\n };\n\n });\n\n// Source: scrollspy/scrollspy.js\nangular.module('mgcrea.ngStrap.scrollspy', ['mgcrea.ngStrap.helpers.debounce', 'mgcrea.ngStrap.helpers.dimensions'])\n\n .provider('$scrollspy', function() {\n\n // Pool of registered spies\n var spies = this.$$spies = {};\n\n var defaults = this.defaults = {\n debounce: 150,\n throttle: 100,\n offset: 100\n };\n\n this.$get = function($window, $document, $rootScope, dimensions, debounce, throttle) {\n\n var windowEl = angular.element($window);\n var docEl = angular.element($document.prop('documentElement'));\n var bodyEl = angular.element($window.document.body);\n\n // Helper functions\n\n function nodeName(element, name) {\n return element[0].nodeName && element[0].nodeName.toLowerCase() === name.toLowerCase();\n }\n\n function ScrollSpyFactory(config) {\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n if(!options.element) options.element = bodyEl;\n var isWindowSpy = nodeName(options.element, 'body');\n var scrollEl = isWindowSpy ? windowEl : options.element;\n var scrollId = isWindowSpy ? 'window' : options.id;\n\n // Use existing spy\n if(spies[scrollId]) {\n spies[scrollId].$$count++;\n return spies[scrollId];\n }\n\n var $scrollspy = {};\n\n // Private vars\n var unbindViewContentLoaded, unbindIncludeContentLoaded;\n var trackedElements = $scrollspy.$trackedElements = [];\n var sortedElements = [];\n var activeTarget;\n var debouncedCheckPosition;\n var throttledCheckPosition;\n var debouncedCheckOffsets;\n var viewportHeight;\n var scrollTop;\n\n $scrollspy.init = function() {\n\n // Setup internal ref counter\n this.$$count = 1;\n\n // Bind events\n debouncedCheckPosition = debounce(this.checkPosition, options.debounce);\n throttledCheckPosition = throttle(this.checkPosition, options.throttle);\n scrollEl.on('click', this.checkPositionWithEventLoop);\n windowEl.on('resize', debouncedCheckPosition);\n scrollEl.on('scroll', throttledCheckPosition);\n\n debouncedCheckOffsets = debounce(this.checkOffsets, options.debounce);\n unbindViewContentLoaded = $rootScope.$on('$viewContentLoaded', debouncedCheckOffsets);\n unbindIncludeContentLoaded = $rootScope.$on('$includeContentLoaded', debouncedCheckOffsets);\n debouncedCheckOffsets();\n\n // Register spy for reuse\n if(scrollId) {\n spies[scrollId] = $scrollspy;\n }\n\n };\n\n $scrollspy.destroy = function() {\n\n // Check internal ref counter\n this.$$count--;\n if(this.$$count > 0) {\n return;\n }\n\n // Unbind events\n scrollEl.off('click', this.checkPositionWithEventLoop);\n windowEl.off('resize', debouncedCheckPosition);\n scrollEl.off('scroll', throttledCheckPosition);\n unbindViewContentLoaded();\n unbindIncludeContentLoaded();\n if (scrollId) {\n delete spies[scrollId];\n }\n };\n\n $scrollspy.checkPosition = function() {\n\n // Not ready yet\n if(!sortedElements.length) return;\n\n // Calculate the scroll position\n scrollTop = (isWindowSpy ? $window.pageYOffset : scrollEl.prop('scrollTop')) || 0;\n\n // Calculate the viewport height for use by the components\n viewportHeight = Math.max($window.innerHeight, docEl.prop('clientHeight'));\n\n // Activate first element if scroll is smaller\n if(scrollTop < sortedElements[0].offsetTop && activeTarget !== sortedElements[0].target) {\n return $scrollspy.$activateElement(sortedElements[0]);\n }\n\n // Activate proper element\n for (var i = sortedElements.length; i--;) {\n if(angular.isUndefined(sortedElements[i].offsetTop) || sortedElements[i].offsetTop === null) continue;\n if(activeTarget === sortedElements[i].target) continue;\n if(scrollTop < sortedElements[i].offsetTop) continue;\n if(sortedElements[i + 1] && scrollTop > sortedElements[i + 1].offsetTop) continue;\n return $scrollspy.$activateElement(sortedElements[i]);\n }\n\n };\n\n $scrollspy.checkPositionWithEventLoop = function() {\n // IE 9 throws an error if we use 'this' instead of '$scrollspy'\n // in this setTimeout call\n setTimeout($scrollspy.checkPosition, 1);\n };\n\n // Protected methods\n\n $scrollspy.$activateElement = function(element) {\n if(activeTarget) {\n var activeElement = $scrollspy.$getTrackedElement(activeTarget);\n if(activeElement) {\n activeElement.source.removeClass('active');\n if(nodeName(activeElement.source, 'li') && nodeName(activeElement.source.parent().parent(), 'li')) {\n activeElement.source.parent().parent().removeClass('active');\n }\n }\n }\n activeTarget = element.target;\n element.source.addClass('active');\n if(nodeName(element.source, 'li') && nodeName(element.source.parent().parent(), 'li')) {\n element.source.parent().parent().addClass('active');\n }\n };\n\n $scrollspy.$getTrackedElement = function(target) {\n return trackedElements.filter(function(obj) {\n return obj.target === target;\n })[0];\n };\n\n // Track offsets behavior\n\n $scrollspy.checkOffsets = function() {\n\n angular.forEach(trackedElements, function(trackedElement) {\n var targetElement = document.querySelector(trackedElement.target);\n trackedElement.offsetTop = targetElement ? dimensions.offset(targetElement).top : null;\n if(options.offset && trackedElement.offsetTop !== null) trackedElement.offsetTop -= options.offset * 1;\n });\n\n sortedElements = trackedElements\n .filter(function(el) {\n return el.offsetTop !== null;\n })\n .sort(function(a, b) {\n return a.offsetTop - b.offsetTop;\n });\n\n debouncedCheckPosition();\n\n };\n\n $scrollspy.trackElement = function(target, source) {\n trackedElements.push({target: target, source: source});\n };\n\n $scrollspy.untrackElement = function(target, source) {\n var toDelete;\n for (var i = trackedElements.length; i--;) {\n if(trackedElements[i].target === target && trackedElements[i].source === source) {\n toDelete = i;\n break;\n }\n }\n trackedElements = trackedElements.splice(toDelete, 1);\n };\n\n $scrollspy.activate = function(i) {\n trackedElements[i].addClass('active');\n };\n\n // Initialize plugin\n\n $scrollspy.init();\n return $scrollspy;\n\n }\n\n return ScrollSpyFactory;\n\n };\n\n })\n\n .directive('bsScrollspy', function($rootScope, debounce, dimensions, $scrollspy) {\n\n return {\n restrict: 'EAC',\n link: function postLink(scope, element, attr) {\n\n var options = {scope: scope};\n angular.forEach(['offset', 'target'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n var scrollspy = $scrollspy(options);\n scrollspy.trackElement(options.target, element);\n\n scope.$on('$destroy', function() {\n if (scrollspy) {\n scrollspy.untrackElement(options.target, element);\n scrollspy.destroy();\n }\n options = null;\n scrollspy = null;\n });\n\n }\n };\n\n })\n\n\n .directive('bsScrollspyList', function($rootScope, debounce, dimensions, $scrollspy) {\n\n return {\n restrict: 'A',\n compile: function postLink(element, attr) {\n var children = element[0].querySelectorAll('li > a[href]');\n angular.forEach(children, function(child) {\n var childEl = angular.element(child);\n childEl.parent().attr('bs-scrollspy', '').attr('data-target', childEl.attr('href'));\n });\n }\n\n };\n\n });\n\n// Source: select/select.js\nangular.module('mgcrea.ngStrap.select', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions'])\n\n .provider('$select', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'select',\n prefixEvent: '$select',\n placement: 'bottom-left',\n templateUrl: 'select/select.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n multiple: false,\n allNoneButtons: false,\n sort: true,\n caretHtml: ' ',\n placeholder: 'Choose among the following...',\n allText: 'All',\n noneText: 'None',\n maxLength: 3,\n maxLengthHtml: 'selected',\n iconCheckmark: 'glyphicon glyphicon-ok'\n };\n\n this.$get = function($window, $document, $rootScope, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n\n function SelectFactory(element, controller, config) {\n\n var $select = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $select = $tooltip(element, options);\n var scope = $select.$scope;\n\n scope.$matches = [];\n if (options.multiple) {\n scope.$activeIndex = [];\n }\n else {\n scope.$activeIndex = -1;\n }\n scope.$isMultiple = options.multiple;\n scope.$showAllNoneButtons = options.allNoneButtons && options.multiple;\n scope.$iconCheckmark = options.iconCheckmark;\n scope.$allText = options.allText;\n scope.$noneText = options.noneText;\n\n scope.$activate = function(index) {\n scope.$$postDigest(function() {\n $select.activate(index);\n });\n };\n\n scope.$select = function(index, evt) {\n scope.$$postDigest(function() {\n $select.select(index);\n });\n };\n\n scope.$isVisible = function() {\n return $select.$isVisible();\n };\n\n scope.$isActive = function(index) {\n return $select.$isActive(index);\n };\n\n scope.$selectAll = function () {\n for (var i = 0; i < scope.$matches.length; i++) {\n if (!scope.$isActive(i)) {\n scope.$select(i);\n }\n }\n };\n\n scope.$selectNone = function () {\n for (var i = 0; i < scope.$matches.length; i++) {\n if (scope.$isActive(i)) {\n scope.$select(i);\n }\n }\n };\n\n // Public methods\n\n $select.update = function(matches) {\n scope.$matches = matches;\n $select.$updateActiveIndex();\n };\n\n $select.activate = function(index) {\n if(options.multiple) {\n $select.$isActive(index) ? scope.$activeIndex.splice(scope.$activeIndex.indexOf(index), 1) : scope.$activeIndex.push(index);\n if(options.sort) scope.$activeIndex.sort(function(a, b) { return a - b; }); // use numeric sort instead of default sort\n } else {\n scope.$activeIndex = index;\n }\n return scope.$activeIndex;\n };\n\n $select.select = function(index) {\n var value = scope.$matches[index].value;\n scope.$apply(function() {\n $select.activate(index);\n if(options.multiple) {\n controller.$setViewValue(scope.$activeIndex.map(function(index) {\n return scope.$matches[index].value;\n }));\n } else {\n controller.$setViewValue(value);\n // Hide if single select\n $select.hide();\n }\n });\n // Emit event\n scope.$emit(options.prefixEvent + '.select', value, index, $select);\n };\n\n // Protected methods\n\n $select.$updateActiveIndex = function() {\n if(controller.$modelValue && scope.$matches.length) {\n if(options.multiple && angular.isArray(controller.$modelValue)) {\n scope.$activeIndex = controller.$modelValue.map(function(value) {\n return $select.$getIndex(value);\n });\n } else {\n scope.$activeIndex = $select.$getIndex(controller.$modelValue);\n }\n } else if(scope.$activeIndex >= scope.$matches.length) {\n scope.$activeIndex = options.multiple ? [] : 0;\n }\n };\n\n $select.$isVisible = function() {\n if(!options.minLength || !controller) {\n return scope.$matches.length;\n }\n // minLength support\n return scope.$matches.length && controller.$viewValue.length >= options.minLength;\n };\n\n $select.$isActive = function(index) {\n if(options.multiple) {\n return scope.$activeIndex.indexOf(index) !== -1;\n } else {\n return scope.$activeIndex === index;\n }\n };\n\n $select.$getIndex = function(value) {\n var l = scope.$matches.length, i = l;\n if(!l) return;\n for(i = l; i--;) {\n if(scope.$matches[i].value === value) break;\n }\n if(i < 0) return;\n return i;\n };\n\n $select.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n targetEl.triggerHandler('click');\n }\n };\n\n $select.$onKeyDown = function(evt) {\n if (!/(9|13|38|40)/.test(evt.keyCode)) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // release focus on tab\n if (options.multiple && evt.keyCode === 9) {\n return $select.hide();\n }\n\n // Select with enter\n if(!options.multiple && (evt.keyCode === 13 || evt.keyCode === 9)) {\n return $select.select(scope.$activeIndex);\n }\n\n if (!options.multiple) {\n // Navigate with keyboard\n if(evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--;\n else if(evt.keyCode === 38 && scope.$activeIndex < 0) scope.$activeIndex = scope.$matches.length - 1;\n else if(evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++;\n else if(angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0;\n scope.$digest();\n }\n };\n\n // Overrides\n\n var _show = $select.show;\n $select.show = function() {\n _show();\n if(options.multiple) {\n $select.$element.addClass('select-multiple');\n }\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n $select.$element.on(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $select.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $select.hide;\n $select.hide = function() {\n if(!options.multiple && !controller.$modelValue) {\n scope.$activeIndex = -1;\n }\n $select.$element.off(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $select.$onKeyDown);\n }\n _hide(true);\n };\n\n return $select;\n\n }\n\n SelectFactory.defaults = defaults;\n return SelectFactory;\n\n };\n\n })\n\n .directive('bsSelect', function($window, $parse, $q, $select, $parseOptions) {\n\n var defaults = $select.defaults;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope, placeholder: defaults.placeholder};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'placeholder', 'allNoneButtons', 'maxLength', 'maxLengthHtml', 'allText', 'noneText', 'iconCheckmark', 'autoClose', 'id', 'sort', 'caretHtml', 'prefixClass', 'prefixEvent'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'allNoneButtons', 'sort'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Only parse data-multiple. Angular sets existence attributes to true (multiple/required/etc), they apply this\n // to data-multiple as well for some reason, so we'll parse this ourselves and disregard multiple\n var dataMultiple = element.attr('data-multiple');\n if(angular.isDefined(dataMultiple)) {\n if(falseValueRegExp.test(dataMultiple))\n options.multiple = false;\n else\n options.multiple = dataMultiple;\n }\n\n // Add support for select markup\n if(element[0].nodeName.toLowerCase() === 'select') {\n var inputEl = element;\n inputEl.css('display', 'none');\n element = angular.element('');\n inputEl.after(element);\n }\n\n // Build proper bsOptions\n var parsedOptions = $parseOptions(attr.bsOptions);\n\n // Initialize select\n var select = $select(element, controller, options);\n\n // Watch bsOptions values before filtering for changes\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').trim();\n scope.$watchCollection(watchedOptions, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue);\n parsedOptions.valuesFn(scope, controller)\n .then(function(values) {\n select.update(values);\n controller.$render();\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue);\n select.$updateActiveIndex();\n controller.$render();\n }, true);\n\n // Model rendering in view\n controller.$render = function () {\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n var selected, index;\n if(options.multiple && angular.isArray(controller.$modelValue)) {\n selected = controller.$modelValue.map(function(value) {\n index = select.$getIndex(value);\n return angular.isDefined(index) ? select.$scope.$matches[index].label : false;\n }).filter(angular.isDefined);\n if(selected.length > (options.maxLength || defaults.maxLength)) {\n selected = selected.length + ' ' + (options.maxLengthHtml || defaults.maxLengthHtml);\n } else {\n selected = selected.join(', ');\n }\n } else {\n index = select.$getIndex(controller.$modelValue);\n selected = angular.isDefined(index) ? select.$scope.$matches[index].label : false;\n }\n element.html((selected ? selected : options.placeholder) + (options.caretHtml ? options.caretHtml : defaults.caretHtml));\n };\n\n if(options.multiple){\n controller.$isEmpty = function(value){\n return !value || value.length === 0;\n };\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (select) select.destroy();\n options = null;\n select = null;\n });\n\n }\n };\n\n });\n\n// Source: timepicker/timepicker.js\nangular.module('mgcrea.ngStrap.timepicker', ['mgcrea.ngStrap.helpers.dateParser', 'mgcrea.ngStrap.helpers.dateFormatter', 'mgcrea.ngStrap.tooltip'])\n\n .provider('$timepicker', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n //uncommenting the following line will break backwards compatability\n // prefixEvent: 'timepicker',\n prefixClass: 'timepicker',\n placement: 'bottom-left',\n templateUrl: 'timepicker/timepicker.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n // lang: $locale.id,\n useNative: true,\n timeType: 'date',\n timeFormat: 'shortTime',\n timezone: null,\n modelTimeFormat: null,\n autoclose: false,\n minTime: -Infinity,\n maxTime: +Infinity,\n length: 5,\n hourStep: 1,\n minuteStep: 5,\n secondStep: 5,\n roundDisplay: false,\n iconUp: 'glyphicon glyphicon-chevron-up',\n iconDown: 'glyphicon glyphicon-chevron-down',\n arrowBehavior: 'pager'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) {\n\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if (!defaults.lang) {\n defaults.lang = $dateFormatter.getDefaultLocale();\n }\n\n function timepickerFactory(element, controller, config) {\n\n var $timepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $timepicker.$options;\n var scope = $timepicker.$scope;\n\n var lang = options.lang;\n var formatDate = function(date, format, timezone) {\n return $dateFormatter.formatDate(date, format, lang, timezone);\n };\n\n function floorMinutes(time) {\n // coeff used to floor current time to nearest minuteStep interval\n var coeff = 1000 * 60 * options.minuteStep;\n return new Date(Math.floor(time.getTime() / coeff) * coeff);\n }\n\n // View vars\n\n var selectedIndex = 0;\n var defaultDate = options.roundDisplay ? floorMinutes(new Date()) : new Date();\n var startDate = controller.$dateValue || defaultDate;\n var viewDate = {\n hour: startDate.getHours(),\n meridian: startDate.getHours() < 12,\n minute: startDate.getMinutes(),\n second: startDate.getSeconds(),\n millisecond: startDate.getMilliseconds()\n };\n\n var format = $dateFormatter.getDatetimeFormat(options.timeFormat, lang);\n\n var hoursFormat = $dateFormatter.hoursFormat(format),\n timeSeparator = $dateFormatter.timeSeparator(format),\n minutesFormat = $dateFormatter.minutesFormat(format),\n secondsFormat = $dateFormatter.secondsFormat(format),\n showSeconds = $dateFormatter.showSeconds(format),\n showAM = $dateFormatter.showAM(format);\n\n scope.$iconUp = options.iconUp;\n scope.$iconDown = options.iconDown;\n\n // Scope methods\n\n scope.$select = function(date, index) {\n $timepicker.select(date, index);\n };\n scope.$moveIndex = function(value, index) {\n $timepicker.$moveIndex(value, index);\n };\n scope.$switchMeridian = function(date) {\n $timepicker.switchMeridian(date);\n };\n\n // Public methods\n\n $timepicker.update = function(date) {\n // console.warn('$timepicker.update() newValue=%o', date);\n if (angular.isDate(date) && !isNaN(date.getTime())) {\n $timepicker.$date = date;\n angular.extend(viewDate, {\n hour: date.getHours(),\n minute: date.getMinutes(),\n second: date.getSeconds(),\n millisecond: date.getMilliseconds()\n });\n $timepicker.$build();\n } else if (!$timepicker.$isBuilt) {\n $timepicker.$build();\n }\n };\n\n $timepicker.select = function(date, index, keep) {\n // console.warn('$timepicker.select', date, scope.$mode);\n if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) controller.$dateValue = new Date(1970, 0, 1);\n if (!angular.isDate(date)) date = new Date(date);\n if (index === 0) controller.$dateValue.setHours(date.getHours());\n else if (index === 1) controller.$dateValue.setMinutes(date.getMinutes());\n else if (index === 2) controller.$dateValue.setSeconds(date.getSeconds());\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n if (options.autoclose && !keep) {\n $timeout(function() {\n $timepicker.hide(true);\n });\n }\n };\n\n $timepicker.switchMeridian = function(date) {\n if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) {\n return;\n }\n var hours = (date || controller.$dateValue).getHours();\n controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12);\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n };\n\n // Protected methods\n\n $timepicker.$build = function() {\n // console.warn('$timepicker.$build() viewDate=%o', viewDate);\n var i, midIndex = scope.midIndex = parseInt(options.length / 2, 10);\n var hours = [],\n hour;\n for (i = 0; i < options.length; i++) {\n hour = new Date(1970, 0, 1, viewDate.hour - (midIndex - i) * options.hourStep);\n hours.push({\n date: hour,\n label: formatDate(hour, hoursFormat),\n selected: $timepicker.$date && $timepicker.$isSelected(hour, 0),\n disabled: $timepicker.$isDisabled(hour, 0)\n });\n }\n var minutes = [],\n minute;\n for (i = 0; i < options.length; i++) {\n minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep);\n minutes.push({\n date: minute,\n label: formatDate(minute, minutesFormat),\n selected: $timepicker.$date && $timepicker.$isSelected(minute, 1),\n disabled: $timepicker.$isDisabled(minute, 1)\n });\n }\n var seconds = [],\n second;\n for (i = 0; i < options.length; i++) {\n second = new Date(1970, 0, 1, 0, 0, viewDate.second - (midIndex - i) * options.secondStep);\n seconds.push({\n date: second,\n label: formatDate(second, secondsFormat),\n selected: $timepicker.$date && $timepicker.$isSelected(second, 2),\n disabled: $timepicker.$isDisabled(second, 2)\n });\n }\n\n var rows = [];\n for (i = 0; i < options.length; i++) {\n if (showSeconds) {\n rows.push([hours[i], minutes[i], seconds[i]]);\n } else {\n rows.push([hours[i], minutes[i]]);\n }\n }\n scope.rows = rows;\n scope.showSeconds = showSeconds;\n scope.showAM = showAM;\n scope.isAM = ($timepicker.$date || hours[midIndex].date).getHours() < 12;\n scope.timeSeparator = timeSeparator;\n $timepicker.$isBuilt = true;\n };\n\n $timepicker.$isSelected = function(date, index) {\n if (!$timepicker.$date) return false;\n else if (index === 0) {\n return date.getHours() === $timepicker.$date.getHours();\n } else if (index === 1) {\n return date.getMinutes() === $timepicker.$date.getMinutes();\n } else if (index === 2) {\n return date.getSeconds() === $timepicker.$date.getSeconds();\n }\n };\n\n $timepicker.$isDisabled = function(date, index) {\n var selectedTime;\n if (index === 0) {\n selectedTime = date.getTime() + viewDate.minute * 6e4 + viewDate.second * 1e3;\n } else if (index === 1) {\n selectedTime = date.getTime() + viewDate.hour * 36e5 + viewDate.second * 1e3;\n } else if (index === 2) {\n selectedTime = date.getTime() + viewDate.hour * 36e5 + viewDate.minute * 6e4;\n }\n return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1;\n };\n\n scope.$arrowAction = function(value, index) {\n if (options.arrowBehavior === 'picker') {\n $timepicker.$setTimeByStep(value, index);\n } else {\n $timepicker.$moveIndex(value, index);\n }\n };\n\n $timepicker.$setTimeByStep = function(value, index) {\n var newDate = new Date($timepicker.$date || startDate);\n var hours = newDate.getHours();\n var minutes = newDate.getMinutes();\n var seconds = newDate.getSeconds();\n if (index === 0) {\n newDate.setHours(hours - (parseInt(options.hourStep, 10) * value));\n } else if (index === 1) {\n newDate.setMinutes(minutes - (parseInt(options.minuteStep, 10) * value));\n } else if (index === 2) {\n newDate.setSeconds(seconds - (parseInt(options.secondStep, 10) * value));\n }\n $timepicker.select(newDate, index, true);\n };\n\n $timepicker.$moveIndex = function(value, index) {\n var targetDate;\n if (index === 0) {\n targetDate = new Date(1970, 0, 1, viewDate.hour + (value * options.length), viewDate.minute, viewDate.second);\n angular.extend(viewDate, {\n hour: targetDate.getHours()\n });\n } else if (index === 1) {\n targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + (value * options.length * options.minuteStep), viewDate.second);\n angular.extend(viewDate, {\n minute: targetDate.getMinutes()\n });\n } else if (index === 2) {\n targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute, viewDate.second + (value * options.length * options.secondStep));\n angular.extend(viewDate, {\n second: targetDate.getSeconds()\n });\n }\n $timepicker.$build();\n };\n\n $timepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n if (evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if (isTouch) {\n var targetEl = angular.element(evt.target);\n if (targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $timepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // Close on enter\n if (evt.keyCode === 13) {\n $timepicker.hide(true);\n return;\n }\n\n // Navigate with keyboard\n var newDate = new Date($timepicker.$date);\n var hours = newDate.getHours(),\n hoursLength = formatDate(newDate, hoursFormat).length;\n var minutes = newDate.getMinutes(),\n minutesLength = formatDate(newDate, minutesFormat).length;\n var seconds = newDate.getSeconds(),\n secondsLength = formatDate(newDate, secondsFormat).length;\n var sepLength = 1;\n var lateralMove = /(37|39)/.test(evt.keyCode);\n var count = 2 + showSeconds * 1 + showAM * 1;\n\n // Navigate indexes (left, right)\n if (lateralMove) {\n if (evt.keyCode === 37) selectedIndex = selectedIndex < 1 ? count - 1 : selectedIndex - 1;\n else if (evt.keyCode === 39) selectedIndex = selectedIndex < count - 1 ? selectedIndex + 1 : 0;\n }\n\n // Update values (up, down)\n var selectRange = [0, hoursLength];\n var incr = 0;\n if (evt.keyCode === 38) incr = -1;\n if (evt.keyCode === 40) incr = +1;\n var isSeconds = selectedIndex === 2 && showSeconds;\n var isMeridian = selectedIndex === 2 && !showSeconds || selectedIndex === 3 && showSeconds;\n if (selectedIndex === 0) {\n newDate.setHours(hours + incr * parseInt(options.hourStep, 10));\n // re-calculate hours length because we have changed hours value\n hoursLength = formatDate(newDate, hoursFormat).length;\n selectRange = [0, hoursLength];\n } else if (selectedIndex === 1) {\n newDate.setMinutes(minutes + incr * parseInt(options.minuteStep, 10));\n // re-calculate minutes length because we have changes minutes value\n minutesLength = formatDate(newDate, minutesFormat).length;\n selectRange = [hoursLength + sepLength, minutesLength];\n } else if (isSeconds) {\n newDate.setSeconds(seconds + incr * parseInt(options.secondStep, 10));\n // re-calculate seconds length because we have changes seconds value\n secondsLength = formatDate(newDate, secondsFormat).length;\n selectRange = [hoursLength + sepLength + minutesLength + sepLength, secondsLength];\n } else if (isMeridian) {\n if (!lateralMove) $timepicker.switchMeridian();\n selectRange = [hoursLength + sepLength + minutesLength + sepLength + (secondsLength + sepLength) * showSeconds, 2];\n }\n $timepicker.select(newDate, selectedIndex, true);\n createSelection(selectRange[0], selectRange[1]);\n parentScope.$digest();\n };\n\n // Private\n\n function createSelection(start, length) {\n var end = start + length;\n if (element[0].createTextRange) {\n var selRange = element[0].createTextRange();\n selRange.collapse(true);\n selRange.moveStart('character', start);\n selRange.moveEnd('character', end);\n selRange.select();\n } else if (element[0].setSelectionRange) {\n element[0].setSelectionRange(start, end);\n } else if (angular.isUndefined(element[0].selectionStart)) {\n element[0].selectionStart = start;\n element[0].selectionEnd = end;\n }\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $timepicker.init;\n $timepicker.init = function() {\n if (isNative && options.useNative) {\n element.prop('type', 'time');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if (isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $timepicker.destroy;\n $timepicker.destroy = function() {\n if (isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $timepicker.show;\n $timepicker.show = function() {\n if((!isTouch && element.attr('readonly')) || element.attr('disabled')) return;\n _show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n $timepicker.$element && $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if (options.keyboard) {\n element && element.on('keydown', $timepicker.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $timepicker.hide;\n $timepicker.hide = function(blur) {\n if (!$timepicker.$isShown) return;\n $timepicker.$element && $timepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if (options.keyboard) {\n element && element.off('keydown', $timepicker.$onKeyDown);\n }\n _hide(blur);\n };\n\n return $timepicker;\n\n }\n\n timepickerFactory.defaults = defaults;\n return timepickerFactory;\n\n };\n\n })\n\n\n .directive('bsTimepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) {\n\n var defaults = $timepicker.defaults;\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {\n scope: scope\n };\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'autoclose', 'timeType', 'timeFormat', 'timezone', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'secondStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown', 'roundDisplay', 'id', 'prefixClass', 'prefixEvent'], function(key) {\n if (angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'autoclose', 'useNative', 'roundDisplay'], function(key) {\n if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if (!timepicker || !angular.isDefined(newValue)) return;\n if (angular.isString(newValue)) newValue = !!newValue.match(/true|,?(timepicker),?/i);\n newValue === true ? timepicker.show() : timepicker.hide();\n });\n\n // Initialize timepicker\n if (isNative && (options.useNative || defaults.useNative)) options.timeFormat = 'HH:mm';\n var timepicker = $timepicker(element, controller, options);\n options = timepicker.$options;\n\n var lang = options.lang;\n var formatDate = function(date, format, timezone) {\n return $dateFormatter.formatDate(date, format, lang, timezone);\n };\n\n // Initialize parser\n var dateParser = $dateParser({\n format: options.timeFormat,\n lang: lang\n });\n\n // Observe attributes for changes\n angular.forEach(['minTime', 'maxTime'], function(key) {\n // console.warn('attr.$observe(%s)', key, attr[key]);\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\n timepicker.$options[key] = dateParser.getTimeForAttribute(key, newValue);\n !isNaN(timepicker.$options[key]) && timepicker.$build();\n validateAgainstMinMaxTime(controller.$dateValue);\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue, controller.$dateValue);\n timepicker.update(controller.$dateValue);\n }, true);\n\n function validateAgainstMinMaxTime(parsedTime) {\n if (!angular.isDate(parsedTime)) return;\n var isMinValid = isNaN(options.minTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) >= options.minTime;\n var isMaxValid = isNaN(options.maxTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) <= options.maxTime;\n var isValid = isMinValid && isMaxValid;\n controller.$setValidity('date', isValid);\n controller.$setValidity('min', isMinValid);\n controller.$setValidity('max', isMaxValid);\n // Only update the model when we have a valid date\n if (!isValid) {\n return;\n }\n controller.$dateValue = parsedTime;\n }\n\n // viewValue -> $parsers -> modelValue\n controller.$parsers.unshift(function(viewValue) {\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\n var date;\n // Null values should correctly reset the model value & validity\n if (!viewValue) {\n // BREAKING CHANGE:\n // return null (not undefined) when input value is empty, so angularjs 1.3\n // ngModelController can go ahead and run validators, like ngRequired\n controller.$setValidity('date', true);\n return null;\n }\n var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue);\n if (!parsedTime || isNaN(parsedTime.getTime())) {\n controller.$setValidity('date', false);\n // Return undefined, causes ngModelController to\n // invalidate model value\n return undefined;\n } else {\n validateAgainstMinMaxTime(parsedTime);\n }\n\n if (options.timeType === 'string') {\n date = dateParser.timezoneOffsetAdjust(parsedTime, options.timezone, true);\n return formatDate(date, options.modelTimeFormat || options.timeFormat);\n }\n date = dateParser.timezoneOffsetAdjust(controller.$dateValue, options.timezone, true);\n if (options.timeType === 'number') {\n return date.getTime();\n } else if (options.timeType === 'unix') {\n return date.getTime() / 1000;\n } else if (options.timeType === 'iso') {\n return date.toISOString();\n } else {\n return new Date(date);\n }\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var date;\n if (angular.isUndefined(modelValue) || modelValue === null) {\n date = NaN;\n } else if (angular.isDate(modelValue)) {\n date = modelValue;\n } else if (options.timeType === 'string') {\n date = dateParser.parse(modelValue, null, options.modelTimeFormat);\n } else if (options.timeType === 'unix') {\n date = new Date(modelValue * 1000);\n } else {\n date = new Date(modelValue);\n }\n // Setup default value?\n // if(isNaN(date.getTime())) date = new Date(new Date().setMinutes(0) + 36e5);\n controller.$dateValue = dateParser.timezoneOffsetAdjust(date, options.timezone);\n return getTimeFormattedString();\n });\n\n // viewValue -> element\n controller.$render = function() {\n // console.warn('$render(\"%s\"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);\n element.val(getTimeFormattedString());\n };\n\n function getTimeFormattedString() {\n return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat);\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (timepicker) timepicker.destroy();\n options = null;\n timepicker = null;\n });\n\n }\n };\n\n });\n\n// Source: tab/tab.js\nangular.module('mgcrea.ngStrap.tab', [])\n\n .provider('$tab', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n template: 'tab/tab.tpl.html',\n navClass: 'nav-tabs',\n activeClass: 'active'\n };\n\n var controller = this.controller = function($scope, $element, $attrs) {\n var self = this;\n\n // Attributes options\n self.$options = angular.copy(defaults);\n angular.forEach(['animation', 'navClass', 'activeClass'], function(key) {\n if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];\n });\n\n // Publish options on scope\n $scope.$navClass = self.$options.navClass;\n $scope.$activeClass = self.$options.activeClass;\n\n self.$panes = $scope.$panes = [];\n\n // Please use $activePaneChangeListeners if you use `bsActivePane`\n // Because we removed `ngModel` as default, we rename viewChangeListeners to\n // activePaneChangeListeners to make more sense.\n self.$activePaneChangeListeners = self.$viewChangeListeners = [];\n\n self.$push = function(pane) {\n if(angular.isUndefined(self.$panes.$active)) {\n $scope.$setActive(pane.name || 0);\n }\n self.$panes.push(pane);\n };\n\n self.$remove = function(pane) {\n var index = self.$panes.indexOf(pane);\n var active = self.$panes.$active;\n var activeIndex;\n if(angular.isString(active)) {\n activeIndex = self.$panes.map(function(pane) {\n return pane.name;\n }).indexOf(active);\n } else {\n activeIndex = self.$panes.$active;\n }\n\n // remove pane from $panes array\n self.$panes.splice(index, 1);\n\n if (index < activeIndex) {\n // we removed a pane before the active pane, so we need to\n // decrement the active pane index\n activeIndex--;\n }\n else if (index === activeIndex && activeIndex === self.$panes.length) {\n // we remove the active pane and it was the one at the end,\n // so select the previous one\n activeIndex--;\n }\n if(activeIndex >= 0 && activeIndex < self.$panes.length) {\n self.$setActive(self.$panes[activeIndex].name || activeIndex);\n } else {\n self.$setActive();\n }\n };\n\n self.$setActive = $scope.$setActive = function(value) {\n self.$panes.$active = value;\n self.$activePaneChangeListeners.forEach(function(fn) {\n fn();\n });\n };\n\n self.$isActive = $scope.$isActive = function($pane, $index) {\n return self.$panes.$active === $pane.name || self.$panes.$active === $index;\n };\n\n };\n\n this.$get = function() {\n var $tab = {};\n $tab.defaults = defaults;\n $tab.controller = controller;\n return $tab;\n };\n\n })\n\n .directive('bsTabs', function($window, $animate, $tab, $parse) {\n\n var defaults = $tab.defaults;\n\n return {\n require: ['?ngModel', 'bsTabs'],\n transclude: true,\n scope: true,\n controller: ['$scope', '$element', '$attrs', $tab.controller],\n templateUrl: function(element, attr) {\n return attr.template || defaults.template;\n },\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsTabsCtrl = controllers[1];\n\n // 'ngModel' does interfere with form validation\n // and status, use `bsActivePane` instead to avoid it\n if(ngModelCtrl) {\n\n // Update the modelValue following\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\n ngModelCtrl.$setViewValue(bsTabsCtrl.$panes.$active);\n });\n\n // modelValue -> $formatters -> viewValue\n ngModelCtrl.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n bsTabsCtrl.$setActive(modelValue);\n return modelValue;\n });\n\n }\n\n if (attrs.bsActivePane) {\n // adapted from angularjs ngModelController bindings\n // https://github.com/angular/angular.js/blob/v1.3.1/src%2Fng%2Fdirective%2Finput.js#L1730\n var parsedBsActivePane = $parse(attrs.bsActivePane);\n\n // Update bsActivePane value with change\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\n parsedBsActivePane.assign(scope, bsTabsCtrl.$panes.$active);\n });\n\n // watch bsActivePane for value changes\n scope.$watch(attrs.bsActivePane, function(newValue, oldValue) {\n bsTabsCtrl.$setActive(newValue);\n }, true);\n }\n }\n };\n\n })\n\n .directive('bsPane', function($window, $animate, $sce) {\n\n return {\n require: ['^?ngModel', '^bsTabs'],\n scope: true,\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsTabsCtrl = controllers[1];\n\n // Add base class\n element.addClass('tab-pane');\n\n // Observe title attribute for change\n attrs.$observe('title', function(newValue, oldValue) {\n scope.title = $sce.trustAsHtml(newValue);\n });\n\n // Save tab name into scope\n scope.name = attrs.name;\n\n // Add animation class\n if(bsTabsCtrl.$options.animation) {\n element.addClass(bsTabsCtrl.$options.animation);\n }\n\n attrs.$observe('disabled', function(newValue, oldValue) {\n scope.disabled = scope.$eval(newValue);\n });\n\n // Push pane to parent bsTabs controller\n bsTabsCtrl.$push(scope);\n\n // remove pane from tab controller when pane is destroyed\n scope.$on('$destroy', function() {\n bsTabsCtrl.$remove(scope);\n });\n\n function render() {\n var index = bsTabsCtrl.$panes.indexOf(scope);\n $animate[bsTabsCtrl.$isActive(scope, index) ? 'addClass' : 'removeClass'](element, bsTabsCtrl.$options.activeClass);\n }\n\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\n render();\n });\n render();\n\n }\n };\n\n });\n\n// Source: typeahead/typeahead.js\nangular.module('mgcrea.ngStrap.typeahead', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions'])\n\n .provider('$typeahead', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'typeahead',\n prefixEvent: '$typeahead',\n placement: 'bottom-left',\n templateUrl: 'typeahead/typeahead.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n minLength: 1,\n filter: 'bsAsyncFilter',\n limit: 6,\n autoSelect: false,\n comparator: '',\n trimValue: true\n };\n\n this.$get = function($window, $rootScope, $tooltip, $$rAF, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n\n function TypeaheadFactory(element, controller, config) {\n\n var $typeahead = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $typeahead = $tooltip(element, options);\n var parentScope = config.scope;\n var scope = $typeahead.$scope;\n\n scope.$resetMatches = function() {\n scope.$matches = [];\n scope.$activeIndex = options.autoSelect ? 0 : -1; // If set to 0, the first match will be highlighted\n };\n scope.$resetMatches();\n\n scope.$activate = function(index) {\n scope.$$postDigest(function() {\n $typeahead.activate(index);\n });\n };\n\n scope.$select = function(index, evt) {\n scope.$$postDigest(function() {\n $typeahead.select(index);\n });\n };\n\n scope.$isVisible = function() {\n return $typeahead.$isVisible();\n };\n\n // Public methods\n\n $typeahead.update = function(matches) {\n scope.$matches = matches;\n if (scope.$activeIndex >= matches.length) {\n scope.$activeIndex = options.autoSelect ? 0 : -1;\n }\n\n // wrap in a $timeout so the results are updated\n // before repositioning\n safeDigest(scope);\n $$rAF($typeahead.$applyPlacement);\n };\n\n $typeahead.activate = function(index) {\n scope.$activeIndex = index;\n };\n\n $typeahead.select = function(index) {\n if (index === -1) return;\n var value = scope.$matches[index].value;\n // console.log('$setViewValue', value);\n controller.$setViewValue(value);\n controller.$render();\n scope.$resetMatches();\n if (parentScope) parentScope.$digest();\n // Emit event\n scope.$emit(options.prefixEvent + '.select', value, index, $typeahead);\n };\n\n // Protected methods\n\n $typeahead.$isVisible = function() {\n if (!options.minLength || !controller) {\n return !!scope.$matches.length;\n }\n // minLength support\n return scope.$matches.length && angular.isString(controller.$viewValue) && controller.$viewValue.length >= options.minLength;\n };\n\n $typeahead.$getIndex = function(value) {\n var l = scope.$matches.length,\n i = l;\n if (!l) return;\n for (i = l; i--;) {\n if (scope.$matches[i].value === value) break;\n }\n if (i < 0) return;\n return i;\n };\n\n $typeahead.$onMouseDown = function(evt) {\n // Prevent blur on mousedown\n evt.preventDefault();\n evt.stopPropagation();\n };\n\n $typeahead.$onKeyDown = function(evt) {\n if (!/(38|40|13)/.test(evt.keyCode)) return;\n\n // Let ngSubmit pass if the typeahead tip is hidden or no option is selected\n if ($typeahead.$isVisible() && !(evt.keyCode === 13 && scope.$activeIndex === -1)) {\n evt.preventDefault();\n evt.stopPropagation();\n }\n\n // Select with enter\n if (evt.keyCode === 13 && scope.$matches.length) {\n $typeahead.select(scope.$activeIndex);\n }\n\n // Navigate with keyboard\n else if (evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--;\n else if (evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++;\n else if (angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0;\n scope.$digest();\n };\n\n // Overrides\n\n var show = $typeahead.show;\n $typeahead.show = function() {\n show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed immediately.\n $timeout(function() {\n $typeahead.$element && $typeahead.$element.on('mousedown', $typeahead.$onMouseDown);\n if (options.keyboard) {\n element && element.on('keydown', $typeahead.$onKeyDown);\n }\n }, 0, false);\n };\n\n var hide = $typeahead.hide;\n $typeahead.hide = function() {\n $typeahead.$element && $typeahead.$element.off('mousedown', $typeahead.$onMouseDown);\n if (options.keyboard) {\n element && element.off('keydown', $typeahead.$onKeyDown);\n }\n if (!options.autoSelect)\n $typeahead.activate(-1);\n hide();\n };\n\n return $typeahead;\n\n }\n\n // Helper functions\n\n function safeDigest(scope) {\n scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();\n }\n\n TypeaheadFactory.defaults = defaults;\n return TypeaheadFactory;\n\n };\n\n })\n\n .filter('bsAsyncFilter', function($filter) {\n return function(array, expression, comparator) {\n if (array && angular.isFunction(array.then)) {\n return array.then(function(results) {\n return $filter('filter')(results, expression, comparator);\n });\n } else {\n return $filter('filter')(array, expression, comparator);\n }\n };\n })\n\n .directive('bsTypeahead', function($window, $parse, $q, $typeahead, $parseOptions) {\n\n var defaults = $typeahead.defaults;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {\n scope: scope\n };\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'filter', 'limit', 'minLength', 'watchOptions', 'selectMode', 'autoSelect', 'comparator', 'id', 'prefixEvent', 'prefixClass'], function(key) {\n if (angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'trimValue'], function(key) {\n if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false;\n });\n\n // Disable browser autocompletion\n element.attr('autocomplete', 'false');\n\n // Build proper bsOptions\n var filter = options.filter || defaults.filter;\n var limit = options.limit || defaults.limit;\n var comparator = options.comparator || defaults.comparator;\n\n var bsOptions = attr.bsOptions;\n if (filter) bsOptions += ' | ' + filter + ':$viewValue';\n if (comparator) bsOptions += ':' + comparator;\n if (limit) bsOptions += ' | limitTo:' + limit;\n var parsedOptions = $parseOptions(bsOptions);\n\n // Initialize typeahead\n var typeahead = $typeahead(element, controller, options);\n\n // Watch options on demand\n if (options.watchOptions) {\n // Watch bsOptions values before filtering for changes, drop function calls\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').replace(/\\(.*\\)/g, '').trim();\n scope.$watchCollection(watchedOptions, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue);\n parsedOptions.valuesFn(scope, controller).then(function(values) {\n typeahead.update(values);\n controller.$render();\n });\n });\n }\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('$watch', element.attr('ng-model'), newValue);\n scope.$modelValue = newValue; // Publish modelValue on scope for custom templates\n parsedOptions.valuesFn(scope, controller)\n .then(function(values) {\n // Prevent input with no future prospect if selectMode is truthy\n // @TODO test selectMode\n if (options.selectMode && !values.length && newValue.length > 0) {\n controller.$setViewValue(controller.$viewValue.substring(0, controller.$viewValue.length - 1));\n return;\n }\n if (values.length > limit) values = values.slice(0, limit);\n var isVisible = typeahead.$isVisible();\n isVisible && typeahead.update(values);\n // Do not re-queue an update if a correct value has been selected\n if (values.length === 1 && values[0].value === newValue) return;\n !isVisible && typeahead.update(values);\n // Queue a new rendering that will leverage collection loading\n controller.$render();\n });\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var displayValue = parsedOptions.displayValue(modelValue);\n\n // If we can determine the displayValue, use that\n if (displayValue) {\n return displayValue;\n }\n\n // If there's no display value, attempt to use the modelValue.\n // If the model is an object not much we can do\n if (modelValue && typeof modelValue !== 'object') {\n return modelValue;\n }\n return '';\n });\n\n // Model rendering in view\n controller.$render = function() {\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n if (controller.$isEmpty(controller.$viewValue)) {\n return element.val('');\n }\n var index = typeahead.$getIndex(controller.$modelValue);\n var selected = angular.isDefined(index) ? typeahead.$scope.$matches[index].label : controller.$viewValue;\n selected = angular.isObject(selected) ? parsedOptions.displayValue(selected) : selected;\n var value = selected ? selected.toString().replace(/<(?:.|\\n)*?>/gm, '') : '';\n element.val(options.trimValue === false ? value : value.trim());\n };\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (typeahead) typeahead.destroy();\n options = null;\n typeahead = null;\n });\n\n }\n };\n\n });\n\n// Source: tooltip/tooltip.js\nangular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.core', 'mgcrea.ngStrap.helpers.dimensions'])\n\n .provider('$tooltip', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n customClass: '',\n prefixClass: 'tooltip',\n prefixEvent: 'tooltip',\n container: false,\n target: false,\n placement: 'top',\n templateUrl: 'tooltip/tooltip.tpl.html',\n template: '',\n contentTemplate: false,\n trigger: 'hover focus',\n keyboard: false,\n html: false,\n show: false,\n title: '',\n type: '',\n delay: 0,\n autoClose: false,\n bsEnabled: true,\n viewport: {\n selector: 'body',\n padding: 0\n }\n };\n\n this.$get = function($window, $rootScope, $bsCompiler, $q, $templateCache, $http, $animate, $sce, dimensions, $$rAF, $timeout) {\n\n var trim = String.prototype.trim;\n var isTouch = 'createTouch' in $window.document;\n var htmlReplaceRegExp = /ng-bind=\"/ig;\n var $body = angular.element($window.document);\n\n function TooltipFactory(element, config) {\n\n var $tooltip = {};\n\n // Common vars\n var options = $tooltip.$options = angular.extend({}, defaults, config);\n var promise = $tooltip.$promise = $bsCompiler.compile(options);\n var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new();\n\n var nodeName = element[0].nodeName.toLowerCase();\n if(options.delay && angular.isString(options.delay)) {\n var split = options.delay.split(',').map(parseFloat);\n options.delay = split.length > 1 ? {show: split[0], hide: split[1]} : split[0];\n }\n\n // Store $id to identify the triggering element in events\n // give priority to options.id, otherwise, try to use\n // element id if defined\n $tooltip.$id = options.id || element.attr('id') || '';\n\n // Support scope as string options\n if(options.title) {\n scope.title = $sce.trustAsHtml(options.title);\n }\n\n // Provide scope helpers\n scope.$setEnabled = function(isEnabled) {\n scope.$$postDigest(function() {\n $tooltip.setEnabled(isEnabled);\n });\n };\n scope.$hide = function() {\n scope.$$postDigest(function() {\n $tooltip.hide();\n });\n };\n scope.$show = function() {\n scope.$$postDigest(function() {\n $tooltip.show();\n });\n };\n scope.$toggle = function() {\n scope.$$postDigest(function() {\n $tooltip.toggle();\n });\n };\n // Publish isShown as a protected var on scope\n $tooltip.$isShown = scope.$isShown = false;\n\n // Private vars\n var timeout, hoverState;\n\n // Fetch, compile then initialize tooltip\n var compileData, tipElement, tipContainer, tipScope;\n promise.then(function(data) {\n compileData = data;\n $tooltip.init();\n });\n\n $tooltip.init = function() {\n\n // Options: delay\n if (options.delay && angular.isNumber(options.delay)) {\n options.delay = {\n show: options.delay,\n hide: options.delay\n };\n }\n\n // Replace trigger on touch devices ?\n // if(isTouch && options.trigger === defaults.trigger) {\n // options.trigger.replace(/hover/g, 'click');\n // }\n\n // Options : container\n if(options.container === 'self') {\n tipContainer = element;\n } else if(angular.isElement(options.container)) {\n tipContainer = options.container;\n } else if(options.container) {\n tipContainer = findElement(options.container);\n }\n\n // Options: trigger\n bindTriggerEvents();\n\n // Options: target\n if(options.target) {\n options.target = angular.isElement(options.target) ? options.target : findElement(options.target);\n }\n\n // Options: show\n if(options.show) {\n scope.$$postDigest(function() {\n options.trigger === 'focus' ? element[0].focus() : $tooltip.show();\n });\n }\n\n };\n\n $tooltip.destroy = function() {\n\n // Unbind events\n unbindTriggerEvents();\n\n // Remove element\n destroyTipElement();\n\n // Destroy scope\n scope.$destroy();\n\n };\n\n $tooltip.enter = function() {\n\n clearTimeout(timeout);\n hoverState = 'in';\n if (!options.delay || !options.delay.show) {\n return $tooltip.show();\n }\n\n timeout = setTimeout(function() {\n if (hoverState ==='in') $tooltip.show();\n }, options.delay.show);\n\n };\n\n $tooltip.show = function() {\n if (!options.bsEnabled || $tooltip.$isShown) return;\n\n scope.$emit(options.prefixEvent + '.show.before', $tooltip);\n var parent, after;\n if (options.container) {\n parent = tipContainer;\n if (tipContainer[0].lastChild) {\n after = angular.element(tipContainer[0].lastChild);\n } else {\n after = null;\n }\n } else {\n parent = null;\n after = element;\n }\n\n\n // Hide any existing tipElement\n if(tipElement) destroyTipElement();\n // Fetch a cloned element linked from template\n tipScope = $tooltip.$scope.$new();\n tipElement = $tooltip.$element = compileData.link(tipScope, function(clonedElement, scope) {});\n\n // Set the initial positioning. Make the tooltip invisible\n // so IE doesn't try to focus on it off screen.\n tipElement.css({top: '-9999px', left: '-9999px', right: 'auto', display: 'block', visibility: 'hidden'});\n\n // Options: animation\n if(options.animation) tipElement.addClass(options.animation);\n // Options: type\n if(options.type) tipElement.addClass(options.prefixClass + '-' + options.type);\n // Options: custom classes\n if(options.customClass) tipElement.addClass(options.customClass);\n\n // Append the element, without any animations. If we append\n // using $animate.enter, some of the animations cause the placement\n // to be off due to the transforms.\n after ? after.after(tipElement) : parent.prepend(tipElement);\n\n $tooltip.$isShown = scope.$isShown = true;\n safeDigest(scope);\n\n // Now, apply placement\n $tooltip.$applyPlacement();\n\n // Once placed, animate it.\n // Support v1.2+ $animate\n // https://github.com/angular/angular.js/issues/11713\n if(angular.version.minor <= 2) {\n $animate.enter(tipElement, parent, after, enterAnimateCallback);\n } else {\n $animate.enter(tipElement, parent, after).then(enterAnimateCallback);\n }\n safeDigest(scope);\n\n $$rAF(function () {\n // Once the tooltip is placed and the animation starts, make the tooltip visible\n if(tipElement) tipElement.css({visibility: 'visible'});\n });\n\n // Bind events\n if(options.keyboard) {\n if(options.trigger !== 'focus') {\n $tooltip.focus();\n }\n bindKeyboardEvents();\n }\n\n if(options.autoClose) {\n bindAutoCloseEvents();\n }\n\n };\n\n function enterAnimateCallback() {\n scope.$emit(options.prefixEvent + '.show', $tooltip);\n }\n\n $tooltip.leave = function() {\n\n clearTimeout(timeout);\n hoverState = 'out';\n if (!options.delay || !options.delay.hide) {\n return $tooltip.hide();\n }\n timeout = setTimeout(function () {\n if (hoverState === 'out') {\n $tooltip.hide();\n }\n }, options.delay.hide);\n\n };\n\n var _blur;\n var _tipToHide;\n $tooltip.hide = function(blur) {\n\n if(!$tooltip.$isShown) return;\n scope.$emit(options.prefixEvent + '.hide.before', $tooltip);\n\n // store blur value for leaveAnimateCallback to use\n _blur = blur;\n\n // store current tipElement reference to use\n // in leaveAnimateCallback\n _tipToHide = tipElement;\n\n // Support v1.2+ $animate\n // https://github.com/angular/angular.js/issues/11713\n if(angular.version.minor <= 2) {\n $animate.leave(tipElement, leaveAnimateCallback);\n } else {\n $animate.leave(tipElement).then(leaveAnimateCallback);\n }\n\n $tooltip.$isShown = scope.$isShown = false;\n safeDigest(scope);\n\n // Unbind events\n if(options.keyboard && tipElement !== null) {\n unbindKeyboardEvents();\n }\n\n if(options.autoClose && tipElement !== null) {\n unbindAutoCloseEvents();\n }\n };\n\n function leaveAnimateCallback() {\n scope.$emit(options.prefixEvent + '.hide', $tooltip);\n\n // check if current tipElement still references\n // the same element when hide was called\n if (tipElement === _tipToHide) {\n // Allow to blur the input when hidden, like when pressing enter key\n if(_blur && options.trigger === 'focus') {\n return element[0].blur();\n }\n\n // clean up child scopes\n destroyTipElement();\n }\n }\n\n $tooltip.toggle = function() {\n $tooltip.$isShown ? $tooltip.leave() : $tooltip.enter();\n };\n\n $tooltip.focus = function() {\n tipElement[0].focus();\n };\n\n $tooltip.setEnabled = function(isEnabled) {\n options.bsEnabled = isEnabled;\n };\n\n $tooltip.setViewport = function(viewport) {\n options.viewport = viewport;\n };\n\n // Protected methods\n\n $tooltip.$applyPlacement = function() {\n if(!tipElement) return;\n\n // Determine if we're doing an auto or normal placement\n var placement = options.placement,\n autoToken = /\\s?auto?\\s?/i,\n autoPlace = autoToken.test(placement);\n\n if (autoPlace) {\n placement = placement.replace(autoToken, '') || defaults.placement;\n }\n\n // Need to add the position class before we get\n // the offsets\n tipElement.addClass(options.placement);\n\n // Get the position of the target element\n // and the height and width of the tooltip so we can center it.\n var elementPosition = getPosition(),\n tipWidth = tipElement.prop('offsetWidth'),\n tipHeight = tipElement.prop('offsetHeight');\n\n // Refresh viewport position\n $tooltip.$viewport = options.viewport && findElement(options.viewport.selector || options.viewport);\n\n // If we're auto placing, we need to check the positioning\n if (autoPlace) {\n var originalPlacement = placement;\n var viewportPosition = getPosition($tooltip.$viewport);\n\n // Determine if the vertical placement\n if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > viewportPosition.bottom) {\n placement = originalPlacement.replace('bottom', 'top');\n } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < viewportPosition.top) {\n placement = originalPlacement.replace('top', 'bottom');\n }\n\n // Determine the horizontal placement\n // The exotic placements of left and right are opposite of the standard placements. Their arrows are put on the left/right\n // and flow in the opposite direction of their placement.\n if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') &&\n elementPosition.right + tipWidth > viewportPosition.width) {\n\n placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right');\n } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') &&\n elementPosition.left - tipWidth < viewportPosition.left) {\n\n placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left');\n }\n\n tipElement.removeClass(originalPlacement).addClass(placement);\n }\n\n // Get the tooltip's top and left coordinates to center it with this directive.\n var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight);\n applyPlacement(tipPosition, placement);\n };\n\n $tooltip.$onKeyUp = function(evt) {\n if (evt.which === 27 && $tooltip.$isShown) {\n $tooltip.hide();\n evt.stopPropagation();\n }\n };\n\n $tooltip.$onFocusKeyUp = function(evt) {\n if (evt.which === 27) {\n element[0].blur();\n evt.stopPropagation();\n }\n };\n\n $tooltip.$onFocusElementMouseDown = function(evt) {\n evt.preventDefault();\n evt.stopPropagation();\n // Some browsers do not auto-focus buttons (eg. Safari)\n $tooltip.$isShown ? element[0].blur() : element[0].focus();\n };\n\n // bind/unbind events\n function bindTriggerEvents() {\n var triggers = options.trigger.split(' ');\n angular.forEach(triggers, function(trigger) {\n if(trigger === 'click') {\n element.on('click', $tooltip.toggle);\n } else if(trigger !== 'manual') {\n element.on(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);\n element.on(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);\n nodeName === 'button' && trigger !== 'hover' && element.on(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);\n }\n });\n }\n\n function unbindTriggerEvents() {\n var triggers = options.trigger.split(' ');\n for (var i = triggers.length; i--;) {\n var trigger = triggers[i];\n if(trigger === 'click') {\n element.off('click', $tooltip.toggle);\n } else if(trigger !== 'manual') {\n element.off(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);\n element.off(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);\n nodeName === 'button' && trigger !== 'hover' && element.off(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);\n }\n }\n }\n\n function bindKeyboardEvents() {\n if(options.trigger !== 'focus') {\n tipElement.on('keyup', $tooltip.$onKeyUp);\n } else {\n element.on('keyup', $tooltip.$onFocusKeyUp);\n }\n }\n\n function unbindKeyboardEvents() {\n if(options.trigger !== 'focus') {\n tipElement.off('keyup', $tooltip.$onKeyUp);\n } else {\n element.off('keyup', $tooltip.$onFocusKeyUp);\n }\n }\n\n var _autoCloseEventsBinded = false;\n function bindAutoCloseEvents() {\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n // Stop propagation when clicking inside tooltip\n tipElement.on('click', stopEventPropagation);\n\n // Hide when clicking outside tooltip\n $body.on('click', $tooltip.hide);\n\n _autoCloseEventsBinded = true;\n }, 0, false);\n }\n\n function unbindAutoCloseEvents() {\n if (_autoCloseEventsBinded) {\n tipElement.off('click', stopEventPropagation);\n $body.off('click', $tooltip.hide);\n _autoCloseEventsBinded = false;\n }\n }\n\n function stopEventPropagation(event) {\n event.stopPropagation();\n }\n\n // Private methods\n\n function getPosition($element) {\n $element = $element || (options.target || element);\n\n var el = $element[0],\n isBody = el.tagName === 'BODY';\n\n var elRect = el.getBoundingClientRect();\n var rect = {};\n\n // IE8 has issues with angular.extend and using elRect directly.\n // By coping the values of elRect into a new object, we can continue to use extend\n for (var p in elRect) {\n // DO NOT use hasOwnProperty when inspecting the return of getBoundingClientRect.\n rect[p] = elRect[p];\n }\n\n if (rect.width === null) {\n // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093\n rect = angular.extend({}, rect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top });\n }\n var elOffset = isBody ? { top: 0, left: 0 } : dimensions.offset(el),\n scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.prop('scrollTop') || 0 },\n outerDims = isBody ? { width: document.documentElement.clientWidth, height: $window.innerHeight } : null;\n\n return angular.extend({}, rect, scroll, outerDims, elOffset);\n }\n\n function getCalculatedOffset(placement, position, actualWidth, actualHeight) {\n var offset;\n var split = placement.split('-');\n\n switch (split[0]) {\n case 'right':\n offset = {\n top: position.top + position.height / 2 - actualHeight / 2,\n left: position.left + position.width\n };\n break;\n case 'bottom':\n offset = {\n top: position.top + position.height,\n left: position.left + position.width / 2 - actualWidth / 2\n };\n break;\n case 'left':\n offset = {\n top: position.top + position.height / 2 - actualHeight / 2,\n left: position.left - actualWidth\n };\n break;\n default:\n offset = {\n top: position.top - actualHeight,\n left: position.left + position.width / 2 - actualWidth / 2\n };\n break;\n }\n\n if(!split[1]) {\n return offset;\n }\n\n // Add support for corners @todo css\n if(split[0] === 'top' || split[0] === 'bottom') {\n switch (split[1]) {\n case 'left':\n offset.left = position.left;\n break;\n case 'right':\n offset.left = position.left + position.width - actualWidth;\n }\n } else if(split[0] === 'left' || split[0] === 'right') {\n switch (split[1]) {\n case 'top':\n offset.top = position.top - actualHeight;\n break;\n case 'bottom':\n offset.top = position.top + position.height;\n }\n }\n\n return offset;\n }\n\n function applyPlacement(offset, placement) {\n var tip = tipElement[0],\n width = tip.offsetWidth,\n height = tip.offsetHeight;\n\n // manually read margins because getBoundingClientRect includes difference\n var marginTop = parseInt(dimensions.css(tip, 'margin-top'), 10),\n marginLeft = parseInt(dimensions.css(tip, 'margin-left'), 10);\n\n // we must check for NaN for ie 8/9\n if (isNaN(marginTop)) marginTop = 0;\n if (isNaN(marginLeft)) marginLeft = 0;\n\n offset.top = offset.top + marginTop;\n offset.left = offset.left + marginLeft;\n\n // dimensions setOffset doesn't round pixel values\n // so we use setOffset directly with our own function\n dimensions.setOffset(tip, angular.extend({\n using: function (props) {\n tipElement.css({\n top: Math.round(props.top) + 'px',\n left: Math.round(props.left) + 'px',\n right: ''\n });\n }\n }, offset), 0);\n\n // check to see if placing tip in new offset caused the tip to resize itself\n var actualWidth = tip.offsetWidth,\n actualHeight = tip.offsetHeight;\n\n if (placement === 'top' && actualHeight !== height) {\n offset.top = offset.top + height - actualHeight;\n }\n\n // If it's an exotic placement, exit now instead of\n // applying a delta and changing the arrow\n if (/top-left|top-right|bottom-left|bottom-right/.test(placement)) return;\n\n var delta = getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight);\n\n if (delta.left) {\n offset.left += delta.left;\n } else {\n offset.top += delta.top;\n }\n\n dimensions.setOffset(tip, offset);\n\n if (/top|right|bottom|left/.test(placement)) {\n var isVertical = /top|bottom/.test(placement),\n arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight,\n arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight';\n\n replaceArrow(arrowDelta, tip[arrowOffsetPosition], isVertical);\n }\n }\n\n // @source https://github.com/twbs/bootstrap/blob/v3.3.5/js/tooltip.js#L380\n function getViewportAdjustedDelta(placement, position, actualWidth, actualHeight) {\n var delta = {top: 0, left: 0};\n if (!$tooltip.$viewport) return delta;\n\n var viewportPadding = options.viewport && options.viewport.padding || 0;\n var viewportDimensions = getPosition($tooltip.$viewport);\n\n if (/right|left/.test(placement)) {\n var topEdgeOffset = position.top - viewportPadding - viewportDimensions.scroll;\n var bottomEdgeOffset = position.top + viewportPadding - viewportDimensions.scroll + actualHeight;\n if (topEdgeOffset < viewportDimensions.top) { // top overflow\n delta.top = viewportDimensions.top - topEdgeOffset;\n } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow\n delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset;\n }\n } else {\n var leftEdgeOffset = position.left - viewportPadding;\n var rightEdgeOffset = position.left + viewportPadding + actualWidth;\n if (leftEdgeOffset < viewportDimensions.left) { // left overflow\n delta.left = viewportDimensions.left - leftEdgeOffset;\n } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow\n delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset;\n }\n }\n\n return delta;\n }\n\n function replaceArrow(delta, dimension, isHorizontal) {\n var $arrow = findElement('.tooltip-arrow, .arrow', tipElement[0]);\n\n $arrow.css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')\n .css(isHorizontal ? 'top' : 'left', '');\n }\n\n function destroyTipElement() {\n // Cancel pending callbacks\n clearTimeout(timeout);\n\n if($tooltip.$isShown && tipElement !== null) {\n if(options.autoClose) {\n unbindAutoCloseEvents();\n }\n\n if(options.keyboard) {\n unbindKeyboardEvents();\n }\n }\n\n if(tipScope) {\n tipScope.$destroy();\n tipScope = null;\n }\n\n if(tipElement) {\n tipElement.remove();\n tipElement = $tooltip.$element = null;\n }\n }\n\n return $tooltip;\n\n }\n\n // Helper functions\n\n function safeDigest(scope) {\n scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();\n }\n\n function findElement(query, element) {\n return angular.element((element || document).querySelectorAll(query));\n }\n\n var fetchPromises = {};\n function fetchTemplate(template) {\n if(fetchPromises[template]) return fetchPromises[template];\n return (fetchPromises[template] = $http.get(template, {cache: $templateCache}).then(function(res) {\n return res.data;\n }));\n }\n\n return TooltipFactory;\n\n };\n\n })\n\n .directive('bsTooltip', function($window, $location, $sce, $tooltip, $$rAF) {\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'backdropAnimation', 'type', 'customClass', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // should not parse target attribute (anchor tag), only data-target #1454\n var dataTarget = element.attr('data-target');\n if(angular.isDefined(dataTarget)) {\n if(falseValueRegExp.test(dataTarget))\n options.target = false;\n else\n options.target = dataTarget;\n }\n\n // overwrite inherited title value when no value specified\n // fix for angular 1.3.1 531a8de72c439d8ddd064874bf364c00cedabb11\n if (!scope.hasOwnProperty('title')){\n scope.title = '';\n }\n\n // Observe scope attributes for change\n attr.$observe('title', function(newValue) {\n if (angular.isDefined(newValue) || !scope.hasOwnProperty('title')) {\n var oldValue = scope.title;\n scope.title = $sce.trustAsHtml(newValue);\n angular.isDefined(oldValue) && $$rAF(function() {\n tooltip && tooltip.$applyPlacement();\n });\n }\n });\n\n // Support scope as an object\n attr.bsTooltip && scope.$watch(attr.bsTooltip, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.title = newValue;\n }\n angular.isDefined(oldValue) && $$rAF(function() {\n tooltip && tooltip.$applyPlacement();\n });\n }, true);\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!tooltip || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(tooltip),?/i);\n newValue === true ? tooltip.show() : tooltip.hide();\n });\n\n // Enabled binding support\n attr.bsEnabled && scope.$watch(attr.bsEnabled, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.bsEnabled, newValue, oldValue);\n if(!tooltip || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|1|,?(tooltip),?/i);\n newValue === false ? tooltip.setEnabled(false) : tooltip.setEnabled(true);\n });\n\n // Viewport support\n attr.viewport && scope.$watch(attr.viewport, function (newValue) {\n if(!tooltip || !angular.isDefined(newValue)) return;\n tooltip.setViewport(newValue);\n });\n\n // Initialize popover\n var tooltip = $tooltip(element, options);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if(tooltip) tooltip.destroy();\n options = null;\n tooltip = null;\n });\n\n }\n };\n\n });\n\n})(window, document);\n","'use strict';\n\n// NOTICE: This file was forked from the angular-material project (github.com/angular/material)\n// MIT Licensed - Copyright (c) 2014-2015 Google, Inc. http://angularjs.org\n\nangular.module('mgcrea.ngStrap.core', [])\n .service('$bsCompiler', bsCompilerService);\n\nfunction bsCompilerService($q, $http, $injector, $compile, $controller, $templateCache) {\n /* jshint validthis: true */\n\n /*\n * @ngdoc service\n * @name $bsCompiler\n * @module material.core\n * @description\n * The $bsCompiler service is an abstraction of angular's compiler, that allows the developer\n * to easily compile an element with a templateUrl, controller, and locals.\n *\n * @usage\n * \n * $bsCompiler.compile({\n * templateUrl: 'modal.html',\n * controller: 'ModalCtrl',\n * locals: {\n * modal: myModalInstance;\n * }\n * }).then(function(compileData) {\n * compileData.element; // modal.html's template in an element\n * compileData.link(myScope); //attach controller & scope to element\n * });\n * \n */\n\n /*\n * @ngdoc method\n * @name $bsCompiler#compile\n * @description A helper to compile an HTML template/templateUrl with a given controller,\n * locals, and scope.\n * @param {object} options An options object, with the following properties:\n *\n * - `controller` - `{(string=|function()=}` Controller fn that should be associated with\n * newly created scope or the name of a registered controller if passed as a string.\n * - `controllerAs` - `{string=}` A controller alias name. If present the controller will be\n * published to scope under the `controllerAs` name.\n * - `template` - `{string=}` An html template as a string.\n * - `templateUrl` - `{string=}` A path to an html template.\n * - `transformTemplate` - `{function(template)=}` A function which transforms the template after\n * it is loaded. It will be given the template string as a parameter, and should\n * return a a new string representing the transformed template.\n * - `resolve` - `{Object.=}` - An optional map of dependencies which should\n * be injected into the controller. If any of these dependencies are promises, the compiler\n * will wait for them all to be resolved, or if one is rejected before the controller is\n * instantiated `compile()` will fail..\n * * `key` - `{string}`: a name of a dependency to be injected into the controller.\n * * `factory` - `{string|function}`: If `string` then it is an alias for a service.\n * Otherwise if function, then it is injected and the return value is treated as the\n * dependency. If the result is a promise, it is resolved before its value is\n * injected into the controller.\n *\n * @returns {object=} promise A promise, which will be resolved with a `compileData` object.\n * `compileData` has the following properties:\n *\n * - `element` - `{element}`: an uncompiled element matching the provided template.\n * - `link` - `{function(scope)}`: A link function, which, when called, will compile\n * the element and instantiate the provided controller (if given).\n * - `locals` - `{object}`: The locals which will be passed into the controller once `link` is\n * called. If `bindToController` is true, they will be coppied to the ctrl instead\n * - `bindToController` - `bool`: bind the locals to the controller, instead of passing them in.\n */\n this.compile = function(options) {\n\n if(options.template && /\\.html$/.test(options.template)) {\n console.warn('Deprecated use of `template` option to pass a file. Please use the `templateUrl` option instead.');\n options.templateUrl = options.template;\n options.template = '';\n }\n\n var templateUrl = options.templateUrl;\n var template = options.template || '';\n var controller = options.controller;\n var controllerAs = options.controllerAs;\n var resolve = angular.copy(options.resolve || {});\n var locals = angular.copy(options.locals || {});\n var transformTemplate = options.transformTemplate || angular.identity;\n var bindToController = options.bindToController;\n\n // Take resolve values and invoke them.\n // Resolves can either be a string (value: 'MyRegisteredAngularConst'),\n // or an invokable 'factory' of sorts: (value: function ValueGetter($dependency) {})\n angular.forEach(resolve, function(value, key) {\n if (angular.isString(value)) {\n resolve[key] = $injector.get(value);\n } else {\n resolve[key] = $injector.invoke(value);\n }\n });\n // Add the locals, which are just straight values to inject\n // eg locals: { three: 3 }, will inject three into the controller\n angular.extend(resolve, locals);\n\n if (templateUrl) {\n resolve.$template = fetchTemplate(templateUrl);\n } else {\n resolve.$template = $q.when(template);\n }\n\n if (options.contentTemplate) {\n // TODO(mgcrea): deprecate?\n resolve.$template = $q.all([resolve.$template, fetchTemplate(options.contentTemplate)])\n .then(function(templates) {\n var templateEl = angular.element(templates[0]);\n var contentEl = findElement('[ng-bind=\"content\"]', templateEl[0]).removeAttr('ng-bind').html(templates[1]);\n // Drop the default footer as you probably don't want it if you use a custom contentTemplate\n if(!options.templateUrl) contentEl.next().remove();\n return templateEl[0].outerHTML;\n });\n }\n\n // Wait for all the resolves to finish if they are promises\n return $q.all(resolve).then(function(locals) {\n\n var template = transformTemplate(locals.$template);\n if (options.html) {\n template = template.replace(/ng-bind=\"/ig, 'ng-bind-html=\"');\n }\n // var element = options.element || angular.element('
').html(template.trim()).contents();\n var element = angular.element('
').html(template.trim()).contents();\n var linkFn = $compile(element);\n\n // Return a linking function that can be used later when the element is ready\n return {\n locals: locals,\n element: element,\n link: function link(scope) {\n locals.$scope = scope;\n\n // Instantiate controller if it exists, because we have scope\n if (controller) {\n var invokeCtrl = $controller(controller, locals, true);\n if (bindToController) {\n angular.extend(invokeCtrl.instance, locals);\n }\n // Support angular@~1.2 invokeCtrl\n var ctrl = angular.isObject(invokeCtrl) ? invokeCtrl : invokeCtrl();\n // See angular-route source for this logic\n element.data('$ngControllerController', ctrl);\n element.children().data('$ngControllerController', ctrl);\n\n if (controllerAs) {\n scope[controllerAs] = ctrl;\n }\n }\n\n return linkFn.apply(null, arguments);\n }\n };\n });\n\n };\n\n function findElement(query, element) {\n return angular.element((element || document).querySelectorAll(query));\n }\n\n var fetchPromises = {};\n function fetchTemplate(template) {\n if(fetchPromises[template]) return fetchPromises[template];\n return (fetchPromises[template] = $http.get(template, {cache: $templateCache})\n .then(function(res) {\n return res.data;\n }));\n }\n\n}\n","'use strict';\n\nangular.module('mgcrea.ngStrap.helpers.dateFormatter', [])\n\n .service('$dateFormatter', function($locale, dateFilter) {\n\n // The unused `lang` arguments are on purpose. The default implementation does not\n // use them and it always uses the locale loaded into the `$locale` service.\n // Custom implementations might use it, thus allowing different directives to\n // have different languages.\n\n this.getDefaultLocale = function() {\n return $locale.id;\n };\n\n // Format is either a data format name, e.g. \"shortTime\" or \"fullDate\", or a date format\n // Return either the corresponding date format or the given date format.\n this.getDatetimeFormat = function(format, lang) {\n return $locale.DATETIME_FORMATS[format] || format;\n };\n\n this.weekdaysShort = function(lang) {\n return $locale.DATETIME_FORMATS.SHORTDAY;\n };\n\n function splitTimeFormat(format) {\n return /(h+)([:\\.])?(m+)([:\\.])?(s*)[ ]?(a?)/i.exec(format).slice(1);\n }\n\n // h:mm a => h\n this.hoursFormat = function(timeFormat) {\n return splitTimeFormat(timeFormat)[0];\n };\n\n // h:mm a => mm\n this.minutesFormat = function(timeFormat) {\n return splitTimeFormat(timeFormat)[2];\n };\n\n // h:mm:ss a => ss\n this.secondsFormat = function(timeFormat) {\n return splitTimeFormat(timeFormat)[4];\n };\n\n // h:mm a => :\n this.timeSeparator = function(timeFormat) {\n return splitTimeFormat(timeFormat)[1];\n };\n\n // h:mm:ss a => true, h:mm a => false\n this.showSeconds = function(timeFormat) {\n return !!splitTimeFormat(timeFormat)[4];\n };\n\n // h:mm a => true, H.mm => false\n this.showAM = function(timeFormat) {\n return !!splitTimeFormat(timeFormat)[5];\n };\n\n this.formatDate = function(date, format, lang, timezone){\n return dateFilter(date, format, timezone);\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.affix', ['mgcrea.ngStrap.helpers.dimensions', 'mgcrea.ngStrap.helpers.debounce'])\n\n .provider('$affix', function() {\n\n var defaults = this.defaults = {\n offsetTop: 'auto',\n inlineStyles: true\n };\n\n this.$get = function($window, debounce, dimensions) {\n\n var bodyEl = angular.element($window.document.body);\n var windowEl = angular.element($window);\n\n function AffixFactory(element, config) {\n\n var $affix = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n var targetEl = options.target;\n\n // Initial private vars\n var reset = 'affix affix-top affix-bottom',\n setWidth = false,\n initialAffixTop = 0,\n initialOffsetTop = 0,\n offsetTop = 0,\n offsetBottom = 0,\n affixed = null,\n unpin = null;\n\n var parent = element.parent();\n // Options: custom parent\n if (options.offsetParent) {\n if (options.offsetParent.match(/^\\d+$/)) {\n for (var i = 0; i < (options.offsetParent * 1) - 1; i++) {\n parent = parent.parent();\n }\n }\n else {\n parent = angular.element(options.offsetParent);\n }\n }\n\n $affix.init = function() {\n\n this.$parseOffsets();\n initialOffsetTop = dimensions.offset(element[0]).top + initialAffixTop;\n setWidth = !element[0].style.width;\n\n // Bind events\n targetEl.on('scroll', this.checkPosition);\n targetEl.on('click', this.checkPositionWithEventLoop);\n windowEl.on('resize', this.$debouncedOnResize);\n\n // Both of these checkPosition() calls are necessary for the case where\n // the user hits refresh after scrolling to the bottom of the page.\n this.checkPosition();\n this.checkPositionWithEventLoop();\n\n };\n\n $affix.destroy = function() {\n\n // Unbind events\n targetEl.off('scroll', this.checkPosition);\n targetEl.off('click', this.checkPositionWithEventLoop);\n windowEl.off('resize', this.$debouncedOnResize);\n\n };\n\n $affix.checkPositionWithEventLoop = function() {\n\n // IE 9 throws an error if we use 'this' instead of '$affix'\n // in this setTimeout call\n setTimeout($affix.checkPosition, 1);\n\n };\n\n $affix.checkPosition = function() {\n // if (!this.$element.is(':visible')) return\n\n var scrollTop = getScrollTop();\n var position = dimensions.offset(element[0]);\n var elementHeight = dimensions.height(element[0]);\n\n // Get required affix class according to position\n var affix = getRequiredAffixClass(unpin, position, elementHeight);\n\n // Did affix status changed this last check?\n if(affixed === affix) return;\n affixed = affix;\n\n // Add proper affix class\n element.removeClass(reset).addClass('affix' + ((affix !== 'middle') ? '-' + affix : ''));\n\n if(affix === 'top') {\n unpin = null;\n if(setWidth) {\n element.css('width', '');\n }\n if (options.inlineStyles) {\n element.css('position', (options.offsetParent) ? '' : 'relative');\n element.css('top', '');\n }\n } else if(affix === 'bottom') {\n if (options.offsetUnpin) {\n unpin = -(options.offsetUnpin * 1);\n }\n else {\n // Calculate unpin threshold when affixed to bottom.\n // Hopefully the browser scrolls pixel by pixel.\n unpin = position.top - scrollTop;\n }\n if(setWidth) {\n element.css('width', '');\n }\n if (options.inlineStyles) {\n element.css('position', (options.offsetParent) ? '' : 'relative');\n element.css('top', (options.offsetParent) ? '' : ((bodyEl[0].offsetHeight - offsetBottom - elementHeight - initialOffsetTop) + 'px'));\n }\n } else { // affix === 'middle'\n unpin = null;\n if(setWidth) {\n element.css('width', element[0].offsetWidth + 'px');\n }\n if (options.inlineStyles) {\n element.css('position', 'fixed');\n element.css('top', initialAffixTop + 'px');\n }\n }\n\n };\n\n $affix.$onResize = function() {\n $affix.$parseOffsets();\n $affix.checkPosition();\n };\n $affix.$debouncedOnResize = debounce($affix.$onResize, 50);\n\n $affix.$parseOffsets = function() {\n var initialPosition = element.css('position');\n // Reset position to calculate correct offsetTop\n if (options.inlineStyles){\n element.css('position', (options.offsetParent) ? '' : 'relative');\n }\n\n if(options.offsetTop) {\n if(options.offsetTop === 'auto') {\n options.offsetTop = '+0';\n }\n if(options.offsetTop.match(/^[-+]\\d+$/)) {\n initialAffixTop = - options.offsetTop * 1;\n if(options.offsetParent) {\n offsetTop = dimensions.offset(parent[0]).top + (options.offsetTop * 1);\n }\n else {\n offsetTop = dimensions.offset(element[0]).top - dimensions.css(element[0], 'marginTop', true) + (options.offsetTop * 1);\n }\n }\n else {\n offsetTop = options.offsetTop * 1;\n }\n }\n\n if(options.offsetBottom) {\n if(options.offsetParent && options.offsetBottom.match(/^[-+]\\d+$/)) {\n // add 1 pixel due to rounding problems...\n offsetBottom = getScrollHeight() - (dimensions.offset(parent[0]).top + dimensions.height(parent[0])) + (options.offsetBottom * 1) + 1;\n }\n else {\n offsetBottom = options.offsetBottom * 1;\n }\n }\n\n // Bring back the element's position after calculations\n if (options.inlineStyles){\n element.css('position', initialPosition);\n }\n };\n\n // Private methods\n\n function getRequiredAffixClass(unpin, position, elementHeight) {\n\n var scrollTop = getScrollTop();\n var scrollHeight = getScrollHeight();\n\n if(scrollTop <= offsetTop) {\n return 'top';\n } else if(unpin !== null && (scrollTop + unpin <= position.top)) {\n return 'middle';\n } else if(offsetBottom !== null && (position.top + elementHeight + initialAffixTop >= scrollHeight - offsetBottom)) {\n return 'bottom';\n } else {\n return 'middle';\n }\n\n }\n\n function getScrollTop() {\n return targetEl[0] === $window ? $window.pageYOffset : targetEl[0].scrollTop;\n }\n\n function getScrollHeight() {\n return targetEl[0] === $window ? $window.document.body.scrollHeight : targetEl[0].scrollHeight;\n }\n\n $affix.init();\n return $affix;\n\n }\n\n return AffixFactory;\n\n };\n\n })\n\n .directive('bsAffix', function($affix, $window) {\n\n return {\n restrict: 'EAC',\n require: '^?bsAffixTarget',\n link: function postLink(scope, element, attr, affixTarget) {\n\n var options = {scope: scope, target: affixTarget ? affixTarget.$element : angular.element($window)};\n angular.forEach(['offsetTop', 'offsetBottom', 'offsetParent', 'offsetUnpin', 'inlineStyles'], function(key) {\n if(angular.isDefined(attr[key])) {\n var option = attr[key];\n if (/true/i.test(option)) option = true;\n if (/false/i.test(option)) option = false;\n options[key] = option;\n }\n });\n\n var affix = $affix(element, options);\n scope.$on('$destroy', function() {\n affix && affix.destroy();\n options = null;\n affix = null;\n });\n\n }\n };\n\n })\n\n .directive('bsAffixTarget', function() {\n return {\n controller: function($element) {\n this.$element = $element;\n }\n };\n });\n","'use strict';\n\n// @BUG: following snippet won't compile correctly\n// @TODO: submit issue to core\n// ' ' +\n\nangular.module('mgcrea.ngStrap.alert', ['mgcrea.ngStrap.modal'])\n\n .provider('$alert', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'alert',\n prefixEvent: 'alert',\n placement: null,\n templateUrl: 'alert/alert.tpl.html',\n container: false,\n element: null,\n backdrop: false,\n keyboard: true,\n show: true,\n // Specific options\n duration: false,\n type: false,\n dismissable: true\n };\n\n this.$get = function($modal, $timeout) {\n\n function AlertFactory(config) {\n\n var $alert = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $alert = $modal(options);\n\n // Support scope as string options [/*title, content, */ type, dismissable]\n $alert.$scope.dismissable = !!options.dismissable;\n if(options.type) {\n $alert.$scope.type = options.type;\n }\n\n // Support auto-close duration\n var show = $alert.show;\n if(options.duration) {\n $alert.show = function() {\n show();\n $timeout(function() {\n $alert.hide();\n }, options.duration * 1000);\n };\n }\n\n return $alert;\n\n }\n\n return AlertFactory;\n\n };\n\n })\n\n .directive('bsAlert', function($window, $sce, $alert) {\n\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope, element: element, show: false};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'keyboard', 'html', 'container', 'animation', 'duration', 'dismissable'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['keyboard', 'html', 'container', 'dismissable'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // overwrite inherited title value when no value specified\n // fix for angular 1.3.1 531a8de72c439d8ddd064874bf364c00cedabb11\n if (!scope.hasOwnProperty('title')){\n scope.title = '';\n }\n\n // Support scope as data-attrs\n angular.forEach(['title', 'content', 'type'], function(key) {\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\n scope[key] = $sce.trustAsHtml(newValue);\n });\n });\n\n // Support scope as an object\n attr.bsAlert && scope.$watch(attr.bsAlert, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.content = newValue;\n }\n }, true);\n\n // Initialize alert\n var alert = $alert(options);\n\n // Trigger\n element.on(attr.trigger || 'click', alert.toggle);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (alert) alert.destroy();\n options = null;\n alert = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.aside', ['mgcrea.ngStrap.modal'])\n\n .provider('$aside', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade-and-slide-right',\n prefixClass: 'aside',\n prefixEvent: 'aside',\n placement: 'right',\n templateUrl: 'aside/aside.tpl.html',\n contentTemplate: false,\n container: false,\n element: null,\n backdrop: true,\n keyboard: true,\n html: false,\n show: true\n };\n\n this.$get = function($modal) {\n\n function AsideFactory(config) {\n\n var $aside = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $aside = $modal(options);\n\n return $aside;\n\n }\n\n return AsideFactory;\n\n };\n\n })\n\n .directive('bsAside', function($window, $sce, $aside) {\n\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n // Directive options\n var options = {scope: scope, element: element, show: false};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['backdrop', 'keyboard', 'html', 'container'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Support scope as data-attrs\n angular.forEach(['title', 'content'], function(key) {\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\n scope[key] = $sce.trustAsHtml(newValue);\n });\n });\n\n // Support scope as an object\n attr.bsAside && scope.$watch(attr.bsAside, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.content = newValue;\n }\n }, true);\n\n // Initialize aside\n var aside = $aside(options);\n\n // Trigger\n element.on(attr.trigger || 'click', aside.toggle);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (aside) aside.destroy();\n options = null;\n aside = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.button', [])\n\n .provider('$button', function() {\n\n var defaults = this.defaults = {\n activeClass:'active',\n toggleEvent:'click'\n };\n\n this.$get = function() {\n return {defaults: defaults};\n };\n\n })\n\n .directive('bsCheckboxGroup', function() {\n\n return {\n restrict: 'A',\n require: 'ngModel',\n compile: function postLink(element, attr) {\n element.attr('data-toggle', 'buttons');\n element.removeAttr('ng-model');\n var children = element[0].querySelectorAll('input[type=\"checkbox\"]');\n angular.forEach(children, function(child) {\n var childEl = angular.element(child);\n childEl.attr('bs-checkbox', '');\n childEl.attr('ng-model', attr.ngModel + '.' + childEl.attr('value'));\n });\n }\n\n };\n\n })\n\n .directive('bsCheckbox', function($button, $$rAF) {\n\n var defaults = $button.defaults;\n var constantValueRegExp = /^(true|false|\\d+)$/;\n\n return {\n restrict: 'A',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n var options = defaults;\n\n // Support label > input[type=\"checkbox\"]\n var isInput = element[0].nodeName === 'INPUT';\n var activeElement = isInput ? element.parent() : element;\n\n var trueValue = angular.isDefined(attr.trueValue) ? attr.trueValue : true;\n if(constantValueRegExp.test(attr.trueValue)) {\n trueValue = scope.$eval(attr.trueValue);\n }\n var falseValue = angular.isDefined(attr.falseValue) ? attr.falseValue : false;\n if(constantValueRegExp.test(attr.falseValue)) {\n falseValue = scope.$eval(attr.falseValue);\n }\n\n // Parse exotic values\n var hasExoticValues = typeof trueValue !== 'boolean' || typeof falseValue !== 'boolean';\n if(hasExoticValues) {\n controller.$parsers.push(function(viewValue) {\n // console.warn('$parser', element.attr('ng-model'), 'viewValue', viewValue);\n return viewValue ? trueValue : falseValue;\n });\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n return angular.equals(modelValue, trueValue);\n });\n // Fix rendering for exotic values\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n controller.$render();\n });\n }\n\n // model -> view\n controller.$render = function () {\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n var isActive = angular.equals(controller.$modelValue, trueValue);\n $$rAF(function() {\n if(isInput) element[0].checked = isActive;\n activeElement.toggleClass(options.activeClass, isActive);\n });\n };\n\n // view -> model\n element.bind(options.toggleEvent, function() {\n scope.$apply(function () {\n // console.warn('!click', element.attr('ng-model'), 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue, 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue);\n if(!isInput) {\n controller.$setViewValue(!activeElement.hasClass('active'));\n }\n if(!hasExoticValues) {\n controller.$render();\n }\n });\n });\n\n }\n\n };\n\n })\n\n .directive('bsRadioGroup', function() {\n\n return {\n restrict: 'A',\n require: 'ngModel',\n compile: function postLink(element, attr) {\n element.attr('data-toggle', 'buttons');\n element.removeAttr('ng-model');\n var children = element[0].querySelectorAll('input[type=\"radio\"]');\n angular.forEach(children, function(child) {\n angular.element(child).attr('bs-radio', '');\n angular.element(child).attr('ng-model', attr.ngModel);\n });\n }\n\n };\n\n })\n\n .directive('bsRadio', function($button, $$rAF) {\n\n var defaults = $button.defaults;\n var constantValueRegExp = /^(true|false|\\d+)$/;\n\n return {\n restrict: 'A',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n var options = defaults;\n\n // Support `label > input[type=\"radio\"]` markup\n var isInput = element[0].nodeName === 'INPUT';\n var activeElement = isInput ? element.parent() : element;\n\n var value;\n attr.$observe('value', function(v) {\n value = constantValueRegExp.test(v) ? scope.$eval(v) : v;\n controller.$render();\n });\n\n // model -> view\n controller.$render = function () {\n // console.warn('$render', element.attr('value'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n var isActive = angular.equals(controller.$modelValue, value);\n $$rAF(function() {\n if(isInput) element[0].checked = isActive;\n activeElement.toggleClass(options.activeClass, isActive);\n });\n };\n\n // view -> model\n element.bind(options.toggleEvent, function() {\n scope.$apply(function () {\n // console.warn('!click', element.attr('value'), 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue, 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue);\n controller.$setViewValue(value);\n controller.$render();\n });\n });\n\n }\n\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.collapse', [])\n\n .provider('$collapse', function() {\n\n var defaults = this.defaults = {\n animation: 'am-collapse',\n disallowToggle: false,\n activeClass: 'in',\n startCollapsed: false,\n allowMultiple: false\n };\n\n var controller = this.controller = function($scope, $element, $attrs) {\n var self = this;\n\n // Attributes options\n self.$options = angular.copy(defaults);\n angular.forEach(['animation', 'disallowToggle', 'activeClass', 'startCollapsed', 'allowMultiple'], function (key) {\n if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['disallowToggle', 'startCollapsed', 'allowMultiple'], function(key) {\n if(angular.isDefined($attrs[key]) && falseValueRegExp.test($attrs[key])) {\n self.$options[key] = false;\n }\n });\n\n self.$toggles = [];\n self.$targets = [];\n\n self.$viewChangeListeners = [];\n\n self.$registerToggle = function(element) {\n self.$toggles.push(element);\n };\n self.$registerTarget = function(element) {\n self.$targets.push(element);\n };\n\n self.$unregisterToggle = function(element) {\n var index = self.$toggles.indexOf(element);\n // remove toggle from $toggles array\n self.$toggles.splice(index, 1);\n };\n self.$unregisterTarget = function(element) {\n var index = self.$targets.indexOf(element);\n\n // remove element from $targets array\n self.$targets.splice(index, 1);\n\n if (self.$options.allowMultiple) {\n // remove target index from $active array values\n deactivateItem(element);\n }\n\n // fix active item indexes\n fixActiveItemIndexes(index);\n\n self.$viewChangeListeners.forEach(function(fn) {\n fn();\n });\n };\n\n // use array to store all the currently open panels\n self.$targets.$active = !self.$options.startCollapsed ? [0] : [];\n self.$setActive = $scope.$setActive = function(value) {\n if(angular.isArray(value)) {\n self.$targets.$active = value;\n }\n else if(!self.$options.disallowToggle) {\n // toogle element active status\n isActive(value) ? deactivateItem(value) : activateItem(value);\n } else {\n activateItem(value);\n }\n\n self.$viewChangeListeners.forEach(function(fn) {\n fn();\n });\n };\n\n self.$activeIndexes = function() {\n return self.$options.allowMultiple ? self.$targets.$active :\n self.$targets.$active.length === 1 ? self.$targets.$active[0] : -1;\n };\n\n function fixActiveItemIndexes(index) {\n // item with index was removed, so we\n // need to adjust other items index values\n var activeIndexes = self.$targets.$active;\n for(var i = 0; i < activeIndexes.length; i++) {\n if (index < activeIndexes[i]) {\n activeIndexes[i] = activeIndexes[i] - 1;\n }\n\n // the last item is active, so we need to\n // adjust its index\n if (activeIndexes[i] === self.$targets.length) {\n activeIndexes[i] = self.$targets.length - 1;\n }\n }\n }\n\n function isActive(value) {\n var activeItems = self.$targets.$active;\n return activeItems.indexOf(value) === -1 ? false : true;\n }\n\n function deactivateItem(value) {\n var index = self.$targets.$active.indexOf(value);\n if (index !== -1) {\n self.$targets.$active.splice(index, 1);\n }\n }\n\n function activateItem(value) {\n if (!self.$options.allowMultiple) {\n // remove current selected item\n self.$targets.$active.splice(0, 1);\n }\n\n if (self.$targets.$active.indexOf(value) === -1) {\n self.$targets.$active.push(value);\n }\n }\n\n };\n\n this.$get = function() {\n var $collapse = {};\n $collapse.defaults = defaults;\n $collapse.controller = controller;\n return $collapse;\n };\n\n })\n\n .directive('bsCollapse', function($window, $animate, $collapse) {\n\n var defaults = $collapse.defaults;\n\n return {\n require: ['?ngModel', 'bsCollapse'],\n controller: ['$scope', '$element', '$attrs', $collapse.controller],\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsCollapseCtrl = controllers[1];\n\n if(ngModelCtrl) {\n\n // Update the modelValue following\n bsCollapseCtrl.$viewChangeListeners.push(function() {\n ngModelCtrl.$setViewValue(bsCollapseCtrl.$activeIndexes());\n });\n\n // modelValue -> $formatters -> viewValue\n ngModelCtrl.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n if (angular.isArray(modelValue)) {\n // model value is an array, so just replace\n // the active items directly\n bsCollapseCtrl.$setActive(modelValue);\n }\n else {\n var activeIndexes = bsCollapseCtrl.$activeIndexes();\n\n if (angular.isArray(activeIndexes)) {\n // we have an array of selected indexes\n if (activeIndexes.indexOf(modelValue * 1) === -1) {\n // item with modelValue index is not active\n bsCollapseCtrl.$setActive(modelValue * 1);\n }\n }\n else if (activeIndexes !== modelValue * 1) {\n bsCollapseCtrl.$setActive(modelValue * 1);\n }\n }\n return modelValue;\n });\n\n }\n\n }\n };\n\n })\n\n .directive('bsCollapseToggle', function() {\n\n return {\n require: ['^?ngModel', '^bsCollapse'],\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsCollapseCtrl = controllers[1];\n\n // Add base attr\n element.attr('data-toggle', 'collapse');\n\n // Push pane to parent bsCollapse controller\n bsCollapseCtrl.$registerToggle(element);\n\n // remove toggle from collapse controller when toggle is destroyed\n scope.$on('$destroy', function() {\n bsCollapseCtrl.$unregisterToggle(element);\n });\n\n element.on('click', function() {\n var index = attrs.bsCollapseToggle && attrs.bsCollapseToggle !== 'bs-collapse-toggle' ? attrs.bsCollapseToggle : bsCollapseCtrl.$toggles.indexOf(element);\n bsCollapseCtrl.$setActive(index * 1);\n scope.$apply();\n });\n\n }\n };\n\n })\n\n .directive('bsCollapseTarget', function($animate) {\n\n return {\n require: ['^?ngModel', '^bsCollapse'],\n // scope: true,\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsCollapseCtrl = controllers[1];\n\n // Add base class\n element.addClass('collapse');\n\n // Add animation class\n if(bsCollapseCtrl.$options.animation) {\n element.addClass(bsCollapseCtrl.$options.animation);\n }\n\n // Push pane to parent bsCollapse controller\n bsCollapseCtrl.$registerTarget(element);\n\n // remove pane target from collapse controller when target is destroyed\n scope.$on('$destroy', function() {\n bsCollapseCtrl.$unregisterTarget(element);\n });\n\n function render() {\n var index = bsCollapseCtrl.$targets.indexOf(element);\n var active = bsCollapseCtrl.$activeIndexes();\n var action = 'removeClass';\n if (angular.isArray(active)) {\n if (active.indexOf(index) !== -1) {\n action = 'addClass';\n }\n }\n else if (index === active) {\n action = 'addClass';\n }\n\n $animate[action](element, bsCollapseCtrl.$options.activeClass);\n }\n\n bsCollapseCtrl.$viewChangeListeners.push(function() {\n render();\n });\n render();\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.datepicker', [\n 'mgcrea.ngStrap.helpers.dateParser',\n 'mgcrea.ngStrap.helpers.dateFormatter',\n 'mgcrea.ngStrap.tooltip'])\n\n .provider('$datepicker', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n //uncommenting the following line will break backwards compatability\n // prefixEvent: 'datepicker',\n prefixClass: 'datepicker',\n placement: 'bottom-left',\n templateUrl: 'datepicker/datepicker.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n // lang: $locale.id,\n useNative: false,\n dateType: 'date',\n dateFormat: 'shortDate',\n timezone: null,\n modelDateFormat: null,\n dayFormat: 'dd',\n monthFormat: 'MMM',\n yearFormat: 'yyyy',\n monthTitleFormat: 'MMMM yyyy',\n yearTitleFormat: 'yyyy',\n strictFormat: false,\n autoclose: false,\n minDate: -Infinity,\n maxDate: +Infinity,\n startView: 0,\n minView: 0,\n startWeek: 0,\n daysOfWeekDisabled: '',\n iconLeft: 'glyphicon glyphicon-chevron-left',\n iconRight: 'glyphicon glyphicon-chevron-right'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, datepickerViews, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\n\n function DatepickerFactory(element, controller, config) {\n\n var $datepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $datepicker.$options;\n var scope = $datepicker.$scope;\n if(options.startView) options.startView -= options.minView;\n\n // View vars\n\n var pickerViews = datepickerViews($datepicker);\n $datepicker.$views = pickerViews.views;\n var viewDate = pickerViews.viewDate;\n scope.$mode = options.startView;\n scope.$iconLeft = options.iconLeft;\n scope.$iconRight = options.iconRight;\n var $picker = $datepicker.$views[scope.$mode];\n\n // Scope methods\n\n scope.$select = function(date) {\n $datepicker.select(date);\n };\n scope.$selectPane = function(value) {\n $datepicker.$selectPane(value);\n };\n scope.$toggleMode = function() {\n $datepicker.setMode((scope.$mode + 1) % $datepicker.$views.length);\n };\n\n // Public methods\n\n $datepicker.update = function(date) {\n // console.warn('$datepicker.update() newValue=%o', date);\n if(angular.isDate(date) && !isNaN(date.getTime())) {\n $datepicker.$date = date;\n $picker.update.call($picker, date);\n }\n // Build only if pristine\n $datepicker.$build(true);\n };\n\n $datepicker.updateDisabledDates = function(dateRanges) {\n options.disabledDateRanges = dateRanges;\n for(var i = 0, l = scope.rows.length; i < l; i++) {\n angular.forEach(scope.rows[i], $datepicker.$setDisabledEl);\n }\n };\n\n $datepicker.select = function(date, keep) {\n // console.warn('$datepicker.select', date, scope.$mode);\n if(!angular.isDate(controller.$dateValue)) controller.$dateValue = new Date(date);\n if(!scope.$mode || keep) {\n controller.$setViewValue(angular.copy(date));\n controller.$render();\n if(options.autoclose && !keep) {\n $timeout(function() { $datepicker.hide(true); });\n }\n } else {\n angular.extend(viewDate, {year: date.getFullYear(), month: date.getMonth(), date: date.getDate()});\n $datepicker.setMode(scope.$mode - 1);\n $datepicker.$build();\n }\n };\n\n $datepicker.setMode = function(mode) {\n // console.warn('$datepicker.setMode', mode);\n scope.$mode = mode;\n $picker = $datepicker.$views[scope.$mode];\n $datepicker.$build();\n };\n\n // Protected methods\n\n $datepicker.$build = function(pristine) {\n // console.warn('$datepicker.$build() viewDate=%o', viewDate);\n if(pristine === true && $picker.built) return;\n if(pristine === false && !$picker.built) return;\n $picker.build.call($picker);\n };\n\n $datepicker.$updateSelected = function() {\n for(var i = 0, l = scope.rows.length; i < l; i++) {\n angular.forEach(scope.rows[i], updateSelected);\n }\n };\n\n $datepicker.$isSelected = function(date) {\n return $picker.isSelected(date);\n };\n\n $datepicker.$setDisabledEl = function(el) {\n el.disabled = $picker.isDisabled(el.date);\n };\n\n $datepicker.$selectPane = function(value) {\n var steps = $picker.steps;\n // set targetDate to first day of month to avoid problems with\n // date values rollover. This assumes the viewDate does not\n // depend on the day of the month\n var targetDate = new Date(Date.UTC(viewDate.year + ((steps.year || 0) * value), viewDate.month + ((steps.month || 0) * value), 1));\n angular.extend(viewDate, {year: targetDate.getUTCFullYear(), month: targetDate.getUTCMonth(), date: targetDate.getUTCDate()});\n $datepicker.$build();\n };\n\n $datepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $datepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n if(evt.keyCode === 13) {\n if(!scope.$mode) {\n return $datepicker.hide(true);\n } else {\n return scope.$apply(function() { $datepicker.setMode(scope.$mode - 1); });\n }\n }\n\n // Navigate with keyboard\n $picker.onKeyDown(evt);\n parentScope.$digest();\n };\n\n // Private\n\n function updateSelected(el) {\n el.selected = $datepicker.$isSelected(el.date);\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $datepicker.init;\n $datepicker.init = function() {\n if(isNative && options.useNative) {\n element.prop('type', 'date');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if(isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $datepicker.destroy;\n $datepicker.destroy = function() {\n if(isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $datepicker.show;\n $datepicker.show = function() {\n if((!isTouch && element.attr('readonly')) || element.attr('disabled')) return;\n _show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n // if $datepicker is no longer showing, don't setup events\n if(!$datepicker.$isShown) return;\n $datepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $datepicker.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $datepicker.hide;\n $datepicker.hide = function(blur) {\n if(!$datepicker.$isShown) return;\n $datepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $datepicker.$onKeyDown);\n }\n _hide(blur);\n };\n\n return $datepicker;\n\n }\n\n DatepickerFactory.defaults = defaults;\n return DatepickerFactory;\n\n };\n\n })\n\n .directive('bsDatepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $datepicker) {\n\n var defaults = $datepicker.defaults;\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'autoclose', 'dateType', 'dateFormat', 'timezone', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled', 'id', 'prefixClass', 'prefixEvent'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'autoclose', 'useNative'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!datepicker || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(datepicker),?/i);\n newValue === true ? datepicker.show() : datepicker.hide();\n });\n\n // Initialize datepicker\n var datepicker = $datepicker(element, controller, options);\n options = datepicker.$options;\n // Set expected iOS format\n if(isNative && options.useNative) options.dateFormat = 'yyyy-MM-dd';\n\n var lang = options.lang;\n\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n\n var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});\n\n // Observe attributes for changes\n angular.forEach(['minDate', 'maxDate'], function(key) {\n // console.warn('attr.$observe(%s)', key, attr[key]);\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\n // console.warn('attr.$observe(%s)=%o', key, newValue);\n datepicker.$options[key] = dateParser.getDateForAttribute(key, newValue);\n // Build only if dirty\n !isNaN(datepicker.$options[key]) && datepicker.$build(false);\n validateAgainstMinMaxDate(controller.$dateValue);\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n datepicker.update(controller.$dateValue);\n }, true);\n\n // Normalize undefined/null/empty array,\n // so that we don't treat changing from undefined->null as a change.\n function normalizeDateRanges(ranges) {\n if (!ranges || !ranges.length) return null;\n return ranges;\n }\n\n if (angular.isDefined(attr.disabledDates)) {\n scope.$watch(attr.disabledDates, function(disabledRanges, previousValue) {\n disabledRanges = normalizeDateRanges(disabledRanges);\n previousValue = normalizeDateRanges(previousValue);\n\n if (disabledRanges) {\n datepicker.updateDisabledDates(disabledRanges);\n }\n });\n }\n\n function validateAgainstMinMaxDate(parsedDate) {\n if (!angular.isDate(parsedDate)) return;\n var isMinValid = isNaN(datepicker.$options.minDate) || parsedDate.getTime() >= datepicker.$options.minDate;\n var isMaxValid = isNaN(datepicker.$options.maxDate) || parsedDate.getTime() <= datepicker.$options.maxDate;\n var isValid = isMinValid && isMaxValid;\n controller.$setValidity('date', isValid);\n controller.$setValidity('min', isMinValid);\n controller.$setValidity('max', isMaxValid);\n // Only update the model when we have a valid date\n if(isValid) controller.$dateValue = parsedDate;\n }\n\n // viewValue -> $parsers -> modelValue\n controller.$parsers.unshift(function(viewValue) {\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\n var date;\n // Null values should correctly reset the model value & validity\n if(!viewValue) {\n controller.$setValidity('date', true);\n // BREAKING CHANGE:\n // return null (not undefined) when input value is empty, so angularjs 1.3\n // ngModelController can go ahead and run validators, like ngRequired\n return null;\n }\n var parsedDate = dateParser.parse(viewValue, controller.$dateValue);\n if(!parsedDate || isNaN(parsedDate.getTime())) {\n controller.$setValidity('date', false);\n // return undefined, causes ngModelController to\n // invalidate model value\n return;\n } else {\n validateAgainstMinMaxDate(parsedDate);\n }\n\n if(options.dateType === 'string') {\n date = dateParser.timezoneOffsetAdjust(parsedDate, options.timezone, true);\n return formatDate(date, options.modelDateFormat || options.dateFormat);\n }\n date = dateParser.timezoneOffsetAdjust(controller.$dateValue, options.timezone, true);\n if(options.dateType === 'number') {\n return date.getTime();\n } else if(options.dateType === 'unix') {\n return date.getTime() / 1000;\n } else if(options.dateType === 'iso') {\n return date.toISOString();\n } else {\n return new Date(date);\n }\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var date;\n if(angular.isUndefined(modelValue) || modelValue === null) {\n date = NaN;\n } else if(angular.isDate(modelValue)) {\n date = modelValue;\n } else if(options.dateType === 'string') {\n date = dateParser.parse(modelValue, null, options.modelDateFormat);\n } else if(options.dateType === 'unix') {\n date = new Date(modelValue * 1000);\n } else {\n date = new Date(modelValue);\n }\n // Setup default value?\n // if(isNaN(date.getTime())) {\n // var today = new Date();\n // date = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0, 0);\n // }\n controller.$dateValue = dateParser.timezoneOffsetAdjust(date, options.timezone);\n return getDateFormattedString();\n });\n\n // viewValue -> element\n controller.$render = function() {\n // console.warn('$render(\"%s\"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);\n element.val(getDateFormattedString());\n };\n\n function getDateFormattedString() {\n return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.dateFormat);\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if(datepicker) datepicker.destroy();\n options = null;\n datepicker = null;\n });\n\n }\n };\n\n })\n\n .provider('datepickerViews', function() {\n\n var defaults = this.defaults = {\n dayFormat: 'dd',\n daySplit: 7\n };\n\n // Split array into smaller arrays\n function split(arr, size) {\n var arrays = [];\n while(arr.length > 0) {\n arrays.push(arr.splice(0, size));\n }\n return arrays;\n }\n\n // Modulus operator\n function mod(n, m) {\n return ((n % m) + m) % m;\n }\n\n this.$get = function($dateFormatter, $dateParser, $sce) {\n\n return function(picker) {\n\n var scope = picker.$scope;\n var options = picker.$options;\n\n var lang = options.lang;\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});\n\n var weekDaysMin = $dateFormatter.weekdaysShort(lang);\n var weekDaysLabels = weekDaysMin.slice(options.startWeek).concat(weekDaysMin.slice(0, options.startWeek));\n var weekDaysLabelsHtml = $sce.trustAsHtml('' + weekDaysLabels.join('') + '');\n\n var startDate = picker.$date || (options.startDate ? dateParser.getDateForAttribute('startDate', options.startDate) : new Date());\n var viewDate = {year: startDate.getFullYear(), month: startDate.getMonth(), date: startDate.getDate()};\n\n var views = [{\n format: options.dayFormat,\n split: 7,\n steps: { month: 1 },\n update: function(date, force) {\n if(!this.built || force || date.getFullYear() !== viewDate.year || date.getMonth() !== viewDate.month) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getDate() !== viewDate.date || date.getDate() === 1) {\n // chaging picker current month will cause viewDate.date to be set to first day of the month,\n // in $datepicker.$selectPane, so picker would not update selected day display if\n // user picks first day of the new month.\n // As a workaround, we are always forcing update when picked date is first day of month.\n viewDate.date = picker.$date.getDate();\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstDayOfMonth = new Date(viewDate.year, viewDate.month, 1), firstDayOfMonthOffset = firstDayOfMonth.getTimezoneOffset();\n var firstDate = new Date(+firstDayOfMonth - mod(firstDayOfMonth.getDay() - options.startWeek, 7) * 864e5), firstDateOffset = firstDate.getTimezoneOffset();\n var today = dateParser.timezoneOffsetAdjust(new Date(), options.timezone).toDateString();\n // Handle daylight time switch\n if(firstDateOffset !== firstDayOfMonthOffset) firstDate = new Date(+firstDate + (firstDateOffset - firstDayOfMonthOffset) * 60e3);\n var days = [], day;\n for(var i = 0; i < 42; i++) { // < 7 * 6\n day = dateParser.daylightSavingAdjust(new Date(firstDate.getFullYear(), firstDate.getMonth(), firstDate.getDate() + i));\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)});\n }\n scope.title = formatDate(firstDayOfMonth, options.monthTitleFormat);\n scope.showLabels = true;\n scope.labels = weekDaysLabelsHtml;\n scope.rows = split(days, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth() && date.getDate() === picker.$date.getDate();\n },\n isDisabled: function(date) {\n var time = date.getTime();\n\n // Disabled because of min/max date.\n if (time < options.minDate || time > options.maxDate) return true;\n\n // Disabled due to being a disabled day of the week\n if (options.daysOfWeekDisabled.indexOf(date.getDay()) !== -1) return true;\n\n // Disabled because of disabled date range.\n if (options.disabledDateRanges) {\n for (var i = 0; i < options.disabledDateRanges.length; i++) {\n if (time >= options.disabledDateRanges[i].start && time <= options.disabledDateRanges[i].end) {\n return true;\n }\n }\n }\n\n return false;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualTime = picker.$date.getTime();\n var newDate;\n\n if(evt.keyCode === 37) newDate = new Date(actualTime - 1 * 864e5);\n else if(evt.keyCode === 38) newDate = new Date(actualTime - 7 * 864e5);\n else if(evt.keyCode === 39) newDate = new Date(actualTime + 1 * 864e5);\n else if(evt.keyCode === 40) newDate = new Date(actualTime + 7 * 864e5);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }, {\n name: 'month',\n format: options.monthFormat,\n split: 4,\n steps: { year: 1 },\n update: function(date, force) {\n if(!this.built || date.getFullYear() !== viewDate.year) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getMonth() !== viewDate.month) {\n angular.extend(viewDate, {month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstMonth = new Date(viewDate.year, 0, 1);\n var months = [], month;\n for (var i = 0; i < 12; i++) {\n month = new Date(viewDate.year, i, 1);\n months.push({date: month, label: formatDate(month, this.format), selected: picker.$isSelected(month), disabled: this.isDisabled(month)});\n }\n scope.title = formatDate(month, options.yearTitleFormat);\n scope.showLabels = false;\n scope.rows = split(months, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth();\n },\n isDisabled: function(date) {\n var lastDate = +new Date(date.getFullYear(), date.getMonth() + 1, 0);\n return lastDate < options.minDate || date.getTime() > options.maxDate;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualMonth = picker.$date.getMonth();\n var newDate = new Date(picker.$date);\n\n if(evt.keyCode === 37) newDate.setMonth(actualMonth - 1);\n else if(evt.keyCode === 38) newDate.setMonth(actualMonth - 4);\n else if(evt.keyCode === 39) newDate.setMonth(actualMonth + 1);\n else if(evt.keyCode === 40) newDate.setMonth(actualMonth + 4);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }, {\n name: 'year',\n format: options.yearFormat,\n split: 4,\n steps: { year: 12 },\n update: function(date, force) {\n if(!this.built || force || parseInt(date.getFullYear()/20, 10) !== parseInt(viewDate.year/20, 10)) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getFullYear() !== viewDate.year) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstYear = viewDate.year - viewDate.year % (this.split * 3);\n var years = [], year;\n for (var i = 0; i < 12; i++) {\n year = new Date(firstYear + i, 0, 1);\n years.push({date: year, label: formatDate(year, this.format), selected: picker.$isSelected(year), disabled: this.isDisabled(year)});\n }\n scope.title = years[0].label + '-' + years[years.length - 1].label;\n scope.showLabels = false;\n scope.rows = split(years, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear();\n },\n isDisabled: function(date) {\n var lastDate = +new Date(date.getFullYear() + 1, 0, 0);\n return lastDate < options.minDate || date.getTime() > options.maxDate;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualYear = picker.$date.getFullYear(),\n newDate = new Date(picker.$date);\n\n if(evt.keyCode === 37) newDate.setYear(actualYear - 1);\n else if(evt.keyCode === 38) newDate.setYear(actualYear - 4);\n else if(evt.keyCode === 39) newDate.setYear(actualYear + 1);\n else if(evt.keyCode === 40) newDate.setYear(actualYear + 4);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }];\n\n return {\n views: options.minView ? Array.prototype.slice.call(views, options.minView) : views,\n viewDate: viewDate\n };\n\n };\n\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.dropdown', ['mgcrea.ngStrap.tooltip'])\n\n .provider('$dropdown', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'dropdown',\n prefixEvent: 'dropdown',\n placement: 'bottom-left',\n templateUrl: 'dropdown/dropdown.tpl.html',\n trigger: 'click',\n container: false,\n keyboard: true,\n html: false,\n delay: 0\n };\n\n this.$get = function($window, $rootScope, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var matchesSelector = Element.prototype.matchesSelector || Element.prototype.webkitMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector;\n\n function DropdownFactory(element, config) {\n\n var $dropdown = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n var scope = $dropdown.$scope = options.scope && options.scope.$new() || $rootScope.$new();\n\n $dropdown = $tooltip(element, options);\n var parentEl = element.parent();\n\n // Protected methods\n\n $dropdown.$onKeyDown = function(evt) {\n if (!/(38|40)/.test(evt.keyCode)) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // Retrieve focused index\n var items = angular.element($dropdown.$element[0].querySelectorAll('li:not(.divider) a'));\n if(!items.length) return;\n var index;\n angular.forEach(items, function(el, i) {\n if(matchesSelector && matchesSelector.call(el, ':focus')) index = i;\n });\n\n // Navigate with keyboard\n if(evt.keyCode === 38 && index > 0) index--;\n else if(evt.keyCode === 40 && index < items.length - 1) index++;\n else if(angular.isUndefined(index)) index = 0;\n items.eq(index)[0].focus();\n\n };\n\n // Overrides\n\n var show = $dropdown.show;\n $dropdown.show = function() {\n show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n options.keyboard && $dropdown.$element && $dropdown.$element.on('keydown', $dropdown.$onKeyDown);\n bodyEl.on('click', onBodyClick);\n }, 0, false);\n parentEl.hasClass('dropdown') && parentEl.addClass('open');\n };\n\n var hide = $dropdown.hide;\n $dropdown.hide = function() {\n if(!$dropdown.$isShown) return;\n options.keyboard && $dropdown.$element && $dropdown.$element.off('keydown', $dropdown.$onKeyDown);\n bodyEl.off('click', onBodyClick);\n parentEl.hasClass('dropdown') && parentEl.removeClass('open');\n hide();\n };\n\n var destroy = $dropdown.destroy;\n $dropdown.destroy = function() {\n bodyEl.off('click', onBodyClick);\n destroy();\n };\n\n // Private functions\n\n function onBodyClick(evt) {\n if(evt.target === element[0]) return;\n return evt.target !== element[0] && $dropdown.hide();\n }\n\n return $dropdown;\n\n }\n\n return DropdownFactory;\n\n };\n\n })\n\n .directive('bsDropdown', function($window, $sce, $dropdown) {\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Support scope as an object\n attr.bsDropdown && scope.$watch(attr.bsDropdown, function(newValue, oldValue) {\n scope.content = newValue;\n }, true);\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!dropdown || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(dropdown),?/i);\n newValue === true ? dropdown.show() : dropdown.hide();\n });\n\n // Initialize dropdown\n var dropdown = $dropdown(element, options);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (dropdown) dropdown.destroy();\n options = null;\n dropdown = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.helpers.dateParser', [])\n\n.provider('$dateParser', function($localeProvider) {\n\n // define a custom ParseDate object to use instead of native Date\n // to avoid date values wrapping when setting date component values\n function ParseDate() {\n this.year = 1970;\n this.month = 0;\n this.day = 1;\n this.hours = 0;\n this.minutes = 0;\n this.seconds = 0;\n this.milliseconds = 0;\n }\n\n ParseDate.prototype.setMilliseconds = function(value) { this.milliseconds = value; };\n ParseDate.prototype.setSeconds = function(value) { this.seconds = value; };\n ParseDate.prototype.setMinutes = function(value) { this.minutes = value; };\n ParseDate.prototype.setHours = function(value) { this.hours = value; };\n ParseDate.prototype.getHours = function() { return this.hours; };\n ParseDate.prototype.setDate = function(value) { this.day = value; };\n ParseDate.prototype.setMonth = function(value) { this.month = value; };\n ParseDate.prototype.setFullYear = function(value) { this.year = value; };\n ParseDate.prototype.fromDate = function(value) {\n this.year = value.getFullYear();\n this.month = value.getMonth();\n this.day = value.getDate();\n this.hours = value.getHours();\n this.minutes = value.getMinutes();\n this.seconds = value.getSeconds();\n this.milliseconds = value.getMilliseconds();\n return this;\n };\n\n ParseDate.prototype.toDate = function() {\n return new Date(this.year, this.month, this.day, this.hours, this.minutes, this.seconds, this.milliseconds);\n };\n\n var proto = ParseDate.prototype;\n\n function noop() {\n }\n\n function isNumeric(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n }\n\n function indexOfCaseInsensitive(array, value) {\n var len = array.length, str=value.toString().toLowerCase();\n for (var i=0; i 12 when midnight changeover, but then cannot generate\n * midnight datetime, so jump to 1AM, otherwise reset.\n * @param date (Date) the date to check\n * @return (Date) the corrected date\n *\n * __ copied from jquery ui datepicker __\n */\n $dateParser.daylightSavingAdjust = function(date) {\n if (!date) {\n return null;\n }\n date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);\n return date;\n };\n\n /* Correct the date for timezone offset.\n * @param date (Date) the date to adjust\n * @param timezone (string) the timezone to adjust for\n * @param undo (boolean) to add or subtract timezone offset\n * @return (Date) the corrected date\n */\n $dateParser.timezoneOffsetAdjust = function(date, timezone, undo) {\n if (!date) {\n return null;\n }\n // Right now, only 'UTC' is supported.\n if (timezone && timezone === 'UTC') {\n date = new Date(date.getTime());\n date.setMinutes(date.getMinutes() + (undo?-1:1)*date.getTimezoneOffset());\n }\n return date;\n };\n\n // Private functions\n\n function setMapForFormat(format) {\n var keys = Object.keys(setFnMap), i;\n var map = [], sortedMap = [];\n // Map to setFn\n var clonedFormat = format;\n for(i = 0; i < keys.length; i++) {\n if(format.split(keys[i]).length > 1) {\n var index = clonedFormat.search(keys[i]);\n format = format.split(keys[i]).join('');\n if(setFnMap[keys[i]]) {\n map[index] = setFnMap[keys[i]];\n }\n }\n }\n // Sort result map\n angular.forEach(map, function(v) {\n // conditional required since angular.forEach broke around v1.2.21\n // related pr: https://github.com/angular/angular.js/pull/8525\n if(v) sortedMap.push(v);\n });\n return sortedMap;\n }\n\n function escapeReservedSymbols(text) {\n return text.replace(/\\//g, '[\\\\/]').replace('/-/g', '[-]').replace(/\\./g, '[.]').replace(/\\\\s/g, '[\\\\s]');\n }\n\n function regExpForFormat(format) {\n var keys = Object.keys(regExpMap), i;\n\n var re = format;\n // Abstract replaces to avoid collisions\n for(i = 0; i < keys.length; i++) {\n re = re.split(keys[i]).join('${' + i + '}');\n }\n // Replace abstracted values\n for(i = 0; i < keys.length; i++) {\n re = re.split('${' + i + '}').join('(' + regExpMap[keys[i]] + ')');\n }\n format = escapeReservedSymbols(format);\n\n return new RegExp('^' + re + '$', ['i']);\n }\n\n $dateParser.init();\n return $dateParser;\n\n };\n\n return DateParserFactory;\n\n };\n\n});\n","'use strict';\n\nangular.module('mgcrea.ngStrap.helpers.debounce', [])\n\n// @source jashkenas/underscore\n// @url https://github.com/jashkenas/underscore/blob/1.5.2/underscore.js#L693\n.factory('debounce', function($timeout) {\n return function(func, wait, immediate) {\n var timeout = null;\n return function() {\n var context = this,\n args = arguments,\n callNow = immediate && !timeout;\n if(timeout) {\n $timeout.cancel(timeout);\n }\n timeout = $timeout(function later() {\n timeout = null;\n if(!immediate) {\n func.apply(context, args);\n }\n }, wait, false);\n if(callNow) {\n func.apply(context, args);\n }\n return timeout;\n };\n };\n})\n\n\n// @source jashkenas/underscore\n// @url https://github.com/jashkenas/underscore/blob/1.5.2/underscore.js#L661\n.factory('throttle', function($timeout) {\n return function(func, wait, options) {\n var timeout = null;\n options || (options = {});\n return function() {\n var context = this,\n args = arguments;\n if(!timeout) {\n if(options.leading !== false) {\n func.apply(context, args);\n }\n timeout = $timeout(function later() {\n timeout = null;\n if(options.trailing !== false) {\n func.apply(context, args);\n }\n }, wait, false);\n }\n };\n };\n});\n\n","'use strict';\n\nangular.module('mgcrea.ngStrap.helpers.dimensions', [])\n\n .factory('dimensions', function($document, $window) {\n\n var jqLite = angular.element;\n var fn = {};\n\n /**\n * Test the element nodeName\n * @param element\n * @param name\n */\n var nodeName = fn.nodeName = function(element, name) {\n return element.nodeName && element.nodeName.toLowerCase() === name.toLowerCase();\n };\n\n /**\n * Returns the element computed style\n * @param element\n * @param prop\n * @param extra\n */\n fn.css = function(element, prop, extra) {\n var value;\n if (element.currentStyle) { //IE\n value = element.currentStyle[prop];\n } else if (window.getComputedStyle) {\n value = window.getComputedStyle(element)[prop];\n } else {\n value = element.style[prop];\n }\n return extra === true ? parseFloat(value) || 0 : value;\n };\n\n /**\n * Provides read-only equivalent of jQuery's offset function:\n * @required-by bootstrap-tooltip, bootstrap-affix\n * @url http://api.jquery.com/offset/\n * @param element\n */\n fn.offset = function(element) {\n var boxRect = element.getBoundingClientRect();\n var docElement = element.ownerDocument;\n return {\n width: boxRect.width || element.offsetWidth,\n height: boxRect.height || element.offsetHeight,\n top: boxRect.top + (window.pageYOffset || docElement.documentElement.scrollTop) - (docElement.documentElement.clientTop || 0),\n left: boxRect.left + (window.pageXOffset || docElement.documentElement.scrollLeft) - (docElement.documentElement.clientLeft || 0)\n };\n };\n \n /**\n * Provides set equivalent of jQuery's offset function:\n * @required-by bootstrap-tooltip\n * @url http://api.jquery.com/offset/\n * @param element\n * @param options\n * @param i\n */\n fn.setOffset = function (element, options, i) {\n var curPosition,\n curLeft,\n curCSSTop,\n curTop,\n curOffset,\n curCSSLeft,\n calculatePosition,\n position = fn.css(element, 'position'),\n curElem = angular.element(element),\n props = {};\n \n // Set position first, in-case top/left are set even on static elem\n if (position === 'static') {\n element.style.position = 'relative';\n }\n \n curOffset = fn.offset(element);\n curCSSTop = fn.css(element, 'top');\n curCSSLeft = fn.css(element, 'left');\n calculatePosition = (position === 'absolute' || position === 'fixed') && \n (curCSSTop + curCSSLeft).indexOf('auto') > -1;\n \n // Need to be able to calculate position if either\n // top or left is auto and position is either absolute or fixed\n if (calculatePosition) {\n curPosition = fn.position(element);\n curTop = curPosition.top;\n curLeft = curPosition.left;\n } else {\n curTop = parseFloat(curCSSTop) || 0;\n curLeft = parseFloat(curCSSLeft) || 0;\n }\n \n if (angular.isFunction(options)) {\n options = options.call(element, i, curOffset);\n }\n \n if (options.top !== null ) {\n props.top = (options.top - curOffset.top) + curTop;\n }\n if ( options.left !== null ) {\n props.left = (options.left - curOffset.left) + curLeft;\n }\n\n if ('using' in options) {\n options.using.call(curElem, props);\n } else {\n curElem.css({\n top: props.top + 'px',\n left: props.left + 'px'\n });\n }\n };\n\n /**\n * Provides read-only equivalent of jQuery's position function\n * @required-by bootstrap-tooltip, bootstrap-affix\n * @url http://api.jquery.com/offset/\n * @param element\n */\n fn.position = function(element) {\n\n var offsetParentRect = {top: 0, left: 0},\n offsetParentElement,\n offset;\n\n // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent\n if (fn.css(element, 'position') === 'fixed') {\n\n // We assume that getBoundingClientRect is available when computed position is fixed\n offset = element.getBoundingClientRect();\n\n } else {\n\n // Get *real* offsetParentElement\n offsetParentElement = offsetParent(element);\n\n // Get correct offsets\n offset = fn.offset(element);\n if (!nodeName(offsetParentElement, 'html')) {\n offsetParentRect = fn.offset(offsetParentElement);\n }\n\n // Add offsetParent borders\n offsetParentRect.top += fn.css(offsetParentElement, 'borderTopWidth', true);\n offsetParentRect.left += fn.css(offsetParentElement, 'borderLeftWidth', true);\n }\n\n // Subtract parent offsets and element margins\n return {\n width: element.offsetWidth,\n height: element.offsetHeight,\n top: offset.top - offsetParentRect.top - fn.css(element, 'marginTop', true),\n left: offset.left - offsetParentRect.left - fn.css(element, 'marginLeft', true)\n };\n\n };\n\n /**\n * Returns the closest, non-statically positioned offsetParent of a given element\n * @required-by fn.position\n * @param element\n */\n var offsetParent = function offsetParentElement(element) {\n var docElement = element.ownerDocument;\n var offsetParent = element.offsetParent || docElement;\n if(nodeName(offsetParent, '#document')) return docElement.documentElement;\n while(offsetParent && !nodeName(offsetParent, 'html') && fn.css(offsetParent, 'position') === 'static') {\n offsetParent = offsetParent.offsetParent;\n }\n return offsetParent || docElement.documentElement;\n };\n\n /**\n * Provides equivalent of jQuery's height function\n * @required-by bootstrap-affix\n * @url http://api.jquery.com/height/\n * @param element\n * @param outer\n */\n fn.height = function(element, outer) {\n var value = element.offsetHeight;\n if(outer) {\n value += fn.css(element, 'marginTop', true) + fn.css(element, 'marginBottom', true);\n } else {\n value -= fn.css(element, 'paddingTop', true) + fn.css(element, 'paddingBottom', true) + fn.css(element, 'borderTopWidth', true) + fn.css(element, 'borderBottomWidth', true);\n }\n return value;\n };\n\n /**\n * Provides equivalent of jQuery's width function\n * @required-by bootstrap-affix\n * @url http://api.jquery.com/width/\n * @param element\n * @param outer\n */\n fn.width = function(element, outer) {\n var value = element.offsetWidth;\n if(outer) {\n value += fn.css(element, 'marginLeft', true) + fn.css(element, 'marginRight', true);\n } else {\n value -= fn.css(element, 'paddingLeft', true) + fn.css(element, 'paddingRight', true) + fn.css(element, 'borderLeftWidth', true) + fn.css(element, 'borderRightWidth', true);\n }\n return value;\n };\n\n return fn;\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.helpers.parseOptions', [])\n\n .provider('$parseOptions', function() {\n\n var defaults = this.defaults = {\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+(.*?))?$/\n };\n\n this.$get = function($parse, $q) {\n\n function ParseOptionsFactory(attr, config) {\n\n var $parseOptions = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n $parseOptions.$values = [];\n\n // Private vars\n var match, displayFn, valueName, keyName, groupByFn, valueFn, valuesFn;\n\n $parseOptions.init = function() {\n $parseOptions.$match = match = attr.match(options.regexp);\n displayFn = $parse(match[2] || match[1]),\n valueName = match[4] || match[6],\n keyName = match[5],\n groupByFn = $parse(match[3] || ''),\n valueFn = $parse(match[2] ? match[1] : valueName),\n valuesFn = $parse(match[7]);\n };\n\n $parseOptions.valuesFn = function(scope, controller) {\n return $q.when(valuesFn(scope, controller))\n .then(function(values) {\n if(!angular.isArray(values)) {\n values = [];\n }\n $parseOptions.$values = values.length ? parseValues(values, scope) : [];\n return $parseOptions.$values;\n });\n };\n\n $parseOptions.displayValue = function(modelValue) {\n var scope = {};\n scope[valueName] = modelValue;\n return displayFn(scope);\n };\n\n // Private functions\n\n function parseValues(values, scope) {\n return values.map(function(match, index) {\n var locals = {}, label, value;\n locals[valueName] = match;\n label = displayFn(scope, locals);\n value = valueFn(scope, locals);\n return {label: label, value: value, index: index};\n });\n }\n\n $parseOptions.init();\n return $parseOptions;\n\n }\n\n return ParseOptionsFactory;\n\n };\n\n });\n","'use strict';\n\n(angular.version.minor < 3 && angular.version.dot < 14) && angular.module('ng')\n\n.factory('$$rAF', function($window, $timeout) {\n\n var requestAnimationFrame = $window.requestAnimationFrame ||\n $window.webkitRequestAnimationFrame ||\n $window.mozRequestAnimationFrame;\n\n var cancelAnimationFrame = $window.cancelAnimationFrame ||\n $window.webkitCancelAnimationFrame ||\n $window.mozCancelAnimationFrame ||\n $window.webkitCancelRequestAnimationFrame;\n\n var rafSupported = !!requestAnimationFrame;\n var raf = rafSupported ?\n function(fn) {\n var id = requestAnimationFrame(fn);\n return function() {\n cancelAnimationFrame(id);\n };\n } :\n function(fn) {\n var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666\n return function() {\n $timeout.cancel(timer);\n };\n };\n\n raf.supported = rafSupported;\n\n return raf;\n\n});\n\n// .factory('$$animateReflow', function($$rAF, $document) {\n\n// var bodyEl = $document[0].body;\n\n// return function(fn) {\n// //the returned function acts as the cancellation function\n// return $$rAF(function() {\n// //the line below will force the browser to perform a repaint\n// //so that all the animated elements within the animation frame\n// //will be properly updated and drawn on screen. This is\n// //required to perform multi-class CSS based animations with\n// //Firefox. DO NOT REMOVE THIS LINE.\n// var a = bodyEl.offsetWidth + 1;\n// fn();\n// });\n// };\n\n// });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.modal', ['mgcrea.ngStrap.core', 'mgcrea.ngStrap.helpers.dimensions'])\n\n .provider('$modal', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n backdropAnimation: 'am-fade',\n prefixClass: 'modal',\n prefixEvent: 'modal',\n placement: 'top',\n templateUrl: 'modal/modal.tpl.html',\n template: '',\n contentTemplate: false,\n container: false,\n element: null,\n backdrop: true,\n keyboard: true,\n html: false,\n show: true\n };\n\n this.$get = function($window, $rootScope, $bsCompiler, $q, $templateCache, $http, $animate, $timeout, $sce, dimensions) {\n\n var forEach = angular.forEach;\n var trim = String.prototype.trim;\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n var bodyElement = angular.element($window.document.body);\n\n function ModalFactory(config) {\n\n var $modal = {};\n\n // Common vars\n var options = $modal.$options = angular.extend({}, defaults, config);\n var promise = $modal.$promise = $bsCompiler.compile(options);\n var scope = $modal.$scope = options.scope && options.scope.$new() || $rootScope.$new();\n\n if(!options.element && !options.container) {\n options.container = 'body';\n }\n\n // Store $id to identify the triggering element in events\n // give priority to options.id, otherwise, try to use\n // element id if defined\n $modal.$id = options.id || options.element && options.element.attr('id') || '';\n\n // Support scope as string options\n forEach(['title', 'content'], function(key) {\n if(options[key]) scope[key] = $sce.trustAsHtml(options[key]);\n });\n\n // Provide scope helpers\n scope.$hide = function() {\n scope.$$postDigest(function() {\n $modal.hide();\n });\n };\n scope.$show = function() {\n scope.$$postDigest(function() {\n $modal.show();\n });\n };\n scope.$toggle = function() {\n scope.$$postDigest(function() {\n $modal.toggle();\n });\n };\n // Publish isShown as a protected var on scope\n $modal.$isShown = scope.$isShown = false;\n\n // Fetch, compile then initialize modal\n var compileData, modalElement, modalScope;\n var backdropElement = angular.element('
');\n backdropElement.css({position:'fixed', top:'0px', left:'0px', bottom:'0px', right:'0px', 'z-index': 1038});\n promise.then(function(data) {\n compileData = data;\n $modal.init();\n });\n\n $modal.init = function() {\n\n // Options: show\n if(options.show) {\n scope.$$postDigest(function() {\n $modal.show();\n });\n }\n\n };\n\n $modal.destroy = function() {\n\n // Remove element\n destroyModalElement();\n\n // remove backdrop element\n if(backdropElement) {\n backdropElement.remove();\n backdropElement = null;\n }\n\n // Destroy scope\n scope.$destroy();\n };\n\n $modal.show = function() {\n if($modal.$isShown) return;\n\n var parent, after;\n if(angular.isElement(options.container)) {\n parent = options.container;\n after = options.container[0].lastChild ? angular.element(options.container[0].lastChild) : null;\n } else {\n if (options.container) {\n parent = findElement(options.container);\n after = parent[0] && parent[0].lastChild ? angular.element(parent[0].lastChild) : null;\n } else {\n parent = null;\n after = options.element;\n }\n }\n\n // destroy any existing modal elements\n if(modalElement) destroyModalElement();\n\n // create a new scope, so we can destroy it and all child scopes\n // when destroying the modal element\n modalScope = $modal.$scope.$new();\n // Fetch a cloned element linked from template (noop callback is required)\n modalElement = $modal.$element = compileData.link(modalScope, function(clonedElement, scope) {});\n\n if(scope.$emit(options.prefixEvent + '.show.before', $modal).defaultPrevented) {\n return;\n }\n\n // Set the initial positioning.\n modalElement.css({display: 'block'}).addClass(options.placement);\n\n // Options: animation\n if(options.animation) {\n if(options.backdrop) {\n backdropElement.addClass(options.backdropAnimation);\n }\n modalElement.addClass(options.animation);\n }\n\n if(options.backdrop) {\n $animate.enter(backdropElement, bodyElement, null);\n }\n\n // Support v1.2+ $animate\n // https://github.com/angular/angular.js/issues/11713\n if(angular.version.minor <= 2) {\n $animate.enter(modalElement, parent, after, enterAnimateCallback);\n } else {\n $animate.enter(modalElement, parent, after).then(enterAnimateCallback);\n }\n\n $modal.$isShown = scope.$isShown = true;\n safeDigest(scope);\n // Focus once the enter-animation has started\n // Weird PhantomJS bug hack\n var el = modalElement[0];\n requestAnimationFrame(function() {\n el.focus();\n });\n\n bodyElement.addClass(options.prefixClass + '-open');\n if(options.animation) {\n bodyElement.addClass(options.prefixClass + '-with-' + options.animation);\n }\n\n // Bind events\n bindBackdropEvents();\n bindKeyboardEvents();\n };\n\n function enterAnimateCallback() {\n scope.$emit(options.prefixEvent + '.show', $modal);\n }\n\n $modal.hide = function() {\n if(!$modal.$isShown) return;\n\n if(scope.$emit(options.prefixEvent + '.hide.before', $modal).defaultPrevented) {\n return;\n }\n\n // Support v1.2+ $animate\n // https://github.com/angular/angular.js/issues/11713\n if(angular.version.minor <= 2) {\n $animate.leave(modalElement, leaveAnimateCallback);\n } else {\n $animate.leave(modalElement).then(leaveAnimateCallback);\n }\n\n if(options.backdrop) {\n $animate.leave(backdropElement);\n }\n $modal.$isShown = scope.$isShown = false;\n safeDigest(scope);\n\n // Unbind events\n unbindBackdropEvents();\n unbindKeyboardEvents();\n };\n\n function leaveAnimateCallback() {\n scope.$emit(options.prefixEvent + '.hide', $modal);\n bodyElement.removeClass(options.prefixClass + '-open');\n if(options.animation) {\n bodyElement.removeClass(options.prefixClass + '-with-' + options.animation);\n }\n }\n\n $modal.toggle = function() {\n\n $modal.$isShown ? $modal.hide() : $modal.show();\n\n };\n\n $modal.focus = function() {\n modalElement[0].focus();\n };\n\n // Protected methods\n\n $modal.$onKeyUp = function(evt) {\n\n if (evt.which === 27 && $modal.$isShown) {\n $modal.hide();\n evt.stopPropagation();\n }\n\n };\n\n function bindBackdropEvents() {\n if(options.backdrop) {\n modalElement.on('click', hideOnBackdropClick);\n backdropElement.on('click', hideOnBackdropClick);\n backdropElement.on('wheel', preventEventDefault);\n }\n }\n\n function unbindBackdropEvents() {\n if(options.backdrop) {\n modalElement.off('click', hideOnBackdropClick);\n backdropElement.off('click', hideOnBackdropClick);\n backdropElement.off('wheel', preventEventDefault);\n }\n }\n\n function bindKeyboardEvents() {\n if(options.keyboard) {\n modalElement.on('keyup', $modal.$onKeyUp);\n }\n }\n\n function unbindKeyboardEvents() {\n if(options.keyboard) {\n modalElement.off('keyup', $modal.$onKeyUp);\n }\n }\n\n // Private methods\n\n function hideOnBackdropClick(evt) {\n if(evt.target !== evt.currentTarget) return;\n options.backdrop === 'static' ? $modal.focus() : $modal.hide();\n }\n\n function preventEventDefault(evt) {\n evt.preventDefault();\n }\n\n function destroyModalElement() {\n if($modal.$isShown && modalElement !== null) {\n // un-bind events\n unbindBackdropEvents();\n unbindKeyboardEvents();\n }\n\n if(modalScope) {\n modalScope.$destroy();\n modalScope = null;\n }\n\n if(modalElement) {\n modalElement.remove();\n modalElement = $modal.$element = null;\n }\n }\n\n return $modal;\n\n }\n\n // Helper functions\n\n function safeDigest(scope) {\n scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();\n }\n\n function findElement(query, element) {\n return angular.element((element || document).querySelectorAll(query));\n }\n\n return ModalFactory;\n\n };\n\n })\n\n .directive('bsModal', function($window, $sce, $modal) {\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope, element: element, show: false};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'controller', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation', 'id', 'prefixEvent', 'prefixClass'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['backdrop', 'keyboard', 'html', 'container'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Support scope as data-attrs\n angular.forEach(['title', 'content'], function(key) {\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\n scope[key] = $sce.trustAsHtml(newValue);\n });\n });\n\n // Support scope as an object\n attr.bsModal && scope.$watch(attr.bsModal, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.content = newValue;\n }\n }, true);\n\n // Initialize modal\n var modal = $modal(options);\n\n // Trigger\n element.on(attr.trigger || 'click', modal.toggle);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (modal) modal.destroy();\n options = null;\n modal = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.navbar', [])\n\n .provider('$navbar', function() {\n\n var defaults = this.defaults = {\n activeClass: 'active',\n routeAttr: 'data-match-route',\n strict: false\n };\n\n this.$get = function() {\n return {defaults: defaults};\n };\n\n })\n\n .directive('bsNavbar', function($window, $location, $navbar) {\n\n var defaults = $navbar.defaults;\n\n return {\n restrict: 'A',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = angular.copy(defaults);\n angular.forEach(Object.keys(defaults), function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Watch for the $location\n scope.$watch(function() {\n\n return $location.path();\n\n }, function(newValue, oldValue) {\n\n var liElements = element[0].querySelectorAll('li[' + options.routeAttr + ']');\n\n angular.forEach(liElements, function(li) {\n\n var liElement = angular.element(li);\n var pattern = liElement.attr(options.routeAttr).replace('/', '\\\\/');\n if(options.strict) {\n pattern = '^' + pattern + '$';\n }\n var regexp = new RegExp(pattern, 'i');\n\n if(regexp.test(newValue)) {\n liElement.addClass(options.activeClass);\n } else {\n liElement.removeClass(options.activeClass);\n }\n\n });\n\n });\n\n }\n\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.popover', ['mgcrea.ngStrap.tooltip'])\n\n .provider('$popover', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n customClass: '',\n // uncommenting the next two lines will break backwards compatability\n // prefixClass: 'popover',\n // prefixEvent: 'popover',\n container: false,\n target: false,\n placement: 'right',\n templateUrl: 'popover/popover.tpl.html',\n contentTemplate: false,\n trigger: 'click',\n keyboard: true,\n html: false,\n title: '',\n content: '',\n delay: 0,\n autoClose: false\n };\n\n this.$get = function($tooltip) {\n\n function PopoverFactory(element, config) {\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n var $popover = $tooltip(element, options);\n\n // Support scope as string options [/*title, */content]\n if(options.content) {\n $popover.$scope.content = options.content;\n }\n\n return $popover;\n\n }\n\n return PopoverFactory;\n\n };\n\n })\n\n .directive('bsPopover', function($window, $sce, $popover) {\n\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'customClass', 'autoClose', 'id', 'prefixClass', 'prefixEvent'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'autoClose'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // should not parse target attribute (anchor tag), only data-target #1454\n var dataTarget = element.attr('data-target');\n if(angular.isDefined(dataTarget)) {\n if(falseValueRegExp.test(dataTarget))\n options.target = false;\n else\n options.target = dataTarget;\n }\n\n // Support scope as data-attrs\n angular.forEach(['title', 'content'], function(key) {\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\n scope[key] = $sce.trustAsHtml(newValue);\n angular.isDefined(oldValue) && requestAnimationFrame(function() {\n popover && popover.$applyPlacement();\n });\n });\n });\n\n // Support scope as an object\n attr.bsPopover && scope.$watch(attr.bsPopover, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.content = newValue;\n }\n angular.isDefined(oldValue) && requestAnimationFrame(function() {\n popover && popover.$applyPlacement();\n });\n }, true);\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!popover || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(popover),?/i);\n newValue === true ? popover.show() : popover.hide();\n });\n\n // Viewport support\n attr.viewport && scope.$watch(attr.viewport, function (newValue) {\n if(!popover || !angular.isDefined(newValue)) return;\n popover.setViewport(newValue);\n });\n\n // Initialize popover\n var popover = $popover(element, options);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (popover) popover.destroy();\n options = null;\n popover = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.scrollspy', ['mgcrea.ngStrap.helpers.debounce', 'mgcrea.ngStrap.helpers.dimensions'])\n\n .provider('$scrollspy', function() {\n\n // Pool of registered spies\n var spies = this.$$spies = {};\n\n var defaults = this.defaults = {\n debounce: 150,\n throttle: 100,\n offset: 100\n };\n\n this.$get = function($window, $document, $rootScope, dimensions, debounce, throttle) {\n\n var windowEl = angular.element($window);\n var docEl = angular.element($document.prop('documentElement'));\n var bodyEl = angular.element($window.document.body);\n\n // Helper functions\n\n function nodeName(element, name) {\n return element[0].nodeName && element[0].nodeName.toLowerCase() === name.toLowerCase();\n }\n\n function ScrollSpyFactory(config) {\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n if(!options.element) options.element = bodyEl;\n var isWindowSpy = nodeName(options.element, 'body');\n var scrollEl = isWindowSpy ? windowEl : options.element;\n var scrollId = isWindowSpy ? 'window' : options.id;\n\n // Use existing spy\n if(spies[scrollId]) {\n spies[scrollId].$$count++;\n return spies[scrollId];\n }\n\n var $scrollspy = {};\n\n // Private vars\n var unbindViewContentLoaded, unbindIncludeContentLoaded;\n var trackedElements = $scrollspy.$trackedElements = [];\n var sortedElements = [];\n var activeTarget;\n var debouncedCheckPosition;\n var throttledCheckPosition;\n var debouncedCheckOffsets;\n var viewportHeight;\n var scrollTop;\n\n $scrollspy.init = function() {\n\n // Setup internal ref counter\n this.$$count = 1;\n\n // Bind events\n debouncedCheckPosition = debounce(this.checkPosition, options.debounce);\n throttledCheckPosition = throttle(this.checkPosition, options.throttle);\n scrollEl.on('click', this.checkPositionWithEventLoop);\n windowEl.on('resize', debouncedCheckPosition);\n scrollEl.on('scroll', throttledCheckPosition);\n\n debouncedCheckOffsets = debounce(this.checkOffsets, options.debounce);\n unbindViewContentLoaded = $rootScope.$on('$viewContentLoaded', debouncedCheckOffsets);\n unbindIncludeContentLoaded = $rootScope.$on('$includeContentLoaded', debouncedCheckOffsets);\n debouncedCheckOffsets();\n\n // Register spy for reuse\n if(scrollId) {\n spies[scrollId] = $scrollspy;\n }\n\n };\n\n $scrollspy.destroy = function() {\n\n // Check internal ref counter\n this.$$count--;\n if(this.$$count > 0) {\n return;\n }\n\n // Unbind events\n scrollEl.off('click', this.checkPositionWithEventLoop);\n windowEl.off('resize', debouncedCheckPosition);\n scrollEl.off('scroll', throttledCheckPosition);\n unbindViewContentLoaded();\n unbindIncludeContentLoaded();\n if (scrollId) {\n delete spies[scrollId];\n }\n };\n\n $scrollspy.checkPosition = function() {\n\n // Not ready yet\n if(!sortedElements.length) return;\n\n // Calculate the scroll position\n scrollTop = (isWindowSpy ? $window.pageYOffset : scrollEl.prop('scrollTop')) || 0;\n\n // Calculate the viewport height for use by the components\n viewportHeight = Math.max($window.innerHeight, docEl.prop('clientHeight'));\n\n // Activate first element if scroll is smaller\n if(scrollTop < sortedElements[0].offsetTop && activeTarget !== sortedElements[0].target) {\n return $scrollspy.$activateElement(sortedElements[0]);\n }\n\n // Activate proper element\n for (var i = sortedElements.length; i--;) {\n if(angular.isUndefined(sortedElements[i].offsetTop) || sortedElements[i].offsetTop === null) continue;\n if(activeTarget === sortedElements[i].target) continue;\n if(scrollTop < sortedElements[i].offsetTop) continue;\n if(sortedElements[i + 1] && scrollTop > sortedElements[i + 1].offsetTop) continue;\n return $scrollspy.$activateElement(sortedElements[i]);\n }\n\n };\n\n $scrollspy.checkPositionWithEventLoop = function() {\n // IE 9 throws an error if we use 'this' instead of '$scrollspy'\n // in this setTimeout call\n setTimeout($scrollspy.checkPosition, 1);\n };\n\n // Protected methods\n\n $scrollspy.$activateElement = function(element) {\n if(activeTarget) {\n var activeElement = $scrollspy.$getTrackedElement(activeTarget);\n if(activeElement) {\n activeElement.source.removeClass('active');\n if(nodeName(activeElement.source, 'li') && nodeName(activeElement.source.parent().parent(), 'li')) {\n activeElement.source.parent().parent().removeClass('active');\n }\n }\n }\n activeTarget = element.target;\n element.source.addClass('active');\n if(nodeName(element.source, 'li') && nodeName(element.source.parent().parent(), 'li')) {\n element.source.parent().parent().addClass('active');\n }\n };\n\n $scrollspy.$getTrackedElement = function(target) {\n return trackedElements.filter(function(obj) {\n return obj.target === target;\n })[0];\n };\n\n // Track offsets behavior\n\n $scrollspy.checkOffsets = function() {\n\n angular.forEach(trackedElements, function(trackedElement) {\n var targetElement = document.querySelector(trackedElement.target);\n trackedElement.offsetTop = targetElement ? dimensions.offset(targetElement).top : null;\n if(options.offset && trackedElement.offsetTop !== null) trackedElement.offsetTop -= options.offset * 1;\n });\n\n sortedElements = trackedElements\n .filter(function(el) {\n return el.offsetTop !== null;\n })\n .sort(function(a, b) {\n return a.offsetTop - b.offsetTop;\n });\n\n debouncedCheckPosition();\n\n };\n\n $scrollspy.trackElement = function(target, source) {\n trackedElements.push({target: target, source: source});\n };\n\n $scrollspy.untrackElement = function(target, source) {\n var toDelete;\n for (var i = trackedElements.length; i--;) {\n if(trackedElements[i].target === target && trackedElements[i].source === source) {\n toDelete = i;\n break;\n }\n }\n trackedElements = trackedElements.splice(toDelete, 1);\n };\n\n $scrollspy.activate = function(i) {\n trackedElements[i].addClass('active');\n };\n\n // Initialize plugin\n\n $scrollspy.init();\n return $scrollspy;\n\n }\n\n return ScrollSpyFactory;\n\n };\n\n })\n\n .directive('bsScrollspy', function($rootScope, debounce, dimensions, $scrollspy) {\n\n return {\n restrict: 'EAC',\n link: function postLink(scope, element, attr) {\n\n var options = {scope: scope};\n angular.forEach(['offset', 'target'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n var scrollspy = $scrollspy(options);\n scrollspy.trackElement(options.target, element);\n\n scope.$on('$destroy', function() {\n if (scrollspy) {\n scrollspy.untrackElement(options.target, element);\n scrollspy.destroy();\n }\n options = null;\n scrollspy = null;\n });\n\n }\n };\n\n })\n\n\n .directive('bsScrollspyList', function($rootScope, debounce, dimensions, $scrollspy) {\n\n return {\n restrict: 'A',\n compile: function postLink(element, attr) {\n var children = element[0].querySelectorAll('li > a[href]');\n angular.forEach(children, function(child) {\n var childEl = angular.element(child);\n childEl.parent().attr('bs-scrollspy', '').attr('data-target', childEl.attr('href'));\n });\n }\n\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.select', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions'])\n\n .provider('$select', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'select',\n prefixEvent: '$select',\n placement: 'bottom-left',\n templateUrl: 'select/select.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n multiple: false,\n allNoneButtons: false,\n sort: true,\n caretHtml: ' ',\n placeholder: 'Choose among the following...',\n allText: 'All',\n noneText: 'None',\n maxLength: 3,\n maxLengthHtml: 'selected',\n iconCheckmark: 'glyphicon glyphicon-ok'\n };\n\n this.$get = function($window, $document, $rootScope, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n\n function SelectFactory(element, controller, config) {\n\n var $select = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $select = $tooltip(element, options);\n var scope = $select.$scope;\n\n scope.$matches = [];\n if (options.multiple) {\n scope.$activeIndex = [];\n }\n else {\n scope.$activeIndex = -1;\n }\n scope.$isMultiple = options.multiple;\n scope.$showAllNoneButtons = options.allNoneButtons && options.multiple;\n scope.$iconCheckmark = options.iconCheckmark;\n scope.$allText = options.allText;\n scope.$noneText = options.noneText;\n\n scope.$activate = function(index) {\n scope.$$postDigest(function() {\n $select.activate(index);\n });\n };\n\n scope.$select = function(index, evt) {\n scope.$$postDigest(function() {\n $select.select(index);\n });\n };\n\n scope.$isVisible = function() {\n return $select.$isVisible();\n };\n\n scope.$isActive = function(index) {\n return $select.$isActive(index);\n };\n\n scope.$selectAll = function () {\n for (var i = 0; i < scope.$matches.length; i++) {\n if (!scope.$isActive(i)) {\n scope.$select(i);\n }\n }\n };\n\n scope.$selectNone = function () {\n for (var i = 0; i < scope.$matches.length; i++) {\n if (scope.$isActive(i)) {\n scope.$select(i);\n }\n }\n };\n\n // Public methods\n\n $select.update = function(matches) {\n scope.$matches = matches;\n $select.$updateActiveIndex();\n };\n\n $select.activate = function(index) {\n if(options.multiple) {\n $select.$isActive(index) ? scope.$activeIndex.splice(scope.$activeIndex.indexOf(index), 1) : scope.$activeIndex.push(index);\n if(options.sort) scope.$activeIndex.sort(function(a, b) { return a - b; }); // use numeric sort instead of default sort\n } else {\n scope.$activeIndex = index;\n }\n return scope.$activeIndex;\n };\n\n $select.select = function(index) {\n var value = scope.$matches[index].value;\n scope.$apply(function() {\n $select.activate(index);\n if(options.multiple) {\n controller.$setViewValue(scope.$activeIndex.map(function(index) {\n return scope.$matches[index].value;\n }));\n } else {\n controller.$setViewValue(value);\n // Hide if single select\n $select.hide();\n }\n });\n // Emit event\n scope.$emit(options.prefixEvent + '.select', value, index, $select);\n };\n\n // Protected methods\n\n $select.$updateActiveIndex = function() {\n if(controller.$modelValue && scope.$matches.length) {\n if(options.multiple && angular.isArray(controller.$modelValue)) {\n scope.$activeIndex = controller.$modelValue.map(function(value) {\n return $select.$getIndex(value);\n });\n } else {\n scope.$activeIndex = $select.$getIndex(controller.$modelValue);\n }\n } else if(scope.$activeIndex >= scope.$matches.length) {\n scope.$activeIndex = options.multiple ? [] : 0;\n }\n };\n\n $select.$isVisible = function() {\n if(!options.minLength || !controller) {\n return scope.$matches.length;\n }\n // minLength support\n return scope.$matches.length && controller.$viewValue.length >= options.minLength;\n };\n\n $select.$isActive = function(index) {\n if(options.multiple) {\n return scope.$activeIndex.indexOf(index) !== -1;\n } else {\n return scope.$activeIndex === index;\n }\n };\n\n $select.$getIndex = function(value) {\n var l = scope.$matches.length, i = l;\n if(!l) return;\n for(i = l; i--;) {\n if(scope.$matches[i].value === value) break;\n }\n if(i < 0) return;\n return i;\n };\n\n $select.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n targetEl.triggerHandler('click');\n }\n };\n\n $select.$onKeyDown = function(evt) {\n if (!/(9|13|38|40)/.test(evt.keyCode)) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // release focus on tab\n if (options.multiple && evt.keyCode === 9) {\n return $select.hide();\n }\n\n // Select with enter\n if(!options.multiple && (evt.keyCode === 13 || evt.keyCode === 9)) {\n return $select.select(scope.$activeIndex);\n }\n\n if (!options.multiple) {\n // Navigate with keyboard\n if(evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--;\n else if(evt.keyCode === 38 && scope.$activeIndex < 0) scope.$activeIndex = scope.$matches.length - 1;\n else if(evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++;\n else if(angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0;\n scope.$digest();\n }\n };\n\n // Overrides\n\n var _show = $select.show;\n $select.show = function() {\n _show();\n if(options.multiple) {\n $select.$element.addClass('select-multiple');\n }\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n $select.$element.on(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $select.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $select.hide;\n $select.hide = function() {\n if(!options.multiple && !controller.$modelValue) {\n scope.$activeIndex = -1;\n }\n $select.$element.off(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $select.$onKeyDown);\n }\n _hide(true);\n };\n\n return $select;\n\n }\n\n SelectFactory.defaults = defaults;\n return SelectFactory;\n\n };\n\n })\n\n .directive('bsSelect', function($window, $parse, $q, $select, $parseOptions) {\n\n var defaults = $select.defaults;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope, placeholder: defaults.placeholder};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'placeholder', 'allNoneButtons', 'maxLength', 'maxLengthHtml', 'allText', 'noneText', 'iconCheckmark', 'autoClose', 'id', 'sort', 'caretHtml', 'prefixClass', 'prefixEvent'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'allNoneButtons', 'sort'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Only parse data-multiple. Angular sets existence attributes to true (multiple/required/etc), they apply this\n // to data-multiple as well for some reason, so we'll parse this ourselves and disregard multiple\n var dataMultiple = element.attr('data-multiple');\n if(angular.isDefined(dataMultiple)) {\n if(falseValueRegExp.test(dataMultiple))\n options.multiple = false;\n else\n options.multiple = dataMultiple;\n }\n\n // Add support for select markup\n if(element[0].nodeName.toLowerCase() === 'select') {\n var inputEl = element;\n inputEl.css('display', 'none');\n element = angular.element('');\n inputEl.after(element);\n }\n\n // Build proper bsOptions\n var parsedOptions = $parseOptions(attr.bsOptions);\n\n // Initialize select\n var select = $select(element, controller, options);\n\n // Watch bsOptions values before filtering for changes\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').trim();\n scope.$watchCollection(watchedOptions, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue);\n parsedOptions.valuesFn(scope, controller)\n .then(function(values) {\n select.update(values);\n controller.$render();\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue);\n select.$updateActiveIndex();\n controller.$render();\n }, true);\n\n // Model rendering in view\n controller.$render = function () {\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n var selected, index;\n if(options.multiple && angular.isArray(controller.$modelValue)) {\n selected = controller.$modelValue.map(function(value) {\n index = select.$getIndex(value);\n return angular.isDefined(index) ? select.$scope.$matches[index].label : false;\n }).filter(angular.isDefined);\n if(selected.length > (options.maxLength || defaults.maxLength)) {\n selected = selected.length + ' ' + (options.maxLengthHtml || defaults.maxLengthHtml);\n } else {\n selected = selected.join(', ');\n }\n } else {\n index = select.$getIndex(controller.$modelValue);\n selected = angular.isDefined(index) ? select.$scope.$matches[index].label : false;\n }\n element.html((selected ? selected : options.placeholder) + (options.caretHtml ? options.caretHtml : defaults.caretHtml));\n };\n\n if(options.multiple){\n controller.$isEmpty = function(value){\n return !value || value.length === 0;\n };\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (select) select.destroy();\n options = null;\n select = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.timepicker', ['mgcrea.ngStrap.helpers.dateParser', 'mgcrea.ngStrap.helpers.dateFormatter', 'mgcrea.ngStrap.tooltip'])\n\n .provider('$timepicker', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n //uncommenting the following line will break backwards compatability\n // prefixEvent: 'timepicker',\n prefixClass: 'timepicker',\n placement: 'bottom-left',\n templateUrl: 'timepicker/timepicker.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n // lang: $locale.id,\n useNative: true,\n timeType: 'date',\n timeFormat: 'shortTime',\n timezone: null,\n modelTimeFormat: null,\n autoclose: false,\n minTime: -Infinity,\n maxTime: +Infinity,\n length: 5,\n hourStep: 1,\n minuteStep: 5,\n secondStep: 5,\n roundDisplay: false,\n iconUp: 'glyphicon glyphicon-chevron-up',\n iconDown: 'glyphicon glyphicon-chevron-down',\n arrowBehavior: 'pager'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) {\n\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if (!defaults.lang) {\n defaults.lang = $dateFormatter.getDefaultLocale();\n }\n\n function timepickerFactory(element, controller, config) {\n\n var $timepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $timepicker.$options;\n var scope = $timepicker.$scope;\n\n var lang = options.lang;\n var formatDate = function(date, format, timezone) {\n return $dateFormatter.formatDate(date, format, lang, timezone);\n };\n\n function floorMinutes(time) {\n // coeff used to floor current time to nearest minuteStep interval\n var coeff = 1000 * 60 * options.minuteStep;\n return new Date(Math.floor(time.getTime() / coeff) * coeff);\n }\n\n // View vars\n\n var selectedIndex = 0;\n var defaultDate = options.roundDisplay ? floorMinutes(new Date()) : new Date();\n var startDate = controller.$dateValue || defaultDate;\n var viewDate = {\n hour: startDate.getHours(),\n meridian: startDate.getHours() < 12,\n minute: startDate.getMinutes(),\n second: startDate.getSeconds(),\n millisecond: startDate.getMilliseconds()\n };\n\n var format = $dateFormatter.getDatetimeFormat(options.timeFormat, lang);\n\n var hoursFormat = $dateFormatter.hoursFormat(format),\n timeSeparator = $dateFormatter.timeSeparator(format),\n minutesFormat = $dateFormatter.minutesFormat(format),\n secondsFormat = $dateFormatter.secondsFormat(format),\n showSeconds = $dateFormatter.showSeconds(format),\n showAM = $dateFormatter.showAM(format);\n\n scope.$iconUp = options.iconUp;\n scope.$iconDown = options.iconDown;\n\n // Scope methods\n\n scope.$select = function(date, index) {\n $timepicker.select(date, index);\n };\n scope.$moveIndex = function(value, index) {\n $timepicker.$moveIndex(value, index);\n };\n scope.$switchMeridian = function(date) {\n $timepicker.switchMeridian(date);\n };\n\n // Public methods\n\n $timepicker.update = function(date) {\n // console.warn('$timepicker.update() newValue=%o', date);\n if (angular.isDate(date) && !isNaN(date.getTime())) {\n $timepicker.$date = date;\n angular.extend(viewDate, {\n hour: date.getHours(),\n minute: date.getMinutes(),\n second: date.getSeconds(),\n millisecond: date.getMilliseconds()\n });\n $timepicker.$build();\n } else if (!$timepicker.$isBuilt) {\n $timepicker.$build();\n }\n };\n\n $timepicker.select = function(date, index, keep) {\n // console.warn('$timepicker.select', date, scope.$mode);\n if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) controller.$dateValue = new Date(1970, 0, 1);\n if (!angular.isDate(date)) date = new Date(date);\n if (index === 0) controller.$dateValue.setHours(date.getHours());\n else if (index === 1) controller.$dateValue.setMinutes(date.getMinutes());\n else if (index === 2) controller.$dateValue.setSeconds(date.getSeconds());\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n if (options.autoclose && !keep) {\n $timeout(function() {\n $timepicker.hide(true);\n });\n }\n };\n\n $timepicker.switchMeridian = function(date) {\n if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) {\n return;\n }\n var hours = (date || controller.$dateValue).getHours();\n controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12);\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n };\n\n // Protected methods\n\n $timepicker.$build = function() {\n // console.warn('$timepicker.$build() viewDate=%o', viewDate);\n var i, midIndex = scope.midIndex = parseInt(options.length / 2, 10);\n var hours = [],\n hour;\n for (i = 0; i < options.length; i++) {\n hour = new Date(1970, 0, 1, viewDate.hour - (midIndex - i) * options.hourStep);\n hours.push({\n date: hour,\n label: formatDate(hour, hoursFormat),\n selected: $timepicker.$date && $timepicker.$isSelected(hour, 0),\n disabled: $timepicker.$isDisabled(hour, 0)\n });\n }\n var minutes = [],\n minute;\n for (i = 0; i < options.length; i++) {\n minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep);\n minutes.push({\n date: minute,\n label: formatDate(minute, minutesFormat),\n selected: $timepicker.$date && $timepicker.$isSelected(minute, 1),\n disabled: $timepicker.$isDisabled(minute, 1)\n });\n }\n var seconds = [],\n second;\n for (i = 0; i < options.length; i++) {\n second = new Date(1970, 0, 1, 0, 0, viewDate.second - (midIndex - i) * options.secondStep);\n seconds.push({\n date: second,\n label: formatDate(second, secondsFormat),\n selected: $timepicker.$date && $timepicker.$isSelected(second, 2),\n disabled: $timepicker.$isDisabled(second, 2)\n });\n }\n\n var rows = [];\n for (i = 0; i < options.length; i++) {\n if (showSeconds) {\n rows.push([hours[i], minutes[i], seconds[i]]);\n } else {\n rows.push([hours[i], minutes[i]]);\n }\n }\n scope.rows = rows;\n scope.showSeconds = showSeconds;\n scope.showAM = showAM;\n scope.isAM = ($timepicker.$date || hours[midIndex].date).getHours() < 12;\n scope.timeSeparator = timeSeparator;\n $timepicker.$isBuilt = true;\n };\n\n $timepicker.$isSelected = function(date, index) {\n if (!$timepicker.$date) return false;\n else if (index === 0) {\n return date.getHours() === $timepicker.$date.getHours();\n } else if (index === 1) {\n return date.getMinutes() === $timepicker.$date.getMinutes();\n } else if (index === 2) {\n return date.getSeconds() === $timepicker.$date.getSeconds();\n }\n };\n\n $timepicker.$isDisabled = function(date, index) {\n var selectedTime;\n if (index === 0) {\n selectedTime = date.getTime() + viewDate.minute * 6e4 + viewDate.second * 1e3;\n } else if (index === 1) {\n selectedTime = date.getTime() + viewDate.hour * 36e5 + viewDate.second * 1e3;\n } else if (index === 2) {\n selectedTime = date.getTime() + viewDate.hour * 36e5 + viewDate.minute * 6e4;\n }\n return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1;\n };\n\n scope.$arrowAction = function(value, index) {\n if (options.arrowBehavior === 'picker') {\n $timepicker.$setTimeByStep(value, index);\n } else {\n $timepicker.$moveIndex(value, index);\n }\n };\n\n $timepicker.$setTimeByStep = function(value, index) {\n var newDate = new Date($timepicker.$date || startDate);\n var hours = newDate.getHours();\n var minutes = newDate.getMinutes();\n var seconds = newDate.getSeconds();\n if (index === 0) {\n newDate.setHours(hours - (parseInt(options.hourStep, 10) * value));\n } else if (index === 1) {\n newDate.setMinutes(minutes - (parseInt(options.minuteStep, 10) * value));\n } else if (index === 2) {\n newDate.setSeconds(seconds - (parseInt(options.secondStep, 10) * value));\n }\n $timepicker.select(newDate, index, true);\n };\n\n $timepicker.$moveIndex = function(value, index) {\n var targetDate;\n if (index === 0) {\n targetDate = new Date(1970, 0, 1, viewDate.hour + (value * options.length), viewDate.minute, viewDate.second);\n angular.extend(viewDate, {\n hour: targetDate.getHours()\n });\n } else if (index === 1) {\n targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + (value * options.length * options.minuteStep), viewDate.second);\n angular.extend(viewDate, {\n minute: targetDate.getMinutes()\n });\n } else if (index === 2) {\n targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute, viewDate.second + (value * options.length * options.secondStep));\n angular.extend(viewDate, {\n second: targetDate.getSeconds()\n });\n }\n $timepicker.$build();\n };\n\n $timepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n if (evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if (isTouch) {\n var targetEl = angular.element(evt.target);\n if (targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $timepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // Close on enter\n if (evt.keyCode === 13) {\n $timepicker.hide(true);\n return;\n }\n\n // Navigate with keyboard\n var newDate = new Date($timepicker.$date);\n var hours = newDate.getHours(),\n hoursLength = formatDate(newDate, hoursFormat).length;\n var minutes = newDate.getMinutes(),\n minutesLength = formatDate(newDate, minutesFormat).length;\n var seconds = newDate.getSeconds(),\n secondsLength = formatDate(newDate, secondsFormat).length;\n var sepLength = 1;\n var lateralMove = /(37|39)/.test(evt.keyCode);\n var count = 2 + showSeconds * 1 + showAM * 1;\n\n // Navigate indexes (left, right)\n if (lateralMove) {\n if (evt.keyCode === 37) selectedIndex = selectedIndex < 1 ? count - 1 : selectedIndex - 1;\n else if (evt.keyCode === 39) selectedIndex = selectedIndex < count - 1 ? selectedIndex + 1 : 0;\n }\n\n // Update values (up, down)\n var selectRange = [0, hoursLength];\n var incr = 0;\n if (evt.keyCode === 38) incr = -1;\n if (evt.keyCode === 40) incr = +1;\n var isSeconds = selectedIndex === 2 && showSeconds;\n var isMeridian = selectedIndex === 2 && !showSeconds || selectedIndex === 3 && showSeconds;\n if (selectedIndex === 0) {\n newDate.setHours(hours + incr * parseInt(options.hourStep, 10));\n // re-calculate hours length because we have changed hours value\n hoursLength = formatDate(newDate, hoursFormat).length;\n selectRange = [0, hoursLength];\n } else if (selectedIndex === 1) {\n newDate.setMinutes(minutes + incr * parseInt(options.minuteStep, 10));\n // re-calculate minutes length because we have changes minutes value\n minutesLength = formatDate(newDate, minutesFormat).length;\n selectRange = [hoursLength + sepLength, minutesLength];\n } else if (isSeconds) {\n newDate.setSeconds(seconds + incr * parseInt(options.secondStep, 10));\n // re-calculate seconds length because we have changes seconds value\n secondsLength = formatDate(newDate, secondsFormat).length;\n selectRange = [hoursLength + sepLength + minutesLength + sepLength, secondsLength];\n } else if (isMeridian) {\n if (!lateralMove) $timepicker.switchMeridian();\n selectRange = [hoursLength + sepLength + minutesLength + sepLength + (secondsLength + sepLength) * showSeconds, 2];\n }\n $timepicker.select(newDate, selectedIndex, true);\n createSelection(selectRange[0], selectRange[1]);\n parentScope.$digest();\n };\n\n // Private\n\n function createSelection(start, length) {\n var end = start + length;\n if (element[0].createTextRange) {\n var selRange = element[0].createTextRange();\n selRange.collapse(true);\n selRange.moveStart('character', start);\n selRange.moveEnd('character', end);\n selRange.select();\n } else if (element[0].setSelectionRange) {\n element[0].setSelectionRange(start, end);\n } else if (angular.isUndefined(element[0].selectionStart)) {\n element[0].selectionStart = start;\n element[0].selectionEnd = end;\n }\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $timepicker.init;\n $timepicker.init = function() {\n if (isNative && options.useNative) {\n element.prop('type', 'time');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if (isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $timepicker.destroy;\n $timepicker.destroy = function() {\n if (isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $timepicker.show;\n $timepicker.show = function() {\n if((!isTouch && element.attr('readonly')) || element.attr('disabled')) return;\n _show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n $timepicker.$element && $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if (options.keyboard) {\n element && element.on('keydown', $timepicker.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $timepicker.hide;\n $timepicker.hide = function(blur) {\n if (!$timepicker.$isShown) return;\n $timepicker.$element && $timepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if (options.keyboard) {\n element && element.off('keydown', $timepicker.$onKeyDown);\n }\n _hide(blur);\n };\n\n return $timepicker;\n\n }\n\n timepickerFactory.defaults = defaults;\n return timepickerFactory;\n\n };\n\n })\n\n\n .directive('bsTimepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) {\n\n var defaults = $timepicker.defaults;\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {\n scope: scope\n };\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'autoclose', 'timeType', 'timeFormat', 'timezone', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'secondStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown', 'roundDisplay', 'id', 'prefixClass', 'prefixEvent'], function(key) {\n if (angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'autoclose', 'useNative', 'roundDisplay'], function(key) {\n if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if (!timepicker || !angular.isDefined(newValue)) return;\n if (angular.isString(newValue)) newValue = !!newValue.match(/true|,?(timepicker),?/i);\n newValue === true ? timepicker.show() : timepicker.hide();\n });\n\n // Initialize timepicker\n if (isNative && (options.useNative || defaults.useNative)) options.timeFormat = 'HH:mm';\n var timepicker = $timepicker(element, controller, options);\n options = timepicker.$options;\n\n var lang = options.lang;\n var formatDate = function(date, format, timezone) {\n return $dateFormatter.formatDate(date, format, lang, timezone);\n };\n\n // Initialize parser\n var dateParser = $dateParser({\n format: options.timeFormat,\n lang: lang\n });\n\n // Observe attributes for changes\n angular.forEach(['minTime', 'maxTime'], function(key) {\n // console.warn('attr.$observe(%s)', key, attr[key]);\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\n timepicker.$options[key] = dateParser.getTimeForAttribute(key, newValue);\n !isNaN(timepicker.$options[key]) && timepicker.$build();\n validateAgainstMinMaxTime(controller.$dateValue);\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue, controller.$dateValue);\n timepicker.update(controller.$dateValue);\n }, true);\n\n function validateAgainstMinMaxTime(parsedTime) {\n if (!angular.isDate(parsedTime)) return;\n var isMinValid = isNaN(options.minTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) >= options.minTime;\n var isMaxValid = isNaN(options.maxTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) <= options.maxTime;\n var isValid = isMinValid && isMaxValid;\n controller.$setValidity('date', isValid);\n controller.$setValidity('min', isMinValid);\n controller.$setValidity('max', isMaxValid);\n // Only update the model when we have a valid date\n if (!isValid) {\n return;\n }\n controller.$dateValue = parsedTime;\n }\n\n // viewValue -> $parsers -> modelValue\n controller.$parsers.unshift(function(viewValue) {\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\n var date;\n // Null values should correctly reset the model value & validity\n if (!viewValue) {\n // BREAKING CHANGE:\n // return null (not undefined) when input value is empty, so angularjs 1.3\n // ngModelController can go ahead and run validators, like ngRequired\n controller.$setValidity('date', true);\n return null;\n }\n var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue);\n if (!parsedTime || isNaN(parsedTime.getTime())) {\n controller.$setValidity('date', false);\n // Return undefined, causes ngModelController to\n // invalidate model value\n return undefined;\n } else {\n validateAgainstMinMaxTime(parsedTime);\n }\n\n if (options.timeType === 'string') {\n date = dateParser.timezoneOffsetAdjust(parsedTime, options.timezone, true);\n return formatDate(date, options.modelTimeFormat || options.timeFormat);\n }\n date = dateParser.timezoneOffsetAdjust(controller.$dateValue, options.timezone, true);\n if (options.timeType === 'number') {\n return date.getTime();\n } else if (options.timeType === 'unix') {\n return date.getTime() / 1000;\n } else if (options.timeType === 'iso') {\n return date.toISOString();\n } else {\n return new Date(date);\n }\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var date;\n if (angular.isUndefined(modelValue) || modelValue === null) {\n date = NaN;\n } else if (angular.isDate(modelValue)) {\n date = modelValue;\n } else if (options.timeType === 'string') {\n date = dateParser.parse(modelValue, null, options.modelTimeFormat);\n } else if (options.timeType === 'unix') {\n date = new Date(modelValue * 1000);\n } else {\n date = new Date(modelValue);\n }\n // Setup default value?\n // if(isNaN(date.getTime())) date = new Date(new Date().setMinutes(0) + 36e5);\n controller.$dateValue = dateParser.timezoneOffsetAdjust(date, options.timezone);\n return getTimeFormattedString();\n });\n\n // viewValue -> element\n controller.$render = function() {\n // console.warn('$render(\"%s\"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);\n element.val(getTimeFormattedString());\n };\n\n function getTimeFormattedString() {\n return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat);\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (timepicker) timepicker.destroy();\n options = null;\n timepicker = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.tab', [])\n\n .provider('$tab', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n template: 'tab/tab.tpl.html',\n navClass: 'nav-tabs',\n activeClass: 'active'\n };\n\n var controller = this.controller = function($scope, $element, $attrs) {\n var self = this;\n\n // Attributes options\n self.$options = angular.copy(defaults);\n angular.forEach(['animation', 'navClass', 'activeClass'], function(key) {\n if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];\n });\n\n // Publish options on scope\n $scope.$navClass = self.$options.navClass;\n $scope.$activeClass = self.$options.activeClass;\n\n self.$panes = $scope.$panes = [];\n\n // Please use $activePaneChangeListeners if you use `bsActivePane`\n // Because we removed `ngModel` as default, we rename viewChangeListeners to\n // activePaneChangeListeners to make more sense.\n self.$activePaneChangeListeners = self.$viewChangeListeners = [];\n\n self.$push = function(pane) {\n if(angular.isUndefined(self.$panes.$active)) {\n $scope.$setActive(pane.name || 0);\n }\n self.$panes.push(pane);\n };\n\n self.$remove = function(pane) {\n var index = self.$panes.indexOf(pane);\n var active = self.$panes.$active;\n var activeIndex;\n if(angular.isString(active)) {\n activeIndex = self.$panes.map(function(pane) {\n return pane.name;\n }).indexOf(active);\n } else {\n activeIndex = self.$panes.$active;\n }\n\n // remove pane from $panes array\n self.$panes.splice(index, 1);\n\n if (index < activeIndex) {\n // we removed a pane before the active pane, so we need to\n // decrement the active pane index\n activeIndex--;\n }\n else if (index === activeIndex && activeIndex === self.$panes.length) {\n // we remove the active pane and it was the one at the end,\n // so select the previous one\n activeIndex--;\n }\n if(activeIndex >= 0 && activeIndex < self.$panes.length) {\n self.$setActive(self.$panes[activeIndex].name || activeIndex);\n } else {\n self.$setActive();\n }\n };\n\n self.$setActive = $scope.$setActive = function(value) {\n self.$panes.$active = value;\n self.$activePaneChangeListeners.forEach(function(fn) {\n fn();\n });\n };\n\n self.$isActive = $scope.$isActive = function($pane, $index) {\n return self.$panes.$active === $pane.name || self.$panes.$active === $index;\n };\n\n };\n\n this.$get = function() {\n var $tab = {};\n $tab.defaults = defaults;\n $tab.controller = controller;\n return $tab;\n };\n\n })\n\n .directive('bsTabs', function($window, $animate, $tab, $parse) {\n\n var defaults = $tab.defaults;\n\n return {\n require: ['?ngModel', 'bsTabs'],\n transclude: true,\n scope: true,\n controller: ['$scope', '$element', '$attrs', $tab.controller],\n templateUrl: function(element, attr) {\n return attr.template || defaults.template;\n },\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsTabsCtrl = controllers[1];\n\n // 'ngModel' does interfere with form validation\n // and status, use `bsActivePane` instead to avoid it\n if(ngModelCtrl) {\n\n // Update the modelValue following\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\n ngModelCtrl.$setViewValue(bsTabsCtrl.$panes.$active);\n });\n\n // modelValue -> $formatters -> viewValue\n ngModelCtrl.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n bsTabsCtrl.$setActive(modelValue);\n return modelValue;\n });\n\n }\n\n if (attrs.bsActivePane) {\n // adapted from angularjs ngModelController bindings\n // https://github.com/angular/angular.js/blob/v1.3.1/src%2Fng%2Fdirective%2Finput.js#L1730\n var parsedBsActivePane = $parse(attrs.bsActivePane);\n\n // Update bsActivePane value with change\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\n parsedBsActivePane.assign(scope, bsTabsCtrl.$panes.$active);\n });\n\n // watch bsActivePane for value changes\n scope.$watch(attrs.bsActivePane, function(newValue, oldValue) {\n bsTabsCtrl.$setActive(newValue);\n }, true);\n }\n }\n };\n\n })\n\n .directive('bsPane', function($window, $animate, $sce) {\n\n return {\n require: ['^?ngModel', '^bsTabs'],\n scope: true,\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsTabsCtrl = controllers[1];\n\n // Add base class\n element.addClass('tab-pane');\n\n // Observe title attribute for change\n attrs.$observe('title', function(newValue, oldValue) {\n scope.title = $sce.trustAsHtml(newValue);\n });\n\n // Save tab name into scope\n scope.name = attrs.name;\n\n // Add animation class\n if(bsTabsCtrl.$options.animation) {\n element.addClass(bsTabsCtrl.$options.animation);\n }\n\n attrs.$observe('disabled', function(newValue, oldValue) {\n scope.disabled = scope.$eval(newValue);\n });\n\n // Push pane to parent bsTabs controller\n bsTabsCtrl.$push(scope);\n\n // remove pane from tab controller when pane is destroyed\n scope.$on('$destroy', function() {\n bsTabsCtrl.$remove(scope);\n });\n\n function render() {\n var index = bsTabsCtrl.$panes.indexOf(scope);\n $animate[bsTabsCtrl.$isActive(scope, index) ? 'addClass' : 'removeClass'](element, bsTabsCtrl.$options.activeClass);\n }\n\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\n render();\n });\n render();\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.typeahead', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions'])\n\n .provider('$typeahead', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'typeahead',\n prefixEvent: '$typeahead',\n placement: 'bottom-left',\n templateUrl: 'typeahead/typeahead.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n minLength: 1,\n filter: 'bsAsyncFilter',\n limit: 6,\n autoSelect: false,\n comparator: '',\n trimValue: true\n };\n\n this.$get = function($window, $rootScope, $tooltip, $$rAF, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n\n function TypeaheadFactory(element, controller, config) {\n\n var $typeahead = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $typeahead = $tooltip(element, options);\n var parentScope = config.scope;\n var scope = $typeahead.$scope;\n\n scope.$resetMatches = function() {\n scope.$matches = [];\n scope.$activeIndex = options.autoSelect ? 0 : -1; // If set to 0, the first match will be highlighted\n };\n scope.$resetMatches();\n\n scope.$activate = function(index) {\n scope.$$postDigest(function() {\n $typeahead.activate(index);\n });\n };\n\n scope.$select = function(index, evt) {\n scope.$$postDigest(function() {\n $typeahead.select(index);\n });\n };\n\n scope.$isVisible = function() {\n return $typeahead.$isVisible();\n };\n\n // Public methods\n\n $typeahead.update = function(matches) {\n scope.$matches = matches;\n if (scope.$activeIndex >= matches.length) {\n scope.$activeIndex = options.autoSelect ? 0 : -1;\n }\n\n // wrap in a $timeout so the results are updated\n // before repositioning\n safeDigest(scope);\n $$rAF($typeahead.$applyPlacement);\n };\n\n $typeahead.activate = function(index) {\n scope.$activeIndex = index;\n };\n\n $typeahead.select = function(index) {\n if (index === -1) return;\n var value = scope.$matches[index].value;\n // console.log('$setViewValue', value);\n controller.$setViewValue(value);\n controller.$render();\n scope.$resetMatches();\n if (parentScope) parentScope.$digest();\n // Emit event\n scope.$emit(options.prefixEvent + '.select', value, index, $typeahead);\n };\n\n // Protected methods\n\n $typeahead.$isVisible = function() {\n if (!options.minLength || !controller) {\n return !!scope.$matches.length;\n }\n // minLength support\n return scope.$matches.length && angular.isString(controller.$viewValue) && controller.$viewValue.length >= options.minLength;\n };\n\n $typeahead.$getIndex = function(value) {\n var l = scope.$matches.length,\n i = l;\n if (!l) return;\n for (i = l; i--;) {\n if (scope.$matches[i].value === value) break;\n }\n if (i < 0) return;\n return i;\n };\n\n $typeahead.$onMouseDown = function(evt) {\n // Prevent blur on mousedown\n evt.preventDefault();\n evt.stopPropagation();\n };\n\n $typeahead.$onKeyDown = function(evt) {\n if (!/(38|40|13)/.test(evt.keyCode)) return;\n\n // Let ngSubmit pass if the typeahead tip is hidden or no option is selected\n if ($typeahead.$isVisible() && !(evt.keyCode === 13 && scope.$activeIndex === -1)) {\n evt.preventDefault();\n evt.stopPropagation();\n }\n\n // Select with enter\n if (evt.keyCode === 13 && scope.$matches.length) {\n $typeahead.select(scope.$activeIndex);\n }\n\n // Navigate with keyboard\n else if (evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--;\n else if (evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++;\n else if (angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0;\n scope.$digest();\n };\n\n // Overrides\n\n var show = $typeahead.show;\n $typeahead.show = function() {\n show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed immediately.\n $timeout(function() {\n $typeahead.$element && $typeahead.$element.on('mousedown', $typeahead.$onMouseDown);\n if (options.keyboard) {\n element && element.on('keydown', $typeahead.$onKeyDown);\n }\n }, 0, false);\n };\n\n var hide = $typeahead.hide;\n $typeahead.hide = function() {\n $typeahead.$element && $typeahead.$element.off('mousedown', $typeahead.$onMouseDown);\n if (options.keyboard) {\n element && element.off('keydown', $typeahead.$onKeyDown);\n }\n if (!options.autoSelect)\n $typeahead.activate(-1);\n hide();\n };\n\n return $typeahead;\n\n }\n\n // Helper functions\n\n function safeDigest(scope) {\n scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();\n }\n\n TypeaheadFactory.defaults = defaults;\n return TypeaheadFactory;\n\n };\n\n })\n\n .filter('bsAsyncFilter', function($filter) {\n return function(array, expression, comparator) {\n if (array && angular.isFunction(array.then)) {\n return array.then(function(results) {\n return $filter('filter')(results, expression, comparator);\n });\n } else {\n return $filter('filter')(array, expression, comparator);\n }\n };\n })\n\n .directive('bsTypeahead', function($window, $parse, $q, $typeahead, $parseOptions) {\n\n var defaults = $typeahead.defaults;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {\n scope: scope\n };\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'filter', 'limit', 'minLength', 'watchOptions', 'selectMode', 'autoSelect', 'comparator', 'id', 'prefixEvent', 'prefixClass'], function(key) {\n if (angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'trimValue'], function(key) {\n if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false;\n });\n\n // Disable browser autocompletion\n element.attr('autocomplete', 'false');\n\n // Build proper bsOptions\n var filter = options.filter || defaults.filter;\n var limit = options.limit || defaults.limit;\n var comparator = options.comparator || defaults.comparator;\n\n var bsOptions = attr.bsOptions;\n if (filter) bsOptions += ' | ' + filter + ':$viewValue';\n if (comparator) bsOptions += ':' + comparator;\n if (limit) bsOptions += ' | limitTo:' + limit;\n var parsedOptions = $parseOptions(bsOptions);\n\n // Initialize typeahead\n var typeahead = $typeahead(element, controller, options);\n\n // Watch options on demand\n if (options.watchOptions) {\n // Watch bsOptions values before filtering for changes, drop function calls\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').replace(/\\(.*\\)/g, '').trim();\n scope.$watchCollection(watchedOptions, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue);\n parsedOptions.valuesFn(scope, controller).then(function(values) {\n typeahead.update(values);\n controller.$render();\n });\n });\n }\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('$watch', element.attr('ng-model'), newValue);\n scope.$modelValue = newValue; // Publish modelValue on scope for custom templates\n parsedOptions.valuesFn(scope, controller)\n .then(function(values) {\n // Prevent input with no future prospect if selectMode is truthy\n // @TODO test selectMode\n if (options.selectMode && !values.length && newValue.length > 0) {\n controller.$setViewValue(controller.$viewValue.substring(0, controller.$viewValue.length - 1));\n return;\n }\n if (values.length > limit) values = values.slice(0, limit);\n var isVisible = typeahead.$isVisible();\n isVisible && typeahead.update(values);\n // Do not re-queue an update if a correct value has been selected\n if (values.length === 1 && values[0].value === newValue) return;\n !isVisible && typeahead.update(values);\n // Queue a new rendering that will leverage collection loading\n controller.$render();\n });\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var displayValue = parsedOptions.displayValue(modelValue);\n\n // If we can determine the displayValue, use that\n if (displayValue) {\n return displayValue;\n }\n\n // If there's no display value, attempt to use the modelValue.\n // If the model is an object not much we can do\n if (modelValue && typeof modelValue !== 'object') {\n return modelValue;\n }\n return '';\n });\n\n // Model rendering in view\n controller.$render = function() {\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n if (controller.$isEmpty(controller.$viewValue)) {\n return element.val('');\n }\n var index = typeahead.$getIndex(controller.$modelValue);\n var selected = angular.isDefined(index) ? typeahead.$scope.$matches[index].label : controller.$viewValue;\n selected = angular.isObject(selected) ? parsedOptions.displayValue(selected) : selected;\n var value = selected ? selected.toString().replace(/<(?:.|\\n)*?>/gm, '') : '';\n element.val(options.trimValue === false ? value : value.trim());\n };\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (typeahead) typeahead.destroy();\n options = null;\n typeahead = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.core', 'mgcrea.ngStrap.helpers.dimensions'])\n\n .provider('$tooltip', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n customClass: '',\n prefixClass: 'tooltip',\n prefixEvent: 'tooltip',\n container: false,\n target: false,\n placement: 'top',\n templateUrl: 'tooltip/tooltip.tpl.html',\n template: '',\n contentTemplate: false,\n trigger: 'hover focus',\n keyboard: false,\n html: false,\n show: false,\n title: '',\n type: '',\n delay: 0,\n autoClose: false,\n bsEnabled: true,\n viewport: {\n selector: 'body',\n padding: 0\n }\n };\n\n this.$get = function($window, $rootScope, $bsCompiler, $q, $templateCache, $http, $animate, $sce, dimensions, $$rAF, $timeout) {\n\n var trim = String.prototype.trim;\n var isTouch = 'createTouch' in $window.document;\n var htmlReplaceRegExp = /ng-bind=\"/ig;\n var $body = angular.element($window.document);\n\n function TooltipFactory(element, config) {\n\n var $tooltip = {};\n\n // Common vars\n var options = $tooltip.$options = angular.extend({}, defaults, config);\n var promise = $tooltip.$promise = $bsCompiler.compile(options);\n var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new();\n\n var nodeName = element[0].nodeName.toLowerCase();\n if(options.delay && angular.isString(options.delay)) {\n var split = options.delay.split(',').map(parseFloat);\n options.delay = split.length > 1 ? {show: split[0], hide: split[1]} : split[0];\n }\n\n // Store $id to identify the triggering element in events\n // give priority to options.id, otherwise, try to use\n // element id if defined\n $tooltip.$id = options.id || element.attr('id') || '';\n\n // Support scope as string options\n if(options.title) {\n scope.title = $sce.trustAsHtml(options.title);\n }\n\n // Provide scope helpers\n scope.$setEnabled = function(isEnabled) {\n scope.$$postDigest(function() {\n $tooltip.setEnabled(isEnabled);\n });\n };\n scope.$hide = function() {\n scope.$$postDigest(function() {\n $tooltip.hide();\n });\n };\n scope.$show = function() {\n scope.$$postDigest(function() {\n $tooltip.show();\n });\n };\n scope.$toggle = function() {\n scope.$$postDigest(function() {\n $tooltip.toggle();\n });\n };\n // Publish isShown as a protected var on scope\n $tooltip.$isShown = scope.$isShown = false;\n\n // Private vars\n var timeout, hoverState;\n\n // Fetch, compile then initialize tooltip\n var compileData, tipElement, tipContainer, tipScope;\n promise.then(function(data) {\n compileData = data;\n $tooltip.init();\n });\n\n $tooltip.init = function() {\n\n // Options: delay\n if (options.delay && angular.isNumber(options.delay)) {\n options.delay = {\n show: options.delay,\n hide: options.delay\n };\n }\n\n // Replace trigger on touch devices ?\n // if(isTouch && options.trigger === defaults.trigger) {\n // options.trigger.replace(/hover/g, 'click');\n // }\n\n // Options : container\n if(options.container === 'self') {\n tipContainer = element;\n } else if(angular.isElement(options.container)) {\n tipContainer = options.container;\n } else if(options.container) {\n tipContainer = findElement(options.container);\n }\n\n // Options: trigger\n bindTriggerEvents();\n\n // Options: target\n if(options.target) {\n options.target = angular.isElement(options.target) ? options.target : findElement(options.target);\n }\n\n // Options: show\n if(options.show) {\n scope.$$postDigest(function() {\n options.trigger === 'focus' ? element[0].focus() : $tooltip.show();\n });\n }\n\n };\n\n $tooltip.destroy = function() {\n\n // Unbind events\n unbindTriggerEvents();\n\n // Remove element\n destroyTipElement();\n\n // Destroy scope\n scope.$destroy();\n\n };\n\n $tooltip.enter = function() {\n\n clearTimeout(timeout);\n hoverState = 'in';\n if (!options.delay || !options.delay.show) {\n return $tooltip.show();\n }\n\n timeout = setTimeout(function() {\n if (hoverState ==='in') $tooltip.show();\n }, options.delay.show);\n\n };\n\n $tooltip.show = function() {\n if (!options.bsEnabled || $tooltip.$isShown) return;\n\n scope.$emit(options.prefixEvent + '.show.before', $tooltip);\n var parent, after;\n if (options.container) {\n parent = tipContainer;\n if (tipContainer[0].lastChild) {\n after = angular.element(tipContainer[0].lastChild);\n } else {\n after = null;\n }\n } else {\n parent = null;\n after = element;\n }\n\n\n // Hide any existing tipElement\n if(tipElement) destroyTipElement();\n // Fetch a cloned element linked from template\n tipScope = $tooltip.$scope.$new();\n tipElement = $tooltip.$element = compileData.link(tipScope, function(clonedElement, scope) {});\n\n // Set the initial positioning. Make the tooltip invisible\n // so IE doesn't try to focus on it off screen.\n tipElement.css({top: '-9999px', left: '-9999px', right: 'auto', display: 'block', visibility: 'hidden'});\n\n // Options: animation\n if(options.animation) tipElement.addClass(options.animation);\n // Options: type\n if(options.type) tipElement.addClass(options.prefixClass + '-' + options.type);\n // Options: custom classes\n if(options.customClass) tipElement.addClass(options.customClass);\n\n // Append the element, without any animations. If we append\n // using $animate.enter, some of the animations cause the placement\n // to be off due to the transforms.\n after ? after.after(tipElement) : parent.prepend(tipElement);\n\n $tooltip.$isShown = scope.$isShown = true;\n safeDigest(scope);\n\n // Now, apply placement\n $tooltip.$applyPlacement();\n\n // Once placed, animate it.\n // Support v1.2+ $animate\n // https://github.com/angular/angular.js/issues/11713\n if(angular.version.minor <= 2) {\n $animate.enter(tipElement, parent, after, enterAnimateCallback);\n } else {\n $animate.enter(tipElement, parent, after).then(enterAnimateCallback);\n }\n safeDigest(scope);\n\n $$rAF(function () {\n // Once the tooltip is placed and the animation starts, make the tooltip visible\n if(tipElement) tipElement.css({visibility: 'visible'});\n });\n\n // Bind events\n if(options.keyboard) {\n if(options.trigger !== 'focus') {\n $tooltip.focus();\n }\n bindKeyboardEvents();\n }\n\n if(options.autoClose) {\n bindAutoCloseEvents();\n }\n\n };\n\n function enterAnimateCallback() {\n scope.$emit(options.prefixEvent + '.show', $tooltip);\n }\n\n $tooltip.leave = function() {\n\n clearTimeout(timeout);\n hoverState = 'out';\n if (!options.delay || !options.delay.hide) {\n return $tooltip.hide();\n }\n timeout = setTimeout(function () {\n if (hoverState === 'out') {\n $tooltip.hide();\n }\n }, options.delay.hide);\n\n };\n\n var _blur;\n var _tipToHide;\n $tooltip.hide = function(blur) {\n\n if(!$tooltip.$isShown) return;\n scope.$emit(options.prefixEvent + '.hide.before', $tooltip);\n\n // store blur value for leaveAnimateCallback to use\n _blur = blur;\n\n // store current tipElement reference to use\n // in leaveAnimateCallback\n _tipToHide = tipElement;\n\n // Support v1.2+ $animate\n // https://github.com/angular/angular.js/issues/11713\n if(angular.version.minor <= 2) {\n $animate.leave(tipElement, leaveAnimateCallback);\n } else {\n $animate.leave(tipElement).then(leaveAnimateCallback);\n }\n\n $tooltip.$isShown = scope.$isShown = false;\n safeDigest(scope);\n\n // Unbind events\n if(options.keyboard && tipElement !== null) {\n unbindKeyboardEvents();\n }\n\n if(options.autoClose && tipElement !== null) {\n unbindAutoCloseEvents();\n }\n };\n\n function leaveAnimateCallback() {\n scope.$emit(options.prefixEvent + '.hide', $tooltip);\n\n // check if current tipElement still references\n // the same element when hide was called\n if (tipElement === _tipToHide) {\n // Allow to blur the input when hidden, like when pressing enter key\n if(_blur && options.trigger === 'focus') {\n return element[0].blur();\n }\n\n // clean up child scopes\n destroyTipElement();\n }\n }\n\n $tooltip.toggle = function() {\n $tooltip.$isShown ? $tooltip.leave() : $tooltip.enter();\n };\n\n $tooltip.focus = function() {\n tipElement[0].focus();\n };\n\n $tooltip.setEnabled = function(isEnabled) {\n options.bsEnabled = isEnabled;\n };\n\n $tooltip.setViewport = function(viewport) {\n options.viewport = viewport;\n };\n\n // Protected methods\n\n $tooltip.$applyPlacement = function() {\n if(!tipElement) return;\n\n // Determine if we're doing an auto or normal placement\n var placement = options.placement,\n autoToken = /\\s?auto?\\s?/i,\n autoPlace = autoToken.test(placement);\n\n if (autoPlace) {\n placement = placement.replace(autoToken, '') || defaults.placement;\n }\n\n // Need to add the position class before we get\n // the offsets\n tipElement.addClass(options.placement);\n\n // Get the position of the target element\n // and the height and width of the tooltip so we can center it.\n var elementPosition = getPosition(),\n tipWidth = tipElement.prop('offsetWidth'),\n tipHeight = tipElement.prop('offsetHeight');\n\n // Refresh viewport position\n $tooltip.$viewport = options.viewport && findElement(options.viewport.selector || options.viewport);\n\n // If we're auto placing, we need to check the positioning\n if (autoPlace) {\n var originalPlacement = placement;\n var viewportPosition = getPosition($tooltip.$viewport);\n\n // Determine if the vertical placement\n if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > viewportPosition.bottom) {\n placement = originalPlacement.replace('bottom', 'top');\n } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < viewportPosition.top) {\n placement = originalPlacement.replace('top', 'bottom');\n }\n\n // Determine the horizontal placement\n // The exotic placements of left and right are opposite of the standard placements. Their arrows are put on the left/right\n // and flow in the opposite direction of their placement.\n if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') &&\n elementPosition.right + tipWidth > viewportPosition.width) {\n\n placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right');\n } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') &&\n elementPosition.left - tipWidth < viewportPosition.left) {\n\n placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left');\n }\n\n tipElement.removeClass(originalPlacement).addClass(placement);\n }\n\n // Get the tooltip's top and left coordinates to center it with this directive.\n var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight);\n applyPlacement(tipPosition, placement);\n };\n\n $tooltip.$onKeyUp = function(evt) {\n if (evt.which === 27 && $tooltip.$isShown) {\n $tooltip.hide();\n evt.stopPropagation();\n }\n };\n\n $tooltip.$onFocusKeyUp = function(evt) {\n if (evt.which === 27) {\n element[0].blur();\n evt.stopPropagation();\n }\n };\n\n $tooltip.$onFocusElementMouseDown = function(evt) {\n evt.preventDefault();\n evt.stopPropagation();\n // Some browsers do not auto-focus buttons (eg. Safari)\n $tooltip.$isShown ? element[0].blur() : element[0].focus();\n };\n\n // bind/unbind events\n function bindTriggerEvents() {\n var triggers = options.trigger.split(' ');\n angular.forEach(triggers, function(trigger) {\n if(trigger === 'click') {\n element.on('click', $tooltip.toggle);\n } else if(trigger !== 'manual') {\n element.on(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);\n element.on(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);\n nodeName === 'button' && trigger !== 'hover' && element.on(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);\n }\n });\n }\n\n function unbindTriggerEvents() {\n var triggers = options.trigger.split(' ');\n for (var i = triggers.length; i--;) {\n var trigger = triggers[i];\n if(trigger === 'click') {\n element.off('click', $tooltip.toggle);\n } else if(trigger !== 'manual') {\n element.off(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);\n element.off(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);\n nodeName === 'button' && trigger !== 'hover' && element.off(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);\n }\n }\n }\n\n function bindKeyboardEvents() {\n if(options.trigger !== 'focus') {\n tipElement.on('keyup', $tooltip.$onKeyUp);\n } else {\n element.on('keyup', $tooltip.$onFocusKeyUp);\n }\n }\n\n function unbindKeyboardEvents() {\n if(options.trigger !== 'focus') {\n tipElement.off('keyup', $tooltip.$onKeyUp);\n } else {\n element.off('keyup', $tooltip.$onFocusKeyUp);\n }\n }\n\n var _autoCloseEventsBinded = false;\n function bindAutoCloseEvents() {\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n // Stop propagation when clicking inside tooltip\n tipElement.on('click', stopEventPropagation);\n\n // Hide when clicking outside tooltip\n $body.on('click', $tooltip.hide);\n\n _autoCloseEventsBinded = true;\n }, 0, false);\n }\n\n function unbindAutoCloseEvents() {\n if (_autoCloseEventsBinded) {\n tipElement.off('click', stopEventPropagation);\n $body.off('click', $tooltip.hide);\n _autoCloseEventsBinded = false;\n }\n }\n\n function stopEventPropagation(event) {\n event.stopPropagation();\n }\n\n // Private methods\n\n function getPosition($element) {\n $element = $element || (options.target || element);\n\n var el = $element[0],\n isBody = el.tagName === 'BODY';\n\n var elRect = el.getBoundingClientRect();\n var rect = {};\n\n // IE8 has issues with angular.extend and using elRect directly.\n // By coping the values of elRect into a new object, we can continue to use extend\n for (var p in elRect) {\n // DO NOT use hasOwnProperty when inspecting the return of getBoundingClientRect.\n rect[p] = elRect[p];\n }\n\n if (rect.width === null) {\n // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093\n rect = angular.extend({}, rect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top });\n }\n var elOffset = isBody ? { top: 0, left: 0 } : dimensions.offset(el),\n scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.prop('scrollTop') || 0 },\n outerDims = isBody ? { width: document.documentElement.clientWidth, height: $window.innerHeight } : null;\n\n return angular.extend({}, rect, scroll, outerDims, elOffset);\n }\n\n function getCalculatedOffset(placement, position, actualWidth, actualHeight) {\n var offset;\n var split = placement.split('-');\n\n switch (split[0]) {\n case 'right':\n offset = {\n top: position.top + position.height / 2 - actualHeight / 2,\n left: position.left + position.width\n };\n break;\n case 'bottom':\n offset = {\n top: position.top + position.height,\n left: position.left + position.width / 2 - actualWidth / 2\n };\n break;\n case 'left':\n offset = {\n top: position.top + position.height / 2 - actualHeight / 2,\n left: position.left - actualWidth\n };\n break;\n default:\n offset = {\n top: position.top - actualHeight,\n left: position.left + position.width / 2 - actualWidth / 2\n };\n break;\n }\n\n if(!split[1]) {\n return offset;\n }\n\n // Add support for corners @todo css\n if(split[0] === 'top' || split[0] === 'bottom') {\n switch (split[1]) {\n case 'left':\n offset.left = position.left;\n break;\n case 'right':\n offset.left = position.left + position.width - actualWidth;\n }\n } else if(split[0] === 'left' || split[0] === 'right') {\n switch (split[1]) {\n case 'top':\n offset.top = position.top - actualHeight;\n break;\n case 'bottom':\n offset.top = position.top + position.height;\n }\n }\n\n return offset;\n }\n\n function applyPlacement(offset, placement) {\n var tip = tipElement[0],\n width = tip.offsetWidth,\n height = tip.offsetHeight;\n\n // manually read margins because getBoundingClientRect includes difference\n var marginTop = parseInt(dimensions.css(tip, 'margin-top'), 10),\n marginLeft = parseInt(dimensions.css(tip, 'margin-left'), 10);\n\n // we must check for NaN for ie 8/9\n if (isNaN(marginTop)) marginTop = 0;\n if (isNaN(marginLeft)) marginLeft = 0;\n\n offset.top = offset.top + marginTop;\n offset.left = offset.left + marginLeft;\n\n // dimensions setOffset doesn't round pixel values\n // so we use setOffset directly with our own function\n dimensions.setOffset(tip, angular.extend({\n using: function (props) {\n tipElement.css({\n top: Math.round(props.top) + 'px',\n left: Math.round(props.left) + 'px',\n right: ''\n });\n }\n }, offset), 0);\n\n // check to see if placing tip in new offset caused the tip to resize itself\n var actualWidth = tip.offsetWidth,\n actualHeight = tip.offsetHeight;\n\n if (placement === 'top' && actualHeight !== height) {\n offset.top = offset.top + height - actualHeight;\n }\n\n // If it's an exotic placement, exit now instead of\n // applying a delta and changing the arrow\n if (/top-left|top-right|bottom-left|bottom-right/.test(placement)) return;\n\n var delta = getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight);\n\n if (delta.left) {\n offset.left += delta.left;\n } else {\n offset.top += delta.top;\n }\n\n dimensions.setOffset(tip, offset);\n\n if (/top|right|bottom|left/.test(placement)) {\n var isVertical = /top|bottom/.test(placement),\n arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight,\n arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight';\n\n replaceArrow(arrowDelta, tip[arrowOffsetPosition], isVertical);\n }\n }\n\n // @source https://github.com/twbs/bootstrap/blob/v3.3.5/js/tooltip.js#L380\n function getViewportAdjustedDelta(placement, position, actualWidth, actualHeight) {\n var delta = {top: 0, left: 0};\n if (!$tooltip.$viewport) return delta;\n\n var viewportPadding = options.viewport && options.viewport.padding || 0;\n var viewportDimensions = getPosition($tooltip.$viewport);\n\n if (/right|left/.test(placement)) {\n var topEdgeOffset = position.top - viewportPadding - viewportDimensions.scroll;\n var bottomEdgeOffset = position.top + viewportPadding - viewportDimensions.scroll + actualHeight;\n if (topEdgeOffset < viewportDimensions.top) { // top overflow\n delta.top = viewportDimensions.top - topEdgeOffset;\n } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow\n delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset;\n }\n } else {\n var leftEdgeOffset = position.left - viewportPadding;\n var rightEdgeOffset = position.left + viewportPadding + actualWidth;\n if (leftEdgeOffset < viewportDimensions.left) { // left overflow\n delta.left = viewportDimensions.left - leftEdgeOffset;\n } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow\n delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset;\n }\n }\n\n return delta;\n }\n\n function replaceArrow(delta, dimension, isHorizontal) {\n var $arrow = findElement('.tooltip-arrow, .arrow', tipElement[0]);\n\n $arrow.css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')\n .css(isHorizontal ? 'top' : 'left', '');\n }\n\n function destroyTipElement() {\n // Cancel pending callbacks\n clearTimeout(timeout);\n\n if($tooltip.$isShown && tipElement !== null) {\n if(options.autoClose) {\n unbindAutoCloseEvents();\n }\n\n if(options.keyboard) {\n unbindKeyboardEvents();\n }\n }\n\n if(tipScope) {\n tipScope.$destroy();\n tipScope = null;\n }\n\n if(tipElement) {\n tipElement.remove();\n tipElement = $tooltip.$element = null;\n }\n }\n\n return $tooltip;\n\n }\n\n // Helper functions\n\n function safeDigest(scope) {\n scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();\n }\n\n function findElement(query, element) {\n return angular.element((element || document).querySelectorAll(query));\n }\n\n var fetchPromises = {};\n function fetchTemplate(template) {\n if(fetchPromises[template]) return fetchPromises[template];\n return (fetchPromises[template] = $http.get(template, {cache: $templateCache}).then(function(res) {\n return res.data;\n }));\n }\n\n return TooltipFactory;\n\n };\n\n })\n\n .directive('bsTooltip', function($window, $location, $sce, $tooltip, $$rAF) {\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'backdropAnimation', 'type', 'customClass', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // should not parse target attribute (anchor tag), only data-target #1454\n var dataTarget = element.attr('data-target');\n if(angular.isDefined(dataTarget)) {\n if(falseValueRegExp.test(dataTarget))\n options.target = false;\n else\n options.target = dataTarget;\n }\n\n // overwrite inherited title value when no value specified\n // fix for angular 1.3.1 531a8de72c439d8ddd064874bf364c00cedabb11\n if (!scope.hasOwnProperty('title')){\n scope.title = '';\n }\n\n // Observe scope attributes for change\n attr.$observe('title', function(newValue) {\n if (angular.isDefined(newValue) || !scope.hasOwnProperty('title')) {\n var oldValue = scope.title;\n scope.title = $sce.trustAsHtml(newValue);\n angular.isDefined(oldValue) && $$rAF(function() {\n tooltip && tooltip.$applyPlacement();\n });\n }\n });\n\n // Support scope as an object\n attr.bsTooltip && scope.$watch(attr.bsTooltip, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.title = newValue;\n }\n angular.isDefined(oldValue) && $$rAF(function() {\n tooltip && tooltip.$applyPlacement();\n });\n }, true);\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!tooltip || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(tooltip),?/i);\n newValue === true ? tooltip.show() : tooltip.hide();\n });\n\n // Enabled binding support\n attr.bsEnabled && scope.$watch(attr.bsEnabled, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.bsEnabled, newValue, oldValue);\n if(!tooltip || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|1|,?(tooltip),?/i);\n newValue === false ? tooltip.setEnabled(false) : tooltip.setEnabled(true);\n });\n\n // Viewport support\n attr.viewport && scope.$watch(attr.viewport, function (newValue) {\n if(!tooltip || !angular.isDefined(newValue)) return;\n tooltip.setViewport(newValue);\n });\n\n // Initialize popover\n var tooltip = $tooltip(element, options);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if(tooltip) tooltip.destroy();\n options = null;\n tooltip = null;\n });\n\n }\n };\n\n });\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/dist/angular-strap.tpl.js b/dist/angular-strap.tpl.js index 9c0ce2183..5dd509b83 100644 --- a/dist/angular-strap.tpl.js +++ b/dist/angular-strap.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -22,22 +22,22 @@ angular.module('mgcrea.ngStrap.modal').run([ '$templateCache', function($templateCache) { $templateCache.put('modal/modal.tpl.html', ''); } ]); - angular.module('mgcrea.ngStrap.select').run([ '$templateCache', function($templateCache) { - $templateCache.put('select/select.tpl.html', ''); - } ]); angular.module('mgcrea.ngStrap.popover').run([ '$templateCache', function($templateCache) { $templateCache.put('popover/popover.tpl.html', '

'); } ]); - angular.module('mgcrea.ngStrap.tab').run([ '$templateCache', function($templateCache) { - $templateCache.put('tab/tab.tpl.html', '
'); - } ]); - angular.module('mgcrea.ngStrap.tooltip').run([ '$templateCache', function($templateCache) { - $templateCache.put('tooltip/tooltip.tpl.html', '
'); + angular.module('mgcrea.ngStrap.select').run([ '$templateCache', function($templateCache) { + $templateCache.put('select/select.tpl.html', ''); } ]); angular.module('mgcrea.ngStrap.timepicker').run([ '$templateCache', function($templateCache) { $templateCache.put('timepicker/timepicker.tpl.html', ''); } ]); + angular.module('mgcrea.ngStrap.tab').run([ '$templateCache', function($templateCache) { + $templateCache.put('tab/tab.tpl.html', '
'); + } ]); angular.module('mgcrea.ngStrap.typeahead').run([ '$templateCache', function($templateCache) { $templateCache.put('typeahead/typeahead.tpl.html', ''); } ]); + angular.module('mgcrea.ngStrap.tooltip').run([ '$templateCache', function($templateCache) { + $templateCache.put('tooltip/tooltip.tpl.html', '
'); + } ]); })(window, document); \ No newline at end of file diff --git a/dist/angular-strap.tpl.min.js b/dist/angular-strap.tpl.min.js index 9170ba702..8b97e4184 100644 --- a/dist/angular-strap.tpl.min.js +++ b/dist/angular-strap.tpl.min.js @@ -1,8 +1,8 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT */ -!function(t,e,n){'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.select').run(['$templateCache',function(t){t.put('select/select.tpl.html','')}]),angular.module('mgcrea.ngStrap.popover').run(['$templateCache',function(t){t.put('popover/popover.tpl.html','

')}]),angular.module('mgcrea.ngStrap.tab').run(['$templateCache',function(t){t.put('tab/tab.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(t,e,n){'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.select').run(['$templateCache',function(t){t.put('select/select.tpl.html','')}]),angular.module('mgcrea.ngStrap.timepicker').run(['$templateCache',function(t){t.put('timepicker/timepicker.tpl.html','')}]),angular.module('mgcrea.ngStrap.tab').run(['$templateCache',function(t){t.put('tab/tab.tpl.html','
')}]),angular.module('mgcrea.ngStrap.typeahead').run(['$templateCache',function(t){t.put('typeahead/typeahead.tpl.html','')}]),angular.module('mgcrea.ngStrap.tooltip').run(['$templateCache',function(t){t.put('tooltip/tooltip.tpl.html','
')}])}(window,document); \ No newline at end of file diff --git a/dist/modules/affix.js b/dist/modules/affix.js index b55bef2a6..d95088a4f 100644 --- a/dist/modules/affix.js +++ b/dist/modules/affix.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/affix.min.js b/dist/modules/affix.min.js index d6132d59c..9eaefdc7f 100644 --- a/dist/modules/affix.min.js +++ b/dist/modules/affix.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/alert.js b/dist/modules/alert.js index 8de890919..d78c05f09 100644 --- a/dist/modules/alert.js +++ b/dist/modules/alert.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/alert.min.js b/dist/modules/alert.min.js index 779d601a3..2791c0a63 100644 --- a/dist/modules/alert.min.js +++ b/dist/modules/alert.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/alert.tpl.js b/dist/modules/alert.tpl.js index 926e98360..d5ac7b34f 100644 --- a/dist/modules/alert.tpl.js +++ b/dist/modules/alert.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @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 aef07a937..17c22e01b 100644 --- a/dist/modules/alert.tpl.min.js +++ b/dist/modules/alert.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/aside.js b/dist/modules/aside.js index 528f4b34e..48d3ea57d 100644 --- a/dist/modules/aside.js +++ b/dist/modules/aside.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/aside.min.js b/dist/modules/aside.min.js index 271e4951c..5c9076cf1 100644 --- a/dist/modules/aside.min.js +++ b/dist/modules/aside.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/aside.tpl.js b/dist/modules/aside.tpl.js index c501366f0..387b47aae 100644 --- a/dist/modules/aside.tpl.js +++ b/dist/modules/aside.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @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 e97d23a8e..17ae2833b 100644 --- a/dist/modules/aside.tpl.min.js +++ b/dist/modules/aside.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/button.js b/dist/modules/button.js index 016b3cdb5..3c79e441a 100644 --- a/dist/modules/button.js +++ b/dist/modules/button.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/button.min.js b/dist/modules/button.min.js index edce3ee8a..9bbbc5c5f 100644 --- a/dist/modules/button.min.js +++ b/dist/modules/button.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/collapse.js b/dist/modules/collapse.js index 9f34d58c9..dac304644 100644 --- a/dist/modules/collapse.js +++ b/dist/modules/collapse.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/collapse.min.js b/dist/modules/collapse.min.js index 30ff36474..dd4ea968e 100644 --- a/dist/modules/collapse.min.js +++ b/dist/modules/collapse.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/compiler.js b/dist/modules/compiler.js index 6be4aa632..f78ec2fb9 100644 --- a/dist/modules/compiler.js +++ b/dist/modules/compiler.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/compiler.min.js b/dist/modules/compiler.min.js index 1fa3a210e..c7ab03e9e 100644 --- a/dist/modules/compiler.min.js +++ b/dist/modules/compiler.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/date-formatter.js b/dist/modules/date-formatter.js index 5cff9f6ac..a71bb3c5e 100644 --- a/dist/modules/date-formatter.js +++ b/dist/modules/date-formatter.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @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 a67dd8c5a..6849c9dbb 100644 --- a/dist/modules/date-formatter.min.js +++ b/dist/modules/date-formatter.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/date-parser.js b/dist/modules/date-parser.js index 95a0cf07a..0b78e2055 100644 --- a/dist/modules/date-parser.js +++ b/dist/modules/date-parser.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @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 39b80ac8c..1af00486a 100644 --- a/dist/modules/date-parser.min.js +++ b/dist/modules/date-parser.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/datepicker.js b/dist/modules/datepicker.js index 8085258cf..facc6e582 100644 --- a/dist/modules/datepicker.js +++ b/dist/modules/datepicker.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -185,6 +185,7 @@ angular.module('mgcrea.ngStrap.datepicker', [ 'mgcrea.ngStrap.helpers.dateParser }; var _show = $datepicker.show; $datepicker.show = function() { + if (!isTouch && element.attr('readonly') || element.attr('disabled')) return; _show(); $timeout(function() { if (!$datepicker.$isShown) return; diff --git a/dist/modules/datepicker.min.js b/dist/modules/datepicker.min.js index 07cd6fea6..1b7303813 100644 --- a/dist/modules/datepicker.min.js +++ b/dist/modules/datepicker.min.js @@ -1,9 +1,9 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT */ -'use strict';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',templateUrl:'datepicker/datepicker.tpl.html',trigger:'focus',container:!1,keyboard:!0,html:!1,delay:0,useNative:!1,dateType:'date',dateFormat:'shortDate',timezone:null,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,a,n,i,o,r,s,d){function l(t,a,n){function i(e){e.selected=l.$isSelected(e.date)}function o(){t[0].focus()}var l=s(t,angular.extend({},e,n)),g=n.scope,m=l.$options,f=l.$scope;m.startView&&(m.startView-=m.minView);var $=r(l);l.$views=$.views;var h=$.viewDate;f.$mode=m.startView,f.$iconLeft=m.iconLeft,f.$iconRight=m.iconRight;var D=l.$views[f.$mode];f.$select=function(e){l.select(e)},f.$selectPane=function(e){l.$selectPane(e)},f.$toggleMode=function(){l.setMode((f.$mode+1)%l.$views.length)},l.update=function(e){angular.isDate(e)&&!isNaN(e.getTime())&&(l.$date=e,D.update.call(D,e)),l.$build(!0)},l.updateDisabledDates=function(e){m.disabledDateRanges=e;for(var t=0,a=f.rows.length;a>t;t++)angular.forEach(f.rows[t],l.$setDisabledEl)},l.select=function(e,t){angular.isDate(a.$dateValue)||(a.$dateValue=new Date(e)),!f.$mode||t?(a.$setViewValue(angular.copy(e)),a.$render(),m.autoclose&&!t&&d(function(){l.hide(!0)})):(angular.extend(h,{year:e.getFullYear(),month:e.getMonth(),date:e.getDate()}),l.setMode(f.$mode-1),l.$build())},l.setMode=function(e){f.$mode=e,D=l.$views[f.$mode],l.$build()},l.$build=function(e){e===!0&&D.built||(e!==!1||D.built)&&D.build.call(D)},l.$updateSelected=function(){for(var e=0,t=f.rows.length;t>e;e++)angular.forEach(f.rows[e],i)},l.$isSelected=function(e){return D.isSelected(e)},l.$setDisabledEl=function(e){e.disabled=D.isDisabled(e.date)},l.$selectPane=function(e){var t=D.steps,a=new Date(Date.UTC(h.year+(t.year||0)*e,h.month+(t.month||0)*e,1));angular.extend(h,{year:a.getUTCFullYear(),month:a.getUTCMonth(),date:a.getUTCDate()}),l.$build()},l.$onMouseDown=function(e){if(e.preventDefault(),e.stopPropagation(),c){var t=angular.element(e.target);'button'!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler('click')}},l.$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 f.$mode?f.$apply(function(){l.setMode(f.$mode-1)}):l.hide(!0);D.onKeyDown(e),g.$digest()}};var p=l.init;l.init=function(){return u&&m.useNative?(t.prop('type','date'),void t.css('-webkit-appearance','textfield')):(c&&(t.prop('type','text'),t.attr('readonly','true'),t.on('click',o)),void p())};var y=l.destroy;l.destroy=function(){u&&m.useNative&&t.off('click',o),y()};var w=l.show;l.show=function(){w(),d(function(){l.$isShown&&(l.$element.on(c?'touchstart':'mousedown',l.$onMouseDown),m.keyboard&&t.on('keydown',l.$onKeyDown))},0,!1)};var b=l.hide;return l.hide=function(e){l.$isShown&&(l.$element.off(c?'touchstart':'mousedown',l.$onMouseDown),m.keyboard&&t.off('keydown',l.$onKeyDown),b(e))},l}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=o.getDefaultLocale()),l.defaults=e,l}]}).directive('bsDatepicker',['$window','$parse','$q','$dateFormatter','$dateParser','$datepicker',function(e,t,a,n,i,o){var r=(o.defaults,/(ip(a|o)d|iphone|android)/gi.test(e.navigator.userAgent));return{restrict:'EAC',require:'ngModel',link:function(e,t,a,s){function d(e){return e&&e.length?e:null}function l(e){if(angular.isDate(e)){var t=isNaN(m.$options.minDate)||e.getTime()>=m.$options.minDate,a=isNaN(m.$options.maxDate)||e.getTime()<=m.$options.maxDate,n=t&&a;s.$setValidity('date',n),s.$setValidity('min',t),s.$setValidity('max',a),n&&(s.$dateValue=e)}}function u(){return!s.$dateValue||isNaN(s.$dateValue.getTime())?'':$(s.$dateValue,c.dateFormat)}var c={scope:e};angular.forEach(['template','templateUrl','controller','controllerAs','placement','container','delay','trigger','html','animation','autoclose','dateType','dateFormat','timezone','modelDateFormat','dayFormat','strictFormat','startWeek','startDate','useNative','lang','startView','minView','iconLeft','iconRight','daysOfWeekDisabled','id','prefixClass','prefixEvent'],function(e){angular.isDefined(a[e])&&(c[e]=a[e])});var g=/^(false|0|)$/i;angular.forEach(['html','container','autoclose','useNative'],function(e){angular.isDefined(a[e])&&g.test(a[e])&&(c[e]=!1)}),a.bsShow&&e.$watch(a.bsShow,function(e,t){m&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(datepicker),?/i)),e===!0?m.show():m.hide())});var m=o(t,s,c);c=m.$options,r&&c.useNative&&(c.dateFormat='yyyy-MM-dd');var f=c.lang,$=function(e,t){return n.formatDate(e,t,f)},h=i({format:c.dateFormat,lang:f,strict:c.strictFormat});angular.forEach(['minDate','maxDate'],function(e){angular.isDefined(a[e])&&a.$observe(e,function(t){m.$options[e]=h.getDateForAttribute(e,t),!isNaN(m.$options[e])&&m.$build(!1),l(s.$dateValue)})}),e.$watch(a.ngModel,function(e,t){m.update(s.$dateValue)},!0),angular.isDefined(a.disabledDates)&&e.$watch(a.disabledDates,function(e,t){e=d(e),t=d(t),e&&m.updateDisabledDates(e)}),s.$parsers.unshift(function(e){var t;if(!e)return s.$setValidity('date',!0),null;var a=h.parse(e,s.$dateValue);return!a||isNaN(a.getTime())?void s.$setValidity('date',!1):(l(a),'string'===c.dateType?(t=h.timezoneOffsetAdjust(a,c.timezone,!0),$(t,c.modelDateFormat||c.dateFormat)):(t=h.timezoneOffsetAdjust(s.$dateValue,c.timezone,!0),'number'===c.dateType?t.getTime():'unix'===c.dateType?t.getTime()/1e3:'iso'===c.dateType?t.toISOString():new Date(t)))}),s.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:'string'===c.dateType?h.parse(e,null,c.modelDateFormat):new Date('unix'===c.dateType?1e3*e:e),s.$dateValue=h.timezoneOffsetAdjust(t,c.timezone),u()}),s.$render=function(){t.val(u())},e.$on('$destroy',function(){m&&m.destroy(),c=null,m=null})}}}]).provider('datepickerViews',function(){function e(e,t){for(var a=[];e.length>0;)a.push(e.splice(0,t));return a}function t(e,t){return(e%t+t)%t}this.defaults={dayFormat:'dd',daySplit:7};this.$get=['$dateFormatter','$dateParser','$sce',function(a,n,i){return function(o){var r=o.$scope,s=o.$options,d=s.lang,l=function(e,t){return a.formatDate(e,t,d)},u=n({format:s.dateFormat,lang:d,strict:s.strictFormat}),c=a.weekdaysShort(d),g=c.slice(s.startWeek).concat(c.slice(0,s.startWeek)),m=i.trustAsHtml(''+g.join('')+''),f=o.$date||(s.startDate?u.getDateForAttribute('startDate',s.startDate):new Date),$={year:f.getFullYear(),month:f.getMonth(),date:f.getDate()},h=[{format:s.dayFormat,split:7,steps:{month:1},update:function(e,t){!this.built||t||e.getFullYear()!==$.year||e.getMonth()!==$.month?(angular.extend($,{year:o.$date.getFullYear(),month:o.$date.getMonth(),date:o.$date.getDate()}),o.$build()):(e.getDate()!==$.date||1===e.getDate())&&($.date=o.$date.getDate(),o.$updateSelected())},build:function(){var a=new Date($.year,$.month,1),n=a.getTimezoneOffset(),i=new Date(+a-864e5*t(a.getDay()-s.startWeek,7)),d=i.getTimezoneOffset(),c=u.timezoneOffsetAdjust(new Date,s.timezone).toDateString();d!==n&&(i=new Date(+i+6e4*(d-n)));for(var g,f=[],h=0;42>h;h++)g=u.daylightSavingAdjust(new Date(i.getFullYear(),i.getMonth(),i.getDate()+h)),f.push({date:g,isToday:g.toDateString()===c,label:l(g,this.format),selected:o.$date&&this.isSelected(g),muted:g.getMonth()!==$.month,disabled:this.isDisabled(g)});r.title=l(a,s.monthTitleFormat),r.showLabels=!0,r.labels=m,r.rows=e(f,this.split),this.built=!0},isSelected:function(e){return o.$date&&e.getFullYear()===o.$date.getFullYear()&&e.getMonth()===o.$date.getMonth()&&e.getDate()===o.$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 a=0;a=s.disabledDateRanges[a].start&&t<=s.disabledDateRanges[a].end)return!0;return!1},onKeyDown:function(e){if(o.$date){var t,a=o.$date.getTime();37===e.keyCode?t=new Date(a-864e5):38===e.keyCode?t=new Date(a-6048e5):39===e.keyCode?t=new Date(a+864e5):40===e.keyCode&&(t=new Date(a+6048e5)),this.isDisabled(t)||o.select(t,!0)}}},{name:'month',format:s.monthFormat,split:4,steps:{year:1},update:function(e,t){this.built&&e.getFullYear()===$.year?e.getMonth()!==$.month&&(angular.extend($,{month:o.$date.getMonth(),date:o.$date.getDate()}),o.$updateSelected()):(angular.extend($,{year:o.$date.getFullYear(),month:o.$date.getMonth(),date:o.$date.getDate()}),o.$build())},build:function(){for(var t,a=(new Date($.year,0,1),[]),n=0;12>n;n++)t=new Date($.year,n,1),a.push({date:t,label:l(t,this.format),selected:o.$isSelected(t),disabled:this.isDisabled(t)});r.title=l(t,s.yearTitleFormat),r.showLabels=!1,r.rows=e(a,this.split),this.built=!0},isSelected:function(e){return o.$date&&e.getFullYear()===o.$date.getFullYear()&&e.getMonth()===o.$date.getMonth()},isDisabled:function(e){var t=+new Date(e.getFullYear(),e.getMonth()+1,0);return ts.maxDate},onKeyDown:function(e){if(o.$date){var t=o.$date.getMonth(),a=new Date(o.$date);37===e.keyCode?a.setMonth(t-1):38===e.keyCode?a.setMonth(t-4):39===e.keyCode?a.setMonth(t+1):40===e.keyCode&&a.setMonth(t+4),this.isDisabled(a)||o.select(a,!0)}}},{name:'year',format:s.yearFormat,split:4,steps:{year:12},update:function(e,t){!this.built||t||parseInt(e.getFullYear()/20,10)!==parseInt($.year/20,10)?(angular.extend($,{year:o.$date.getFullYear(),month:o.$date.getMonth(),date:o.$date.getDate()}),o.$build()):e.getFullYear()!==$.year&&(angular.extend($,{year:o.$date.getFullYear(),month:o.$date.getMonth(),date:o.$date.getDate()}),o.$updateSelected())},build:function(){for(var t,a=$.year-$.year%(3*this.split),n=[],i=0;12>i;i++)t=new Date(a+i,0,1),n.push({date:t,label:l(t,this.format),selected:o.$isSelected(t),disabled:this.isDisabled(t)});r.title=n[0].label+'-'+n[n.length-1].label,r.showLabels=!1,r.rows=e(n,this.split),this.built=!0},isSelected:function(e){return o.$date&&e.getFullYear()===o.$date.getFullYear()},isDisabled:function(e){var t=+new Date(e.getFullYear()+1,0,0);return ts.maxDate},onKeyDown:function(e){if(o.$date){var t=o.$date.getFullYear(),a=new Date(o.$date);37===e.keyCode?a.setYear(t-1):38===e.keyCode?a.setYear(t-4):39===e.keyCode?a.setYear(t+1):40===e.keyCode&&a.setYear(t+4),this.isDisabled(a)||o.select(a,!0)}}}];return{views:s.minView?Array.prototype.slice.call(h,s.minView):h,viewDate:$}}}]}); +'use strict';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',templateUrl:'datepicker/datepicker.tpl.html',trigger:'focus',container:!1,keyboard:!0,html:!1,delay:0,useNative:!1,dateType:'date',dateFormat:'shortDate',timezone:null,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,a,n,i,o,r,d,s){function l(t,a,n){function i(e){e.selected=l.$isSelected(e.date)}function o(){t[0].focus()}var l=d(t,angular.extend({},e,n)),g=n.scope,m=l.$options,f=l.$scope;m.startView&&(m.startView-=m.minView);var $=r(l);l.$views=$.views;var h=$.viewDate;f.$mode=m.startView,f.$iconLeft=m.iconLeft,f.$iconRight=m.iconRight;var D=l.$views[f.$mode];f.$select=function(e){l.select(e)},f.$selectPane=function(e){l.$selectPane(e)},f.$toggleMode=function(){l.setMode((f.$mode+1)%l.$views.length)},l.update=function(e){angular.isDate(e)&&!isNaN(e.getTime())&&(l.$date=e,D.update.call(D,e)),l.$build(!0)},l.updateDisabledDates=function(e){m.disabledDateRanges=e;for(var t=0,a=f.rows.length;a>t;t++)angular.forEach(f.rows[t],l.$setDisabledEl)},l.select=function(e,t){angular.isDate(a.$dateValue)||(a.$dateValue=new Date(e)),!f.$mode||t?(a.$setViewValue(angular.copy(e)),a.$render(),m.autoclose&&!t&&s(function(){l.hide(!0)})):(angular.extend(h,{year:e.getFullYear(),month:e.getMonth(),date:e.getDate()}),l.setMode(f.$mode-1),l.$build())},l.setMode=function(e){f.$mode=e,D=l.$views[f.$mode],l.$build()},l.$build=function(e){e===!0&&D.built||(e!==!1||D.built)&&D.build.call(D)},l.$updateSelected=function(){for(var e=0,t=f.rows.length;t>e;e++)angular.forEach(f.rows[e],i)},l.$isSelected=function(e){return D.isSelected(e)},l.$setDisabledEl=function(e){e.disabled=D.isDisabled(e.date)},l.$selectPane=function(e){var t=D.steps,a=new Date(Date.UTC(h.year+(t.year||0)*e,h.month+(t.month||0)*e,1));angular.extend(h,{year:a.getUTCFullYear(),month:a.getUTCMonth(),date:a.getUTCDate()}),l.$build()},l.$onMouseDown=function(e){if(e.preventDefault(),e.stopPropagation(),c){var t=angular.element(e.target);'button'!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler('click')}},l.$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 f.$mode?f.$apply(function(){l.setMode(f.$mode-1)}):l.hide(!0);D.onKeyDown(e),g.$digest()}};var p=l.init;l.init=function(){return u&&m.useNative?(t.prop('type','date'),void t.css('-webkit-appearance','textfield')):(c&&(t.prop('type','text'),t.attr('readonly','true'),t.on('click',o)),void p())};var y=l.destroy;l.destroy=function(){u&&m.useNative&&t.off('click',o),y()};var w=l.show;l.show=function(){!c&&t.attr('readonly')||t.attr('disabled')||(w(),s(function(){l.$isShown&&(l.$element.on(c?'touchstart':'mousedown',l.$onMouseDown),m.keyboard&&t.on('keydown',l.$onKeyDown))},0,!1))};var b=l.hide;return l.hide=function(e){l.$isShown&&(l.$element.off(c?'touchstart':'mousedown',l.$onMouseDown),m.keyboard&&t.off('keydown',l.$onKeyDown),b(e))},l}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=o.getDefaultLocale()),l.defaults=e,l}]}).directive('bsDatepicker',['$window','$parse','$q','$dateFormatter','$dateParser','$datepicker',function(e,t,a,n,i,o){var r=(o.defaults,/(ip(a|o)d|iphone|android)/gi.test(e.navigator.userAgent));return{restrict:'EAC',require:'ngModel',link:function(e,t,a,d){function s(e){return e&&e.length?e:null}function l(e){if(angular.isDate(e)){var t=isNaN(m.$options.minDate)||e.getTime()>=m.$options.minDate,a=isNaN(m.$options.maxDate)||e.getTime()<=m.$options.maxDate,n=t&&a;d.$setValidity('date',n),d.$setValidity('min',t),d.$setValidity('max',a),n&&(d.$dateValue=e)}}function u(){return!d.$dateValue||isNaN(d.$dateValue.getTime())?'':$(d.$dateValue,c.dateFormat)}var c={scope:e};angular.forEach(['template','templateUrl','controller','controllerAs','placement','container','delay','trigger','html','animation','autoclose','dateType','dateFormat','timezone','modelDateFormat','dayFormat','strictFormat','startWeek','startDate','useNative','lang','startView','minView','iconLeft','iconRight','daysOfWeekDisabled','id','prefixClass','prefixEvent'],function(e){angular.isDefined(a[e])&&(c[e]=a[e])});var g=/^(false|0|)$/i;angular.forEach(['html','container','autoclose','useNative'],function(e){angular.isDefined(a[e])&&g.test(a[e])&&(c[e]=!1)}),a.bsShow&&e.$watch(a.bsShow,function(e,t){m&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(datepicker),?/i)),e===!0?m.show():m.hide())});var m=o(t,d,c);c=m.$options,r&&c.useNative&&(c.dateFormat='yyyy-MM-dd');var f=c.lang,$=function(e,t){return n.formatDate(e,t,f)},h=i({format:c.dateFormat,lang:f,strict:c.strictFormat});angular.forEach(['minDate','maxDate'],function(e){angular.isDefined(a[e])&&a.$observe(e,function(t){m.$options[e]=h.getDateForAttribute(e,t),!isNaN(m.$options[e])&&m.$build(!1),l(d.$dateValue)})}),e.$watch(a.ngModel,function(e,t){m.update(d.$dateValue)},!0),angular.isDefined(a.disabledDates)&&e.$watch(a.disabledDates,function(e,t){e=s(e),t=s(t),e&&m.updateDisabledDates(e)}),d.$parsers.unshift(function(e){var t;if(!e)return d.$setValidity('date',!0),null;var a=h.parse(e,d.$dateValue);return!a||isNaN(a.getTime())?void d.$setValidity('date',!1):(l(a),'string'===c.dateType?(t=h.timezoneOffsetAdjust(a,c.timezone,!0),$(t,c.modelDateFormat||c.dateFormat)):(t=h.timezoneOffsetAdjust(d.$dateValue,c.timezone,!0),'number'===c.dateType?t.getTime():'unix'===c.dateType?t.getTime()/1e3:'iso'===c.dateType?t.toISOString():new Date(t)))}),d.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:'string'===c.dateType?h.parse(e,null,c.modelDateFormat):new Date('unix'===c.dateType?1e3*e:e),d.$dateValue=h.timezoneOffsetAdjust(t,c.timezone),u()}),d.$render=function(){t.val(u())},e.$on('$destroy',function(){m&&m.destroy(),c=null,m=null})}}}]).provider('datepickerViews',function(){function e(e,t){for(var a=[];e.length>0;)a.push(e.splice(0,t));return a}function t(e,t){return(e%t+t)%t}this.defaults={dayFormat:'dd',daySplit:7};this.$get=['$dateFormatter','$dateParser','$sce',function(a,n,i){return function(o){var r=o.$scope,d=o.$options,s=d.lang,l=function(e,t){return a.formatDate(e,t,s)},u=n({format:d.dateFormat,lang:s,strict:d.strictFormat}),c=a.weekdaysShort(s),g=c.slice(d.startWeek).concat(c.slice(0,d.startWeek)),m=i.trustAsHtml(''+g.join('')+''),f=o.$date||(d.startDate?u.getDateForAttribute('startDate',d.startDate):new Date),$={year:f.getFullYear(),month:f.getMonth(),date:f.getDate()},h=[{format:d.dayFormat,split:7,steps:{month:1},update:function(e,t){!this.built||t||e.getFullYear()!==$.year||e.getMonth()!==$.month?(angular.extend($,{year:o.$date.getFullYear(),month:o.$date.getMonth(),date:o.$date.getDate()}),o.$build()):(e.getDate()!==$.date||1===e.getDate())&&($.date=o.$date.getDate(),o.$updateSelected())},build:function(){var a=new Date($.year,$.month,1),n=a.getTimezoneOffset(),i=new Date(+a-864e5*t(a.getDay()-d.startWeek,7)),s=i.getTimezoneOffset(),c=u.timezoneOffsetAdjust(new Date,d.timezone).toDateString();s!==n&&(i=new Date(+i+6e4*(s-n)));for(var g,f=[],h=0;42>h;h++)g=u.daylightSavingAdjust(new Date(i.getFullYear(),i.getMonth(),i.getDate()+h)),f.push({date:g,isToday:g.toDateString()===c,label:l(g,this.format),selected:o.$date&&this.isSelected(g),muted:g.getMonth()!==$.month,disabled:this.isDisabled(g)});r.title=l(a,d.monthTitleFormat),r.showLabels=!0,r.labels=m,r.rows=e(f,this.split),this.built=!0},isSelected:function(e){return o.$date&&e.getFullYear()===o.$date.getFullYear()&&e.getMonth()===o.$date.getMonth()&&e.getDate()===o.$date.getDate()},isDisabled:function(e){var t=e.getTime();if(td.maxDate)return!0;if(-1!==d.daysOfWeekDisabled.indexOf(e.getDay()))return!0;if(d.disabledDateRanges)for(var a=0;a=d.disabledDateRanges[a].start&&t<=d.disabledDateRanges[a].end)return!0;return!1},onKeyDown:function(e){if(o.$date){var t,a=o.$date.getTime();37===e.keyCode?t=new Date(a-864e5):38===e.keyCode?t=new Date(a-6048e5):39===e.keyCode?t=new Date(a+864e5):40===e.keyCode&&(t=new Date(a+6048e5)),this.isDisabled(t)||o.select(t,!0)}}},{name:'month',format:d.monthFormat,split:4,steps:{year:1},update:function(e,t){this.built&&e.getFullYear()===$.year?e.getMonth()!==$.month&&(angular.extend($,{month:o.$date.getMonth(),date:o.$date.getDate()}),o.$updateSelected()):(angular.extend($,{year:o.$date.getFullYear(),month:o.$date.getMonth(),date:o.$date.getDate()}),o.$build())},build:function(){for(var t,a=(new Date($.year,0,1),[]),n=0;12>n;n++)t=new Date($.year,n,1),a.push({date:t,label:l(t,this.format),selected:o.$isSelected(t),disabled:this.isDisabled(t)});r.title=l(t,d.yearTitleFormat),r.showLabels=!1,r.rows=e(a,this.split),this.built=!0},isSelected:function(e){return o.$date&&e.getFullYear()===o.$date.getFullYear()&&e.getMonth()===o.$date.getMonth()},isDisabled:function(e){var t=+new Date(e.getFullYear(),e.getMonth()+1,0);return td.maxDate},onKeyDown:function(e){if(o.$date){var t=o.$date.getMonth(),a=new Date(o.$date);37===e.keyCode?a.setMonth(t-1):38===e.keyCode?a.setMonth(t-4):39===e.keyCode?a.setMonth(t+1):40===e.keyCode&&a.setMonth(t+4),this.isDisabled(a)||o.select(a,!0)}}},{name:'year',format:d.yearFormat,split:4,steps:{year:12},update:function(e,t){!this.built||t||parseInt(e.getFullYear()/20,10)!==parseInt($.year/20,10)?(angular.extend($,{year:o.$date.getFullYear(),month:o.$date.getMonth(),date:o.$date.getDate()}),o.$build()):e.getFullYear()!==$.year&&(angular.extend($,{year:o.$date.getFullYear(),month:o.$date.getMonth(),date:o.$date.getDate()}),o.$updateSelected())},build:function(){for(var t,a=$.year-$.year%(3*this.split),n=[],i=0;12>i;i++)t=new Date(a+i,0,1),n.push({date:t,label:l(t,this.format),selected:o.$isSelected(t),disabled:this.isDisabled(t)});r.title=n[0].label+'-'+n[n.length-1].label,r.showLabels=!1,r.rows=e(n,this.split),this.built=!0},isSelected:function(e){return o.$date&&e.getFullYear()===o.$date.getFullYear()},isDisabled:function(e){var t=+new Date(e.getFullYear()+1,0,0);return td.maxDate},onKeyDown:function(e){if(o.$date){var t=o.$date.getFullYear(),a=new Date(o.$date);37===e.keyCode?a.setYear(t-1):38===e.keyCode?a.setYear(t-4):39===e.keyCode?a.setYear(t+1):40===e.keyCode&&a.setYear(t+4),this.isDisabled(a)||o.select(a,!0)}}}];return{views:d.minView?Array.prototype.slice.call(h,d.minView):h,viewDate:$}}}]}); //# sourceMappingURL=../modules/datepicker.min.js.map \ No newline at end of file diff --git a/dist/modules/datepicker.min.js.map b/dist/modules/datepicker.min.js.map index 87956a06e..400ebed82 100644 --- a/dist/modules/datepicker.min.js.map +++ b/dist/modules/datepicker.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["modules/datepicker.js"],"names":["angular","container","provider","keyboard","this","defaults","html","delay","useNative","dateType","dateFormat","timezone","modelDateFormat","dayFormat","monthFormat","yearFormat","monthTitleFormat","yearTitleFormat","strictFormat","autoclose","minDate","Infinity","maxDate","startView","minView","startWeek","daysOfWeekDisabled","iconLeft","iconRight","$get","bodyEl","isNative","DatepickerFactory","parentScope","config","scope","$datepicker","pickerViews","views","el","selected","date","element","focus","viewDate","options","$iconLeft","$iconRight","$picker","$views","$mode","datepickerViews","$selectPane","value","$toggleMode","setMode","select","isDate","$build","length","updateDisabledDates","disabledDateRanges","dateRanges","$date","forEach","i","$dateValue","controller","$setViewValue","copy","$render","hide","keep","Date","extend","year","getFullYear","month","getDate","mode","pristine","call","$updateSelected","rows","built","$isSelected","$setDisabledEl","disabled","isDisabled","steps","targetDate","getUTCFullYear","getUTCMonth","UTC","$onMouseDown","evt","preventDefault","stopPropagation","isTouch","getUTCDate","targetEl","$onKeyDown","nodeName","test","keyCode","shiftKey","altKey","$apply","updateSelected","onKeyDown","$digest","prop","init","attr","focusElement","_init","_destroy","destroy","off","_show","show","$timeout","_hide","on","blur","$element","directive","$options","$scope","require","restrict","$window","navigator","userAgent","link","falseValueRegExp","previousValue","normalizeDateRanges","ranges","disabledRanges","datepicker","isMaxValid","isValid","isMinValid","isNaN","parsedDate","getTime","$parsers","unshift","viewValue","$setValidity","getDateFormattedString","formatDate","bsShow","newValue","oldValue","isDefined","key","lang","format","$dateFormatter","dateParser","$dateParser","strict","validateAgainstMinMaxDate","$watch","ngModel","getDateForAttribute","disabledDates","parse","timezoneOffsetAdjust","$formatters","isUndefined","modelValue","NaN","daySplit","arr","mod","n","m","arrays","splice","size","push","$sce","weekDaysMin","weekdaysShort","weekDaysLabelsHtml","startDate","picker","weekDaysLabels","slice","concat","split","getMonth","update","firstDayOfMonth","firstDate","getDay","today","firstDateOffset","build","day","days","isToday","toDateString","label","muted","title","showLabels","labels","time","isSelected","indexOf","newDate","name","firstMonth","months","lastDate","actualMonth","parseInt","firstYear","years","actualYear","setYear","Array","prototype"],"mappings":"AAOA,YAEAA,SAQMC,OAAW,6BAAA,oCAAA,uCAAA,2BAAAC,SAAA,cAAA,WAPf,GAQIC,GAAUC,KAAAC,UACVC,UAAM,UACNC,YAAO,aAEPC,UAAW,cACXC,YAAU,iCACVC,QAAAA,QACAC,WAAU,EACVC,UAAAA,EACAC,MAAAA,EACAC,MAAAA,EACAC,WAAAA,EACAC,SAAAA,OACAC,WAAAA,YACAC,SAAAA,KACAC,gBAAW,KACXC,UAAUC,KACVC,YAAUD,MACVE,WAAW,OACXC,iBAAS,YACTC,gBAAW,OACXC,cAAAA,EACAC,WAAU,EACVC,UAAAA,EAAAA,GARFN,UAAUD,EAAAA,GAWVjB,UAAKyB,EAEHL,QAAIM,EACJL,UAAIM,EACJL,mBAAe,GACfC,SAAItB,mCAEJuB,UAASI,oCAVb5B,MAaMyB,MAAII,UAAcC,YAAOC,aAAAA,OAAAA,iBAAAA,kBAAAA,WAAAA,WAAAA,SAAAA,EAAAA,EAAAA,EAAAA,EAAAA,EAAAA,EAAAA,EAAAA,GAR7B,QAgBIC,GAAqBC,EAAYC,EAAAA,GA2IjCF,QAAAA,GAAmBG,GACjBA,EAAAC,SAAGT,EAAoBvB,YAAW+B,EAAAE,MAxCtC,QA0CMC,KAzCJA,EA0CI,GAAAC,QA9IJ,GAAIC,GAAWP,EAAYO,EAAAA,QAAAA,UAAAA,EAAAA,IAC3BT,EAAcU,EAAQtB,MACtBY,EAAMW,EAAoBnB,SAC1BQ,EAAMY,EAAaF,MACfG,GAAAA,YAAUZ,EAAYa,WAAaC,EAAAA,QAIvCf,IAAAA,GAAgBgB,EAASV,EAlB3BL,GAmBIA,OAAmBK,EAAAA,KAlBvB,IAAIG,GAAWP,EAAYO,QAoBzBT,GAAMiB,MAAAA,EAAc7B,UAlBtBY,EAmBIC,UAAYgB,EAAYC,SAlB5BlB,EAAMY,WAAaF,EAAQjB,SAoBzBO,IAAAA,GAAMmB,EAAcL,OAAAd,EAAAe,MAlBtBf,GAmBIC,QAAYmB,SAASpB,GAlBvBC,EAAYoB,OAAOf,IAErBN,EAuBOnC,YAAQyD,SAAOhB,GAtBpBL,EAuBIA,YAAoBK,IArB1BN,EAAMmB,YAAc,WAyBhBlB,EAAYsB,SAAOvB,EAAAe,MAAA,GAAAd,EAAAa,OAAAU,SAGrBvB,EAAYwB,OAAAA,SAAAA,GACVf,QAAQgB,OAAAA,KAAqBC,MAAAA,EAAAA,aAC7B1B,EAAY2B,MAAO5B,EACjBnC,EAAQgE,OAAAA,KAAQ7B,EAAW8B,IAvB/B7B,EAAYsB,QAAO,IAErBtB,EA2BQpC,oBAA0BkE,SAAAA,GAC9BrB,EAAIV,mBAAqB2B,CA1B3B,KA2BIK,GAAAA,GAAWC,EAAAA,EAAAA,EAAAA,KAAcpE,OAAayC,EAAL4B,EAAK5B,IACtC0B,QAAAA,QAAWG,EAAAA,KAAAA,GAAAA,EAAAA,iBAxBjBlC,EA0B8BA,OAAYmC,SAAK9B,EAAA+B,GAzBxCxE,QAAQyD,OAAOU,EAAWD,cAAaC,EAAWD,WAAa,GAAIO,MAAKhC,KACxEN,EAAMe,OAASsB,GAClBL,EAyBOC,cAAApE,QAAAqE,KAAA5B,IACLzC,EAAQ0E,UAAkBC,EAAMlC,YAAKmC,GAAeC,EAAOpC,WAAiBA,EAAWqC,MAAAA,OAlBzF9E,QAAQ0E,OAAO9B,GACb+B,KAAMlC,EAAKmC,cAuBfxC,MAAYmB,EAAAA,WAEVpB,KAAMe,EAAQ6B,YAEd3C,EAAYsB,QAAAA,EAAAA,MAAAA,GAtBZtB,EAAYsB,WAGhBtB,EA2BO4C,QAAa,SAAUhC,GAC1BA,EAAAA,MAAciC,EA1BhBjC,EAAUZ,EAAYa,OAAOd,EAAMe,OA6BnCd,EAAY8C,UA1Bd9C,EA4Bc4B,OAAQ7B,SAAMgD,GA3BtBH,KAAa,GAAQhC,EAAQoC,QAC7BJ,KAAa,GAAUhC,EAAQoC,QA8BnChD,EAAAA,MAAYiD,KAAAA,IA3BdjD,EAAY8C,gBAAkB,WA+B5B9C,IAAAA,GAAAA,GAAYkD,EAAAA,EAAAA,EAAAA,KAAiB3B,OAASpB,EAAAA,EAAAA,IACpCA,QAAGgD,QAAWvC,EAAQwC,KAAAA,GAAWjD,IA3BrCH,EA+BQqD,YAAgBA,SAAAA,GAIpB,MAAIC,GAAAA,WAAsBjB,IAhC9BrC,EAiCoCsD,eAAWC,SAAAA,GAhC7CpD,EAgC+DsC,SAAOa,EAAWE,WAAAA,EAAAA,OA9BnFxD,EAAYgB,YAAc,SAASC,GA+B/BjB,GAAAA,GAAYsB,EAAAA,MA7BVgC,EAAa,GAAIjB,MAAKA,KAAKoB,IAAIjD,EAAS+B,MAAQc,EAAMd,MAAQ,GAAKtB,EAAOT,EAASiC,OAASY,EAAMZ,OAAS,GAAKxB,EAAO,GAgC3HjB,SAAAA,OAAY0D,GAEVC,KAAIC,EAAAA,iBACJD,MAAIE,EAAAA,cAEJxD,KAAGyD,EAASC,eA/Bd/D,EAiCOgE,UA/BThE,EAAY0D,aAAe,SAASC,GAGlC,GAFAA,EAiCIK,iBAhCJL,EAAIE,kBACAC,EAAS,CAmCb9D,GAAAA,GAAYiE,QAAa3D,QAASqD,EAAAA,OACaA,YAAxCK,EAAA,GAAAE,SAAmBC,gBACpBP,EAAAA,EAAAA,UAGJI,EAAOI,eAAgB,WAhC3BpE,EAmCaiE,WAAA,SAAAN,GAlCX,GAmCM,mBAAoBQ,KAAAR,EAAAS,WAAAT,EAAAU,WAAAV,EAAAW,OAnC1B,CAGA,GAFAX,EAAIC,iBACJD,EAAIE,kBACgB,KAAhBF,EAAIS,QACN,MAAKrE,GAAMe,MAGFf,EAAMwE,OAAO,WAuCxBvE,EAASwE,QAAerE,EAAAA,MAAAA,KANdsE,EAAUd,MAAAA,EAWlBrD,GAAQmE,UAAGlE,GAtCbV,EAAY6E,WAQd,IA0CMpE,GAAQqE,EAAKC,IAzCnB5E,GA0Cc6E,KAAK,WAzCjB,MA0CIvE,IAAWG,EAASqE,WAzCtBxE,EAAQqE,KAAK,OAAQ,YA2CrBI,GAAAA,IAAAA,qBAAAA,eAGEC,IACJhF,EAAYiF,KAAAA,OAAU,QACpB3E,EAAGX,KAAAA,WAAoBvB,QACrBkC,EAAQ4E,GAAAA,QAAIJ,QAEdE,MAGF,IAAIG,GAAQnF,EAAYoF,OACxBpF,GAAYoF,QAAO,WACjBD,GAAAA,EAAAA,WAGAE,EAASH,IAAA,QAAAJ,GA5CXE,IAEF,IAAIG,GA+CI7E,EAAW8E,IA9CnBpF,GAAYoF,KAAO,WACjBD,IACAE,EAAS,WAiDLC,EAAQtF,WACZA,EAAYmC,SAAOoD,GAASC,EAAAA,aAAAA,YAAAA,EAAAA,cACtBxF,EAAAA,UACJA,EAAYyF,GAAAA,UAAa3B,EAAUG,cAEjC3D,GAAAA,GA9CN,IAgDIgF,GAAME,EAAAA,IAiBR7F,OAhEFK,GAAYmC,KAAO,SAASqD,GAkDnBxF,EAAAA,WAhDPA,EAAYyF,SAASP,IAAIpB,EAAU,aAAe,YAAa9D,EAAY0D,cAoD7E9D,EAAAA,UACAU,EAAOV,IAAAA,UAAAA,EAAAA,YAMV8F,EAAUF,KAGL7F,EA3NJ,GAcIA,IADIc,QAAUT,QAAY2F,EAAAA,SAAAA,MACd3F,8BAAY4F,KAAAA,EAAAA,UAAAA,YACxB9B,EAAW3E,eAAWsB,GAAQtB,UAAasB,CAgN7CoF,OA5ME5H,GAAIgC,OAAcc,EAAAA,KAAgBf,EAAAA,oBA2MpC8F,EAAU7H,SAAAA,EACV4H,MAvDHH,UA2DSjF,gBAAAA,UAAAA,SAAAA,KAAAA,iBAAAA,cAAAA,cAAAA,SAAAA,EAAAA,EAAAA,EAAAA,EAAAA,EAAAA,GA1DV,GACId,IAyDwBI,EAAAA,SAzDb,8BAA8BoE,KAAK4B,EAAQC,UAAUC,WACpE,QACEH,SAyDSlI,MAxDTiI,QAAS,UACTK,KA2DQC,SAAAA,EAAmB7F,EAAAuE,EAAA9C,GArBzB,QA2EMqE,GAAgBC,GA1EpB,MA4EIC,IAAIC,EAAgBhF,OAClBiF,EADkB,KAhE1B,QA6EIzE,GAA+B0E,GAE/B,GAAGC,QAAS3E,OAAAA,GAAZ,CA7EF,GAAI4E,GAAaC,MAAMJ,EAAWb,SAAS3G,UAAY6H,EAAWC,WAAaN,EAAWb,SAAS3G,QAiFnG+C,EAAWgF,MAASC,EAAQrB,SAASsB,UAAAA,EAAAA,WAAAA,EAAAA,SAAAA,QAE/B5G,EAAAA,GAAAA,CAEJ0B,GAAIkF,aAAW,OAAAP,GAjFjB3E,EAkFIA,aAAWmF,MAAaP,GAjF5B5E,EAqFWmF,aAAA,MAAAT,GApFPC,IAAS3E,EAAWD,WAAa+E,IAiDvC,QAASM,KACP,OAAQpF,EAAWD,YAAc8E,MAAM7E,EAAWD,WAAWgF,WAAa,GAAKM,EAAWrF,EAAWD,WAAYrB,EAAQnC,YAjDzHV,GAAAA,IACEmC,MAAGnC,EAKLiH,SAAKwC,SAAUtH,WAAa8E,cAAa,aAASyC,eAAUC,YAAAA,YAAAA,QAAAA,UAAAA,OAAAA,YAAAA,YAAAA,WAAAA,aAAAA,WAAAA,kBAAAA,YAAAA,eAAAA,YAAAA,YAAAA,YAAAA,OAAAA,YAAAA,UAAAA,WAAAA,YAAAA,qBAAAA,KAAAA,cAAAA,eAAAA,SAAAA,GAC1D3J,QAAI4I,UAAe5I,EAAAA,MAAQ4J,EAAUF,GAAWzC,EAAA4C,KA5DpD,IA8DIH,GAAoBd,eA7DxB5I,SAAQgE,SAAU,OAAQ,YAAa,YAAa,aAAe,SAAS6F,GAiEtEjB,QAAAA,UAAaxG,EAAYM,KAASyB,EAAYtB,KAAAA,EAAAA,MAAAA,EAAAA,IAAAA,KAGlDoE,EAAGlF,QAAAA,EAAYc,OAAQrC,EAAAA,OAAWqC,SAAQnC,EAAaiJ,GAEnDG,GAAeA,QAAAA,UAAAA,KAEfN,QAAAA,SAAaE,KAAeK,IAAAA,EAAAA,MAAAA,2BAC9BL,KAAOM,EAAAA,EAAeR,OAAiBO,EAAQD,SAGjD,IAAIG,GAAaC,EAAAA,EAAAA,EAAAA,EAnEnBrH,GAmEwCA,EAAQnC,SAAYoJ,GAAMA,EAAAA,YAAAA,EAAAA,WAAAA,aAjElE,IAiEwEK,GAAQtH,EAAQ3B,KAhEpFsI,EAAa,SAAS/G,EAAMsH,GAmE9B/J,MAAQgE,GAASwF,WAAW/G,EAAAsH,EAAYD,IAIpClB,EAAWb,GAnEfgC,OAqEKf,EAAMJ,WApEXkB,KAqEIM,EApEJD,OAAQtH,EAAQ3B,cAyEhBiB,SAAMkI,SAAYC,UAAS,WAASZ,SAAUC,GAC5Cf,QAAAA,UAAkBzE,EAAAA,KAAWD,EAAAA,SAAAA,EAAAA,SAAAA,GAC5B0E,EAAAb,SAAA8B,GAAAI,EAAAM,oBAAAV,EAAAH,IAIHV,MAASP,EAAAA,SAAoBC,KAAAA,EAAAA,QAAAA,GAC3B0B,EAAuBzG,EAAeO,gBAIxC/B,EAAInC,OAAQ4J,EAAAA,QAAeY,SAAAA,EAAgBb,GACzCxH,EAAMkI,OAAYG,EAAAA,cA1EnB,GAKCxK,QAAQ4J,UAAU3C,EAAKuD,gBACzBrI,EAAMkI,OAAOpD,EAAKuD,cAAe,SAAS7B,EAAgBH,GA8E1DG,EAASyB,EAA0BnB,GACjCT,EAAa/E,EAAoB+E,GAC7BO,GACAF,EAAAA,oBAA8Bd,KA/DtC5D,EAqFQ8E,SAAAA,QAAoBA,SAAAA,GApF1B,GAqFI9E,EApFJ,KAuFIkF,EAEAe,MAxFFjG,GAuFOmF,aAAA,QAAA,GACLc,IAGF,IAAGvH,GAAQpC,EAAagK,MAAApB,EAAUlF,EAAAD,WAvFpC,QAwFIzB,GAAOwH,MAAWS,EAAAA,eAClBvG,GAAOqF,aAAiB3G,QAAQjC,IAGlCwJ,EAAwBnB,GAENxI,WAxFhBoC,EAwFQA,UACRJ,EAAOA,EAAKyG,qBAAYD,EAAApG,EAAAlC,UAAA,GACnB6I,EAAW/I,EAAAA,EAAaG,iBAAOiC,EAAAnC,cAtFxC+B,EAwFSwH,EAAAS,qBAAAvG,EAAAD,WAAArB,EAAAlC,UAAA,GACW8B,WAAhBI,EAAOpC,SAvFFgC,EAAKyG,UACkB,SAArBrG,EAAQpC,SA2FRkK,EAAAA,UAAiB,IAEtBlI,QAAAA,EAAAA,SACDzC,EAAQ4K,cAEJ,GAAG5K,MAAAA,OAxFdmE,EA2Fa8F,YAAWQ,KAAMI,SAAAA,GA1F5B,GAAIpI,EAaJ,OAXEA,GA0FEA,QAAOmI,YAASC,IAAa,OAAAA,EACxBC,EAAAA,EACE9K,QAAS6K,OAAAA,GA1FXA,EAiGiBZ,WAAb/F,EAAAA,SACJqF,EAAAA,MAAAA,EAAAA,KAAAA,EAAAA,iBAIEjF,GAAAA,MAnGqB,SAArBzB,EAAQpC,SAmGE,IAAV6D,EAhGOuG,GAsGhB1G,EAAQA,WAAWD,EAAc8E,qBAAiB9E,EAAWgF,EAAAA,UAnGxDK,MAETpF,EAsGOyE,QAAYA,WACf/F,EAAAA,IAAU0G,MASjBrJ,EAAAA,IAAS,WAAA,WAEJG,GAAgBA,EAAAA,UAClBQ,EAAW,KACXkK,EAAU,YAMV7K,SAAM8K,kBAAgB,WAOxB,QAASC,GAAIC,EAAGC,GA7GhB,IA8GE,GAAAC,MA9GKJ,EAAIrH,OAAS,GAiHpBvD,EAAKyB,KAAAmJ,EAAAK,OAAA,EAAAC,GA9GL,OAkHQnJ,GAhHV,QAmHU2H,GAAAA,EAAOjH,GAlHf,OAmHQ2G,EAAAA,EAAAA,GAAa2B,EAlBVI,KAASF,UA5GpBxK,UAAW,KA8GTkK,SAAOK,EAjGXhL,MAAKyB,MAAS,iBAAkB,cAAe,OAAQ,SAASmI,EAAgBE,EAAasB,GAC3F,MAmHQvB,UAAAA,GAlHN,GAkHgCF,GAAQlH,EAAQnC,OAAYoJ,EAAMA,EAAAA,SAAMK,EAAQtH,EAAQ3B,KA/GpFsI,EAAa,SAAS/G,EAAMsH,GAiH9B,MAAI0B,GAAczB,WAAe0B,EAAAA,EAAc5B,IAE3C6B,EAAAA,GAEJ5B,OAAI6B,EAAYC,WAChB/B,KAAIlH,EAAY+B,OAAMiH,EAAUhH,eAA4CnC,EAAgBqC,EAAAA,cAAAA,GA7G1FgH,EAAiBL,EAAYM,MAAMlJ,EAAQpB,WAAWuK,OAAOP,EAAYM,MAAM,EAAGlJ,EAAQpB,YA+GxFa,EAAAA,EAAAA,YAAAA,+BAAAA,EAAAA,KAAAA,qCAAAA,SACAyH,EAAQlH,EAAQhC,QAAAA,EAAAA,UAAAA,EAAAA,oBAAAA,YAAAA,EAAAA,WAAAA,GAAAA,OAChBoL,GACAxG,KAAAA,EAAAA,cA7GJZ,MA6GaA,EAAOqH,WA5GpBzJ,KAAMmJ,EAAU9G,WA8GVxC,IA3GNyH,OA4GQ/J,EAAQ0E,UA3GhBuH,MA2GkCtH,EA1GlCc,OACEZ,MAyGkGpC,GAvGpG0J,OAwGQN,SAAOnI,EAAAA,IAvGRtD,KAwGMgF,OAAQN,GAAAA,EAAclC,gBAAiBH,EAAKqC,MAAcrC,EAAGyJ,aAAAtJ,EAAAiC,OAKlEjC,QAAAA,OAASH,GACToJ,KAAO3G,EAAAA,MAAAA,cA3GTL,MAAOgH,EAAO9H,MAAMmI,WACpBzJ,KAAMoJ,EAAO9H,MAAMe,YA8GnB+G,EAAIO,WACAC,EAAYvH,YAAUsH,EAAAA,MAAsCE,IAApBrB,EAAImB,aAChDxJ,EAAI2J,KAAQtC,EAAWS,MAAAA,UAEvBmB,EAAGW,oBA1GTC,MA6GQC,WA5GN,GA6GMC,GAAKpB,GAAAA,MAAAA,EAAAA,KAAAA,EAAAA,MAAAA,GAAAA,EAAAA,EAAAA,oBAAM9I,EAAMiK,GAAAA,OAAAA,EAAAA,MAAAA,EAAAA,EAAAA,SAAAA,EAAAA,UAAAA,IAAAA,EAAAA,EAAAA,oBAAKE,EAAAA,EAAaC,qBAAmBN,GAAAA,MAAAA,EAAAA,UAAAA,cAAOO,KAAkBJ,IAAU3C,EAAAA,GAAAA,OAAAA,EAAAA,KAAAA,EAAAA,IAxG/F,KAwGwJgD,GAAtClB,GAAVrJ,KAAgDuK,EAAOL,EAAIR,GAAAA,EAAAA,IAvGjKQ,EAuGgMnH,EAAeC,qBAAWkH,GAAAA,MAAAA,EAAAA,cAAAA,EAAAA,WAAAA,EAAAA,UAAAA,IAtG1NC,EAAKpB,MACH9I,KAAMiK,EAuGNvK,QAAM6K,EAAQxD,iBAAW4C,EACzBjK,MAAM8K,EAAaP,EAAAtM,KAAA2J,QACnB5H,SAAM+K,EAASvB,OAAAA,KAAAA,WAAAA,GACfxJ,MAAMgD,EAAO8G,aAAiBA,EAAAA,MAC9B7L,SAAaA,KAAAoF,WAAAkH,IAGbvK,GAAA6K,MAAcjJ,EAAStB,EAAKmC,EAAkBiH,kBArGlD1J,EAAM8K,YAAa,EAuGjBzH,EAAAA,OAAYmG,EACVxJ,EAAIgL,KAAO1K,EAAKyG,EAAAA,KAAAA,OAGhB9I,KAAI+M,OAAOtK,GAtGjBuK,WA4GUvK,SAAQgB,GA3GhB,MA4GWgI,GAAI5H,OAAWpB,EAAAA,gBAAQgB,EAAmBF,MAAQM,eAAKxB,EAAAyJ,aAAAL,EAAA9H,MAAAmI,YAAAzJ,EAAAqC,YAAA+G,EAAA9H,MAAAe,WA1GpEU,WA4GY,SAAO/C,GA3GjB,GAAI0K,GAAO1K,EAAKyG,SAChB,IAAIiE,EAAOtK,EAAQzB,SAAW+L,EAAOtK,EAAQvB,QAAS,OAAO,CAC7D,IAA0D,KAAtDuB,EAAQnB,mBAAmB2L,QAAQ5K,EAAK6J,UAAkB,OAAO,CA8GjE,IAAAzJ,EAAOgB,mBA5GT,IAAK,GAAII,GAAI,EAAGA,EAAIpB,EAAQgB,mBAAmBF,OAAQM,IA8GvD4C,GAAAA,GAAWhE,EAASkD,mBAAAA,GAAAA,OAAAA,GAAAA,EAAAA,mBAAAA,GAAAA,IACb8F,OAAO9H,CAIZ,QAAIuJ,GA3GVzG,UAkHWzG,SAAKoF,GAjHd,GAAKqG,EAAO9H,MAAZ,CAqHEgG,GACAkC,GADAlC,EAAgBjJ,EAAAA,MAAAA,SAEhB2E,MAAAA,EAAAA,QAAAA,EAAAA,GAAAA,MAAAA,EAAAA,OAAAA,KAAAA,EAAAA,QAAAA,EAAAA,GAAAA,MAAAA,EAAAA,QAAAA,KAAAA,EAAAA,QAAAA,EAAAA,GAAAA,MAAAA,EAAAA,OAAAA,KAAAA,EAAAA,UAAAA,EAAAA,GAAAA,MAAAA,EAAAA,SAASd,KAAMa,WAAA8H,IAAAzB,EAAArI,OAAA8J,GAAA,OA9GnBC,KAgHM,QA/GNxD,OAgHQ/J,EAAQ0E,YA/GhBuH,MA+GkCtH,EA9GlCc,OACEd,KA6GkGlC,GA3GpG0J,OA4GQN,SAAOnI,EAAAA,GA3GRtD,KA4GMgF,OAAQ8G,EAAAA,gBAAwBrH,EAAOF,KArGvClC,EAAKyJ,aAAetJ,EAASiC,QA0GtC4H,QAAO/H,OAAA9B,GACD4K,MAAAA,EAAazJ,MAAIU,WACjBgJ,KAAAA,EAAa5I,MAAAA,YAEfA,EAAAA,oBARA7E,QAAQ0E,OAAO9B,GAAWiC,KAAAA,EAAOgH,MAAO9H,cAAkBtB,MAAMoJ,EAAO9H,MAAMe,WAzG/ErC,KAAMoJ,EAAO9H,MAAMe,YAErB+G,EAAOnI,WASX+I,MAuGkCK,WApGhC,IAAK,GAoGiH1M,GAAVmF,GAA3BsG,GAAOxG,MAAAA,EAAYR,KAAAA,EAAAA,OApG3FZ,EAAI,EAAO,GAAJA,EAAQA,IACtBY,EAAQ,GAAIJ,MAAK7B,EAAS+B,KAAMV,EAAG,GAqGjC9B,EAAM6K,MACN7K,KAAM8K,EACN9K,MAAMgD,EAAasI,EAAQrN,KAAK6L,QAChC7L,SAAayL,EAAAxG,YAAAR,GAnGbU,SAAUnF,KAAKoF,WAAWX,IAG9B1C,GAAM6K,MAAQxD,EAAW3E,EAAOhC,EAAQ5B,iBAqGtCuE,EAAAA,YAAqB/C,EACnBN,EAAIuL,KAAAA,EAAYD,EAAShL,KAAKmC,OAC9BxE,KAAAgF,OAAOsI,GAET7G,WAAW,SAASd,GAClB,MAAK8F,GAAO9H,OAAOtB,EAAAmC,gBAAAiH,EAAA9H,MAAAa,eAAAnC,EAAAyJ,aAAAL,EAAA9H,MAAAmI,YAlGzB1G,WAAY,SAAS/C,GAqGf,GAAIkL,IAAAA,GAAc9B,MAAO9H,EAAAA,cAAMmI,EAAAA,WAAAA,EAAAA,EAC/B,OAAIoB,GAAc7I,EAAKoH,SAAO9H,EAAAA,UAAAA,EAAAA,SAlGpC8C,UAyGWzG,SAAKoF,GAxGd,GAAKqG,EAAO9H,MAAZ,CA4GEgG,GAAAA,GAAgBhJ,EAAAA,MAAAA,WAChBkL,EAAO,GAAAxH,MAAAoH,EAAA9H,MACP0B,MAAAA,EAAAA,QAAAA,EAAAA,SAAAA,EAAAA,GAAAA,KAAAA,EAAAA,QAAAA,EAAAA,SAAAA,EAAAA,GAAAA,KAAAA,EAAAA,QAAAA,EAAAA,SAAAA,EAAAA,GAAAA,KAAAA,EAAAA,SAAAA,EAAAA,SAAAA,EAAAA,GAASd,KAAMa,WAAA8H,IAAAzB,EAAArI,OAAA8J,GAAA,OArGnBC,KAuGM,OAtGNxD,OAuGQ/J,EAAQ0E,WAtGhBuH,MAsGkCtH,EArGlCc,OACEd,KAoGkGlC,IAlGpG0J,OAmGQN,SAAOnI,EAAAA,IAlGRtD,KAmGMgF,OAAQR,GAAAA,SAAkBhC,EAAAA,cAAe,GAAA,MAAAgL,SAAAhL,EAAA+B,KAAA,GAAA,KAC9C3E,QAAQ0E,OAAO9B,GAAW+B,KAAMkH,EAAO9H,MAAMa,cAAeC,MAAOgH,EAAO9H,MAAMmI,WAAYzJ,KAAMoJ,EAAO9H,MAAMe,YAC/G+G,EAAO3G,UA9FFzC,EAAKmC,gBAAkBhC,EAAS+B,OACzC3E,QAAQ0E,OAAO9B,GAgGf6J,KAAOZ,EAAA9H,MAAAa,cACDiJ,MAAAA,EAAYjL,MAAAA,WACZkL,KAAAA,EAAYnJ,MAAAA,YAEdA,EAAOO,oBA5FfuH,MA6FgCK,WA1F9B,IAAK,GA0F6G1M,GAA9CoC,EAAUqJ,EAAOxG,KAAAA,EAAYV,MAAAA,EAAAA,KAAAA,OAAOY,KA1F/FtB,EAAI,EAAO,GAAJA,EAAQA,IACtBU,EAAO,GAAIF,MAAKoJ,EAAY5J,EAAG,EAAG,GA2FhC9B,EAAM6K,MACN7K,KAAM8K,EACN9K,MAAMgD,EAAa2I,EAAO1N,KAAK6L,QAC/B7L,SAAayL,EAAAxG,YAAAV,GAzFbY,SAAUnF,KAAKoF,WAAWb,IAG9BxC,GAAM6K,MAAQc,EAAM,GAAGhB,MAAQ,IAAMgB,EAAMA,EAAMnK,OAAS,GAAGmJ,MA2F3DtH,EAAAA,YAAqB/C,EACnBN,EAAIuL,KAAAA,EAAYI,EAASrL,KAAKmC,OAC9BxE,KAAAgF,OAAOsI,GAET7G,WAAW,SAASd,GAClB,MAAK8F,GAAO9H,OAAOtB,EAAAmC,gBAAAiH,EAAA9H,MAAAa,eAxFzBY,WAAY,SAAS/C,GA2Ff,GAAIsL,IAAAA,GAAalC,MAAO9H,EAAMa,cAC1B0I,EAAAA,EAAAA,EAEJ,OAAGvH,GAAIS,EAAgB8G,SAAQU,EAAQD,UAAalL,EAC/CvB,SA3FXuF,UAAW,SAASd,GAClB,GAAK8F,EAAO9H,MAAZ,CAoGAnB,GAAAA,GAAUA,EAAAA,MAAAA,cAAAA,EAAAA,GAAAA,MAAAA,EAAAA,MAhGU,MAAhBmD,EAAIS,QAAgB8G,EAAQU,QAAQD,EAAa,GAA6B,KAAhBhI,EAAIS,QAAgB8G,EAAQU,QAAQD,EAAa,GAA6B,KAAhBhI,EAAIS,QAAgB8G,EAAQU,QAAQD,EAAa,GAA6B,KAAhBhI,EAAIS,SAAgB8G,EAAQU,QAAQD,EAAa,GAC1O3N,KAAKoF,WAAW8H,IAAUzB,EAAOrI,OAAO8J,GAAS,MAG1D,QACEhL,MAAOO,EAAQrB,QAAUyM,MAAMC,UAAUnC,MAAM9G,KAAK3C,EAAOO,EAAQrB,SAAWc,EAC9EM,SAAUA","file":"modules/datepicker.min.js","sourcesContent":["'use strict';\n\nangular.module('mgcrea.ngStrap.datepicker', [\n 'mgcrea.ngStrap.helpers.dateParser',\n 'mgcrea.ngStrap.helpers.dateFormatter',\n 'mgcrea.ngStrap.tooltip'])\n\n .provider('$datepicker', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n //uncommenting the following line will break backwards compatability\n // prefixEvent: 'datepicker',\n prefixClass: 'datepicker',\n placement: 'bottom-left',\n templateUrl: 'datepicker/datepicker.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n // lang: $locale.id,\n useNative: false,\n dateType: 'date',\n dateFormat: 'shortDate',\n timezone: null,\n modelDateFormat: null,\n dayFormat: 'dd',\n monthFormat: 'MMM',\n yearFormat: 'yyyy',\n monthTitleFormat: 'MMMM yyyy',\n yearTitleFormat: 'yyyy',\n strictFormat: false,\n autoclose: false,\n minDate: -Infinity,\n maxDate: +Infinity,\n startView: 0,\n minView: 0,\n startWeek: 0,\n daysOfWeekDisabled: '',\n iconLeft: 'glyphicon glyphicon-chevron-left',\n iconRight: 'glyphicon glyphicon-chevron-right'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, datepickerViews, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\n\n function DatepickerFactory(element, controller, config) {\n\n var $datepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $datepicker.$options;\n var scope = $datepicker.$scope;\n if(options.startView) options.startView -= options.minView;\n\n // View vars\n\n var pickerViews = datepickerViews($datepicker);\n $datepicker.$views = pickerViews.views;\n var viewDate = pickerViews.viewDate;\n scope.$mode = options.startView;\n scope.$iconLeft = options.iconLeft;\n scope.$iconRight = options.iconRight;\n var $picker = $datepicker.$views[scope.$mode];\n\n // Scope methods\n\n scope.$select = function(date) {\n $datepicker.select(date);\n };\n scope.$selectPane = function(value) {\n $datepicker.$selectPane(value);\n };\n scope.$toggleMode = function() {\n $datepicker.setMode((scope.$mode + 1) % $datepicker.$views.length);\n };\n\n // Public methods\n\n $datepicker.update = function(date) {\n // console.warn('$datepicker.update() newValue=%o', date);\n if(angular.isDate(date) && !isNaN(date.getTime())) {\n $datepicker.$date = date;\n $picker.update.call($picker, date);\n }\n // Build only if pristine\n $datepicker.$build(true);\n };\n\n $datepicker.updateDisabledDates = function(dateRanges) {\n options.disabledDateRanges = dateRanges;\n for(var i = 0, l = scope.rows.length; i < l; i++) {\n angular.forEach(scope.rows[i], $datepicker.$setDisabledEl);\n }\n };\n\n $datepicker.select = function(date, keep) {\n // console.warn('$datepicker.select', date, scope.$mode);\n if(!angular.isDate(controller.$dateValue)) controller.$dateValue = new Date(date);\n if(!scope.$mode || keep) {\n controller.$setViewValue(angular.copy(date));\n controller.$render();\n if(options.autoclose && !keep) {\n $timeout(function() { $datepicker.hide(true); });\n }\n } else {\n angular.extend(viewDate, {year: date.getFullYear(), month: date.getMonth(), date: date.getDate()});\n $datepicker.setMode(scope.$mode - 1);\n $datepicker.$build();\n }\n };\n\n $datepicker.setMode = function(mode) {\n // console.warn('$datepicker.setMode', mode);\n scope.$mode = mode;\n $picker = $datepicker.$views[scope.$mode];\n $datepicker.$build();\n };\n\n // Protected methods\n\n $datepicker.$build = function(pristine) {\n // console.warn('$datepicker.$build() viewDate=%o', viewDate);\n if(pristine === true && $picker.built) return;\n if(pristine === false && !$picker.built) return;\n $picker.build.call($picker);\n };\n\n $datepicker.$updateSelected = function() {\n for(var i = 0, l = scope.rows.length; i < l; i++) {\n angular.forEach(scope.rows[i], updateSelected);\n }\n };\n\n $datepicker.$isSelected = function(date) {\n return $picker.isSelected(date);\n };\n\n $datepicker.$setDisabledEl = function(el) {\n el.disabled = $picker.isDisabled(el.date);\n };\n\n $datepicker.$selectPane = function(value) {\n var steps = $picker.steps;\n // set targetDate to first day of month to avoid problems with\n // date values rollover. This assumes the viewDate does not\n // depend on the day of the month\n var targetDate = new Date(Date.UTC(viewDate.year + ((steps.year || 0) * value), viewDate.month + ((steps.month || 0) * value), 1));\n angular.extend(viewDate, {year: targetDate.getUTCFullYear(), month: targetDate.getUTCMonth(), date: targetDate.getUTCDate()});\n $datepicker.$build();\n };\n\n $datepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $datepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n if(evt.keyCode === 13) {\n if(!scope.$mode) {\n return $datepicker.hide(true);\n } else {\n return scope.$apply(function() { $datepicker.setMode(scope.$mode - 1); });\n }\n }\n\n // Navigate with keyboard\n $picker.onKeyDown(evt);\n parentScope.$digest();\n };\n\n // Private\n\n function updateSelected(el) {\n el.selected = $datepicker.$isSelected(el.date);\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $datepicker.init;\n $datepicker.init = function() {\n if(isNative && options.useNative) {\n element.prop('type', 'date');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if(isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $datepicker.destroy;\n $datepicker.destroy = function() {\n if(isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $datepicker.show;\n $datepicker.show = function() {\n _show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n // if $datepicker is no longer showing, don't setup events\n if(!$datepicker.$isShown) return;\n $datepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $datepicker.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $datepicker.hide;\n $datepicker.hide = function(blur) {\n if(!$datepicker.$isShown) return;\n $datepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $datepicker.$onKeyDown);\n }\n _hide(blur);\n };\n\n return $datepicker;\n\n }\n\n DatepickerFactory.defaults = defaults;\n return DatepickerFactory;\n\n };\n\n })\n\n .directive('bsDatepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $datepicker) {\n\n var defaults = $datepicker.defaults;\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'autoclose', 'dateType', 'dateFormat', 'timezone', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled', 'id', 'prefixClass', 'prefixEvent'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'autoclose', 'useNative'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!datepicker || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(datepicker),?/i);\n newValue === true ? datepicker.show() : datepicker.hide();\n });\n\n // Initialize datepicker\n var datepicker = $datepicker(element, controller, options);\n options = datepicker.$options;\n // Set expected iOS format\n if(isNative && options.useNative) options.dateFormat = 'yyyy-MM-dd';\n\n var lang = options.lang;\n\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n\n var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});\n\n // Observe attributes for changes\n angular.forEach(['minDate', 'maxDate'], function(key) {\n // console.warn('attr.$observe(%s)', key, attr[key]);\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\n // console.warn('attr.$observe(%s)=%o', key, newValue);\n datepicker.$options[key] = dateParser.getDateForAttribute(key, newValue);\n // Build only if dirty\n !isNaN(datepicker.$options[key]) && datepicker.$build(false);\n validateAgainstMinMaxDate(controller.$dateValue);\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n datepicker.update(controller.$dateValue);\n }, true);\n\n // Normalize undefined/null/empty array,\n // so that we don't treat changing from undefined->null as a change.\n function normalizeDateRanges(ranges) {\n if (!ranges || !ranges.length) return null;\n return ranges;\n }\n\n if (angular.isDefined(attr.disabledDates)) {\n scope.$watch(attr.disabledDates, function(disabledRanges, previousValue) {\n disabledRanges = normalizeDateRanges(disabledRanges);\n previousValue = normalizeDateRanges(previousValue);\n\n if (disabledRanges) {\n datepicker.updateDisabledDates(disabledRanges);\n }\n });\n }\n\n function validateAgainstMinMaxDate(parsedDate) {\n if (!angular.isDate(parsedDate)) return;\n var isMinValid = isNaN(datepicker.$options.minDate) || parsedDate.getTime() >= datepicker.$options.minDate;\n var isMaxValid = isNaN(datepicker.$options.maxDate) || parsedDate.getTime() <= datepicker.$options.maxDate;\n var isValid = isMinValid && isMaxValid;\n controller.$setValidity('date', isValid);\n controller.$setValidity('min', isMinValid);\n controller.$setValidity('max', isMaxValid);\n // Only update the model when we have a valid date\n if(isValid) controller.$dateValue = parsedDate;\n }\n\n // viewValue -> $parsers -> modelValue\n controller.$parsers.unshift(function(viewValue) {\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\n var date;\n // Null values should correctly reset the model value & validity\n if(!viewValue) {\n controller.$setValidity('date', true);\n // BREAKING CHANGE:\n // return null (not undefined) when input value is empty, so angularjs 1.3\n // ngModelController can go ahead and run validators, like ngRequired\n return null;\n }\n var parsedDate = dateParser.parse(viewValue, controller.$dateValue);\n if(!parsedDate || isNaN(parsedDate.getTime())) {\n controller.$setValidity('date', false);\n // return undefined, causes ngModelController to\n // invalidate model value\n return;\n } else {\n validateAgainstMinMaxDate(parsedDate);\n }\n\n if(options.dateType === 'string') {\n date = dateParser.timezoneOffsetAdjust(parsedDate, options.timezone, true);\n return formatDate(date, options.modelDateFormat || options.dateFormat);\n }\n date = dateParser.timezoneOffsetAdjust(controller.$dateValue, options.timezone, true);\n if(options.dateType === 'number') {\n return date.getTime();\n } else if(options.dateType === 'unix') {\n return date.getTime() / 1000;\n } else if(options.dateType === 'iso') {\n return date.toISOString();\n } else {\n return new Date(date);\n }\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var date;\n if(angular.isUndefined(modelValue) || modelValue === null) {\n date = NaN;\n } else if(angular.isDate(modelValue)) {\n date = modelValue;\n } else if(options.dateType === 'string') {\n date = dateParser.parse(modelValue, null, options.modelDateFormat);\n } else if(options.dateType === 'unix') {\n date = new Date(modelValue * 1000);\n } else {\n date = new Date(modelValue);\n }\n // Setup default value?\n // if(isNaN(date.getTime())) {\n // var today = new Date();\n // date = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0, 0);\n // }\n controller.$dateValue = dateParser.timezoneOffsetAdjust(date, options.timezone);\n return getDateFormattedString();\n });\n\n // viewValue -> element\n controller.$render = function() {\n // console.warn('$render(\"%s\"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);\n element.val(getDateFormattedString());\n };\n\n function getDateFormattedString() {\n return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.dateFormat);\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if(datepicker) datepicker.destroy();\n options = null;\n datepicker = null;\n });\n\n }\n };\n\n })\n\n .provider('datepickerViews', function() {\n\n var defaults = this.defaults = {\n dayFormat: 'dd',\n daySplit: 7\n };\n\n // Split array into smaller arrays\n function split(arr, size) {\n var arrays = [];\n while(arr.length > 0) {\n arrays.push(arr.splice(0, size));\n }\n return arrays;\n }\n\n // Modulus operator\n function mod(n, m) {\n return ((n % m) + m) % m;\n }\n\n this.$get = function($dateFormatter, $dateParser, $sce) {\n\n return function(picker) {\n\n var scope = picker.$scope;\n var options = picker.$options;\n\n var lang = options.lang;\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});\n\n var weekDaysMin = $dateFormatter.weekdaysShort(lang);\n var weekDaysLabels = weekDaysMin.slice(options.startWeek).concat(weekDaysMin.slice(0, options.startWeek));\n var weekDaysLabelsHtml = $sce.trustAsHtml('' + weekDaysLabels.join('') + '');\n\n var startDate = picker.$date || (options.startDate ? dateParser.getDateForAttribute('startDate', options.startDate) : new Date());\n var viewDate = {year: startDate.getFullYear(), month: startDate.getMonth(), date: startDate.getDate()};\n\n var views = [{\n format: options.dayFormat,\n split: 7,\n steps: { month: 1 },\n update: function(date, force) {\n if(!this.built || force || date.getFullYear() !== viewDate.year || date.getMonth() !== viewDate.month) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getDate() !== viewDate.date || date.getDate() === 1) {\n // chaging picker current month will cause viewDate.date to be set to first day of the month,\n // in $datepicker.$selectPane, so picker would not update selected day display if\n // user picks first day of the new month.\n // As a workaround, we are always forcing update when picked date is first day of month.\n viewDate.date = picker.$date.getDate();\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstDayOfMonth = new Date(viewDate.year, viewDate.month, 1), firstDayOfMonthOffset = firstDayOfMonth.getTimezoneOffset();\n var firstDate = new Date(+firstDayOfMonth - mod(firstDayOfMonth.getDay() - options.startWeek, 7) * 864e5), firstDateOffset = firstDate.getTimezoneOffset();\n var today = dateParser.timezoneOffsetAdjust(new Date(), options.timezone).toDateString();\n // Handle daylight time switch\n if(firstDateOffset !== firstDayOfMonthOffset) firstDate = new Date(+firstDate + (firstDateOffset - firstDayOfMonthOffset) * 60e3);\n var days = [], day;\n for(var i = 0; i < 42; i++) { // < 7 * 6\n day = dateParser.daylightSavingAdjust(new Date(firstDate.getFullYear(), firstDate.getMonth(), firstDate.getDate() + i));\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)});\n }\n scope.title = formatDate(firstDayOfMonth, options.monthTitleFormat);\n scope.showLabels = true;\n scope.labels = weekDaysLabelsHtml;\n scope.rows = split(days, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth() && date.getDate() === picker.$date.getDate();\n },\n isDisabled: function(date) {\n var time = date.getTime();\n\n // Disabled because of min/max date.\n if (time < options.minDate || time > options.maxDate) return true;\n\n // Disabled due to being a disabled day of the week\n if (options.daysOfWeekDisabled.indexOf(date.getDay()) !== -1) return true;\n\n // Disabled because of disabled date range.\n if (options.disabledDateRanges) {\n for (var i = 0; i < options.disabledDateRanges.length; i++) {\n if (time >= options.disabledDateRanges[i].start && time <= options.disabledDateRanges[i].end) {\n return true;\n }\n }\n }\n\n return false;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualTime = picker.$date.getTime();\n var newDate;\n\n if(evt.keyCode === 37) newDate = new Date(actualTime - 1 * 864e5);\n else if(evt.keyCode === 38) newDate = new Date(actualTime - 7 * 864e5);\n else if(evt.keyCode === 39) newDate = new Date(actualTime + 1 * 864e5);\n else if(evt.keyCode === 40) newDate = new Date(actualTime + 7 * 864e5);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }, {\n name: 'month',\n format: options.monthFormat,\n split: 4,\n steps: { year: 1 },\n update: function(date, force) {\n if(!this.built || date.getFullYear() !== viewDate.year) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getMonth() !== viewDate.month) {\n angular.extend(viewDate, {month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstMonth = new Date(viewDate.year, 0, 1);\n var months = [], month;\n for (var i = 0; i < 12; i++) {\n month = new Date(viewDate.year, i, 1);\n months.push({date: month, label: formatDate(month, this.format), selected: picker.$isSelected(month), disabled: this.isDisabled(month)});\n }\n scope.title = formatDate(month, options.yearTitleFormat);\n scope.showLabels = false;\n scope.rows = split(months, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth();\n },\n isDisabled: function(date) {\n var lastDate = +new Date(date.getFullYear(), date.getMonth() + 1, 0);\n return lastDate < options.minDate || date.getTime() > options.maxDate;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualMonth = picker.$date.getMonth();\n var newDate = new Date(picker.$date);\n\n if(evt.keyCode === 37) newDate.setMonth(actualMonth - 1);\n else if(evt.keyCode === 38) newDate.setMonth(actualMonth - 4);\n else if(evt.keyCode === 39) newDate.setMonth(actualMonth + 1);\n else if(evt.keyCode === 40) newDate.setMonth(actualMonth + 4);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }, {\n name: 'year',\n format: options.yearFormat,\n split: 4,\n steps: { year: 12 },\n update: function(date, force) {\n if(!this.built || force || parseInt(date.getFullYear()/20, 10) !== parseInt(viewDate.year/20, 10)) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getFullYear() !== viewDate.year) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstYear = viewDate.year - viewDate.year % (this.split * 3);\n var years = [], year;\n for (var i = 0; i < 12; i++) {\n year = new Date(firstYear + i, 0, 1);\n years.push({date: year, label: formatDate(year, this.format), selected: picker.$isSelected(year), disabled: this.isDisabled(year)});\n }\n scope.title = years[0].label + '-' + years[years.length - 1].label;\n scope.showLabels = false;\n scope.rows = split(years, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear();\n },\n isDisabled: function(date) {\n var lastDate = +new Date(date.getFullYear() + 1, 0, 0);\n return lastDate < options.minDate || date.getTime() > options.maxDate;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualYear = picker.$date.getFullYear(),\n newDate = new Date(picker.$date);\n\n if(evt.keyCode === 37) newDate.setYear(actualYear - 1);\n else if(evt.keyCode === 38) newDate.setYear(actualYear - 4);\n else if(evt.keyCode === 39) newDate.setYear(actualYear + 1);\n else if(evt.keyCode === 40) newDate.setYear(actualYear + 4);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }];\n\n return {\n views: options.minView ? Array.prototype.slice.call(views, options.minView) : views,\n viewDate: viewDate\n };\n\n };\n\n };\n\n });\n"],"sourceRoot":"/source/"} \ No newline at end of file +{"version":3,"sources":["modules/datepicker.js"],"names":["angular","container","provider","keyboard","this","defaults","html","delay","useNative","dateType","dateFormat","timezone","modelDateFormat","dayFormat","monthFormat","yearFormat","monthTitleFormat","yearTitleFormat","strictFormat","autoclose","minDate","Infinity","maxDate","startView","minView","startWeek","daysOfWeekDisabled","iconLeft","iconRight","$get","bodyEl","isNative","DatepickerFactory","parentScope","config","scope","$datepicker","pickerViews","views","el","selected","date","element","focus","viewDate","options","$iconLeft","$iconRight","$picker","$views","$mode","datepickerViews","$selectPane","value","$toggleMode","setMode","select","isDate","$build","length","updateDisabledDates","disabledDateRanges","dateRanges","$date","forEach","i","$dateValue","controller","$setViewValue","copy","$render","hide","keep","Date","extend","year","getFullYear","month","getDate","mode","pristine","call","$updateSelected","rows","built","$isSelected","$setDisabledEl","disabled","isDisabled","steps","targetDate","getUTCFullYear","getUTCMonth","UTC","$onMouseDown","evt","preventDefault","stopPropagation","isTouch","getUTCDate","targetEl","$onKeyDown","nodeName","test","keyCode","shiftKey","altKey","$apply","updateSelected","onKeyDown","$digest","prop","init","attr","focusElement","_init","_destroy","destroy","off","_show","show","$timeout","_hide","on","blur","$element","directive","$options","$scope","require","restrict","$window","navigator","userAgent","link","falseValueRegExp","previousValue","normalizeDateRanges","ranges","disabledRanges","datepicker","isMaxValid","isValid","isMinValid","isNaN","parsedDate","getTime","$parsers","unshift","viewValue","$setValidity","getDateFormattedString","formatDate","bsShow","newValue","oldValue","isDefined","key","lang","format","$dateFormatter","dateParser","$dateParser","strict","validateAgainstMinMaxDate","$watch","ngModel","getDateForAttribute","disabledDates","parse","timezoneOffsetAdjust","$formatters","isUndefined","modelValue","NaN","daySplit","arr","mod","n","m","arrays","splice","size","push","$sce","weekDaysMin","weekdaysShort","weekDaysLabelsHtml","startDate","picker","weekDaysLabels","slice","concat","split","getMonth","update","firstDayOfMonth","firstDate","getDay","today","firstDateOffset","build","day","days","isToday","toDateString","label","muted","title","showLabels","labels","time","isSelected","indexOf","newDate","name","firstMonth","months","lastDate","actualMonth","parseInt","firstYear","years","actualYear","setYear","Array","prototype"],"mappings":"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","file":"modules/datepicker.min.js","sourcesContent":["'use strict';\n\nangular.module('mgcrea.ngStrap.datepicker', [\n 'mgcrea.ngStrap.helpers.dateParser',\n 'mgcrea.ngStrap.helpers.dateFormatter',\n 'mgcrea.ngStrap.tooltip'])\n\n .provider('$datepicker', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n //uncommenting the following line will break backwards compatability\n // prefixEvent: 'datepicker',\n prefixClass: 'datepicker',\n placement: 'bottom-left',\n templateUrl: 'datepicker/datepicker.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n // lang: $locale.id,\n useNative: false,\n dateType: 'date',\n dateFormat: 'shortDate',\n timezone: null,\n modelDateFormat: null,\n dayFormat: 'dd',\n monthFormat: 'MMM',\n yearFormat: 'yyyy',\n monthTitleFormat: 'MMMM yyyy',\n yearTitleFormat: 'yyyy',\n strictFormat: false,\n autoclose: false,\n minDate: -Infinity,\n maxDate: +Infinity,\n startView: 0,\n minView: 0,\n startWeek: 0,\n daysOfWeekDisabled: '',\n iconLeft: 'glyphicon glyphicon-chevron-left',\n iconRight: 'glyphicon glyphicon-chevron-right'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, datepickerViews, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\n\n function DatepickerFactory(element, controller, config) {\n\n var $datepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $datepicker.$options;\n var scope = $datepicker.$scope;\n if(options.startView) options.startView -= options.minView;\n\n // View vars\n\n var pickerViews = datepickerViews($datepicker);\n $datepicker.$views = pickerViews.views;\n var viewDate = pickerViews.viewDate;\n scope.$mode = options.startView;\n scope.$iconLeft = options.iconLeft;\n scope.$iconRight = options.iconRight;\n var $picker = $datepicker.$views[scope.$mode];\n\n // Scope methods\n\n scope.$select = function(date) {\n $datepicker.select(date);\n };\n scope.$selectPane = function(value) {\n $datepicker.$selectPane(value);\n };\n scope.$toggleMode = function() {\n $datepicker.setMode((scope.$mode + 1) % $datepicker.$views.length);\n };\n\n // Public methods\n\n $datepicker.update = function(date) {\n // console.warn('$datepicker.update() newValue=%o', date);\n if(angular.isDate(date) && !isNaN(date.getTime())) {\n $datepicker.$date = date;\n $picker.update.call($picker, date);\n }\n // Build only if pristine\n $datepicker.$build(true);\n };\n\n $datepicker.updateDisabledDates = function(dateRanges) {\n options.disabledDateRanges = dateRanges;\n for(var i = 0, l = scope.rows.length; i < l; i++) {\n angular.forEach(scope.rows[i], $datepicker.$setDisabledEl);\n }\n };\n\n $datepicker.select = function(date, keep) {\n // console.warn('$datepicker.select', date, scope.$mode);\n if(!angular.isDate(controller.$dateValue)) controller.$dateValue = new Date(date);\n if(!scope.$mode || keep) {\n controller.$setViewValue(angular.copy(date));\n controller.$render();\n if(options.autoclose && !keep) {\n $timeout(function() { $datepicker.hide(true); });\n }\n } else {\n angular.extend(viewDate, {year: date.getFullYear(), month: date.getMonth(), date: date.getDate()});\n $datepicker.setMode(scope.$mode - 1);\n $datepicker.$build();\n }\n };\n\n $datepicker.setMode = function(mode) {\n // console.warn('$datepicker.setMode', mode);\n scope.$mode = mode;\n $picker = $datepicker.$views[scope.$mode];\n $datepicker.$build();\n };\n\n // Protected methods\n\n $datepicker.$build = function(pristine) {\n // console.warn('$datepicker.$build() viewDate=%o', viewDate);\n if(pristine === true && $picker.built) return;\n if(pristine === false && !$picker.built) return;\n $picker.build.call($picker);\n };\n\n $datepicker.$updateSelected = function() {\n for(var i = 0, l = scope.rows.length; i < l; i++) {\n angular.forEach(scope.rows[i], updateSelected);\n }\n };\n\n $datepicker.$isSelected = function(date) {\n return $picker.isSelected(date);\n };\n\n $datepicker.$setDisabledEl = function(el) {\n el.disabled = $picker.isDisabled(el.date);\n };\n\n $datepicker.$selectPane = function(value) {\n var steps = $picker.steps;\n // set targetDate to first day of month to avoid problems with\n // date values rollover. This assumes the viewDate does not\n // depend on the day of the month\n var targetDate = new Date(Date.UTC(viewDate.year + ((steps.year || 0) * value), viewDate.month + ((steps.month || 0) * value), 1));\n angular.extend(viewDate, {year: targetDate.getUTCFullYear(), month: targetDate.getUTCMonth(), date: targetDate.getUTCDate()});\n $datepicker.$build();\n };\n\n $datepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $datepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n if(evt.keyCode === 13) {\n if(!scope.$mode) {\n return $datepicker.hide(true);\n } else {\n return scope.$apply(function() { $datepicker.setMode(scope.$mode - 1); });\n }\n }\n\n // Navigate with keyboard\n $picker.onKeyDown(evt);\n parentScope.$digest();\n };\n\n // Private\n\n function updateSelected(el) {\n el.selected = $datepicker.$isSelected(el.date);\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $datepicker.init;\n $datepicker.init = function() {\n if(isNative && options.useNative) {\n element.prop('type', 'date');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if(isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $datepicker.destroy;\n $datepicker.destroy = function() {\n if(isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $datepicker.show;\n $datepicker.show = function() {\n if((!isTouch && element.attr('readonly')) || element.attr('disabled')) return;\n _show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n // if $datepicker is no longer showing, don't setup events\n if(!$datepicker.$isShown) return;\n $datepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $datepicker.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $datepicker.hide;\n $datepicker.hide = function(blur) {\n if(!$datepicker.$isShown) return;\n $datepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $datepicker.$onKeyDown);\n }\n _hide(blur);\n };\n\n return $datepicker;\n\n }\n\n DatepickerFactory.defaults = defaults;\n return DatepickerFactory;\n\n };\n\n })\n\n .directive('bsDatepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $datepicker) {\n\n var defaults = $datepicker.defaults;\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'autoclose', 'dateType', 'dateFormat', 'timezone', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled', 'id', 'prefixClass', 'prefixEvent'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'autoclose', 'useNative'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!datepicker || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(datepicker),?/i);\n newValue === true ? datepicker.show() : datepicker.hide();\n });\n\n // Initialize datepicker\n var datepicker = $datepicker(element, controller, options);\n options = datepicker.$options;\n // Set expected iOS format\n if(isNative && options.useNative) options.dateFormat = 'yyyy-MM-dd';\n\n var lang = options.lang;\n\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n\n var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});\n\n // Observe attributes for changes\n angular.forEach(['minDate', 'maxDate'], function(key) {\n // console.warn('attr.$observe(%s)', key, attr[key]);\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\n // console.warn('attr.$observe(%s)=%o', key, newValue);\n datepicker.$options[key] = dateParser.getDateForAttribute(key, newValue);\n // Build only if dirty\n !isNaN(datepicker.$options[key]) && datepicker.$build(false);\n validateAgainstMinMaxDate(controller.$dateValue);\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n datepicker.update(controller.$dateValue);\n }, true);\n\n // Normalize undefined/null/empty array,\n // so that we don't treat changing from undefined->null as a change.\n function normalizeDateRanges(ranges) {\n if (!ranges || !ranges.length) return null;\n return ranges;\n }\n\n if (angular.isDefined(attr.disabledDates)) {\n scope.$watch(attr.disabledDates, function(disabledRanges, previousValue) {\n disabledRanges = normalizeDateRanges(disabledRanges);\n previousValue = normalizeDateRanges(previousValue);\n\n if (disabledRanges) {\n datepicker.updateDisabledDates(disabledRanges);\n }\n });\n }\n\n function validateAgainstMinMaxDate(parsedDate) {\n if (!angular.isDate(parsedDate)) return;\n var isMinValid = isNaN(datepicker.$options.minDate) || parsedDate.getTime() >= datepicker.$options.minDate;\n var isMaxValid = isNaN(datepicker.$options.maxDate) || parsedDate.getTime() <= datepicker.$options.maxDate;\n var isValid = isMinValid && isMaxValid;\n controller.$setValidity('date', isValid);\n controller.$setValidity('min', isMinValid);\n controller.$setValidity('max', isMaxValid);\n // Only update the model when we have a valid date\n if(isValid) controller.$dateValue = parsedDate;\n }\n\n // viewValue -> $parsers -> modelValue\n controller.$parsers.unshift(function(viewValue) {\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\n var date;\n // Null values should correctly reset the model value & validity\n if(!viewValue) {\n controller.$setValidity('date', true);\n // BREAKING CHANGE:\n // return null (not undefined) when input value is empty, so angularjs 1.3\n // ngModelController can go ahead and run validators, like ngRequired\n return null;\n }\n var parsedDate = dateParser.parse(viewValue, controller.$dateValue);\n if(!parsedDate || isNaN(parsedDate.getTime())) {\n controller.$setValidity('date', false);\n // return undefined, causes ngModelController to\n // invalidate model value\n return;\n } else {\n validateAgainstMinMaxDate(parsedDate);\n }\n\n if(options.dateType === 'string') {\n date = dateParser.timezoneOffsetAdjust(parsedDate, options.timezone, true);\n return formatDate(date, options.modelDateFormat || options.dateFormat);\n }\n date = dateParser.timezoneOffsetAdjust(controller.$dateValue, options.timezone, true);\n if(options.dateType === 'number') {\n return date.getTime();\n } else if(options.dateType === 'unix') {\n return date.getTime() / 1000;\n } else if(options.dateType === 'iso') {\n return date.toISOString();\n } else {\n return new Date(date);\n }\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var date;\n if(angular.isUndefined(modelValue) || modelValue === null) {\n date = NaN;\n } else if(angular.isDate(modelValue)) {\n date = modelValue;\n } else if(options.dateType === 'string') {\n date = dateParser.parse(modelValue, null, options.modelDateFormat);\n } else if(options.dateType === 'unix') {\n date = new Date(modelValue * 1000);\n } else {\n date = new Date(modelValue);\n }\n // Setup default value?\n // if(isNaN(date.getTime())) {\n // var today = new Date();\n // date = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0, 0);\n // }\n controller.$dateValue = dateParser.timezoneOffsetAdjust(date, options.timezone);\n return getDateFormattedString();\n });\n\n // viewValue -> element\n controller.$render = function() {\n // console.warn('$render(\"%s\"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);\n element.val(getDateFormattedString());\n };\n\n function getDateFormattedString() {\n return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.dateFormat);\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if(datepicker) datepicker.destroy();\n options = null;\n datepicker = null;\n });\n\n }\n };\n\n })\n\n .provider('datepickerViews', function() {\n\n var defaults = this.defaults = {\n dayFormat: 'dd',\n daySplit: 7\n };\n\n // Split array into smaller arrays\n function split(arr, size) {\n var arrays = [];\n while(arr.length > 0) {\n arrays.push(arr.splice(0, size));\n }\n return arrays;\n }\n\n // Modulus operator\n function mod(n, m) {\n return ((n % m) + m) % m;\n }\n\n this.$get = function($dateFormatter, $dateParser, $sce) {\n\n return function(picker) {\n\n var scope = picker.$scope;\n var options = picker.$options;\n\n var lang = options.lang;\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});\n\n var weekDaysMin = $dateFormatter.weekdaysShort(lang);\n var weekDaysLabels = weekDaysMin.slice(options.startWeek).concat(weekDaysMin.slice(0, options.startWeek));\n var weekDaysLabelsHtml = $sce.trustAsHtml('' + weekDaysLabels.join('') + '');\n\n var startDate = picker.$date || (options.startDate ? dateParser.getDateForAttribute('startDate', options.startDate) : new Date());\n var viewDate = {year: startDate.getFullYear(), month: startDate.getMonth(), date: startDate.getDate()};\n\n var views = [{\n format: options.dayFormat,\n split: 7,\n steps: { month: 1 },\n update: function(date, force) {\n if(!this.built || force || date.getFullYear() !== viewDate.year || date.getMonth() !== viewDate.month) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getDate() !== viewDate.date || date.getDate() === 1) {\n // chaging picker current month will cause viewDate.date to be set to first day of the month,\n // in $datepicker.$selectPane, so picker would not update selected day display if\n // user picks first day of the new month.\n // As a workaround, we are always forcing update when picked date is first day of month.\n viewDate.date = picker.$date.getDate();\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstDayOfMonth = new Date(viewDate.year, viewDate.month, 1), firstDayOfMonthOffset = firstDayOfMonth.getTimezoneOffset();\n var firstDate = new Date(+firstDayOfMonth - mod(firstDayOfMonth.getDay() - options.startWeek, 7) * 864e5), firstDateOffset = firstDate.getTimezoneOffset();\n var today = dateParser.timezoneOffsetAdjust(new Date(), options.timezone).toDateString();\n // Handle daylight time switch\n if(firstDateOffset !== firstDayOfMonthOffset) firstDate = new Date(+firstDate + (firstDateOffset - firstDayOfMonthOffset) * 60e3);\n var days = [], day;\n for(var i = 0; i < 42; i++) { // < 7 * 6\n day = dateParser.daylightSavingAdjust(new Date(firstDate.getFullYear(), firstDate.getMonth(), firstDate.getDate() + i));\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)});\n }\n scope.title = formatDate(firstDayOfMonth, options.monthTitleFormat);\n scope.showLabels = true;\n scope.labels = weekDaysLabelsHtml;\n scope.rows = split(days, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth() && date.getDate() === picker.$date.getDate();\n },\n isDisabled: function(date) {\n var time = date.getTime();\n\n // Disabled because of min/max date.\n if (time < options.minDate || time > options.maxDate) return true;\n\n // Disabled due to being a disabled day of the week\n if (options.daysOfWeekDisabled.indexOf(date.getDay()) !== -1) return true;\n\n // Disabled because of disabled date range.\n if (options.disabledDateRanges) {\n for (var i = 0; i < options.disabledDateRanges.length; i++) {\n if (time >= options.disabledDateRanges[i].start && time <= options.disabledDateRanges[i].end) {\n return true;\n }\n }\n }\n\n return false;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualTime = picker.$date.getTime();\n var newDate;\n\n if(evt.keyCode === 37) newDate = new Date(actualTime - 1 * 864e5);\n else if(evt.keyCode === 38) newDate = new Date(actualTime - 7 * 864e5);\n else if(evt.keyCode === 39) newDate = new Date(actualTime + 1 * 864e5);\n else if(evt.keyCode === 40) newDate = new Date(actualTime + 7 * 864e5);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }, {\n name: 'month',\n format: options.monthFormat,\n split: 4,\n steps: { year: 1 },\n update: function(date, force) {\n if(!this.built || date.getFullYear() !== viewDate.year) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getMonth() !== viewDate.month) {\n angular.extend(viewDate, {month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstMonth = new Date(viewDate.year, 0, 1);\n var months = [], month;\n for (var i = 0; i < 12; i++) {\n month = new Date(viewDate.year, i, 1);\n months.push({date: month, label: formatDate(month, this.format), selected: picker.$isSelected(month), disabled: this.isDisabled(month)});\n }\n scope.title = formatDate(month, options.yearTitleFormat);\n scope.showLabels = false;\n scope.rows = split(months, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth();\n },\n isDisabled: function(date) {\n var lastDate = +new Date(date.getFullYear(), date.getMonth() + 1, 0);\n return lastDate < options.minDate || date.getTime() > options.maxDate;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualMonth = picker.$date.getMonth();\n var newDate = new Date(picker.$date);\n\n if(evt.keyCode === 37) newDate.setMonth(actualMonth - 1);\n else if(evt.keyCode === 38) newDate.setMonth(actualMonth - 4);\n else if(evt.keyCode === 39) newDate.setMonth(actualMonth + 1);\n else if(evt.keyCode === 40) newDate.setMonth(actualMonth + 4);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }, {\n name: 'year',\n format: options.yearFormat,\n split: 4,\n steps: { year: 12 },\n update: function(date, force) {\n if(!this.built || force || parseInt(date.getFullYear()/20, 10) !== parseInt(viewDate.year/20, 10)) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getFullYear() !== viewDate.year) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstYear = viewDate.year - viewDate.year % (this.split * 3);\n var years = [], year;\n for (var i = 0; i < 12; i++) {\n year = new Date(firstYear + i, 0, 1);\n years.push({date: year, label: formatDate(year, this.format), selected: picker.$isSelected(year), disabled: this.isDisabled(year)});\n }\n scope.title = years[0].label + '-' + years[years.length - 1].label;\n scope.showLabels = false;\n scope.rows = split(years, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear();\n },\n isDisabled: function(date) {\n var lastDate = +new Date(date.getFullYear() + 1, 0, 0);\n return lastDate < options.minDate || date.getTime() > options.maxDate;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualYear = picker.$date.getFullYear(),\n newDate = new Date(picker.$date);\n\n if(evt.keyCode === 37) newDate.setYear(actualYear - 1);\n else if(evt.keyCode === 38) newDate.setYear(actualYear - 4);\n else if(evt.keyCode === 39) newDate.setYear(actualYear + 1);\n else if(evt.keyCode === 40) newDate.setYear(actualYear + 4);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }];\n\n return {\n views: options.minView ? Array.prototype.slice.call(views, options.minView) : views,\n viewDate: viewDate\n };\n\n };\n\n };\n\n });\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/dist/modules/datepicker.tpl.js b/dist/modules/datepicker.tpl.js index 6e780133f..67cfb1125 100644 --- a/dist/modules/datepicker.tpl.js +++ b/dist/modules/datepicker.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @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 2a3d94d9e..c9c7f41e3 100644 --- a/dist/modules/datepicker.tpl.min.js +++ b/dist/modules/datepicker.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/debounce.js b/dist/modules/debounce.js index 033add9e9..4ffa3857b 100644 --- a/dist/modules/debounce.js +++ b/dist/modules/debounce.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/debounce.min.js b/dist/modules/debounce.min.js index 0c237ff95..2e284d18b 100644 --- a/dist/modules/debounce.min.js +++ b/dist/modules/debounce.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/dimensions.js b/dist/modules/dimensions.js index 368e14007..df30d1b3b 100644 --- a/dist/modules/dimensions.js +++ b/dist/modules/dimensions.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/dimensions.min.js b/dist/modules/dimensions.min.js index a9cd52570..695b16bd3 100644 --- a/dist/modules/dimensions.min.js +++ b/dist/modules/dimensions.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/dropdown.js b/dist/modules/dropdown.js index a27f28bda..f723c9b96 100644 --- a/dist/modules/dropdown.js +++ b/dist/modules/dropdown.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/dropdown.min.js b/dist/modules/dropdown.min.js index 18ae61f4e..ab99b561a 100644 --- a/dist/modules/dropdown.min.js +++ b/dist/modules/dropdown.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/dropdown.tpl.js b/dist/modules/dropdown.tpl.js index 88b780576..1bbe6f63f 100644 --- a/dist/modules/dropdown.tpl.js +++ b/dist/modules/dropdown.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @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 e0d94fc96..eb6226b77 100644 --- a/dist/modules/dropdown.tpl.min.js +++ b/dist/modules/dropdown.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/modal.js b/dist/modules/modal.js index 08cf5b1f9..70351635d 100644 --- a/dist/modules/modal.js +++ b/dist/modules/modal.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/modal.min.js b/dist/modules/modal.min.js index f3737ecf9..2aeb0cfbb 100644 --- a/dist/modules/modal.min.js +++ b/dist/modules/modal.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/modal.tpl.js b/dist/modules/modal.tpl.js index 341d72f3f..154b4a090 100644 --- a/dist/modules/modal.tpl.js +++ b/dist/modules/modal.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @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 e97103cfb..516f343cd 100644 --- a/dist/modules/modal.tpl.min.js +++ b/dist/modules/modal.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/navbar.js b/dist/modules/navbar.js index df8d899f0..c39a35a9c 100644 --- a/dist/modules/navbar.js +++ b/dist/modules/navbar.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/navbar.min.js b/dist/modules/navbar.min.js index 3eb3520e6..b9d1941a0 100644 --- a/dist/modules/navbar.min.js +++ b/dist/modules/navbar.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/parse-options.js b/dist/modules/parse-options.js index bc5e0d292..5f7462662 100644 --- a/dist/modules/parse-options.js +++ b/dist/modules/parse-options.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -24,13 +24,7 @@ angular.module('mgcrea.ngStrap.helpers.parseOptions', []).provider('$parseOption valuesFn = $parse(match[7]); }; $parseOptions.valuesFn = function(scope, controller) { - var valuesPromise; - try { - valuesPromise = valuesFn(scope, controller); - } catch (err) { - valuesPromise = []; - } - return $q.when(valuesPromise).then(function(values) { + return $q.when(valuesFn(scope, controller)).then(function(values) { if (!angular.isArray(values)) { values = []; } diff --git a/dist/modules/parse-options.min.js b/dist/modules/parse-options.min.js index 1ef612712..f3e03bd45 100644 --- a/dist/modules/parse-options.min.js +++ b/dist/modules/parse-options.min.js @@ -1,9 +1,9 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT */ -'use strict';angular.module('mgcrea.ngStrap.helpers.parseOptions',[]).provider('$parseOptions',function(){var n=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(r,e){function s(s,t){function a(n,r){return n.map(function(n,e){var s,t,a={};return a[o]=n,s=l(r,a),t=v(r,a),{label:s,value:t,index:e}})}var u={},i=angular.extend({},n,t);u.$values=[];var c,l,o,$,p,v,f;return u.init=function(){u.$match=c=s.match(i.regexp),l=r(c[2]||c[1]),o=c[4]||c[6],$=c[5],p=r(c[3]||''),v=r(c[2]?c[1]:o),f=r(c[7])},u.valuesFn=function(n,r){var s;try{s=f(n,r)}catch(t){s=[]}return e.when(s).then(function(r){return angular.isArray(r)||(r=[]),u.$values=r.length?a(r,n):[],u.$values})},u.displayValue=function(n){var r={};return r[o]=n,l(r)},u.init(),u}return s}]}); +'use strict';angular.module('mgcrea.ngStrap.helpers.parseOptions',[]).provider('$parseOptions',function(){var n=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(r,e){function s(s,t){function a(n,r){return n.map(function(n,e){var s,t,a={};return a[$]=n,s=o(r,a),t=f(r,a),{label:s,value:t,index:e}})}var u={},i=angular.extend({},n,t);u.$values=[];var l,o,$,c,p,f,v;return u.init=function(){u.$match=l=s.match(i.regexp),o=r(l[2]||l[1]),$=l[4]||l[6],c=l[5],p=r(l[3]||''),f=r(l[2]?l[1]:$),v=r(l[7])},u.valuesFn=function(n,r){return e.when(v(n,r)).then(function(r){return angular.isArray(r)||(r=[]),u.$values=r.length?a(r,n):[],u.$values})},u.displayValue=function(n){var r={};return r[$]=n,o(r)},u.init(),u}return s}]}); //# sourceMappingURL=../modules/parse-options.min.js.map \ No newline at end of file diff --git a/dist/modules/parse-options.min.js.map b/dist/modules/parse-options.min.js.map index 7066b6299..8b21e9d06 100644 --- a/dist/modules/parse-options.min.js.map +++ b/dist/modules/parse-options.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["modules/parse-options.js"],"names":["angular","module","options","config","$parseOptions","$values","regexp","match","this","$get","$match","attr","displayFn","label","value","index","locals","valueName","scope","valueFn","ParseOptionsFactory","groupByFn","valuesFn","$parse","defaults","keyName","controller","valuesPromise","err","when","then","$q","values","displayValue","init"],"mappings":"AAOA,YAEAA,SAQQC,OAAIC,0CAAuCC,SAAAA,gBAAAA,WAPjD,GAQMC,GAAAA,KAAcC,UAPlBC,OAUQC,+KARVC,MAAKC,MAWGL,SAAcM,KAASH,SAAQI,EAAKJ,GAV1C,QAWMK,GAAyBD,EAAMJ,GAoBnC,QAoBcM,GAAOA,EAAAA,GAnBnB,MAmB0BC,GAAOA,IAAAA,SAAAA,EAAAA,GAlB/B,GAkB6CC,GAAAA,EAAPA,IAIxCX,OArBEY,GAAOC,GAAaV,EACpBM,EAAQD,EAAUM,EAAOF,GACzBF,EAAQK,EAAQD,EAAOF,IAoBzBH,MAAOT,EAjBHU,MAAOA,EAqBNM,MAAAA,KA3DP,GAaIC,MAEAC,EAAWC,QAAOhB,UAAMiB,EAAArB,EAb5BC,GAAcC,UAgBZD,IAAAA,GAAAA,EAAckB,EAAWG,EAAgBC,EAAAA,EAAAA,CA0B3C,OAxCAtB,GAeQuB,KAAAA,WACJvB,EAAAM,OAAAH,EAAAI,EAAAJ,MAAAL,EAAAI,QAdFM,EAgBIe,EAAgBL,EAAAA,IAASJ,EAAOQ,IAAAA,EAAAA,EAAAA,IAAAA,EAAAA,GAAAA,EAAAA,EAAAA,GAfpCL,EAgBUO,EAAAA,EAAAA,IAAAA,IAAAA,EAAAA,EAAAA,EAAAA,GAAAA,EAAAA,GAAAA,GAfVN,EAgBIK,EAAAA,EAAAA,KAdNvB,EAgBcyB,SAAKF,SACdG,EAAKJ,GAhBR,GAiBIC,EAhBJ,KACEA,EAAgBL,EAASJ,EAAOQ,GAkB9BtB,MAAAA,GACAuB,KAfJ,MAAOI,GAAGF,KAAKF,GAAeG,KAAK,SAASE,GAK1C,MAcF5B,SAAc6B,QAAAA,KACRf,MAEJd,EAAOQ,QAAUM,EAAAA,OAAAA,EAAAA,EAAAA,MAjBVd,EAAcC,WAGzBD,EAqBUY,aAAoBF,SAAAA,GApB5B,GAqBIE,KAnBJ,OADAE,GAqBIL,GAAQD,EACRE,EAAQK,IANdf,EAAc8B,OACP9B,EAET,MAAOgB","file":"modules/parse-options.min.js","sourcesContent":["'use strict';\n\nangular.module('mgcrea.ngStrap.helpers.parseOptions', [])\n\n .provider('$parseOptions', function() {\n\n var defaults = this.defaults = {\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+(.*?))?$/\n };\n\n this.$get = function($parse, $q) {\n\n function ParseOptionsFactory(attr, config) {\n\n var $parseOptions = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n $parseOptions.$values = [];\n\n // Private vars\n var match, displayFn, valueName, keyName, groupByFn, valueFn, valuesFn;\n\n $parseOptions.init = function() {\n $parseOptions.$match = match = attr.match(options.regexp);\n displayFn = $parse(match[2] || match[1]),\n valueName = match[4] || match[6],\n keyName = match[5],\n groupByFn = $parse(match[3] || ''),\n valueFn = $parse(match[2] ? match[1] : valueName),\n valuesFn = $parse(match[7]);\n };\n\n $parseOptions.valuesFn = function(scope, controller) {\n var valuesPromise;\n try {\n // Might throw 'notarray' error since cea8e75\n valuesPromise = valuesFn(scope, controller);\n } catch(err) {\n valuesPromise = [];\n }\n return $q.when(valuesPromise)\n .then(function(values) {\n if(!angular.isArray(values)) {\n values = [];\n }\n $parseOptions.$values = values.length ? parseValues(values, scope) : [];\n return $parseOptions.$values;\n });\n };\n\n $parseOptions.displayValue = function(modelValue) {\n var scope = {};\n scope[valueName] = modelValue;\n return displayFn(scope);\n };\n\n // Private functions\n\n function parseValues(values, scope) {\n return values.map(function(match, index) {\n var locals = {}, label, value;\n locals[valueName] = match;\n label = displayFn(scope, locals);\n value = valueFn(scope, locals);\n return {label: label, value: value, index: index};\n });\n }\n\n $parseOptions.init();\n return $parseOptions;\n\n }\n\n return ParseOptionsFactory;\n\n };\n\n });\n"],"sourceRoot":"/source/"} \ No newline at end of file +{"version":3,"sources":["modules/parse-options.js"],"names":["angular","module","options","config","$parseOptions","$values","regexp","match","this","$get","$match","attr","displayFn","label","value","index","locals","valueName","scope","valueFn","ParseOptionsFactory","groupByFn","valuesFn","$parse","defaults","keyName","controller","when","values","$q","then","displayValue","init"],"mappings":"AAOA,YAEAA,SAQQC,OAAIC,0CAAuCC,SAAAA,gBAAAA,WAPjD,GAQMC,GAAAA,KAAcC,UAPlBC,OAUQC,+KARVC,MAAKC,MAWGL,SAAcM,KAASH,SAAQI,EAAKJ,GAV1C,QAWMK,GAAyBD,EAAMJ,GAcnC,QAmBcM,GAAOA,EAAAA,GAlBnB,MAkB0BC,GAAOA,IAAAA,SAAAA,EAAAA,GAjB/B,GAiB6CC,GAAAA,EAAPA,IAIxCX,OApBEY,GAAOC,GAAaV,EACpBM,EAAQD,EAAUM,EAAOF,GACzBF,EAAQK,EAAQD,EAAOF,IAmBzBH,MAAOT,EAhBHU,MAAOA,EAoBNM,MAAAA,KApDP,GAaIC,MAEAC,EAAWC,QAAOhB,UAAMiB,EAAArB,EAb5BC,GAAcC,UAgBZD,IAAAA,GAAAA,EAAckB,EAAWG,EAAgBC,EAAAA,EAAAA,CAoB3C,OAlCAtB,GAecuB,KAAKL,WAdjBlB,EAgBQJ,OAAgB4B,EAAAA,EAASrB,MAAAL,EAAAI,QAfjCM,EAgBMgB,EAAAA,EAAAA,IAAAA,EAAAA,IAAAA,EAAAA,EAAAA,IAAAA,EAAAA,GAAAA,EAAAA,EAAAA,GAfNP,EAAYE,EAAOhB,EAAM,IAAM,IAAKY,EAAUI,EAAOhB,EAAM,GAAKA,EAAM,GAAKU,GAC3EK,EAgBIlB,EAAcC,EAAAA,KAdpBD,EAAckB,SAAW,SAASJ,EAAOQ,GACvC,MAAOG,GAAGF,KAAKL,EAASJ,EAAOQ,IAAaI,KAAK,SAASF,GAKxD,MAaFxB,SAAc2B,QAAAA,KACRb,MAEJd,EAAOQ,QAAUM,EAAAA,OAAAA,EAAAA,EAAAA,MAhBVd,EAAcC,WAGzBD,EAoBUY,aAAoBF,SAAAA,GAnB5B,GAoBIE,KAlBJ,OADAE,GAoBIL,GAAQD,EACRE,EAAQK,IALdf,EAAc4B,OACP5B,EAET,MAAOgB","file":"modules/parse-options.min.js","sourcesContent":["'use strict';\n\nangular.module('mgcrea.ngStrap.helpers.parseOptions', [])\n\n .provider('$parseOptions', function() {\n\n var defaults = this.defaults = {\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+(.*?))?$/\n };\n\n this.$get = function($parse, $q) {\n\n function ParseOptionsFactory(attr, config) {\n\n var $parseOptions = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n $parseOptions.$values = [];\n\n // Private vars\n var match, displayFn, valueName, keyName, groupByFn, valueFn, valuesFn;\n\n $parseOptions.init = function() {\n $parseOptions.$match = match = attr.match(options.regexp);\n displayFn = $parse(match[2] || match[1]),\n valueName = match[4] || match[6],\n keyName = match[5],\n groupByFn = $parse(match[3] || ''),\n valueFn = $parse(match[2] ? match[1] : valueName),\n valuesFn = $parse(match[7]);\n };\n\n $parseOptions.valuesFn = function(scope, controller) {\n return $q.when(valuesFn(scope, controller))\n .then(function(values) {\n if(!angular.isArray(values)) {\n values = [];\n }\n $parseOptions.$values = values.length ? parseValues(values, scope) : [];\n return $parseOptions.$values;\n });\n };\n\n $parseOptions.displayValue = function(modelValue) {\n var scope = {};\n scope[valueName] = modelValue;\n return displayFn(scope);\n };\n\n // Private functions\n\n function parseValues(values, scope) {\n return values.map(function(match, index) {\n var locals = {}, label, value;\n locals[valueName] = match;\n label = displayFn(scope, locals);\n value = valueFn(scope, locals);\n return {label: label, value: value, index: index};\n });\n }\n\n $parseOptions.init();\n return $parseOptions;\n\n }\n\n return ParseOptionsFactory;\n\n };\n\n });\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/dist/modules/popover.js b/dist/modules/popover.js index 14e58724c..7cb23ad79 100644 --- a/dist/modules/popover.js +++ b/dist/modules/popover.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/popover.min.js b/dist/modules/popover.min.js index 77b2e76ac..e4a41c975 100644 --- a/dist/modules/popover.min.js +++ b/dist/modules/popover.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/popover.tpl.js b/dist/modules/popover.tpl.js index 1d08ab554..de0a6ec15 100644 --- a/dist/modules/popover.tpl.js +++ b/dist/modules/popover.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @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 6d2296df2..b24ee1ef9 100644 --- a/dist/modules/popover.tpl.min.js +++ b/dist/modules/popover.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/raf.js b/dist/modules/raf.js index b4ad3d602..d9c31f8f2 100644 --- a/dist/modules/raf.js +++ b/dist/modules/raf.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/raf.min.js b/dist/modules/raf.min.js index b4f495e05..770cf34a4 100644 --- a/dist/modules/raf.min.js +++ b/dist/modules/raf.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/scrollspy.js b/dist/modules/scrollspy.js index 36cf23630..45c450502 100644 --- a/dist/modules/scrollspy.js +++ b/dist/modules/scrollspy.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/scrollspy.min.js b/dist/modules/scrollspy.min.js index 81a3d1479..db722bff0 100644 --- a/dist/modules/scrollspy.min.js +++ b/dist/modules/scrollspy.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/select.js b/dist/modules/select.js index 16906c52b..55cdf40db 100644 --- a/dist/modules/select.js +++ b/dist/modules/select.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/select.min.js b/dist/modules/select.min.js index c96477061..6210bcc42 100644 --- a/dist/modules/select.min.js +++ b/dist/modules/select.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/select.tpl.js b/dist/modules/select.tpl.js index 056d4843a..a2df3a17f 100644 --- a/dist/modules/select.tpl.js +++ b/dist/modules/select.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @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 987329071..34108a13d 100644 --- a/dist/modules/select.tpl.min.js +++ b/dist/modules/select.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/tab.js b/dist/modules/tab.js index 2c162bcf3..5031b931f 100644 --- a/dist/modules/tab.js +++ b/dist/modules/tab.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/tab.min.js b/dist/modules/tab.min.js index 028acac79..b184a3dac 100644 --- a/dist/modules/tab.min.js +++ b/dist/modules/tab.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/tab.tpl.js b/dist/modules/tab.tpl.js index 961416e64..34e0f02d4 100644 --- a/dist/modules/tab.tpl.js +++ b/dist/modules/tab.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @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 4f8a372f8..29df73802 100644 --- a/dist/modules/tab.tpl.min.js +++ b/dist/modules/tab.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/timepicker.js b/dist/modules/timepicker.js index 3c35367c8..afd4940d8 100644 --- a/dist/modules/timepicker.js +++ b/dist/modules/timepicker.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -36,10 +36,11 @@ angular.module('mgcrea.ngStrap.timepicker', [ 'mgcrea.ngStrap.helpers.dateParser arrowBehavior: 'pager' }; 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)/gi.test($window.navigator.userAgent); var isTouch = 'createTouch' in $window.document && isNative; - if (!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale(); + if (!defaults.lang) { + defaults.lang = $dateFormatter.getDefaultLocale(); + } function timepickerFactory(element, controller, config) { var $timepicker = $tooltip(element, angular.extend({}, defaults, config)); var parentScope = config.scope; @@ -186,10 +187,10 @@ angular.module('mgcrea.ngStrap.timepicker', [ 'mgcrea.ngStrap.helpers.dateParser } }; $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; - var seconds = newDate.getSeconds(), secondsLength = formatDate(newDate, secondsFormat).length; + var newDate = new Date($timepicker.$date || startDate); + var hours = newDate.getHours(); + var minutes = newDate.getMinutes(); + var seconds = newDate.getSeconds(); if (index === 0) { newDate.setHours(hours - parseInt(options.hourStep, 10) * value); } else if (index === 1) { @@ -234,7 +235,10 @@ angular.module('mgcrea.ngStrap.timepicker', [ 'mgcrea.ngStrap.helpers.dateParser if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return; evt.preventDefault(); evt.stopPropagation(); - if (evt.keyCode === 13) return $timepicker.hide(true); + if (evt.keyCode === 13) { + $timepicker.hide(true); + return; + } var newDate = new Date($timepicker.$date); var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length; var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length; @@ -311,6 +315,7 @@ angular.module('mgcrea.ngStrap.timepicker', [ 'mgcrea.ngStrap.helpers.dateParser }; var _show = $timepicker.show; $timepicker.show = function() { + if (!isTouch && element.attr('readonly') || element.attr('disabled')) return; _show(); $timeout(function() { $timepicker.$element && $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown); @@ -336,7 +341,6 @@ angular.module('mgcrea.ngStrap.timepicker', [ 'mgcrea.ngStrap.helpers.dateParser }).directive('bsTimepicker', [ '$window', '$parse', '$q', '$dateFormatter', '$dateParser', '$timepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) { var defaults = $timepicker.defaults; var isNative = /(ip(a|o)d|iphone|android)/gi.test($window.navigator.userAgent); - var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout; return { restrict: 'EAC', require: 'ngModel', @@ -399,7 +403,7 @@ angular.module('mgcrea.ngStrap.timepicker', [ 'mgcrea.ngStrap.helpers.dateParser var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue); if (!parsedTime || isNaN(parsedTime.getTime())) { controller.$setValidity('date', false); - return; + return undefined; } else { validateAgainstMinMaxTime(parsedTime); } diff --git a/dist/modules/timepicker.min.js b/dist/modules/timepicker.min.js index af28bff2d..64f193ed4 100644 --- a/dist/modules/timepicker.min.js +++ b/dist/modules/timepicker.min.js @@ -1,9 +1,9 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT */ -'use strict';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',templateUrl:'timepicker/timepicker.tpl.html',trigger:'focus',container:!1,keyboard:!0,html:!1,delay:0,useNative:!0,timeType:'date',timeFormat:'shortTime',timezone:null,modelTimeFormat:null,autoclose:!1,minTime:-(1/0),maxTime:+(1/0),length:5,hourStep:1,minuteStep:5,secondStep:5,roundDisplay:!1,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,i,o,r,s){function u(t,n,a){function i(e){var t=6e4*p.minuteStep;return new Date(Math.floor(e.getTime()/t)*t)}function u(e,n){var a=e+n;if(t[0].createTextRange){var i=t[0].createTextRange();i.collapse(!0),i.moveStart('character',e),i.moveEnd('character',a),i.select()}else t[0].setSelectionRange?t[0].setSelectionRange(e,a):angular.isUndefined(t[0].selectionStart)&&(t[0].selectionStart=e,t[0].selectionEnd=a)}function c(){t[0].focus()}var m=r(t,angular.extend({},e,a)),g=a.scope,p=m.$options,$=m.$scope,f=p.lang,h=function(e,t,n){return o.formatDate(e,t,f,n)},v=0,w=p.roundDisplay?i(new Date):new Date,S=n.$dateValue||w,y={hour:S.getHours(),meridian:S.getHours()<12,minute:S.getMinutes(),second:S.getSeconds(),millisecond:S.getMilliseconds()},D=o.getDatetimeFormat(p.timeFormat,f),T=o.hoursFormat(D),V=o.timeSeparator(D),b=o.minutesFormat(D),k=o.secondsFormat(D),M=o.showSeconds(D),x=o.showAM(D);$.$iconUp=p.iconUp,$.$iconDown=p.iconDown,$.$select=function(e,t){m.select(e,t)},$.$moveIndex=function(e,t){m.$moveIndex(e,t)},$.$switchMeridian=function(e){m.switchMeridian(e)},m.update=function(e){angular.isDate(e)&&!isNaN(e.getTime())?(m.$date=e,angular.extend(y,{hour:e.getHours(),minute:e.getMinutes(),second:e.getSeconds(),millisecond:e.getMilliseconds()}),m.$build()):m.$isBuilt||m.$build()},m.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()):2===t&&n.$dateValue.setSeconds(e.getSeconds()),n.$setViewValue(angular.copy(n.$dateValue)),n.$render(),p.autoclose&&!a&&s(function(){m.hide(!0)})},m.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()}},m.$build=function(){var e,t,n=$.midIndex=parseInt(p.length/2,10),a=[];for(e=0;e1*p.maxTime},$.$arrowAction=function(e,t){'picker'===p.arrowBehavior?m.$setTimeByStep(e,t):m.$moveIndex(e,t)},m.$setTimeByStep=function(e,t){{var n=new Date(m.$date),a=n.getHours(),i=(h(n,T).length,n.getMinutes()),o=(h(n,b).length,n.getSeconds());h(n,k).length}0===t?n.setHours(a-parseInt(p.hourStep,10)*e):1===t?n.setMinutes(i-parseInt(p.minuteStep,10)*e):2===t&&n.setSeconds(o-parseInt(p.secondStep,10)*e),m.select(n,t,!0)},m.$moveIndex=function(e,t){var n;0===t?(n=new Date(1970,0,1,y.hour+e*p.length,y.minute,y.second),angular.extend(y,{hour:n.getHours()})):1===t?(n=new Date(1970,0,1,y.hour,y.minute+e*p.length*p.minuteStep,y.second),angular.extend(y,{minute:n.getMinutes()})):2===t&&(n=new Date(1970,0,1,y.hour,y.minute,y.second+e*p.length*p.secondStep),angular.extend(y,{second:n.getSeconds()})),m.$build()},m.$onMouseDown=function(e){if('input'!==e.target.nodeName.toLowerCase()&&e.preventDefault(),e.stopPropagation(),d){var t=angular.element(e.target);'button'!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler('click')}},m.$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 m.hide(!0);var t=new Date(m.$date),n=t.getHours(),a=h(t,T).length,i=t.getMinutes(),o=h(t,b).length,r=t.getSeconds(),s=h(t,k).length,l=1,d=/(37|39)/.test(e.keyCode),c=2+1*M+1*x;d&&(37===e.keyCode?v=1>v?c-1:v-1:39===e.keyCode&&(v=c-1>v?v+1:0));var $=[0,a],f=0;38===e.keyCode&&(f=-1),40===e.keyCode&&(f=1);var w=2===v&&M,S=2===v&&!M||3===v&&M;0===v?(t.setHours(n+f*parseInt(p.hourStep,10)),a=h(t,T).length,$=[0,a]):1===v?(t.setMinutes(i+f*parseInt(p.minuteStep,10)),o=h(t,b).length,$=[a+l,o]):w?(t.setSeconds(r+f*parseInt(p.secondStep,10)),s=h(t,k).length,$=[a+l+o+l,s]):S&&(d||m.switchMeridian(),$=[a+l+o+l+(s+l)*M,2]),m.select(t,v,!0),u($[0],$[1]),g.$digest()}};var N=m.init;m.init=function(){return l&&p.useNative?(t.prop('type','time'),void t.css('-webkit-appearance','textfield')):(d&&(t.prop('type','text'),t.attr('readonly','true'),t.on('click',c)),void N())};var F=m.destroy;m.destroy=function(){l&&p.useNative&&t.off('click',c),F()};var H=m.show;m.show=function(){H(),s(function(){m.$element&&m.$element.on(d?'touchstart':'mousedown',m.$onMouseDown),p.keyboard&&t&&t.on('keydown',m.$onKeyDown)},0,!1)};var A=m.hide;return m.hide=function(e){m.$isShown&&(m.$element&&m.$element.off(d?'touchstart':'mousedown',m.$onMouseDown),p.keyboard&&t&&t.off('keydown',m.$onKeyDown),A(e))},m}var l=(angular.element(t.document.body),/(ip(a|o)d|iphone|android)/gi.test(t.navigator.userAgent)),d='createTouch'in t.document&&l;return e.lang||(e.lang=o.getDefaultLocale()),u.defaults=e,u}]}).directive('bsTimepicker',['$window','$parse','$q','$dateFormatter','$dateParser','$timepicker',function(e,t,n,a,i,o){{var r=o.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,u){function l(e){if(angular.isDate(e)){var t=isNaN(c.minTime)||new Date(e.getTime()).setFullYear(1970,0,1)>=c.minTime,n=isNaN(c.maxTime)||new Date(e.getTime()).setFullYear(1970,0,1)<=c.maxTime,a=t&&n;u.$setValidity('date',a),u.$setValidity('min',t),u.$setValidity('max',n),a&&(u.$dateValue=e)}}function d(){return!u.$dateValue||isNaN(u.$dateValue.getTime())?'':$(u.$dateValue,c.timeFormat)}var c={scope:e};angular.forEach(['template','templateUrl','controller','controllerAs','placement','container','delay','trigger','keyboard','html','animation','autoclose','timeType','timeFormat','timezone','modelTimeFormat','useNative','hourStep','minuteStep','secondStep','length','arrowBehavior','iconUp','iconDown','roundDisplay','id','prefixClass','prefixEvent'],function(e){angular.isDefined(n[e])&&(c[e]=n[e])});var m=/^(false|0|)$/i;angular.forEach(['html','container','autoclose','useNative','roundDisplay'],function(e){angular.isDefined(n[e])&&m.test(n[e])&&(c[e]=!1)}),n.bsShow&&e.$watch(n.bsShow,function(e,t){g&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(timepicker),?/i)),e===!0?g.show():g.hide())}),s&&(c.useNative||r.useNative)&&(c.timeFormat='HH:mm');var g=o(t,u,c);c=g.$options;var p=c.lang,$=function(e,t,n){return a.formatDate(e,t,p,n)},f=i({format:c.timeFormat,lang:p});angular.forEach(['minTime','maxTime'],function(e){angular.isDefined(n[e])&&n.$observe(e,function(t){g.$options[e]=f.getTimeForAttribute(e,t),!isNaN(g.$options[e])&&g.$build(),l(u.$dateValue)})}),e.$watch(n.ngModel,function(e,t){g.update(u.$dateValue)},!0),u.$parsers.unshift(function(e){var t;if(!e)return u.$setValidity('date',!0),null;var n=angular.isDate(e)?e:f.parse(e,u.$dateValue);return!n||isNaN(n.getTime())?void u.$setValidity('date',!1):(l(n),'string'===c.timeType?(t=f.timezoneOffsetAdjust(n,c.timezone,!0),$(t,c.modelTimeFormat||c.timeFormat)):(t=f.timezoneOffsetAdjust(u.$dateValue,c.timezone,!0),'number'===c.timeType?t.getTime():'unix'===c.timeType?t.getTime()/1e3:'iso'===c.timeType?t.toISOString():new Date(t)))}),u.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:'string'===c.timeType?f.parse(e,null,c.modelTimeFormat):new Date('unix'===c.timeType?1e3*e:e),u.$dateValue=f.timezoneOffsetAdjust(t,c.timezone),d()}),u.$render=function(){t.val(d())},e.$on('$destroy',function(){g&&g.destroy(),c=null,g=null})}}}]); +'use strict';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',templateUrl:'timepicker/timepicker.tpl.html',trigger:'focus',container:!1,keyboard:!0,html:!1,delay:0,useNative:!0,timeType:'date',timeFormat:'shortTime',timezone:null,modelTimeFormat:null,autoclose:!1,minTime:-(1/0),maxTime:+(1/0),length:5,hourStep:1,minuteStep:5,secondStep:5,roundDisplay:!1,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,i,o,r,s){function u(t,n,a){function i(e){var t=6e4*p.minuteStep;return new Date(Math.floor(e.getTime()/t)*t)}function u(e,n){var a=e+n;if(t[0].createTextRange){var i=t[0].createTextRange();i.collapse(!0),i.moveStart('character',e),i.moveEnd('character',a),i.select()}else t[0].setSelectionRange?t[0].setSelectionRange(e,a):angular.isUndefined(t[0].selectionStart)&&(t[0].selectionStart=e,t[0].selectionEnd=a)}function c(){t[0].focus()}var m=r(t,angular.extend({},e,a)),g=a.scope,p=m.$options,$=m.$scope,f=p.lang,h=function(e,t,n){return o.formatDate(e,t,f,n)},v=0,w=p.roundDisplay?i(new Date):new Date,S=n.$dateValue||w,y={hour:S.getHours(),meridian:S.getHours()<12,minute:S.getMinutes(),second:S.getSeconds(),millisecond:S.getMilliseconds()},D=o.getDatetimeFormat(p.timeFormat,f),T=o.hoursFormat(D),V=o.timeSeparator(D),b=o.minutesFormat(D),k=o.secondsFormat(D),M=o.showSeconds(D),x=o.showAM(D);$.$iconUp=p.iconUp,$.$iconDown=p.iconDown,$.$select=function(e,t){m.select(e,t)},$.$moveIndex=function(e,t){m.$moveIndex(e,t)},$.$switchMeridian=function(e){m.switchMeridian(e)},m.update=function(e){angular.isDate(e)&&!isNaN(e.getTime())?(m.$date=e,angular.extend(y,{hour:e.getHours(),minute:e.getMinutes(),second:e.getSeconds(),millisecond:e.getMilliseconds()}),m.$build()):m.$isBuilt||m.$build()},m.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()):2===t&&n.$dateValue.setSeconds(e.getSeconds()),n.$setViewValue(angular.copy(n.$dateValue)),n.$render(),p.autoclose&&!a&&s(function(){m.hide(!0)})},m.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()}},m.$build=function(){var e,t,n=$.midIndex=parseInt(p.length/2,10),a=[];for(e=0;e1*p.maxTime},$.$arrowAction=function(e,t){'picker'===p.arrowBehavior?m.$setTimeByStep(e,t):m.$moveIndex(e,t)},m.$setTimeByStep=function(e,t){var n=new Date(m.$date||S),a=n.getHours(),i=n.getMinutes(),o=n.getSeconds();0===t?n.setHours(a-parseInt(p.hourStep,10)*e):1===t?n.setMinutes(i-parseInt(p.minuteStep,10)*e):2===t&&n.setSeconds(o-parseInt(p.secondStep,10)*e),m.select(n,t,!0)},m.$moveIndex=function(e,t){var n;0===t?(n=new Date(1970,0,1,y.hour+e*p.length,y.minute,y.second),angular.extend(y,{hour:n.getHours()})):1===t?(n=new Date(1970,0,1,y.hour,y.minute+e*p.length*p.minuteStep,y.second),angular.extend(y,{minute:n.getMinutes()})):2===t&&(n=new Date(1970,0,1,y.hour,y.minute,y.second+e*p.length*p.secondStep),angular.extend(y,{second:n.getSeconds()})),m.$build()},m.$onMouseDown=function(e){if('input'!==e.target.nodeName.toLowerCase()&&e.preventDefault(),e.stopPropagation(),d){var t=angular.element(e.target);'button'!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler('click')}},m.$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 void m.hide(!0);var t=new Date(m.$date),n=t.getHours(),a=h(t,T).length,i=t.getMinutes(),o=h(t,b).length,r=t.getSeconds(),s=h(t,k).length,l=1,d=/(37|39)/.test(e.keyCode),c=2+1*M+1*x;d&&(37===e.keyCode?v=1>v?c-1:v-1:39===e.keyCode&&(v=c-1>v?v+1:0));var $=[0,a],f=0;38===e.keyCode&&(f=-1),40===e.keyCode&&(f=1);var w=2===v&&M,S=2===v&&!M||3===v&&M;0===v?(t.setHours(n+f*parseInt(p.hourStep,10)),a=h(t,T).length,$=[0,a]):1===v?(t.setMinutes(i+f*parseInt(p.minuteStep,10)),o=h(t,b).length,$=[a+l,o]):w?(t.setSeconds(r+f*parseInt(p.secondStep,10)),s=h(t,k).length,$=[a+l+o+l,s]):S&&(d||m.switchMeridian(),$=[a+l+o+l+(s+l)*M,2]),m.select(t,v,!0),u($[0],$[1]),g.$digest()}};var N=m.init;m.init=function(){return l&&p.useNative?(t.prop('type','time'),void t.css('-webkit-appearance','textfield')):(d&&(t.prop('type','text'),t.attr('readonly','true'),t.on('click',c)),void N())};var F=m.destroy;m.destroy=function(){l&&p.useNative&&t.off('click',c),F()};var H=m.show;m.show=function(){!d&&t.attr('readonly')||t.attr('disabled')||(H(),s(function(){m.$element&&m.$element.on(d?'touchstart':'mousedown',m.$onMouseDown),p.keyboard&&t&&t.on('keydown',m.$onKeyDown)},0,!1))};var I=m.hide;return m.hide=function(e){m.$isShown&&(m.$element&&m.$element.off(d?'touchstart':'mousedown',m.$onMouseDown),p.keyboard&&t&&t.off('keydown',m.$onKeyDown),I(e))},m}var l=/(ip(a|o)d|iphone|android)/gi.test(t.navigator.userAgent),d='createTouch'in t.document&&l;return e.lang||(e.lang=o.getDefaultLocale()),u.defaults=e,u}]}).directive('bsTimepicker',['$window','$parse','$q','$dateFormatter','$dateParser','$timepicker',function(e,t,n,a,i,o){var r=o.defaults,s=/(ip(a|o)d|iphone|android)/gi.test(e.navigator.userAgent);return{restrict:'EAC',require:'ngModel',link:function(e,t,n,u){function l(e){if(angular.isDate(e)){var t=isNaN(c.minTime)||new Date(e.getTime()).setFullYear(1970,0,1)>=c.minTime,n=isNaN(c.maxTime)||new Date(e.getTime()).setFullYear(1970,0,1)<=c.maxTime,a=t&&n;u.$setValidity('date',a),u.$setValidity('min',t),u.$setValidity('max',n),a&&(u.$dateValue=e)}}function d(){return!u.$dateValue||isNaN(u.$dateValue.getTime())?'':$(u.$dateValue,c.timeFormat)}var c={scope:e};angular.forEach(['template','templateUrl','controller','controllerAs','placement','container','delay','trigger','keyboard','html','animation','autoclose','timeType','timeFormat','timezone','modelTimeFormat','useNative','hourStep','minuteStep','secondStep','length','arrowBehavior','iconUp','iconDown','roundDisplay','id','prefixClass','prefixEvent'],function(e){angular.isDefined(n[e])&&(c[e]=n[e])});var m=/^(false|0|)$/i;angular.forEach(['html','container','autoclose','useNative','roundDisplay'],function(e){angular.isDefined(n[e])&&m.test(n[e])&&(c[e]=!1)}),n.bsShow&&e.$watch(n.bsShow,function(e,t){g&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(timepicker),?/i)),e===!0?g.show():g.hide())}),s&&(c.useNative||r.useNative)&&(c.timeFormat='HH:mm');var g=o(t,u,c);c=g.$options;var p=c.lang,$=function(e,t,n){return a.formatDate(e,t,p,n)},f=i({format:c.timeFormat,lang:p});angular.forEach(['minTime','maxTime'],function(e){angular.isDefined(n[e])&&n.$observe(e,function(t){g.$options[e]=f.getTimeForAttribute(e,t),!isNaN(g.$options[e])&&g.$build(),l(u.$dateValue)})}),e.$watch(n.ngModel,function(e,t){g.update(u.$dateValue)},!0),u.$parsers.unshift(function(e){var t;if(!e)return u.$setValidity('date',!0),null;var n=angular.isDate(e)?e:f.parse(e,u.$dateValue);return!n||isNaN(n.getTime())?void u.$setValidity('date',!1):(l(n),'string'===c.timeType?(t=f.timezoneOffsetAdjust(n,c.timezone,!0),$(t,c.modelTimeFormat||c.timeFormat)):(t=f.timezoneOffsetAdjust(u.$dateValue,c.timezone,!0),'number'===c.timeType?t.getTime():'unix'===c.timeType?t.getTime()/1e3:'iso'===c.timeType?t.toISOString():new Date(t)))}),u.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:'string'===c.timeType?f.parse(e,null,c.modelTimeFormat):new Date('unix'===c.timeType?1e3*e:e),u.$dateValue=f.timezoneOffsetAdjust(t,c.timezone),d()}),u.$render=function(){t.val(d())},e.$on('$destroy',function(){g&&g.destroy(),c=null,g=null})}}}]); //# sourceMappingURL=../modules/timepicker.min.js.map \ No newline at end of file diff --git a/dist/modules/timepicker.min.js.map b/dist/modules/timepicker.min.js.map index 0e9437a81..81fc8e160 100644 --- a/dist/modules/timepicker.min.js.map +++ b/dist/modules/timepicker.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["modules/timepicker.js"],"names":["angular","container","provider","keyboard","this","defaults","html","delay","useNative","timeType","timeFormat","timezone","modelTimeFormat","autoclose","minTime","maxTime","Infinity","length","hourStep","minuteStep","secondStep","roundDisplay","iconUp","iconDown","arrowBehavior","bodyEl","isNative","isTouch","timepickerFactory","$get","parentScope","config","scope","formatDate","format","viewDate","hour","startDate","getHours","meridian","coeff","selRange","select","end","start","element","setSelectionRange","isUndefined","collapse","selectionStart","moveStart","selectionEnd","moveEnd","focusElement","focus","_init","$timepicker","init","$tooltip","extend","floorMinutes","time","options","floor","lang","selectedIndex","date","defaultDate","second","getSeconds","millisecond","getMilliseconds","controller","$dateValue","hoursFormat","$dateFormatter","$iconUp","$iconDown","$select","$moveIndex","value","index","$switchMeridian","switchMeridian","isDate","isNaN","getMinutes","getTime","$build","minute","$setViewValue","$timeout","keep","hide","Date","setHours","setMinutes","setSeconds","copy","$render","hours","midIndex","push","label","selected","$isSelected","disabled","i","minutes","seconds","minutesFormat","rows","showSeconds","secondsFormat","$isDisabled","showAM","timeSeparator","$date","isAM","selectedTime","$arrowAction","$setTimeByStep","newDate","hoursLength","parseInt","targetDate","$onMouseDown","evt","target","nodeName","stopPropagation","targetEl","triggerHandler","preventDefault","$onKeyDown","test","keyCode","secondsLength","sepLength","lateralMove","count","minutesLength","selectRange","incr","isSeconds","isMeridian","createSelection","$digest","createTextRange","prop","attr","_destroy","destroy","off","_show","show","_hide","blur","$element","directive","$options","$scope","restrict","$window","requestAnimationFrame","setTimeout","require","link","falseValueRegExp","isMaxValid","isValid","parsedTime","isMinValid","setFullYear","$setValidity","$parsers","unshift","viewValue","getTimeFormattedString","bsShow","newValue","oldValue","timepicker","isDefined","key","forEach","dateParser","$dateParser","$observe","validateAgainstMinMaxTime","$watch","ngModel","getTimeForAttribute","parse","timezoneOffsetAdjust","$formatters","modelValue","NaN","$on"],"mappings":"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","file":"modules/timepicker.min.js","sourcesContent":["'use strict';\n\nangular.module('mgcrea.ngStrap.timepicker', [\n 'mgcrea.ngStrap.helpers.dateParser',\n 'mgcrea.ngStrap.helpers.dateFormatter',\n 'mgcrea.ngStrap.tooltip'])\n\n .provider('$timepicker', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n //uncommenting the following line will break backwards compatability\n // prefixEvent: 'timepicker',\n prefixClass: 'timepicker',\n placement: 'bottom-left',\n templateUrl: 'timepicker/timepicker.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n // lang: $locale.id,\n useNative: true,\n timeType: 'date',\n timeFormat: 'shortTime',\n timezone: null,\n modelTimeFormat: null,\n autoclose: false,\n minTime: -Infinity,\n maxTime: +Infinity,\n length: 5,\n hourStep: 1,\n minuteStep: 5,\n secondStep: 5,\n roundDisplay: false,\n iconUp: 'glyphicon glyphicon-chevron-up',\n iconDown: 'glyphicon glyphicon-chevron-down',\n arrowBehavior: 'pager'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\n\n function timepickerFactory(element, controller, config) {\n\n var $timepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $timepicker.$options;\n var scope = $timepicker.$scope;\n\n var lang = options.lang;\n var formatDate = function(date, format, timezone) {\n return $dateFormatter.formatDate(date, format, lang, timezone);\n };\n\n function floorMinutes(time)\n {\n // coeff used to floor current time to nearest minuteStep interval\n var coeff = 1000 * 60 * options.minuteStep;\n return new Date(Math.floor(time.getTime() / coeff) * coeff);\n }\n\n // View vars\n\n var selectedIndex = 0;\n var defaultDate = options.roundDisplay ? floorMinutes(new Date()) : new Date();\n var startDate = controller.$dateValue || defaultDate;\n var viewDate = {hour: startDate.getHours(), meridian: startDate.getHours() < 12, minute: startDate.getMinutes(), second: startDate.getSeconds(), millisecond: startDate.getMilliseconds()};\n\n var format = $dateFormatter.getDatetimeFormat(options.timeFormat, lang);\n\n var hoursFormat = $dateFormatter.hoursFormat(format),\n timeSeparator = $dateFormatter.timeSeparator(format),\n minutesFormat = $dateFormatter.minutesFormat(format),\n secondsFormat = $dateFormatter.secondsFormat(format),\n showSeconds = $dateFormatter.showSeconds(format),\n showAM = $dateFormatter.showAM(format);\n\n scope.$iconUp = options.iconUp;\n scope.$iconDown = options.iconDown;\n\n // Scope methods\n\n scope.$select = function(date, index) {\n $timepicker.select(date, index);\n };\n scope.$moveIndex = function(value, index) {\n $timepicker.$moveIndex(value, index);\n };\n scope.$switchMeridian = function(date) {\n $timepicker.switchMeridian(date);\n };\n\n // Public methods\n\n $timepicker.update = function(date) {\n // console.warn('$timepicker.update() newValue=%o', date);\n if(angular.isDate(date) && !isNaN(date.getTime())) {\n $timepicker.$date = date;\n angular.extend(viewDate, {hour: date.getHours(), minute: date.getMinutes(), second: date.getSeconds(), millisecond: date.getMilliseconds()});\n $timepicker.$build();\n } else if(!$timepicker.$isBuilt) {\n $timepicker.$build();\n }\n };\n\n $timepicker.select = function(date, index, keep) {\n // console.warn('$timepicker.select', date, scope.$mode);\n if(!controller.$dateValue || isNaN(controller.$dateValue.getTime())) controller.$dateValue = new Date(1970, 0, 1);\n if(!angular.isDate(date)) date = new Date(date);\n if(index === 0) controller.$dateValue.setHours(date.getHours());\n else if(index === 1) controller.$dateValue.setMinutes(date.getMinutes());\n else if(index === 2) controller.$dateValue.setSeconds(date.getSeconds());\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n if(options.autoclose && !keep) {\n $timeout(function() { $timepicker.hide(true); });\n }\n };\n\n $timepicker.switchMeridian = function(date) {\n if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) {\n return;\n }\n var hours = (date || controller.$dateValue).getHours();\n controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12);\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n };\n\n // Protected methods\n\n $timepicker.$build = function() {\n // console.warn('$timepicker.$build() viewDate=%o', viewDate);\n var i, midIndex = scope.midIndex = parseInt(options.length / 2, 10);\n var hours = [], hour;\n for(i = 0; i < options.length; i++) {\n hour = new Date(1970, 0, 1, viewDate.hour - (midIndex - i) * options.hourStep);\n hours.push({date: hour, label: formatDate(hour, hoursFormat), selected: $timepicker.$date && $timepicker.$isSelected(hour, 0), disabled: $timepicker.$isDisabled(hour, 0)});\n }\n var minutes = [], minute;\n for(i = 0; i < options.length; i++) {\n minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep);\n minutes.push({date: minute, label: formatDate(minute, minutesFormat), selected: $timepicker.$date && $timepicker.$isSelected(minute, 1), disabled: $timepicker.$isDisabled(minute, 1)});\n }\n var seconds = [], second;\n for(i = 0; i < options.length; i++) {\n second = new Date(1970, 0, 1, 0, 0, viewDate.second - (midIndex - i) * options.secondStep);\n seconds.push({date: second, label: formatDate(second, secondsFormat), selected: $timepicker.$date && $timepicker.$isSelected(second, 2), disabled: $timepicker.$isDisabled(second, 2)});\n }\n\n var rows = [];\n for(i = 0; i < options.length; i++) {\n if (showSeconds) {\n rows.push([hours[i], minutes[i], seconds[i]]);\n } else {\n rows.push([hours[i], minutes[i]]);\n }\n }\n scope.rows = rows;\n scope.showSeconds = showSeconds;\n scope.showAM = showAM;\n scope.isAM = ($timepicker.$date || hours[midIndex].date).getHours() < 12;\n scope.timeSeparator = timeSeparator;\n $timepicker.$isBuilt = true;\n };\n\n $timepicker.$isSelected = function(date, index) {\n if(!$timepicker.$date) return false;\n else if(index === 0) {\n return date.getHours() === $timepicker.$date.getHours();\n } else if(index === 1) {\n return date.getMinutes() === $timepicker.$date.getMinutes();\n } else if(index === 2) {\n return date.getSeconds() === $timepicker.$date.getSeconds();\n }\n };\n\n $timepicker.$isDisabled = function(date, index) {\n var selectedTime;\n if(index === 0) {\n selectedTime = date.getTime() + viewDate.minute * 6e4 + viewDate.second * 1e3;\n } else if(index === 1) {\n selectedTime = date.getTime() + viewDate.hour * 36e5 + viewDate.second * 1e3;\n } else if(index === 2) {\n selectedTime = date.getTime() + viewDate.hour * 36e5 + viewDate.minute * 6e4;\n }\n return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1;\n };\n\n scope.$arrowAction = function (value, index) {\n if (options.arrowBehavior === 'picker') {\n $timepicker.$setTimeByStep(value,index);\n } else {\n $timepicker.$moveIndex(value,index);\n }\n };\n\n $timepicker.$setTimeByStep = function(value, index) {\n var newDate = new Date($timepicker.$date);\n var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;\n var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;\n var seconds = newDate.getSeconds(), secondsLength = formatDate(newDate, secondsFormat).length;\n if (index === 0) {\n newDate.setHours(hours - (parseInt(options.hourStep, 10) * value));\n }\n else if (index === 1) {\n newDate.setMinutes(minutes - (parseInt(options.minuteStep, 10) * value));\n }\n else if (index === 2) {\n newDate.setSeconds(seconds - (parseInt(options.secondStep, 10) * value));\n }\n $timepicker.select(newDate, index, true);\n };\n\n $timepicker.$moveIndex = function(value, index) {\n var targetDate;\n if(index === 0) {\n targetDate = new Date(1970, 0, 1, viewDate.hour + (value * options.length), viewDate.minute, viewDate.second);\n angular.extend(viewDate, {hour: targetDate.getHours()});\n } else if(index === 1) {\n targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + (value * options.length * options.minuteStep), viewDate.second);\n angular.extend(viewDate, {minute: targetDate.getMinutes()});\n } else if(index === 2) {\n targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute, viewDate.second + (value * options.length * options.secondStep));\n angular.extend(viewDate, {second: targetDate.getSeconds()});\n }\n $timepicker.$build();\n };\n\n $timepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n if(evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $timepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // Close on enter\n if(evt.keyCode === 13) return $timepicker.hide(true);\n\n // Navigate with keyboard\n var newDate = new Date($timepicker.$date);\n var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;\n var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;\n var seconds = newDate.getSeconds(), secondsLength = formatDate(newDate, secondsFormat).length;\n var sepLength = 1;\n var lateralMove = /(37|39)/.test(evt.keyCode);\n var count = 2 + showSeconds * 1 + showAM * 1;\n\n // Navigate indexes (left, right)\n if (lateralMove) {\n if(evt.keyCode === 37) selectedIndex = selectedIndex < 1 ? count - 1 : selectedIndex - 1;\n else if(evt.keyCode === 39) selectedIndex = selectedIndex < count - 1 ? selectedIndex + 1 : 0;\n }\n\n // Update values (up, down)\n var selectRange = [0, hoursLength];\n var incr = 0;\n if (evt.keyCode === 38) incr = -1;\n if (evt.keyCode === 40) incr = +1;\n var isSeconds = selectedIndex === 2 && showSeconds;\n var isMeridian = selectedIndex === 2 && !showSeconds || selectedIndex === 3 && showSeconds;\n if(selectedIndex === 0) {\n newDate.setHours(hours + incr*parseInt(options.hourStep, 10));\n // re-calculate hours length because we have changed hours value\n hoursLength = formatDate(newDate, hoursFormat).length;\n selectRange = [0, hoursLength];\n } else if(selectedIndex === 1) {\n newDate.setMinutes(minutes + incr*parseInt(options.minuteStep, 10));\n // re-calculate minutes length because we have changes minutes value\n minutesLength = formatDate(newDate, minutesFormat).length;\n selectRange = [hoursLength + sepLength, minutesLength];\n } else if(isSeconds) {\n newDate.setSeconds(seconds + incr*parseInt(options.secondStep, 10));\n // re-calculate seconds length because we have changes seconds value\n secondsLength = formatDate(newDate, secondsFormat).length;\n selectRange = [hoursLength + sepLength + minutesLength + sepLength, secondsLength];\n } else if(isMeridian) {\n if(!lateralMove) $timepicker.switchMeridian();\n selectRange = [hoursLength + sepLength + minutesLength + sepLength + (secondsLength + sepLength)*showSeconds, 2];\n }\n $timepicker.select(newDate, selectedIndex, true);\n createSelection(selectRange[0], selectRange[1]);\n parentScope.$digest();\n };\n\n // Private\n\n function createSelection(start, length) {\n var end = start + length;\n if(element[0].createTextRange) {\n var selRange = element[0].createTextRange();\n selRange.collapse(true);\n selRange.moveStart('character', start);\n selRange.moveEnd('character', end);\n selRange.select();\n } else if(element[0].setSelectionRange) {\n element[0].setSelectionRange(start, end);\n } else if(angular.isUndefined(element[0].selectionStart)) {\n element[0].selectionStart = start;\n element[0].selectionEnd = end;\n }\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $timepicker.init;\n $timepicker.init = function() {\n if(isNative && options.useNative) {\n element.prop('type', 'time');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if(isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $timepicker.destroy;\n $timepicker.destroy = function() {\n if(isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $timepicker.show;\n $timepicker.show = function() {\n _show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n $timepicker.$element && $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if(options.keyboard) {\n element && element.on('keydown', $timepicker.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $timepicker.hide;\n $timepicker.hide = function(blur) {\n if(!$timepicker.$isShown) return;\n $timepicker.$element && $timepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if(options.keyboard) {\n element && element.off('keydown', $timepicker.$onKeyDown);\n }\n _hide(blur);\n };\n\n return $timepicker;\n\n }\n\n timepickerFactory.defaults = defaults;\n return timepickerFactory;\n\n };\n\n })\n\n\n .directive('bsTimepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) {\n\n var defaults = $timepicker.defaults;\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'autoclose', 'timeType', 'timeFormat', 'timezone', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'secondStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown', 'roundDisplay', 'id', 'prefixClass', 'prefixEvent'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'autoclose', 'useNative', 'roundDisplay'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!timepicker || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(timepicker),?/i);\n newValue === true ? timepicker.show() : timepicker.hide();\n });\n\n // Initialize timepicker\n if(isNative && (options.useNative || defaults.useNative)) options.timeFormat = 'HH:mm';\n var timepicker = $timepicker(element, controller, options);\n options = timepicker.$options;\n\n var lang = options.lang;\n var formatDate = function(date, format, timezone) {\n return $dateFormatter.formatDate(date, format, lang, timezone);\n };\n\n // Initialize parser\n var dateParser = $dateParser({format: options.timeFormat, lang: lang});\n\n // Observe attributes for changes\n angular.forEach(['minTime', 'maxTime'], function(key) {\n // console.warn('attr.$observe(%s)', key, attr[key]);\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\n timepicker.$options[key] = dateParser.getTimeForAttribute(key, newValue);\n !isNaN(timepicker.$options[key]) && timepicker.$build();\n validateAgainstMinMaxTime(controller.$dateValue);\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue, controller.$dateValue);\n timepicker.update(controller.$dateValue);\n }, true);\n\n function validateAgainstMinMaxTime(parsedTime) {\n if (!angular.isDate(parsedTime)) return;\n var isMinValid = isNaN(options.minTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) >= options.minTime;\n var isMaxValid = isNaN(options.maxTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) <= options.maxTime;\n var isValid = isMinValid && isMaxValid;\n controller.$setValidity('date', isValid);\n controller.$setValidity('min', isMinValid);\n controller.$setValidity('max', isMaxValid);\n // Only update the model when we have a valid date\n if(!isValid) {\n return;\n }\n controller.$dateValue = parsedTime;\n }\n\n // viewValue -> $parsers -> modelValue\n controller.$parsers.unshift(function(viewValue) {\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\n var date;\n // Null values should correctly reset the model value & validity\n if(!viewValue) {\n // BREAKING CHANGE:\n // return null (not undefined) when input value is empty, so angularjs 1.3\n // ngModelController can go ahead and run validators, like ngRequired\n controller.$setValidity('date', true);\n return null;\n }\n var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue);\n if(!parsedTime || isNaN(parsedTime.getTime())) {\n controller.$setValidity('date', false);\n // return undefined, causes ngModelController to\n // invalidate model value\n return;\n } else {\n validateAgainstMinMaxTime(parsedTime);\n }\n\n if(options.timeType === 'string') {\n date = dateParser.timezoneOffsetAdjust(parsedTime, options.timezone, true);\n return formatDate(date, options.modelTimeFormat || options.timeFormat);\n }\n date = dateParser.timezoneOffsetAdjust(controller.$dateValue, options.timezone, true);\n if(options.timeType === 'number') {\n return date.getTime();\n } else if(options.timeType === 'unix') {\n return date.getTime() / 1000;\n } else if(options.timeType === 'iso') {\n return date.toISOString();\n } else {\n return new Date(date);\n }\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var date;\n if(angular.isUndefined(modelValue) || modelValue === null) {\n date = NaN;\n } else if(angular.isDate(modelValue)) {\n date = modelValue;\n } else if(options.timeType === 'string') {\n date = dateParser.parse(modelValue, null, options.modelTimeFormat);\n } else if(options.timeType === 'unix') {\n date = new Date(modelValue * 1000);\n } else {\n date = new Date(modelValue);\n }\n // Setup default value?\n // if(isNaN(date.getTime())) date = new Date(new Date().setMinutes(0) + 36e5);\n controller.$dateValue = dateParser.timezoneOffsetAdjust(date, options.timezone);\n return getTimeFormattedString();\n });\n\n // viewValue -> element\n controller.$render = function() {\n // console.warn('$render(\"%s\"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);\n element.val(getTimeFormattedString());\n };\n\n function getTimeFormattedString() {\n return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat);\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (timepicker) timepicker.destroy();\n options = null;\n timepicker = null;\n });\n\n }\n };\n\n });\n"],"sourceRoot":"/source/"} \ No newline at end of file +{"version":3,"sources":["modules/timepicker.js"],"names":["angular","container","provider","keyboard","this","defaults","html","delay","useNative","timeType","timeFormat","timezone","modelTimeFormat","autoclose","minTime","maxTime","Infinity","length","hourStep","minuteStep","secondStep","roundDisplay","iconUp","iconDown","arrowBehavior","isNative","$get","$timepicker","$tooltip","element","extend","config","timepickerFactory","formatDate","format","viewDate","hour","startDate","getHours","meridian","coeff","selRange","select","end","start","setSelectionRange","isUndefined","collapse","selectionStart","moveStart","selectionEnd","moveEnd","focusElement","focus","_init","init","parentScope","floorMinutes","time","options","scope","floor","lang","selectedIndex","date","defaultDate","second","getSeconds","millisecond","getMilliseconds","controller","$dateValue","hoursFormat","$dateFormatter","$iconUp","$iconDown","$select","$moveIndex","value","index","$switchMeridian","switchMeridian","isDate","isNaN","getMinutes","getTime","$build","minute","$setViewValue","$timeout","keep","hide","Date","setHours","setMinutes","setSeconds","copy","$render","hours","midIndex","push","label","selected","$isSelected","disabled","i","minutes","seconds","minutesFormat","rows","showSeconds","secondsFormat","$isDisabled","showAM","timeSeparator","$date","isAM","selectedTime","$arrowAction","$setTimeByStep","newDate","parseInt","targetDate","$onMouseDown","evt","target","nodeName","stopPropagation","targetEl","triggerHandler","preventDefault","isTouch","$onKeyDown","test","keyCode","sepLength","lateralMove","count","minutesLength","selectRange","hoursLength","incr","isSeconds","isMeridian","secondsLength","createSelection","$digest","createTextRange","prop","attr","_destroy","destroy","off","_show","show","_hide","blur","$element","directive","$options","require","restrict","$window","navigator","userAgent","link","falseValueRegExp","isMaxValid","isValid","parsedTime","isMinValid","setFullYear","$setValidity","$parsers","unshift","viewValue","getTimeFormattedString","bsShow","newValue","oldValue","timepicker","isDefined","key","forEach","dateParser","$dateParser","$observe","validateAgainstMinMaxTime","$watch","ngModel","getTimeForAttribute","parse","timezoneOffsetAdjust","$formatters","modelValue","NaN","$on"],"mappings":"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","file":"modules/timepicker.min.js","sourcesContent":["'use strict';\n\nangular.module('mgcrea.ngStrap.timepicker', ['mgcrea.ngStrap.helpers.dateParser', 'mgcrea.ngStrap.helpers.dateFormatter', 'mgcrea.ngStrap.tooltip'])\n\n .provider('$timepicker', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n //uncommenting the following line will break backwards compatability\n // prefixEvent: 'timepicker',\n prefixClass: 'timepicker',\n placement: 'bottom-left',\n templateUrl: 'timepicker/timepicker.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n // lang: $locale.id,\n useNative: true,\n timeType: 'date',\n timeFormat: 'shortTime',\n timezone: null,\n modelTimeFormat: null,\n autoclose: false,\n minTime: -Infinity,\n maxTime: +Infinity,\n length: 5,\n hourStep: 1,\n minuteStep: 5,\n secondStep: 5,\n roundDisplay: false,\n iconUp: 'glyphicon glyphicon-chevron-up',\n iconDown: 'glyphicon glyphicon-chevron-down',\n arrowBehavior: 'pager'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) {\n\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if (!defaults.lang) {\n defaults.lang = $dateFormatter.getDefaultLocale();\n }\n\n function timepickerFactory(element, controller, config) {\n\n var $timepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $timepicker.$options;\n var scope = $timepicker.$scope;\n\n var lang = options.lang;\n var formatDate = function(date, format, timezone) {\n return $dateFormatter.formatDate(date, format, lang, timezone);\n };\n\n function floorMinutes(time) {\n // coeff used to floor current time to nearest minuteStep interval\n var coeff = 1000 * 60 * options.minuteStep;\n return new Date(Math.floor(time.getTime() / coeff) * coeff);\n }\n\n // View vars\n\n var selectedIndex = 0;\n var defaultDate = options.roundDisplay ? floorMinutes(new Date()) : new Date();\n var startDate = controller.$dateValue || defaultDate;\n var viewDate = {\n hour: startDate.getHours(),\n meridian: startDate.getHours() < 12,\n minute: startDate.getMinutes(),\n second: startDate.getSeconds(),\n millisecond: startDate.getMilliseconds()\n };\n\n var format = $dateFormatter.getDatetimeFormat(options.timeFormat, lang);\n\n var hoursFormat = $dateFormatter.hoursFormat(format),\n timeSeparator = $dateFormatter.timeSeparator(format),\n minutesFormat = $dateFormatter.minutesFormat(format),\n secondsFormat = $dateFormatter.secondsFormat(format),\n showSeconds = $dateFormatter.showSeconds(format),\n showAM = $dateFormatter.showAM(format);\n\n scope.$iconUp = options.iconUp;\n scope.$iconDown = options.iconDown;\n\n // Scope methods\n\n scope.$select = function(date, index) {\n $timepicker.select(date, index);\n };\n scope.$moveIndex = function(value, index) {\n $timepicker.$moveIndex(value, index);\n };\n scope.$switchMeridian = function(date) {\n $timepicker.switchMeridian(date);\n };\n\n // Public methods\n\n $timepicker.update = function(date) {\n // console.warn('$timepicker.update() newValue=%o', date);\n if (angular.isDate(date) && !isNaN(date.getTime())) {\n $timepicker.$date = date;\n angular.extend(viewDate, {\n hour: date.getHours(),\n minute: date.getMinutes(),\n second: date.getSeconds(),\n millisecond: date.getMilliseconds()\n });\n $timepicker.$build();\n } else if (!$timepicker.$isBuilt) {\n $timepicker.$build();\n }\n };\n\n $timepicker.select = function(date, index, keep) {\n // console.warn('$timepicker.select', date, scope.$mode);\n if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) controller.$dateValue = new Date(1970, 0, 1);\n if (!angular.isDate(date)) date = new Date(date);\n if (index === 0) controller.$dateValue.setHours(date.getHours());\n else if (index === 1) controller.$dateValue.setMinutes(date.getMinutes());\n else if (index === 2) controller.$dateValue.setSeconds(date.getSeconds());\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n if (options.autoclose && !keep) {\n $timeout(function() {\n $timepicker.hide(true);\n });\n }\n };\n\n $timepicker.switchMeridian = function(date) {\n if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) {\n return;\n }\n var hours = (date || controller.$dateValue).getHours();\n controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12);\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n };\n\n // Protected methods\n\n $timepicker.$build = function() {\n // console.warn('$timepicker.$build() viewDate=%o', viewDate);\n var i, midIndex = scope.midIndex = parseInt(options.length / 2, 10);\n var hours = [],\n hour;\n for (i = 0; i < options.length; i++) {\n hour = new Date(1970, 0, 1, viewDate.hour - (midIndex - i) * options.hourStep);\n hours.push({\n date: hour,\n label: formatDate(hour, hoursFormat),\n selected: $timepicker.$date && $timepicker.$isSelected(hour, 0),\n disabled: $timepicker.$isDisabled(hour, 0)\n });\n }\n var minutes = [],\n minute;\n for (i = 0; i < options.length; i++) {\n minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep);\n minutes.push({\n date: minute,\n label: formatDate(minute, minutesFormat),\n selected: $timepicker.$date && $timepicker.$isSelected(minute, 1),\n disabled: $timepicker.$isDisabled(minute, 1)\n });\n }\n var seconds = [],\n second;\n for (i = 0; i < options.length; i++) {\n second = new Date(1970, 0, 1, 0, 0, viewDate.second - (midIndex - i) * options.secondStep);\n seconds.push({\n date: second,\n label: formatDate(second, secondsFormat),\n selected: $timepicker.$date && $timepicker.$isSelected(second, 2),\n disabled: $timepicker.$isDisabled(second, 2)\n });\n }\n\n var rows = [];\n for (i = 0; i < options.length; i++) {\n if (showSeconds) {\n rows.push([hours[i], minutes[i], seconds[i]]);\n } else {\n rows.push([hours[i], minutes[i]]);\n }\n }\n scope.rows = rows;\n scope.showSeconds = showSeconds;\n scope.showAM = showAM;\n scope.isAM = ($timepicker.$date || hours[midIndex].date).getHours() < 12;\n scope.timeSeparator = timeSeparator;\n $timepicker.$isBuilt = true;\n };\n\n $timepicker.$isSelected = function(date, index) {\n if (!$timepicker.$date) return false;\n else if (index === 0) {\n return date.getHours() === $timepicker.$date.getHours();\n } else if (index === 1) {\n return date.getMinutes() === $timepicker.$date.getMinutes();\n } else if (index === 2) {\n return date.getSeconds() === $timepicker.$date.getSeconds();\n }\n };\n\n $timepicker.$isDisabled = function(date, index) {\n var selectedTime;\n if (index === 0) {\n selectedTime = date.getTime() + viewDate.minute * 6e4 + viewDate.second * 1e3;\n } else if (index === 1) {\n selectedTime = date.getTime() + viewDate.hour * 36e5 + viewDate.second * 1e3;\n } else if (index === 2) {\n selectedTime = date.getTime() + viewDate.hour * 36e5 + viewDate.minute * 6e4;\n }\n return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1;\n };\n\n scope.$arrowAction = function(value, index) {\n if (options.arrowBehavior === 'picker') {\n $timepicker.$setTimeByStep(value, index);\n } else {\n $timepicker.$moveIndex(value, index);\n }\n };\n\n $timepicker.$setTimeByStep = function(value, index) {\n var newDate = new Date($timepicker.$date || startDate);\n var hours = newDate.getHours();\n var minutes = newDate.getMinutes();\n var seconds = newDate.getSeconds();\n if (index === 0) {\n newDate.setHours(hours - (parseInt(options.hourStep, 10) * value));\n } else if (index === 1) {\n newDate.setMinutes(minutes - (parseInt(options.minuteStep, 10) * value));\n } else if (index === 2) {\n newDate.setSeconds(seconds - (parseInt(options.secondStep, 10) * value));\n }\n $timepicker.select(newDate, index, true);\n };\n\n $timepicker.$moveIndex = function(value, index) {\n var targetDate;\n if (index === 0) {\n targetDate = new Date(1970, 0, 1, viewDate.hour + (value * options.length), viewDate.minute, viewDate.second);\n angular.extend(viewDate, {\n hour: targetDate.getHours()\n });\n } else if (index === 1) {\n targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + (value * options.length * options.minuteStep), viewDate.second);\n angular.extend(viewDate, {\n minute: targetDate.getMinutes()\n });\n } else if (index === 2) {\n targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute, viewDate.second + (value * options.length * options.secondStep));\n angular.extend(viewDate, {\n second: targetDate.getSeconds()\n });\n }\n $timepicker.$build();\n };\n\n $timepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n if (evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if (isTouch) {\n var targetEl = angular.element(evt.target);\n if (targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $timepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // Close on enter\n if (evt.keyCode === 13) {\n $timepicker.hide(true);\n return;\n }\n\n // Navigate with keyboard\n var newDate = new Date($timepicker.$date);\n var hours = newDate.getHours(),\n hoursLength = formatDate(newDate, hoursFormat).length;\n var minutes = newDate.getMinutes(),\n minutesLength = formatDate(newDate, minutesFormat).length;\n var seconds = newDate.getSeconds(),\n secondsLength = formatDate(newDate, secondsFormat).length;\n var sepLength = 1;\n var lateralMove = /(37|39)/.test(evt.keyCode);\n var count = 2 + showSeconds * 1 + showAM * 1;\n\n // Navigate indexes (left, right)\n if (lateralMove) {\n if (evt.keyCode === 37) selectedIndex = selectedIndex < 1 ? count - 1 : selectedIndex - 1;\n else if (evt.keyCode === 39) selectedIndex = selectedIndex < count - 1 ? selectedIndex + 1 : 0;\n }\n\n // Update values (up, down)\n var selectRange = [0, hoursLength];\n var incr = 0;\n if (evt.keyCode === 38) incr = -1;\n if (evt.keyCode === 40) incr = +1;\n var isSeconds = selectedIndex === 2 && showSeconds;\n var isMeridian = selectedIndex === 2 && !showSeconds || selectedIndex === 3 && showSeconds;\n if (selectedIndex === 0) {\n newDate.setHours(hours + incr * parseInt(options.hourStep, 10));\n // re-calculate hours length because we have changed hours value\n hoursLength = formatDate(newDate, hoursFormat).length;\n selectRange = [0, hoursLength];\n } else if (selectedIndex === 1) {\n newDate.setMinutes(minutes + incr * parseInt(options.minuteStep, 10));\n // re-calculate minutes length because we have changes minutes value\n minutesLength = formatDate(newDate, minutesFormat).length;\n selectRange = [hoursLength + sepLength, minutesLength];\n } else if (isSeconds) {\n newDate.setSeconds(seconds + incr * parseInt(options.secondStep, 10));\n // re-calculate seconds length because we have changes seconds value\n secondsLength = formatDate(newDate, secondsFormat).length;\n selectRange = [hoursLength + sepLength + minutesLength + sepLength, secondsLength];\n } else if (isMeridian) {\n if (!lateralMove) $timepicker.switchMeridian();\n selectRange = [hoursLength + sepLength + minutesLength + sepLength + (secondsLength + sepLength) * showSeconds, 2];\n }\n $timepicker.select(newDate, selectedIndex, true);\n createSelection(selectRange[0], selectRange[1]);\n parentScope.$digest();\n };\n\n // Private\n\n function createSelection(start, length) {\n var end = start + length;\n if (element[0].createTextRange) {\n var selRange = element[0].createTextRange();\n selRange.collapse(true);\n selRange.moveStart('character', start);\n selRange.moveEnd('character', end);\n selRange.select();\n } else if (element[0].setSelectionRange) {\n element[0].setSelectionRange(start, end);\n } else if (angular.isUndefined(element[0].selectionStart)) {\n element[0].selectionStart = start;\n element[0].selectionEnd = end;\n }\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $timepicker.init;\n $timepicker.init = function() {\n if (isNative && options.useNative) {\n element.prop('type', 'time');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if (isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $timepicker.destroy;\n $timepicker.destroy = function() {\n if (isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $timepicker.show;\n $timepicker.show = function() {\n if((!isTouch && element.attr('readonly')) || element.attr('disabled')) return;\n _show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n $timepicker.$element && $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if (options.keyboard) {\n element && element.on('keydown', $timepicker.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $timepicker.hide;\n $timepicker.hide = function(blur) {\n if (!$timepicker.$isShown) return;\n $timepicker.$element && $timepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if (options.keyboard) {\n element && element.off('keydown', $timepicker.$onKeyDown);\n }\n _hide(blur);\n };\n\n return $timepicker;\n\n }\n\n timepickerFactory.defaults = defaults;\n return timepickerFactory;\n\n };\n\n })\n\n\n .directive('bsTimepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) {\n\n var defaults = $timepicker.defaults;\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {\n scope: scope\n };\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'autoclose', 'timeType', 'timeFormat', 'timezone', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'secondStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown', 'roundDisplay', 'id', 'prefixClass', 'prefixEvent'], function(key) {\n if (angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'autoclose', 'useNative', 'roundDisplay'], function(key) {\n if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if (!timepicker || !angular.isDefined(newValue)) return;\n if (angular.isString(newValue)) newValue = !!newValue.match(/true|,?(timepicker),?/i);\n newValue === true ? timepicker.show() : timepicker.hide();\n });\n\n // Initialize timepicker\n if (isNative && (options.useNative || defaults.useNative)) options.timeFormat = 'HH:mm';\n var timepicker = $timepicker(element, controller, options);\n options = timepicker.$options;\n\n var lang = options.lang;\n var formatDate = function(date, format, timezone) {\n return $dateFormatter.formatDate(date, format, lang, timezone);\n };\n\n // Initialize parser\n var dateParser = $dateParser({\n format: options.timeFormat,\n lang: lang\n });\n\n // Observe attributes for changes\n angular.forEach(['minTime', 'maxTime'], function(key) {\n // console.warn('attr.$observe(%s)', key, attr[key]);\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\n timepicker.$options[key] = dateParser.getTimeForAttribute(key, newValue);\n !isNaN(timepicker.$options[key]) && timepicker.$build();\n validateAgainstMinMaxTime(controller.$dateValue);\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue, controller.$dateValue);\n timepicker.update(controller.$dateValue);\n }, true);\n\n function validateAgainstMinMaxTime(parsedTime) {\n if (!angular.isDate(parsedTime)) return;\n var isMinValid = isNaN(options.minTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) >= options.minTime;\n var isMaxValid = isNaN(options.maxTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) <= options.maxTime;\n var isValid = isMinValid && isMaxValid;\n controller.$setValidity('date', isValid);\n controller.$setValidity('min', isMinValid);\n controller.$setValidity('max', isMaxValid);\n // Only update the model when we have a valid date\n if (!isValid) {\n return;\n }\n controller.$dateValue = parsedTime;\n }\n\n // viewValue -> $parsers -> modelValue\n controller.$parsers.unshift(function(viewValue) {\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\n var date;\n // Null values should correctly reset the model value & validity\n if (!viewValue) {\n // BREAKING CHANGE:\n // return null (not undefined) when input value is empty, so angularjs 1.3\n // ngModelController can go ahead and run validators, like ngRequired\n controller.$setValidity('date', true);\n return null;\n }\n var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue);\n if (!parsedTime || isNaN(parsedTime.getTime())) {\n controller.$setValidity('date', false);\n // Return undefined, causes ngModelController to\n // invalidate model value\n return undefined;\n } else {\n validateAgainstMinMaxTime(parsedTime);\n }\n\n if (options.timeType === 'string') {\n date = dateParser.timezoneOffsetAdjust(parsedTime, options.timezone, true);\n return formatDate(date, options.modelTimeFormat || options.timeFormat);\n }\n date = dateParser.timezoneOffsetAdjust(controller.$dateValue, options.timezone, true);\n if (options.timeType === 'number') {\n return date.getTime();\n } else if (options.timeType === 'unix') {\n return date.getTime() / 1000;\n } else if (options.timeType === 'iso') {\n return date.toISOString();\n } else {\n return new Date(date);\n }\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var date;\n if (angular.isUndefined(modelValue) || modelValue === null) {\n date = NaN;\n } else if (angular.isDate(modelValue)) {\n date = modelValue;\n } else if (options.timeType === 'string') {\n date = dateParser.parse(modelValue, null, options.modelTimeFormat);\n } else if (options.timeType === 'unix') {\n date = new Date(modelValue * 1000);\n } else {\n date = new Date(modelValue);\n }\n // Setup default value?\n // if(isNaN(date.getTime())) date = new Date(new Date().setMinutes(0) + 36e5);\n controller.$dateValue = dateParser.timezoneOffsetAdjust(date, options.timezone);\n return getTimeFormattedString();\n });\n\n // viewValue -> element\n controller.$render = function() {\n // console.warn('$render(\"%s\"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);\n element.val(getTimeFormattedString());\n };\n\n function getTimeFormattedString() {\n return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat);\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (timepicker) timepicker.destroy();\n options = null;\n timepicker = null;\n });\n\n }\n };\n\n });\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/dist/modules/timepicker.tpl.js b/dist/modules/timepicker.tpl.js index c00b3f27d..c52de12b4 100644 --- a/dist/modules/timepicker.tpl.js +++ b/dist/modules/timepicker.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @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 20ed3638e..d21aaec1a 100644 --- a/dist/modules/timepicker.tpl.min.js +++ b/dist/modules/timepicker.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/tooltip.js b/dist/modules/tooltip.js index e72591342..f3f9757a7 100644 --- a/dist/modules/tooltip.js +++ b/dist/modules/tooltip.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -239,18 +239,18 @@ angular.module('mgcrea.ngStrap.tooltip', [ 'mgcrea.ngStrap.core', 'mgcrea.ngStra } tipElement.addClass(options.placement); var elementPosition = getPosition(), tipWidth = tipElement.prop('offsetWidth'), tipHeight = tipElement.prop('offsetHeight'); + $tooltip.$viewport = options.viewport && findElement(options.viewport.selector || options.viewport); if (autoPlace) { var originalPlacement = placement; - var container = options.container ? findElement(options.container) : element.parent(); - var containerPosition = getPosition(container); - if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > containerPosition.bottom) { + var viewportPosition = getPosition($tooltip.$viewport); + if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > viewportPosition.bottom) { placement = originalPlacement.replace('bottom', 'top'); - } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < containerPosition.top) { + } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < viewportPosition.top) { placement = originalPlacement.replace('top', 'bottom'); } - if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') && elementPosition.right + tipWidth > containerPosition.width) { + if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') && elementPosition.right + tipWidth > viewportPosition.width) { placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right'); - } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') && elementPosition.left - tipWidth < containerPosition.left) { + } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') && elementPosition.left - tipWidth < viewportPosition.left) { placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left'); } tipElement.removeClass(originalPlacement).addClass(placement); @@ -450,23 +450,24 @@ angular.module('mgcrea.ngStrap.tooltip', [ 'mgcrea.ngStrap.core', 'mgcrea.ngStra var delta = { top: 0, left: 0 - }, $viewport = options.viewport && findElement(options.viewport.selector || options.viewport); - if (!$viewport) { - return delta; - } - var viewportPadding = options.viewport && options.viewport.padding || 0, viewportDimensions = getPosition($viewport); + }; + if (!$tooltip.$viewport) return delta; + var viewportPadding = options.viewport && options.viewport.padding || 0; + var viewportDimensions = getPosition($tooltip.$viewport); if (/right|left/.test(placement)) { - var topEdgeOffset = position.top - viewportPadding - viewportDimensions.scroll, bottomEdgeOffset = position.top + viewportPadding - viewportDimensions.scroll + actualHeight; + var topEdgeOffset = position.top - viewportPadding - viewportDimensions.scroll; + var bottomEdgeOffset = position.top + viewportPadding - viewportDimensions.scroll + actualHeight; if (topEdgeOffset < viewportDimensions.top) { delta.top = viewportDimensions.top - topEdgeOffset; } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset; } } else { - var leftEdgeOffset = position.left - viewportPadding, rightEdgeOffset = position.left + viewportPadding + actualWidth; + var leftEdgeOffset = position.left - viewportPadding; + var rightEdgeOffset = position.left + viewportPadding + actualWidth; if (leftEdgeOffset < viewportDimensions.left) { delta.left = viewportDimensions.left - leftEdgeOffset; - } else if (rightEdgeOffset > viewportDimensions.width) { + } else if (rightEdgeOffset > viewportDimensions.right) { delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset; } } diff --git a/dist/modules/tooltip.min.js b/dist/modules/tooltip.min.js index e062eb05c..98fb9ff32 100644 --- a/dist/modules/tooltip.min.js +++ b/dist/modules/tooltip.min.js @@ -1,9 +1,9 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT */ -'use strict';angular.module('mgcrea.ngStrap.tooltip',['mgcrea.ngStrap.core','mgcrea.ngStrap.helpers.dimensions']).provider('$tooltip',function(){var t=this.defaults={animation:'am-fade',customClass:'',prefixClass:'tooltip',prefixEvent:'tooltip',container:!1,target:!1,placement:'top',templateUrl:'tooltip/tooltip.tpl.html',template:'',contentTemplate:!1,trigger:'hover focus',keyboard:!1,html:!1,show:!1,title:'',type:'',delay:0,autoClose:!1,bsEnabled:!0,viewport:{selector:'body',padding:0}};this.$get=['$window','$rootScope','$bsCompiler','$q','$templateCache','$http','$animate','$sce','dimensions','$$rAF','$timeout',function(e,o,n,i,r,l,a,s,f,c,u){function p(i,r){function l(){U.$emit(A.prefixEvent+'.show',F)}function p(){if(U.$emit(A.prefixEvent+'.hide',F),q===j){if(V&&'focus'===A.trigger)return i[0].blur();P()}}function $(){var t=A.trigger.split(' ');angular.forEach(t,function(t){'click'===t?i.on('click',F.toggle):'manual'!==t&&(i.on('hover'===t?'mouseenter':'focus',F.enter),i.on('hover'===t?'mouseleave':'blur',F.leave),'button'===H&&'hover'!==t&&i.on(g?'touchstart':'mousedown',F.$onFocusElementMouseDown))})}function w(){for(var t=A.trigger.split(' '),e=t.length;e--;){var o=t[e];'click'===o?i.off('click',F.toggle):'manual'!==o&&(i.off('hover'===o?'mouseenter':'focus',F.enter),i.off('hover'===o?'mouseleave':'blur',F.leave),'button'===H&&'hover'!==o&&i.off(g?'touchstart':'mousedown',F.$onFocusElementMouseDown))}}function v(){'focus'!==A.trigger?q.on('keyup',F.$onKeyUp):i.on('keyup',F.$onFocusKeyUp)}function b(){'focus'!==A.trigger?q.off('keyup',F.$onKeyUp):i.off('keyup',F.$onFocusKeyUp)}function y(){u(function(){q.on('click',E),m.on('click',F.hide),L=!0},0,!1)}function k(){L&&(q.off('click',E),m.off('click',F.hide),L=!1)}function E(t){t.stopPropagation()}function C(t){t=t||A.target||i;var o=t[0],n='BODY'===o.tagName,r=o.getBoundingClientRect(),l={};for(var a in r)l[a]=r[a];null===l.width&&(l=angular.extend({},l,{width:r.right-r.left,height:r.bottom-r.top}));var s=n?{top:0,left:0}:f.offset(o),c={scroll:n?document.documentElement.scrollTop||document.body.scrollTop:t.prop('scrollTop')||0},u=n?{width:document.documentElement.clientWidth,height:e.innerHeight}:null;return angular.extend({},l,c,u,s)}function S(t,e,o,n){var i,r=t.split('-');switch(r[0]){case'right':i={top:e.top+e.height/2-n/2,left:e.left+e.width};break;case'bottom':i={top:e.top+e.height,left:e.left+e.width/2-o/2};break;case'left':i={top:e.top+e.height/2-n/2,left:e.left-o};break;default:i={top:e.top-n,left:e.left+e.width/2-o/2}}if(!r[1])return i;if('top'===r[0]||'bottom'===r[0])switch(r[1]){case'left':i.left=e.left;break;case'right':i.left=e.left+e.width-o}else if('left'===r[0]||'right'===r[0])switch(r[1]){case'top':i.top=e.top-n;break;case'bottom':i.top=e.top+e.height}return i}function D(t,e){var o=q[0],n=o.offsetWidth,i=o.offsetHeight,r=parseInt(f.css(o,'margin-top'),10),l=parseInt(f.css(o,'margin-left'),10);isNaN(r)&&(r=0),isNaN(l)&&(l=0),t.top=t.top+r,t.left=t.left+l,f.setOffset(o,angular.extend({using:function(t){q.css({top:Math.round(t.top)+'px',left:Math.round(t.left)+'px',right:''})}},t),0);var a=o.offsetWidth,s=o.offsetHeight;if('top'===e&&s!==i&&(t.top=t.top+i-s),!/top-left|top-right|bottom-left|bottom-right/.test(e)){var c=x(e,t,a,s);if(c.left?t.left+=c.left:t.top+=c.top,f.setOffset(o,t),/top|right|bottom|left/.test(e)){var u=/top|bottom/.test(e),p=u?2*c.left-n+a:2*c.top-i+s,h=u?'offsetWidth':'offsetHeight';T(p,o[h],u)}}}function x(t,e,o,n){var i={top:0,left:0},r=A.viewport&&d(A.viewport.selector||A.viewport);if(!r)return i;var l=A.viewport&&A.viewport.padding||0,a=C(r);if(/right|left/.test(t)){var s=e.top-l-a.scroll,f=e.top+l-a.scroll+n;sa.top+a.height&&(i.top=a.top+a.height-f)}else{var c=e.left-l,u=e.left+l+o;ca.width&&(i.left=a.left+a.width-u)}return i}function T(t,e,o){var n=d('.tooltip-arrow, .arrow',q[0]);n.css(o?'left':'top',50*(1-t/e)+'%').css(o?'top':'left','')}function P(){clearTimeout(K),F.$isShown&&null!==q&&(A.autoClose&&k(),A.keyboard&&b()),I&&(I.$destroy(),I=null),q&&(q.remove(),q=F.$element=null)}var F={},A=F.$options=angular.extend({},t,r),O=F.$promise=n.compile(A),U=F.$scope=A.scope&&A.scope.$new()||o.$new(),H=i[0].nodeName.toLowerCase();if(A.delay&&angular.isString(A.delay)){var N=A.delay.split(',').map(parseFloat);A.delay=N.length>1?{show:N[0],hide:N[1]}:N[0]}F.$id=A.id||i.attr('id')||'',A.title&&(U.title=s.trustAsHtml(A.title)),U.$setEnabled=function(t){U.$$postDigest(function(){F.setEnabled(t)})},U.$hide=function(){U.$$postDigest(function(){F.hide()})},U.$show=function(){U.$$postDigest(function(){F.show()})},U.$toggle=function(){U.$$postDigest(function(){F.toggle()})},F.$isShown=U.$isShown=!1;var K,M,W,q,B,I;O.then(function(t){W=t,F.init()}),F.init=function(){A.delay&&angular.isNumber(A.delay)&&(A.delay={show:A.delay,hide:A.delay}),'self'===A.container?B=i:angular.isElement(A.container)?B=A.container:A.container&&(B=d(A.container)),$(),A.target&&(A.target=angular.isElement(A.target)?A.target:d(A.target)),A.show&&U.$$postDigest(function(){'focus'===A.trigger?i[0].focus():F.show()})},F.destroy=function(){w(),P(),U.$destroy()},F.enter=function(){return clearTimeout(K),M='in',A.delay&&A.delay.show?void(K=setTimeout(function(){'in'===M&&F.show()},A.delay.show)):F.show()},F.show=function(){if(A.bsEnabled&&!F.$isShown){U.$emit(A.prefixEvent+'.show.before',F);var t,e;A.container?(t=B,e=B[0].lastChild?angular.element(B[0].lastChild):null):(t=null,e=i),q&&P(),I=F.$scope.$new(),q=F.$element=W.link(I,function(t,e){}),q.css({top:'-9999px',left:'-9999px',right:'auto',display:'block',visibility:'hidden'}),A.animation&&q.addClass(A.animation),A.type&&q.addClass(A.prefixClass+'-'+A.type),A.customClass&&q.addClass(A.customClass),e?e.after(q):t.prepend(q),F.$isShown=U.$isShown=!0,h(U),F.$applyPlacement(),angular.version.minor<=2?a.enter(q,t,e,l):a.enter(q,t,e).then(l),h(U),c(function(){q&&q.css({visibility:'visible'})}),A.keyboard&&('focus'!==A.trigger&&F.focus(),v()),A.autoClose&&y()}},F.leave=function(){return clearTimeout(K),M='out',A.delay&&A.delay.hide?void(K=setTimeout(function(){'out'===M&&F.hide()},A.delay.hide)):F.hide()};var V,j;F.hide=function(t){F.$isShown&&(U.$emit(A.prefixEvent+'.hide.before',F),V=t,j=q,angular.version.minor<=2?a.leave(q,p):a.leave(q).then(p),F.$isShown=U.$isShown=!1,h(U),A.keyboard&&null!==q&&b(),A.autoClose&&null!==q&&k())},F.toggle=function(){F.$isShown?F.leave():F.enter()},F.focus=function(){q[0].focus()},F.setEnabled=function(t){A.bsEnabled=t},F.setViewport=function(t){A.viewport=t},F.$applyPlacement=function(){if(q){var e=A.placement,o=/\s?auto?\s?/i,n=o.test(e);n&&(e=e.replace(o,'')||t.placement),q.addClass(A.placement);var r=C(),l=q.prop('offsetWidth'),a=q.prop('offsetHeight');if(n){var s=e,f=A.container?d(A.container):i.parent(),c=C(f);s.indexOf('bottom')>=0&&r.bottom+a>c.bottom?e=s.replace('bottom','top'):s.indexOf('top')>=0&&r.top-ac.width?e='right'===s?'left':e.replace('left','right'):('left'===s||'bottom-right'===s||'top-right'===s)&&r.left-ll.top+l.height&&(i.top=l.top+l.height-s)}else{var f=e.left-r,c=e.left+r+o;fl.right&&(i.left=l.left+l.width-c)}return i}function T(t,e,o){var n=d('.tooltip-arrow, .arrow',q[0]);n.css(o?'left':'top',50*(1-t/e)+'%').css(o?'top':'left','')}function P(){clearTimeout(K),F.$isShown&&null!==q&&(A.autoClose&&k(),A.keyboard&&b()),I&&(I.$destroy(),I=null),q&&(q.remove(),q=F.$element=null)}var F={},A=F.$options=angular.extend({},t,r),O=F.$promise=n.compile(A),U=F.$scope=A.scope&&A.scope.$new()||o.$new(),H=i[0].nodeName.toLowerCase();if(A.delay&&angular.isString(A.delay)){var N=A.delay.split(',').map(parseFloat);A.delay=N.length>1?{show:N[0],hide:N[1]}:N[0]}F.$id=A.id||i.attr('id')||'',A.title&&(U.title=s.trustAsHtml(A.title)),U.$setEnabled=function(t){U.$$postDigest(function(){F.setEnabled(t)})},U.$hide=function(){U.$$postDigest(function(){F.hide()})},U.$show=function(){U.$$postDigest(function(){F.show()})},U.$toggle=function(){U.$$postDigest(function(){F.toggle()})},F.$isShown=U.$isShown=!1;var K,M,W,q,B,I;O.then(function(t){W=t,F.init()}),F.init=function(){A.delay&&angular.isNumber(A.delay)&&(A.delay={show:A.delay,hide:A.delay}),'self'===A.container?B=i:angular.isElement(A.container)?B=A.container:A.container&&(B=d(A.container)),$(),A.target&&(A.target=angular.isElement(A.target)?A.target:d(A.target)),A.show&&U.$$postDigest(function(){'focus'===A.trigger?i[0].focus():F.show()})},F.destroy=function(){v(),P(),U.$destroy()},F.enter=function(){return clearTimeout(K),M='in',A.delay&&A.delay.show?void(K=setTimeout(function(){'in'===M&&F.show()},A.delay.show)):F.show()},F.show=function(){if(A.bsEnabled&&!F.$isShown){U.$emit(A.prefixEvent+'.show.before',F);var t,e;A.container?(t=B,e=B[0].lastChild?angular.element(B[0].lastChild):null):(t=null,e=i),q&&P(),I=F.$scope.$new(),q=F.$element=W.link(I,function(t,e){}),q.css({top:'-9999px',left:'-9999px',right:'auto',display:'block',visibility:'hidden'}),A.animation&&q.addClass(A.animation),A.type&&q.addClass(A.prefixClass+'-'+A.type),A.customClass&&q.addClass(A.customClass),e?e.after(q):t.prepend(q),F.$isShown=U.$isShown=!0,h(U),F.$applyPlacement(),angular.version.minor<=2?a.enter(q,t,e,l):a.enter(q,t,e).then(l),h(U),c(function(){q&&q.css({visibility:'visible'})}),A.keyboard&&('focus'!==A.trigger&&F.focus(),w()),A.autoClose&&y()}},F.leave=function(){return clearTimeout(K),M='out',A.delay&&A.delay.hide?void(K=setTimeout(function(){'out'===M&&F.hide()},A.delay.hide)):F.hide()};var V,j;F.hide=function(t){F.$isShown&&(U.$emit(A.prefixEvent+'.hide.before',F),V=t,j=q,angular.version.minor<=2?a.leave(q,p):a.leave(q).then(p),F.$isShown=U.$isShown=!1,h(U),A.keyboard&&null!==q&&b(),A.autoClose&&null!==q&&k())},F.toggle=function(){F.$isShown?F.leave():F.enter()},F.focus=function(){q[0].focus()},F.setEnabled=function(t){A.bsEnabled=t},F.setViewport=function(t){A.viewport=t},F.$applyPlacement=function(){if(q){var e=A.placement,o=/\s?auto?\s?/i,n=o.test(e);n&&(e=e.replace(o,'')||t.placement),q.addClass(A.placement);var i=C(),r=q.prop('offsetWidth'),l=q.prop('offsetHeight');if(F.$viewport=A.viewport&&d(A.viewport.selector||A.viewport),n){var a=e,s=C(F.$viewport);a.indexOf('bottom')>=0&&i.bottom+l>s.bottom?e=a.replace('bottom','top'):a.indexOf('top')>=0&&i.top-ls.width?e='right'===a?'left':e.replace('left','right'):('left'===a||'bottom-right'===a||'top-right'===a)&&i.left-r 1 ? {show: split[0], hide: split[1]} : split[0];\n }\n\n // Store $id to identify the triggering element in events\n // give priority to options.id, otherwise, try to use\n // element id if defined\n $tooltip.$id = options.id || element.attr('id') || '';\n\n // Support scope as string options\n if(options.title) {\n scope.title = $sce.trustAsHtml(options.title);\n }\n\n // Provide scope helpers\n scope.$setEnabled = function(isEnabled) {\n scope.$$postDigest(function() {\n $tooltip.setEnabled(isEnabled);\n });\n };\n scope.$hide = function() {\n scope.$$postDigest(function() {\n $tooltip.hide();\n });\n };\n scope.$show = function() {\n scope.$$postDigest(function() {\n $tooltip.show();\n });\n };\n scope.$toggle = function() {\n scope.$$postDigest(function() {\n $tooltip.toggle();\n });\n };\n // Publish isShown as a protected var on scope\n $tooltip.$isShown = scope.$isShown = false;\n\n // Private vars\n var timeout, hoverState;\n\n // Fetch, compile then initialize tooltip\n var compileData, tipElement, tipContainer, tipScope;\n promise.then(function(data) {\n compileData = data;\n $tooltip.init();\n });\n\n $tooltip.init = function() {\n\n // Options: delay\n if (options.delay && angular.isNumber(options.delay)) {\n options.delay = {\n show: options.delay,\n hide: options.delay\n };\n }\n\n // Replace trigger on touch devices ?\n // if(isTouch && options.trigger === defaults.trigger) {\n // options.trigger.replace(/hover/g, 'click');\n // }\n\n // Options : container\n if(options.container === 'self') {\n tipContainer = element;\n } else if(angular.isElement(options.container)) {\n tipContainer = options.container;\n } else if(options.container) {\n tipContainer = findElement(options.container);\n }\n\n // Options: trigger\n bindTriggerEvents();\n\n // Options: target\n if(options.target) {\n options.target = angular.isElement(options.target) ? options.target : findElement(options.target);\n }\n\n // Options: show\n if(options.show) {\n scope.$$postDigest(function() {\n options.trigger === 'focus' ? element[0].focus() : $tooltip.show();\n });\n }\n\n };\n\n $tooltip.destroy = function() {\n\n // Unbind events\n unbindTriggerEvents();\n\n // Remove element\n destroyTipElement();\n\n // Destroy scope\n scope.$destroy();\n\n };\n\n $tooltip.enter = function() {\n\n clearTimeout(timeout);\n hoverState = 'in';\n if (!options.delay || !options.delay.show) {\n return $tooltip.show();\n }\n\n timeout = setTimeout(function() {\n if (hoverState ==='in') $tooltip.show();\n }, options.delay.show);\n\n };\n\n $tooltip.show = function() {\n if (!options.bsEnabled || $tooltip.$isShown) return;\n\n scope.$emit(options.prefixEvent + '.show.before', $tooltip);\n var parent, after;\n if (options.container) {\n parent = tipContainer;\n if (tipContainer[0].lastChild) {\n after = angular.element(tipContainer[0].lastChild);\n } else {\n after = null;\n }\n } else {\n parent = null;\n after = element;\n }\n\n\n // Hide any existing tipElement\n if(tipElement) destroyTipElement();\n // Fetch a cloned element linked from template\n tipScope = $tooltip.$scope.$new();\n tipElement = $tooltip.$element = compileData.link(tipScope, function(clonedElement, scope) {});\n\n // Set the initial positioning. Make the tooltip invisible\n // so IE doesn't try to focus on it off screen.\n tipElement.css({top: '-9999px', left: '-9999px', right: 'auto', display: 'block', visibility: 'hidden'});\n\n // Options: animation\n if(options.animation) tipElement.addClass(options.animation);\n // Options: type\n if(options.type) tipElement.addClass(options.prefixClass + '-' + options.type);\n // Options: custom classes\n if(options.customClass) tipElement.addClass(options.customClass);\n\n // Append the element, without any animations. If we append\n // using $animate.enter, some of the animations cause the placement\n // to be off due to the transforms.\n after ? after.after(tipElement) : parent.prepend(tipElement);\n\n $tooltip.$isShown = scope.$isShown = true;\n safeDigest(scope);\n\n // Now, apply placement\n $tooltip.$applyPlacement();\n\n // Once placed, animate it.\n // Support v1.2+ $animate\n // https://github.com/angular/angular.js/issues/11713\n if(angular.version.minor <= 2) {\n $animate.enter(tipElement, parent, after, enterAnimateCallback);\n } else {\n $animate.enter(tipElement, parent, after).then(enterAnimateCallback);\n }\n safeDigest(scope);\n\n $$rAF(function () {\n // Once the tooltip is placed and the animation starts, make the tooltip visible\n if(tipElement) tipElement.css({visibility: 'visible'});\n });\n\n // Bind events\n if(options.keyboard) {\n if(options.trigger !== 'focus') {\n $tooltip.focus();\n }\n bindKeyboardEvents();\n }\n\n if(options.autoClose) {\n bindAutoCloseEvents();\n }\n\n };\n\n function enterAnimateCallback() {\n scope.$emit(options.prefixEvent + '.show', $tooltip);\n }\n\n $tooltip.leave = function() {\n\n clearTimeout(timeout);\n hoverState = 'out';\n if (!options.delay || !options.delay.hide) {\n return $tooltip.hide();\n }\n timeout = setTimeout(function () {\n if (hoverState === 'out') {\n $tooltip.hide();\n }\n }, options.delay.hide);\n\n };\n\n var _blur;\n var _tipToHide;\n $tooltip.hide = function(blur) {\n\n if(!$tooltip.$isShown) return;\n scope.$emit(options.prefixEvent + '.hide.before', $tooltip);\n\n // store blur value for leaveAnimateCallback to use\n _blur = blur;\n\n // store current tipElement reference to use\n // in leaveAnimateCallback\n _tipToHide = tipElement;\n\n // Support v1.2+ $animate\n // https://github.com/angular/angular.js/issues/11713\n if(angular.version.minor <= 2) {\n $animate.leave(tipElement, leaveAnimateCallback);\n } else {\n $animate.leave(tipElement).then(leaveAnimateCallback);\n }\n\n $tooltip.$isShown = scope.$isShown = false;\n safeDigest(scope);\n\n // Unbind events\n if(options.keyboard && tipElement !== null) {\n unbindKeyboardEvents();\n }\n\n if(options.autoClose && tipElement !== null) {\n unbindAutoCloseEvents();\n }\n };\n\n function leaveAnimateCallback() {\n scope.$emit(options.prefixEvent + '.hide', $tooltip);\n\n // check if current tipElement still references\n // the same element when hide was called\n if (tipElement === _tipToHide) {\n // Allow to blur the input when hidden, like when pressing enter key\n if(_blur && options.trigger === 'focus') {\n return element[0].blur();\n }\n\n // clean up child scopes\n destroyTipElement();\n }\n }\n\n $tooltip.toggle = function() {\n $tooltip.$isShown ? $tooltip.leave() : $tooltip.enter();\n };\n\n $tooltip.focus = function() {\n tipElement[0].focus();\n };\n\n $tooltip.setEnabled = function(isEnabled) {\n options.bsEnabled = isEnabled;\n };\n\n $tooltip.setViewport = function(viewport) {\n options.viewport = viewport;\n };\n\n // Protected methods\n\n $tooltip.$applyPlacement = function() {\n if(!tipElement) return;\n\n // Determine if we're doing an auto or normal placement\n var placement = options.placement,\n autoToken = /\\s?auto?\\s?/i,\n autoPlace = autoToken.test(placement);\n\n if (autoPlace) {\n placement = placement.replace(autoToken, '') || defaults.placement;\n }\n\n // Need to add the position class before we get\n // the offsets\n tipElement.addClass(options.placement);\n\n // Get the position of the target element\n // and the height and width of the tooltip so we can center it.\n var elementPosition = getPosition(),\n tipWidth = tipElement.prop('offsetWidth'),\n tipHeight = tipElement.prop('offsetHeight');\n\n // If we're auto placing, we need to check the positioning\n if (autoPlace) {\n var originalPlacement = placement;\n var container = options.container ? findElement(options.container) : element.parent();\n var containerPosition = getPosition(container);\n\n // Determine if the vertical placement\n if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > containerPosition.bottom) {\n placement = originalPlacement.replace('bottom', 'top');\n } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < containerPosition.top) {\n placement = originalPlacement.replace('top', 'bottom');\n }\n\n // Determine the horizontal placement\n // The exotic placements of left and right are opposite of the standard placements. Their arrows are put on the left/right\n // and flow in the opposite direction of their placement.\n if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') &&\n elementPosition.right + tipWidth > containerPosition.width) {\n\n placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right');\n } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') &&\n elementPosition.left - tipWidth < containerPosition.left) {\n\n placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left');\n }\n\n tipElement.removeClass(originalPlacement).addClass(placement);\n }\n\n // Get the tooltip's top and left coordinates to center it with this directive.\n var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight);\n applyPlacement(tipPosition, placement);\n };\n\n $tooltip.$onKeyUp = function(evt) {\n if (evt.which === 27 && $tooltip.$isShown) {\n $tooltip.hide();\n evt.stopPropagation();\n }\n };\n\n $tooltip.$onFocusKeyUp = function(evt) {\n if (evt.which === 27) {\n element[0].blur();\n evt.stopPropagation();\n }\n };\n\n $tooltip.$onFocusElementMouseDown = function(evt) {\n evt.preventDefault();\n evt.stopPropagation();\n // Some browsers do not auto-focus buttons (eg. Safari)\n $tooltip.$isShown ? element[0].blur() : element[0].focus();\n };\n\n // bind/unbind events\n function bindTriggerEvents() {\n var triggers = options.trigger.split(' ');\n angular.forEach(triggers, function(trigger) {\n if(trigger === 'click') {\n element.on('click', $tooltip.toggle);\n } else if(trigger !== 'manual') {\n element.on(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);\n element.on(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);\n nodeName === 'button' && trigger !== 'hover' && element.on(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);\n }\n });\n }\n\n function unbindTriggerEvents() {\n var triggers = options.trigger.split(' ');\n for (var i = triggers.length; i--;) {\n var trigger = triggers[i];\n if(trigger === 'click') {\n element.off('click', $tooltip.toggle);\n } else if(trigger !== 'manual') {\n element.off(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);\n element.off(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);\n nodeName === 'button' && trigger !== 'hover' && element.off(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);\n }\n }\n }\n\n function bindKeyboardEvents() {\n if(options.trigger !== 'focus') {\n tipElement.on('keyup', $tooltip.$onKeyUp);\n } else {\n element.on('keyup', $tooltip.$onFocusKeyUp);\n }\n }\n\n function unbindKeyboardEvents() {\n if(options.trigger !== 'focus') {\n tipElement.off('keyup', $tooltip.$onKeyUp);\n } else {\n element.off('keyup', $tooltip.$onFocusKeyUp);\n }\n }\n\n var _autoCloseEventsBinded = false;\n function bindAutoCloseEvents() {\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n // Stop propagation when clicking inside tooltip\n tipElement.on('click', stopEventPropagation);\n\n // Hide when clicking outside tooltip\n $body.on('click', $tooltip.hide);\n\n _autoCloseEventsBinded = true;\n }, 0, false);\n }\n\n function unbindAutoCloseEvents() {\n if (_autoCloseEventsBinded) {\n tipElement.off('click', stopEventPropagation);\n $body.off('click', $tooltip.hide);\n _autoCloseEventsBinded = false;\n }\n }\n\n function stopEventPropagation(event) {\n event.stopPropagation();\n }\n\n // Private methods\n\n function getPosition($element) {\n $element = $element || (options.target || element);\n\n var el = $element[0],\n isBody = el.tagName === 'BODY';\n\n var elRect = el.getBoundingClientRect();\n var rect = {};\n\n // IE8 has issues with angular.extend and using elRect directly.\n // By coping the values of elRect into a new object, we can continue to use extend\n for (var p in elRect) {\n // DO NOT use hasOwnProperty when inspecting the return of getBoundingClientRect.\n rect[p] = elRect[p];\n }\n\n if (rect.width === null) {\n // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093\n rect = angular.extend({}, rect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top });\n }\n var elOffset = isBody ? { top: 0, left: 0 } : dimensions.offset(el),\n scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.prop('scrollTop') || 0 },\n outerDims = isBody ? { width: document.documentElement.clientWidth, height: $window.innerHeight } : null;\n\n return angular.extend({}, rect, scroll, outerDims, elOffset);\n }\n\n function getCalculatedOffset(placement, position, actualWidth, actualHeight) {\n var offset;\n var split = placement.split('-');\n\n switch (split[0]) {\n case 'right':\n offset = {\n top: position.top + position.height / 2 - actualHeight / 2,\n left: position.left + position.width\n };\n break;\n case 'bottom':\n offset = {\n top: position.top + position.height,\n left: position.left + position.width / 2 - actualWidth / 2\n };\n break;\n case 'left':\n offset = {\n top: position.top + position.height / 2 - actualHeight / 2,\n left: position.left - actualWidth\n };\n break;\n default:\n offset = {\n top: position.top - actualHeight,\n left: position.left + position.width / 2 - actualWidth / 2\n };\n break;\n }\n\n if(!split[1]) {\n return offset;\n }\n\n // Add support for corners @todo css\n if(split[0] === 'top' || split[0] === 'bottom') {\n switch (split[1]) {\n case 'left':\n offset.left = position.left;\n break;\n case 'right':\n offset.left = position.left + position.width - actualWidth;\n }\n } else if(split[0] === 'left' || split[0] === 'right') {\n switch (split[1]) {\n case 'top':\n offset.top = position.top - actualHeight;\n break;\n case 'bottom':\n offset.top = position.top + position.height;\n }\n }\n\n return offset;\n }\n\n function applyPlacement(offset, placement) {\n var tip = tipElement[0],\n width = tip.offsetWidth,\n height = tip.offsetHeight;\n\n // manually read margins because getBoundingClientRect includes difference\n var marginTop = parseInt(dimensions.css(tip, 'margin-top'), 10),\n marginLeft = parseInt(dimensions.css(tip, 'margin-left'), 10);\n\n // we must check for NaN for ie 8/9\n if (isNaN(marginTop)) marginTop = 0;\n if (isNaN(marginLeft)) marginLeft = 0;\n\n offset.top = offset.top + marginTop;\n offset.left = offset.left + marginLeft;\n\n // dimensions setOffset doesn't round pixel values\n // so we use setOffset directly with our own function\n dimensions.setOffset(tip, angular.extend({\n using: function (props) {\n tipElement.css({\n top: Math.round(props.top) + 'px',\n left: Math.round(props.left) + 'px',\n right: ''\n });\n }\n }, offset), 0);\n\n // check to see if placing tip in new offset caused the tip to resize itself\n var actualWidth = tip.offsetWidth,\n actualHeight = tip.offsetHeight;\n\n if (placement === 'top' && actualHeight !== height) {\n offset.top = offset.top + height - actualHeight;\n }\n\n // If it's an exotic placement, exit now instead of\n // applying a delta and changing the arrow\n if (/top-left|top-right|bottom-left|bottom-right/.test(placement)) return;\n\n var delta = getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight);\n\n if (delta.left) {\n offset.left += delta.left;\n } else {\n offset.top += delta.top;\n }\n\n dimensions.setOffset(tip, offset);\n\n if (/top|right|bottom|left/.test(placement)) {\n var isVertical = /top|bottom/.test(placement),\n arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight,\n arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight';\n\n replaceArrow(arrowDelta, tip[arrowOffsetPosition], isVertical);\n }\n }\n\n function getViewportAdjustedDelta(placement, position, actualWidth, actualHeight) {\n var delta = { top: 0, left: 0 },\n $viewport = options.viewport && findElement(options.viewport.selector || options.viewport);\n\n if (!$viewport) {\n return delta;\n }\n\n var viewportPadding = options.viewport && options.viewport.padding || 0,\n viewportDimensions = getPosition($viewport);\n\n if (/right|left/.test(placement)) {\n var topEdgeOffset = position.top - viewportPadding - viewportDimensions.scroll,\n bottomEdgeOffset = position.top + viewportPadding - viewportDimensions.scroll + actualHeight;\n if (topEdgeOffset < viewportDimensions.top) { // top overflow\n delta.top = viewportDimensions.top - topEdgeOffset;\n } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow\n delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset;\n }\n } else {\n var leftEdgeOffset = position.left - viewportPadding,\n rightEdgeOffset = position.left + viewportPadding + actualWidth;\n if (leftEdgeOffset < viewportDimensions.left) { // left overflow\n delta.left = viewportDimensions.left - leftEdgeOffset;\n } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow\n delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset;\n }\n }\n\n return delta;\n }\n\n function replaceArrow(delta, dimension, isHorizontal) {\n var $arrow = findElement('.tooltip-arrow, .arrow', tipElement[0]);\n\n $arrow.css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')\n .css(isHorizontal ? 'top' : 'left', '');\n }\n\n function destroyTipElement() {\n // Cancel pending callbacks\n clearTimeout(timeout);\n\n if($tooltip.$isShown && tipElement !== null) {\n if(options.autoClose) {\n unbindAutoCloseEvents();\n }\n\n if(options.keyboard) {\n unbindKeyboardEvents();\n }\n }\n\n if(tipScope) {\n tipScope.$destroy();\n tipScope = null;\n }\n\n if(tipElement) {\n tipElement.remove();\n tipElement = $tooltip.$element = null;\n }\n }\n\n return $tooltip;\n\n }\n\n // Helper functions\n\n function safeDigest(scope) {\n scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();\n }\n\n function findElement(query, element) {\n return angular.element((element || document).querySelectorAll(query));\n }\n\n var fetchPromises = {};\n function fetchTemplate(template) {\n if(fetchPromises[template]) return fetchPromises[template];\n return (fetchPromises[template] = $http.get(template, {cache: $templateCache}).then(function(res) {\n return res.data;\n }));\n }\n\n return TooltipFactory;\n\n };\n\n })\n\n .directive('bsTooltip', function($window, $location, $sce, $tooltip, $$rAF) {\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'backdropAnimation', 'type', 'customClass', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // should not parse target attribute (anchor tag), only data-target #1454\n var dataTarget = element.attr('data-target');\n if(angular.isDefined(dataTarget)) {\n if(falseValueRegExp.test(dataTarget))\n options.target = false;\n else\n options.target = dataTarget;\n }\n\n // overwrite inherited title value when no value specified\n // fix for angular 1.3.1 531a8de72c439d8ddd064874bf364c00cedabb11\n if (!scope.hasOwnProperty('title')){\n scope.title = '';\n }\n\n // Observe scope attributes for change\n attr.$observe('title', function(newValue) {\n if (angular.isDefined(newValue) || !scope.hasOwnProperty('title')) {\n var oldValue = scope.title;\n scope.title = $sce.trustAsHtml(newValue);\n angular.isDefined(oldValue) && $$rAF(function() {\n tooltip && tooltip.$applyPlacement();\n });\n }\n });\n\n // Support scope as an object\n attr.bsTooltip && scope.$watch(attr.bsTooltip, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.title = newValue;\n }\n angular.isDefined(oldValue) && $$rAF(function() {\n tooltip && tooltip.$applyPlacement();\n });\n }, true);\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!tooltip || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(tooltip),?/i);\n newValue === true ? tooltip.show() : tooltip.hide();\n });\n\n // Enabled binding support\n attr.bsEnabled && scope.$watch(attr.bsEnabled, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.bsEnabled, newValue, oldValue);\n if(!tooltip || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|1|,?(tooltip),?/i);\n newValue === false ? tooltip.setEnabled(false) : tooltip.setEnabled(true);\n });\n\n // Viewport support\n attr.viewport && scope.$watch(attr.viewport, function (newValue) {\n if(!tooltip || !angular.isDefined(newValue)) return;\n tooltip.setViewport(newValue);\n });\n\n // Initialize popover\n var tooltip = $tooltip(element, options);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if(tooltip) tooltip.destroy();\n options = null;\n tooltip = null;\n });\n\n }\n };\n\n });\n"],"sourceRoot":"/source/"} \ No newline at end of file +{"version":3,"sources":["modules/tooltip.js"],"names":["angular","target","provider","placement","this","defaults","templateUrl","template","contentTemplate","trigger","keyboard","html","show","title","type","delay","autoClose","bsEnabled","viewport","selector","padding","$get","String","htmlReplaceRegExp","$body","options","$tooltip","extend","config","split","enterAnimateCallback","scope","$emit","prefixEvent","leaveAnimateCallback","_tipToHide","leave","$isShown","element","blur","tipElement","nodeName","forEach","triggers","on","toggle","unbindTriggerEvents","enter","i","length","off","bindKeyboardEvents","$onKeyUp","isTouch","$onFocusElementMouseDown","unbindKeyboardEvents","_autoCloseEventsBinded","bindAutoCloseEvents","$timeout","hide","unbindAutoCloseEvents","stopEventPropagation","event","getPosition","$element","rect","stopPropagation","width","elRect","height","p","top","left","dimensions","offset","el","scroll","isBody","document","documentElement","$window","getCalculatedOffset","position","actualWidth","actualHeight","outerDims","clientWidth","innerHeight","tip","marginTop","parseInt","using","props","css","isNaN","right","marginLeft","setOffset","delta","getViewportAdjustedDelta","isVertical","replaceArrow","arrowDelta","test","arrowOffsetPosition","viewportDimensions","$viewport","topEdgeOffset","bottomEdgeOffset","viewportPadding","leftEdgeOffset","rightEdgeOffset","dimension","isHorizontal","findElement","$arrow","clearTimeout","timeout","tipScope","$destroy","$$phase","$options","$promise","$bsCompiler","compile","$scope","$new","$rootScope","toLowerCase","$id","attr","map","parseFloat","$sce","trustAsHtml","$setEnabled","$$postDigest","id","$hide","setEnabled","isEnabled","compileData","promise","then","init","container","tipContainer","bindTriggerEvents","isElement","destroyTipElement","hoverState","parent","after","lastChild","display","visibility","link","clonedElement","safeDigest","version","minor","addClass","animation","$animate","customClass","$$rAF","$applyPlacement","focus","_blur","replace","elementPosition","autoPlace","autoToken","viewportPosition","originalPlacement","indexOf","tipHeight","removeClass","tipPosition","applyPlacement","tipWidth","evt","preventDefault","fetchTemplate","fetchPromises","cache","$templateCache","res","isString","directive","$location","restrict","falseValueRegExp","transclusion","dataTarget","key","isDefined","hasOwnProperty","oldValue","tooltip","$observe","newValue","bsTooltip","$watch","isObject","bsShow","match","setViewport","$on","destroy"],"mappings":"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","file":"modules/tooltip.min.js","sourcesContent":["'use strict';\n\nangular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.core', 'mgcrea.ngStrap.helpers.dimensions'])\n\n .provider('$tooltip', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n customClass: '',\n prefixClass: 'tooltip',\n prefixEvent: 'tooltip',\n container: false,\n target: false,\n placement: 'top',\n templateUrl: 'tooltip/tooltip.tpl.html',\n template: '',\n contentTemplate: false,\n trigger: 'hover focus',\n keyboard: false,\n html: false,\n show: false,\n title: '',\n type: '',\n delay: 0,\n autoClose: false,\n bsEnabled: true,\n viewport: {\n selector: 'body',\n padding: 0\n }\n };\n\n this.$get = function($window, $rootScope, $bsCompiler, $q, $templateCache, $http, $animate, $sce, dimensions, $$rAF, $timeout) {\n\n var trim = String.prototype.trim;\n var isTouch = 'createTouch' in $window.document;\n var htmlReplaceRegExp = /ng-bind=\"/ig;\n var $body = angular.element($window.document);\n\n function TooltipFactory(element, config) {\n\n var $tooltip = {};\n\n // Common vars\n var options = $tooltip.$options = angular.extend({}, defaults, config);\n var promise = $tooltip.$promise = $bsCompiler.compile(options);\n var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new();\n\n var nodeName = element[0].nodeName.toLowerCase();\n if(options.delay && angular.isString(options.delay)) {\n var split = options.delay.split(',').map(parseFloat);\n options.delay = split.length > 1 ? {show: split[0], hide: split[1]} : split[0];\n }\n\n // Store $id to identify the triggering element in events\n // give priority to options.id, otherwise, try to use\n // element id if defined\n $tooltip.$id = options.id || element.attr('id') || '';\n\n // Support scope as string options\n if(options.title) {\n scope.title = $sce.trustAsHtml(options.title);\n }\n\n // Provide scope helpers\n scope.$setEnabled = function(isEnabled) {\n scope.$$postDigest(function() {\n $tooltip.setEnabled(isEnabled);\n });\n };\n scope.$hide = function() {\n scope.$$postDigest(function() {\n $tooltip.hide();\n });\n };\n scope.$show = function() {\n scope.$$postDigest(function() {\n $tooltip.show();\n });\n };\n scope.$toggle = function() {\n scope.$$postDigest(function() {\n $tooltip.toggle();\n });\n };\n // Publish isShown as a protected var on scope\n $tooltip.$isShown = scope.$isShown = false;\n\n // Private vars\n var timeout, hoverState;\n\n // Fetch, compile then initialize tooltip\n var compileData, tipElement, tipContainer, tipScope;\n promise.then(function(data) {\n compileData = data;\n $tooltip.init();\n });\n\n $tooltip.init = function() {\n\n // Options: delay\n if (options.delay && angular.isNumber(options.delay)) {\n options.delay = {\n show: options.delay,\n hide: options.delay\n };\n }\n\n // Replace trigger on touch devices ?\n // if(isTouch && options.trigger === defaults.trigger) {\n // options.trigger.replace(/hover/g, 'click');\n // }\n\n // Options : container\n if(options.container === 'self') {\n tipContainer = element;\n } else if(angular.isElement(options.container)) {\n tipContainer = options.container;\n } else if(options.container) {\n tipContainer = findElement(options.container);\n }\n\n // Options: trigger\n bindTriggerEvents();\n\n // Options: target\n if(options.target) {\n options.target = angular.isElement(options.target) ? options.target : findElement(options.target);\n }\n\n // Options: show\n if(options.show) {\n scope.$$postDigest(function() {\n options.trigger === 'focus' ? element[0].focus() : $tooltip.show();\n });\n }\n\n };\n\n $tooltip.destroy = function() {\n\n // Unbind events\n unbindTriggerEvents();\n\n // Remove element\n destroyTipElement();\n\n // Destroy scope\n scope.$destroy();\n\n };\n\n $tooltip.enter = function() {\n\n clearTimeout(timeout);\n hoverState = 'in';\n if (!options.delay || !options.delay.show) {\n return $tooltip.show();\n }\n\n timeout = setTimeout(function() {\n if (hoverState ==='in') $tooltip.show();\n }, options.delay.show);\n\n };\n\n $tooltip.show = function() {\n if (!options.bsEnabled || $tooltip.$isShown) return;\n\n scope.$emit(options.prefixEvent + '.show.before', $tooltip);\n var parent, after;\n if (options.container) {\n parent = tipContainer;\n if (tipContainer[0].lastChild) {\n after = angular.element(tipContainer[0].lastChild);\n } else {\n after = null;\n }\n } else {\n parent = null;\n after = element;\n }\n\n\n // Hide any existing tipElement\n if(tipElement) destroyTipElement();\n // Fetch a cloned element linked from template\n tipScope = $tooltip.$scope.$new();\n tipElement = $tooltip.$element = compileData.link(tipScope, function(clonedElement, scope) {});\n\n // Set the initial positioning. Make the tooltip invisible\n // so IE doesn't try to focus on it off screen.\n tipElement.css({top: '-9999px', left: '-9999px', right: 'auto', display: 'block', visibility: 'hidden'});\n\n // Options: animation\n if(options.animation) tipElement.addClass(options.animation);\n // Options: type\n if(options.type) tipElement.addClass(options.prefixClass + '-' + options.type);\n // Options: custom classes\n if(options.customClass) tipElement.addClass(options.customClass);\n\n // Append the element, without any animations. If we append\n // using $animate.enter, some of the animations cause the placement\n // to be off due to the transforms.\n after ? after.after(tipElement) : parent.prepend(tipElement);\n\n $tooltip.$isShown = scope.$isShown = true;\n safeDigest(scope);\n\n // Now, apply placement\n $tooltip.$applyPlacement();\n\n // Once placed, animate it.\n // Support v1.2+ $animate\n // https://github.com/angular/angular.js/issues/11713\n if(angular.version.minor <= 2) {\n $animate.enter(tipElement, parent, after, enterAnimateCallback);\n } else {\n $animate.enter(tipElement, parent, after).then(enterAnimateCallback);\n }\n safeDigest(scope);\n\n $$rAF(function () {\n // Once the tooltip is placed and the animation starts, make the tooltip visible\n if(tipElement) tipElement.css({visibility: 'visible'});\n });\n\n // Bind events\n if(options.keyboard) {\n if(options.trigger !== 'focus') {\n $tooltip.focus();\n }\n bindKeyboardEvents();\n }\n\n if(options.autoClose) {\n bindAutoCloseEvents();\n }\n\n };\n\n function enterAnimateCallback() {\n scope.$emit(options.prefixEvent + '.show', $tooltip);\n }\n\n $tooltip.leave = function() {\n\n clearTimeout(timeout);\n hoverState = 'out';\n if (!options.delay || !options.delay.hide) {\n return $tooltip.hide();\n }\n timeout = setTimeout(function () {\n if (hoverState === 'out') {\n $tooltip.hide();\n }\n }, options.delay.hide);\n\n };\n\n var _blur;\n var _tipToHide;\n $tooltip.hide = function(blur) {\n\n if(!$tooltip.$isShown) return;\n scope.$emit(options.prefixEvent + '.hide.before', $tooltip);\n\n // store blur value for leaveAnimateCallback to use\n _blur = blur;\n\n // store current tipElement reference to use\n // in leaveAnimateCallback\n _tipToHide = tipElement;\n\n // Support v1.2+ $animate\n // https://github.com/angular/angular.js/issues/11713\n if(angular.version.minor <= 2) {\n $animate.leave(tipElement, leaveAnimateCallback);\n } else {\n $animate.leave(tipElement).then(leaveAnimateCallback);\n }\n\n $tooltip.$isShown = scope.$isShown = false;\n safeDigest(scope);\n\n // Unbind events\n if(options.keyboard && tipElement !== null) {\n unbindKeyboardEvents();\n }\n\n if(options.autoClose && tipElement !== null) {\n unbindAutoCloseEvents();\n }\n };\n\n function leaveAnimateCallback() {\n scope.$emit(options.prefixEvent + '.hide', $tooltip);\n\n // check if current tipElement still references\n // the same element when hide was called\n if (tipElement === _tipToHide) {\n // Allow to blur the input when hidden, like when pressing enter key\n if(_blur && options.trigger === 'focus') {\n return element[0].blur();\n }\n\n // clean up child scopes\n destroyTipElement();\n }\n }\n\n $tooltip.toggle = function() {\n $tooltip.$isShown ? $tooltip.leave() : $tooltip.enter();\n };\n\n $tooltip.focus = function() {\n tipElement[0].focus();\n };\n\n $tooltip.setEnabled = function(isEnabled) {\n options.bsEnabled = isEnabled;\n };\n\n $tooltip.setViewport = function(viewport) {\n options.viewport = viewport;\n };\n\n // Protected methods\n\n $tooltip.$applyPlacement = function() {\n if(!tipElement) return;\n\n // Determine if we're doing an auto or normal placement\n var placement = options.placement,\n autoToken = /\\s?auto?\\s?/i,\n autoPlace = autoToken.test(placement);\n\n if (autoPlace) {\n placement = placement.replace(autoToken, '') || defaults.placement;\n }\n\n // Need to add the position class before we get\n // the offsets\n tipElement.addClass(options.placement);\n\n // Get the position of the target element\n // and the height and width of the tooltip so we can center it.\n var elementPosition = getPosition(),\n tipWidth = tipElement.prop('offsetWidth'),\n tipHeight = tipElement.prop('offsetHeight');\n\n // Refresh viewport position\n $tooltip.$viewport = options.viewport && findElement(options.viewport.selector || options.viewport);\n\n // If we're auto placing, we need to check the positioning\n if (autoPlace) {\n var originalPlacement = placement;\n var viewportPosition = getPosition($tooltip.$viewport);\n\n // Determine if the vertical placement\n if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > viewportPosition.bottom) {\n placement = originalPlacement.replace('bottom', 'top');\n } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < viewportPosition.top) {\n placement = originalPlacement.replace('top', 'bottom');\n }\n\n // Determine the horizontal placement\n // The exotic placements of left and right are opposite of the standard placements. Their arrows are put on the left/right\n // and flow in the opposite direction of their placement.\n if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') &&\n elementPosition.right + tipWidth > viewportPosition.width) {\n\n placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right');\n } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') &&\n elementPosition.left - tipWidth < viewportPosition.left) {\n\n placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left');\n }\n\n tipElement.removeClass(originalPlacement).addClass(placement);\n }\n\n // Get the tooltip's top and left coordinates to center it with this directive.\n var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight);\n applyPlacement(tipPosition, placement);\n };\n\n $tooltip.$onKeyUp = function(evt) {\n if (evt.which === 27 && $tooltip.$isShown) {\n $tooltip.hide();\n evt.stopPropagation();\n }\n };\n\n $tooltip.$onFocusKeyUp = function(evt) {\n if (evt.which === 27) {\n element[0].blur();\n evt.stopPropagation();\n }\n };\n\n $tooltip.$onFocusElementMouseDown = function(evt) {\n evt.preventDefault();\n evt.stopPropagation();\n // Some browsers do not auto-focus buttons (eg. Safari)\n $tooltip.$isShown ? element[0].blur() : element[0].focus();\n };\n\n // bind/unbind events\n function bindTriggerEvents() {\n var triggers = options.trigger.split(' ');\n angular.forEach(triggers, function(trigger) {\n if(trigger === 'click') {\n element.on('click', $tooltip.toggle);\n } else if(trigger !== 'manual') {\n element.on(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);\n element.on(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);\n nodeName === 'button' && trigger !== 'hover' && element.on(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);\n }\n });\n }\n\n function unbindTriggerEvents() {\n var triggers = options.trigger.split(' ');\n for (var i = triggers.length; i--;) {\n var trigger = triggers[i];\n if(trigger === 'click') {\n element.off('click', $tooltip.toggle);\n } else if(trigger !== 'manual') {\n element.off(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);\n element.off(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);\n nodeName === 'button' && trigger !== 'hover' && element.off(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);\n }\n }\n }\n\n function bindKeyboardEvents() {\n if(options.trigger !== 'focus') {\n tipElement.on('keyup', $tooltip.$onKeyUp);\n } else {\n element.on('keyup', $tooltip.$onFocusKeyUp);\n }\n }\n\n function unbindKeyboardEvents() {\n if(options.trigger !== 'focus') {\n tipElement.off('keyup', $tooltip.$onKeyUp);\n } else {\n element.off('keyup', $tooltip.$onFocusKeyUp);\n }\n }\n\n var _autoCloseEventsBinded = false;\n function bindAutoCloseEvents() {\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n // Stop propagation when clicking inside tooltip\n tipElement.on('click', stopEventPropagation);\n\n // Hide when clicking outside tooltip\n $body.on('click', $tooltip.hide);\n\n _autoCloseEventsBinded = true;\n }, 0, false);\n }\n\n function unbindAutoCloseEvents() {\n if (_autoCloseEventsBinded) {\n tipElement.off('click', stopEventPropagation);\n $body.off('click', $tooltip.hide);\n _autoCloseEventsBinded = false;\n }\n }\n\n function stopEventPropagation(event) {\n event.stopPropagation();\n }\n\n // Private methods\n\n function getPosition($element) {\n $element = $element || (options.target || element);\n\n var el = $element[0],\n isBody = el.tagName === 'BODY';\n\n var elRect = el.getBoundingClientRect();\n var rect = {};\n\n // IE8 has issues with angular.extend and using elRect directly.\n // By coping the values of elRect into a new object, we can continue to use extend\n for (var p in elRect) {\n // DO NOT use hasOwnProperty when inspecting the return of getBoundingClientRect.\n rect[p] = elRect[p];\n }\n\n if (rect.width === null) {\n // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093\n rect = angular.extend({}, rect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top });\n }\n var elOffset = isBody ? { top: 0, left: 0 } : dimensions.offset(el),\n scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.prop('scrollTop') || 0 },\n outerDims = isBody ? { width: document.documentElement.clientWidth, height: $window.innerHeight } : null;\n\n return angular.extend({}, rect, scroll, outerDims, elOffset);\n }\n\n function getCalculatedOffset(placement, position, actualWidth, actualHeight) {\n var offset;\n var split = placement.split('-');\n\n switch (split[0]) {\n case 'right':\n offset = {\n top: position.top + position.height / 2 - actualHeight / 2,\n left: position.left + position.width\n };\n break;\n case 'bottom':\n offset = {\n top: position.top + position.height,\n left: position.left + position.width / 2 - actualWidth / 2\n };\n break;\n case 'left':\n offset = {\n top: position.top + position.height / 2 - actualHeight / 2,\n left: position.left - actualWidth\n };\n break;\n default:\n offset = {\n top: position.top - actualHeight,\n left: position.left + position.width / 2 - actualWidth / 2\n };\n break;\n }\n\n if(!split[1]) {\n return offset;\n }\n\n // Add support for corners @todo css\n if(split[0] === 'top' || split[0] === 'bottom') {\n switch (split[1]) {\n case 'left':\n offset.left = position.left;\n break;\n case 'right':\n offset.left = position.left + position.width - actualWidth;\n }\n } else if(split[0] === 'left' || split[0] === 'right') {\n switch (split[1]) {\n case 'top':\n offset.top = position.top - actualHeight;\n break;\n case 'bottom':\n offset.top = position.top + position.height;\n }\n }\n\n return offset;\n }\n\n function applyPlacement(offset, placement) {\n var tip = tipElement[0],\n width = tip.offsetWidth,\n height = tip.offsetHeight;\n\n // manually read margins because getBoundingClientRect includes difference\n var marginTop = parseInt(dimensions.css(tip, 'margin-top'), 10),\n marginLeft = parseInt(dimensions.css(tip, 'margin-left'), 10);\n\n // we must check for NaN for ie 8/9\n if (isNaN(marginTop)) marginTop = 0;\n if (isNaN(marginLeft)) marginLeft = 0;\n\n offset.top = offset.top + marginTop;\n offset.left = offset.left + marginLeft;\n\n // dimensions setOffset doesn't round pixel values\n // so we use setOffset directly with our own function\n dimensions.setOffset(tip, angular.extend({\n using: function (props) {\n tipElement.css({\n top: Math.round(props.top) + 'px',\n left: Math.round(props.left) + 'px',\n right: ''\n });\n }\n }, offset), 0);\n\n // check to see if placing tip in new offset caused the tip to resize itself\n var actualWidth = tip.offsetWidth,\n actualHeight = tip.offsetHeight;\n\n if (placement === 'top' && actualHeight !== height) {\n offset.top = offset.top + height - actualHeight;\n }\n\n // If it's an exotic placement, exit now instead of\n // applying a delta and changing the arrow\n if (/top-left|top-right|bottom-left|bottom-right/.test(placement)) return;\n\n var delta = getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight);\n\n if (delta.left) {\n offset.left += delta.left;\n } else {\n offset.top += delta.top;\n }\n\n dimensions.setOffset(tip, offset);\n\n if (/top|right|bottom|left/.test(placement)) {\n var isVertical = /top|bottom/.test(placement),\n arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight,\n arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight';\n\n replaceArrow(arrowDelta, tip[arrowOffsetPosition], isVertical);\n }\n }\n\n // @source https://github.com/twbs/bootstrap/blob/v3.3.5/js/tooltip.js#L380\n function getViewportAdjustedDelta(placement, position, actualWidth, actualHeight) {\n var delta = {top: 0, left: 0};\n if (!$tooltip.$viewport) return delta;\n\n var viewportPadding = options.viewport && options.viewport.padding || 0;\n var viewportDimensions = getPosition($tooltip.$viewport);\n\n if (/right|left/.test(placement)) {\n var topEdgeOffset = position.top - viewportPadding - viewportDimensions.scroll;\n var bottomEdgeOffset = position.top + viewportPadding - viewportDimensions.scroll + actualHeight;\n if (topEdgeOffset < viewportDimensions.top) { // top overflow\n delta.top = viewportDimensions.top - topEdgeOffset;\n } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow\n delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset;\n }\n } else {\n var leftEdgeOffset = position.left - viewportPadding;\n var rightEdgeOffset = position.left + viewportPadding + actualWidth;\n if (leftEdgeOffset < viewportDimensions.left) { // left overflow\n delta.left = viewportDimensions.left - leftEdgeOffset;\n } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow\n delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset;\n }\n }\n\n return delta;\n }\n\n function replaceArrow(delta, dimension, isHorizontal) {\n var $arrow = findElement('.tooltip-arrow, .arrow', tipElement[0]);\n\n $arrow.css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')\n .css(isHorizontal ? 'top' : 'left', '');\n }\n\n function destroyTipElement() {\n // Cancel pending callbacks\n clearTimeout(timeout);\n\n if($tooltip.$isShown && tipElement !== null) {\n if(options.autoClose) {\n unbindAutoCloseEvents();\n }\n\n if(options.keyboard) {\n unbindKeyboardEvents();\n }\n }\n\n if(tipScope) {\n tipScope.$destroy();\n tipScope = null;\n }\n\n if(tipElement) {\n tipElement.remove();\n tipElement = $tooltip.$element = null;\n }\n }\n\n return $tooltip;\n\n }\n\n // Helper functions\n\n function safeDigest(scope) {\n scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();\n }\n\n function findElement(query, element) {\n return angular.element((element || document).querySelectorAll(query));\n }\n\n var fetchPromises = {};\n function fetchTemplate(template) {\n if(fetchPromises[template]) return fetchPromises[template];\n return (fetchPromises[template] = $http.get(template, {cache: $templateCache}).then(function(res) {\n return res.data;\n }));\n }\n\n return TooltipFactory;\n\n };\n\n })\n\n .directive('bsTooltip', function($window, $location, $sce, $tooltip, $$rAF) {\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'backdropAnimation', 'type', 'customClass', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key]))\n options[key] = false;\n });\n\n // should not parse target attribute (anchor tag), only data-target #1454\n var dataTarget = element.attr('data-target');\n if(angular.isDefined(dataTarget)) {\n if(falseValueRegExp.test(dataTarget))\n options.target = false;\n else\n options.target = dataTarget;\n }\n\n // overwrite inherited title value when no value specified\n // fix for angular 1.3.1 531a8de72c439d8ddd064874bf364c00cedabb11\n if (!scope.hasOwnProperty('title')){\n scope.title = '';\n }\n\n // Observe scope attributes for change\n attr.$observe('title', function(newValue) {\n if (angular.isDefined(newValue) || !scope.hasOwnProperty('title')) {\n var oldValue = scope.title;\n scope.title = $sce.trustAsHtml(newValue);\n angular.isDefined(oldValue) && $$rAF(function() {\n tooltip && tooltip.$applyPlacement();\n });\n }\n });\n\n // Support scope as an object\n attr.bsTooltip && scope.$watch(attr.bsTooltip, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.title = newValue;\n }\n angular.isDefined(oldValue) && $$rAF(function() {\n tooltip && tooltip.$applyPlacement();\n });\n }, true);\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!tooltip || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(tooltip),?/i);\n newValue === true ? tooltip.show() : tooltip.hide();\n });\n\n // Enabled binding support\n attr.bsEnabled && scope.$watch(attr.bsEnabled, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.bsEnabled, newValue, oldValue);\n if(!tooltip || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|1|,?(tooltip),?/i);\n newValue === false ? tooltip.setEnabled(false) : tooltip.setEnabled(true);\n });\n\n // Viewport support\n attr.viewport && scope.$watch(attr.viewport, function (newValue) {\n if(!tooltip || !angular.isDefined(newValue)) return;\n tooltip.setViewport(newValue);\n });\n\n // Initialize popover\n var tooltip = $tooltip(element, options);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if(tooltip) tooltip.destroy();\n options = null;\n tooltip = null;\n });\n\n }\n };\n\n });\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/dist/modules/tooltip.tpl.js b/dist/modules/tooltip.tpl.js index 9329124cb..f102ef529 100644 --- a/dist/modules/tooltip.tpl.js +++ b/dist/modules/tooltip.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @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 a59b5cafe..543253042 100644 --- a/dist/modules/tooltip.tpl.min.js +++ b/dist/modules/tooltip.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/typeahead.js b/dist/modules/typeahead.js index ad8864f8e..3e220c866 100644 --- a/dist/modules/typeahead.js +++ b/dist/modules/typeahead.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -20,7 +20,7 @@ angular.module('mgcrea.ngStrap.typeahead', [ 'mgcrea.ngStrap.tooltip', 'mgcrea.n html: false, delay: 0, minLength: 1, - filter: 'filter', + filter: 'bsAsyncFilter', limit: 6, autoSelect: false, comparator: '', @@ -129,7 +129,17 @@ angular.module('mgcrea.ngStrap.typeahead', [ 'mgcrea.ngStrap.tooltip', 'mgcrea.n TypeaheadFactory.defaults = defaults; return TypeaheadFactory; } ]; -}).directive('bsTypeahead', [ '$window', '$parse', '$q', '$typeahead', '$parseOptions', function($window, $parse, $q, $typeahead, $parseOptions) { +}).filter('bsAsyncFilter', [ '$filter', function($filter) { + return function(array, expression, comparator) { + if (array && angular.isFunction(array.then)) { + return array.then(function(results) { + return $filter('filter')(results, expression, comparator); + }); + } else { + return $filter('filter')(array, expression, comparator); + } + }; +} ]).directive('bsTypeahead', [ '$window', '$parse', '$q', '$typeahead', '$parseOptions', function($window, $parse, $q, $typeahead, $parseOptions) { var defaults = $typeahead.defaults; return { restrict: 'EAC', @@ -181,14 +191,18 @@ angular.module('mgcrea.ngStrap.typeahead', [ 'mgcrea.ngStrap.tooltip', 'mgcrea.n }); controller.$formatters.push(function(modelValue) { var displayValue = parsedOptions.displayValue(modelValue); - if (displayValue) return displayValue; + if (displayValue) { + return displayValue; + } if (modelValue && typeof modelValue !== 'object') { return modelValue; } return ''; }); controller.$render = function() { - if (controller.$isEmpty(controller.$viewValue)) return element.val(''); + if (controller.$isEmpty(controller.$viewValue)) { + return element.val(''); + } var index = typeahead.$getIndex(controller.$modelValue); var selected = angular.isDefined(index) ? typeahead.$scope.$matches[index].label : controller.$viewValue; selected = angular.isObject(selected) ? parsedOptions.displayValue(selected) : selected; diff --git a/dist/modules/typeahead.min.js b/dist/modules/typeahead.min.js index c9039d542..852b30f0d 100644 --- a/dist/modules/typeahead.min.js +++ b/dist/modules/typeahead.min.js @@ -1,9 +1,9 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT */ -'use strict';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',templateUrl:'typeahead/typeahead.tpl.html',trigger:'focus',container:!1,keyboard:!0,html:!1,delay:0,minLength:1,filter:'filter',limit:6,autoSelect:!1,comparator:'',trimValue:!0};this.$get=['$window','$rootScope','$tooltip','$$rAF','$timeout',function(t,n,a,i,o){function r(t,n,r){var c={},s=angular.extend({},e,r);c=a(t,s);var u=r.scope,$=c.$scope;$.$resetMatches=function(){$.$matches=[],$.$activeIndex=s.autoSelect?0:-1},$.$resetMatches(),$.$activate=function(e){$.$$postDigest(function(){c.activate(e)})},$.$select=function(e,t){$.$$postDigest(function(){c.select(e)})},$.$isVisible=function(){return c.$isVisible()},c.update=function(e){$.$matches=e,$.$activeIndex>=e.length&&($.$activeIndex=s.autoSelect?0:-1),l($),i(c.$applyPlacement)},c.activate=function(e){$.$activeIndex=e},c.select=function(e){if(-1!==e){var t=$.$matches[e].value;n.$setViewValue(t),n.$render(),$.$resetMatches(),u&&u.$digest(),$.$emit(s.prefixEvent+'.select',t,e,c)}},c.$isVisible=function(){return s.minLength&&n?$.$matches.length&&angular.isString(n.$viewValue)&&n.$viewValue.length>=s.minLength:!!$.$matches.length},c.$getIndex=function(e){var t=$.$matches.length,n=t;if(t){for(n=t;n--&&$.$matches[n].value!==e;);if(!(0>n))return n}},c.$onMouseDown=function(e){e.preventDefault(),e.stopPropagation()},c.$onKeyDown=function(e){/(38|40|13)/.test(e.keyCode)&&(!c.$isVisible()||13===e.keyCode&&-1===$.$activeIndex||(e.preventDefault(),e.stopPropagation()),13===e.keyCode&&$.$matches.length?c.select($.$activeIndex):38===e.keyCode&&$.$activeIndex>0?$.$activeIndex--:40===e.keyCode&&$.$activeIndex<$.$matches.length-1?$.$activeIndex++:angular.isUndefined($.$activeIndex)&&($.$activeIndex=0),$.$digest())};var d=c.show;c.show=function(){d(),o(function(){c.$element&&c.$element.on('mousedown',c.$onMouseDown),s.keyboard&&t&&t.on('keydown',c.$onKeyDown)},0,!1)};var f=c.hide;return c.hide=function(){c.$element&&c.$element.off('mousedown',c.$onMouseDown),s.keyboard&&t&&t.off('keydown',c.$onKeyDown),s.autoSelect||c.activate(-1),f()},c}function l(e){e.$$phase||e.$root&&e.$root.$$phase||e.$digest()}angular.element(t.document.body);return r.defaults=e,r}]}).directive('bsTypeahead',['$window','$parse','$q','$typeahead','$parseOptions',function(e,t,n,a,i){var o=a.defaults;return{restrict:'EAC',require:'ngModel',link:function(e,t,n,r){var l={scope:e};angular.forEach(['template','templateUrl','controller','controllerAs','placement','container','delay','trigger','keyboard','html','animation','filter','limit','minLength','watchOptions','selectMode','autoSelect','comparator','id','prefixEvent','prefixClass'],function(e){angular.isDefined(n[e])&&(l[e]=n[e])});var c=/^(false|0|)$/i;angular.forEach(['html','container','trimValue'],function(e){angular.isDefined(n[e])&&c.test(n[e])&&(l[e]=!1)}),t.attr('autocomplete','false');var s=l.filter||o.filter,u=l.limit||o.limit,$=l.comparator||o.comparator,d=n.bsOptions;s&&(d+=' | '+s+':$viewValue'),$&&(d+=':'+$),u&&(d+=' | limitTo:'+u);var f=i(d),p=a(t,r,l);if(l.watchOptions){var m=f.$match[7].replace(/\|.+/,'').replace(/\(.*\)/g,'').trim();e.$watchCollection(m,function(t,n){f.valuesFn(e,r).then(function(e){p.update(e),r.$render()})})}e.$watch(n.ngModel,function(t,n){e.$modelValue=t,f.valuesFn(e,r).then(function(e){if(l.selectMode&&!e.length&&t.length>0)return void r.$setViewValue(r.$viewValue.substring(0,r.$viewValue.length-1));e.length>u&&(e=e.slice(0,u));var n=p.$isVisible();n&&p.update(e),(1!==e.length||e[0].value!==t)&&(!n&&p.update(e),r.$render())})}),r.$formatters.push(function(e){var t=f.displayValue(e);return t?t:e&&'object'!=typeof e?e:''}),r.$render=function(){if(r.$isEmpty(r.$viewValue))return t.val('');var e=p.$getIndex(r.$modelValue),n=angular.isDefined(e)?p.$scope.$matches[e].label:r.$viewValue;n=angular.isObject(n)?f.displayValue(n):n;var a=n?n.toString().replace(/<(?:.|\n)*?>/gm,''):'';t.val(l.trimValue===!1?a:a.trim())},e.$on('$destroy',function(){p&&p.destroy(),l=null,p=null})}}}]); +'use strict';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',templateUrl:'typeahead/typeahead.tpl.html',trigger:'focus',container:!1,keyboard:!0,html:!1,delay:0,minLength:1,filter:'bsAsyncFilter',limit:6,autoSelect:!1,comparator:'',trimValue:!0};this.$get=['$window','$rootScope','$tooltip','$$rAF','$timeout',function(t,n,a,i,o){function r(t,n,r){var c={},u=angular.extend({},e,r);c=a(t,u);var s=r.scope,$=c.$scope;$.$resetMatches=function(){$.$matches=[],$.$activeIndex=u.autoSelect?0:-1},$.$resetMatches(),$.$activate=function(e){$.$$postDigest(function(){c.activate(e)})},$.$select=function(e,t){$.$$postDigest(function(){c.select(e)})},$.$isVisible=function(){return c.$isVisible()},c.update=function(e){$.$matches=e,$.$activeIndex>=e.length&&($.$activeIndex=u.autoSelect?0:-1),l($),i(c.$applyPlacement)},c.activate=function(e){$.$activeIndex=e},c.select=function(e){if(-1!==e){var t=$.$matches[e].value;n.$setViewValue(t),n.$render(),$.$resetMatches(),s&&s.$digest(),$.$emit(u.prefixEvent+'.select',t,e,c)}},c.$isVisible=function(){return u.minLength&&n?$.$matches.length&&angular.isString(n.$viewValue)&&n.$viewValue.length>=u.minLength:!!$.$matches.length},c.$getIndex=function(e){var t=$.$matches.length,n=t;if(t){for(n=t;n--&&$.$matches[n].value!==e;);if(!(0>n))return n}},c.$onMouseDown=function(e){e.preventDefault(),e.stopPropagation()},c.$onKeyDown=function(e){/(38|40|13)/.test(e.keyCode)&&(!c.$isVisible()||13===e.keyCode&&-1===$.$activeIndex||(e.preventDefault(),e.stopPropagation()),13===e.keyCode&&$.$matches.length?c.select($.$activeIndex):38===e.keyCode&&$.$activeIndex>0?$.$activeIndex--:40===e.keyCode&&$.$activeIndex<$.$matches.length-1?$.$activeIndex++:angular.isUndefined($.$activeIndex)&&($.$activeIndex=0),$.$digest())};var d=c.show;c.show=function(){d(),o(function(){c.$element&&c.$element.on('mousedown',c.$onMouseDown),u.keyboard&&t&&t.on('keydown',c.$onKeyDown)},0,!1)};var f=c.hide;return c.hide=function(){c.$element&&c.$element.off('mousedown',c.$onMouseDown),u.keyboard&&t&&t.off('keydown',c.$onKeyDown),u.autoSelect||c.activate(-1),f()},c}function l(e){e.$$phase||e.$root&&e.$root.$$phase||e.$digest()}angular.element(t.document.body);return r.defaults=e,r}]}).filter('bsAsyncFilter',['$filter',function(e){return function(t,n,a){return t&&angular.isFunction(t.then)?t.then(function(t){return e('filter')(t,n,a)}):e('filter')(t,n,a)}}]).directive('bsTypeahead',['$window','$parse','$q','$typeahead','$parseOptions',function(e,t,n,a,i){var o=a.defaults;return{restrict:'EAC',require:'ngModel',link:function(e,t,n,r){var l={scope:e};angular.forEach(['template','templateUrl','controller','controllerAs','placement','container','delay','trigger','keyboard','html','animation','filter','limit','minLength','watchOptions','selectMode','autoSelect','comparator','id','prefixEvent','prefixClass'],function(e){angular.isDefined(n[e])&&(l[e]=n[e])});var c=/^(false|0|)$/i;angular.forEach(['html','container','trimValue'],function(e){angular.isDefined(n[e])&&c.test(n[e])&&(l[e]=!1)}),t.attr('autocomplete','false');var u=l.filter||o.filter,s=l.limit||o.limit,$=l.comparator||o.comparator,d=n.bsOptions;u&&(d+=' | '+u+':$viewValue'),$&&(d+=':'+$),s&&(d+=' | limitTo:'+s);var f=i(d),p=a(t,r,l);if(l.watchOptions){var m=f.$match[7].replace(/\|.+/,'').replace(/\(.*\)/g,'').trim();e.$watchCollection(m,function(t,n){f.valuesFn(e,r).then(function(e){p.update(e),r.$render()})})}e.$watch(n.ngModel,function(t,n){e.$modelValue=t,f.valuesFn(e,r).then(function(e){if(l.selectMode&&!e.length&&t.length>0)return void r.$setViewValue(r.$viewValue.substring(0,r.$viewValue.length-1));e.length>s&&(e=e.slice(0,s));var n=p.$isVisible();n&&p.update(e),(1!==e.length||e[0].value!==t)&&(!n&&p.update(e),r.$render())})}),r.$formatters.push(function(e){var t=f.displayValue(e);return t?t:e&&'object'!=typeof e?e:''}),r.$render=function(){if(r.$isEmpty(r.$viewValue))return t.val('');var e=p.$getIndex(r.$modelValue),n=angular.isDefined(e)?p.$scope.$matches[e].label:r.$viewValue;n=angular.isObject(n)?f.displayValue(n):n;var a=n?n.toString().replace(/<(?:.|\n)*?>/gm,''):'';t.val(l.trimValue===!1?a:a.trim())},e.$on('$destroy',function(){p&&p.destroy(),l=null,p=null})}}}]); //# sourceMappingURL=../modules/typeahead.min.js.map \ No newline at end of file diff --git a/dist/modules/typeahead.min.js.map b/dist/modules/typeahead.min.js.map index eb0394f83..c134956d3 100644 --- a/dist/modules/typeahead.min.js.map +++ b/dist/modules/typeahead.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["modules/typeahead.js"],"names":["angular","trigger","provider","container","this","defaults","keyboard","html","delay","minLength","filter","limit","autoSelect","comparator","trimValue","$get","bodyEl","$typeahead","options","scope","$scope","$matches","extend","config","$resetMatches","$$postDigest","activate","$activeIndex","select","index","$select","evt","matches","$isVisible","safeDigest","update","$$rAF","value","controller","$render","$emit","prefixEvent","parentScope","length","l","isString","$viewValue","i","preventDefault","stopPropagation","keyCode","$digest","show","$timeout","$element","$onMouseDown","hide","on","$onKeyDown","element","TypeaheadFactory","$$phase","$root","$window","document","body","link","require","directive","restrict","falseValueRegExp","attr","key","bsOptions","test","parsedOptions","$parseOptions","typeahead","watchOptions","watchedOptions","$watchCollection","values","$match","replace","trim","$watch","ngModel","newValue","oldValue","$modelValue","valuesFn","selectMode","isVisible","slice","$formatters","displayValue","modelValue","push","$getIndex","selected","$on","$isEmpty","val","destroy","isDefined","label","isObject","toString"],"mappings":"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","file":"modules/typeahead.min.js","sourcesContent":["'use strict';\n\nangular.module('mgcrea.ngStrap.typeahead', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions'])\n\n .provider('$typeahead', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'typeahead',\n prefixEvent: '$typeahead',\n placement: 'bottom-left',\n templateUrl: 'typeahead/typeahead.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n minLength: 1,\n filter: 'filter',\n limit: 6,\n autoSelect: false,\n comparator: '',\n trimValue: true\n };\n\n this.$get = function($window, $rootScope, $tooltip, $$rAF, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n\n function TypeaheadFactory(element, controller, config) {\n\n var $typeahead = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $typeahead = $tooltip(element, options);\n var parentScope = config.scope;\n var scope = $typeahead.$scope;\n\n scope.$resetMatches = function(){\n scope.$matches = [];\n scope.$activeIndex = options.autoSelect ? 0 : -1; // If set to 0, the first match will be highlighted\n };\n scope.$resetMatches();\n\n scope.$activate = function(index) {\n scope.$$postDigest(function() {\n $typeahead.activate(index);\n });\n };\n\n scope.$select = function(index, evt) {\n scope.$$postDigest(function() {\n $typeahead.select(index);\n });\n };\n\n scope.$isVisible = function() {\n return $typeahead.$isVisible();\n };\n\n // Public methods\n\n $typeahead.update = function(matches) {\n scope.$matches = matches;\n if(scope.$activeIndex >= matches.length) {\n scope.$activeIndex = options.autoSelect ? 0: -1;\n }\n\n // wrap in a $timeout so the results are updated\n // before repositioning\n safeDigest(scope);\n $$rAF($typeahead.$applyPlacement);\n };\n\n $typeahead.activate = function(index) {\n scope.$activeIndex = index;\n };\n\n $typeahead.select = function(index) {\n if(index === -1) return;\n var value = scope.$matches[index].value;\n // console.log('$setViewValue', value);\n controller.$setViewValue(value);\n controller.$render();\n scope.$resetMatches();\n if(parentScope) parentScope.$digest();\n // Emit event\n scope.$emit(options.prefixEvent + '.select', value, index, $typeahead);\n };\n\n // Protected methods\n\n $typeahead.$isVisible = function() {\n if(!options.minLength || !controller) {\n return !!scope.$matches.length;\n }\n // minLength support\n return scope.$matches.length && angular.isString(controller.$viewValue) && controller.$viewValue.length >= options.minLength;\n };\n\n $typeahead.$getIndex = function(value) {\n var l = scope.$matches.length, i = l;\n if(!l) return;\n for(i = l; i--;) {\n if(scope.$matches[i].value === value) break;\n }\n if(i < 0) return;\n return i;\n };\n\n $typeahead.$onMouseDown = function(evt) {\n // Prevent blur on mousedown\n evt.preventDefault();\n evt.stopPropagation();\n };\n\n $typeahead.$onKeyDown = function(evt) {\n if(!/(38|40|13)/.test(evt.keyCode)) return;\n\n // Let ngSubmit pass if the typeahead tip is hidden or no option is selected\n if($typeahead.$isVisible() && !(evt.keyCode === 13 && scope.$activeIndex === -1)) {\n evt.preventDefault();\n evt.stopPropagation();\n }\n\n // Select with enter\n if(evt.keyCode === 13 && scope.$matches.length) {\n $typeahead.select(scope.$activeIndex);\n }\n\n // Navigate with keyboard\n else if(evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--;\n else if(evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++;\n else if(angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0;\n scope.$digest();\n };\n\n // Overrides\n\n var show = $typeahead.show;\n $typeahead.show = function() {\n show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed immediately.\n $timeout(function() {\n $typeahead.$element && $typeahead.$element.on('mousedown', $typeahead.$onMouseDown);\n if(options.keyboard) {\n element && element.on('keydown', $typeahead.$onKeyDown);\n }\n }, 0, false);\n };\n\n var hide = $typeahead.hide;\n $typeahead.hide = function() {\n $typeahead.$element && $typeahead.$element.off('mousedown', $typeahead.$onMouseDown);\n if(options.keyboard) {\n element && element.off('keydown', $typeahead.$onKeyDown);\n }\n if(!options.autoSelect)\n $typeahead.activate(-1);\n hide();\n };\n\n return $typeahead;\n\n }\n\n // Helper functions\n\n function safeDigest(scope) {\n scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();\n }\n\n TypeaheadFactory.defaults = defaults;\n return TypeaheadFactory;\n\n };\n\n })\n\n .directive('bsTypeahead', function($window, $parse, $q, $typeahead, $parseOptions) {\n\n var defaults = $typeahead.defaults;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'filter', 'limit', 'minLength', 'watchOptions', 'selectMode', 'autoSelect', 'comparator', 'id', 'prefixEvent', 'prefixClass'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'trimValue'], function(key) {\n if(angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false;\n });\n\n // Disable browser autocompletion\n element.attr('autocomplete' ,'false');\n\n // Build proper bsOptions\n var filter = options.filter || defaults.filter;\n var limit = options.limit || defaults.limit;\n var comparator = options.comparator || defaults.comparator;\n\n var bsOptions = attr.bsOptions;\n if(filter) bsOptions += ' | ' + filter + ':$viewValue';\n if (comparator) bsOptions += ':' + comparator;\n if(limit) bsOptions += ' | limitTo:' + limit;\n var parsedOptions = $parseOptions(bsOptions);\n\n // Initialize typeahead\n var typeahead = $typeahead(element, controller, options);\n\n // Watch options on demand\n if(options.watchOptions) {\n // Watch bsOptions values before filtering for changes, drop function calls\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').replace(/\\(.*\\)/g, '').trim();\n scope.$watchCollection(watchedOptions, function (newValue, oldValue) {\n // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue);\n parsedOptions.valuesFn(scope, controller).then(function (values) {\n typeahead.update(values);\n controller.$render();\n });\n });\n }\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('$watch', element.attr('ng-model'), newValue);\n scope.$modelValue = newValue; // Publish modelValue on scope for custom templates\n parsedOptions.valuesFn(scope, controller)\n .then(function(values) {\n // Prevent input with no future prospect if selectMode is truthy\n // @TODO test selectMode\n if(options.selectMode && !values.length && newValue.length > 0) {\n controller.$setViewValue(controller.$viewValue.substring(0, controller.$viewValue.length - 1));\n return;\n }\n if(values.length > limit) values = values.slice(0, limit);\n var isVisible = typeahead.$isVisible();\n isVisible && typeahead.update(values);\n // Do not re-queue an update if a correct value has been selected\n if(values.length === 1 && values[0].value === newValue) return;\n !isVisible && typeahead.update(values);\n // Queue a new rendering that will leverage collection loading\n controller.$render();\n });\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var displayValue = parsedOptions.displayValue(modelValue);\n\n // If we can determine the displayValue, use that\n if (displayValue) return displayValue;\n\n // If there's no display value, attempt to use the modelValue.\n // If the model is an object not much we can do\n if (modelValue && typeof modelValue !== 'object') {\n return modelValue;\n }\n return '';\n });\n\n // Model rendering in view\n controller.$render = function () {\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n if(controller.$isEmpty(controller.$viewValue)) return element.val('');\n var index = typeahead.$getIndex(controller.$modelValue);\n var selected = angular.isDefined(index) ? typeahead.$scope.$matches[index].label : controller.$viewValue;\n selected = angular.isObject(selected) ? parsedOptions.displayValue(selected) : selected;\n var value = selected ? selected.toString().replace(/<(?:.|\\n)*?>/gm, '') : '';\n element.val(options.trimValue === false ? value : value.trim());\n };\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (typeahead) typeahead.destroy();\n options = null;\n typeahead = null;\n });\n\n }\n };\n\n });\n"],"sourceRoot":"/source/"} \ No newline at end of file +{"version":3,"sources":["modules/typeahead.js"],"names":["angular","trigger","provider","container","this","defaults","keyboard","html","delay","minLength","filter","limit","autoSelect","comparator","trimValue","$get","bodyEl","$typeahead","options","scope","$scope","$matches","extend","config","$resetMatches","$$postDigest","activate","$activeIndex","select","index","$select","evt","matches","$isVisible","safeDigest","update","$$rAF","value","controller","$render","$emit","prefixEvent","parentScope","length","l","isString","$viewValue","i","preventDefault","stopPropagation","keyCode","$digest","show","$timeout","$element","$onMouseDown","hide","on","$onKeyDown","element","TypeaheadFactory","array","isFunction","then","$$phase","$window","document","body","$filter","expression","directive","results","restrict","require","link","falseValueRegExp","attr","key","bsOptions","test","parsedOptions","$parseOptions","typeahead","watchOptions","watchedOptions","$watchCollection","values","$match","replace","trim","$watch","ngModel","newValue","oldValue","$modelValue","valuesFn","selectMode","isVisible","slice","$formatters","displayValue","push","modelValue","selected","val","destroy","isDefined","label","isObject","toString","$on"],"mappings":"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","file":"modules/typeahead.min.js","sourcesContent":["'use strict';\n\nangular.module('mgcrea.ngStrap.typeahead', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions'])\n\n .provider('$typeahead', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'typeahead',\n prefixEvent: '$typeahead',\n placement: 'bottom-left',\n templateUrl: 'typeahead/typeahead.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n minLength: 1,\n filter: 'bsAsyncFilter',\n limit: 6,\n autoSelect: false,\n comparator: '',\n trimValue: true\n };\n\n this.$get = function($window, $rootScope, $tooltip, $$rAF, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n\n function TypeaheadFactory(element, controller, config) {\n\n var $typeahead = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $typeahead = $tooltip(element, options);\n var parentScope = config.scope;\n var scope = $typeahead.$scope;\n\n scope.$resetMatches = function() {\n scope.$matches = [];\n scope.$activeIndex = options.autoSelect ? 0 : -1; // If set to 0, the first match will be highlighted\n };\n scope.$resetMatches();\n\n scope.$activate = function(index) {\n scope.$$postDigest(function() {\n $typeahead.activate(index);\n });\n };\n\n scope.$select = function(index, evt) {\n scope.$$postDigest(function() {\n $typeahead.select(index);\n });\n };\n\n scope.$isVisible = function() {\n return $typeahead.$isVisible();\n };\n\n // Public methods\n\n $typeahead.update = function(matches) {\n scope.$matches = matches;\n if (scope.$activeIndex >= matches.length) {\n scope.$activeIndex = options.autoSelect ? 0 : -1;\n }\n\n // wrap in a $timeout so the results are updated\n // before repositioning\n safeDigest(scope);\n $$rAF($typeahead.$applyPlacement);\n };\n\n $typeahead.activate = function(index) {\n scope.$activeIndex = index;\n };\n\n $typeahead.select = function(index) {\n if (index === -1) return;\n var value = scope.$matches[index].value;\n // console.log('$setViewValue', value);\n controller.$setViewValue(value);\n controller.$render();\n scope.$resetMatches();\n if (parentScope) parentScope.$digest();\n // Emit event\n scope.$emit(options.prefixEvent + '.select', value, index, $typeahead);\n };\n\n // Protected methods\n\n $typeahead.$isVisible = function() {\n if (!options.minLength || !controller) {\n return !!scope.$matches.length;\n }\n // minLength support\n return scope.$matches.length && angular.isString(controller.$viewValue) && controller.$viewValue.length >= options.minLength;\n };\n\n $typeahead.$getIndex = function(value) {\n var l = scope.$matches.length,\n i = l;\n if (!l) return;\n for (i = l; i--;) {\n if (scope.$matches[i].value === value) break;\n }\n if (i < 0) return;\n return i;\n };\n\n $typeahead.$onMouseDown = function(evt) {\n // Prevent blur on mousedown\n evt.preventDefault();\n evt.stopPropagation();\n };\n\n $typeahead.$onKeyDown = function(evt) {\n if (!/(38|40|13)/.test(evt.keyCode)) return;\n\n // Let ngSubmit pass if the typeahead tip is hidden or no option is selected\n if ($typeahead.$isVisible() && !(evt.keyCode === 13 && scope.$activeIndex === -1)) {\n evt.preventDefault();\n evt.stopPropagation();\n }\n\n // Select with enter\n if (evt.keyCode === 13 && scope.$matches.length) {\n $typeahead.select(scope.$activeIndex);\n }\n\n // Navigate with keyboard\n else if (evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--;\n else if (evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++;\n else if (angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0;\n scope.$digest();\n };\n\n // Overrides\n\n var show = $typeahead.show;\n $typeahead.show = function() {\n show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed immediately.\n $timeout(function() {\n $typeahead.$element && $typeahead.$element.on('mousedown', $typeahead.$onMouseDown);\n if (options.keyboard) {\n element && element.on('keydown', $typeahead.$onKeyDown);\n }\n }, 0, false);\n };\n\n var hide = $typeahead.hide;\n $typeahead.hide = function() {\n $typeahead.$element && $typeahead.$element.off('mousedown', $typeahead.$onMouseDown);\n if (options.keyboard) {\n element && element.off('keydown', $typeahead.$onKeyDown);\n }\n if (!options.autoSelect)\n $typeahead.activate(-1);\n hide();\n };\n\n return $typeahead;\n\n }\n\n // Helper functions\n\n function safeDigest(scope) {\n scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();\n }\n\n TypeaheadFactory.defaults = defaults;\n return TypeaheadFactory;\n\n };\n\n })\n\n .filter('bsAsyncFilter', function($filter) {\n return function(array, expression, comparator) {\n if (array && angular.isFunction(array.then)) {\n return array.then(function(results) {\n return $filter('filter')(results, expression, comparator);\n });\n } else {\n return $filter('filter')(array, expression, comparator);\n }\n };\n })\n\n .directive('bsTypeahead', function($window, $parse, $q, $typeahead, $parseOptions) {\n\n var defaults = $typeahead.defaults;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {\n scope: scope\n };\n angular.forEach(['template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'filter', 'limit', 'minLength', 'watchOptions', 'selectMode', 'autoSelect', 'comparator', 'id', 'prefixEvent', 'prefixClass'], function(key) {\n if (angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // use string regex match boolean attr falsy values, leave truthy values be\n var falseValueRegExp = /^(false|0|)$/i;\n angular.forEach(['html', 'container', 'trimValue'], function(key) {\n if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false;\n });\n\n // Disable browser autocompletion\n element.attr('autocomplete', 'false');\n\n // Build proper bsOptions\n var filter = options.filter || defaults.filter;\n var limit = options.limit || defaults.limit;\n var comparator = options.comparator || defaults.comparator;\n\n var bsOptions = attr.bsOptions;\n if (filter) bsOptions += ' | ' + filter + ':$viewValue';\n if (comparator) bsOptions += ':' + comparator;\n if (limit) bsOptions += ' | limitTo:' + limit;\n var parsedOptions = $parseOptions(bsOptions);\n\n // Initialize typeahead\n var typeahead = $typeahead(element, controller, options);\n\n // Watch options on demand\n if (options.watchOptions) {\n // Watch bsOptions values before filtering for changes, drop function calls\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').replace(/\\(.*\\)/g, '').trim();\n scope.$watchCollection(watchedOptions, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue);\n parsedOptions.valuesFn(scope, controller).then(function(values) {\n typeahead.update(values);\n controller.$render();\n });\n });\n }\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('$watch', element.attr('ng-model'), newValue);\n scope.$modelValue = newValue; // Publish modelValue on scope for custom templates\n parsedOptions.valuesFn(scope, controller)\n .then(function(values) {\n // Prevent input with no future prospect if selectMode is truthy\n // @TODO test selectMode\n if (options.selectMode && !values.length && newValue.length > 0) {\n controller.$setViewValue(controller.$viewValue.substring(0, controller.$viewValue.length - 1));\n return;\n }\n if (values.length > limit) values = values.slice(0, limit);\n var isVisible = typeahead.$isVisible();\n isVisible && typeahead.update(values);\n // Do not re-queue an update if a correct value has been selected\n if (values.length === 1 && values[0].value === newValue) return;\n !isVisible && typeahead.update(values);\n // Queue a new rendering that will leverage collection loading\n controller.$render();\n });\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var displayValue = parsedOptions.displayValue(modelValue);\n\n // If we can determine the displayValue, use that\n if (displayValue) {\n return displayValue;\n }\n\n // If there's no display value, attempt to use the modelValue.\n // If the model is an object not much we can do\n if (modelValue && typeof modelValue !== 'object') {\n return modelValue;\n }\n return '';\n });\n\n // Model rendering in view\n controller.$render = function() {\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n if (controller.$isEmpty(controller.$viewValue)) {\n return element.val('');\n }\n var index = typeahead.$getIndex(controller.$modelValue);\n var selected = angular.isDefined(index) ? typeahead.$scope.$matches[index].label : controller.$viewValue;\n selected = angular.isObject(selected) ? parsedOptions.displayValue(selected) : selected;\n var value = selected ? selected.toString().replace(/<(?:.|\\n)*?>/gm, '') : '';\n element.val(options.trimValue === false ? value : value.trim());\n };\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (typeahead) typeahead.destroy();\n options = null;\n typeahead = null;\n });\n\n }\n };\n\n });\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/dist/modules/typeahead.tpl.js b/dist/modules/typeahead.tpl.js index 38600a6ae..161aadc0a 100644 --- a/dist/modules/typeahead.tpl.js +++ b/dist/modules/typeahead.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @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 ee51ea799..01c04f814 100644 --- a/dist/modules/typeahead.tpl.min.js +++ b/dist/modules/typeahead.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.0 - 2015-07-12 + * @version v2.3.1 - 2015-07-19 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/docs/scripts/app.js b/docs/scripts/app.js index 7b95406ac..1be77a6ba 100644 --- a/docs/scripts/app.js +++ b/docs/scripts/app.js @@ -4,7 +4,7 @@ angular.module('mgcrea.ngStrapDocs', ['mgcrea.ngStrap', 'mgcrea.ngPlunkr', 'ngRoute', 'ngAnimate']) -.constant('version', 'v2.3.0') +.constant('version', 'v2.3.1') .config(function($plunkrProvider, version) { diff --git a/docs/scripts/services/angular-plunkr.js b/docs/scripts/services/angular-plunkr.js index ab39c8f5e..8016aa3c5 100644 --- a/docs/scripts/services/angular-plunkr.js +++ b/docs/scripts/services/angular-plunkr.js @@ -4,7 +4,7 @@ angular.module('mgcrea.ngPlunkr', ['mgcrea.ngStrap.helpers.debounce']) .run(function($templateCache, version) { - var ngVersion = '1.3.15'; + var ngVersion = '1.4.2'; var templateHtml = '' + '\n' + diff --git a/package.json b/package.json index de9d21b5b..15e6f1c14 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "angular-strap", "description": "AngularStrap - AngularJS directives for Bootstrap", - "version": "2.3.0", + "version": "2.3.1", "keywords": [ "angular", "bootstrap"