From fe980ba236311d18be84800468f5cacefe7dbf0f Mon Sep 17 00:00:00 2001 From: Olivier Louvignes Date: Tue, 15 Sep 2015 13:03:58 +0200 Subject: [PATCH] chore(release): cut the 2.3.2 release --- bower.json | 2 +- dist/angular-strap.js | 6895 ++++++++++++++-------------- dist/angular-strap.min.js | 9 +- dist/angular-strap.min.js.map | 2 +- dist/angular-strap.tpl.js | 14 +- dist/angular-strap.tpl.min.js | 4 +- dist/modules/affix.js | 4 +- dist/modules/affix.min.js | 4 +- dist/modules/affix.min.js.map | 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 | 2 +- dist/modules/datepicker.min.js | 2 +- dist/modules/datepicker.tpl.js | 4 +- dist/modules/datepicker.tpl.min.js | 4 +- 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 | 6 +- dist/modules/modal.min.js | 4 +- dist/modules/modal.min.js.map | 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 | 2 +- dist/modules/parse-options.min.js | 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 | 27 +- dist/modules/select.min.js | 4 +- dist/modules/select.min.js.map | 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 | 2 +- dist/modules/timepicker.min.js | 2 +- dist/modules/timepicker.tpl.js | 2 +- dist/modules/timepicker.tpl.min.js | 2 +- dist/modules/tooltip.js | 2 +- dist/modules/tooltip.min.js | 2 +- dist/modules/tooltip.tpl.js | 2 +- dist/modules/tooltip.tpl.min.js | 2 +- dist/modules/typeahead.js | 4 +- 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 +- package.json | 2 +- 79 files changed, 3579 insertions(+), 3538 deletions(-) diff --git a/bower.json b/bower.json index 72c47129b..1a75135e7 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "angular-strap", "description": "AngularStrap - AngularJS directives for Bootstrap", - "version": "2.3.1", + "version": "2.3.2", "keywords": [ "angular", "bootstrap" diff --git a/dist/angular-strap.js b/dist/angular-strap.js index 5eabc2856..e229c63ea 100644 --- a/dist/angular-strap.js +++ b/dist/angular-strap.js @@ -1,1245 +1,731 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT */ (function(window, document, undefined) { 'use strict'; - angular.module('mgcrea.ngStrap', [ 'mgcrea.ngStrap.modal', 'mgcrea.ngStrap.aside', 'mgcrea.ngStrap.alert', 'mgcrea.ngStrap.button', 'mgcrea.ngStrap.select', 'mgcrea.ngStrap.datepicker', 'mgcrea.ngStrap.timepicker', 'mgcrea.ngStrap.navbar', 'mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.popover', 'mgcrea.ngStrap.dropdown', 'mgcrea.ngStrap.typeahead', 'mgcrea.ngStrap.scrollspy', 'mgcrea.ngStrap.affix', 'mgcrea.ngStrap.tab', 'mgcrea.ngStrap.collapse' ]); - angular.module('mgcrea.ngStrap.affix', [ 'mgcrea.ngStrap.helpers.dimensions', 'mgcrea.ngStrap.helpers.debounce' ]).provider('$affix', function() { + angular.module('mgcrea.ngStrap.typeahead', [ 'mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions' ]).provider('$typeahead', function() { var defaults = this.defaults = { - offsetTop: 'auto', - inlineStyles: true + 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', 'debounce', 'dimensions', function($window, debounce, dimensions) { + this.$get = [ '$window', '$rootScope', '$tooltip', '$$rAF', '$timeout', function($window, $rootScope, $tooltip, $$rAF, $timeout) { var bodyEl = angular.element($window.document.body); - var windowEl = angular.element($window); - function AffixFactory(element, config) { - var $affix = {}; + function TypeaheadFactory(element, controller, config) { + var $typeahead = {}; var options = angular.extend({}, defaults, config); - var targetEl = options.target; - var reset = 'affix affix-top affix-bottom', setWidth = false, initialAffixTop = 0, initialOffsetTop = 0, offsetTop = 0, offsetBottom = 0, affixed = null, unpin = null; - var parent = element.parent(); - if (options.offsetParent) { - if (options.offsetParent.match(/^\d+$/)) { - for (var i = 0; i < options.offsetParent * 1 - 1; i++) { - parent = parent.parent(); - } - } else { - parent = angular.element(options.offsetParent); - } - } - $affix.init = function() { - this.$parseOffsets(); - initialOffsetTop = dimensions.offset(element[0]).top + initialAffixTop; - setWidth = !element[0].style.width; - targetEl.on('scroll', this.checkPosition); - targetEl.on('click', this.checkPositionWithEventLoop); - windowEl.on('resize', this.$debouncedOnResize); - this.checkPosition(); - this.checkPositionWithEventLoop(); + $typeahead = $tooltip(element, options); + var parentScope = config.scope; + var scope = $typeahead.$scope; + scope.$resetMatches = function() { + scope.$matches = []; + scope.$activeIndex = options.autoSelect ? 0 : -1; }; - $affix.destroy = function() { - targetEl.off('scroll', this.checkPosition); - targetEl.off('click', this.checkPositionWithEventLoop); - windowEl.off('resize', this.$debouncedOnResize); + scope.$resetMatches(); + scope.$activate = function(index) { + scope.$$postDigest(function() { + $typeahead.activate(index); + }); }; - $affix.checkPositionWithEventLoop = function() { - setTimeout($affix.checkPosition, 1); + scope.$select = function(index, evt) { + scope.$$postDigest(function() { + $typeahead.select(index); + }); }; - $affix.checkPosition = function() { - var scrollTop = getScrollTop(); - var position = dimensions.offset(element[0]); - var elementHeight = dimensions.height(element[0]); - var affix = getRequiredAffixClass(unpin, position, elementHeight); - if (affixed === affix) return; - affixed = affix; - element.removeClass(reset).addClass('affix' + (affix !== 'middle' ? '-' + affix : '')); - if (affix === 'top') { - unpin = null; - if (setWidth) { - element.css('width', ''); - } - if (options.inlineStyles) { - element.css('position', options.offsetParent ? '' : 'relative'); - element.css('top', ''); - } - } else if (affix === 'bottom') { - if (options.offsetUnpin) { - unpin = -(options.offsetUnpin * 1); - } else { - unpin = position.top - scrollTop; - } - if (setWidth) { - element.css('width', ''); - } - if (options.inlineStyles) { - element.css('position', options.offsetParent ? '' : 'relative'); - element.css('top', options.offsetParent ? '' : bodyEl[0].offsetHeight - offsetBottom - elementHeight - initialOffsetTop + 'px'); - } - } else { - unpin = null; - if (setWidth) { - element.css('width', element[0].offsetWidth + 'px'); - } - if (options.inlineStyles) { - element.css('position', 'fixed'); - element.css('top', initialAffixTop + 'px'); - } + scope.$isVisible = function() { + return $typeahead.$isVisible(); + }; + $typeahead.update = function(matches) { + scope.$matches = matches; + if (scope.$activeIndex >= matches.length) { + scope.$activeIndex = options.autoSelect ? 0 : -1; } + safeDigest(scope); + $$rAF($typeahead.$applyPlacement); }; - $affix.$onResize = function() { - $affix.$parseOffsets(); - $affix.checkPosition(); + $typeahead.activate = function(index) { + scope.$activeIndex = index; }; - $affix.$debouncedOnResize = debounce($affix.$onResize, 50); - $affix.$parseOffsets = function() { - var initialPosition = element.css('position'); - if (options.inlineStyles) { - element.css('position', options.offsetParent ? '' : 'relative'); - } - if (options.offsetTop) { - if (options.offsetTop === 'auto') { - options.offsetTop = '+0'; - } - if (options.offsetTop.match(/^[-+]\d+$/)) { - initialAffixTop = -options.offsetTop * 1; - if (options.offsetParent) { - offsetTop = dimensions.offset(parent[0]).top + options.offsetTop * 1; - } else { - offsetTop = dimensions.offset(element[0]).top - dimensions.css(element[0], 'marginTop', true) + options.offsetTop * 1; - } - } else { - offsetTop = options.offsetTop * 1; - } + $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; } - if (options.offsetBottom) { - if (options.offsetParent && options.offsetBottom.match(/^[-+]\d+$/)) { - offsetBottom = getScrollHeight() - (dimensions.offset(parent[0]).top + dimensions.height(parent[0])) + options.offsetBottom * 1 + 1; - } else { - offsetBottom = options.offsetBottom * 1; - } + 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 (options.inlineStyles) { - element.css('position', initialPosition); + 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(); } + 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(); }; - function getRequiredAffixClass(unpin, position, elementHeight) { - var scrollTop = getScrollTop(); - var scrollHeight = getScrollHeight(); - if (scrollTop <= offsetTop) { - return 'top'; - } else if (unpin !== null && scrollTop + unpin <= position.top) { - return 'middle'; - } else if (offsetBottom !== null && position.top + elementHeight + initialAffixTop >= scrollHeight - offsetBottom) { - return 'bottom'; - } else { - return 'middle'; + var show = $typeahead.show; + $typeahead.show = function() { + show(); + $timeout(function() { + $typeahead.$element && $typeahead.$element.on('mousedown', $typeahead.$onMouseDown); + if (options.keyboard) { + 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); } - } - function getScrollTop() { - return targetEl[0] === $window ? $window.pageYOffset : targetEl[0].scrollTop; - } - function getScrollHeight() { - return targetEl[0] === $window ? $window.document.body.scrollHeight : targetEl[0].scrollHeight; - } - $affix.init(); - return $affix; + if (!options.autoSelect) $typeahead.activate(-1); + hide(); + }; + return $typeahead; } - return AffixFactory; + function safeDigest(scope) { + scope.$$phase || scope.$root && scope.$root.$$phase || scope.$digest(); + } + TypeaheadFactory.defaults = defaults; + return TypeaheadFactory; } ]; - }).directive('bsAffix', [ '$affix', '$window', function($affix, $window) { + }).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', - require: '^?bsAffixTarget', - link: function postLink(scope, element, attr, affixTarget) { + require: 'ngModel', + link: function postLink(scope, element, attr, controller) { var options = { - scope: scope, - target: affixTarget ? affixTarget.$element : angular.element($window) + scope: scope }; - angular.forEach([ 'offsetTop', 'offsetBottom', 'offsetParent', 'offsetUnpin', 'inlineStyles' ], function(key) { - if (angular.isDefined(attr[key])) { - var option = attr[key]; - if (/true/i.test(option)) option = true; - if (/false/i.test(option)) option = false; - options[key] = option; - } - }); - var affix = $affix(element, options); - scope.$on('$destroy', function() { - affix && affix.destroy(); - options = null; - affix = null; - }); - } - }; - } ]).directive('bsAffixTarget', function() { - return { - controller: [ '$element', function($element) { - this.$element = $element; - } ] - }; - }); - angular.module('mgcrea.ngStrap.alert', [ 'mgcrea.ngStrap.modal' ]).provider('$alert', function() { - var defaults = this.defaults = { - animation: 'am-fade', - prefixClass: 'alert', - prefixEvent: 'alert', - placement: null, - templateUrl: 'alert/alert.tpl.html', - container: false, - element: null, - backdrop: false, - keyboard: true, - show: true, - duration: false, - type: false, - dismissable: true - }; - this.$get = [ '$modal', '$timeout', function($modal, $timeout) { - function AlertFactory(config) { - var $alert = {}; - var options = angular.extend({}, defaults, config); - $alert = $modal(options); - $alert.$scope.dismissable = !!options.dismissable; - if (options.type) { - $alert.$scope.type = options.type; - } - var show = $alert.show; - if (options.duration) { - $alert.show = function() { - show(); - $timeout(function() { - $alert.hide(); - }, options.duration * 1e3); - }; - } - return $alert; - } - return AlertFactory; - } ]; - }).directive('bsAlert', [ '$window', '$sce', '$alert', function($window, $sce, $alert) { - var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout; - return { - restrict: 'EAC', - scope: true, - link: function postLink(scope, element, attr, transclusion) { - var options = { - scope: scope, - element: element, - show: false - }; - angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'keyboard', 'html', 'container', 'animation', 'duration', 'dismissable' ], 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([ 'keyboard', 'html', 'container', 'dismissable' ], function(key) { + angular.forEach([ 'html', 'container', 'trimValue' ], function(key) { if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false; }); - if (!scope.hasOwnProperty('title')) { - scope.title = ''; + if (!element.attr('autocomplete')) element.attr('autocomplete', 'off'); + 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(); + }); + }); } - angular.forEach([ 'title', 'content', 'type' ], function(key) { - attr[key] && attr.$observe(key, function(newValue, oldValue) { - scope[key] = $sce.trustAsHtml(newValue); + 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.bsAlert && scope.$watch(attr.bsAlert, function(newValue, oldValue) { - if (angular.isObject(newValue)) { - angular.extend(scope, newValue); - } else { - scope.content = newValue; + controller.$formatters.push(function(modelValue) { + var displayValue = parsedOptions.displayValue(modelValue); + if (displayValue) { + return displayValue; } - }, true); - var alert = $alert(options); - element.on(attr.trigger || 'click', alert.toggle); + if (modelValue && typeof modelValue !== 'object') { + return modelValue; + } + return ''; + }); + 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 (alert) alert.destroy(); + if (typeahead) typeahead.destroy(); options = null; - alert = null; + typeahead = null; }); } }; } ]); - angular.module('mgcrea.ngStrap.aside', [ 'mgcrea.ngStrap.modal' ]).provider('$aside', function() { + angular.module('mgcrea.ngStrap.tooltip', [ 'mgcrea.ngStrap.core', 'mgcrea.ngStrap.helpers.dimensions' ]).provider('$tooltip', function() { var defaults = this.defaults = { - animation: 'am-fade-and-slide-right', - prefixClass: 'aside', - prefixEvent: 'aside', - placement: 'right', - templateUrl: 'aside/aside.tpl.html', - contentTemplate: false, + animation: 'am-fade', + customClass: '', + prefixClass: 'tooltip', + prefixEvent: 'tooltip', container: false, - element: null, - backdrop: true, - keyboard: true, + target: false, + placement: 'top', + templateUrl: 'tooltip/tooltip.tpl.html', + template: '', + contentTemplate: false, + trigger: 'hover focus', + keyboard: false, html: false, - show: true - }; - this.$get = [ '$modal', function($modal) { - function AsideFactory(config) { - var $aside = {}; - var options = angular.extend({}, defaults, config); - $aside = $modal(options); - return $aside; + show: false, + title: '', + type: '', + delay: 0, + autoClose: false, + bsEnabled: true, + viewport: { + selector: 'body', + padding: 0 } - return AsideFactory; - } ]; - }).directive('bsAside', [ '$window', '$sce', '$aside', function($window, $sce, $aside) { - var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout; - return { - restrict: 'EAC', - scope: true, - link: function postLink(scope, element, attr, transclusion) { - var options = { - scope: scope, - element: element, - show: false + }; + 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); + }); }; - angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation' ], function(key) { - if (angular.isDefined(attr[key])) options[key] = attr[key]; - }); - var falseValueRegExp = /^(false|0|)$/i; - angular.forEach([ 'backdrop', 'keyboard', 'html', 'container' ], function(key) { - if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false; - }); - angular.forEach([ 'title', 'content' ], function(key) { - attr[key] && attr.$observe(key, function(newValue, oldValue) { - scope[key] = $sce.trustAsHtml(newValue); + scope.$hide = function() { + scope.$$postDigest(function() { + $tooltip.hide(); + }); + }; + scope.$show = function() { + scope.$$postDigest(function() { + $tooltip.show(); + }); + }; + scope.$toggle = function() { + scope.$$postDigest(function() { + $tooltip.toggle(); }); + }; + $tooltip.$isShown = scope.$isShown = false; + var timeout, hoverState; + var compileData, tipElement, tipContainer, tipScope; + promise.then(function(data) { + compileData = data; + $tooltip.init(); }); - attr.bsAside && scope.$watch(attr.bsAside, function(newValue, oldValue) { - if (angular.isObject(newValue)) { - angular.extend(scope, newValue); - } else { - scope.content = newValue; + $tooltip.init = function() { + if (options.delay && angular.isNumber(options.delay)) { + options.delay = { + show: options.delay, + hide: options.delay + }; + } + if (options.container === 'self') { + tipContainer = element; + } else if (angular.isElement(options.container)) { + tipContainer = options.container; + } else if (options.container) { + tipContainer = findElement(options.container); + } + bindTriggerEvents(); + if (options.target) { + options.target = angular.isElement(options.target) ? options.target : findElement(options.target); + } + if (options.show) { + scope.$$postDigest(function() { + options.trigger === 'focus' ? element[0].focus() : $tooltip.show(); + }); } - }, true); - var aside = $aside(options); - element.on(attr.trigger || 'click', aside.toggle); - scope.$on('$destroy', function() { - if (aside) aside.destroy(); - options = null; - aside = null; - }); - } - }; - } ]); - angular.module('mgcrea.ngStrap.button', []).provider('$button', function() { - var defaults = this.defaults = { - activeClass: 'active', - toggleEvent: 'click' - }; - this.$get = function() { - return { - defaults: defaults - }; - }; - }).directive('bsCheckboxGroup', function() { - return { - restrict: 'A', - require: 'ngModel', - compile: function postLink(element, attr) { - element.attr('data-toggle', 'buttons'); - element.removeAttr('ng-model'); - var children = element[0].querySelectorAll('input[type="checkbox"]'); - angular.forEach(children, function(child) { - var childEl = angular.element(child); - childEl.attr('bs-checkbox', ''); - childEl.attr('ng-model', attr.ngModel + '.' + childEl.attr('value')); - }); - } - }; - }).directive('bsCheckbox', [ '$button', '$$rAF', function($button, $$rAF) { - var defaults = $button.defaults; - var constantValueRegExp = /^(true|false|\d+)$/; - return { - restrict: 'A', - require: 'ngModel', - link: function postLink(scope, element, attr, controller) { - var options = defaults; - var isInput = element[0].nodeName === 'INPUT'; - var activeElement = isInput ? element.parent() : element; - var trueValue = angular.isDefined(attr.trueValue) ? attr.trueValue : true; - if (constantValueRegExp.test(attr.trueValue)) { - trueValue = scope.$eval(attr.trueValue); - } - var falseValue = angular.isDefined(attr.falseValue) ? attr.falseValue : false; - if (constantValueRegExp.test(attr.falseValue)) { - falseValue = scope.$eval(attr.falseValue); - } - var hasExoticValues = typeof trueValue !== 'boolean' || typeof falseValue !== 'boolean'; - if (hasExoticValues) { - controller.$parsers.push(function(viewValue) { - return viewValue ? trueValue : falseValue; - }); - controller.$formatters.push(function(modelValue) { - return angular.equals(modelValue, trueValue); - }); - scope.$watch(attr.ngModel, function(newValue, oldValue) { - controller.$render(); - }); - } - controller.$render = function() { - var isActive = angular.equals(controller.$modelValue, trueValue); - $$rAF(function() { - if (isInput) element[0].checked = isActive; - activeElement.toggleClass(options.activeClass, isActive); - }); }; - element.bind(options.toggleEvent, function() { - scope.$apply(function() { - if (!isInput) { - controller.$setViewValue(!activeElement.hasClass('active')); - } - if (!hasExoticValues) { - controller.$render(); + $tooltip.destroy = function() { + unbindTriggerEvents(); + destroyTipElement(); + scope.$destroy(); + }; + $tooltip.enter = function() { + clearTimeout(timeout); + hoverState = 'in'; + if (!options.delay || !options.delay.show) { + return $tooltip.show(); + } + 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 { + 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' }); - }); - } - }; - } ]).directive('bsRadioGroup', function() { - return { - restrict: 'A', - require: 'ngModel', - compile: function postLink(element, attr) { - element.attr('data-toggle', 'buttons'); - element.removeAttr('ng-model'); - var children = element[0].querySelectorAll('input[type="radio"]'); - angular.forEach(children, function(child) { - angular.element(child).attr('bs-radio', ''); - angular.element(child).attr('ng-model', attr.ngModel); - }); - } - }; - }).directive('bsRadio', [ '$button', '$$rAF', function($button, $$rAF) { - var defaults = $button.defaults; - var constantValueRegExp = /^(true|false|\d+)$/; - return { - restrict: 'A', - require: 'ngModel', - link: function postLink(scope, element, attr, controller) { - var options = defaults; - var isInput = element[0].nodeName === 'INPUT'; - var activeElement = isInput ? element.parent() : element; - var value; - attr.$observe('value', function(v) { - value = constantValueRegExp.test(v) ? scope.$eval(v) : v; - controller.$render(); - }); - controller.$render = function() { - var isActive = angular.equals(controller.$modelValue, value); + 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 (isInput) element[0].checked = isActive; - activeElement.toggleClass(options.activeClass, isActive); + if (tipElement) tipElement.css({ + visibility: 'visible' + }); }); + if (options.keyboard) { + if (options.trigger !== 'focus') { + $tooltip.focus(); + } + bindKeyboardEvents(); + } + if (options.autoClose) { + bindAutoCloseEvents(); + } }; - element.bind(options.toggleEvent, function() { - scope.$apply(function() { - controller.$setViewValue(value); - controller.$render(); - }); - }); - } - }; - } ]); - angular.module('mgcrea.ngStrap.collapse', []).provider('$collapse', function() { - var defaults = this.defaults = { - animation: 'am-collapse', - disallowToggle: false, - activeClass: 'in', - startCollapsed: false, - allowMultiple: false - }; - var controller = this.controller = function($scope, $element, $attrs) { - var self = this; - self.$options = angular.copy(defaults); - angular.forEach([ 'animation', 'disallowToggle', 'activeClass', 'startCollapsed', 'allowMultiple' ], function(key) { - if (angular.isDefined($attrs[key])) self.$options[key] = $attrs[key]; - }); - var falseValueRegExp = /^(false|0|)$/i; - angular.forEach([ 'disallowToggle', 'startCollapsed', 'allowMultiple' ], function(key) { - if (angular.isDefined($attrs[key]) && falseValueRegExp.test($attrs[key])) { - self.$options[key] = false; - } - }); - self.$toggles = []; - self.$targets = []; - self.$viewChangeListeners = []; - self.$registerToggle = function(element) { - self.$toggles.push(element); - }; - self.$registerTarget = function(element) { - self.$targets.push(element); - }; - self.$unregisterToggle = function(element) { - var index = self.$toggles.indexOf(element); - self.$toggles.splice(index, 1); - }; - self.$unregisterTarget = function(element) { - var index = self.$targets.indexOf(element); - self.$targets.splice(index, 1); - if (self.$options.allowMultiple) { - deactivateItem(element); + function enterAnimateCallback() { + scope.$emit(options.prefixEvent + '.show', $tooltip); } - fixActiveItemIndexes(index); - self.$viewChangeListeners.forEach(function(fn) { - fn(); - }); - }; - self.$targets.$active = !self.$options.startCollapsed ? [ 0 ] : []; - self.$setActive = $scope.$setActive = function(value) { - if (angular.isArray(value)) { - self.$targets.$active = value; - } else if (!self.$options.disallowToggle) { - isActive(value) ? deactivateItem(value) : activateItem(value); - } else { - activateItem(value); - } - self.$viewChangeListeners.forEach(function(fn) { - fn(); - }); - }; - self.$activeIndexes = function() { - return self.$options.allowMultiple ? self.$targets.$active : self.$targets.$active.length === 1 ? self.$targets.$active[0] : -1; - }; - function fixActiveItemIndexes(index) { - var activeIndexes = self.$targets.$active; - for (var i = 0; i < activeIndexes.length; i++) { - if (index < activeIndexes[i]) { - activeIndexes[i] = activeIndexes[i] - 1; - } - if (activeIndexes[i] === self.$targets.length) { - activeIndexes[i] = self.$targets.length - 1; + $tooltip.leave = function() { + clearTimeout(timeout); + hoverState = 'out'; + if (!options.delay || !options.delay.hide) { + return $tooltip.hide(); } - } - } - function isActive(value) { - var activeItems = self.$targets.$active; - return activeItems.indexOf(value) === -1 ? false : true; - } - function deactivateItem(value) { - var index = self.$targets.$active.indexOf(value); - if (index !== -1) { - self.$targets.$active.splice(index, 1); - } - } - function activateItem(value) { - if (!self.$options.allowMultiple) { - self.$targets.$active.splice(0, 1); - } - if (self.$targets.$active.indexOf(value) === -1) { - self.$targets.$active.push(value); - } - } - }; - this.$get = function() { - var $collapse = {}; - $collapse.defaults = defaults; - $collapse.controller = controller; - return $collapse; - }; - }).directive('bsCollapse', [ '$window', '$animate', '$collapse', function($window, $animate, $collapse) { - var defaults = $collapse.defaults; - return { - require: [ '?ngModel', 'bsCollapse' ], - controller: [ '$scope', '$element', '$attrs', $collapse.controller ], - link: function postLink(scope, element, attrs, controllers) { - var ngModelCtrl = controllers[0]; - var bsCollapseCtrl = controllers[1]; - if (ngModelCtrl) { - bsCollapseCtrl.$viewChangeListeners.push(function() { - ngModelCtrl.$setViewValue(bsCollapseCtrl.$activeIndexes()); - }); - ngModelCtrl.$formatters.push(function(modelValue) { - if (angular.isArray(modelValue)) { - bsCollapseCtrl.$setActive(modelValue); - } else { - var activeIndexes = bsCollapseCtrl.$activeIndexes(); - if (angular.isArray(activeIndexes)) { - if (activeIndexes.indexOf(modelValue * 1) === -1) { - bsCollapseCtrl.$setActive(modelValue * 1); - } - } else if (activeIndexes !== modelValue * 1) { - bsCollapseCtrl.$setActive(modelValue * 1); - } - } - return modelValue; - }); - } - } - }; - } ]).directive('bsCollapseToggle', function() { - return { - require: [ '^?ngModel', '^bsCollapse' ], - link: function postLink(scope, element, attrs, controllers) { - var ngModelCtrl = controllers[0]; - var bsCollapseCtrl = controllers[1]; - element.attr('data-toggle', 'collapse'); - bsCollapseCtrl.$registerToggle(element); - scope.$on('$destroy', function() { - bsCollapseCtrl.$unregisterToggle(element); - }); - element.on('click', function() { - var index = attrs.bsCollapseToggle && attrs.bsCollapseToggle !== 'bs-collapse-toggle' ? attrs.bsCollapseToggle : bsCollapseCtrl.$toggles.indexOf(element); - bsCollapseCtrl.$setActive(index * 1); - scope.$apply(); - }); - } - }; - }).directive('bsCollapseTarget', [ '$animate', function($animate) { - return { - require: [ '^?ngModel', '^bsCollapse' ], - link: function postLink(scope, element, attrs, controllers) { - var ngModelCtrl = controllers[0]; - var bsCollapseCtrl = controllers[1]; - element.addClass('collapse'); - if (bsCollapseCtrl.$options.animation) { - element.addClass(bsCollapseCtrl.$options.animation); - } - bsCollapseCtrl.$registerTarget(element); - scope.$on('$destroy', function() { - bsCollapseCtrl.$unregisterTarget(element); - }); - function render() { - var index = bsCollapseCtrl.$targets.indexOf(element); - var active = bsCollapseCtrl.$activeIndexes(); - var action = 'removeClass'; - if (angular.isArray(active)) { - if (active.indexOf(index) !== -1) { - action = 'addClass'; + timeout = setTimeout(function() { + if (hoverState === 'out') { + $tooltip.hide(); } - } else if (index === active) { - action = 'addClass'; - } - $animate[action](element, bsCollapseCtrl.$options.activeClass); - } - bsCollapseCtrl.$viewChangeListeners.push(function() { - render(); - }); - render(); - } - }; - } ]); - angular.module('mgcrea.ngStrap.datepicker', [ 'mgcrea.ngStrap.helpers.dateParser', 'mgcrea.ngStrap.helpers.dateFormatter', 'mgcrea.ngStrap.tooltip' ]).provider('$datepicker', function() { - var defaults = this.defaults = { - animation: 'am-fade', - prefixClass: 'datepicker', - placement: 'bottom-left', - templateUrl: 'datepicker/datepicker.tpl.html', - trigger: 'focus', - container: false, - keyboard: true, - html: false, - delay: 0, - useNative: false, - dateType: 'date', - dateFormat: 'shortDate', - timezone: null, - modelDateFormat: null, - dayFormat: 'dd', - monthFormat: 'MMM', - yearFormat: 'yyyy', - monthTitleFormat: 'MMMM yyyy', - yearTitleFormat: 'yyyy', - strictFormat: false, - autoclose: false, - minDate: -Infinity, - maxDate: +Infinity, - startView: 0, - minView: 0, - startWeek: 0, - daysOfWeekDisabled: '', - iconLeft: 'glyphicon glyphicon-chevron-left', - iconRight: 'glyphicon glyphicon-chevron-right' - }; - this.$get = [ '$window', '$document', '$rootScope', '$sce', '$dateFormatter', 'datepickerViews', '$tooltip', '$timeout', function($window, $document, $rootScope, $sce, $dateFormatter, datepickerViews, $tooltip, $timeout) { - var bodyEl = angular.element($window.document.body); - var isNative = /(ip(a|o)d|iphone|android)/gi.test($window.navigator.userAgent); - var isTouch = 'createTouch' in $window.document && isNative; - if (!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale(); - function DatepickerFactory(element, controller, config) { - var $datepicker = $tooltip(element, angular.extend({}, defaults, config)); - var parentScope = config.scope; - var options = $datepicker.$options; - var scope = $datepicker.$scope; - if (options.startView) options.startView -= options.minView; - var pickerViews = datepickerViews($datepicker); - $datepicker.$views = pickerViews.views; - var viewDate = pickerViews.viewDate; - scope.$mode = options.startView; - scope.$iconLeft = options.iconLeft; - scope.$iconRight = options.iconRight; - var $picker = $datepicker.$views[scope.$mode]; - scope.$select = function(date) { - $datepicker.select(date); - }; - scope.$selectPane = function(value) { - $datepicker.$selectPane(value); - }; - scope.$toggleMode = function() { - $datepicker.setMode((scope.$mode + 1) % $datepicker.$views.length); + }, options.delay.hide); }; - $datepicker.update = function(date) { - if (angular.isDate(date) && !isNaN(date.getTime())) { - $datepicker.$date = date; - $picker.update.call($picker, date); + 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); } - $datepicker.$build(true); - }; - $datepicker.updateDisabledDates = function(dateRanges) { - options.disabledDateRanges = dateRanges; - for (var i = 0, l = scope.rows.length; i < l; i++) { - angular.forEach(scope.rows[i], $datepicker.$setDisabledEl); + $tooltip.$isShown = scope.$isShown = false; + safeDigest(scope); + if (options.keyboard && tipElement !== null) { + unbindKeyboardEvents(); + } + if (options.autoClose && tipElement !== null) { + unbindAutoCloseEvents(); } }; - $datepicker.select = function(date, keep) { - if (!angular.isDate(controller.$dateValue)) controller.$dateValue = new Date(date); - if (!scope.$mode || keep) { - controller.$setViewValue(angular.copy(date)); - controller.$render(); - if (options.autoclose && !keep) { - $timeout(function() { - $datepicker.hide(true); - }); + function leaveAnimateCallback() { + scope.$emit(options.prefixEvent + '.hide', $tooltip); + if (tipElement === _tipToHide) { + if (_blur && options.trigger === 'focus') { + return element[0].blur(); } - } else { - angular.extend(viewDate, { - year: date.getFullYear(), - month: date.getMonth(), - date: date.getDate() - }); - $datepicker.setMode(scope.$mode - 1); - $datepicker.$build(); + destroyTipElement(); } + } + $tooltip.toggle = function() { + $tooltip.$isShown ? $tooltip.leave() : $tooltip.enter(); }; - $datepicker.setMode = function(mode) { - scope.$mode = mode; - $picker = $datepicker.$views[scope.$mode]; - $datepicker.$build(); - }; - $datepicker.$build = function(pristine) { - if (pristine === true && $picker.built) return; - if (pristine === false && !$picker.built) return; - $picker.build.call($picker); + $tooltip.focus = function() { + tipElement[0].focus(); }; - $datepicker.$updateSelected = function() { - for (var i = 0, l = scope.rows.length; i < l; i++) { - angular.forEach(scope.rows[i], updateSelected); - } - }; - $datepicker.$isSelected = function(date) { - return $picker.isSelected(date); - }; - $datepicker.$setDisabledEl = function(el) { - el.disabled = $picker.isDisabled(el.date); + $tooltip.setEnabled = function(isEnabled) { + options.bsEnabled = isEnabled; }; - $datepicker.$selectPane = function(value) { - var steps = $picker.steps; - var targetDate = new Date(Date.UTC(viewDate.year + (steps.year || 0) * value, viewDate.month + (steps.month || 0) * value, 1)); - angular.extend(viewDate, { - year: targetDate.getUTCFullYear(), - month: targetDate.getUTCMonth(), - date: targetDate.getUTCDate() - }); - $datepicker.$build(); + $tooltip.setViewport = function(viewport) { + options.viewport = viewport; }; - $datepicker.$onMouseDown = function(evt) { - evt.preventDefault(); - evt.stopPropagation(); - if (isTouch) { - var targetEl = angular.element(evt.target); - if (targetEl[0].nodeName.toLowerCase() !== 'button') { - targetEl = targetEl.parent(); - } - targetEl.triggerHandler('click'); + $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; } - }; - $datepicker.$onKeyDown = function(evt) { - if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return; - evt.preventDefault(); - evt.stopPropagation(); - if (evt.keyCode === 13) { - if (!scope.$mode) { - return $datepicker.hide(true); - } else { - return scope.$apply(function() { - $datepicker.setMode(scope.$mode - 1); - }); + 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'); } + 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); } - $picker.onKeyDown(evt); - parentScope.$digest(); - }; - function updateSelected(el) { - el.selected = $datepicker.$isSelected(el.date); - } - function focusElement() { - element[0].focus(); - } - var _init = $datepicker.init; - $datepicker.init = function() { - if (isNative && options.useNative) { - element.prop('type', 'date'); - element.css('-webkit-appearance', 'textfield'); - return; - } else if (isTouch) { - element.prop('type', 'text'); - element.attr('readonly', 'true'); - element.on('click', focusElement); - } - _init(); + var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight); + applyPlacement(tipPosition, placement); }; - var _destroy = $datepicker.destroy; - $datepicker.destroy = function() { - if (isNative && options.useNative) { - element.off('click', focusElement); + $tooltip.$onKeyUp = function(evt) { + if (evt.which === 27 && $tooltip.$isShown) { + $tooltip.hide(); + evt.stopPropagation(); } - _destroy(); - }; - var _show = $datepicker.show; - $datepicker.show = function() { - if (!isTouch && element.attr('readonly') || element.attr('disabled')) return; - _show(); - $timeout(function() { - if (!$datepicker.$isShown) return; - $datepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown); - if (options.keyboard) { - element.on('keydown', $datepicker.$onKeyDown); - } - }, 0, false); }; - var _hide = $datepicker.hide; - $datepicker.hide = function(blur) { - if (!$datepicker.$isShown) return; - $datepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown); - if (options.keyboard) { - element.off('keydown', $datepicker.$onKeyDown); + $tooltip.$onFocusKeyUp = function(evt) { + if (evt.which === 27) { + element[0].blur(); + evt.stopPropagation(); } - _hide(blur); - }; - return $datepicker; - } - DatepickerFactory.defaults = defaults; - return DatepickerFactory; - } ]; - }).directive('bsDatepicker', [ '$window', '$parse', '$q', '$dateFormatter', '$dateParser', '$datepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $datepicker) { - var defaults = $datepicker.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 }; - 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) { - if (angular.isDefined(attr[key])) options[key] = attr[key]; - }); - var falseValueRegExp = /^(false|0|)$/i; - angular.forEach([ 'html', 'container', 'autoclose', 'useNative' ], function(key) { - if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false; - }); - attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) { - if (!datepicker || !angular.isDefined(newValue)) return; - if (angular.isString(newValue)) newValue = !!newValue.match(/true|,?(datepicker),?/i); - newValue === true ? datepicker.show() : datepicker.hide(); - }); - var datepicker = $datepicker(element, controller, options); - options = datepicker.$options; - if (isNative && options.useNative) options.dateFormat = 'yyyy-MM-dd'; - var lang = options.lang; - var formatDate = function(date, format) { - return $dateFormatter.formatDate(date, format, lang); + $tooltip.$onFocusElementMouseDown = function(evt) { + evt.preventDefault(); + evt.stopPropagation(); + $tooltip.$isShown ? element[0].blur() : element[0].focus(); }; - var dateParser = $dateParser({ - format: options.dateFormat, - lang: lang, - strict: options.strictFormat - }); - angular.forEach([ 'minDate', 'maxDate' ], function(key) { - angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) { - datepicker.$options[key] = dateParser.getDateForAttribute(key, newValue); - !isNaN(datepicker.$options[key]) && datepicker.$build(false); - validateAgainstMinMaxDate(controller.$dateValue); - }); - }); - scope.$watch(attr.ngModel, function(newValue, oldValue) { - datepicker.update(controller.$dateValue); - }, true); - function normalizeDateRanges(ranges) { - if (!ranges || !ranges.length) return null; - return ranges; - } - if (angular.isDefined(attr.disabledDates)) { - scope.$watch(attr.disabledDates, function(disabledRanges, previousValue) { - disabledRanges = normalizeDateRanges(disabledRanges); - previousValue = normalizeDateRanges(previousValue); - if (disabledRanges) { - datepicker.updateDisabledDates(disabledRanges); + function 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 validateAgainstMinMaxDate(parsedDate) { - if (!angular.isDate(parsedDate)) return; - var isMinValid = isNaN(datepicker.$options.minDate) || parsedDate.getTime() >= datepicker.$options.minDate; - var isMaxValid = isNaN(datepicker.$options.maxDate) || parsedDate.getTime() <= datepicker.$options.maxDate; - var isValid = isMinValid && isMaxValid; - controller.$setValidity('date', isValid); - controller.$setValidity('min', isMinValid); - controller.$setValidity('max', isMaxValid); - if (isValid) controller.$dateValue = parsedDate; - } - controller.$parsers.unshift(function(viewValue) { - var date; - if (!viewValue) { - controller.$setValidity('date', true); - return null; + 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); + } } - var parsedDate = dateParser.parse(viewValue, controller.$dateValue); - if (!parsedDate || isNaN(parsedDate.getTime())) { - controller.$setValidity('date', false); - return; + } + function bindKeyboardEvents() { + if (options.trigger !== 'focus') { + tipElement.on('keyup', $tooltip.$onKeyUp); } else { - validateAgainstMinMaxDate(parsedDate); - } - if (options.dateType === 'string') { - date = dateParser.timezoneOffsetAdjust(parsedDate, options.timezone, true); - return formatDate(date, options.modelDateFormat || options.dateFormat); + element.on('keyup', $tooltip.$onFocusKeyUp); } - date = dateParser.timezoneOffsetAdjust(controller.$dateValue, options.timezone, true); - if (options.dateType === 'number') { - return date.getTime(); - } else if (options.dateType === 'unix') { - return date.getTime() / 1e3; - } else if (options.dateType === 'iso') { - return date.toISOString(); + } + function unbindKeyboardEvents() { + if (options.trigger !== 'focus') { + tipElement.off('keyup', $tooltip.$onKeyUp); } else { - return new Date(date); + element.off('keyup', $tooltip.$onFocusKeyUp); } - }); - 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.dateType === 'string') { - date = dateParser.parse(modelValue, null, options.modelDateFormat); - } else if (options.dateType === 'unix') { - date = new Date(modelValue * 1e3); - } else { - date = new Date(modelValue); + } + 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; } - controller.$dateValue = dateParser.timezoneOffsetAdjust(date, options.timezone); - return getDateFormattedString(); - }); - controller.$render = function() { - element.val(getDateFormattedString()); - }; - function getDateFormattedString() { - return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.dateFormat); } - scope.$on('$destroy', function() { - if (datepicker) datepicker.destroy(); - options = null; - datepicker = null; - }); - } - }; - } ]).provider('datepickerViews', function() { - var defaults = this.defaults = { - dayFormat: 'dd', - daySplit: 7 - }; - function split(arr, size) { - var arrays = []; - while (arr.length > 0) { - arrays.push(arr.splice(0, size)); - } - return arrays; - } - function mod(n, m) { - return (n % m + m) % m; - } - this.$get = [ '$dateFormatter', '$dateParser', '$sce', function($dateFormatter, $dateParser, $sce) { - return function(picker) { - var scope = picker.$scope; - var options = picker.$options; - var lang = options.lang; - var formatDate = function(date, format) { - return $dateFormatter.formatDate(date, format, lang); - }; - var dateParser = $dateParser({ - format: options.dateFormat, - lang: lang, - strict: options.strictFormat - }); - var weekDaysMin = $dateFormatter.weekdaysShort(lang); - var weekDaysLabels = weekDaysMin.slice(options.startWeek).concat(weekDaysMin.slice(0, options.startWeek)); - var weekDaysLabelsHtml = $sce.trustAsHtml('' + weekDaysLabels.join('') + ''); - var startDate = picker.$date || (options.startDate ? dateParser.getDateForAttribute('startDate', options.startDate) : new Date()); - var viewDate = { - year: startDate.getFullYear(), - month: startDate.getMonth(), - date: startDate.getDate() - }; - var views = [ { - format: options.dayFormat, - split: 7, - steps: { - month: 1 - }, - update: function(date, force) { - if (!this.built || force || date.getFullYear() !== viewDate.year || date.getMonth() !== viewDate.month) { - angular.extend(viewDate, { - year: picker.$date.getFullYear(), - month: picker.$date.getMonth(), - date: picker.$date.getDate() - }); - picker.$build(); - } else if (date.getDate() !== viewDate.date || date.getDate() === 1) { - viewDate.date = picker.$date.getDate(); - picker.$updateSelected(); - } - }, - build: function() { - var firstDayOfMonth = new Date(viewDate.year, viewDate.month, 1), firstDayOfMonthOffset = firstDayOfMonth.getTimezoneOffset(); - var firstDate = new Date(+firstDayOfMonth - mod(firstDayOfMonth.getDay() - options.startWeek, 7) * 864e5), firstDateOffset = firstDate.getTimezoneOffset(); - var today = dateParser.timezoneOffsetAdjust(new Date(), options.timezone).toDateString(); - if (firstDateOffset !== firstDayOfMonthOffset) firstDate = new Date(+firstDate + (firstDateOffset - firstDayOfMonthOffset) * 6e4); - var days = [], day; - for (var i = 0; i < 42; i++) { - day = dateParser.daylightSavingAdjust(new Date(firstDate.getFullYear(), firstDate.getMonth(), firstDate.getDate() + i)); - days.push({ - date: day, - isToday: day.toDateString() === today, - label: formatDate(day, this.format), - selected: picker.$date && this.isSelected(day), - muted: day.getMonth() !== viewDate.month, - disabled: this.isDisabled(day) - }); - } - scope.title = formatDate(firstDayOfMonth, options.monthTitleFormat); - scope.showLabels = true; - scope.labels = weekDaysLabelsHtml; - scope.rows = split(days, this.split); - this.built = true; - }, - isSelected: function(date) { - return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth() && date.getDate() === picker.$date.getDate(); - }, - isDisabled: function(date) { - var time = date.getTime(); - if (time < options.minDate || time > options.maxDate) return true; - if (options.daysOfWeekDisabled.indexOf(date.getDay()) !== -1) return true; - if (options.disabledDateRanges) { - for (var i = 0; i < options.disabledDateRanges.length; i++) { - if (time >= options.disabledDateRanges[i].start && time <= options.disabledDateRanges[i].end) { - return true; - } - } + 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]; + } + 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); + } + 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; } - return false; - }, - onKeyDown: function(evt) { - if (!picker.$date) { - return; + } else if (split[0] === 'left' || split[0] === 'right') { + switch (split[1]) { + case 'top': + offset.top = position.top - actualHeight; + break; + + case 'bottom': + offset.top = position.top + position.height; } - var actualTime = picker.$date.getTime(); - var newDate; - if (evt.keyCode === 37) newDate = new Date(actualTime - 1 * 864e5); else if (evt.keyCode === 38) newDate = new Date(actualTime - 7 * 864e5); else if (evt.keyCode === 39) newDate = new Date(actualTime + 1 * 864e5); else if (evt.keyCode === 40) newDate = new Date(actualTime + 7 * 864e5); - if (!this.isDisabled(newDate)) picker.select(newDate, true); } - }, { - name: 'month', - format: options.monthFormat, - split: 4, - steps: { - year: 1 - }, - update: function(date, force) { - if (!this.built || date.getFullYear() !== viewDate.year) { - angular.extend(viewDate, { - year: picker.$date.getFullYear(), - month: picker.$date.getMonth(), - date: picker.$date.getDate() - }); - picker.$build(); - } else if (date.getMonth() !== viewDate.month) { - angular.extend(viewDate, { - month: picker.$date.getMonth(), - date: picker.$date.getDate() + 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: '' }); - picker.$updateSelected(); } - }, - build: function() { - var firstMonth = new Date(viewDate.year, 0, 1); - var months = [], month; - for (var i = 0; i < 12; i++) { - month = new Date(viewDate.year, i, 1); - months.push({ - date: month, - label: formatDate(month, this.format), - selected: picker.$isSelected(month), - disabled: this.isDisabled(month) - }); + }, 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; + } + 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); + } + } + 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; } - scope.title = formatDate(month, options.yearTitleFormat); - scope.showLabels = false; - scope.rows = split(months, this.split); - this.built = true; - }, - isSelected: function(date) { - return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth(); - }, - isDisabled: function(date) { - var lastDate = +new Date(date.getFullYear(), date.getMonth() + 1, 0); - return lastDate < options.minDate || date.getTime() > options.maxDate; - }, - onKeyDown: function(evt) { - if (!picker.$date) { - return; + } 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; } - var actualMonth = picker.$date.getMonth(); - var newDate = new Date(picker.$date); - if (evt.keyCode === 37) newDate.setMonth(actualMonth - 1); else if (evt.keyCode === 38) newDate.setMonth(actualMonth - 4); else if (evt.keyCode === 39) newDate.setMonth(actualMonth + 1); else if (evt.keyCode === 40) newDate.setMonth(actualMonth + 4); - if (!this.isDisabled(newDate)) picker.select(newDate, true); } - }, { - name: 'year', - format: options.yearFormat, - split: 4, - steps: { - year: 12 - }, - update: function(date, force) { - if (!this.built || force || parseInt(date.getFullYear() / 20, 10) !== parseInt(viewDate.year / 20, 10)) { - angular.extend(viewDate, { - year: picker.$date.getFullYear(), - month: picker.$date.getMonth(), - date: picker.$date.getDate() - }); - picker.$build(); - } else if (date.getFullYear() !== viewDate.year) { - angular.extend(viewDate, { - year: picker.$date.getFullYear(), - month: picker.$date.getMonth(), - date: picker.$date.getDate() - }); - picker.$updateSelected(); - } - }, - build: function() { - var firstYear = viewDate.year - viewDate.year % (this.split * 3); - var years = [], year; - for (var i = 0; i < 12; i++) { - year = new Date(firstYear + i, 0, 1); - years.push({ - date: year, - label: formatDate(year, this.format), - selected: picker.$isSelected(year), - disabled: this.isDisabled(year) - }); + 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(); } - scope.title = years[0].label + '-' + years[years.length - 1].label; - scope.showLabels = false; - scope.rows = split(years, this.split); - this.built = true; - }, - isSelected: function(date) { - return picker.$date && date.getFullYear() === picker.$date.getFullYear(); - }, - isDisabled: function(date) { - var lastDate = +new Date(date.getFullYear() + 1, 0, 0); - return lastDate < options.minDate || date.getTime() > options.maxDate; - }, - onKeyDown: function(evt) { - if (!picker.$date) { - return; + if (options.keyboard) { + unbindKeyboardEvents(); } - var actualYear = picker.$date.getFullYear(), newDate = new Date(picker.$date); - if (evt.keyCode === 37) newDate.setYear(actualYear - 1); else if (evt.keyCode === 38) newDate.setYear(actualYear - 4); else if (evt.keyCode === 39) newDate.setYear(actualYear + 1); else if (evt.keyCode === 40) newDate.setYear(actualYear + 4); - if (!this.isDisabled(newDate)) picker.select(newDate, true); } - } ]; - return { - views: options.minView ? Array.prototype.slice.call(views, options.minView) : views, - viewDate: viewDate - }; - }; - } ]; - }); - angular.module('mgcrea.ngStrap.dropdown', [ 'mgcrea.ngStrap.tooltip' ]).provider('$dropdown', function() { - var defaults = this.defaults = { - animation: 'am-fade', - prefixClass: 'dropdown', - prefixEvent: 'dropdown', - placement: 'bottom-left', - templateUrl: 'dropdown/dropdown.tpl.html', - trigger: 'click', - container: false, - keyboard: true, - html: false, - delay: 0 - }; - this.$get = [ '$window', '$rootScope', '$tooltip', '$timeout', function($window, $rootScope, $tooltip, $timeout) { - var bodyEl = angular.element($window.document.body); - var matchesSelector = Element.prototype.matchesSelector || Element.prototype.webkitMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector; - function DropdownFactory(element, config) { - var $dropdown = {}; - var options = angular.extend({}, defaults, config); - var scope = $dropdown.$scope = options.scope && options.scope.$new() || $rootScope.$new(); - $dropdown = $tooltip(element, options); - var parentEl = element.parent(); - $dropdown.$onKeyDown = function(evt) { - if (!/(38|40)/.test(evt.keyCode)) return; - evt.preventDefault(); - evt.stopPropagation(); - var items = angular.element($dropdown.$element[0].querySelectorAll('li:not(.divider) a')); - if (!items.length) return; - var index; - angular.forEach(items, function(el, i) { - if (matchesSelector && matchesSelector.call(el, ':focus')) index = i; - }); - if (evt.keyCode === 38 && index > 0) index--; else if (evt.keyCode === 40 && index < items.length - 1) index++; else if (angular.isUndefined(index)) index = 0; - items.eq(index)[0].focus(); - }; - var show = $dropdown.show; - $dropdown.show = function() { - show(); - $timeout(function() { - options.keyboard && $dropdown.$element && $dropdown.$element.on('keydown', $dropdown.$onKeyDown); - bodyEl.on('click', onBodyClick); - }, 0, false); - parentEl.hasClass('dropdown') && parentEl.addClass('open'); - }; - var hide = $dropdown.hide; - $dropdown.hide = function() { - if (!$dropdown.$isShown) return; - options.keyboard && $dropdown.$element && $dropdown.$element.off('keydown', $dropdown.$onKeyDown); - bodyEl.off('click', onBodyClick); - parentEl.hasClass('dropdown') && parentEl.removeClass('open'); - hide(); - }; - var destroy = $dropdown.destroy; - $dropdown.destroy = function() { - bodyEl.off('click', onBodyClick); - destroy(); - }; - function onBodyClick(evt) { - if (evt.target === element[0]) return; - return evt.target !== element[0] && $dropdown.hide(); + if (tipScope) { + tipScope.$destroy(); + tipScope = null; + } + if (tipElement) { + tipElement.remove(); + tipElement = $tooltip.$element = null; + } } - return $dropdown; + return $tooltip; } - return DropdownFactory; + 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; + }); + } + return TooltipFactory; } ]; - }).directive('bsDropdown', [ '$window', '$sce', '$dropdown', function($window, $sce, $dropdown) { + }).directive('bsTooltip', [ '$window', '$location', '$sce', '$tooltip', '$$rAF', function($window, $location, $sce, $tooltip, $$rAF) { return { restrict: 'EAC', scope: true, @@ -1247,1005 +733,923 @@ var options = { scope: scope }; - angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'id' ], 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' ], function(key) { if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false; }); - attr.bsDropdown && scope.$watch(attr.bsDropdown, function(newValue, oldValue) { - scope.content = newValue; + 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(); + }); + } + }); + 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 (!dropdown || !angular.isDefined(newValue)) return; - if (angular.isString(newValue)) newValue = !!newValue.match(/true|,?(dropdown),?/i); - newValue === true ? dropdown.show() : dropdown.hide(); - }); - var dropdown = $dropdown(element, options); + 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); + }); + 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 (dropdown) dropdown.destroy(); + if (tooltip) tooltip.destroy(); options = null; - dropdown = null; + tooltip = null; }); } }; } ]); - angular.module('mgcrea.ngStrap.core', []).service('$bsCompiler', bsCompilerService); - function bsCompilerService($q, $http, $injector, $compile, $controller, $templateCache) { - this.compile = function(options) { - if (options.template && /\.html$/.test(options.template)) { - console.warn('Deprecated use of `template` option to pass a file. Please use the `templateUrl` option instead.'); - options.templateUrl = options.template; - options.template = ''; - } - var templateUrl = options.templateUrl; - var template = options.template || ''; - var controller = options.controller; - var controllerAs = options.controllerAs; - var resolve = angular.copy(options.resolve || {}); - var locals = angular.copy(options.locals || {}); - var transformTemplate = options.transformTemplate || angular.identity; - var bindToController = options.bindToController; - angular.forEach(resolve, function(value, key) { - if (angular.isString(value)) { - resolve[key] = $injector.get(value); - } else { - resolve[key] = $injector.invoke(value); - } - }); - angular.extend(resolve, locals); - if (templateUrl) { - resolve.$template = fetchTemplate(templateUrl); - } else { - resolve.$template = $q.when(template); - } - if (options.contentTemplate) { - resolve.$template = $q.all([ resolve.$template, fetchTemplate(options.contentTemplate) ]).then(function(templates) { - var templateEl = angular.element(templates[0]); - var contentEl = findElement('[ng-bind="content"]', templateEl[0]).removeAttr('ng-bind').html(templates[1]); - if (!options.templateUrl) contentEl.next().remove(); - return templateEl[0].outerHTML; - }); + 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', + prefixClass: 'timepicker', + placement: 'bottom-left', + templateUrl: 'timepicker/timepicker.tpl.html', + trigger: 'focus', + container: false, + keyboard: true, + html: false, + 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' + }; + 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 $q.all(resolve).then(function(locals) { - var template = transformTemplate(locals.$template); - if (options.html) { - template = template.replace(/ng-bind="/gi, 'ng-bind-html="'); + 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); } - var element = angular.element('
').html(template.trim()).contents(); - var linkFn = $compile(element); - return { - locals: locals, - element: element, - link: function link(scope) { - locals.$scope = scope; - if (controller) { - var invokeCtrl = $controller(controller, locals, true); - if (bindToController) { - angular.extend(invokeCtrl.instance, locals); - } - var ctrl = angular.isObject(invokeCtrl) ? invokeCtrl : invokeCtrl(); - element.data('$ngControllerController', ctrl); - element.children().data('$ngControllerController', ctrl); - if (controllerAs) { - scope[controllerAs] = ctrl; - } + 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() + }); + $timepicker.$build(); + } else if (!$timepicker.$isBuilt) { + $timepicker.$build(); + } + }; + $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); + }); + } + }; + $timepicker.switchMeridian = function(date) { + if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) { + return; + } + var hours = (date || controller.$dateValue).getHours(); + controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12); + controller.$setViewValue(angular.copy(controller.$dateValue)); + controller.$render(); + }; + $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) + }); + } + var minutes = [], minute; + for (i = 0; i < options.length; i++) { + minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep); + minutes.push({ + date: minute, + label: formatDate(minute, minutesFormat), + selected: $timepicker.$date && $timepicker.$isSelected(minute, 1), + disabled: $timepicker.$isDisabled(minute, 1) + }); + } + var 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] ]); } - return linkFn.apply(null, arguments); } + scope.rows = rows; + scope.showSeconds = showSeconds; + scope.showAM = showAM; + scope.isAM = ($timepicker.$date || hours[midIndex].date).getHours() < 12; + scope.timeSeparator = timeSeparator; + $timepicker.$isBuilt = true; }; - }); - }; - 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; - }); - } - } - bsCompilerService.$inject = [ '$q', '$http', '$injector', '$compile', '$controller', '$templateCache' ]; - angular.module('mgcrea.ngStrap.helpers.dateFormatter', []).service('$dateFormatter', [ '$locale', 'dateFilter', function($locale, dateFilter) { - this.getDefaultLocale = function() { - return $locale.id; - }; - this.getDatetimeFormat = function(format, lang) { - return $locale.DATETIME_FORMATS[format] || format; - }; - this.weekdaysShort = function(lang) { - return $locale.DATETIME_FORMATS.SHORTDAY; - }; - function splitTimeFormat(format) { - return /(h+)([:\.])?(m+)([:\.])?(s*)[ ]?(a?)/i.exec(format).slice(1); - } - this.hoursFormat = function(timeFormat) { - return splitTimeFormat(timeFormat)[0]; - }; - this.minutesFormat = function(timeFormat) { - return splitTimeFormat(timeFormat)[2]; - }; - this.secondsFormat = function(timeFormat) { - return splitTimeFormat(timeFormat)[4]; - }; - this.timeSeparator = function(timeFormat) { - return splitTimeFormat(timeFormat)[1]; - }; - this.showSeconds = function(timeFormat) { - return !!splitTimeFormat(timeFormat)[4]; - }; - this.showAM = function(timeFormat) { - return !!splitTimeFormat(timeFormat)[5]; - }; - this.formatDate = function(date, format, lang, timezone) { - return dateFilter(date, format, timezone); - }; - } ]); - angular.module('mgcrea.ngStrap.helpers.dateParser', []).provider('$dateParser', [ '$localeProvider', function($localeProvider) { - function ParseDate() { - this.year = 1970; - this.month = 0; - this.day = 1; - this.hours = 0; - this.minutes = 0; - this.seconds = 0; - this.milliseconds = 0; - } - ParseDate.prototype.setMilliseconds = function(value) { - this.milliseconds = value; - }; - ParseDate.prototype.setSeconds = function(value) { - this.seconds = value; - }; - ParseDate.prototype.setMinutes = function(value) { - this.minutes = value; - }; - ParseDate.prototype.setHours = function(value) { - this.hours = value; - }; - ParseDate.prototype.getHours = function() { - return this.hours; - }; - ParseDate.prototype.setDate = function(value) { - this.day = value; - }; - ParseDate.prototype.setMonth = function(value) { - this.month = value; - }; - ParseDate.prototype.setFullYear = function(value) { - this.year = value; - }; - ParseDate.prototype.fromDate = function(value) { - this.year = value.getFullYear(); - this.month = value.getMonth(); - this.day = value.getDate(); - this.hours = value.getHours(); - this.minutes = value.getMinutes(); - this.seconds = value.getSeconds(); - this.milliseconds = value.getMilliseconds(); - return this; - }; - ParseDate.prototype.toDate = function() { - return new Date(this.year, this.month, this.day, this.hours, this.minutes, this.seconds, this.milliseconds); - }; - var proto = ParseDate.prototype; - function noop() {} - function isNumeric(n) { - return !isNaN(parseFloat(n)) && isFinite(n); - } - function indexOfCaseInsensitive(array, value) { - var len = array.length, str = value.toString().toLowerCase(); - for (var i = 0; i < len; i++) { - if (array[i].toLowerCase() === str) { - return i; - } - } - return -1; - } - var defaults = this.defaults = { - format: 'shortDate', - strict: false - }; - this.$get = [ '$locale', 'dateFilter', function($locale, dateFilter) { - var DateParserFactory = function(config) { - var options = angular.extend({}, defaults, config); - var $dateParser = {}; - var regExpMap = { - sss: '[0-9]{3}', - ss: '[0-5][0-9]', - s: options.strict ? '[1-5]?[0-9]' : '[0-9]|[0-5][0-9]', - mm: '[0-5][0-9]', - m: options.strict ? '[1-5]?[0-9]' : '[0-9]|[0-5][0-9]', - HH: '[01][0-9]|2[0-3]', - H: options.strict ? '1?[0-9]|2[0-3]' : '[01]?[0-9]|2[0-3]', - hh: '[0][1-9]|[1][012]', - h: options.strict ? '[1-9]|1[012]' : '0?[1-9]|1[012]', - a: 'AM|PM', - EEEE: $locale.DATETIME_FORMATS.DAY.join('|'), - EEE: $locale.DATETIME_FORMATS.SHORTDAY.join('|'), - dd: '0[1-9]|[12][0-9]|3[01]', - d: options.strict ? '[1-9]|[1-2][0-9]|3[01]' : '0?[1-9]|[1-2][0-9]|3[01]', - MMMM: $locale.DATETIME_FORMATS.MONTH.join('|'), - MMM: $locale.DATETIME_FORMATS.SHORTMONTH.join('|'), - MM: '0[1-9]|1[012]', - M: options.strict ? '[1-9]|1[012]' : '0?[1-9]|1[012]', - yyyy: '[1]{1}[0-9]{3}|[2]{1}[0-9]{3}', - yy: '[0-9]{2}', - y: options.strict ? '-?(0|[1-9][0-9]{0,3})' : '-?0*[0-9]{1,4}' - }; - var setFnMap = { - sss: proto.setMilliseconds, - ss: proto.setSeconds, - s: proto.setSeconds, - mm: proto.setMinutes, - m: proto.setMinutes, - HH: proto.setHours, - H: proto.setHours, - hh: proto.setHours, - h: proto.setHours, - EEEE: noop, - EEE: noop, - dd: proto.setDate, - d: proto.setDate, - a: function(value) { - var hours = this.getHours() % 12; - return this.setHours(value.match(/pm/i) ? hours + 12 : hours); - }, - MMMM: function(value) { - return this.setMonth(indexOfCaseInsensitive($locale.DATETIME_FORMATS.MONTH, value)); - }, - MMM: function(value) { - return this.setMonth(indexOfCaseInsensitive($locale.DATETIME_FORMATS.SHORTMONTH, value)); - }, - MM: function(value) { - return this.setMonth(1 * value - 1); - }, - M: function(value) { - return this.setMonth(1 * value - 1); - }, - yyyy: proto.setFullYear, - yy: function(value) { - return this.setFullYear(2e3 + 1 * value); - }, - y: function(value) { - return 1 * value <= 50 && value.length === 2 ? this.setFullYear(2e3 + 1 * value) : this.setFullYear(1 * value); + $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(); } }; - var regex, setMap; - $dateParser.init = function() { - $dateParser.$format = $locale.DATETIME_FORMATS[options.format] || options.format; - regex = regExpForFormat($dateParser.$format); - setMap = setMapForFormat($dateParser.$format); - }; - $dateParser.isValid = function(date) { - if (angular.isDate(date)) return !isNaN(date.getTime()); - return regex.test(date); - }; - $dateParser.parse = function(value, baseDate, format, timezone) { - if (format) format = $locale.DATETIME_FORMATS[format] || format; - if (angular.isDate(value)) value = dateFilter(value, format || $dateParser.$format, timezone); - var formatRegex = format ? regExpForFormat(format) : regex; - var formatSetMap = format ? setMapForFormat(format) : setMap; - var matches = formatRegex.exec(value); - if (!matches) return false; - var date = baseDate && !isNaN(baseDate.getTime()) ? new ParseDate().fromDate(baseDate) : new ParseDate().fromDate(new Date(1970, 0, 1, 0)); - for (var i = 0; i < matches.length - 1; i++) { - formatSetMap[i] && formatSetMap[i].call(date, matches[i + 1]); - } - var newDate = date.toDate(); - if (parseInt(date.day, 10) !== newDate.getDate()) { - return false; + $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; } - return newDate; + return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1; }; - $dateParser.getDateForAttribute = function(key, value) { - var date; - if (value === 'today') { - var today = new Date(); - date = new Date(today.getFullYear(), today.getMonth(), today.getDate() + (key === 'maxDate' ? 1 : 0), 0, 0, 0, key === 'minDate' ? 0 : -1); - } else if (angular.isString(value) && value.match(/^".+"$/)) { - date = new Date(value.substr(1, value.length - 2)); - } else if (isNumeric(value)) { - date = new Date(parseInt(value, 10)); - } else if (angular.isString(value) && 0 === value.length) { - date = key === 'minDate' ? -Infinity : +Infinity; + scope.$arrowAction = function(value, index) { + if (options.arrowBehavior === 'picker') { + $timepicker.$setTimeByStep(value, index); } else { - date = new Date(value); + $timepicker.$moveIndex(value, index); } - return date; }; - $dateParser.getTimeForAttribute = function(key, value) { - var time; - if (value === 'now') { - time = new Date().setFullYear(1970, 0, 1); - } else if (angular.isString(value) && value.match(/^".+"$/)) { - time = new Date(value.substr(1, value.length - 2)).setFullYear(1970, 0, 1); - } else if (isNumeric(value)) { - time = new Date(parseInt(value, 10)).setFullYear(1970, 0, 1); - } else if (angular.isString(value) && 0 === value.length) { - time = key === 'minTime' ? -Infinity : +Infinity; - } else { - time = $dateParser.parse(value, new Date(1970, 0, 1, 0)); + $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); } - return time; + $timepicker.select(newDate, index, true); }; - $dateParser.daylightSavingAdjust = function(date) { - if (!date) { - return null; + $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() + }); } - date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); - return date; + $timepicker.$build(); }; - $dateParser.timezoneOffsetAdjust = function(date, timezone, undo) { - if (!date) { - return null; - } - if (timezone && timezone === 'UTC') { - date = new Date(date.getTime()); - date.setMinutes(date.getMinutes() + (undo ? -1 : 1) * date.getTimezoneOffset()); + $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(); + } + targetEl.triggerHandler('click'); } - return date; }; - function setMapForFormat(format) { - var keys = Object.keys(setFnMap), i; - var map = [], sortedMap = []; - var clonedFormat = format; - for (i = 0; i < keys.length; i++) { - if (format.split(keys[i]).length > 1) { - var index = clonedFormat.search(keys[i]); - format = format.split(keys[i]).join(''); - if (setFnMap[keys[i]]) { - map[index] = setFnMap[keys[i]]; - } - } + $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; } - angular.forEach(map, function(v) { - if (v) sortedMap.push(v); - }); - return sortedMap; - } - function escapeReservedSymbols(text) { - return text.replace(/\//g, '[\\/]').replace('/-/g', '[-]').replace(/\./g, '[.]').replace(/\\s/g, '[\\s]'); - } - function regExpForFormat(format) { - var keys = Object.keys(regExpMap), i; - var re = format; - for (i = 0; i < keys.length; i++) { - re = re.split(keys[i]).join('${' + i + '}'); + 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; } - for (i = 0; i < keys.length; i++) { - re = re.split('${' + i + '}').join('(' + regExpMap[keys[i]] + ')'); + 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; } - format = escapeReservedSymbols(format); - return new RegExp('^' + re + '$', [ 'i' ]); } - $dateParser.init(); - return $dateParser; - }; - return DateParserFactory; - } ]; - } ]); - angular.module('mgcrea.ngStrap.helpers.debounce', []).factory('debounce', [ '$timeout', function($timeout) { - return function(func, wait, immediate) { - var timeout = null; - return function() { - var context = this, args = arguments, callNow = immediate && !timeout; - if (timeout) { - $timeout.cancel(timeout); + function focusElement() { + element[0].focus(); } - timeout = $timeout(function later() { - timeout = null; - if (!immediate) { - func.apply(context, args); + 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); } - }, wait, false); - if (callNow) { - func.apply(context, args); - } - return timeout; - }; - }; - } ]).factory('throttle', [ '$timeout', function($timeout) { - return function(func, wait, options) { - var timeout = null; - options || (options = {}); - return function() { - var context = this, args = arguments; - if (!timeout) { - if (options.leading !== false) { - func.apply(context, args); + _init(); + }; + var _destroy = $timepicker.destroy; + $timepicker.destroy = function() { + if (isNative && options.useNative) { + element.off('click', focusElement); } - timeout = $timeout(function later() { - timeout = null; - if (options.trailing !== false) { - func.apply(context, args); + _destroy(); + }; + 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); } - }, wait, false); - } - }; - }; - } ]); - angular.module('mgcrea.ngStrap.helpers.dimensions', []).factory('dimensions', [ '$document', '$window', function($document, $window) { - var jqLite = angular.element; - var fn = {}; - var nodeName = fn.nodeName = function(element, name) { - return element.nodeName && element.nodeName.toLowerCase() === name.toLowerCase(); - }; - fn.css = function(element, prop, extra) { - var value; - if (element.currentStyle) { - value = element.currentStyle[prop]; - } else if (window.getComputedStyle) { - value = window.getComputedStyle(element)[prop]; - } else { - value = element.style[prop]; - } - return extra === true ? parseFloat(value) || 0 : value; - }; - fn.offset = function(element) { - var boxRect = element.getBoundingClientRect(); - var docElement = element.ownerDocument; - return { - width: boxRect.width || element.offsetWidth, - height: boxRect.height || element.offsetHeight, - top: boxRect.top + (window.pageYOffset || docElement.documentElement.scrollTop) - (docElement.documentElement.clientTop || 0), - left: boxRect.left + (window.pageXOffset || docElement.documentElement.scrollLeft) - (docElement.documentElement.clientLeft || 0) - }; - }; - fn.setOffset = function(element, options, i) { - var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition, position = fn.css(element, 'position'), curElem = angular.element(element), props = {}; - if (position === 'static') { - element.style.position = 'relative'; - } - curOffset = fn.offset(element); - curCSSTop = fn.css(element, 'top'); - curCSSLeft = fn.css(element, 'left'); - calculatePosition = (position === 'absolute' || position === 'fixed') && (curCSSTop + curCSSLeft).indexOf('auto') > -1; - if (calculatePosition) { - curPosition = fn.position(element); - curTop = curPosition.top; - curLeft = curPosition.left; - } else { - curTop = parseFloat(curCSSTop) || 0; - curLeft = parseFloat(curCSSLeft) || 0; - } - if (angular.isFunction(options)) { - options = options.call(element, i, curOffset); - } - if (options.top !== null) { - props.top = options.top - curOffset.top + curTop; - } - if (options.left !== null) { - props.left = options.left - curOffset.left + curLeft; + }, 0, false); + }; + 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); + }; + return $timepicker; } - if ('using' in options) { - options.using.call(curElem, props); - } else { - curElem.css({ - top: props.top + 'px', - left: props.left + 'px' + 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 + }; + 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]; }); - } - }; - fn.position = function(element) { - var offsetParentRect = { - top: 0, - left: 0 - }, offsetParentElement, offset; - if (fn.css(element, 'position') === 'fixed') { - offset = element.getBoundingClientRect(); - } else { - offsetParentElement = offsetParent(element); - offset = fn.offset(element); - if (!nodeName(offsetParentElement, 'html')) { - offsetParentRect = fn.offset(offsetParentElement); - } - offsetParentRect.top += fn.css(offsetParentElement, 'borderTopWidth', true); - offsetParentRect.left += fn.css(offsetParentElement, 'borderLeftWidth', true); - } - return { - width: element.offsetWidth, - height: element.offsetHeight, - top: offset.top - offsetParentRect.top - fn.css(element, 'marginTop', true), - left: offset.left - offsetParentRect.left - fn.css(element, 'marginLeft', true) - }; - }; - var offsetParent = function offsetParentElement(element) { - var docElement = element.ownerDocument; - var offsetParent = element.offsetParent || docElement; - if (nodeName(offsetParent, '#document')) return docElement.documentElement; - while (offsetParent && !nodeName(offsetParent, 'html') && fn.css(offsetParent, 'position') === 'static') { - offsetParent = offsetParent.offsetParent; - } - return offsetParent || docElement.documentElement; - }; - fn.height = function(element, outer) { - var value = element.offsetHeight; - if (outer) { - value += fn.css(element, 'marginTop', true) + fn.css(element, 'marginBottom', true); - } else { - value -= fn.css(element, 'paddingTop', true) + fn.css(element, 'paddingBottom', true) + fn.css(element, 'borderTopWidth', true) + fn.css(element, 'borderBottomWidth', true); - } - return value; - }; - fn.width = function(element, outer) { - var value = element.offsetWidth; - if (outer) { - value += fn.css(element, 'marginLeft', true) + fn.css(element, 'marginRight', true); - } else { - value -= fn.css(element, 'paddingLeft', true) + fn.css(element, 'paddingRight', true) + fn.css(element, 'borderLeftWidth', true) + fn.css(element, 'borderRightWidth', true); - } - return value; - }; - return fn; - } ]); - angular.module('mgcrea.ngStrap.helpers.parseOptions', []).provider('$parseOptions', function() { - var defaults = this.defaults = { - regexp: /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/ - }; - this.$get = [ '$parse', '$q', function($parse, $q) { - function ParseOptionsFactory(attr, config) { - var $parseOptions = {}; - var options = angular.extend({}, defaults, config); - $parseOptions.$values = []; - var match, displayFn, valueName, keyName, groupByFn, valueFn, valuesFn; - $parseOptions.init = function() { - $parseOptions.$match = match = attr.match(options.regexp); - displayFn = $parse(match[2] || match[1]), valueName = match[4] || match[6], keyName = match[5], - groupByFn = $parse(match[3] || ''), valueFn = $parse(match[2] ? match[1] : valueName), - valuesFn = $parse(match[7]); + 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); }; - $parseOptions.valuesFn = function(scope, controller) { - return $q.when(valuesFn(scope, controller)).then(function(values) { - if (!angular.isArray(values)) { - values = []; - } - $parseOptions.$values = values.length ? parseValues(values, scope) : []; - return $parseOptions.$values; + 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; + } + controller.$dateValue = parsedTime; + } + controller.$parsers.unshift(function(viewValue) { + var date; + if (!viewValue) { + controller.$setValidity('date', true); + return null; + } + var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue); + if (!parsedTime || isNaN(parsedTime.getTime())) { + controller.$setValidity('date', false); + return undefined; + } else { + validateAgainstMinMaxTime(parsedTime); + } + 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()); }; - $parseOptions.displayValue = function(modelValue) { - var scope = {}; - scope[valueName] = modelValue; - return displayFn(scope); - }; - function parseValues(values, scope) { - return values.map(function(match, index) { - var locals = {}, label, value; - locals[valueName] = match; - label = displayFn(scope, locals); - value = valueFn(scope, locals); - return { - label: label, - value: value, - index: index - }; - }); + function getTimeFormattedString() { + return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat); } - $parseOptions.init(); - return $parseOptions; + scope.$on('$destroy', function() { + if (timepicker) timepicker.destroy(); + options = null; + timepicker = null; + }); } - return ParseOptionsFactory; - } ]; - }); - angular.version.minor < 3 && angular.version.dot < 14 && angular.module('ng').factory('$$rAF', [ '$window', '$timeout', function($window, $timeout) { - var requestAnimationFrame = $window.requestAnimationFrame || $window.webkitRequestAnimationFrame || $window.mozRequestAnimationFrame; - var cancelAnimationFrame = $window.cancelAnimationFrame || $window.webkitCancelAnimationFrame || $window.mozCancelAnimationFrame || $window.webkitCancelRequestAnimationFrame; - var rafSupported = !!requestAnimationFrame; - var raf = rafSupported ? function(fn) { - var id = requestAnimationFrame(fn); - return function() { - cancelAnimationFrame(id); - }; - } : function(fn) { - var timer = $timeout(fn, 16.66, false); - return function() { - $timeout.cancel(timer); - }; }; - raf.supported = rafSupported; - return raf; } ]); - angular.module('mgcrea.ngStrap.modal', [ 'mgcrea.ngStrap.core', 'mgcrea.ngStrap.helpers.dimensions' ]).provider('$modal', function() { + angular.module('mgcrea.ngStrap.tab', []).provider('$tab', function() { var defaults = this.defaults = { animation: 'am-fade', - backdropAnimation: 'am-fade', - prefixClass: 'modal', - prefixEvent: 'modal', - placement: 'top', - templateUrl: 'modal/modal.tpl.html', - template: '', - contentTemplate: false, - container: false, - element: null, - backdrop: true, - keyboard: true, - html: false, - show: true + template: 'tab/tab.tpl.html', + navClass: 'nav-tabs', + activeClass: 'active' }; - this.$get = [ '$window', '$rootScope', '$bsCompiler', '$q', '$templateCache', '$http', '$animate', '$timeout', '$sce', 'dimensions', function($window, $rootScope, $bsCompiler, $q, $templateCache, $http, $animate, $timeout, $sce, dimensions) { - var forEach = angular.forEach; - var trim = String.prototype.trim; - var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout; - var bodyElement = angular.element($window.document.body); - function ModalFactory(config) { - var $modal = {}; - var options = $modal.$options = angular.extend({}, defaults, config); - var promise = $modal.$promise = $bsCompiler.compile(options); - var scope = $modal.$scope = options.scope && options.scope.$new() || $rootScope.$new(); - if (!options.element && !options.container) { - options.container = 'body'; + 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); } - $modal.$id = options.id || options.element && options.element.attr('id') || ''; - forEach([ 'title', 'content' ], function(key) { - if (options[key]) scope[key] = $sce.trustAsHtml(options[key]); - }); - scope.$hide = function() { - scope.$$postDigest(function() { - $modal.hide(); - }); - }; - scope.$show = function() { + 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.select', [ 'mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions' ]).provider('$select', function() { + var defaults = this.defaults = { + animation: 'am-fade', + prefixClass: 'select', + prefixEvent: '$select', + placement: 'bottom-left', + templateUrl: 'select/select.tpl.html', + trigger: 'focus', + container: false, + keyboard: true, + html: false, + delay: 0, + multiple: false, + allNoneButtons: false, + sort: true, + 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($window, $document, $rootScope, $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; + function SelectFactory(element, controller, config) { + var $select = {}; + var options = angular.extend({}, defaults, config); + $select = $tooltip(element, options); + var scope = $select.$scope; + scope.$matches = []; + if (options.multiple) { + scope.$activeIndex = []; + } else { + scope.$activeIndex = -1; + } + scope.$isMultiple = options.multiple; + scope.$showAllNoneButtons = options.allNoneButtons && options.multiple; + scope.$iconCheckmark = options.iconCheckmark; + scope.$allText = options.allText; + scope.$noneText = options.noneText; + scope.$activate = function(index) { scope.$$postDigest(function() { - $modal.show(); + $select.activate(index); }); }; - scope.$toggle = function() { + scope.$select = function(index, evt) { scope.$$postDigest(function() { - $modal.toggle(); + $select.select(index); }); }; - $modal.$isShown = scope.$isShown = false; - var compileData, modalElement, modalScope; - var backdropElement = angular.element('
'); - backdropElement.css({ - position: 'fixed', - top: '0px', - left: '0px', - bottom: '0px', - right: '0px', - 'z-index': 1038 - }); - promise.then(function(data) { - compileData = data; - $modal.init(); - }); - $modal.init = function() { - if (options.show) { - scope.$$postDigest(function() { - $modal.show(); - }); - } + scope.$isVisible = function() { + return $select.$isVisible(); }; - $modal.destroy = function() { - destroyModalElement(); - if (backdropElement) { - backdropElement.remove(); - backdropElement = null; - } - scope.$destroy(); + scope.$isActive = function(index) { + return $select.$isActive(index); }; - $modal.show = function() { - if ($modal.$isShown) return; - var parent, after; - if (angular.isElement(options.container)) { - parent = options.container; - after = options.container[0].lastChild ? angular.element(options.container[0].lastChild) : null; - } else { - if (options.container) { - parent = findElement(options.container); - after = parent[0] && parent[0].lastChild ? angular.element(parent[0].lastChild) : null; - } else { - parent = null; - after = options.element; + scope.$selectAll = function() { + for (var i = 0; i < scope.$matches.length; i++) { + if (!scope.$isActive(i)) { + scope.$select(i); } } - if (modalElement) destroyModalElement(); - modalScope = $modal.$scope.$new(); - modalElement = $modal.$element = compileData.link(modalScope, function(clonedElement, scope) {}); - if (scope.$emit(options.prefixEvent + '.show.before', $modal).defaultPrevented) { - return; - } - modalElement.css({ - display: 'block' - }).addClass(options.placement); - if (options.animation) { - if (options.backdrop) { - backdropElement.addClass(options.backdropAnimation); + }; + scope.$selectNone = function() { + for (var i = 0; i < scope.$matches.length; i++) { + if (scope.$isActive(i)) { + scope.$select(i); } - modalElement.addClass(options.animation); - } - if (options.backdrop) { - $animate.enter(backdropElement, bodyElement, null); } - if (angular.version.minor <= 2) { - $animate.enter(modalElement, parent, after, enterAnimateCallback); + }; + $select.update = function(matches) { + scope.$matches = matches; + $select.$updateActiveIndex(); + }; + $select.activate = function(index) { + if (options.multiple) { + $select.$isActive(index) ? scope.$activeIndex.splice(scope.$activeIndex.indexOf(index), 1) : scope.$activeIndex.push(index); + if (options.sort) scope.$activeIndex.sort(function(a, b) { + return a - b; + }); } else { - $animate.enter(modalElement, parent, after).then(enterAnimateCallback); - } - $modal.$isShown = scope.$isShown = true; - safeDigest(scope); - var el = modalElement[0]; - requestAnimationFrame(function() { - el.focus(); - }); - bodyElement.addClass(options.prefixClass + '-open'); - if (options.animation) { - bodyElement.addClass(options.prefixClass + '-with-' + options.animation); + scope.$activeIndex = index; } - bindBackdropEvents(); - bindKeyboardEvents(); + return scope.$activeIndex; }; - function enterAnimateCallback() { - scope.$emit(options.prefixEvent + '.show', $modal); - } - $modal.hide = function() { - if (!$modal.$isShown) return; - if (scope.$emit(options.prefixEvent + '.hide.before', $modal).defaultPrevented) { - return; + $select.select = function(index) { + var value = scope.$matches[index].value; + scope.$apply(function() { + $select.activate(index); + if (options.multiple) { + controller.$setViewValue(scope.$activeIndex.map(function(index) { + if (angular.isUndefined(scope.$matches[index])) { + return null; + } + return scope.$matches[index].value; + })); + } else { + controller.$setViewValue(value); + $select.hide(); + } + }); + scope.$emit(options.prefixEvent + '.select', value, index, $select); + }; + $select.$updateActiveIndex = function() { + if (controller.$modelValue && scope.$matches.length) { + if (options.multiple && angular.isArray(controller.$modelValue)) { + scope.$activeIndex = controller.$modelValue.map(function(value) { + return $select.$getIndex(value); + }); + } else { + scope.$activeIndex = $select.$getIndex(controller.$modelValue); + } + } else if (scope.$activeIndex >= scope.$matches.length) { + scope.$activeIndex = options.multiple ? [] : 0; + } else if (!controller.$modelValue && !options.multiple) { + scope.$activeIndex = -1; } - if (angular.version.minor <= 2) { - $animate.leave(modalElement, leaveAnimateCallback); - } else { - $animate.leave(modalElement).then(leaveAnimateCallback); + }; + $select.$isVisible = function() { + if (!options.minLength || !controller) { + return scope.$matches.length; } - if (options.backdrop) { - $animate.leave(backdropElement); + return scope.$matches.length && controller.$viewValue.length >= options.minLength; + }; + $select.$isActive = function(index) { + if (options.multiple) { + return scope.$activeIndex.indexOf(index) !== -1; + } else { + return scope.$activeIndex === index; } - $modal.$isShown = scope.$isShown = false; - safeDigest(scope); - unbindBackdropEvents(); - unbindKeyboardEvents(); }; - function leaveAnimateCallback() { - scope.$emit(options.prefixEvent + '.hide', $modal); - bodyElement.removeClass(options.prefixClass + '-open'); - if (options.animation) { - bodyElement.removeClass(options.prefixClass + '-with-' + options.animation); + $select.$getIndex = function(value) { + var l = scope.$matches.length, i = l; + if (!l) return; + for (i = l; i--; ) { + if (scope.$matches[i].value === value) break; } - } - $modal.toggle = function() { - $modal.$isShown ? $modal.hide() : $modal.show(); + if (i < 0) return; + return i; }; - $modal.focus = function() { - modalElement[0].focus(); + $select.$onMouseDown = function(evt) { + evt.preventDefault(); + evt.stopPropagation(); + if (isTouch) { + var targetEl = angular.element(evt.target); + targetEl.triggerHandler('click'); + } }; - $modal.$onKeyUp = function(evt) { - if (evt.which === 27 && $modal.$isShown) { - $modal.hide(); + $select.$onKeyDown = function(evt) { + if (!/(9|13|38|40)/.test(evt.keyCode)) return; + if (evt.keyCode !== 9) { + evt.preventDefault(); evt.stopPropagation(); } - }; - function bindBackdropEvents() { - if (options.backdrop) { - modalElement.on('click', hideOnBackdropClick); - backdropElement.on('click', hideOnBackdropClick); - backdropElement.on('wheel', preventEventDefault); + if (options.multiple && evt.keyCode === 9) { + return $select.hide(); } - } - function unbindBackdropEvents() { - if (options.backdrop) { - modalElement.off('click', hideOnBackdropClick); - backdropElement.off('click', hideOnBackdropClick); - backdropElement.off('wheel', preventEventDefault); + if (!options.multiple && (evt.keyCode === 13 || evt.keyCode === 9)) { + return $select.select(scope.$activeIndex); } - } - function bindKeyboardEvents() { - if (options.keyboard) { - modalElement.on('keyup', $modal.$onKeyUp); + if (!options.multiple) { + if (evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--; else if (evt.keyCode === 38 && scope.$activeIndex < 0) scope.$activeIndex = scope.$matches.length - 1; else if (evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++; else if (angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0; + scope.$digest(); } - } - function unbindKeyboardEvents() { - if (options.keyboard) { - modalElement.off('keyup', $modal.$onKeyUp); + }; + $select.$isIE = function() { + var ua = $window.navigator.userAgent; + return ua.indexOf('MSIE ') > 0 || ua.indexOf('Trident/') > 0 || ua.indexOf('Edge/') > 0; + }; + $select.$selectScrollFix = function(e) { + if ($document[0].activeElement.tagName === 'UL') { + e.preventDefault(); + e.stopImmediatePropagation(); + e.target.focus(); } - } - function hideOnBackdropClick(evt) { - if (evt.target !== evt.currentTarget) return; - options.backdrop === 'static' ? $modal.focus() : $modal.hide(); - } - function preventEventDefault(evt) { - evt.preventDefault(); - } - function destroyModalElement() { - if ($modal.$isShown && modalElement !== null) { - unbindBackdropEvents(); - unbindKeyboardEvents(); + }; + var _show = $select.show; + $select.show = function() { + _show(); + if (options.multiple) { + $select.$element.addClass('select-multiple'); } - if (modalScope) { - modalScope.$destroy(); - modalScope = null; + $timeout(function() { + $select.$element.on(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown); + if (options.keyboard) { + element.on('keydown', $select.$onKeyDown); + } + }, 0, false); + }; + var _hide = $select.hide; + $select.hide = function() { + if (!options.multiple && !controller.$modelValue) { + scope.$activeIndex = -1; } - if (modalElement) { - modalElement.remove(); - modalElement = $modal.$element = null; + $select.$element.off(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown); + if (options.keyboard) { + element.off('keydown', $select.$onKeyDown); } - } - return $modal; - } - function safeDigest(scope) { - scope.$$phase || scope.$root && scope.$root.$$phase || scope.$digest(); - } - function findElement(query, element) { - return angular.element((element || document).querySelectorAll(query)); + _hide(true); + }; + return $select; } - return ModalFactory; + SelectFactory.defaults = defaults; + return SelectFactory; } ]; - }).directive('bsModal', [ '$window', '$sce', '$modal', function($window, $sce, $modal) { + }).directive('bsSelect', [ '$window', '$parse', '$q', '$select', '$parseOptions', function($window, $parse, $q, $select, $parseOptions) { + var defaults = $select.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, - element: element, - show: false + placeholder: defaults.placeholder }; - angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'controller', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation', 'id', 'prefixEvent', 'prefixClass' ], function(key) { + 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) { if (angular.isDefined(attr[key])) options[key] = attr[key]; }); var falseValueRegExp = /^(false|0|)$/i; - angular.forEach([ 'backdrop', 'keyboard', 'html', 'container' ], function(key) { + angular.forEach([ 'html', 'container', 'allNoneButtons', 'sort' ], function(key) { if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false; }); - angular.forEach([ 'title', 'content' ], function(key) { - attr[key] && attr.$observe(key, function(newValue, oldValue) { - scope[key] = $sce.trustAsHtml(newValue); + var dataMultiple = element.attr('data-multiple'); + if (angular.isDefined(dataMultiple)) { + if (falseValueRegExp.test(dataMultiple)) options.multiple = false; else options.multiple = dataMultiple; + } + if (element[0].nodeName.toLowerCase() === 'select') { + var inputEl = element; + inputEl.css('display', 'none'); + element = angular.element(''); + inputEl.after(element); + } + var parsedOptions = $parseOptions(attr.bsOptions); + var select = $select(element, controller, options); + if (select.$isIE()) { + element[0].addEventListener('blur', select.$selectScrollFix); + } + var watchedOptions = parsedOptions.$match[7].replace(/\|.+/, '').trim(); + scope.$watchCollection(watchedOptions, function(newValue, oldValue) { + parsedOptions.valuesFn(scope, controller).then(function(values) { + select.update(values); + controller.$render(); }); }); - attr.bsModal && scope.$watch(attr.bsModal, function(newValue, oldValue) { - if (angular.isObject(newValue)) { - angular.extend(scope, newValue); + scope.$watch(attr.ngModel, function(newValue, oldValue) { + select.$updateActiveIndex(); + controller.$render(); + }, true); + controller.$render = function() { + var selected, index; + if (options.multiple && angular.isArray(controller.$modelValue)) { + selected = controller.$modelValue.map(function(value) { + index = select.$getIndex(value); + return angular.isDefined(index) ? select.$scope.$matches[index].label : false; + }).filter(angular.isDefined); + if (selected.length > (options.maxLength || defaults.maxLength)) { + selected = selected.length + ' ' + (options.maxLengthHtml || defaults.maxLengthHtml); + } else { + selected = selected.join(', '); + } } else { - scope.content = newValue; + index = select.$getIndex(controller.$modelValue); + selected = angular.isDefined(index) ? select.$scope.$matches[index].label : false; } - }, true); - var modal = $modal(options); - element.on(attr.trigger || 'click', modal.toggle); + element.html((selected ? selected : options.placeholder) + (options.caretHtml ? options.caretHtml : defaults.caretHtml)); + }; + if (options.multiple) { + controller.$isEmpty = function(value) { + return !value || value.length === 0; + }; + } scope.$on('$destroy', function() { - if (modal) modal.destroy(); + if (select) select.destroy(); options = null; - modal = null; + select = null; }); } }; } ]); - angular.module('mgcrea.ngStrap.navbar', []).provider('$navbar', function() { + angular.module('mgcrea.ngStrap.scrollspy', [ 'mgcrea.ngStrap.helpers.debounce', 'mgcrea.ngStrap.helpers.dimensions' ]).provider('$scrollspy', function() { + var spies = this.$$spies = {}; var defaults = this.defaults = { - activeClass: 'active', - routeAttr: 'data-match-route', - strict: false - }; - this.$get = function() { - return { - defaults: defaults - }; - }; - }).directive('bsNavbar', [ '$window', '$location', '$navbar', function($window, $location, $navbar) { - var defaults = $navbar.defaults; - return { - restrict: 'A', - link: function postLink(scope, element, attr, controller) { - var options = angular.copy(defaults); - angular.forEach(Object.keys(defaults), function(key) { - if (angular.isDefined(attr[key])) options[key] = attr[key]; - }); - scope.$watch(function() { - return $location.path(); - }, function(newValue, oldValue) { - var liElements = element[0].querySelectorAll('li[' + options.routeAttr + ']'); - angular.forEach(liElements, function(li) { - var liElement = angular.element(li); - var pattern = liElement.attr(options.routeAttr).replace('/', '\\/'); - if (options.strict) { - pattern = '^' + pattern + '$'; - } - var regexp = new RegExp(pattern, 'i'); - if (regexp.test(newValue)) { - liElement.addClass(options.activeClass); - } else { - liElement.removeClass(options.activeClass); - } - }); - }); - } - }; - } ]); - 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 = { - debounce: 150, - throttle: 100, - offset: 100 + debounce: 150, + throttle: 100, + offset: 100 }; this.$get = [ '$window', '$document', '$rootScope', 'dimensions', 'debounce', 'throttle', function($window, $document, $rootScope, dimensions, debounce, throttle) { var windowEl = angular.element($window); @@ -2413,974 +1817,1277 @@ } }; } ]); - angular.module('mgcrea.ngStrap.select', [ 'mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions' ]).provider('$select', function() { + angular.module('mgcrea.ngStrap.popover', [ 'mgcrea.ngStrap.tooltip' ]).provider('$popover', function() { var defaults = this.defaults = { animation: 'am-fade', - prefixClass: 'select', - prefixEvent: '$select', - placement: 'bottom-left', - templateUrl: 'select/select.tpl.html', - trigger: 'focus', + customClass: '', container: false, + target: false, + placement: 'right', + templateUrl: 'popover/popover.tpl.html', + contentTemplate: false, + trigger: 'click', keyboard: true, html: false, + title: '', + content: '', delay: 0, - multiple: false, - allNoneButtons: false, - sort: true, - caretHtml: ' ', - placeholder: 'Choose among the following...', - allText: 'All', - noneText: 'None', - maxLength: 3, - maxLengthHtml: 'selected', - iconCheckmark: 'glyphicon glyphicon-ok' + autoClose: false }; - this.$get = [ '$window', '$document', '$rootScope', '$tooltip', '$timeout', function($window, $document, $rootScope, $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; - function SelectFactory(element, controller, config) { - var $select = {}; + this.$get = [ '$tooltip', function($tooltip) { + function PopoverFactory(element, config) { var options = angular.extend({}, defaults, config); - $select = $tooltip(element, options); - var scope = $select.$scope; - scope.$matches = []; - if (options.multiple) { - scope.$activeIndex = []; - } else { - scope.$activeIndex = -1; + var $popover = $tooltip(element, options); + if (options.content) { + $popover.$scope.content = options.content; } - scope.$isMultiple = options.multiple; - scope.$showAllNoneButtons = options.allNoneButtons && options.multiple; - scope.$iconCheckmark = options.iconCheckmark; - scope.$allText = options.allText; - scope.$noneText = options.noneText; - scope.$activate = function(index) { - scope.$$postDigest(function() { - $select.activate(index); - }); - }; - scope.$select = function(index, evt) { - scope.$$postDigest(function() { - $select.select(index); - }); - }; - scope.$isVisible = function() { - return $select.$isVisible(); - }; - scope.$isActive = function(index) { - return $select.$isActive(index); - }; - scope.$selectAll = function() { - for (var i = 0; i < scope.$matches.length; i++) { - if (!scope.$isActive(i)) { - scope.$select(i); - } - } - }; - scope.$selectNone = function() { - for (var i = 0; i < scope.$matches.length; i++) { - if (scope.$isActive(i)) { - scope.$select(i); - } - } - }; - $select.update = function(matches) { - scope.$matches = matches; - $select.$updateActiveIndex(); + 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 }; - $select.activate = function(index) { - if (options.multiple) { - $select.$isActive(index) ? scope.$activeIndex.splice(scope.$activeIndex.indexOf(index), 1) : scope.$activeIndex.push(index); - if (options.sort) scope.$activeIndex.sort(function(a, b) { - return a - b; + 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.$activeIndex = index; + scope.content = newValue; } - return scope.$activeIndex; - }; - $select.select = function(index) { - var value = scope.$matches[index].value; - scope.$apply(function() { - $select.activate(index); - if (options.multiple) { - controller.$setViewValue(scope.$activeIndex.map(function(index) { - return scope.$matches[index].value; - })); - } else { - controller.$setViewValue(value); - $select.hide(); - } + angular.isDefined(oldValue) && requestAnimationFrame(function() { + popover && popover.$applyPlacement(); }); - scope.$emit(options.prefixEvent + '.select', value, index, $select); - }; - $select.$updateActiveIndex = function() { - if (controller.$modelValue && scope.$matches.length) { - if (options.multiple && angular.isArray(controller.$modelValue)) { - scope.$activeIndex = controller.$modelValue.map(function(value) { - return $select.$getIndex(value); - }); - } else { - scope.$activeIndex = $select.$getIndex(controller.$modelValue); - } - } else if (scope.$activeIndex >= scope.$matches.length) { - scope.$activeIndex = options.multiple ? [] : 0; - } - }; - $select.$isVisible = function() { - if (!options.minLength || !controller) { - return scope.$matches.length; - } - return scope.$matches.length && controller.$viewValue.length >= options.minLength; - }; - $select.$isActive = function(index) { - if (options.multiple) { - return scope.$activeIndex.indexOf(index) !== -1; - } else { - return scope.$activeIndex === index; - } - }; - $select.$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 (i < 0) return; - return i; - }; - $select.$onMouseDown = function(evt) { - evt.preventDefault(); - evt.stopPropagation(); - if (isTouch) { - var targetEl = angular.element(evt.target); - targetEl.triggerHandler('click'); - } - }; - $select.$onKeyDown = function(evt) { - if (!/(9|13|38|40)/.test(evt.keyCode)) return; - evt.preventDefault(); - evt.stopPropagation(); - if (options.multiple && evt.keyCode === 9) { - return $select.hide(); - } - if (!options.multiple && (evt.keyCode === 13 || evt.keyCode === 9)) { - return $select.select(scope.$activeIndex); - } - if (!options.multiple) { - if (evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--; else if (evt.keyCode === 38 && scope.$activeIndex < 0) scope.$activeIndex = scope.$matches.length - 1; 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 = $select.show; - $select.show = function() { - _show(); - if (options.multiple) { - $select.$element.addClass('select-multiple'); - } - $timeout(function() { - $select.$element.on(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown); - if (options.keyboard) { - element.on('keydown', $select.$onKeyDown); - } - }, 0, false); - }; - var _hide = $select.hide; - $select.hide = function() { - if (!options.multiple && !controller.$modelValue) { - scope.$activeIndex = -1; - } - $select.$element.off(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown); - if (options.keyboard) { - element.off('keydown', $select.$onKeyDown); - } - _hide(true); - }; - return $select; + }, 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; + }); } - SelectFactory.defaults = defaults; - return SelectFactory; - } ]; - }).directive('bsSelect', [ '$window', '$parse', '$q', '$select', '$parseOptions', function($window, $parse, $q, $select, $parseOptions) { - var defaults = $select.defaults; + }; + } ]); + angular.module('mgcrea.ngStrap.navbar', []).provider('$navbar', function() { + var defaults = this.defaults = { + activeClass: 'active', + routeAttr: 'data-match-route', + strict: false + }; + this.$get = function() { + return { + defaults: defaults + }; + }; + }).directive('bsNavbar', [ '$window', '$location', '$navbar', function($window, $location, $navbar) { + var defaults = $navbar.defaults; return { - restrict: 'EAC', - require: 'ngModel', + restrict: 'A', link: function postLink(scope, element, attr, controller) { - var options = { - scope: scope, - placeholder: defaults.placeholder - }; - 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) { + var options = angular.copy(defaults); + angular.forEach(Object.keys(defaults), function(key) { if (angular.isDefined(attr[key])) options[key] = attr[key]; }); - var falseValueRegExp = /^(false|0|)$/i; - angular.forEach([ 'html', 'container', 'allNoneButtons', 'sort' ], function(key) { - if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false; - }); - var dataMultiple = element.attr('data-multiple'); - if (angular.isDefined(dataMultiple)) { - if (falseValueRegExp.test(dataMultiple)) options.multiple = false; else options.multiple = dataMultiple; - } - if (element[0].nodeName.toLowerCase() === 'select') { - var inputEl = element; - inputEl.css('display', 'none'); - element = angular.element(''); - inputEl.after(element); - } - var parsedOptions = $parseOptions(attr.bsOptions); - var select = $select(element, controller, options); - var watchedOptions = parsedOptions.$match[7].replace(/\|.+/, '').trim(); - scope.$watchCollection(watchedOptions, function(newValue, oldValue) { - parsedOptions.valuesFn(scope, controller).then(function(values) { - select.update(values); - controller.$render(); - }); - }); - scope.$watch(attr.ngModel, function(newValue, oldValue) { - select.$updateActiveIndex(); - controller.$render(); - }, true); - controller.$render = function() { - var selected, index; - if (options.multiple && angular.isArray(controller.$modelValue)) { - selected = controller.$modelValue.map(function(value) { - index = select.$getIndex(value); - return angular.isDefined(index) ? select.$scope.$matches[index].label : false; - }).filter(angular.isDefined); - if (selected.length > (options.maxLength || defaults.maxLength)) { - selected = selected.length + ' ' + (options.maxLengthHtml || defaults.maxLengthHtml); + scope.$watch(function() { + return $location.path(); + }, function(newValue, oldValue) { + var liElements = element[0].querySelectorAll('li[' + options.routeAttr + ']'); + angular.forEach(liElements, function(li) { + var liElement = angular.element(li); + var pattern = liElement.attr(options.routeAttr).replace('/', '\\/'); + if (options.strict) { + pattern = '^' + pattern + '$'; + } + var regexp = new RegExp(pattern, 'i'); + if (regexp.test(newValue)) { + liElement.addClass(options.activeClass); } else { - selected = selected.join(', '); + liElement.removeClass(options.activeClass); } - } else { - index = select.$getIndex(controller.$modelValue); - selected = angular.isDefined(index) ? select.$scope.$matches[index].label : false; - } - element.html((selected ? selected : options.placeholder) + (options.caretHtml ? options.caretHtml : defaults.caretHtml)); - }; - if (options.multiple) { - controller.$isEmpty = function(value) { - return !value || value.length === 0; - }; - } - scope.$on('$destroy', function() { - if (select) select.destroy(); - options = null; - select = null; + }); }); } }; } ]); - angular.module('mgcrea.ngStrap.timepicker', [ 'mgcrea.ngStrap.helpers.dateParser', 'mgcrea.ngStrap.helpers.dateFormatter', 'mgcrea.ngStrap.tooltip' ]).provider('$timepicker', function() { + angular.module('mgcrea.ngStrap.modal', [ 'mgcrea.ngStrap.core', 'mgcrea.ngStrap.helpers.dimensions' ]).provider('$modal', function() { var defaults = this.defaults = { animation: 'am-fade', - prefixClass: 'timepicker', - placement: 'bottom-left', - templateUrl: 'timepicker/timepicker.tpl.html', - trigger: 'focus', + backdropAnimation: 'am-fade', + prefixClass: 'modal', + prefixEvent: 'modal', + placement: 'top', + templateUrl: 'modal/modal.tpl.html', + template: '', + contentTemplate: false, container: false, + element: null, + backdrop: true, keyboard: true, html: false, - 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' + show: true }; - 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(); - } - 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); - } - 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); + this.$get = [ '$window', '$rootScope', '$bsCompiler', '$animate', '$timeout', '$sce', 'dimensions', function($window, $rootScope, $bsCompiler, $animate, $timeout, $sce, dimensions) { + var forEach = angular.forEach; + var trim = String.prototype.trim; + var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout; + var bodyElement = angular.element($window.document.body); + function ModalFactory(config) { + var $modal = {}; + var options = $modal.$options = angular.extend({}, defaults, config); + var promise = $modal.$promise = $bsCompiler.compile(options); + var scope = $modal.$scope = options.scope && options.scope.$new() || $rootScope.$new(); + if (!options.element && !options.container) { + options.container = 'body'; + } + $modal.$id = options.id || options.element && options.element.attr('id') || ''; + forEach([ 'title', 'content' ], function(key) { + if (options[key]) scope[key] = $sce.trustAsHtml(options[key]); + }); + scope.$hide = function() { + scope.$$postDigest(function() { + $modal.hide(); + }); }; - scope.$moveIndex = function(value, index) { - $timepicker.$moveIndex(value, index); + scope.$show = function() { + scope.$$postDigest(function() { + $modal.show(); + }); }; - scope.$switchMeridian = function(date) { - $timepicker.switchMeridian(date); + scope.$toggle = function() { + scope.$$postDigest(function() { + $modal.toggle(); + }); }; - $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() + $modal.$isShown = scope.$isShown = false; + var compileData, modalElement, modalScope; + var backdropElement = angular.element('
'); + backdropElement.css({ + position: 'fixed', + top: '0px', + left: '0px', + bottom: '0px', + right: '0px', + 'z-index': 1038 + }); + promise.then(function(data) { + compileData = data; + $modal.init(); + }); + $modal.init = function() { + if (options.show) { + scope.$$postDigest(function() { + $modal.show(); }); - $timepicker.$build(); - } else if (!$timepicker.$isBuilt) { - $timepicker.$build(); } }; - $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); - }); + $modal.destroy = function() { + destroyModalElement(); + if (backdropElement) { + backdropElement.remove(); + backdropElement = null; } + scope.$destroy(); }; - $timepicker.switchMeridian = function(date) { - if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) { + $modal.show = function() { + if ($modal.$isShown) return; + var parent, after; + if (angular.isElement(options.container)) { + parent = options.container; + after = options.container[0].lastChild ? angular.element(options.container[0].lastChild) : null; + } else { + if (options.container) { + parent = findElement(options.container); + after = parent[0] && parent[0].lastChild ? angular.element(parent[0].lastChild) : null; + } else { + parent = null; + after = options.element; + } + } + if (modalElement) destroyModalElement(); + modalScope = $modal.$scope.$new(); + modalElement = $modal.$element = compileData.link(modalScope, function(clonedElement, scope) {}); + if (scope.$emit(options.prefixEvent + '.show.before', $modal).defaultPrevented) { return; } - 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) - }); + modalElement.css({ + display: 'block' + }).addClass(options.placement); + if (options.animation) { + if (options.backdrop) { + backdropElement.addClass(options.backdropAnimation); + } + modalElement.addClass(options.animation); } - 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.backdrop) { + $animate.enter(backdropElement, bodyElement, null); } - 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) - }); + if (angular.version.minor <= 2) { + $animate.enter(modalElement, parent, after, enterAnimateCallback); + } else { + $animate.enter(modalElement, parent, after).then(enterAnimateCallback); } - 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] ]); - } + $modal.$isShown = scope.$isShown = true; + safeDigest(scope); + var el = modalElement[0]; + requestAnimationFrame(function() { + el.focus(); + }); + bodyElement.addClass(options.prefixClass + '-open'); + if (options.animation) { + bodyElement.addClass(options.prefixClass + '-with-' + options.animation); } - scope.rows = rows; - scope.showSeconds = showSeconds; - scope.showAM = showAM; - scope.isAM = ($timepicker.$date || hours[midIndex].date).getHours() < 12; - scope.timeSeparator = timeSeparator; - $timepicker.$isBuilt = true; + bindBackdropEvents(); + bindKeyboardEvents(); }; - $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(); + function enterAnimateCallback() { + scope.$emit(options.prefixEvent + '.show', $modal); + } + $modal.hide = function() { + if (!$modal.$isShown) return; + if (scope.$emit(options.prefixEvent + '.hide.before', $modal).defaultPrevented) { + return; } - }; - $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; + if (angular.version.minor <= 2) { + $animate.leave(modalElement, leaveAnimateCallback); + } else { + $animate.leave(modalElement).then(leaveAnimateCallback); } - return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1; + if (options.backdrop) { + $animate.leave(backdropElement); + } + $modal.$isShown = scope.$isShown = false; + safeDigest(scope); + unbindBackdropEvents(); + unbindKeyboardEvents(); }; - scope.$arrowAction = function(value, index) { - if (options.arrowBehavior === 'picker') { - $timepicker.$setTimeByStep(value, index); - } else { - $timepicker.$moveIndex(value, index); + function leaveAnimateCallback() { + scope.$emit(options.prefixEvent + '.hide', $modal); + bodyElement.removeClass(options.prefixClass + '-open'); + if (options.animation) { + bodyElement.removeClass(options.prefixClass + '-with-' + options.animation); } + } + $modal.toggle = function() { + $modal.$isShown ? $modal.hide() : $modal.show(); }; - $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); + $modal.focus = function() { + modalElement[0].focus(); + }; + $modal.$onKeyUp = function(evt) { + if (evt.which === 27 && $modal.$isShown) { + $modal.hide(); + evt.stopPropagation(); } - $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() - }); + function bindBackdropEvents() { + if (options.backdrop) { + modalElement.on('click', hideOnBackdropClick); + backdropElement.on('click', hideOnBackdropClick); + backdropElement.on('wheel', preventEventDefault); } - $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(); - } - targetEl.triggerHandler('click'); + } + function unbindBackdropEvents() { + if (options.backdrop) { + modalElement.off('click', hideOnBackdropClick); + backdropElement.off('click', hideOnBackdropClick); + backdropElement.off('wheel', preventEventDefault); } - }; - $timepicker.$onKeyDown = function(evt) { - if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return; + } + function bindKeyboardEvents() { + if (options.keyboard) { + modalElement.on('keyup', $modal.$onKeyUp); + } + } + function unbindKeyboardEvents() { + if (options.keyboard) { + modalElement.off('keyup', $modal.$onKeyUp); + } + } + function hideOnBackdropClick(evt) { + if (evt.target !== evt.currentTarget) return; + options.backdrop === 'static' ? $modal.focus() : $modal.hide(); + } + function preventEventDefault(evt) { evt.preventDefault(); - evt.stopPropagation(); - if (evt.keyCode === 13) { - $timepicker.hide(true); - return; + } + function destroyModalElement() { + if ($modal.$isShown && modalElement !== null) { + unbindBackdropEvents(); + unbindKeyboardEvents(); } - 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; + if (modalScope) { + modalScope.$destroy(); + modalScope = null; } - 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 ]; + if (modalElement) { + modalElement.remove(); + modalElement = $modal.$element = null; } - $timepicker.select(newDate, selectedIndex, true); - createSelection(selectRange[0], selectRange[1]); - parentScope.$digest(); + } + return $modal; + } + function safeDigest(scope) { + scope.$$phase || scope.$root && scope.$root.$$phase || scope.$digest(); + } + function findElement(query, element) { + return angular.element((element || document).querySelectorAll(query)); + } + return ModalFactory; + } ]; + }).directive('bsModal', [ '$window', '$sce', '$modal', function($window, $sce, $modal) { + return { + restrict: 'EAC', + scope: true, + link: function postLink(scope, element, attr, transclusion) { + var options = { + scope: scope, + element: element, + show: false }; - 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; + angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation', 'backdropAnimation', 'id', 'prefixEvent', 'prefixClass' ], function(key) { + if (angular.isDefined(attr[key])) options[key] = attr[key]; + }); + var falseValueRegExp = /^(false|0|)$/i; + angular.forEach([ 'backdrop', 'keyboard', 'html', 'container' ], function(key) { + if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false; + }); + angular.forEach([ 'title', 'content' ], function(key) { + attr[key] && attr.$observe(key, function(newValue, oldValue) { + scope[key] = $sce.trustAsHtml(newValue); + }); + }); + attr.bsModal && scope.$watch(attr.bsModal, function(newValue, oldValue) { + if (angular.isObject(newValue)) { + angular.extend(scope, newValue); + } else { + scope.content = newValue; } + }, true); + var modal = $modal(options); + element.on(attr.trigger || 'click', modal.toggle); + scope.$on('$destroy', function() { + if (modal) modal.destroy(); + options = null; + modal = null; + }); + } + }; + } ]); + angular.version.minor < 3 && angular.version.dot < 14 && angular.module('ng').factory('$$rAF', [ '$window', '$timeout', function($window, $timeout) { + var requestAnimationFrame = $window.requestAnimationFrame || $window.webkitRequestAnimationFrame || $window.mozRequestAnimationFrame; + var cancelAnimationFrame = $window.cancelAnimationFrame || $window.webkitCancelAnimationFrame || $window.mozCancelAnimationFrame || $window.webkitCancelRequestAnimationFrame; + var rafSupported = !!requestAnimationFrame; + var raf = rafSupported ? function(fn) { + var id = requestAnimationFrame(fn); + return function() { + cancelAnimationFrame(id); + }; + } : function(fn) { + var timer = $timeout(fn, 16.66, false); + return function() { + $timeout.cancel(timer); + }; + }; + raf.supported = rafSupported; + return raf; + } ]); + angular.module('mgcrea.ngStrap.helpers.parseOptions', []).provider('$parseOptions', function() { + var defaults = this.defaults = { + regexp: /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/ + }; + this.$get = [ '$parse', '$q', function($parse, $q) { + function ParseOptionsFactory(attr, config) { + var $parseOptions = {}; + var options = angular.extend({}, defaults, config); + $parseOptions.$values = []; + var match, displayFn, valueName, keyName, groupByFn, valueFn, valuesFn; + $parseOptions.init = function() { + $parseOptions.$match = match = attr.match(options.regexp); + displayFn = $parse(match[2] || match[1]), valueName = match[4] || match[6], keyName = match[5], + groupByFn = $parse(match[3] || ''), valueFn = $parse(match[2] ? match[1] : valueName), + valuesFn = $parse(match[7]); + }; + $parseOptions.valuesFn = function(scope, controller) { + return $q.when(valuesFn(scope, controller)).then(function(values) { + if (!angular.isArray(values)) { + values = []; + } + $parseOptions.$values = values.length ? parseValues(values, scope) : []; + return $parseOptions.$values; + }); + }; + $parseOptions.displayValue = function(modelValue) { + var scope = {}; + scope[valueName] = modelValue; + return displayFn(scope); + }; + function parseValues(values, scope) { + return values.map(function(match, index) { + var locals = {}, label, value; + locals[valueName] = match; + label = displayFn(scope, locals); + value = valueFn(scope, locals); + return { + label: label, + value: value, + index: index + }; + }); } - function focusElement() { - element[0].focus(); + $parseOptions.init(); + return $parseOptions; + } + return ParseOptionsFactory; + } ]; + }); + angular.module('mgcrea.ngStrap.helpers.dimensions', []).factory('dimensions', [ '$document', '$window', function($document, $window) { + var jqLite = angular.element; + var fn = {}; + var nodeName = fn.nodeName = function(element, name) { + return element.nodeName && element.nodeName.toLowerCase() === name.toLowerCase(); + }; + fn.css = function(element, prop, extra) { + var value; + if (element.currentStyle) { + value = element.currentStyle[prop]; + } else if (window.getComputedStyle) { + value = window.getComputedStyle(element)[prop]; + } else { + value = element.style[prop]; + } + return extra === true ? parseFloat(value) || 0 : value; + }; + fn.offset = function(element) { + var boxRect = element.getBoundingClientRect(); + var docElement = element.ownerDocument; + return { + width: boxRect.width || element.offsetWidth, + height: boxRect.height || element.offsetHeight, + top: boxRect.top + (window.pageYOffset || docElement.documentElement.scrollTop) - (docElement.documentElement.clientTop || 0), + left: boxRect.left + (window.pageXOffset || docElement.documentElement.scrollLeft) - (docElement.documentElement.clientLeft || 0) + }; + }; + fn.setOffset = function(element, options, i) { + var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition, position = fn.css(element, 'position'), curElem = angular.element(element), props = {}; + if (position === 'static') { + element.style.position = 'relative'; + } + curOffset = fn.offset(element); + curCSSTop = fn.css(element, 'top'); + curCSSLeft = fn.css(element, 'left'); + calculatePosition = (position === 'absolute' || position === 'fixed') && (curCSSTop + curCSSLeft).indexOf('auto') > -1; + if (calculatePosition) { + curPosition = fn.position(element); + curTop = curPosition.top; + curLeft = curPosition.left; + } else { + curTop = parseFloat(curCSSTop) || 0; + curLeft = parseFloat(curCSSLeft) || 0; + } + if (angular.isFunction(options)) { + options = options.call(element, i, curOffset); + } + if (options.top !== null) { + props.top = options.top - curOffset.top + curTop; + } + if (options.left !== null) { + props.left = options.left - curOffset.left + curLeft; + } + if ('using' in options) { + options.using.call(curElem, props); + } else { + curElem.css({ + top: props.top + 'px', + left: props.left + 'px' + }); + } + }; + fn.position = function(element) { + var offsetParentRect = { + top: 0, + left: 0 + }, offsetParentElement, offset; + if (fn.css(element, 'position') === 'fixed') { + offset = element.getBoundingClientRect(); + } else { + offsetParentElement = offsetParent(element); + offset = fn.offset(element); + if (!nodeName(offsetParentElement, 'html')) { + offsetParentRect = fn.offset(offsetParentElement); } - 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); + offsetParentRect.top += fn.css(offsetParentElement, 'borderTopWidth', true); + offsetParentRect.left += fn.css(offsetParentElement, 'borderLeftWidth', true); + } + return { + width: element.offsetWidth, + height: element.offsetHeight, + top: offset.top - offsetParentRect.top - fn.css(element, 'marginTop', true), + left: offset.left - offsetParentRect.left - fn.css(element, 'marginLeft', true) + }; + }; + var offsetParent = function offsetParentElement(element) { + var docElement = element.ownerDocument; + var offsetParent = element.offsetParent || docElement; + if (nodeName(offsetParent, '#document')) return docElement.documentElement; + while (offsetParent && !nodeName(offsetParent, 'html') && fn.css(offsetParent, 'position') === 'static') { + offsetParent = offsetParent.offsetParent; + } + return offsetParent || docElement.documentElement; + }; + fn.height = function(element, outer) { + var value = element.offsetHeight; + if (outer) { + value += fn.css(element, 'marginTop', true) + fn.css(element, 'marginBottom', true); + } else { + value -= fn.css(element, 'paddingTop', true) + fn.css(element, 'paddingBottom', true) + fn.css(element, 'borderTopWidth', true) + fn.css(element, 'borderBottomWidth', true); + } + return value; + }; + fn.width = function(element, outer) { + var value = element.offsetWidth; + if (outer) { + value += fn.css(element, 'marginLeft', true) + fn.css(element, 'marginRight', true); + } else { + value -= fn.css(element, 'paddingLeft', true) + fn.css(element, 'paddingRight', true) + fn.css(element, 'borderLeftWidth', true) + fn.css(element, 'borderRightWidth', true); + } + return value; + }; + return fn; + } ]); + angular.module('mgcrea.ngStrap.helpers.debounce', []).factory('debounce', [ '$timeout', function($timeout) { + return function(func, wait, immediate) { + var timeout = null; + return function() { + var context = this, args = arguments, callNow = immediate && !timeout; + if (timeout) { + $timeout.cancel(timeout); + } + timeout = $timeout(function later() { + timeout = null; + if (!immediate) { + func.apply(context, args); } - _init(); - }; - var _destroy = $timepicker.destroy; - $timepicker.destroy = function() { - if (isNative && options.useNative) { - element.off('click', focusElement); + }, wait, false); + if (callNow) { + func.apply(context, args); + } + return timeout; + }; + }; + } ]).factory('throttle', [ '$timeout', function($timeout) { + return function(func, wait, options) { + var timeout = null; + options || (options = {}); + return function() { + var context = this, args = arguments; + if (!timeout) { + if (options.leading !== false) { + func.apply(context, args); } - _destroy(); - }; - 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); + timeout = $timeout(function later() { + timeout = null; + if (options.trailing !== false) { + func.apply(context, args); } - }, 0, false); + }, wait, false); + } + }; + }; + } ]); + angular.module('mgcrea.ngStrap.helpers.dateParser', []).provider('$dateParser', [ '$localeProvider', function($localeProvider) { + function ParseDate() { + this.year = 1970; + this.month = 0; + this.day = 1; + this.hours = 0; + this.minutes = 0; + this.seconds = 0; + this.milliseconds = 0; + } + ParseDate.prototype.setMilliseconds = function(value) { + this.milliseconds = value; + }; + ParseDate.prototype.setSeconds = function(value) { + this.seconds = value; + }; + ParseDate.prototype.setMinutes = function(value) { + this.minutes = value; + }; + ParseDate.prototype.setHours = function(value) { + this.hours = value; + }; + ParseDate.prototype.getHours = function() { + return this.hours; + }; + ParseDate.prototype.setDate = function(value) { + this.day = value; + }; + ParseDate.prototype.setMonth = function(value) { + this.month = value; + }; + ParseDate.prototype.setFullYear = function(value) { + this.year = value; + }; + ParseDate.prototype.fromDate = function(value) { + this.year = value.getFullYear(); + this.month = value.getMonth(); + this.day = value.getDate(); + this.hours = value.getHours(); + this.minutes = value.getMinutes(); + this.seconds = value.getSeconds(); + this.milliseconds = value.getMilliseconds(); + return this; + }; + ParseDate.prototype.toDate = function() { + return new Date(this.year, this.month, this.day, this.hours, this.minutes, this.seconds, this.milliseconds); + }; + var proto = ParseDate.prototype; + function noop() {} + function isNumeric(n) { + return !isNaN(parseFloat(n)) && isFinite(n); + } + function indexOfCaseInsensitive(array, value) { + var len = array.length, str = value.toString().toLowerCase(); + for (var i = 0; i < len; i++) { + if (array[i].toLowerCase() === str) { + return i; + } + } + return -1; + } + var defaults = this.defaults = { + format: 'shortDate', + strict: false + }; + this.$get = [ '$locale', 'dateFilter', function($locale, dateFilter) { + var DateParserFactory = function(config) { + var options = angular.extend({}, defaults, config); + var $dateParser = {}; + var regExpMap = { + sss: '[0-9]{3}', + ss: '[0-5][0-9]', + s: options.strict ? '[1-5]?[0-9]' : '[0-9]|[0-5][0-9]', + mm: '[0-5][0-9]', + m: options.strict ? '[1-5]?[0-9]' : '[0-9]|[0-5][0-9]', + HH: '[01][0-9]|2[0-3]', + H: options.strict ? '1?[0-9]|2[0-3]' : '[01]?[0-9]|2[0-3]', + hh: '[0][1-9]|[1][012]', + h: options.strict ? '[1-9]|1[012]' : '0?[1-9]|1[012]', + a: 'AM|PM', + EEEE: $locale.DATETIME_FORMATS.DAY.join('|'), + EEE: $locale.DATETIME_FORMATS.SHORTDAY.join('|'), + dd: '0[1-9]|[12][0-9]|3[01]', + d: options.strict ? '[1-9]|[1-2][0-9]|3[01]' : '0?[1-9]|[1-2][0-9]|3[01]', + MMMM: $locale.DATETIME_FORMATS.MONTH.join('|'), + MMM: $locale.DATETIME_FORMATS.SHORTMONTH.join('|'), + MM: '0[1-9]|1[012]', + M: options.strict ? '[1-9]|1[012]' : '0?[1-9]|1[012]', + yyyy: '[1]{1}[0-9]{3}|[2]{1}[0-9]{3}', + yy: '[0-9]{2}', + y: options.strict ? '-?(0|[1-9][0-9]{0,3})' : '-?0*[0-9]{1,4}' }; - 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); + var setFnMap = { + sss: proto.setMilliseconds, + ss: proto.setSeconds, + s: proto.setSeconds, + mm: proto.setMinutes, + m: proto.setMinutes, + HH: proto.setHours, + H: proto.setHours, + hh: proto.setHours, + h: proto.setHours, + EEEE: noop, + EEE: noop, + dd: proto.setDate, + d: proto.setDate, + a: function(value) { + var hours = this.getHours() % 12; + return this.setHours(value.match(/pm/i) ? hours + 12 : hours); + }, + MMMM: function(value) { + return this.setMonth(indexOfCaseInsensitive($locale.DATETIME_FORMATS.MONTH, value)); + }, + MMM: function(value) { + return this.setMonth(indexOfCaseInsensitive($locale.DATETIME_FORMATS.SHORTMONTH, value)); + }, + MM: function(value) { + return this.setMonth(1 * value - 1); + }, + M: function(value) { + return this.setMonth(1 * value - 1); + }, + yyyy: proto.setFullYear, + yy: function(value) { + return this.setFullYear(2e3 + 1 * value); + }, + y: function(value) { + return 1 * value <= 50 && value.length === 2 ? this.setFullYear(2e3 + 1 * value) : this.setFullYear(1 * value); } - _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); - return { - restrict: 'EAC', - require: 'ngModel', - link: function postLink(scope, element, attr, controller) { - var options = { - scope: scope + var regex, setMap; + $dateParser.init = function() { + $dateParser.$format = $locale.DATETIME_FORMATS[options.format] || options.format; + regex = regExpForFormat($dateParser.$format); + setMap = setMapForFormat($dateParser.$format); }; - 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); + $dateParser.isValid = function(date) { + if (angular.isDate(date)) return !isNaN(date.getTime()); + return regex.test(date); }; - 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; + $dateParser.parse = function(value, baseDate, format, timezone) { + if (format) format = $locale.DATETIME_FORMATS[format] || format; + if (angular.isDate(value)) value = dateFilter(value, format || $dateParser.$format, timezone); + var formatRegex = format ? regExpForFormat(format) : regex; + var formatSetMap = format ? setMapForFormat(format) : setMap; + var matches = formatRegex.exec(value); + if (!matches) return false; + var date = baseDate && !isNaN(baseDate.getTime()) ? new ParseDate().fromDate(baseDate) : new ParseDate().fromDate(new Date(1970, 0, 1, 0)); + for (var i = 0; i < matches.length - 1; i++) { + formatSetMap[i] && formatSetMap[i].call(date, matches[i + 1]); } - controller.$dateValue = parsedTime; - } - controller.$parsers.unshift(function(viewValue) { - var date; - if (!viewValue) { - controller.$setValidity('date', true); - return null; + var newDate = date.toDate(); + if (parseInt(date.day, 10) !== newDate.getDate()) { + return false; } - var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue); - if (!parsedTime || isNaN(parsedTime.getTime())) { - controller.$setValidity('date', false); - return undefined; + return newDate; + }; + $dateParser.getDateForAttribute = function(key, value) { + var date; + if (value === 'today') { + var today = new Date(); + date = new Date(today.getFullYear(), today.getMonth(), today.getDate() + (key === 'maxDate' ? 1 : 0), 0, 0, 0, key === 'minDate' ? 0 : -1); + } else if (angular.isString(value) && value.match(/^".+"$/)) { + date = new Date(value.substr(1, value.length - 2)); + } else if (isNumeric(value)) { + date = new Date(parseInt(value, 10)); + } else if (angular.isString(value) && 0 === value.length) { + date = key === 'minDate' ? -Infinity : +Infinity; } else { - validateAgainstMinMaxTime(parsedTime); - } - if (options.timeType === 'string') { - date = dateParser.timezoneOffsetAdjust(parsedTime, options.timezone, true); - return formatDate(date, options.modelTimeFormat || options.timeFormat); + date = new Date(value); } - 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(); + return date; + }; + $dateParser.getTimeForAttribute = function(key, value) { + var time; + if (value === 'now') { + time = new Date().setFullYear(1970, 0, 1); + } else if (angular.isString(value) && value.match(/^".+"$/)) { + time = new Date(value.substr(1, value.length - 2)).setFullYear(1970, 0, 1); + } else if (isNumeric(value)) { + time = new Date(parseInt(value, 10)).setFullYear(1970, 0, 1); + } else if (angular.isString(value) && 0 === value.length) { + time = key === 'minTime' ? -Infinity : +Infinity; } else { - return new Date(date); + time = $dateParser.parse(value, new Date(1970, 0, 1, 0)); } - }); - 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); + return time; + }; + $dateParser.daylightSavingAdjust = function(date) { + if (!date) { + return null; } - controller.$dateValue = dateParser.timezoneOffsetAdjust(date, options.timezone); - return getTimeFormattedString(); - }); - controller.$render = function() { - element.val(getTimeFormattedString()); + date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); + return date; }; - function getTimeFormattedString() { - return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat); - } - 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); + $dateParser.timezoneOffsetAdjust = function(date, timezone, undo) { + if (!date) { + return null; + } + if (timezone && timezone === 'UTC') { + date = new Date(date.getTime()); + date.setMinutes(date.getMinutes() + (undo ? -1 : 1) * date.getTimezoneOffset()); + } + return date; + }; + function setMapForFormat(format) { + var keys = Object.keys(setFnMap), i; + var map = [], sortedMap = []; + var clonedFormat = format; + for (i = 0; i < keys.length; i++) { + if (format.split(keys[i]).length > 1) { + var index = clonedFormat.search(keys[i]); + format = format.split(keys[i]).join(''); + if (setFnMap[keys[i]]) { + map[index] = setFnMap[keys[i]]; + } + } + } + angular.forEach(map, function(v) { + if (v) sortedMap.push(v); + }); + return sortedMap; } - 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 escapeReservedSymbols(text) { + return text.replace(/\//g, '[\\/]').replace('/-/g', '[-]').replace(/\./g, '[.]').replace(/\\s/g, '[\\s]'); } - self.$panes.splice(index, 1); - if (index < activeIndex) { - activeIndex--; - } else if (index === activeIndex && activeIndex === self.$panes.length) { - activeIndex--; + function regExpForFormat(format) { + var keys = Object.keys(regExpMap), i; + var re = format; + for (i = 0; i < keys.length; i++) { + re = re.split(keys[i]).join('${' + i + '}'); + } + for (i = 0; i < keys.length; i++) { + re = re.split('${' + i + '}').join('(' + regExpMap[keys[i]] + ')'); + } + format = escapeReservedSymbols(format); + return new RegExp('^' + re + '$', [ 'i' ]); } - if (activeIndex >= 0 && activeIndex < self.$panes.length) { - self.$setActive(self.$panes[activeIndex].name || activeIndex); + $dateParser.init(); + return $dateParser; + }; + return DateParserFactory; + } ]; + } ]); + angular.module('mgcrea.ngStrap.helpers.dateFormatter', []).service('$dateFormatter', [ '$locale', 'dateFilter', function($locale, dateFilter) { + this.getDefaultLocale = function() { + return $locale.id; + }; + this.getDatetimeFormat = function(format, lang) { + return $locale.DATETIME_FORMATS[format] || format; + }; + this.weekdaysShort = function(lang) { + return $locale.DATETIME_FORMATS.SHORTDAY; + }; + function splitTimeFormat(format) { + return /(h+)([:\.])?(m+)([:\.])?(s*)[ ]?(a?)/i.exec(format).slice(1); + } + this.hoursFormat = function(timeFormat) { + return splitTimeFormat(timeFormat)[0]; + }; + this.minutesFormat = function(timeFormat) { + return splitTimeFormat(timeFormat)[2]; + }; + this.secondsFormat = function(timeFormat) { + return splitTimeFormat(timeFormat)[4]; + }; + this.timeSeparator = function(timeFormat) { + return splitTimeFormat(timeFormat)[1]; + }; + this.showSeconds = function(timeFormat) { + return !!splitTimeFormat(timeFormat)[4]; + }; + this.showAM = function(timeFormat) { + return !!splitTimeFormat(timeFormat)[5]; + }; + this.formatDate = function(date, format, lang, timezone) { + return dateFilter(date, format, timezone); + }; + } ]); + angular.module('mgcrea.ngStrap.core', []).service('$bsCompiler', bsCompilerService); + function bsCompilerService($q, $http, $injector, $compile, $controller, $templateCache) { + this.compile = function(options) { + if (options.template && /\.html$/.test(options.template)) { + console.warn('Deprecated use of `template` option to pass a file. Please use the `templateUrl` option instead.'); + options.templateUrl = options.template; + options.template = ''; + } + var templateUrl = options.templateUrl; + var template = options.template || ''; + var controller = options.controller; + var controllerAs = options.controllerAs; + var resolve = angular.copy(options.resolve || {}); + var locals = angular.copy(options.locals || {}); + var transformTemplate = options.transformTemplate || angular.identity; + var bindToController = options.bindToController; + angular.forEach(resolve, function(value, key) { + if (angular.isString(value)) { + resolve[key] = $injector.get(value); } else { - self.$setActive(); + resolve[key] = $injector.invoke(value); } - }; - self.$setActive = $scope.$setActive = function(value) { - self.$panes.$active = value; - self.$activePaneChangeListeners.forEach(function(fn) { - fn(); + }); + angular.extend(resolve, locals); + if (templateUrl) { + resolve.$template = fetchTemplate(templateUrl); + } else { + resolve.$template = $q.when(template); + } + if (options.contentTemplate) { + resolve.$template = $q.all([ resolve.$template, fetchTemplate(options.contentTemplate) ]).then(function(templates) { + var templateEl = angular.element(templates[0]); + var contentEl = findElement('[ng-bind="content"]', templateEl[0]).removeAttr('ng-bind').html(templates[1]); + if (!options.templateUrl) contentEl.next().remove(); + return templateEl[0].outerHTML; }); - }; - self.$isActive = $scope.$isActive = function($pane, $index) { - return self.$panes.$active === $pane.name || self.$panes.$active === $index; - }; + } + return $q.all(resolve).then(function(locals) { + var template = transformTemplate(locals.$template); + if (options.html) { + template = template.replace(/ng-bind="/gi, 'ng-bind-html="'); + } + var element = angular.element('
').html(template.trim()).contents(); + var linkFn = $compile(element); + return { + locals: locals, + element: element, + link: function link(scope) { + locals.$scope = scope; + if (controller) { + var invokeCtrl = $controller(controller, locals, true); + if (bindToController) { + angular.extend(invokeCtrl.instance, locals); + } + var ctrl = angular.isObject(invokeCtrl) ? invokeCtrl : invokeCtrl(); + element.data('$ngControllerController', ctrl); + element.children().data('$ngControllerController', ctrl); + if (controllerAs) { + scope[controllerAs] = ctrl; + } + } + return linkFn.apply(null, arguments); + } + }; + }); }; - this.$get = function() { - var $tab = {}; - $tab.defaults = defaults; - $tab.controller = controller; - return $tab; + 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; + }); + } + } + bsCompilerService.$inject = [ '$q', '$http', '$injector', '$compile', '$controller', '$templateCache' ]; + angular.module('mgcrea.ngStrap.dropdown', [ 'mgcrea.ngStrap.tooltip' ]).provider('$dropdown', function() { + var defaults = this.defaults = { + animation: 'am-fade', + prefixClass: 'dropdown', + prefixEvent: 'dropdown', + placement: 'bottom-left', + templateUrl: 'dropdown/dropdown.tpl.html', + trigger: 'click', + container: false, + keyboard: true, + html: false, + delay: 0 }; - }).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); + this.$get = [ '$window', '$rootScope', '$tooltip', '$timeout', function($window, $rootScope, $tooltip, $timeout) { + var bodyEl = angular.element($window.document.body); + var matchesSelector = Element.prototype.matchesSelector || Element.prototype.webkitMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector; + function DropdownFactory(element, config) { + var $dropdown = {}; + var options = angular.extend({}, defaults, config); + var scope = $dropdown.$scope = options.scope && options.scope.$new() || $rootScope.$new(); + $dropdown = $tooltip(element, options); + var parentEl = element.parent(); + $dropdown.$onKeyDown = function(evt) { + if (!/(38|40)/.test(evt.keyCode)) return; + evt.preventDefault(); + evt.stopPropagation(); + var items = angular.element($dropdown.$element[0].querySelectorAll('li:not(.divider) a')); + if (!items.length) return; + var index; + angular.forEach(items, function(el, i) { + if (matchesSelector && matchesSelector.call(el, ':focus')) index = i; }); - scope.$watch(attrs.bsActivePane, function(newValue, oldValue) { - bsTabsCtrl.$setActive(newValue); - }, true); + if (evt.keyCode === 38 && index > 0) index--; else if (evt.keyCode === 40 && index < items.length - 1) index++; else if (angular.isUndefined(index)) index = 0; + items.eq(index)[0].focus(); + }; + var show = $dropdown.show; + $dropdown.show = function() { + show(); + $timeout(function() { + options.keyboard && $dropdown.$element && $dropdown.$element.on('keydown', $dropdown.$onKeyDown); + bodyEl.on('click', onBodyClick); + }, 0, false); + parentEl.hasClass('dropdown') && parentEl.addClass('open'); + }; + var hide = $dropdown.hide; + $dropdown.hide = function() { + if (!$dropdown.$isShown) return; + options.keyboard && $dropdown.$element && $dropdown.$element.off('keydown', $dropdown.$onKeyDown); + bodyEl.off('click', onBodyClick); + parentEl.hasClass('dropdown') && parentEl.removeClass('open'); + hide(); + }; + var destroy = $dropdown.destroy; + $dropdown.destroy = function() { + bodyEl.off('click', onBodyClick); + destroy(); + }; + function onBodyClick(evt) { + if (evt.target === element[0]) return; + return evt.target !== element[0] && $dropdown.hide(); } + return $dropdown; } - }; - } ]).directive('bsPane', [ '$window', '$animate', '$sce', function($window, $animate, $sce) { + return DropdownFactory; + } ]; + }).directive('bsDropdown', [ '$window', '$sce', '$dropdown', function($window, $sce, $dropdown) { return { - require: [ '^?ngModel', '^bsTabs' ], + restrict: 'EAC', 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); + link: function postLink(scope, element, attr, transclusion) { + var options = { + scope: scope + }; + angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'id' ], function(key) { + if (angular.isDefined(attr[key])) options[key] = attr[key]; }); - scope.name = attrs.name; - if (bsTabsCtrl.$options.animation) { - element.addClass(bsTabsCtrl.$options.animation); - } - attrs.$observe('disabled', function(newValue, oldValue) { - scope.disabled = scope.$eval(newValue); + var falseValueRegExp = /^(false|0|)$/i; + angular.forEach([ 'html', 'container' ], function(key) { + if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false; }); - bsTabsCtrl.$push(scope); - scope.$on('$destroy', function() { - bsTabsCtrl.$remove(scope); + attr.bsDropdown && scope.$watch(attr.bsDropdown, function(newValue, oldValue) { + scope.content = newValue; + }, true); + attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) { + if (!dropdown || !angular.isDefined(newValue)) return; + if (angular.isString(newValue)) newValue = !!newValue.match(/true|,?(dropdown),?/i); + newValue === true ? dropdown.show() : dropdown.hide(); }); - function render() { - var index = bsTabsCtrl.$panes.indexOf(scope); - $animate[bsTabsCtrl.$isActive(scope, index) ? 'addClass' : 'removeClass'](element, bsTabsCtrl.$options.activeClass); - } - bsTabsCtrl.$activePaneChangeListeners.push(function() { - render(); + var dropdown = $dropdown(element, options); + scope.$on('$destroy', function() { + if (dropdown) dropdown.destroy(); + options = null; + dropdown = null; }); - render(); } }; } ]); - angular.module('mgcrea.ngStrap.typeahead', [ 'mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions' ]).provider('$typeahead', function() { + angular.module('mgcrea.ngStrap.datepicker', [ 'mgcrea.ngStrap.helpers.dateParser', 'mgcrea.ngStrap.helpers.dateFormatter', 'mgcrea.ngStrap.tooltip' ]).provider('$datepicker', function() { var defaults = this.defaults = { animation: 'am-fade', - prefixClass: 'typeahead', - prefixEvent: '$typeahead', + prefixClass: 'datepicker', placement: 'bottom-left', - templateUrl: 'typeahead/typeahead.tpl.html', + templateUrl: 'datepicker/datepicker.tpl.html', trigger: 'focus', container: false, keyboard: true, html: false, delay: 0, - minLength: 1, - filter: 'bsAsyncFilter', - limit: 6, - autoSelect: false, - comparator: '', - trimValue: true + useNative: false, + dateType: 'date', + dateFormat: 'shortDate', + timezone: null, + modelDateFormat: null, + dayFormat: 'dd', + monthFormat: 'MMM', + yearFormat: 'yyyy', + monthTitleFormat: 'MMMM yyyy', + yearTitleFormat: 'yyyy', + strictFormat: false, + autoclose: false, + minDate: -Infinity, + maxDate: +Infinity, + startView: 0, + minView: 0, + startWeek: 0, + daysOfWeekDisabled: '', + iconLeft: 'glyphicon glyphicon-chevron-left', + iconRight: 'glyphicon glyphicon-chevron-right' }; - this.$get = [ '$window', '$rootScope', '$tooltip', '$$rAF', '$timeout', function($window, $rootScope, $tooltip, $$rAF, $timeout) { + this.$get = [ '$window', '$document', '$rootScope', '$sce', '$dateFormatter', 'datepickerViews', '$tooltip', '$timeout', function($window, $document, $rootScope, $sce, $dateFormatter, datepickerViews, $tooltip, $timeout) { var bodyEl = angular.element($window.document.body); - function TypeaheadFactory(element, controller, config) { - var $typeahead = {}; - var options = angular.extend({}, defaults, config); - $typeahead = $tooltip(element, options); + 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 DatepickerFactory(element, controller, config) { + var $datepicker = $tooltip(element, angular.extend({}, defaults, config)); var parentScope = config.scope; - var scope = $typeahead.$scope; - scope.$resetMatches = function() { - scope.$matches = []; - scope.$activeIndex = options.autoSelect ? 0 : -1; + var options = $datepicker.$options; + var scope = $datepicker.$scope; + if (options.startView) options.startView -= options.minView; + var pickerViews = datepickerViews($datepicker); + $datepicker.$views = pickerViews.views; + var viewDate = pickerViews.viewDate; + scope.$mode = options.startView; + scope.$iconLeft = options.iconLeft; + scope.$iconRight = options.iconRight; + var $picker = $datepicker.$views[scope.$mode]; + scope.$select = function(date) { + $datepicker.select(date); }; - scope.$resetMatches(); - scope.$activate = function(index) { - scope.$$postDigest(function() { - $typeahead.activate(index); - }); + scope.$selectPane = function(value) { + $datepicker.$selectPane(value); }; - scope.$select = function(index, evt) { - scope.$$postDigest(function() { - $typeahead.select(index); - }); + scope.$toggleMode = function() { + $datepicker.setMode((scope.$mode + 1) % $datepicker.$views.length); }; - scope.$isVisible = function() { - return $typeahead.$isVisible(); + $datepicker.update = function(date) { + if (angular.isDate(date) && !isNaN(date.getTime())) { + $datepicker.$date = date; + $picker.update.call($picker, date); + } + $datepicker.$build(true); }; - $typeahead.update = function(matches) { - scope.$matches = matches; - if (scope.$activeIndex >= matches.length) { - scope.$activeIndex = options.autoSelect ? 0 : -1; + $datepicker.updateDisabledDates = function(dateRanges) { + options.disabledDateRanges = dateRanges; + for (var i = 0, l = scope.rows.length; i < l; i++) { + angular.forEach(scope.rows[i], $datepicker.$setDisabledEl); } - safeDigest(scope); - $$rAF($typeahead.$applyPlacement); }; - $typeahead.activate = function(index) { - scope.$activeIndex = index; + $datepicker.select = function(date, keep) { + if (!angular.isDate(controller.$dateValue)) controller.$dateValue = new Date(date); + if (!scope.$mode || keep) { + controller.$setViewValue(angular.copy(date)); + controller.$render(); + if (options.autoclose && !keep) { + $timeout(function() { + $datepicker.hide(true); + }); + } + } else { + angular.extend(viewDate, { + year: date.getFullYear(), + month: date.getMonth(), + date: date.getDate() + }); + $datepicker.setMode(scope.$mode - 1); + $datepicker.$build(); + } }; - $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); + $datepicker.setMode = function(mode) { + scope.$mode = mode; + $picker = $datepicker.$views[scope.$mode]; + $datepicker.$build(); }; - $typeahead.$isVisible = function() { - if (!options.minLength || !controller) { - return !!scope.$matches.length; + $datepicker.$build = function(pristine) { + if (pristine === true && $picker.built) return; + if (pristine === false && !$picker.built) return; + $picker.build.call($picker); + }; + $datepicker.$updateSelected = function() { + for (var i = 0, l = scope.rows.length; i < l; i++) { + angular.forEach(scope.rows[i], updateSelected); } - 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; + $datepicker.$isSelected = function(date) { + return $picker.isSelected(date); + }; + $datepicker.$setDisabledEl = function(el) { + el.disabled = $picker.isDisabled(el.date); + }; + $datepicker.$selectPane = function(value) { + var steps = $picker.steps; + var targetDate = new Date(Date.UTC(viewDate.year + (steps.year || 0) * value, viewDate.month + (steps.month || 0) * value, 1)); + angular.extend(viewDate, { + year: targetDate.getUTCFullYear(), + month: targetDate.getUTCMonth(), + date: targetDate.getUTCDate() + }); + $datepicker.$build(); + }; + $datepicker.$onMouseDown = function(evt) { + evt.preventDefault(); + evt.stopPropagation(); + if (isTouch) { + var targetEl = angular.element(evt.target); + if (targetEl[0].nodeName.toLowerCase() !== 'button') { + targetEl = targetEl.parent(); + } + targetEl.triggerHandler('click'); + } + }; + $datepicker.$onKeyDown = function(evt) { + if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return; + evt.preventDefault(); + evt.stopPropagation(); + if (evt.keyCode === 13) { + if (!scope.$mode) { + return $datepicker.hide(true); + } else { + return scope.$apply(function() { + $datepicker.setMode(scope.$mode - 1); + }); + } + } + $picker.onKeyDown(evt); + parentScope.$digest(); + }; + function updateSelected(el) { + el.selected = $datepicker.$isSelected(el.date); + } + function focusElement() { + element[0].focus(); + } + var _init = $datepicker.init; + $datepicker.init = function() { + if (isNative && options.useNative) { + element.prop('type', 'date'); + element.css('-webkit-appearance', 'textfield'); + return; + } else if (isTouch) { + element.prop('type', 'text'); + element.attr('readonly', 'true'); + element.on('click', focusElement); } - if (i < 0) return; - return i; - }; - $typeahead.$onMouseDown = function(evt) { - evt.preventDefault(); - evt.stopPropagation(); + _init(); }; - $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(); + var _destroy = $datepicker.destroy; + $datepicker.destroy = function() { + if (isNative && options.useNative) { + element.off('click', focusElement); } - 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(); + _destroy(); }; - var show = $typeahead.show; - $typeahead.show = function() { - show(); + var _show = $datepicker.show; + $datepicker.show = function() { + if (!isTouch && element.attr('readonly') || element.attr('disabled')) return; + _show(); $timeout(function() { - $typeahead.$element && $typeahead.$element.on('mousedown', $typeahead.$onMouseDown); + if (!$datepicker.$isShown) return; + $datepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown); if (options.keyboard) { - element && element.on('keydown', $typeahead.$onKeyDown); + element.on('keydown', $datepicker.$onKeyDown); } }, 0, false); }; - var hide = $typeahead.hide; - $typeahead.hide = function() { - $typeahead.$element && $typeahead.$element.off('mousedown', $typeahead.$onMouseDown); + var _hide = $datepicker.hide; + $datepicker.hide = function(blur) { + if (!$datepicker.$isShown) return; + $datepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown); if (options.keyboard) { - element && element.off('keydown', $typeahead.$onKeyDown); + element.off('keydown', $datepicker.$onKeyDown); } - if (!options.autoSelect) $typeahead.activate(-1); - hide(); + _hide(blur); }; - return $typeahead; - } - function safeDigest(scope) { - scope.$$phase || scope.$root && scope.$root.$$phase || scope.$digest(); + return $datepicker; } - TypeaheadFactory.defaults = defaults; - return TypeaheadFactory; + DatepickerFactory.defaults = defaults; + return DatepickerFactory; } ]; - }).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; + }).directive('bsDatepicker', [ '$window', '$parse', '$q', '$dateFormatter', '$dateParser', '$datepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $datepicker) { + var defaults = $datepicker.defaults; + var isNative = /(ip(a|o)d|iphone|android)/gi.test($window.navigator.userAgent); return { restrict: 'EAC', require: 'ngModel', @@ -3388,645 +3095,959 @@ 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', '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) { if (angular.isDefined(attr[key])) options[key] = attr[key]; }); var falseValueRegExp = /^(false|0|)$/i; - angular.forEach([ 'html', 'container', 'trimValue' ], 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(); - }); - }); - } - 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(); - }); - }); - controller.$formatters.push(function(modelValue) { - var displayValue = parsedOptions.displayValue(modelValue); - if (displayValue) { - return displayValue; - } - if (modelValue && typeof modelValue !== 'object') { - return modelValue; - } - return ''; - }); - 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 (typeahead) typeahead.destroy(); - options = null; - typeahead = null; - }); - } - }; - } ]); - 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(); - }); - }; - $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 - }; - } - if (options.container === 'self') { - tipContainer = element; - } else if (angular.isElement(options.container)) { - tipContainer = options.container; - } else if (options.container) { - tipContainer = findElement(options.container); - } - bindTriggerEvents(); - if (options.target) { - options.target = angular.isElement(options.target) ? options.target : findElement(options.target); - } - if (options.show) { - scope.$$postDigest(function() { - options.trigger === 'focus' ? element[0].focus() : $tooltip.show(); - }); - } - }; - $tooltip.destroy = function() { - unbindTriggerEvents(); - destroyTipElement(); - scope.$destroy(); - }; - $tooltip.enter = function() { - clearTimeout(timeout); - hoverState = 'in'; - if (!options.delay || !options.delay.show) { - return $tooltip.show(); - } - timeout = setTimeout(function() { - if (hoverState === 'in') $tooltip.show(); - }, options.delay.show); + angular.forEach([ 'html', 'container', 'autoclose', 'useNative' ], function(key) { + if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false; + }); + attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) { + if (!datepicker || !angular.isDefined(newValue)) return; + if (angular.isString(newValue)) newValue = !!newValue.match(/true|,?(datepicker),?/i); + newValue === true ? datepicker.show() : datepicker.hide(); + }); + var datepicker = $datepicker(element, controller, options); + options = datepicker.$options; + if (isNative && options.useNative) options.dateFormat = 'yyyy-MM-dd'; + var lang = options.lang; + var formatDate = function(date, format) { + return $dateFormatter.formatDate(date, format, lang); }; - $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; + var dateParser = $dateParser({ + format: options.dateFormat, + lang: lang, + strict: options.strictFormat + }); + angular.forEach([ 'minDate', 'maxDate' ], function(key) { + angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) { + datepicker.$options[key] = dateParser.getDateForAttribute(key, newValue); + !isNaN(datepicker.$options[key]) && datepicker.$build(false); + validateAgainstMinMaxDate(controller.$dateValue); + }); + }); + scope.$watch(attr.ngModel, function(newValue, oldValue) { + datepicker.update(controller.$dateValue); + }, true); + function normalizeDateRanges(ranges) { + if (!ranges || !ranges.length) return null; + return ranges; + } + if (angular.isDefined(attr.disabledDates)) { + scope.$watch(attr.disabledDates, function(disabledRanges, previousValue) { + disabledRanges = normalizeDateRanges(disabledRanges); + previousValue = normalizeDateRanges(previousValue); + if (disabledRanges) { + datepicker.updateDisabledDates(disabledRanges); } - } 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); + } + function validateAgainstMinMaxDate(parsedDate) { + if (!angular.isDate(parsedDate)) return; + var isMinValid = isNaN(datepicker.$options.minDate) || parsedDate.getTime() >= datepicker.$options.minDate; + var isMaxValid = isNaN(datepicker.$options.maxDate) || parsedDate.getTime() <= datepicker.$options.maxDate; + var isValid = isMinValid && isMaxValid; + controller.$setValidity('date', isValid); + controller.$setValidity('min', isMinValid); + controller.$setValidity('max', isMaxValid); + if (isValid) controller.$dateValue = parsedDate; + } + controller.$parsers.unshift(function(viewValue) { + var date; + if (!viewValue) { + controller.$setValidity('date', true); + return null; + } + var parsedDate = dateParser.parse(viewValue, controller.$dateValue); + if (!parsedDate || isNaN(parsedDate.getTime())) { + controller.$setValidity('date', false); + return; } else { - $animate.enter(tipElement, parent, after).then(enterAnimateCallback); + validateAgainstMinMaxDate(parsedDate); } - safeDigest(scope); - $$rAF(function() { - if (tipElement) tipElement.css({ - visibility: 'visible' - }); - }); - if (options.keyboard) { - if (options.trigger !== 'focus') { - $tooltip.focus(); - } - bindKeyboardEvents(); + if (options.dateType === 'string') { + date = dateParser.timezoneOffsetAdjust(parsedDate, options.timezone, true); + return formatDate(date, options.modelDateFormat || options.dateFormat); } - if (options.autoClose) { - bindAutoCloseEvents(); + date = dateParser.timezoneOffsetAdjust(controller.$dateValue, options.timezone, true); + if (options.dateType === 'number') { + return date.getTime(); + } else if (options.dateType === 'unix') { + return date.getTime() / 1e3; + } else if (options.dateType === '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.dateType === 'string') { + date = dateParser.parse(modelValue, null, options.modelDateFormat); + } else if (options.dateType === 'unix') { + date = new Date(modelValue * 1e3); + } else { + date = new Date(modelValue); } + controller.$dateValue = dateParser.timezoneOffsetAdjust(date, options.timezone); + return getDateFormattedString(); + }); + controller.$render = function() { + element.val(getDateFormattedString()); }; - function enterAnimateCallback() { - scope.$emit(options.prefixEvent + '.show', $tooltip); + function getDateFormattedString() { + return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.dateFormat); } - $tooltip.leave = function() { - clearTimeout(timeout); - hoverState = 'out'; - if (!options.delay || !options.delay.hide) { - return $tooltip.hide(); - } - timeout = setTimeout(function() { - if (hoverState === 'out') { - $tooltip.hide(); + scope.$on('$destroy', function() { + if (datepicker) datepicker.destroy(); + options = null; + datepicker = null; + }); + } + }; + } ]).provider('datepickerViews', function() { + var defaults = this.defaults = { + dayFormat: 'dd', + daySplit: 7 + }; + function split(arr, size) { + var arrays = []; + while (arr.length > 0) { + arrays.push(arr.splice(0, size)); + } + return arrays; + } + function mod(n, m) { + return (n % m + m) % m; + } + this.$get = [ '$dateFormatter', '$dateParser', '$sce', function($dateFormatter, $dateParser, $sce) { + return function(picker) { + var scope = picker.$scope; + var options = picker.$options; + var lang = options.lang; + var formatDate = function(date, format) { + return $dateFormatter.formatDate(date, format, lang); + }; + var dateParser = $dateParser({ + format: options.dateFormat, + lang: lang, + strict: options.strictFormat + }); + var weekDaysMin = $dateFormatter.weekdaysShort(lang); + var weekDaysLabels = weekDaysMin.slice(options.startWeek).concat(weekDaysMin.slice(0, options.startWeek)); + var weekDaysLabelsHtml = $sce.trustAsHtml('' + weekDaysLabels.join('') + ''); + var startDate = picker.$date || (options.startDate ? dateParser.getDateForAttribute('startDate', options.startDate) : new Date()); + var viewDate = { + year: startDate.getFullYear(), + month: startDate.getMonth(), + date: startDate.getDate() + }; + var views = [ { + format: options.dayFormat, + split: 7, + steps: { + month: 1 + }, + update: function(date, force) { + if (!this.built || force || date.getFullYear() !== viewDate.year || date.getMonth() !== viewDate.month) { + angular.extend(viewDate, { + year: picker.$date.getFullYear(), + month: picker.$date.getMonth(), + date: picker.$date.getDate() + }); + picker.$build(); + } else if (date.getDate() !== viewDate.date || date.getDate() === 1) { + viewDate.date = picker.$date.getDate(); + picker.$updateSelected(); + } + }, + build: function() { + var firstDayOfMonth = new Date(viewDate.year, viewDate.month, 1), firstDayOfMonthOffset = firstDayOfMonth.getTimezoneOffset(); + var firstDate = new Date(+firstDayOfMonth - mod(firstDayOfMonth.getDay() - options.startWeek, 7) * 864e5), firstDateOffset = firstDate.getTimezoneOffset(); + var today = dateParser.timezoneOffsetAdjust(new Date(), options.timezone).toDateString(); + if (firstDateOffset !== firstDayOfMonthOffset) firstDate = new Date(+firstDate + (firstDateOffset - firstDayOfMonthOffset) * 6e4); + var days = [], day; + for (var i = 0; i < 42; i++) { + day = dateParser.daylightSavingAdjust(new Date(firstDate.getFullYear(), firstDate.getMonth(), firstDate.getDate() + i)); + days.push({ + date: day, + isToday: day.toDateString() === today, + label: formatDate(day, this.format), + selected: picker.$date && this.isSelected(day), + muted: day.getMonth() !== viewDate.month, + disabled: this.isDisabled(day) + }); + } + scope.title = formatDate(firstDayOfMonth, options.monthTitleFormat); + scope.showLabels = true; + scope.labels = weekDaysLabelsHtml; + scope.rows = split(days, this.split); + this.built = true; + }, + isSelected: function(date) { + return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth() && date.getDate() === picker.$date.getDate(); + }, + isDisabled: function(date) { + var time = date.getTime(); + if (time < options.minDate || time > options.maxDate) return true; + if (options.daysOfWeekDisabled.indexOf(date.getDay()) !== -1) return true; + if (options.disabledDateRanges) { + for (var i = 0; i < options.disabledDateRanges.length; i++) { + if (time >= options.disabledDateRanges[i].start && time <= options.disabledDateRanges[i].end) { + return true; + } + } + } + return false; + }, + onKeyDown: function(evt) { + if (!picker.$date) { + return; } - }, options.delay.hide); - }; - 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 actualTime = picker.$date.getTime(); + var newDate; + if (evt.keyCode === 37) newDate = new Date(actualTime - 1 * 864e5); else if (evt.keyCode === 38) newDate = new Date(actualTime - 7 * 864e5); else if (evt.keyCode === 39) newDate = new Date(actualTime + 1 * 864e5); else if (evt.keyCode === 40) newDate = new Date(actualTime + 7 * 864e5); + if (!this.isDisabled(newDate)) picker.select(newDate, true); } - }; - function leaveAnimateCallback() { - scope.$emit(options.prefixEvent + '.hide', $tooltip); - if (tipElement === _tipToHide) { - if (_blur && options.trigger === 'focus') { - return element[0].blur(); + }, { + name: 'month', + format: options.monthFormat, + split: 4, + steps: { + year: 1 + }, + update: function(date, force) { + if (!this.built || date.getFullYear() !== viewDate.year) { + angular.extend(viewDate, { + year: picker.$date.getFullYear(), + month: picker.$date.getMonth(), + date: picker.$date.getDate() + }); + picker.$build(); + } else if (date.getMonth() !== viewDate.month) { + angular.extend(viewDate, { + month: picker.$date.getMonth(), + date: picker.$date.getDate() + }); + picker.$updateSelected(); } - destroyTipElement(); - } - } - $tooltip.toggle = function() { - $tooltip.$isShown ? $tooltip.leave() : $tooltip.enter(); - }; - $tooltip.focus = function() { - tipElement[0].focus(); - }; - $tooltip.setEnabled = function(isEnabled) { - options.bsEnabled = isEnabled; - }; - $tooltip.setViewport = function(viewport) { - options.viewport = viewport; - }; - $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'); + }, + build: function() { + var firstMonth = new Date(viewDate.year, 0, 1); + var months = [], month; + for (var i = 0; i < 12; i++) { + month = new Date(viewDate.year, i, 1); + months.push({ + date: month, + label: formatDate(month, this.format), + selected: picker.$isSelected(month), + disabled: this.isDisabled(month) + }); } - 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'); + scope.title = formatDate(month, options.yearTitleFormat); + scope.showLabels = false; + scope.rows = split(months, this.split); + this.built = true; + }, + isSelected: function(date) { + return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth(); + }, + isDisabled: function(date) { + var lastDate = +new Date(date.getFullYear(), date.getMonth() + 1, 0); + return lastDate < options.minDate || date.getTime() > options.maxDate; + }, + onKeyDown: function(evt) { + if (!picker.$date) { + return; } - tipElement.removeClass(originalPlacement).addClass(placement); - } - var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight); - applyPlacement(tipPosition, placement); - }; - $tooltip.$onKeyUp = function(evt) { - if (evt.which === 27 && $tooltip.$isShown) { - $tooltip.hide(); - evt.stopPropagation(); - } - }; - $tooltip.$onFocusKeyUp = function(evt) { - if (evt.which === 27) { - element[0].blur(); - evt.stopPropagation(); + var actualMonth = picker.$date.getMonth(); + var newDate = new Date(picker.$date); + if (evt.keyCode === 37) newDate.setMonth(actualMonth - 1); else if (evt.keyCode === 38) newDate.setMonth(actualMonth - 4); else if (evt.keyCode === 39) newDate.setMonth(actualMonth + 1); else if (evt.keyCode === 40) newDate.setMonth(actualMonth + 4); + if (!this.isDisabled(newDate)) picker.select(newDate, true); } - }; - $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); + }, { + name: 'year', + format: options.yearFormat, + split: 4, + steps: { + year: 12 + }, + update: function(date, force) { + if (!this.built || force || parseInt(date.getFullYear() / 20, 10) !== parseInt(viewDate.year / 20, 10)) { + angular.extend(viewDate, { + year: picker.$date.getFullYear(), + month: picker.$date.getMonth(), + date: picker.$date.getDate() + }); + picker.$build(); + } else if (date.getFullYear() !== viewDate.year) { + angular.extend(viewDate, { + year: picker.$date.getFullYear(), + month: picker.$date.getMonth(), + date: picker.$date.getDate() + }); + picker.$updateSelected(); } - }); - } - 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); + }, + build: function() { + var firstYear = viewDate.year - viewDate.year % (this.split * 3); + var years = [], year; + for (var i = 0; i < 12; i++) { + year = new Date(firstYear + i, 0, 1); + years.push({ + date: year, + label: formatDate(year, this.format), + selected: picker.$isSelected(year), + disabled: this.isDisabled(year) + }); + } + scope.title = years[0].label + '-' + years[years.length - 1].label; + scope.showLabels = false; + scope.rows = split(years, this.split); + this.built = true; + }, + isSelected: function(date) { + return picker.$date && date.getFullYear() === picker.$date.getFullYear(); + }, + isDisabled: function(date) { + var lastDate = +new Date(date.getFullYear() + 1, 0, 0); + return lastDate < options.minDate || date.getTime() > options.maxDate; + }, + onKeyDown: function(evt) { + if (!picker.$date) { + return; } + var actualYear = picker.$date.getFullYear(), newDate = new Date(picker.$date); + if (evt.keyCode === 37) newDate.setYear(actualYear - 1); else if (evt.keyCode === 38) newDate.setYear(actualYear - 4); else if (evt.keyCode === 39) newDate.setYear(actualYear + 1); else if (evt.keyCode === 40) newDate.setYear(actualYear + 4); + if (!this.isDisabled(newDate)) picker.select(newDate, true); } + } ]; + return { + views: options.minView ? Array.prototype.slice.call(views, options.minView) : views, + viewDate: viewDate + }; + }; + } ]; + }); + angular.module('mgcrea.ngStrap.collapse', []).provider('$collapse', function() { + var defaults = this.defaults = { + animation: 'am-collapse', + disallowToggle: false, + activeClass: 'in', + startCollapsed: false, + allowMultiple: false + }; + var controller = this.controller = function($scope, $element, $attrs) { + var self = this; + self.$options = angular.copy(defaults); + angular.forEach([ 'animation', 'disallowToggle', 'activeClass', 'startCollapsed', 'allowMultiple' ], function(key) { + if (angular.isDefined($attrs[key])) self.$options[key] = $attrs[key]; + }); + var falseValueRegExp = /^(false|0|)$/i; + angular.forEach([ 'disallowToggle', 'startCollapsed', 'allowMultiple' ], function(key) { + if (angular.isDefined($attrs[key]) && falseValueRegExp.test($attrs[key])) { + self.$options[key] = false; + } + }); + self.$toggles = []; + self.$targets = []; + self.$viewChangeListeners = []; + self.$registerToggle = function(element) { + self.$toggles.push(element); + }; + self.$registerTarget = function(element) { + self.$targets.push(element); + }; + self.$unregisterToggle = function(element) { + var index = self.$toggles.indexOf(element); + self.$toggles.splice(index, 1); + }; + self.$unregisterTarget = function(element) { + var index = self.$targets.indexOf(element); + self.$targets.splice(index, 1); + if (self.$options.allowMultiple) { + deactivateItem(element); } - function bindKeyboardEvents() { - if (options.trigger !== 'focus') { - tipElement.on('keyup', $tooltip.$onKeyUp); - } else { - element.on('keyup', $tooltip.$onFocusKeyUp); - } + fixActiveItemIndexes(index); + self.$viewChangeListeners.forEach(function(fn) { + fn(); + }); + }; + self.$targets.$active = !self.$options.startCollapsed ? [ 0 ] : []; + self.$setActive = $scope.$setActive = function(value) { + if (angular.isArray(value)) { + self.$targets.$active = value; + } else if (!self.$options.disallowToggle) { + isActive(value) ? deactivateItem(value) : activateItem(value); + } else { + activateItem(value); } - function unbindKeyboardEvents() { - if (options.trigger !== 'focus') { - tipElement.off('keyup', $tooltip.$onKeyUp); - } else { - element.off('keyup', $tooltip.$onFocusKeyUp); + self.$viewChangeListeners.forEach(function(fn) { + fn(); + }); + }; + self.$activeIndexes = function() { + return self.$options.allowMultiple ? self.$targets.$active : self.$targets.$active.length === 1 ? self.$targets.$active[0] : -1; + }; + function fixActiveItemIndexes(index) { + var activeIndexes = self.$targets.$active; + for (var i = 0; i < activeIndexes.length; i++) { + if (index < activeIndexes[i]) { + activeIndexes[i] = activeIndexes[i] - 1; } - } - 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; + if (activeIndexes[i] === self.$targets.length) { + activeIndexes[i] = self.$targets.length - 1; } } - function stopEventPropagation(event) { - event.stopPropagation(); + } + function isActive(value) { + var activeItems = self.$targets.$active; + return activeItems.indexOf(value) === -1 ? false : true; + } + function deactivateItem(value) { + var index = self.$targets.$active.indexOf(value); + if (index !== -1) { + self.$targets.$active.splice(index, 1); } - 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); + } + function activateItem(value) { + if (!self.$options.allowMultiple) { + self.$targets.$active.splice(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; - } - } - return offset; + if (self.$targets.$active.indexOf(value) === -1) { + self.$targets.$active.push(value); } - 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: '' - }); + } + }; + this.$get = function() { + var $collapse = {}; + $collapse.defaults = defaults; + $collapse.controller = controller; + return $collapse; + }; + }).directive('bsCollapse', [ '$window', '$animate', '$collapse', function($window, $animate, $collapse) { + var defaults = $collapse.defaults; + return { + require: [ '?ngModel', 'bsCollapse' ], + controller: [ '$scope', '$element', '$attrs', $collapse.controller ], + link: function postLink(scope, element, attrs, controllers) { + var ngModelCtrl = controllers[0]; + var bsCollapseCtrl = controllers[1]; + if (ngModelCtrl) { + bsCollapseCtrl.$viewChangeListeners.push(function() { + ngModelCtrl.$setViewValue(bsCollapseCtrl.$activeIndexes()); + }); + ngModelCtrl.$formatters.push(function(modelValue) { + if (angular.isArray(modelValue)) { + bsCollapseCtrl.$setActive(modelValue); + } else { + var activeIndexes = bsCollapseCtrl.$activeIndexes(); + if (angular.isArray(activeIndexes)) { + if (activeIndexes.indexOf(modelValue * 1) === -1) { + bsCollapseCtrl.$setActive(modelValue * 1); + } + } else if (activeIndexes !== modelValue * 1) { + bsCollapseCtrl.$setActive(modelValue * 1); + } } - }, 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; - } - 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); + return modelValue; + }); + } + } + }; + } ]).directive('bsCollapseToggle', function() { + return { + require: [ '^?ngModel', '^bsCollapse' ], + link: function postLink(scope, element, attrs, controllers) { + var ngModelCtrl = controllers[0]; + var bsCollapseCtrl = controllers[1]; + element.attr('data-toggle', 'collapse'); + bsCollapseCtrl.$registerToggle(element); + scope.$on('$destroy', function() { + bsCollapseCtrl.$unregisterToggle(element); + }); + element.on('click', function() { + var index = attrs.bsCollapseToggle && attrs.bsCollapseToggle !== 'bs-collapse-toggle' ? attrs.bsCollapseToggle : bsCollapseCtrl.$toggles.indexOf(element); + bsCollapseCtrl.$setActive(index * 1); + scope.$apply(); + }); + } + }; + }).directive('bsCollapseTarget', [ '$animate', function($animate) { + return { + require: [ '^?ngModel', '^bsCollapse' ], + link: function postLink(scope, element, attrs, controllers) { + var ngModelCtrl = controllers[0]; + var bsCollapseCtrl = controllers[1]; + element.addClass('collapse'); + if (bsCollapseCtrl.$options.animation) { + element.addClass(bsCollapseCtrl.$options.animation); + } + bsCollapseCtrl.$registerTarget(element); + scope.$on('$destroy', function() { + bsCollapseCtrl.$unregisterTarget(element); + }); + function render() { + var index = bsCollapseCtrl.$targets.indexOf(element); + var active = bsCollapseCtrl.$activeIndexes(); + var action = 'removeClass'; + if (angular.isArray(active)) { + if (active.indexOf(index) !== -1) { + action = 'addClass'; + } + } else if (index === active) { + action = 'addClass'; } + $animate[action](element, bsCollapseCtrl.$options.activeClass); } - 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; - } + bsCollapseCtrl.$viewChangeListeners.push(function() { + render(); + }); + render(); + } + }; + } ]); + angular.module('mgcrea.ngStrap.aside', [ 'mgcrea.ngStrap.modal' ]).provider('$aside', function() { + var defaults = this.defaults = { + animation: 'am-fade-and-slide-right', + prefixClass: 'aside', + prefixEvent: 'aside', + placement: 'right', + templateUrl: 'aside/aside.tpl.html', + contentTemplate: false, + container: false, + element: null, + backdrop: true, + keyboard: true, + html: false, + show: true + }; + this.$get = [ '$modal', function($modal) { + function AsideFactory(config) { + var $aside = {}; + var options = angular.extend({}, defaults, config); + $aside = $modal(options); + return $aside; + } + return AsideFactory; + } ]; + }).directive('bsAside', [ '$window', '$sce', '$aside', function($window, $sce, $aside) { + var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout; + return { + restrict: 'EAC', + scope: true, + link: function postLink(scope, element, attr, transclusion) { + var options = { + scope: scope, + element: element, + show: false + }; + angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation' ], function(key) { + if (angular.isDefined(attr[key])) options[key] = attr[key]; + }); + var falseValueRegExp = /^(false|0|)$/i; + angular.forEach([ 'backdrop', 'keyboard', 'html', 'container' ], function(key) { + if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false; + }); + angular.forEach([ 'title', 'content' ], function(key) { + attr[key] && attr.$observe(key, function(newValue, oldValue) { + scope[key] = $sce.trustAsHtml(newValue); + }); + }); + attr.bsAside && scope.$watch(attr.bsAside, function(newValue, oldValue) { + if (angular.isObject(newValue)) { + angular.extend(scope, newValue); } 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; - } + scope.content = newValue; } - return delta; + }, true); + var aside = $aside(options); + element.on(attr.trigger || 'click', aside.toggle); + scope.$on('$destroy', function() { + if (aside) aside.destroy(); + options = null; + aside = null; + }); + } + }; + } ]); + angular.module('mgcrea.ngStrap.button', []).provider('$button', function() { + var defaults = this.defaults = { + activeClass: 'active', + toggleEvent: 'click' + }; + this.$get = function() { + return { + defaults: defaults + }; + }; + }).directive('bsCheckboxGroup', function() { + return { + restrict: 'A', + require: 'ngModel', + compile: function postLink(element, attr) { + element.attr('data-toggle', 'buttons'); + element.removeAttr('ng-model'); + var children = element[0].querySelectorAll('input[type="checkbox"]'); + angular.forEach(children, function(child) { + var childEl = angular.element(child); + childEl.attr('bs-checkbox', ''); + childEl.attr('ng-model', attr.ngModel + '.' + childEl.attr('value')); + }); + } + }; + }).directive('bsCheckbox', [ '$button', '$$rAF', function($button, $$rAF) { + var defaults = $button.defaults; + var constantValueRegExp = /^(true|false|\d+)$/; + return { + restrict: 'A', + require: 'ngModel', + link: function postLink(scope, element, attr, controller) { + var options = defaults; + var isInput = element[0].nodeName === 'INPUT'; + var activeElement = isInput ? element.parent() : element; + var trueValue = angular.isDefined(attr.trueValue) ? attr.trueValue : true; + if (constantValueRegExp.test(attr.trueValue)) { + trueValue = scope.$eval(attr.trueValue); } - 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', ''); + var falseValue = angular.isDefined(attr.falseValue) ? attr.falseValue : false; + if (constantValueRegExp.test(attr.falseValue)) { + falseValue = scope.$eval(attr.falseValue); } - function destroyTipElement() { - clearTimeout(timeout); - if ($tooltip.$isShown && tipElement !== null) { - if (options.autoClose) { - unbindAutoCloseEvents(); + var hasExoticValues = typeof trueValue !== 'boolean' || typeof falseValue !== 'boolean'; + if (hasExoticValues) { + controller.$parsers.push(function(viewValue) { + return viewValue ? trueValue : falseValue; + }); + controller.$formatters.push(function(modelValue) { + return angular.equals(modelValue, trueValue); + }); + scope.$watch(attr.ngModel, function(newValue, oldValue) { + controller.$render(); + }); + } + controller.$render = function() { + var isActive = angular.equals(controller.$modelValue, trueValue); + $$rAF(function() { + if (isInput) element[0].checked = isActive; + activeElement.toggleClass(options.activeClass, isActive); + }); + }; + element.bind(options.toggleEvent, function() { + scope.$apply(function() { + if (!isInput) { + controller.$setViewValue(!activeElement.hasClass('active')); } - if (options.keyboard) { - unbindKeyboardEvents(); + if (!hasExoticValues) { + controller.$render(); } - } - if (tipScope) { - tipScope.$destroy(); - tipScope = null; - } - if (tipElement) { - tipElement.remove(); - tipElement = $tooltip.$element = null; - } + }); + }); + } + }; + } ]).directive('bsRadioGroup', function() { + return { + restrict: 'A', + require: 'ngModel', + compile: function postLink(element, attr) { + element.attr('data-toggle', 'buttons'); + element.removeAttr('ng-model'); + var children = element[0].querySelectorAll('input[type="radio"]'); + angular.forEach(children, function(child) { + angular.element(child).attr('bs-radio', ''); + angular.element(child).attr('ng-model', attr.ngModel); + }); + } + }; + }).directive('bsRadio', [ '$button', '$$rAF', function($button, $$rAF) { + var defaults = $button.defaults; + var constantValueRegExp = /^(true|false|\d+)$/; + return { + restrict: 'A', + require: 'ngModel', + link: function postLink(scope, element, attr, controller) { + var options = defaults; + var isInput = element[0].nodeName === 'INPUT'; + var activeElement = isInput ? element.parent() : element; + var value; + attr.$observe('value', function(v) { + value = constantValueRegExp.test(v) ? scope.$eval(v) : v; + controller.$render(); + }); + controller.$render = function() { + var isActive = angular.equals(controller.$modelValue, value); + $$rAF(function() { + if (isInput) element[0].checked = isActive; + activeElement.toggleClass(options.activeClass, isActive); + }); + }; + element.bind(options.toggleEvent, function() { + scope.$apply(function() { + controller.$setViewValue(value); + controller.$render(); + }); + }); + } + }; + } ]); + angular.module('mgcrea.ngStrap.alert', [ 'mgcrea.ngStrap.modal' ]).provider('$alert', function() { + var defaults = this.defaults = { + animation: 'am-fade', + prefixClass: 'alert', + prefixEvent: 'alert', + placement: null, + templateUrl: 'alert/alert.tpl.html', + container: false, + element: null, + backdrop: false, + keyboard: true, + show: true, + duration: false, + type: false, + dismissable: true + }; + this.$get = [ '$modal', '$timeout', function($modal, $timeout) { + function AlertFactory(config) { + var $alert = {}; + var options = angular.extend({}, defaults, config); + $alert = $modal(options); + $alert.$scope.dismissable = !!options.dismissable; + if (options.type) { + $alert.$scope.type = options.type; } - return $tooltip; - } - 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; - }); + var show = $alert.show; + if (options.duration) { + $alert.show = function() { + show(); + $timeout(function() { + $alert.hide(); + }, options.duration * 1e3); + }; + } + return $alert; } - return TooltipFactory; + return AlertFactory; } ]; - }).directive('bsTooltip', [ '$window', '$location', '$sce', '$tooltip', '$$rAF', function($window, $location, $sce, $tooltip, $$rAF) { + }).directive('bsAlert', [ '$window', '$sce', '$alert', function($window, $sce, $alert) { + var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout; return { restrict: 'EAC', scope: true, link: function postLink(scope, element, attr, transclusion) { var options = { - scope: scope + scope: scope, + element: element, + show: false }; - 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', 'keyboard', 'html', 'container', 'animation', 'duration', 'dismissable' ], function(key) { if (angular.isDefined(attr[key])) options[key] = attr[key]; }); var falseValueRegExp = /^(false|0|)$/i; - angular.forEach([ 'html', 'container' ], function(key) { + angular.forEach([ 'keyboard', 'html', 'container', 'dismissable' ], 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(); - }); - } + angular.forEach([ 'title', 'content', 'type' ], function(key) { + attr[key] && attr.$observe(key, function(newValue, oldValue) { + scope[key] = $sce.trustAsHtml(newValue); + }); }); - attr.bsTooltip && scope.$watch(attr.bsTooltip, function(newValue, oldValue) { + attr.bsAlert && scope.$watch(attr.bsAlert, function(newValue, oldValue) { if (angular.isObject(newValue)) { angular.extend(scope, newValue); } else { - scope.title = newValue; + scope.content = 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); + var alert = $alert(options); + element.on(attr.trigger || 'click', alert.toggle); + scope.$on('$destroy', function() { + if (alert) alert.destroy(); + options = null; + alert = null; }); - attr.viewport && scope.$watch(attr.viewport, function(newValue) { - if (!tooltip || !angular.isDefined(newValue)) return; - tooltip.setViewport(newValue); + } + }; + } ]); + angular.module('mgcrea.ngStrap.affix', [ 'mgcrea.ngStrap.helpers.dimensions', 'mgcrea.ngStrap.helpers.debounce' ]).provider('$affix', function() { + var defaults = this.defaults = { + offsetTop: 'auto', + inlineStyles: true + }; + this.$get = [ '$window', 'debounce', 'dimensions', function($window, debounce, dimensions) { + var bodyEl = angular.element($window.document.body); + var windowEl = angular.element($window); + function AffixFactory(element, config) { + var $affix = {}; + var options = angular.extend({}, defaults, config); + var targetEl = options.target; + var reset = 'affix affix-top affix-bottom', setWidth = false, initialAffixTop = 0, initialOffsetTop = 0, offsetTop = 0, offsetBottom = 0, affixed = null, unpin = null; + var parent = element.parent(); + if (options.offsetParent) { + if (options.offsetParent.match(/^\d+$/)) { + for (var i = 0; i < options.offsetParent * 1 - 1; i++) { + parent = parent.parent(); + } + } else { + parent = angular.element(options.offsetParent); + } + } + $affix.init = function() { + this.$parseOffsets(); + initialOffsetTop = dimensions.offset(element[0]).top + initialAffixTop; + setWidth = !element[0].style.width; + targetEl.on('scroll', this.checkPosition); + targetEl.on('click', this.checkPositionWithEventLoop); + windowEl.on('resize', this.$debouncedOnResize); + this.checkPosition(); + this.checkPositionWithEventLoop(); + }; + $affix.destroy = function() { + targetEl.off('scroll', this.checkPosition); + targetEl.off('click', this.checkPositionWithEventLoop); + windowEl.off('resize', this.$debouncedOnResize); + }; + $affix.checkPositionWithEventLoop = function() { + setTimeout($affix.checkPosition, 1); + }; + $affix.checkPosition = function() { + var scrollTop = getScrollTop(); + var position = dimensions.offset(element[0]); + var elementHeight = dimensions.height(element[0]); + var affix = getRequiredAffixClass(unpin, position, elementHeight); + if (affixed === affix) return; + affixed = affix; + if (affix === 'top') { + unpin = null; + if (setWidth) { + element.css('width', ''); + } + if (options.inlineStyles) { + element.css('position', options.offsetParent ? '' : 'relative'); + element.css('top', ''); + } + } else if (affix === 'bottom') { + if (options.offsetUnpin) { + unpin = -(options.offsetUnpin * 1); + } else { + unpin = position.top - scrollTop; + } + if (setWidth) { + element.css('width', ''); + } + if (options.inlineStyles) { + element.css('position', options.offsetParent ? '' : 'relative'); + element.css('top', options.offsetParent ? '' : bodyEl[0].offsetHeight - offsetBottom - elementHeight - initialOffsetTop + 'px'); + } + } else { + unpin = null; + if (setWidth) { + element.css('width', element[0].offsetWidth + 'px'); + } + if (options.inlineStyles) { + element.css('position', 'fixed'); + element.css('top', initialAffixTop + 'px'); + } + } + element.removeClass(reset).addClass('affix' + (affix !== 'middle' ? '-' + affix : '')); + }; + $affix.$onResize = function() { + $affix.$parseOffsets(); + $affix.checkPosition(); + }; + $affix.$debouncedOnResize = debounce($affix.$onResize, 50); + $affix.$parseOffsets = function() { + var initialPosition = element.css('position'); + if (options.inlineStyles) { + element.css('position', options.offsetParent ? '' : 'relative'); + } + if (options.offsetTop) { + if (options.offsetTop === 'auto') { + options.offsetTop = '+0'; + } + if (options.offsetTop.match(/^[-+]\d+$/)) { + initialAffixTop = -options.offsetTop * 1; + if (options.offsetParent) { + offsetTop = dimensions.offset(parent[0]).top + options.offsetTop * 1; + } else { + offsetTop = dimensions.offset(element[0]).top - dimensions.css(element[0], 'marginTop', true) + options.offsetTop * 1; + } + } else { + offsetTop = options.offsetTop * 1; + } + } + if (options.offsetBottom) { + if (options.offsetParent && options.offsetBottom.match(/^[-+]\d+$/)) { + offsetBottom = getScrollHeight() - (dimensions.offset(parent[0]).top + dimensions.height(parent[0])) + options.offsetBottom * 1 + 1; + } else { + offsetBottom = options.offsetBottom * 1; + } + } + if (options.inlineStyles) { + element.css('position', initialPosition); + } + }; + function getRequiredAffixClass(unpin, position, elementHeight) { + var scrollTop = getScrollTop(); + var scrollHeight = getScrollHeight(); + if (scrollTop <= offsetTop) { + return 'top'; + } else if (unpin !== null && scrollTop + unpin <= position.top) { + return 'middle'; + } else if (offsetBottom !== null && position.top + elementHeight + initialAffixTop >= scrollHeight - offsetBottom) { + return 'bottom'; + } else { + return 'middle'; + } + } + function getScrollTop() { + return targetEl[0] === $window ? $window.pageYOffset : targetEl[0].scrollTop; + } + function getScrollHeight() { + return targetEl[0] === $window ? $window.document.body.scrollHeight : targetEl[0].scrollHeight; + } + $affix.init(); + return $affix; + } + return AffixFactory; + } ]; + }).directive('bsAffix', [ '$affix', '$window', function($affix, $window) { + return { + restrict: 'EAC', + require: '^?bsAffixTarget', + link: function postLink(scope, element, attr, affixTarget) { + var options = { + scope: scope, + target: affixTarget ? affixTarget.$element : angular.element($window) + }; + angular.forEach([ 'offsetTop', 'offsetBottom', 'offsetParent', 'offsetUnpin', 'inlineStyles' ], function(key) { + if (angular.isDefined(attr[key])) { + var option = attr[key]; + if (/true/i.test(option)) option = true; + if (/false/i.test(option)) option = false; + options[key] = option; + } }); - var tooltip = $tooltip(element, options); + var affix = $affix(element, options); scope.$on('$destroy', function() { - if (tooltip) tooltip.destroy(); + affix && affix.destroy(); options = null; - tooltip = null; + affix = null; }); } }; - } ]); + } ]).directive('bsAffixTarget', function() { + return { + controller: [ '$element', function($element) { + this.$element = $element; + } ] + }; + }); + 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' ]); })(window, document); \ No newline at end of file diff --git a/dist/angular-strap.min.js b/dist/angular-strap.min.js index 36e53f859..fb35b71dd 100644 --- a/dist/angular-strap.min.js +++ b/dist/angular-strap.min.js @@ -1,12 +1,11 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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(){!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){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').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.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,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})}}}]),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(){I.$emit(V.prefixEvent+'.show',F)}function p(){if(I.$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'===P&&'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'===P&&'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=E(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';M(f,n[p],d)}}}function E(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 M(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()),q&&(q.$destroy(),q=null),R&&(R.remove(),R=F.$element=null)}var F={},V=F.$options=angular.extend({},e,r),O=F.$promise=o.compile(V),I=F.$scope=V.scope&&V.scope.$new()||a.$new(),P=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&&(I.title=u.trustAsHtml(V.title)),I.$setEnabled=function(e){I.$$postDigest(function(){F.setEnabled(e)})},I.$hide=function(){I.$$postDigest(function(){F.hide()})},I.$show=function(){I.$$postDigest(function(){F.show()})},I.$toggle=function(){I.$$postDigest(function(){F.toggle()})},F.$isShown=I.$isShown=!1;var H,L,U,R,Y,q;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?Y=i:angular.isElement(V.container)?Y=V.container:V.container&&(Y=m(V.container)),v(),V.target&&(V.target=angular.isElement(V.target)?V.target:m(V.target)),V.show&&I.$$postDigest(function(){'focus'===V.trigger?i[0].focus():F.show()})},F.destroy=function(){w(),A(),I.$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){I.$emit(V.prefixEvent+'.show.before',F);var e,t;V.container?(e=Y,t=Y[0].lastChild?angular.element(Y[0].lastChild):null):(e=null,t=i),R&&A(),q=F.$scope.$new(),R=F.$element=U.link(q,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=I.$isShown=!0,g(I),F.$applyPlacement(),angular.version.minor<=2?l.enter(R,e,t,s):l.enter(R,e,t).then(s),g(I),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&&(I.$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=I.$isShown=!1,g(I),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-it?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*E;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 M=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 M())};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',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(a,r,s){var u={},c=angular.extend({},e,s);u=o(a,c);var d=u.$scope;d.$matches=[],d.$activeIndex=c.multiple?[]:-1,d.$isMultiple=c.multiple,d.$showAllNoneButtons=c.allNoneButtons&&c.multiple,d.$iconCheckmark=c.iconCheckmark,d.$allText=c.allText,d.$noneText=c.noneText,d.$activate=function(e){d.$$postDigest(function(){u.activate(e)})},d.$select=function(e,t){d.$$postDigest(function(){u.select(e)})},d.$isVisible=function(){return u.$isVisible()},d.$isActive=function(e){return u.$isActive(e)},d.$selectAll=function(){for(var e=0;e=d.$matches.length?d.$activeIndex=c.multiple?[]:0:r.$modelValue||c.multiple||(d.$activeIndex=-1)},u.$isVisible=function(){return c.minLength&&r?d.$matches.length&&r.$viewValue.length>=c.minLength:d.$matches.length},u.$isActive=function(e){return c.multiple?-1!==d.$activeIndex.indexOf(e):d.$activeIndex===e},u.$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}},u.$onMouseDown=function(e){if(e.preventDefault(),e.stopPropagation(),l){var t=angular.element(e.target);t.triggerHandler('click')}},u.$onKeyDown=function(e){return/(9|13|38|40)/.test(e.keyCode)?(9!==e.keyCode&&(e.preventDefault(),e.stopPropagation()),c.multiple&&9===e.keyCode?u.hide():c.multiple||13!==e.keyCode&&9!==e.keyCode?void(c.multiple||(38===e.keyCode&&d.$activeIndex>0?d.$activeIndex--:38===e.keyCode&&d.$activeIndex<0?d.$activeIndex=d.$matches.length-1:40===e.keyCode&&d.$activeIndex0||e.indexOf('Trident/')>0||e.indexOf('Edge/')>0},u.$selectScrollFix=function(e){'UL'===n[0].activeElement.tagName&&(e.preventDefault(),e.stopImmediatePropagation(),e.target.focus())};var f=u.show;u.show=function(){f(),c.multiple&&u.$element.addClass('select-multiple'),i(function(){u.$element.on(l?'touchstart':'mousedown',u.$onMouseDown),c.keyboard&&a.on('keydown',u.$onKeyDown)},0,!1)};var p=u.hide;return u.hide=function(){c.multiple||r.$modelValue||(d.$activeIndex=-1),u.$element.off(l?'touchstart':'mousedown',u.$onMouseDown),c.keyboard&&a.off('keydown',u.$onKeyDown),p(!0)},u}var s=(angular.element(t.document.body),/(ip(a|o)d|iphone|android)/gi.test(t.navigator.userAgent)),l='createTouch'in t.document&&s;return r.defaults=e,r}]}).directive('bsSelect',['$window','$parse','$q','$select','$parseOptions',function(e,t,n,a,o){var i=a.defaults;return{restrict:'EAC',require:'ngModel',link:function(e,t,n,r){var s={scope:e,placeholder:i.placeholder};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(e){angular.isDefined(n[e])&&(s[e]=n[e])});var l=/^(false|0|)$/i;angular.forEach(['html','container','allNoneButtons','sort'],function(e){angular.isDefined(n[e])&&l.test(n[e])&&(s[e]=!1)});var u=t.attr('data-multiple');if(angular.isDefined(u)&&(s.multiple=l.test(u)?!1:u),'select'===t[0].nodeName.toLowerCase()){var c=t;c.css('display','none'),t=angular.element(''),c.after(t)}var d=o(n.bsOptions),f=a(t,r,s);f.$isIE()&&t[0].addEventListener('blur',f.$selectScrollFix);var 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.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.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.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.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','$animate','$timeout','$sce','dimensions',function(n,a,o,i,r,s,l){function u(t){function n(){k.$emit(b.prefixEvent+'.show',y)}function r(){k.$emit(b.prefixEvent+'.hide',y),g.removeClass(b.prefixClass+'-open'),b.animation&&g.removeClass(b.prefixClass+'-with-'+b.animation)}function l(){b.backdrop&&(x.on('click',h),C.on('click',h),C.on('wheel',v))}function u(){b.backdrop&&(x.off('click',h),C.off('click',h),C.off('wheel',v))}function m(){b.keyboard&&x.on('keyup',y.$onKeyUp)}function $(){b.keyboard&&x.off('keyup',y.$onKeyUp)}function h(e){e.target===e.currentTarget&&('static'===b.backdrop?y.focus():y.hide())}function v(e){e.preventDefault()}function w(){y.$isShown&&null!==x&&(u(),$()),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')||'',f(['title','content'],function(e){b[e]&&(k[e]=s.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=d(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&&i.enter(C,g,null),angular.version.minor<=2?i.enter(x,e,t,n):i.enter(x,e,t).then(n),y.$isShown=k.$isShown=!0,c(k);var a=x[0];p(function(){a.focus()}),g.addClass(b.prefixClass+'-open'),b.animation&&g.addClass(b.prefixClass+'-with-'+b.animation),l(),m()}}},y.hide=function(){y.$isShown&&(k.$emit(b.prefixEvent+'.hide.before',y).defaultPrevented||(angular.version.minor<=2?i.leave(x,r):i.leave(x).then(r),b.backdrop&&i.leave(C),y.$isShown=k.$isShown=!1,c(k),u(),$()))},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 c(e){e.$$phase||e.$root&&e.$root.$$phase||e.$digest()}function d(e,n){return angular.element((n||t).querySelectorAll(e))}var f=angular.forEach,p=(String.prototype.trim,n.requestAnimationFrame||n.setTimeout),g=angular.element(n.document.body);return u}]}).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','placement','backdrop','keyboard','html','container','animation','backdropAnimation','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.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.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.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.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.dateParser',[]).provider('$dateParser',['$localeProvider',function(e){function t(){this.year=1970,this.month=0,this.day=1,this.hours=0,this.minutes=0,this.seconds=0,this.milliseconds=0}function n(){}function a(e){return!isNaN(parseFloat(e))&&isFinite(e)}function o(e,t){for(var n=e.length,a=t.toString().toLowerCase(),o=0;n>o;o++)if(e[o].toLowerCase()===a)return o;return-1}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.dateFormatter',[]).service('$dateFormatter',['$locale','dateFilter',function(e,t){function n(e){return/(h+)([:\.])?(m+)([:\.])?(s*)[ ]?(a?)/i.exec(e).slice(1)}this.getDefaultLocale=function(){return e.id},this.getDatetimeFormat=function(t,n){return e.DATETIME_FORMATS[t]||t},this.weekdaysShort=function(t){return e.DATETIME_FORMATS.SHORTDAY},this.hoursFormat=function(e){return n(e)[0]},this.minutesFormat=function(e){return n(e)[2]},this.secondsFormat=function(e){return n(e)[4]},this.timeSeparator=function(e){return n(e)[1]},this.showSeconds=function(e){return!!n(e)[4]},this.showAM=function(e){return!!n(e)[5]},this.formatDate=function(e,n,a,o){return t(e,n,o)}}]),angular.module('mgcrea.ngStrap.core',[]).service('$bsCompiler',a),a.$inject=['$q','$http','$injector','$compile','$controller','$templateCache'],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&&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.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;n=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,'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'))),o.removeClass(g).addClass('affix'+('middle'!==r?'-'+r:'')))},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',['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'])}(window,document); //# sourceMappingURL=angular-strap.min.js.map \ No newline at end of file diff --git a/dist/angular-strap.min.js.map b/dist/angular-strap.min.js.map index 4846ea2f5..a4e644689 100644 --- a/dist/angular-strap.min.js.map +++ b/dist/angular-strap.min.js.map @@ -1 +1 @@ -{"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 +{"version":3,"sources":["angular-strap.js","typeahead/typeahead.js","helpers/compiler.js","dropdown/dropdown.js","tooltip/tooltip.js","timepicker/timepicker.js","tab/tab.js","select/select.js","scrollspy/scrollspy.js","popover/popover.js","navbar/navbar.js","modal/modal.js","helpers/raf.js","helpers/parse-options.js","helpers/dimensions.js","helpers/debounce.js","helpers/date-parser.js","helpers/date-formatter.js","datepicker/datepicker.js","collapse/collapse.js","aside/aside.js","button/button.js","alert/alert.js","affix/affix.js","module.js"],"names":["placement","document","undefined","templateUrl","options","cache","$templateCache","then","element","res","fetchTemplate","template","fetchPromises","bsCompilerService","$inject","$http","get","angular","module","defaults","this","animation","data","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","apply","trigger","provider","container","keyboard","delay","minLength","filter","limit","autoSelect","comparator","trimValue","$get","bodyEl","$typeahead","$scope","$matches","config","$resetMatches","$$postDigest","activate","$activeIndex","select","index","$select","evt","matches","$isVisible","safeDigest","update","$$rAF","$render","$emit","prefixEvent","parentScope","length","l","$viewValue","i","preventDefault","stopPropagation","keyCode","$digest","show","$timeout","$element","$onMouseDown","hide","on","$onKeyDown","TypeaheadFactory","array","isFunction","$$phase","$window","body","$filter","expression","directive","results","restrict","require","falseValueRegExp","attr","bsOptions","test","parsedOptions","$parseOptions","typeahead","watchOptions","watchedOptions","$watchCollection","values","$match","$watch","ngModel","newValue","oldValue","$modelValue","valuesFn","selectMode","isVisible","slice","$formatters","displayValue","push","modelValue","selected","val","destroy","isDefined","label","toString","$on","target","title","type","autoClose","bsEnabled","viewport","selector","padding","String","htmlReplaceRegExp","$body","$tooltip","split","enterAnimateCallback","leaveAnimateCallback","_tipToHide","leave","$isShown","blur","tipElement","nodeName","triggers","toggle","unbindTriggerEvents","enter","off","bindKeyboardEvents","$onKeyUp","isTouch","$onFocusElementMouseDown","unbindKeyboardEvents","_autoCloseEventsBinded","bindAutoCloseEvents","unbindAutoCloseEvents","stopEventPropagation","event","getPosition","rect","width","elRect","height","p","top","left","dimensions","offset","el","scroll","isBody","documentElement","getCalculatedOffset","position","actualWidth","actualHeight","outerDims","clientWidth","innerHeight","tip","marginTop","parseInt","using","props","css","isNaN","right","marginLeft","setOffset","delta","getViewportAdjustedDelta","isVertical","replaceArrow","arrowDelta","arrowOffsetPosition","viewportDimensions","$viewport","topEdgeOffset","bottomEdgeOffset","viewportPadding","leftEdgeOffset","rightEdgeOffset","dimension","isHorizontal","$arrow","clearTimeout","timeout","tipScope","$destroy","$options","$promise","$bsCompiler","$new","$rootScope","toLowerCase","$id","map","parseFloat","$sce","trustAsHtml","$setEnabled","id","$hide","setEnabled","isEnabled","compileData","promise","init","tipContainer","bindTriggerEvents","isElement","destroyTipElement","hoverState","parent","after","lastChild","display","visibility","clonedElement","version","minor","addClass","$animate","customClass","$applyPlacement","focus","_blur","elementPosition","autoPlace","autoToken","viewportPosition","originalPlacement","indexOf","tipHeight","removeClass","tipPosition","applyPlacement","tipWidth","$location","transclusion","dataTarget","hasOwnProperty","tooltip","$observe","bsTooltip","bsShow","match","setViewport","useNative","timeType","timeFormat","timezone","modelTimeFormat","autoclose","minTime","maxTime","Infinity","hourStep","minuteStep","secondStep","roundDisplay","iconUp","iconDown","arrowBehavior","isNative","$timepicker","timepickerFactory","formatDate","format","viewDate","hour","startDate","getHours","meridian","coeff","selRange","end","start","setSelectionRange","isUndefined","collapse","selectionStart","moveStart","selectionEnd","moveEnd","focusElement","_init","floorMinutes","time","floor","lang","selectedIndex","date","defaultDate","second","getSeconds","millisecond","getMilliseconds","$dateValue","hoursFormat","$dateFormatter","$iconUp","$iconDown","$moveIndex","$switchMeridian","switchMeridian","isDate","getMinutes","getTime","$build","minute","$setViewValue","keep","Date","setHours","setMinutes","setSeconds","hours","midIndex","$isSelected","disabled","minutes","seconds","minutesFormat","rows","showSeconds","secondsFormat","$isDisabled","showAM","timeSeparator","$date","isAM","selectedTime","$arrowAction","$setTimeByStep","newDate","targetDate","targetEl","triggerHandler","sepLength","lateralMove","count","minutesLength","selectRange","hoursLength","incr","isSeconds","isMeridian","secondsLength","createSelection","createTextRange","prop","_destroy","_show","_hide","navigator","userAgent","isMaxValid","isValid","parsedTime","isMinValid","setFullYear","$setValidity","$parsers","unshift","viewValue","getTimeFormattedString","timepicker","dateParser","$dateParser","validateAgainstMinMaxTime","getTimeForAttribute","parse","timezoneOffsetAdjust","NaN","self","navClass","activeClass","$activeClass","$panes","$activePaneChangeListeners","$push","pane","$active","$attrs","$navClass","$remove","active","activeIndex","splice","$setActive","name","fn","$pane","$tab","transclude","postLink","ngModelCtrl","bsTabsCtrl","attrs","bsActivePane","parsedBsActivePane","assign","$parse","render","$isActive","prefixClass","multiple","allNoneButtons","sort","caretHtml","placeholder","allText","noneText","maxLength","maxLengthHtml","iconCheckmark","SelectFactory","$isMultiple","$showAllNoneButtons","$allText","$iconCheckmark","$selectNone","$updateActiveIndex","b","a","$apply","$getIndex","$selectScrollFix","$isIE","stopImmediatePropagation","ua","activeElement","tagName","e","dataMultiple","inputEl","addEventListener","isArray","join","$isEmpty","spies","$document","windowEl","debounce","throttle","ScrollSpyFactory","scrollEl","isWindowSpy","scrollId","$$count","$scrollspy","unbindViewContentLoaded","unbindIncludeContentLoaded","trackedElements","$trackedElements","sortedElements","activeTarget","debouncedCheckPosition","viewportHeight","throttledCheckPosition","debouncedCheckOffsets","scrollTop","checkPositionWithEventLoop","checkOffsets","checkPosition","docEl","$activateElement","offsetTop","setTimeout","source","$getTrackedElement","targetElement","querySelector","trackedElement","trackElement","toDelete","untrackElement","scrollspy","childEl","querySelectorAll","child","content","$popover","PopoverFactory","requestAnimationFrame","popover","bsPopover","routeAttr","$navbar","liElements","li","liElement","pattern","path","RegExp","regexp","backdrop","bodyElement","ModalFactory","$modal","modalElement","unbindBackdropEvents","hideOnBackdropClick","backdropElement","preventEventDefault","destroyModalElement","modalScope","$show","bottom","z-index","defaultPrevented","backdropAnimation","bindBackdropEvents","which","$root","query","bsModal","modal","cancelAnimationFrame","webkitRequestAnimationFrame","mozRequestAnimationFrame","rafSupported","raf","timer","$values","displayFn","valueName","valueFn","ParseOptionsFactory","groupByFn","keyName","jqLite","currentStyle","window","getComputedStyle","extra","boxRect","getBoundingClientRect","style","offsetHeight","docElement","ownerDocument","curPosition","curLeft","curCSSTop","pageYOffset","clientTop","pageXOffset","scrollLeft","clientLeft","curCSSLeft","calculatePosition","curTop","curOffset","curElem","call","offsetParentRect","offsetParentElement","offsetParent","offsetWidth","outer","func","immediate","factory","context","args","cancel","callNow","leading","trailing","wait","year","$localeProvider","milliseconds","ParseDate","prototype","isNumeric","n","isFinite","indexOfCaseInsensitive","len","str","strict","DateParserFactory","day","month","getFullYear","getMonth","proto","noop","toDate","regExpMap","sss","$locale","dateFilter","mm","keys","setFnMap","clonedFormat","search","v","sortedMap","regExpForFormat","re","text","Object","escapeReservedSymbols","regex","m","HH","H","hh","h","EEEE","EEE","DATETIME_FORMATS","SHORTDAY","dd","d","MMMM","MMM","SHORTMONTH","MM","M","DAY","yyyy","yy","y","MONTH","ss","s","setDate","setMonth","setMap","$format","setMapForFormat","baseDate","formatRegex","formatSetMap","exec","fromDate","getDate","today","getDateForAttribute","substr","daylightSavingAdjust","undo","getDefaultLocale","getDatetimeFormat","weekdaysShort","splitTimeFormat","service","matchesSelector","DropdownFactory","$dropdown","onBodyClick","items","parentEl","hasClass","bsDropdown","dropdown","dateType","dateFormat","modelDateFormat","dayFormat","monthFormat","yearFormat","monthTitleFormat","yearTitleFormat","strictFormat","minDate","maxDate","startView","minView","startWeek","daysOfWeekDisabled","iconLeft","iconRight","DatepickerFactory","$datepicker","pickerViews","views","$iconLeft","$iconRight","$picker","$views","$mode","datepickerViews","$selectPane","$toggleMode","setMode","updateDisabledDates","disabledDateRanges","dateRanges","mode","pristine","$updateSelected","built","$setDisabledEl","isDisabled","steps","getUTCFullYear","getUTCMonth","UTC","getUTCDate","shiftKey","altKey","updateSelected","onKeyDown","previousValue","normalizeDateRanges","ranges","disabledRanges","datepicker","parsedDate","getDateFormattedString","validateAgainstMinMaxDate","disabledDates","daySplit","arr","mod","arrays","size","weekDaysMin","weekDaysLabelsHtml","picker","weekDaysLabels","concat","firstDayOfMonth","firstDate","getDay","firstDateOffset","build","days","isToday","toDateString","muted","showLabels","labels","isSelected","firstMonth","months","lastDate","actualMonth","firstYear","years","actualYear","setYear","startCollapsed","allowMultiple","activeIndexes","$targets","activeItems","activateItem","$collapse","$viewChangeListeners","$registerToggle","$toggles","$unregisterToggle","$unregisterTarget","deactivateItem","fixActiveItemIndexes","disallowToggle","isActive","$activeIndexes","bsCollapseCtrl","controllers","bsCollapseToggle","$registerTarget","action","AsideFactory","$aside","bsAside","aside","$button","constantValueRegExp","isInput","trueValue","falseValue","hasExoticValues","equals","checked","bind","toggleEvent","toggleClass","duration","dismissable","AlertFactory","$alert","bsAlert","alert","AffixFactory","$affix","inlineStyles","reset","setWidth","initialAffixTop","getRequiredAffixClass","unpin","getScrollTop","scrollHeight","getScrollHeight","initialOffsetTop","offsetBottom","affixed","$parseOffsets","affix","elementHeight","offsetUnpin","$onResize","$debouncedOnResize","initialPosition","affixTarget","option"],"mappings":"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","file":"angular-strap.min.js","sourcesContent":["(function(window, document, undefined) {\n'use strict';\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 if (!element.attr('autocomplete')) element.attr('autocomplete', 'off');\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// 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: 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 if (angular.isUndefined(scope.$matches[index])) {\n return null;\n }\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 } else if(!controller.$modelValue && !options.multiple) {\n scope.$activeIndex = -1;\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 // Let tab propagate\n if (evt.keyCode !== 9) {\n evt.preventDefault();\n evt.stopPropagation();\n }\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 $select.$isIE = function() {\n var ua = $window.navigator.userAgent;\n return ua.indexOf('MSIE ') > 0 || ua.indexOf('Trident/') > 0 || ua.indexOf('Edge/') > 0;\n };\n\n $select.$selectScrollFix = function(e) {\n if ($document[0].activeElement.tagName === 'UL') {\n e.preventDefault();\n e.stopImmediatePropagation();\n e.target.focus();\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 if (select.$isIE()) {\n element[0].addEventListener('blur', select.$selectScrollFix);\n }\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: 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: 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: 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: 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, $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 helpers\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', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation', 'backdropAnimation', '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: 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: 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/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/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/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/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/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: 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: 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: 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: 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: 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: 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 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 // Add proper affix class\n element.removeClass(reset).addClass('affix' + ((affix !== 'middle') ? '-' + affix : ''));\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: 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})(window, document);\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 if (!element.attr('autocomplete')) element.attr('autocomplete', 'off');\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\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.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.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","'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.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 if (angular.isUndefined(scope.$matches[index])) {\n return null;\n }\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 } else if(!controller.$modelValue && !options.multiple) {\n scope.$activeIndex = -1;\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 // Let tab propagate\n if (evt.keyCode !== 9) {\n evt.preventDefault();\n evt.stopPropagation();\n }\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 $select.$isIE = function() {\n var ua = $window.navigator.userAgent;\n return ua.indexOf('MSIE ') > 0 || ua.indexOf('Trident/') > 0 || ua.indexOf('Edge/') > 0;\n };\n\n $select.$selectScrollFix = function(e) {\n if ($document[0].activeElement.tagName === 'UL') {\n e.preventDefault();\n e.stopImmediatePropagation();\n e.target.focus();\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 if (select.$isIE()) {\n element[0].addEventListener('blur', select.$selectScrollFix);\n }\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.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.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.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.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, $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 helpers\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', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation', 'backdropAnimation', '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\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.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\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.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.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.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.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.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.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\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.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 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 // Add proper affix class\n element.removeClass(reset).addClass('affix' + ((affix !== 'middle') ? '-' + affix : ''));\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","\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"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/dist/angular-strap.tpl.js b/dist/angular-strap.tpl.js index 5dd509b83..530ee1e05 100644 --- a/dist/angular-strap.tpl.js +++ b/dist/angular-strap.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -14,7 +14,7 @@ $templateCache.put('aside/aside.tpl.html', ''); } ]); angular.module('mgcrea.ngStrap.datepicker').run([ '$templateCache', function($templateCache) { - $templateCache.put('datepicker/datepicker.tpl.html', ''); + $templateCache.put('datepicker/datepicker.tpl.html', ''); } ]); angular.module('mgcrea.ngStrap.dropdown').run([ '$templateCache', function($templateCache) { $templateCache.put('dropdown/dropdown.tpl.html', ''); @@ -28,16 +28,16 @@ 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.timepicker').run([ '$templateCache', function($templateCache) { + $templateCache.put('timepicker/timepicker.tpl.html', ''); } ]); angular.module('mgcrea.ngStrap.tooltip').run([ '$templateCache', function($templateCache) { $templateCache.put('tooltip/tooltip.tpl.html', '
'); } ]); + angular.module('mgcrea.ngStrap.typeahead').run([ '$templateCache', function($templateCache) { + $templateCache.put('typeahead/typeahead.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 8b97e4184..9d9ab279a 100644 --- a/dist/angular-strap.tpl.min.js +++ b/dist/angular-strap.tpl.min.js @@ -1,8 +1,8 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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.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 +!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.tab').run(['$templateCache',function(t){t.put('tab/tab.tpl.html','
')}]),angular.module('mgcrea.ngStrap.timepicker').run(['$templateCache',function(t){t.put('timepicker/timepicker.tpl.html','')}]),angular.module('mgcrea.ngStrap.tooltip').run(['$templateCache',function(t){t.put('tooltip/tooltip.tpl.html','
')}]),angular.module('mgcrea.ngStrap.typeahead').run(['$templateCache',function(t){t.put('typeahead/typeahead.tpl.html','')}])}(window,document); \ No newline at end of file diff --git a/dist/modules/affix.js b/dist/modules/affix.js index d95088a4f..203545243 100644 --- a/dist/modules/affix.js +++ b/dist/modules/affix.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -55,7 +55,6 @@ angular.module('mgcrea.ngStrap.affix', [ 'mgcrea.ngStrap.helpers.dimensions', 'm var affix = getRequiredAffixClass(unpin, position, elementHeight); if (affixed === affix) return; affixed = affix; - element.removeClass(reset).addClass('affix' + (affix !== 'middle' ? '-' + affix : '')); if (affix === 'top') { unpin = null; if (setWidth) { @@ -88,6 +87,7 @@ angular.module('mgcrea.ngStrap.affix', [ 'mgcrea.ngStrap.helpers.dimensions', 'm element.css('top', initialAffixTop + 'px'); } } + element.removeClass(reset).addClass('affix' + (affix !== 'middle' ? '-' + affix : '')); }; $affix.$onResize = function() { $affix.$parseOffsets(); diff --git a/dist/modules/affix.min.js b/dist/modules/affix.min.js index 9eaefdc7f..a122e8b4f 100644 --- a/dist/modules/affix.min.js +++ b/dist/modules/affix.min.js @@ -1,9 +1,9 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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.affix',['mgcrea.ngStrap.helpers.dimensions','mgcrea.ngStrap.helpers.debounce']).provider('$affix',function(){var t=this.defaults={offsetTop:'auto',inlineStyles:!0};this.$get=['$window','debounce','dimensions',function(e,o,n){function i(i,r){function c(t,e,o){var n=a(),i=l();return P>=n?'top':null!==t&&n+t<=e.top?'middle':null!==$&&e.top+o+g>=i-$?'bottom':'middle'}function a(){return h[0]===e?e.pageYOffset:h[0].scrollTop}function l(){return h[0]===e?e.document.body.scrollHeight:h[0].scrollHeight}var u={},p=angular.extend({},t,r),h=p.target,d='affix affix-top affix-bottom',m=!1,g=0,v=0,P=0,$=0,x=null,T=null,b=i.parent();if(p.offsetParent)if(p.offsetParent.match(/^\d+$/))for(var k=0;k<1*p.offsetParent-1;k++)b=b.parent();else b=angular.element(p.offsetParent);return u.init=function(){this.$parseOffsets(),v=n.offset(i[0]).top+g,m=!i[0].style.width,h.on('scroll',this.checkPosition),h.on('click',this.checkPositionWithEventLoop),f.on('resize',this.$debouncedOnResize),this.checkPosition(),this.checkPositionWithEventLoop()},u.destroy=function(){h.off('scroll',this.checkPosition),h.off('click',this.checkPositionWithEventLoop),f.off('resize',this.$debouncedOnResize)},u.checkPositionWithEventLoop=function(){setTimeout(u.checkPosition,1)},u.checkPosition=function(){var t=a(),e=n.offset(i[0]),o=n.height(i[0]),f=c(T,e,o);x!==f&&(x=f,i.removeClass(d).addClass('affix'+('middle'!==f?'-'+f:'')),'top'===f?(T=null,m&&i.css('width',''),p.inlineStyles&&(i.css('position',p.offsetParent?'':'relative'),i.css('top',''))):'bottom'===f?(T=p.offsetUnpin?-(1*p.offsetUnpin):e.top-t,m&&i.css('width',''),p.inlineStyles&&(i.css('position',p.offsetParent?'':'relative'),i.css('top',p.offsetParent?'':s[0].offsetHeight-$-o-v+'px'))):(T=null,m&&i.css('width',i[0].offsetWidth+'px'),p.inlineStyles&&(i.css('position','fixed'),i.css('top',g+'px'))))},u.$onResize=function(){u.$parseOffsets(),u.checkPosition()},u.$debouncedOnResize=o(u.$onResize,50),u.$parseOffsets=function(){var t=i.css('position');p.inlineStyles&&i.css('position',p.offsetParent?'':'relative'),p.offsetTop&&('auto'===p.offsetTop&&(p.offsetTop='+0'),p.offsetTop.match(/^[-+]\d+$/)?(g=1*-p.offsetTop,P=p.offsetParent?n.offset(b[0]).top+1*p.offsetTop:n.offset(i[0]).top-n.css(i[0],'marginTop',!0)+1*p.offsetTop):P=1*p.offsetTop),p.offsetBottom&&($=p.offsetParent&&p.offsetBottom.match(/^[-+]\d+$/)?l()-(n.offset(b[0]).top+n.height(b[0]))+1*p.offsetBottom+1:1*p.offsetBottom),p.inlineStyles&&i.css('position',t)},u.init(),u}var s=angular.element(e.document.body),f=angular.element(e);return i}]}).directive('bsAffix',['$affix','$window',function(t,e){return{restrict:'EAC',require:'^?bsAffixTarget',link:function(o,n,i,s){var f={scope:o,target:s?s.$element:angular.element(e)};angular.forEach(['offsetTop','offsetBottom','offsetParent','offsetUnpin','inlineStyles'],function(t){if(angular.isDefined(i[t])){var e=i[t];/true/i.test(e)&&(e=!0),/false/i.test(e)&&(e=!1),f[t]=e}});var r=t(n,f);o.$on('$destroy',function(){r&&r.destroy(),f=null,r=null})}}}]).directive('bsAffixTarget',function(){return{controller:['$element',function(t){this.$element=t}]}}); +'use strict';angular.module('mgcrea.ngStrap.affix',['mgcrea.ngStrap.helpers.dimensions','mgcrea.ngStrap.helpers.debounce']).provider('$affix',function(){var t=this.defaults={offsetTop:'auto',inlineStyles:!0};this.$get=['$window','debounce','dimensions',function(e,o,n){function i(i,r){function c(t,e,o){var n=a(),i=l();return P>=n?'top':null!==t&&n+t<=e.top?'middle':null!==$&&e.top+o+g>=i-$?'bottom':'middle'}function a(){return h[0]===e?e.pageYOffset:h[0].scrollTop}function l(){return h[0]===e?e.document.body.scrollHeight:h[0].scrollHeight}var u={},p=angular.extend({},t,r),h=p.target,d='affix affix-top affix-bottom',m=!1,g=0,v=0,P=0,$=0,x=null,T=null,b=i.parent();if(p.offsetParent)if(p.offsetParent.match(/^\d+$/))for(var k=0;k<1*p.offsetParent-1;k++)b=b.parent();else b=angular.element(p.offsetParent);return u.init=function(){this.$parseOffsets(),v=n.offset(i[0]).top+g,m=!i[0].style.width,h.on('scroll',this.checkPosition),h.on('click',this.checkPositionWithEventLoop),f.on('resize',this.$debouncedOnResize),this.checkPosition(),this.checkPositionWithEventLoop()},u.destroy=function(){h.off('scroll',this.checkPosition),h.off('click',this.checkPositionWithEventLoop),f.off('resize',this.$debouncedOnResize)},u.checkPositionWithEventLoop=function(){setTimeout(u.checkPosition,1)},u.checkPosition=function(){var t=a(),e=n.offset(i[0]),o=n.height(i[0]),f=c(T,e,o);x!==f&&(x=f,'top'===f?(T=null,m&&i.css('width',''),p.inlineStyles&&(i.css('position',p.offsetParent?'':'relative'),i.css('top',''))):'bottom'===f?(T=p.offsetUnpin?-(1*p.offsetUnpin):e.top-t,m&&i.css('width',''),p.inlineStyles&&(i.css('position',p.offsetParent?'':'relative'),i.css('top',p.offsetParent?'':s[0].offsetHeight-$-o-v+'px'))):(T=null,m&&i.css('width',i[0].offsetWidth+'px'),p.inlineStyles&&(i.css('position','fixed'),i.css('top',g+'px'))),i.removeClass(d).addClass('affix'+('middle'!==f?'-'+f:'')))},u.$onResize=function(){u.$parseOffsets(),u.checkPosition()},u.$debouncedOnResize=o(u.$onResize,50),u.$parseOffsets=function(){var t=i.css('position');p.inlineStyles&&i.css('position',p.offsetParent?'':'relative'),p.offsetTop&&('auto'===p.offsetTop&&(p.offsetTop='+0'),p.offsetTop.match(/^[-+]\d+$/)?(g=1*-p.offsetTop,P=p.offsetParent?n.offset(b[0]).top+1*p.offsetTop:n.offset(i[0]).top-n.css(i[0],'marginTop',!0)+1*p.offsetTop):P=1*p.offsetTop),p.offsetBottom&&($=p.offsetParent&&p.offsetBottom.match(/^[-+]\d+$/)?l()-(n.offset(b[0]).top+n.height(b[0]))+1*p.offsetBottom+1:1*p.offsetBottom),p.inlineStyles&&i.css('position',t)},u.init(),u}var s=angular.element(e.document.body),f=angular.element(e);return i}]}).directive('bsAffix',['$affix','$window',function(t,e){return{restrict:'EAC',require:'^?bsAffixTarget',link:function(o,n,i,s){var f={scope:o,target:s?s.$element:angular.element(e)};angular.forEach(['offsetTop','offsetBottom','offsetParent','offsetUnpin','inlineStyles'],function(t){if(angular.isDefined(i[t])){var e=i[t];/true/i.test(e)&&(e=!0),/false/i.test(e)&&(e=!1),f[t]=e}});var r=t(n,f);o.$on('$destroy',function(){r&&r.destroy(),f=null,r=null})}}}]).directive('bsAffixTarget',function(){return{controller:['$element',function(t){this.$element=t}]}}); //# sourceMappingURL=../modules/affix.min.js.map \ No newline at end of file diff --git a/dist/modules/affix.min.js.map b/dist/modules/affix.min.js.map index 510907b9f..f01603f9d 100644 --- a/dist/modules/affix.min.js.map +++ b/dist/modules/affix.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["modules/affix.js"],"names":["angular","windowEl","$window","defaults","AffixFactory","offsetTop","$affix","inlineStyles","options","this","$get","reset","setWidth","initialAffixTop","offsetParent","match","getRequiredAffixClass","unpin","position","top","scrollTop","getScrollTop","scrollHeight","getScrollHeight","targetEl","pageYOffset","directive","document","parent","target","initialOffsetTop","offsetBottom","affixed","element","init","i","$parseOffsets","on","checkPosition","require","checkPositionWithEventLoop","dimensions","offset","destroy","style","width","off","affix","setTimeout","elementHeight","height","css","addClass","offsetUnpin","bodyEl","offsetHeight","offsetWidth","$debouncedOnResize","$onResize","initialPosition","restrict","affixTarget","$element","forEach","link","key","scope","option","$on","attr","test","controller"],"mappings":"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","file":"modules/affix.min.js","sourcesContent":["'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"],"sourceRoot":"/source/"} \ No newline at end of file +{"version":3,"sources":["modules/affix.js"],"names":["angular","windowEl","$window","defaults","AffixFactory","offsetTop","$affix","inlineStyles","options","this","$get","reset","setWidth","initialAffixTop","offsetParent","match","getRequiredAffixClass","unpin","position","top","scrollTop","getScrollTop","scrollHeight","getScrollHeight","targetEl","pageYOffset","directive","document","parent","target","initialOffsetTop","offsetBottom","affixed","element","init","i","$parseOffsets","on","checkPosition","require","checkPositionWithEventLoop","dimensions","offset","destroy","style","width","off","affix","setTimeout","height","elementHeight","css","offsetUnpin","bodyEl","offsetHeight","removeClass","addClass","offsetWidth","$onResize","$debouncedOnResize","initialPosition","restrict","affixTarget","$element","forEach","link","key","scope","option","$on","attr","test","controller"],"mappings":"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","file":"modules/affix.min.js","sourcesContent":["'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 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 // Add proper affix class\n element.removeClass(reset).addClass('affix' + ((affix !== 'middle') ? '-' + affix : ''));\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"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/dist/modules/alert.js b/dist/modules/alert.js index d78c05f09..73f728465 100644 --- a/dist/modules/alert.js +++ b/dist/modules/alert.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 2791c0a63..fedf21559 100644 --- a/dist/modules/alert.min.js +++ b/dist/modules/alert.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 d5ac7b34f..008f0f657 100644 --- a/dist/modules/alert.tpl.js +++ b/dist/modules/alert.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 17c22e01b..18fa29d4c 100644 --- a/dist/modules/alert.tpl.min.js +++ b/dist/modules/alert.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 48d3ea57d..1ac253007 100644 --- a/dist/modules/aside.js +++ b/dist/modules/aside.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 5c9076cf1..473cdb68d 100644 --- a/dist/modules/aside.min.js +++ b/dist/modules/aside.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 387b47aae..1c188adf4 100644 --- a/dist/modules/aside.tpl.js +++ b/dist/modules/aside.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 17ae2833b..b80b21eb4 100644 --- a/dist/modules/aside.tpl.min.js +++ b/dist/modules/aside.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 3c79e441a..8dc73398f 100644 --- a/dist/modules/button.js +++ b/dist/modules/button.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 9bbbc5c5f..084edec60 100644 --- a/dist/modules/button.min.js +++ b/dist/modules/button.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 dac304644..9937f5c63 100644 --- a/dist/modules/collapse.js +++ b/dist/modules/collapse.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 dd4ea968e..c9a5f8f35 100644 --- a/dist/modules/collapse.min.js +++ b/dist/modules/collapse.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 f78ec2fb9..c2e8917eb 100644 --- a/dist/modules/compiler.js +++ b/dist/modules/compiler.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 c7ab03e9e..9403bc571 100644 --- a/dist/modules/compiler.min.js +++ b/dist/modules/compiler.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 a71bb3c5e..04af0da1f 100644 --- a/dist/modules/date-formatter.js +++ b/dist/modules/date-formatter.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 6849c9dbb..42169d220 100644 --- a/dist/modules/date-formatter.min.js +++ b/dist/modules/date-formatter.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 0b78e2055..f4ee82b92 100644 --- a/dist/modules/date-parser.js +++ b/dist/modules/date-parser.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 1af00486a..e182b4025 100644 --- a/dist/modules/date-parser.min.js +++ b/dist/modules/date-parser.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 facc6e582..a00a8654b 100644 --- a/dist/modules/datepicker.js +++ b/dist/modules/datepicker.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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.min.js b/dist/modules/datepicker.min.js index 1b7303813..e66de4e60 100644 --- a/dist/modules/datepicker.min.js +++ b/dist/modules/datepicker.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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.js b/dist/modules/datepicker.tpl.js index 67cfb1125..6dcaffa9c 100644 --- a/dist/modules/datepicker.tpl.js +++ b/dist/modules/datepicker.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -8,5 +8,5 @@ 'use strict'; angular.module('mgcrea.ngStrap.datepicker').run([ '$templateCache', function($templateCache) { - $templateCache.put('datepicker/datepicker.tpl.html', ''); + $templateCache.put('datepicker/datepicker.tpl.html', ''); } ]); \ No newline at end of file diff --git a/dist/modules/datepicker.tpl.min.js b/dist/modules/datepicker.tpl.min.js index c9c7f41e3..3cd076cc2 100644 --- a/dist/modules/datepicker.tpl.min.js +++ b/dist/modules/datepicker.tpl.min.js @@ -1,8 +1,8 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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').run(['$templateCache',function(t){t.put('datepicker/datepicker.tpl.html','')}]); \ No newline at end of file +'use strict';angular.module('mgcrea.ngStrap.datepicker').run(['$templateCache',function(t){t.put('datepicker/datepicker.tpl.html','')}]); \ No newline at end of file diff --git a/dist/modules/debounce.js b/dist/modules/debounce.js index 4ffa3857b..d4642518d 100644 --- a/dist/modules/debounce.js +++ b/dist/modules/debounce.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 2e284d18b..81bd21576 100644 --- a/dist/modules/debounce.min.js +++ b/dist/modules/debounce.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 df30d1b3b..e3ae9586c 100644 --- a/dist/modules/dimensions.js +++ b/dist/modules/dimensions.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 695b16bd3..10283a71e 100644 --- a/dist/modules/dimensions.min.js +++ b/dist/modules/dimensions.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 f723c9b96..ee1737772 100644 --- a/dist/modules/dropdown.js +++ b/dist/modules/dropdown.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 ab99b561a..55a5c828b 100644 --- a/dist/modules/dropdown.min.js +++ b/dist/modules/dropdown.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 1bbe6f63f..86ef430d3 100644 --- a/dist/modules/dropdown.tpl.js +++ b/dist/modules/dropdown.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 eb6226b77..e0b3cef67 100644 --- a/dist/modules/dropdown.tpl.min.js +++ b/dist/modules/dropdown.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 70351635d..4c3ebf5b0 100644 --- a/dist/modules/modal.js +++ b/dist/modules/modal.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -24,7 +24,7 @@ angular.module('mgcrea.ngStrap.modal', [ 'mgcrea.ngStrap.core', 'mgcrea.ngStrap. html: false, show: true }; - this.$get = [ '$window', '$rootScope', '$bsCompiler', '$q', '$templateCache', '$http', '$animate', '$timeout', '$sce', 'dimensions', function($window, $rootScope, $bsCompiler, $q, $templateCache, $http, $animate, $timeout, $sce, dimensions) { + this.$get = [ '$window', '$rootScope', '$bsCompiler', '$animate', '$timeout', '$sce', 'dimensions', function($window, $rootScope, $bsCompiler, $animate, $timeout, $sce, dimensions) { var forEach = angular.forEach; var trim = String.prototype.trim; var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout; @@ -242,7 +242,7 @@ angular.module('mgcrea.ngStrap.modal', [ 'mgcrea.ngStrap.core', 'mgcrea.ngStrap. element: element, show: false }; - angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'controller', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation', 'id', 'prefixEvent', 'prefixClass' ], function(key) { + angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation', 'backdropAnimation', 'id', 'prefixEvent', 'prefixClass' ], function(key) { if (angular.isDefined(attr[key])) options[key] = attr[key]; }); var falseValueRegExp = /^(false|0|)$/i; diff --git a/dist/modules/modal.min.js b/dist/modules/modal.min.js index 2aeb0cfbb..043e06341 100644 --- a/dist/modules/modal.min.js +++ b/dist/modules/modal.min.js @@ -1,9 +1,9 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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.modal',['mgcrea.ngStrap.core','mgcrea.ngStrap.helpers.dimensions']).provider('$modal',function(){var n=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(e,t,o,i,a,r,l,s,c,u){function d(e){function i(){C.$emit(k.prefixEvent+'.show',b)}function a(){C.$emit(k.prefixEvent+'.hide',b),h.removeClass(k.prefixClass+'-open'),k.animation&&h.removeClass(k.prefixClass+'-with-'+k.animation)}function r(){k.backdrop&&(S.on('click',g),A.on('click',g),A.on('wheel',w))}function s(){k.backdrop&&(S.off('click',g),A.off('click',g),A.off('wheel',w))}function u(){k.keyboard&&S.on('keyup',b.$onKeyUp)}function d(){k.keyboard&&S.off('keyup',b.$onKeyUp)}function g(n){n.target===n.currentTarget&&('static'===k.backdrop?b.focus():b.hide())}function w(n){n.preventDefault()}function v(){b.$isShown&&null!==S&&(s(),d()),E&&(E.$destroy(),E=null),S&&(S.remove(),S=b.$element=null)}var b={},k=b.$options=angular.extend({},n,e),x=b.$promise=o.compile(k),C=b.$scope=k.scope&&k.scope.$new()||t.$new();k.element||k.container||(k.container='body'),b.$id=k.id||k.element&&k.element.attr('id')||'',m(['title','content'],function(n){k[n]&&(C[n]=c.trustAsHtml(k[n]))}),C.$hide=function(){C.$$postDigest(function(){b.hide()})},C.$show=function(){C.$$postDigest(function(){b.show()})},C.$toggle=function(){C.$$postDigest(function(){b.toggle()})},b.$isShown=C.$isShown=!1;var y,S,E,A=angular.element('
');return A.css({position:'fixed',top:'0px',left:'0px',bottom:'0px',right:'0px','z-index':1038}),x.then(function(n){y=n,b.init()}),b.init=function(){k.show&&C.$$postDigest(function(){b.show()})},b.destroy=function(){v(),A&&(A.remove(),A=null),C.$destroy()},b.show=function(){if(!b.$isShown){var n,e;if(angular.isElement(k.container)?(n=k.container,e=k.container[0].lastChild?angular.element(k.container[0].lastChild):null):k.container?(n=p(k.container),e=n[0]&&n[0].lastChild?angular.element(n[0].lastChild):null):(n=null,e=k.element),S&&v(),E=b.$scope.$new(),S=b.$element=y.link(E,function(n,e){}),!C.$emit(k.prefixEvent+'.show.before',b).defaultPrevented){S.css({display:'block'}).addClass(k.placement),k.animation&&(k.backdrop&&A.addClass(k.backdropAnimation),S.addClass(k.animation)),k.backdrop&&l.enter(A,h,null),angular.version.minor<=2?l.enter(S,n,e,i):l.enter(S,n,e).then(i),b.$isShown=C.$isShown=!0,f(C);var t=S[0];$(function(){t.focus()}),h.addClass(k.prefixClass+'-open'),k.animation&&h.addClass(k.prefixClass+'-with-'+k.animation),r(),u()}}},b.hide=function(){b.$isShown&&(C.$emit(k.prefixEvent+'.hide.before',b).defaultPrevented||(angular.version.minor<=2?l.leave(S,a):l.leave(S).then(a),k.backdrop&&l.leave(A),b.$isShown=C.$isShown=!1,f(C),s(),d()))},b.toggle=function(){b.$isShown?b.hide():b.show()},b.focus=function(){S[0].focus()},b.$onKeyUp=function(n){27===n.which&&b.$isShown&&(b.hide(),n.stopPropagation())},b}function f(n){n.$$phase||n.$root&&n.$root.$$phase||n.$digest()}function p(n,e){return angular.element((e||document).querySelectorAll(n))}var m=angular.forEach,$=(String.prototype.trim,e.requestAnimationFrame||e.setTimeout),h=angular.element(e.document.body);return d}]}).directive('bsModal',['$window','$sce','$modal',function(n,e,t){return{restrict:'EAC',scope:!0,link:function(n,o,i,a){var r={scope:n,element:o,show:!1};angular.forEach(['template','templateUrl','controller','controllerAs','contentTemplate','controller','placement','backdrop','keyboard','html','container','animation','id','prefixEvent','prefixClass'],function(n){angular.isDefined(i[n])&&(r[n]=i[n])});var l=/^(false|0|)$/i;angular.forEach(['backdrop','keyboard','html','container'],function(n){angular.isDefined(i[n])&&l.test(i[n])&&(r[n]=!1)}),angular.forEach(['title','content'],function(t){i[t]&&i.$observe(t,function(o,i){n[t]=e.trustAsHtml(o)})}),i.bsModal&&n.$watch(i.bsModal,function(e,t){angular.isObject(e)?angular.extend(n,e):n.content=e},!0);var s=t(r);o.on(i.trigger||'click',s.toggle),n.$on('$destroy',function(){s&&s.destroy(),r=null,s=null})}}}]); +'use strict';angular.module('mgcrea.ngStrap.modal',['mgcrea.ngStrap.core','mgcrea.ngStrap.helpers.dimensions']).provider('$modal',function(){var n=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','$animate','$timeout','$sce','dimensions',function(e,t,o,i,a,r,l){function s(e){function a(){y.$emit(k.prefixEvent+'.show',b)}function l(){y.$emit(k.prefixEvent+'.hide',b),p.removeClass(k.prefixClass+'-open'),k.animation&&p.removeClass(k.prefixClass+'-with-'+k.animation)}function s(){k.backdrop&&(S.on('click',g),A.on('click',g),A.on('wheel',w))}function m(){k.backdrop&&(S.off('click',g),A.off('click',g),A.off('wheel',w))}function $(){k.keyboard&&S.on('keyup',b.$onKeyUp)}function h(){k.keyboard&&S.off('keyup',b.$onKeyUp)}function g(n){n.target===n.currentTarget&&('static'===k.backdrop?b.focus():b.hide())}function w(n){n.preventDefault()}function v(){b.$isShown&&null!==S&&(m(),h()),E&&(E.$destroy(),E=null),S&&(S.remove(),S=b.$element=null)}var b={},k=b.$options=angular.extend({},n,e),x=b.$promise=o.compile(k),y=b.$scope=k.scope&&k.scope.$new()||t.$new();k.element||k.container||(k.container='body'),b.$id=k.id||k.element&&k.element.attr('id')||'',d(['title','content'],function(n){k[n]&&(y[n]=r.trustAsHtml(k[n]))}),y.$hide=function(){y.$$postDigest(function(){b.hide()})},y.$show=function(){y.$$postDigest(function(){b.show()})},y.$toggle=function(){y.$$postDigest(function(){b.toggle()})},b.$isShown=y.$isShown=!1;var C,S,E,A=angular.element('
');return A.css({position:'fixed',top:'0px',left:'0px',bottom:'0px',right:'0px','z-index':1038}),x.then(function(n){C=n,b.init()}),b.init=function(){k.show&&y.$$postDigest(function(){b.show()})},b.destroy=function(){v(),A&&(A.remove(),A=null),y.$destroy()},b.show=function(){if(!b.$isShown){var n,e;if(angular.isElement(k.container)?(n=k.container,e=k.container[0].lastChild?angular.element(k.container[0].lastChild):null):k.container?(n=u(k.container),e=n[0]&&n[0].lastChild?angular.element(n[0].lastChild):null):(n=null,e=k.element),S&&v(),E=b.$scope.$new(),S=b.$element=C.link(E,function(n,e){}),!y.$emit(k.prefixEvent+'.show.before',b).defaultPrevented){S.css({display:'block'}).addClass(k.placement),k.animation&&(k.backdrop&&A.addClass(k.backdropAnimation),S.addClass(k.animation)),k.backdrop&&i.enter(A,p,null),angular.version.minor<=2?i.enter(S,n,e,a):i.enter(S,n,e).then(a),b.$isShown=y.$isShown=!0,c(y);var t=S[0];f(function(){t.focus()}),p.addClass(k.prefixClass+'-open'),k.animation&&p.addClass(k.prefixClass+'-with-'+k.animation),s(),$()}}},b.hide=function(){b.$isShown&&(y.$emit(k.prefixEvent+'.hide.before',b).defaultPrevented||(angular.version.minor<=2?i.leave(S,l):i.leave(S).then(l),k.backdrop&&i.leave(A),b.$isShown=y.$isShown=!1,c(y),m(),h()))},b.toggle=function(){b.$isShown?b.hide():b.show()},b.focus=function(){S[0].focus()},b.$onKeyUp=function(n){27===n.which&&b.$isShown&&(b.hide(),n.stopPropagation())},b}function c(n){n.$$phase||n.$root&&n.$root.$$phase||n.$digest()}function u(n,e){return angular.element((e||document).querySelectorAll(n))}var d=angular.forEach,f=(String.prototype.trim,e.requestAnimationFrame||e.setTimeout),p=angular.element(e.document.body);return s}]}).directive('bsModal',['$window','$sce','$modal',function(n,e,t){return{restrict:'EAC',scope:!0,link:function(n,o,i,a){var r={scope:n,element:o,show:!1};angular.forEach(['template','templateUrl','controller','controllerAs','contentTemplate','placement','backdrop','keyboard','html','container','animation','backdropAnimation','id','prefixEvent','prefixClass'],function(n){angular.isDefined(i[n])&&(r[n]=i[n])});var l=/^(false|0|)$/i;angular.forEach(['backdrop','keyboard','html','container'],function(n){angular.isDefined(i[n])&&l.test(i[n])&&(r[n]=!1)}),angular.forEach(['title','content'],function(t){i[t]&&i.$observe(t,function(o,i){n[t]=e.trustAsHtml(o)})}),i.bsModal&&n.$watch(i.bsModal,function(e,t){angular.isObject(e)?angular.extend(n,e):n.content=e},!0);var s=t(r);o.on(i.trigger||'click',s.toggle),n.$on('$destroy',function(){s&&s.destroy(),r=null,s=null})}}}]); //# sourceMappingURL=../modules/modal.min.js.map \ No newline at end of file diff --git a/dist/modules/modal.min.js.map b/dist/modules/modal.min.js.map index 85fd18c7d..b5407cf1e 100644 --- a/dist/modules/modal.min.js.map +++ b/dist/modules/modal.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["modules/modal.js"],"names":["angular","templateUrl","provider","template","this","defaults","contentTemplate","container","element","backdrop","keyboard","html","show","$get","forEach","trim","requestAnimationFrame","bodyElement","options","$options","extend","config","ModalFactory","enterAnimateCallback","scope","version","minor","$modal","toggle","$isShown","removeClass","prefixClass","focus","modalElement","unbindBackdropEvents","off","hideOnBackdropClick","backdropElement","preventEventDefault","bindKeyboardEvents","on","$onKeyUp","evt","destroyModalElement","modalScope","$destroy","$element","key","promise","trustAsHtml","$scope","$new","$rootScope","$hide","$$postDigest","$id","id","attr","$show","$sce","hide","css","position","bottom","right","z-index","then","compileData","init","data","destroy","after","isElement","parent","$emit","display","placement","animation","link","clonedElement","prefixEvent","defaultPrevented","addClass","$animate","enter","backdropAnimation","el","safeDigest","bindBackdropEvents","leave","leaveAnimateCallback","unbindKeyboardEvents","which","directive","$root","$$phase","$window","restrict","query","document","querySelectorAll","setTimeout","body","isDefined","falseValueRegExp","$observe","newValue","oldValue","bsModal","$watch","content","modal","trigger","$on"],"mappings":"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","file":"modules/modal.min.js","sourcesContent":["'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"],"sourceRoot":"/source/"} \ No newline at end of file +{"version":3,"sources":["modules/modal.js"],"names":["angular","templateUrl","provider","template","this","defaults","contentTemplate","container","element","backdrop","keyboard","html","show","$get","forEach","trim","requestAnimationFrame","bodyElement","options","$options","extend","config","ModalFactory","enterAnimateCallback","scope","version","minor","$modal","toggle","$isShown","removeClass","prefixClass","focus","modalElement","unbindBackdropEvents","off","hideOnBackdropClick","backdropElement","preventEventDefault","bindKeyboardEvents","on","$onKeyUp","evt","destroyModalElement","modalScope","$destroy","$element","key","promise","trustAsHtml","$scope","$new","$rootScope","$hide","$$postDigest","$id","id","attr","$show","$sce","hide","css","position","bottom","right","z-index","then","compileData","init","data","destroy","after","isElement","parent","$emit","display","placement","animation","link","clonedElement","prefixEvent","defaultPrevented","addClass","$animate","enter","backdropAnimation","el","safeDigest","bindBackdropEvents","leave","leaveAnimateCallback","unbindKeyboardEvents","which","directive","$root","$$phase","$window","restrict","query","document","querySelectorAll","setTimeout","body","isDefined","falseValueRegExp","$observe","newValue","oldValue","bsModal","$watch","content","modal","trigger","$on"],"mappings":"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","file":"modules/modal.min.js","sourcesContent":["'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, $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 helpers\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', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation', 'backdropAnimation', '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"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/dist/modules/modal.tpl.js b/dist/modules/modal.tpl.js index 154b4a090..29c95a551 100644 --- a/dist/modules/modal.tpl.js +++ b/dist/modules/modal.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 516f343cd..5160fd001 100644 --- a/dist/modules/modal.tpl.min.js +++ b/dist/modules/modal.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 c39a35a9c..d47a70002 100644 --- a/dist/modules/navbar.js +++ b/dist/modules/navbar.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 b9d1941a0..d12a75cf5 100644 --- a/dist/modules/navbar.min.js +++ b/dist/modules/navbar.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 5f7462662..2fc1a059b 100644 --- a/dist/modules/parse-options.js +++ b/dist/modules/parse-options.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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.min.js b/dist/modules/parse-options.min.js index f3e03bd45..f9fdfba0b 100644 --- a/dist/modules/parse-options.min.js +++ b/dist/modules/parse-options.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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.js b/dist/modules/popover.js index 7cb23ad79..fb7b055a4 100644 --- a/dist/modules/popover.js +++ b/dist/modules/popover.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 e4a41c975..74cf35d31 100644 --- a/dist/modules/popover.min.js +++ b/dist/modules/popover.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 de0a6ec15..12f579058 100644 --- a/dist/modules/popover.tpl.js +++ b/dist/modules/popover.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 b24ee1ef9..16fef58a3 100644 --- a/dist/modules/popover.tpl.min.js +++ b/dist/modules/popover.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 d9c31f8f2..cd9e99421 100644 --- a/dist/modules/raf.js +++ b/dist/modules/raf.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 770cf34a4..11a8eac16 100644 --- a/dist/modules/raf.min.js +++ b/dist/modules/raf.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 45c450502..6a99cd612 100644 --- a/dist/modules/scrollspy.js +++ b/dist/modules/scrollspy.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 db722bff0..bf70d6ce2 100644 --- a/dist/modules/scrollspy.min.js +++ b/dist/modules/scrollspy.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 55cdf40db..c8e7a40f3 100644 --- a/dist/modules/select.js +++ b/dist/modules/select.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -101,6 +101,9 @@ angular.module('mgcrea.ngStrap.select', [ 'mgcrea.ngStrap.tooltip', 'mgcrea.ngSt $select.activate(index); if (options.multiple) { controller.$setViewValue(scope.$activeIndex.map(function(index) { + if (angular.isUndefined(scope.$matches[index])) { + return null; + } return scope.$matches[index].value; })); } else { @@ -121,6 +124,8 @@ angular.module('mgcrea.ngStrap.select', [ 'mgcrea.ngStrap.tooltip', 'mgcrea.ngSt } } else if (scope.$activeIndex >= scope.$matches.length) { scope.$activeIndex = options.multiple ? [] : 0; + } else if (!controller.$modelValue && !options.multiple) { + scope.$activeIndex = -1; } }; $select.$isVisible = function() { @@ -155,8 +160,10 @@ angular.module('mgcrea.ngStrap.select', [ 'mgcrea.ngStrap.tooltip', 'mgcrea.ngSt }; $select.$onKeyDown = function(evt) { if (!/(9|13|38|40)/.test(evt.keyCode)) return; - evt.preventDefault(); - evt.stopPropagation(); + if (evt.keyCode !== 9) { + evt.preventDefault(); + evt.stopPropagation(); + } if (options.multiple && evt.keyCode === 9) { return $select.hide(); } @@ -168,6 +175,17 @@ angular.module('mgcrea.ngStrap.select', [ 'mgcrea.ngStrap.tooltip', 'mgcrea.ngSt scope.$digest(); } }; + $select.$isIE = function() { + var ua = $window.navigator.userAgent; + return ua.indexOf('MSIE ') > 0 || ua.indexOf('Trident/') > 0 || ua.indexOf('Edge/') > 0; + }; + $select.$selectScrollFix = function(e) { + if ($document[0].activeElement.tagName === 'UL') { + e.preventDefault(); + e.stopImmediatePropagation(); + e.target.focus(); + } + }; var _show = $select.show; $select.show = function() { _show(); @@ -226,6 +244,9 @@ angular.module('mgcrea.ngStrap.select', [ 'mgcrea.ngStrap.tooltip', 'mgcrea.ngSt } var parsedOptions = $parseOptions(attr.bsOptions); var select = $select(element, controller, options); + if (select.$isIE()) { + element[0].addEventListener('blur', select.$selectScrollFix); + } var watchedOptions = parsedOptions.$match[7].replace(/\|.+/, '').trim(); scope.$watchCollection(watchedOptions, function(newValue, oldValue) { parsedOptions.valuesFn(scope, controller).then(function(values) { diff --git a/dist/modules/select.min.js b/dist/modules/select.min.js index 6210bcc42..e0286c862 100644 --- a/dist/modules/select.min.js +++ b/dist/modules/select.min.js @@ -1,9 +1,9 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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.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,l,i){function o(t,n,a){var o={},c=angular.extend({},e,a);o=l(t,c);var u=o.$scope;u.$matches=[],u.$activeIndex=c.multiple?[]:-1,u.$isMultiple=c.multiple,u.$showAllNoneButtons=c.allNoneButtons&&c.multiple,u.$iconCheckmark=c.iconCheckmark,u.$allText=c.allText,u.$noneText=c.noneText,u.$activate=function(e){u.$$postDigest(function(){o.activate(e)})},u.$select=function(e,t){u.$$postDigest(function(){o.select(e)})},u.$isVisible=function(){return o.$isVisible()},u.$isActive=function(e){return o.$isActive(e)},u.$selectAll=function(){for(var e=0;e=u.$matches.length&&(u.$activeIndex=c.multiple?[]:0)},o.$isVisible=function(){return c.minLength&&n?u.$matches.length&&n.$viewValue.length>=c.minLength:u.$matches.length},o.$isActive=function(e){return c.multiple?-1!==u.$activeIndex.indexOf(e):u.$activeIndex===e},o.$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}},o.$onMouseDown=function(e){if(e.preventDefault(),e.stopPropagation(),r){var t=angular.element(e.target);t.triggerHandler('click')}},o.$onKeyDown=function(e){return/(9|13|38|40)/.test(e.keyCode)?(e.preventDefault(),e.stopPropagation(),c.multiple&&9===e.keyCode?o.hide():c.multiple||13!==e.keyCode&&9!==e.keyCode?void(c.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'),s.after(t)}var $=l(n.bsOptions),d=a(t,o,c),m=$.$match[7].replace(/\|.+/,'').trim();e.$watchCollection(m,function(t,n){$.valuesFn(e,o).then(function(e){d.update(e),o.$render()})}),e.$watch(n.ngModel,function(e,t){d.$updateActiveIndex(),o.$render()},!0),o.$render=function(){var e,n;c.multiple&&angular.isArray(o.$modelValue)?(e=o.$modelValue.map(function(e){return n=d.$getIndex(e),angular.isDefined(n)?d.$scope.$matches[n].label:!1}).filter(angular.isDefined),e=e.length>(c.maxLength||i.maxLength)?e.length+' '+(c.maxLengthHtml||i.maxLengthHtml):e.join(', ')):(n=d.$getIndex(o.$modelValue),e=angular.isDefined(n)?d.$scope.$matches[n].label:!1),t.html((e?e:c.placeholder)+(c.caretHtml?c.caretHtml:i.caretHtml))},c.multiple&&(o.$isEmpty=function(e){return!e||0===e.length}),e.$on('$destroy',function(){d&&d.destroy(),c=null,d=null})}}}]); +'use strict';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,l,i){function o(a,o,c){var u={},s=angular.extend({},e,c);u=l(a,s);var d=u.$scope;d.$matches=[],d.$activeIndex=s.multiple?[]:-1,d.$isMultiple=s.multiple,d.$showAllNoneButtons=s.allNoneButtons&&s.multiple,d.$iconCheckmark=s.iconCheckmark,d.$allText=s.allText,d.$noneText=s.noneText,d.$activate=function(e){d.$$postDigest(function(){u.activate(e)})},d.$select=function(e,t){d.$$postDigest(function(){u.select(e)})},d.$isVisible=function(){return u.$isVisible()},d.$isActive=function(e){return u.$isActive(e)},d.$selectAll=function(){for(var e=0;e=d.$matches.length?d.$activeIndex=s.multiple?[]:0:o.$modelValue||s.multiple||(d.$activeIndex=-1)},u.$isVisible=function(){return s.minLength&&o?d.$matches.length&&o.$viewValue.length>=s.minLength:d.$matches.length},u.$isActive=function(e){return s.multiple?-1!==d.$activeIndex.indexOf(e):d.$activeIndex===e},u.$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}},u.$onMouseDown=function(e){if(e.preventDefault(),e.stopPropagation(),r){var t=angular.element(e.target);t.triggerHandler('click')}},u.$onKeyDown=function(e){return/(9|13|38|40)/.test(e.keyCode)?(9!==e.keyCode&&(e.preventDefault(),e.stopPropagation()),s.multiple&&9===e.keyCode?u.hide():s.multiple||13!==e.keyCode&&9!==e.keyCode?void(s.multiple||(38===e.keyCode&&d.$activeIndex>0?d.$activeIndex--:38===e.keyCode&&d.$activeIndex<0?d.$activeIndex=d.$matches.length-1:40===e.keyCode&&d.$activeIndex0||e.indexOf('Trident/')>0||e.indexOf('Edge/')>0},u.$selectScrollFix=function(e){'UL'===n[0].activeElement.tagName&&(e.preventDefault(),e.stopImmediatePropagation(),e.target.focus())};var $=u.show;u.show=function(){$(),s.multiple&&u.$element.addClass('select-multiple'),i(function(){u.$element.on(r?'touchstart':'mousedown',u.$onMouseDown),s.keyboard&&a.on('keydown',u.$onKeyDown)},0,!1)};var m=u.hide;return u.hide=function(){s.multiple||o.$modelValue||(d.$activeIndex=-1),u.$element.off(r?'touchstart':'mousedown',u.$onMouseDown),s.keyboard&&a.off('keydown',u.$onKeyDown),m(!0)},u}var c=(angular.element(t.document.body),/(ip(a|o)d|iphone|android)/gi.test(t.navigator.userAgent)),r='createTouch'in t.document&&c;return o.defaults=e,o}]}).directive('bsSelect',['$window','$parse','$q','$select','$parseOptions',function(e,t,n,a,l){var i=a.defaults;return{restrict:'EAC',require:'ngModel',link:function(e,t,n,o){var c={scope:e,placeholder:i.placeholder};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(e){angular.isDefined(n[e])&&(c[e]=n[e])});var r=/^(false|0|)$/i;angular.forEach(['html','container','allNoneButtons','sort'],function(e){angular.isDefined(n[e])&&r.test(n[e])&&(c[e]=!1)});var u=t.attr('data-multiple');if(angular.isDefined(u)&&(c.multiple=r.test(u)?!1:u),'select'===t[0].nodeName.toLowerCase()){var s=t;s.css('display','none'),t=angular.element(''),s.after(t)}var d=l(n.bsOptions),$=a(t,o,c);$.$isIE()&&t[0].addEventListener('blur',$.$selectScrollFix);var m=d.$match[7].replace(/\|.+/,'').trim();e.$watchCollection(m,function(t,n){d.valuesFn(e,o).then(function(e){$.update(e),o.$render()})}),e.$watch(n.ngModel,function(e,t){$.$updateActiveIndex(),o.$render()},!0),o.$render=function(){var e,n;c.multiple&&angular.isArray(o.$modelValue)?(e=o.$modelValue.map(function(e){return n=$.$getIndex(e),angular.isDefined(n)?$.$scope.$matches[n].label:!1}).filter(angular.isDefined),e=e.length>(c.maxLength||i.maxLength)?e.length+' '+(c.maxLengthHtml||i.maxLengthHtml):e.join(', ')):(n=$.$getIndex(o.$modelValue),e=angular.isDefined(n)?$.$scope.$matches[n].label:!1),t.html((e?e:c.placeholder)+(c.caretHtml?c.caretHtml:i.caretHtml))},c.multiple&&(o.$isEmpty=function(e){return!e||0===e.length}),e.$on('$destroy',function(){$&&$.destroy(),c=null,$=null})}}}]); //# sourceMappingURL=../modules/select.min.js.map \ No newline at end of file diff --git a/dist/modules/select.min.js.map b/dist/modules/select.min.js.map index 8cd795304..d1a459336 100644 --- a/dist/modules/select.min.js.map +++ b/dist/modules/select.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["modules/select.js"],"names":["angular","trigger","provider","container","this","defaults","keyboard","html","delay","multiple","allNoneButtons","sort","caretHtml","placeholder","allText","noneText","maxLength","maxLengthHtml","iconCheckmark","bodyEl","isNative","isTouch","SelectFactory","$select","$tooltip","element","options","scope","$activeIndex","config","$isMultiple","$showAllNoneButtons","$allText","$iconCheckmark","activate","index","$$postDigest","select","evt","$isActive","$isVisible","i","$selectNone","$matches","length","matches","$updateActiveIndex","b","a","controller","value","hide","$setViewValue","map","$emit","prefixEvent","$modelValue","$getIndex","minLength","$viewValue","l","indexOf","preventDefault","stopPropagation","targetEl","$onMouseDown","keyCode","$digest","_show","isUndefined","show","$element","addClass","$timeout","_hide","on","$onKeyDown","off","directive","$scope","$window","document","link","require","restrict","forEach","attr","falseValueRegExp","isDefined","dataMultiple","key","nodeName","toLowerCase","inputEl","after","test","watchedOptions","$watchCollection","parsedOptions","valuesFn","update","$parseOptions","bsOptions","ngModel","$match","newValue","oldValue","$render","values","selected","isArray","join","label","$isEmpty","$on","destroy"],"mappings":"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","file":"modules/select.min.js","sourcesContent":["'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"],"sourceRoot":"/source/"} \ No newline at end of file +{"version":3,"sources":["modules/select.js"],"names":["angular","trigger","provider","container","this","defaults","keyboard","html","delay","multiple","allNoneButtons","sort","caretHtml","placeholder","allText","noneText","maxLength","maxLengthHtml","iconCheckmark","bodyEl","isNative","isTouch","SelectFactory","$select","$tooltip","element","options","scope","$activeIndex","config","$isMultiple","$showAllNoneButtons","$allText","$iconCheckmark","activate","index","$$postDigest","select","evt","$isActive","$isVisible","i","$selectNone","$matches","length","matches","$updateActiveIndex","b","a","controller","value","$apply","$setViewValue","hide","prefixEvent","$modelValue","$emit","map","$getIndex","minLength","$viewValue","l","indexOf","preventDefault","stopPropagation","targetEl","$onMouseDown","keyCode","$onKeyDown","test","$digest","isUndefined","$selectScrollFix","$isIE","stopImmediatePropagation","target","focus","ua","_show","show","activeElement","tagName","e","$element","addClass","$timeout","_hide","on","off","directive","$scope","$window","document","link","require","restrict","forEach","attr","falseValueRegExp","isDefined","dataMultiple","key","nodeName","toLowerCase","inputEl","after","css","addEventListener","watchedOptions","parsedOptions","valuesFn","update","values","ngModel","$match","newValue","oldValue","$render","selected","isArray","join","label","$isEmpty","$on","destroy"],"mappings":"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","file":"modules/select.min.js","sourcesContent":["'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 if (angular.isUndefined(scope.$matches[index])) {\n return null;\n }\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 } else if(!controller.$modelValue && !options.multiple) {\n scope.$activeIndex = -1;\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 // Let tab propagate\n if (evt.keyCode !== 9) {\n evt.preventDefault();\n evt.stopPropagation();\n }\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 $select.$isIE = function() {\n var ua = $window.navigator.userAgent;\n return ua.indexOf('MSIE ') > 0 || ua.indexOf('Trident/') > 0 || ua.indexOf('Edge/') > 0;\n };\n\n $select.$selectScrollFix = function(e) {\n if ($document[0].activeElement.tagName === 'UL') {\n e.preventDefault();\n e.stopImmediatePropagation();\n e.target.focus();\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 if (select.$isIE()) {\n element[0].addEventListener('blur', select.$selectScrollFix);\n }\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"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/dist/modules/select.tpl.js b/dist/modules/select.tpl.js index a2df3a17f..92b053849 100644 --- a/dist/modules/select.tpl.js +++ b/dist/modules/select.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 34108a13d..fbf53bde6 100644 --- a/dist/modules/select.tpl.min.js +++ b/dist/modules/select.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 5031b931f..a57e99dfc 100644 --- a/dist/modules/tab.js +++ b/dist/modules/tab.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 b184a3dac..fb590a2b8 100644 --- a/dist/modules/tab.min.js +++ b/dist/modules/tab.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 34e0f02d4..85f3abfe3 100644 --- a/dist/modules/tab.tpl.js +++ b/dist/modules/tab.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 29df73802..86479db76 100644 --- a/dist/modules/tab.tpl.min.js +++ b/dist/modules/tab.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 afd4940d8..46e3d4748 100644 --- a/dist/modules/timepicker.js +++ b/dist/modules/timepicker.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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.min.js b/dist/modules/timepicker.min.js index 64f193ed4..502fbf51e 100644 --- a/dist/modules/timepicker.min.js +++ b/dist/modules/timepicker.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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.js b/dist/modules/timepicker.tpl.js index c52de12b4..f0d4920ed 100644 --- a/dist/modules/timepicker.tpl.js +++ b/dist/modules/timepicker.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 d21aaec1a..a80a56900 100644 --- a/dist/modules/timepicker.tpl.min.js +++ b/dist/modules/timepicker.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 f3f9757a7..86df4aa8b 100644 --- a/dist/modules/tooltip.js +++ b/dist/modules/tooltip.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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.min.js b/dist/modules/tooltip.min.js index 98fb9ff32..98a2640b8 100644 --- a/dist/modules/tooltip.min.js +++ b/dist/modules/tooltip.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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.js b/dist/modules/tooltip.tpl.js index f102ef529..42c6da53b 100644 --- a/dist/modules/tooltip.tpl.js +++ b/dist/modules/tooltip.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 543253042..d6f447c0f 100644 --- a/dist/modules/tooltip.tpl.min.js +++ b/dist/modules/tooltip.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 3e220c866..0a46699ac 100644 --- a/dist/modules/typeahead.js +++ b/dist/modules/typeahead.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (https://github.com/mgcrea) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -155,7 +155,7 @@ angular.module('mgcrea.ngStrap.typeahead', [ 'mgcrea.ngStrap.tooltip', 'mgcrea.n angular.forEach([ 'html', 'container', 'trimValue' ], function(key) { if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false; }); - element.attr('autocomplete', 'false'); + if (!element.attr('autocomplete')) element.attr('autocomplete', 'off'); var filter = options.filter || defaults.filter; var limit = options.limit || defaults.limit; var comparator = options.comparator || defaults.comparator; diff --git a/dist/modules/typeahead.min.js b/dist/modules/typeahead.min.js index 852b30f0d..4deff1e12 100644 --- a/dist/modules/typeahead.min.js +++ b/dist/modules/typeahead.min.js @@ -1,9 +1,9 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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:'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})}}}]); +'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')||t.attr('autocomplete','off');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 c134956d3..e0139254f 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","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 +{"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 if (!element.attr('autocomplete')) element.attr('autocomplete', 'off');\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 161aadc0a..869bbe10f 100644 --- a/dist/modules/typeahead.tpl.js +++ b/dist/modules/typeahead.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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 01c04f814..521f43610 100644 --- a/dist/modules/typeahead.tpl.min.js +++ b/dist/modules/typeahead.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.3.1 - 2015-07-19 + * @version v2.3.2 - 2015-09-15 * @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/package.json b/package.json index 69349fcaf..4da2bfd1e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "angular-strap", "description": "AngularStrap - AngularJS directives for Bootstrap", - "version": "2.3.1", + "version": "2.3.2", "keywords": [ "angular", "bootstrap"