diff --git a/bower.json b/bower.json index d5ee28752..6c6f7d6c1 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "angular-strap", "description": "AngularStrap - AngularJS directives for Bootstrap", - "version": "2.1.4", + "version": "2.1.6", "keywords": [ "angular", "bootstrap" diff --git a/dist/angular-strap.js b/dist/angular-strap.js index 28e842395..5971d8832 100644 --- a/dist/angular-strap.js +++ b/dist/angular-strap.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -650,7 +650,8 @@ angular.module('mgcrea.ngStrap.collapse', []) animation: 'am-collapse', disallowToggle: false, activeClass: 'in', - startCollapsed: false + startCollapsed: false, + allowMultiple: false }; var controller = this.controller = function($scope, $element, $attrs) { @@ -658,7 +659,7 @@ angular.module('mgcrea.ngStrap.collapse', []) // Attributes options self.$options = angular.copy(defaults); - angular.forEach(['animation', 'disallowToggle', 'activeClass', 'startCollapsed'], function (key) { + angular.forEach(['animation', 'disallowToggle', 'activeClass', 'startCollapsed', 'allowMultiple'], function (key) { if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key]; }); @@ -681,36 +682,86 @@ angular.module('mgcrea.ngStrap.collapse', []) }; self.$unregisterTarget = function(element) { var index = self.$targets.indexOf(element); - var activeIndex = self.$targets.$active; // remove element from $targets array self.$targets.splice(index, 1); - if (index < activeIndex) { - // we removed a target before the active target, so we need to - // decrement the active target index - activeIndex--; - } - else if (index === activeIndex && activeIndex === self.$targets.length) { - // we remove the active target and it was the one at the end, - // so select the previous one - activeIndex--; + if (self.$options.allowMultiple) { + // remove target index from $active array values + deactivateItem(element); } - self.$setActive(activeIndex); + + // fix active item indexes + fixActiveItemIndexes(index); + + self.$viewChangeListeners.forEach(function(fn) { + fn(); + }); }; - self.$targets.$active = !self.$options.startCollapsed ? 0 : -1; + // use array to store all the currently open panels + self.$targets.$active = !self.$options.startCollapsed ? [0] : []; self.$setActive = $scope.$setActive = function(value) { - if(!self.$options.disallowToggle) { - self.$targets.$active = self.$targets.$active === value ? -1 : value; + if(angular.isArray(value)) { + self.$targets.$active = angular.copy(value); + } + else if(!self.$options.disallowToggle) { + // toogle element active status + isActive(value) ? deactivateItem(value) : activateItem(value); } else { - self.$targets.$active = value; + 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) { + // item with index was removed, so we + // need to adjust other items index values + var activeIndexes = self.$targets.$active; + for(var i = 0; i < activeIndexes.length; i++) { + if (index < activeIndexes[i]) { + activeIndexes[i] = activeIndexes[i] - 1; + } + + // the last item is active, so we need to + // adjust its index + if (activeIndexes[i] === self.$targets.length) { + activeIndexes[i] = self.$targets.length - 1; + } + } + } + + 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) { + // remove current selected item + self.$targets.$active.splice(0, 1); + } + + if (self.$targets.$active.indexOf(value) === -1) { + self.$targets.$active.push(value); + } + } + }; this.$get = function() { @@ -738,14 +789,30 @@ angular.module('mgcrea.ngStrap.collapse', []) // Update the modelValue following bsCollapseCtrl.$viewChangeListeners.push(function() { - ngModelCtrl.$setViewValue(bsCollapseCtrl.$targets.$active); + ngModelCtrl.$setViewValue(bsCollapseCtrl.$activeIndexes()); }); // modelValue -> $formatters -> viewValue ngModelCtrl.$formatters.push(function(modelValue) { // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue); - if (bsCollapseCtrl.$targets.$active !== modelValue * 1) { - bsCollapseCtrl.$setActive(modelValue * 1); + if (angular.isArray(modelValue)) { + // model value is an array, so just replace + // the active items directly + bsCollapseCtrl.$setActive(modelValue); + } + else { + var activeIndexes = bsCollapseCtrl.$activeIndexes(); + + if (angular.isArray(activeIndexes)) { + // we have an array of selected indexes + if (activeIndexes.indexOf(modelValue * 1) === -1) { + // item with modelValue index is not active + bsCollapseCtrl.$setActive(modelValue * 1); + } + } + else if (activeIndexes !== modelValue * 1) { + bsCollapseCtrl.$setActive(modelValue * 1); + } } return modelValue; }); @@ -816,8 +883,18 @@ angular.module('mgcrea.ngStrap.collapse', []) function render() { var index = bsCollapseCtrl.$targets.indexOf(element); - var active = bsCollapseCtrl.$targets.$active; - $animate[index === active ? 'addClass' : 'removeClass'](element, bsCollapseCtrl.$options.activeClass); + 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); } bsCollapseCtrl.$viewChangeListeners.push(function() { @@ -976,7 +1053,7 @@ angular.module('mgcrea.ngStrap.datepicker', [ var steps = $picker.steps; // set targetDate to first day of month to avoid problems with // date values rollover. This assumes the viewDate does not - // depend on the day of the month + // depend on the day of the month var targetDate = new Date(Date.UTC(viewDate.year + ((steps.year || 0) * value), viewDate.month + ((steps.month || 0) * value), 1)); angular.extend(viewDate, {year: targetDate.getUTCFullYear(), month: targetDate.getUTCMonth(), date: targetDate.getUTCDate()}); $datepicker.$build(); @@ -1051,9 +1128,11 @@ angular.module('mgcrea.ngStrap.datepicker', [ var _show = $datepicker.show; $datepicker.show = function() { _show(); - // use timeout to hookup the events to prevent - // event bubbling from being processed imediately. + // use timeout to hookup the events to prevent + // event bubbling from being processed imediately. $timeout(function() { + // if $datepicker is no longer showing, don't setup events + if(!$datepicker.$isShown) return; $datepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown); if(options.keyboard) { element.on('keydown', $datepicker.$onKeyDown); @@ -1094,7 +1173,7 @@ angular.module('mgcrea.ngStrap.datepicker', [ // Directive options var options = {scope: scope, controller: controller}; - angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'dateType', 'dateFormat', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled'], function(key) { + angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'dateType', 'dateFormat', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled', 'id'], function(key) { if(angular.isDefined(attr[key])) options[key] = attr[key]; }); @@ -1116,7 +1195,7 @@ angular.module('mgcrea.ngStrap.datepicker', [ var formatDate = function(date, format) { return $dateFormatter.formatDate(date, format, lang); }; - + var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat}); // Observe attributes for changes @@ -1173,15 +1252,15 @@ angular.module('mgcrea.ngStrap.datepicker', [ if(!viewValue) { controller.$setValidity('date', true); // BREAKING CHANGE: - // return null (not undefined) when input value is empty, so angularjs 1.3 + // return null (not undefined) when input value is empty, so angularjs 1.3 // ngModelController can go ahead and run validators, like ngRequired return null; } var parsedDate = dateParser.parse(viewValue, controller.$dateValue); if(!parsedDate || isNaN(parsedDate.getTime())) { controller.$setValidity('date', false); - // return undefined, causes ngModelController to - // invalidate model value + // return undefined, causes ngModelController to + // invalidate model value return; } else { validateAgainstMinMaxDate(parsedDate); @@ -1522,8 +1601,8 @@ angular.module('mgcrea.ngStrap.dropdown', ['mgcrea.ngStrap.tooltip']) var show = $dropdown.show; $dropdown.show = function() { show(); - // use timeout to hookup the events to prevent - // event bubbling from being processed imediately. + // use timeout to hookup the events to prevent + // event bubbling from being processed imediately. $timeout(function() { options.keyboard && $dropdown.$element.on('keydown', $dropdown.$onKeyDown); bodyEl.on('click', onBodyClick); @@ -1572,7 +1651,7 @@ angular.module('mgcrea.ngStrap.dropdown', ['mgcrea.ngStrap.tooltip']) // Directive options var options = {scope: scope}; - angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template'], function(key) { + angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'id'], function(key) { if(angular.isDefined(attr[key])) options[key] = attr[key]; }); @@ -2290,6 +2369,11 @@ angular.module('mgcrea.ngStrap.modal', ['mgcrea.ngStrap.helpers.dimensions']) options.container = 'body'; } + // store $id to identify the triggering element in events + // give priority to options.id, otherwise, try to use + // element id if defined + $modal.$id = options.id || options.element && options.element.attr('id') || ''; + // Support scope as string options forEach(['title', 'content'], function(key) { if(options[key]) scope[key] = $sce.trustAsHtml(options[key]); @@ -2548,7 +2632,7 @@ angular.module('mgcrea.ngStrap.modal', ['mgcrea.ngStrap.helpers.dimensions']) // Directive options var options = {scope: scope, element: element, show: false}; - angular.forEach(['template', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation'], function(key) { + angular.forEach(['template', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation', 'id'], function(key) { if(angular.isDefined(attr[key])) options[key] = attr[key]; }); @@ -2708,7 +2792,7 @@ angular.module('mgcrea.ngStrap.popover', ['mgcrea.ngStrap.tooltip']) // Directive options var options = {scope: scope}; - angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'customClass', 'autoClose'], function(key) { + angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'customClass', 'autoClose', 'id'], function(key) { if(angular.isDefined(attr[key])) options[key] = attr[key]; }); @@ -2756,397 +2840,143 @@ angular.module('mgcrea.ngStrap.popover', ['mgcrea.ngStrap.tooltip']) }]); -// Source: scrollspy.js -angular.module('mgcrea.ngStrap.scrollspy', ['mgcrea.ngStrap.helpers.debounce', 'mgcrea.ngStrap.helpers.dimensions']) - - .provider('$scrollspy', function() { +// Source: select.js +angular.module('mgcrea.ngStrap.select', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions']) - // Pool of registered spies - var spies = this.$$spies = {}; + .provider('$select', function() { var defaults = this.defaults = { - debounce: 150, - throttle: 100, - offset: 100 + animation: 'am-fade', + prefixClass: 'select', + prefixEvent: '$select', + placement: 'bottom-left', + template: '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", "dimensions", "debounce", "throttle", function($window, $document, $rootScope, dimensions, debounce, throttle) { + this.$get = ["$window", "$document", "$rootScope", "$tooltip", "$timeout", function($window, $document, $rootScope, $tooltip, $timeout) { - var windowEl = angular.element($window); - var docEl = angular.element($document.prop('documentElement')); var bodyEl = angular.element($window.document.body); + var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent); + var isTouch = ('createTouch' in $window.document) && isNative; - // Helper functions - - function nodeName(element, name) { - return element[0].nodeName && element[0].nodeName.toLowerCase() === name.toLowerCase(); - } + function SelectFactory(element, controller, config) { - function ScrollSpyFactory(config) { + var $select = {}; // Common vars var options = angular.extend({}, defaults, config); - if(!options.element) options.element = bodyEl; - var isWindowSpy = nodeName(options.element, 'body'); - var scrollEl = isWindowSpy ? windowEl : options.element; - var scrollId = isWindowSpy ? 'window' : options.id; - - // Use existing spy - if(spies[scrollId]) { - spies[scrollId].$$count++; - return spies[scrollId]; - } - - var $scrollspy = {}; - - // Private vars - var unbindViewContentLoaded, unbindIncludeContentLoaded; - var trackedElements = $scrollspy.$trackedElements = []; - var sortedElements = []; - var activeTarget; - var debouncedCheckPosition; - var throttledCheckPosition; - var debouncedCheckOffsets; - var viewportHeight; - var scrollTop; - - $scrollspy.init = function() { - // Setup internal ref counter - this.$$count = 1; + $select = $tooltip(element, options); + var scope = $select.$scope; - // Bind events - debouncedCheckPosition = debounce(this.checkPosition, options.debounce); - throttledCheckPosition = throttle(this.checkPosition, options.throttle); - scrollEl.on('click', this.checkPositionWithEventLoop); - windowEl.on('resize', debouncedCheckPosition); - scrollEl.on('scroll', throttledCheckPosition); + scope.$matches = []; + scope.$activeIndex = 0; + scope.$isMultiple = options.multiple; + scope.$showAllNoneButtons = options.allNoneButtons && options.multiple; + scope.$iconCheckmark = options.iconCheckmark; + scope.$allText = options.allText; + scope.$noneText = options.noneText; - debouncedCheckOffsets = debounce(this.checkOffsets, options.debounce); - unbindViewContentLoaded = $rootScope.$on('$viewContentLoaded', debouncedCheckOffsets); - unbindIncludeContentLoaded = $rootScope.$on('$includeContentLoaded', debouncedCheckOffsets); - debouncedCheckOffsets(); + scope.$activate = function(index) { + scope.$$postDigest(function() { + $select.activate(index); + }); + }; - // Register spy for reuse - if(scrollId) { - spies[scrollId] = $scrollspy; - } + scope.$select = function(index, evt) { + scope.$$postDigest(function() { + $select.select(index); + }); + }; + scope.$isVisible = function() { + return $select.$isVisible(); }; - $scrollspy.destroy = function() { + scope.$isActive = function(index) { + return $select.$isActive(index); + }; - // Check internal ref counter - this.$$count--; - if(this.$$count > 0) { - return; + scope.$selectAll = function () { + for (var i = 0; i < scope.$matches.length; i++) { + if (!scope.$isActive(i)) { + scope.$select(i); + } } + }; - // Unbind events - scrollEl.off('click', this.checkPositionWithEventLoop); - windowEl.off('resize', debouncedCheckPosition); - scrollEl.off('scroll', throttledCheckPosition); - unbindViewContentLoaded(); - unbindIncludeContentLoaded(); - if (scrollId) { - delete spies[scrollId]; + scope.$selectNone = function () { + for (var i = 0; i < scope.$matches.length; i++) { + if (scope.$isActive(i)) { + scope.$select(i); + } } }; - $scrollspy.checkPosition = function() { - - // Not ready yet - if(!sortedElements.length) return; - - // Calculate the scroll position - scrollTop = (isWindowSpy ? $window.pageYOffset : scrollEl.prop('scrollTop')) || 0; - - // Calculate the viewport height for use by the components - viewportHeight = Math.max($window.innerHeight, docEl.prop('clientHeight')); + // Public methods - // Activate first element if scroll is smaller - if(scrollTop < sortedElements[0].offsetTop && activeTarget !== sortedElements[0].target) { - return $scrollspy.$activateElement(sortedElements[0]); - } + $select.update = function(matches) { + scope.$matches = matches; + $select.$updateActiveIndex(); + }; - // Activate proper element - for (var i = sortedElements.length; i--;) { - if(angular.isUndefined(sortedElements[i].offsetTop) || sortedElements[i].offsetTop === null) continue; - if(activeTarget === sortedElements[i].target) continue; - if(scrollTop < sortedElements[i].offsetTop) continue; - if(sortedElements[i + 1] && scrollTop > sortedElements[i + 1].offsetTop) continue; - return $scrollspy.$activateElement(sortedElements[i]); + $select.activate = function(index) { + if(options.multiple) { + scope.$activeIndex.sort(); + $select.$isActive(index) ? scope.$activeIndex.splice(scope.$activeIndex.indexOf(index), 1) : scope.$activeIndex.push(index); + if(options.sort) scope.$activeIndex.sort(); + } else { + scope.$activeIndex = index; } - + return scope.$activeIndex; }; - $scrollspy.checkPositionWithEventLoop = function() { - // IE 9 throws an error if we use 'this' instead of '$scrollspy' - // in this setTimeout call - setTimeout($scrollspy.checkPosition, 1); + $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); + // Hide if single select + $select.hide(); + } + }); + // Emit event + scope.$emit(options.prefixEvent + '.select', value, index, $select); }; // Protected methods - $scrollspy.$activateElement = function(element) { - if(activeTarget) { - var activeElement = $scrollspy.$getTrackedElement(activeTarget); - if(activeElement) { - activeElement.source.removeClass('active'); - if(nodeName(activeElement.source, 'li') && nodeName(activeElement.source.parent().parent(), 'li')) { - activeElement.source.parent().parent().removeClass('active'); - } + $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); } - } - activeTarget = element.target; - element.source.addClass('active'); - if(nodeName(element.source, 'li') && nodeName(element.source.parent().parent(), 'li')) { - element.source.parent().parent().addClass('active'); - } - }; - - $scrollspy.$getTrackedElement = function(target) { - return trackedElements.filter(function(obj) { - return obj.target === target; - })[0]; - }; - - // Track offsets behavior - - $scrollspy.checkOffsets = function() { - - angular.forEach(trackedElements, function(trackedElement) { - var targetElement = document.querySelector(trackedElement.target); - trackedElement.offsetTop = targetElement ? dimensions.offset(targetElement).top : null; - if(options.offset && trackedElement.offsetTop !== null) trackedElement.offsetTop -= options.offset * 1; - }); - - sortedElements = trackedElements - .filter(function(el) { - return el.offsetTop !== null; - }) - .sort(function(a, b) { - return a.offsetTop - b.offsetTop; - }); - - debouncedCheckPosition(); - - }; - - $scrollspy.trackElement = function(target, source) { - trackedElements.push({target: target, source: source}); - }; - - $scrollspy.untrackElement = function(target, source) { - var toDelete; - for (var i = trackedElements.length; i--;) { - if(trackedElements[i].target === target && trackedElements[i].source === source) { - toDelete = i; - break; - } - } - trackedElements = trackedElements.splice(toDelete, 1); - }; - - $scrollspy.activate = function(i) { - trackedElements[i].addClass('active'); - }; - - // Initialize plugin - - $scrollspy.init(); - return $scrollspy; - - } - - return ScrollSpyFactory; - - }]; - - }) - - .directive('bsScrollspy', ["$rootScope", "debounce", "dimensions", "$scrollspy", function($rootScope, debounce, dimensions, $scrollspy) { - - return { - restrict: 'EAC', - link: function postLink(scope, element, attr) { - - var options = {scope: scope}; - angular.forEach(['offset', 'target'], function(key) { - if(angular.isDefined(attr[key])) options[key] = attr[key]; - }); - - var scrollspy = $scrollspy(options); - scrollspy.trackElement(options.target, element); - - scope.$on('$destroy', function() { - if (scrollspy) { - scrollspy.untrackElement(options.target, element); - scrollspy.destroy(); - } - options = null; - scrollspy = null; - }); - - } - }; - - }]) - - - .directive('bsScrollspyList', ["$rootScope", "debounce", "dimensions", "$scrollspy", function($rootScope, debounce, dimensions, $scrollspy) { - - return { - restrict: 'A', - compile: function postLink(element, attr) { - var children = element[0].querySelectorAll('li > a[href]'); - angular.forEach(children, function(child) { - var childEl = angular.element(child); - childEl.parent().attr('bs-scrollspy', '').attr('data-target', childEl.attr('href')); - }); - } - - }; - - }]); - -// Source: select.js -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', - template: '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)/ig.test($window.navigator.userAgent); - var isTouch = ('createTouch' in $window.document) && isNative; - - function SelectFactory(element, controller, config) { - - var $select = {}; - - // Common vars - var options = angular.extend({}, defaults, config); - - $select = $tooltip(element, options); - var scope = $select.$scope; - - scope.$matches = []; - scope.$activeIndex = 0; - 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); - } - } - }; - - // Public methods - - $select.update = function(matches) { - scope.$matches = matches; - $select.$updateActiveIndex(); - }; - - $select.activate = function(index) { - if(options.multiple) { - scope.$activeIndex.sort(); - $select.$isActive(index) ? scope.$activeIndex.splice(scope.$activeIndex.indexOf(index), 1) : scope.$activeIndex.push(index); - if(options.sort) scope.$activeIndex.sort(); - } else { - scope.$activeIndex = index; - } - 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); - // Hide if single select - $select.hide(); - } - }); - // Emit event - scope.$emit(options.prefixEvent + '.select', value, index); - }; - - // Protected methods - - $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(scope.$activeIndex >= scope.$matches.length) { + scope.$activeIndex = options.multiple ? [] : 0; } }; @@ -3253,7 +3083,7 @@ angular.module('mgcrea.ngStrap.select', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStr // Directive options var options = {scope: scope, placeholder: defaults.placeholder}; - angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'placeholder', 'multiple', 'allNoneButtons', 'maxLength', 'maxLengthHtml', 'allText', 'noneText'], function(key) { + angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'placeholder', 'multiple', 'allNoneButtons', 'maxLength', 'maxLengthHtml', 'allText', 'noneText', 'iconCheckmark', 'autoClose', 'id'], function(key) { if(angular.isDefined(attr[key])) options[key] = attr[key]; }); @@ -3507,378 +3337,1125 @@ angular.module('mgcrea.ngStrap.tab', []) }]); -// Source: tooltip.js -angular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions']) +// Source: scrollspy.js +angular.module('mgcrea.ngStrap.scrollspy', ['mgcrea.ngStrap.helpers.debounce', 'mgcrea.ngStrap.helpers.dimensions']) - .provider('$tooltip', function() { + .provider('$scrollspy', function() { - var defaults = this.defaults = { - animation: 'am-fade', - customClass: '', - prefixClass: 'tooltip', - prefixEvent: 'tooltip', - container: false, - target: false, - placement: 'top', - template: 'tooltip/tooltip.tpl.html', - contentTemplate: false, - trigger: 'hover focus', - keyboard: false, - html: false, - show: false, - title: '', - type: '', - delay: 0, - autoClose: false, - bsEnabled: true + // Pool of registered spies + var spies = this.$$spies = {}; + + var defaults = this.defaults = { + debounce: 150, + throttle: 100, + offset: 100 }; - this.$get = ["$window", "$rootScope", "$compile", "$q", "$templateCache", "$http", "$animate", "$sce", "dimensions", "$$rAF", "$timeout", function($window, $rootScope, $compile, $q, $templateCache, $http, $animate, $sce, dimensions, $$rAF, $timeout) { + this.$get = ["$window", "$document", "$rootScope", "dimensions", "debounce", "throttle", function($window, $document, $rootScope, dimensions, debounce, throttle) { - var trim = String.prototype.trim; - var isTouch = 'createTouch' in $window.document; - var htmlReplaceRegExp = /ng-bind="/ig; - var $body = angular.element($window.document); + var windowEl = angular.element($window); + var docEl = angular.element($document.prop('documentElement')); + var bodyEl = angular.element($window.document.body); - function TooltipFactory(element, config) { + // Helper functions - var $tooltip = {}; + function nodeName(element, name) { + return element[0].nodeName && element[0].nodeName.toLowerCase() === name.toLowerCase(); + } + + function ScrollSpyFactory(config) { // Common vars - var nodeName = element[0].nodeName.toLowerCase(); - var options = $tooltip.$options = angular.extend({}, defaults, config); - $tooltip.$promise = fetchTemplate(options.template); - var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new(); - if(options.delay && angular.isString(options.delay)) { - var split = options.delay.split(',').map(parseFloat); - options.delay = split.length > 1 ? {show: split[0], hide: split[1]} : split[0]; - } + var options = angular.extend({}, defaults, config); + if(!options.element) options.element = bodyEl; + var isWindowSpy = nodeName(options.element, 'body'); + var scrollEl = isWindowSpy ? windowEl : options.element; + var scrollId = isWindowSpy ? 'window' : options.id; - // Support scope as string options - if(options.title) { - scope.title = $sce.trustAsHtml(options.title); + // Use existing spy + if(spies[scrollId]) { + spies[scrollId].$$count++; + return spies[scrollId]; } - // Provide scope helpers - scope.$setEnabled = function(isEnabled) { - scope.$$postDigest(function() { - $tooltip.setEnabled(isEnabled); - }); - }; - scope.$hide = function() { - scope.$$postDigest(function() { - $tooltip.hide(); - }); - }; - scope.$show = function() { - scope.$$postDigest(function() { - $tooltip.show(); - }); - }; - scope.$toggle = function() { - scope.$$postDigest(function() { - $tooltip.toggle(); - }); - }; - // Publish isShown as a protected var on scope - $tooltip.$isShown = scope.$isShown = false; + var $scrollspy = {}; // Private vars - var timeout, hoverState; - - // Support contentTemplate option - if(options.contentTemplate) { - $tooltip.$promise = $tooltip.$promise.then(function(template) { - var templateEl = angular.element(template); - return fetchTemplate(options.contentTemplate) - .then(function(contentTemplate) { - var contentEl = findElement('[ng-bind="content"]', templateEl[0]); - if(!contentEl.length) contentEl = findElement('[ng-bind="title"]', templateEl[0]); - contentEl.removeAttr('ng-bind').html(contentTemplate); - return templateEl[0].outerHTML; - }); - }); - } + var unbindViewContentLoaded, unbindIncludeContentLoaded; + var trackedElements = $scrollspy.$trackedElements = []; + var sortedElements = []; + var activeTarget; + var debouncedCheckPosition; + var throttledCheckPosition; + var debouncedCheckOffsets; + var viewportHeight; + var scrollTop; - // Fetch, compile then initialize tooltip - var tipLinker, tipElement, tipTemplate, tipContainer, tipScope; - $tooltip.$promise.then(function(template) { - if(angular.isObject(template)) template = template.data; - if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html="'); - template = trim.apply(template); - tipTemplate = template; - tipLinker = $compile(template); - $tooltip.init(); - }); + $scrollspy.init = function() { - $tooltip.init = function() { + // Setup internal ref counter + this.$$count = 1; - // Options: delay - if (options.delay && angular.isNumber(options.delay)) { - options.delay = { - show: options.delay, - hide: options.delay - }; - } + // Bind events + debouncedCheckPosition = debounce(this.checkPosition, options.debounce); + throttledCheckPosition = throttle(this.checkPosition, options.throttle); + scrollEl.on('click', this.checkPositionWithEventLoop); + windowEl.on('resize', debouncedCheckPosition); + scrollEl.on('scroll', throttledCheckPosition); - // Replace trigger on touch devices ? - // if(isTouch && options.trigger === defaults.trigger) { - // options.trigger.replace(/hover/g, 'click'); - // } + debouncedCheckOffsets = debounce(this.checkOffsets, options.debounce); + unbindViewContentLoaded = $rootScope.$on('$viewContentLoaded', debouncedCheckOffsets); + unbindIncludeContentLoaded = $rootScope.$on('$includeContentLoaded', debouncedCheckOffsets); + debouncedCheckOffsets(); - // Options : container - if(options.container === 'self') { - tipContainer = element; - } else if(angular.isElement(options.container)) { - tipContainer = options.container; - } else if(options.container) { - tipContainer = findElement(options.container); + // Register spy for reuse + if(scrollId) { + spies[scrollId] = $scrollspy; } - // Options: trigger - bindTriggerEvents(); + }; - // Options: target - if(options.target) { - options.target = angular.isElement(options.target) ? options.target : findElement(options.target); - } + $scrollspy.destroy = function() { - // Options: show - if(options.show) { - scope.$$postDigest(function() { - options.trigger === 'focus' ? element[0].focus() : $tooltip.show(); - }); + // Check internal ref counter + this.$$count--; + if(this.$$count > 0) { + return; } + // Unbind events + scrollEl.off('click', this.checkPositionWithEventLoop); + windowEl.off('resize', debouncedCheckPosition); + scrollEl.off('scroll', throttledCheckPosition); + unbindViewContentLoaded(); + unbindIncludeContentLoaded(); + if (scrollId) { + delete spies[scrollId]; + } }; - $tooltip.destroy = function() { - - // Unbind events - unbindTriggerEvents(); + $scrollspy.checkPosition = function() { - // Remove element - destroyTipElement(); + // Not ready yet + if(!sortedElements.length) return; - // Destroy scope - scope.$destroy(); + // Calculate the scroll position + scrollTop = (isWindowSpy ? $window.pageYOffset : scrollEl.prop('scrollTop')) || 0; - }; + // Calculate the viewport height for use by the components + viewportHeight = Math.max($window.innerHeight, docEl.prop('clientHeight')); - $tooltip.enter = function() { + // Activate first element if scroll is smaller + if(scrollTop < sortedElements[0].offsetTop && activeTarget !== sortedElements[0].target) { + return $scrollspy.$activateElement(sortedElements[0]); + } - clearTimeout(timeout); - hoverState = 'in'; - if (!options.delay || !options.delay.show) { - return $tooltip.show(); + // Activate proper element + for (var i = sortedElements.length; i--;) { + if(angular.isUndefined(sortedElements[i].offsetTop) || sortedElements[i].offsetTop === null) continue; + if(activeTarget === sortedElements[i].target) continue; + if(scrollTop < sortedElements[i].offsetTop) continue; + if(sortedElements[i + 1] && scrollTop > sortedElements[i + 1].offsetTop) continue; + return $scrollspy.$activateElement(sortedElements[i]); } - timeout = setTimeout(function() { - if (hoverState ==='in') $tooltip.show(); - }, options.delay.show); + }; + $scrollspy.checkPositionWithEventLoop = function() { + // IE 9 throws an error if we use 'this' instead of '$scrollspy' + // in this setTimeout call + setTimeout($scrollspy.checkPosition, 1); }; - $tooltip.show = function() { - if (!options.bsEnabled || $tooltip.$isShown) return; + // Protected methods - 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; + $scrollspy.$activateElement = function(element) { + if(activeTarget) { + var activeElement = $scrollspy.$getTrackedElement(activeTarget); + if(activeElement) { + activeElement.source.removeClass('active'); + if(nodeName(activeElement.source, 'li') && nodeName(activeElement.source.parent().parent(), 'li')) { + activeElement.source.parent().parent().removeClass('active'); + } } - } else { - parent = null; - after = element; } + activeTarget = element.target; + element.source.addClass('active'); + if(nodeName(element.source, 'li') && nodeName(element.source.parent().parent(), 'li')) { + element.source.parent().parent().addClass('active'); + } + }; + $scrollspy.$getTrackedElement = function(target) { + return trackedElements.filter(function(obj) { + return obj.target === target; + })[0]; + }; - // Hide any existing tipElement - if(tipElement) destroyTipElement(); - // Fetch a cloned element linked from template - tipScope = $tooltip.$scope.$new(); - tipElement = $tooltip.$element = tipLinker(tipScope, function(clonedElement, scope) {}); + // Track offsets behavior - // Set the initial positioning. Make the tooltip invisible - // so IE doesn't try to focus on it off screen. - tipElement.css({top: '-9999px', left: '-9999px', display: 'block', visibility: 'hidden'}); + $scrollspy.checkOffsets = function() { - // Options: animation - if(options.animation) tipElement.addClass(options.animation); - // Options: type - if(options.type) tipElement.addClass(options.prefixClass + '-' + options.type); - // Options: custom classes - if(options.customClass) tipElement.addClass(options.customClass); + angular.forEach(trackedElements, function(trackedElement) { + var targetElement = document.querySelector(trackedElement.target); + trackedElement.offsetTop = targetElement ? dimensions.offset(targetElement).top : null; + if(options.offset && trackedElement.offsetTop !== null) trackedElement.offsetTop -= options.offset * 1; + }); - // Support v1.3+ $animate - // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9 - var promise = $animate.enter(tipElement, parent, after, enterAnimateCallback); - if(promise && promise.then) promise.then(enterAnimateCallback); + sortedElements = trackedElements + .filter(function(el) { + return el.offsetTop !== null; + }) + .sort(function(a, b) { + return a.offsetTop - b.offsetTop; + }); - $tooltip.$isShown = scope.$isShown = true; - safeDigest(scope); - $$rAF(function () { - $tooltip.$applyPlacement(); + debouncedCheckPosition(); - // Once placed, make the tooltip visible - if(tipElement) tipElement.css({visibility: 'visible'}); - }); // var a = bodyEl.offsetWidth + 1; ? + }; - // Bind events - if(options.keyboard) { - if(options.trigger !== 'focus') { - $tooltip.focus(); - } - bindKeyboardEvents(); - } + $scrollspy.trackElement = function(target, source) { + trackedElements.push({target: target, source: source}); + }; - if(options.autoClose) { - bindAutoCloseEvents(); + $scrollspy.untrackElement = function(target, source) { + var toDelete; + for (var i = trackedElements.length; i--;) { + if(trackedElements[i].target === target && trackedElements[i].source === source) { + toDelete = i; + break; + } } + trackedElements = trackedElements.splice(toDelete, 1); + }; + $scrollspy.activate = function(i) { + trackedElements[i].addClass('active'); }; - function enterAnimateCallback() { - scope.$emit(options.prefixEvent + '.show', $tooltip); - } + // Initialize plugin - $tooltip.leave = function() { + $scrollspy.init(); + return $scrollspy; - clearTimeout(timeout); - hoverState = 'out'; - if (!options.delay || !options.delay.hide) { - return $tooltip.hide(); - } - timeout = setTimeout(function () { - if (hoverState === 'out') { - $tooltip.hide(); - } - }, options.delay.hide); + } - }; + return ScrollSpyFactory; - var _blur; - $tooltip.hide = function(blur) { + }]; - if(!$tooltip.$isShown) return; - scope.$emit(options.prefixEvent + '.hide.before', $tooltip); + }) - // store blur value for leaveAnimateCallback to use - _blur = blur; + .directive('bsScrollspy', ["$rootScope", "debounce", "dimensions", "$scrollspy", function($rootScope, debounce, dimensions, $scrollspy) { - // Support v1.3+ $animate - // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9 - var promise = $animate.leave(tipElement, leaveAnimateCallback); - if(promise && promise.then) promise.then(leaveAnimateCallback); + return { + restrict: 'EAC', + link: function postLink(scope, element, attr) { - $tooltip.$isShown = scope.$isShown = false; - safeDigest(scope); + var options = {scope: scope}; + angular.forEach(['offset', 'target'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); - // Unbind events - if(options.keyboard && tipElement !== null) { - unbindKeyboardEvents(); - } + var scrollspy = $scrollspy(options); + scrollspy.trackElement(options.target, element); - if(options.autoClose && tipElement !== null) { - unbindAutoCloseEvents(); + scope.$on('$destroy', function() { + if (scrollspy) { + scrollspy.untrackElement(options.target, element); + scrollspy.destroy(); } - }; + options = null; + scrollspy = null; + }); - function leaveAnimateCallback() { - scope.$emit(options.prefixEvent + '.hide', $tooltip); - // Allow to blur the input when hidden, like when pressing enter key - if(_blur && options.trigger === 'focus') { - return element[0].blur(); - } + } + }; - // clean up child scopes - destroyTipElement(); - } + }]) - $tooltip.toggle = function() { - $tooltip.$isShown ? $tooltip.leave() : $tooltip.enter(); - }; - $tooltip.focus = function() { - tipElement[0].focus(); - }; + .directive('bsScrollspyList', ["$rootScope", "debounce", "dimensions", "$scrollspy", function($rootScope, debounce, dimensions, $scrollspy) { - $tooltip.setEnabled = function(isEnabled) { - options.bsEnabled = isEnabled; - }; + return { + restrict: 'A', + compile: function postLink(element, attr) { + var children = element[0].querySelectorAll('li > a[href]'); + angular.forEach(children, function(child) { + var childEl = angular.element(child); + childEl.parent().attr('bs-scrollspy', '').attr('data-target', childEl.attr('href')); + }); + } - // Protected methods + }; - $tooltip.$applyPlacement = function() { - if(!tipElement) return; + }]); - // Determine if we're doing an auto or normal placement - var placement = options.placement, - autoToken = /\s?auto?\s?/i, - autoPlace = autoToken.test(placement); +// Source: timepicker.js +angular.module('mgcrea.ngStrap.timepicker', [ + 'mgcrea.ngStrap.helpers.dateParser', + 'mgcrea.ngStrap.helpers.dateFormatter', + 'mgcrea.ngStrap.tooltip']) - if (autoPlace) { - placement = placement.replace(autoToken, '') || defaults.placement; - } + .provider('$timepicker', function() { - // Need to add the position class before we get - // the offsets - tipElement.addClass(options.placement); + var defaults = this.defaults = { + animation: 'am-fade', + prefixClass: 'timepicker', + placement: 'bottom-left', + template: 'timepicker/timepicker.tpl.html', + trigger: 'focus', + container: false, + keyboard: true, + html: false, + delay: 0, + // lang: $locale.id, + useNative: true, + timeType: 'date', + timeFormat: 'shortTime', + modelTimeFormat: null, + autoclose: false, + minTime: -Infinity, + maxTime: +Infinity, + length: 5, + hourStep: 1, + minuteStep: 5, + iconUp: 'glyphicon glyphicon-chevron-up', + iconDown: 'glyphicon glyphicon-chevron-down', + arrowBehavior: 'pager' + }; - // Get the position of the target element - // and the height and width of the tooltip so we can center it. - var elementPosition = getPosition(), - tipWidth = tipElement.prop('offsetWidth'), - tipHeight = tipElement.prop('offsetHeight'); + this.$get = ["$window", "$document", "$rootScope", "$sce", "$dateFormatter", "$tooltip", "$timeout", function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) { - // If we're auto placing, we need to check the positioning - if (autoPlace) { - var originalPlacement = placement; - var container = options.container ? angular.element(document.querySelector(options.container)) : element.parent(); - var containerPosition = getPosition(container); + var bodyEl = angular.element($window.document.body); + var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent); + var isTouch = ('createTouch' in $window.document) && isNative; + if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale(); - // Determine if the vertical placement - if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > containerPosition.bottom) { - placement = originalPlacement.replace('bottom', 'top'); - } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < containerPosition.top) { - placement = originalPlacement.replace('top', 'bottom'); - } + function timepickerFactory(element, controller, config) { - // Determine the horizontal placement - // The exotic placements of left and right are opposite of the standard placements. Their arrows are put on the left/right - // and flow in the opposite direction of their placement. - if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') && - elementPosition.right + tipWidth > containerPosition.width) { + var $timepicker = $tooltip(element, angular.extend({}, defaults, config)); + var parentScope = config.scope; + var options = $timepicker.$options; + var scope = $timepicker.$scope; - placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right'); - } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') && - elementPosition.left - tipWidth < containerPosition.left) { + var lang = options.lang; + var formatDate = function(date, format) { + return $dateFormatter.formatDate(date, format, lang); + }; - placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left'); - } + // View vars - tipElement.removeClass(originalPlacement).addClass(placement); - } + var selectedIndex = 0; + var startDate = controller.$dateValue || new Date(); + var viewDate = {hour: startDate.getHours(), meridian: startDate.getHours() < 12, minute: startDate.getMinutes(), second: startDate.getSeconds(), millisecond: startDate.getMilliseconds()}; - // Get the tooltip's top and left coordinates to center it with this directive. - var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight); - applyPlacementCss(tipPosition.top, tipPosition.left); - }; + var format = $dateFormatter.getDatetimeFormat(options.timeFormat, lang); - $tooltip.$onKeyUp = function(evt) { - if (evt.which === 27 && $tooltip.$isShown) { - $tooltip.hide(); - evt.stopPropagation(); - } - }; + var hoursFormat = $dateFormatter.hoursFormat(format), + timeSeparator = $dateFormatter.timeSeparator(format), + minutesFormat = $dateFormatter.minutesFormat(format), + showAM = $dateFormatter.showAM(format); - $tooltip.$onFocusKeyUp = function(evt) { - if (evt.which === 27) { - element[0].blur(); + scope.$iconUp = options.iconUp; + scope.$iconDown = options.iconDown; + + // Scope methods + + 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); + }; + + // Public methods + + $timepicker.update = function(date) { + // console.warn('$timepicker.update() newValue=%o', date); + if(angular.isDate(date) && !isNaN(date.getTime())) { + $timepicker.$date = date; + angular.extend(viewDate, {hour: date.getHours(), minute: date.getMinutes(), second: date.getSeconds(), millisecond: date.getMilliseconds()}); + $timepicker.$build(); + } else if(!$timepicker.$isBuilt) { + $timepicker.$build(); + } + }; + + $timepicker.select = function(date, index, keep) { + // console.warn('$timepicker.select', date, scope.$mode); + if(!controller.$dateValue || isNaN(controller.$dateValue.getTime())) controller.$dateValue = new Date(1970, 0, 1); + if(!angular.isDate(date)) date = new Date(date); + if(index === 0) controller.$dateValue.setHours(date.getHours()); + else if(index === 1) controller.$dateValue.setMinutes(date.getMinutes()); + controller.$setViewValue(angular.copy(controller.$dateValue)); + controller.$render(); + if(options.autoclose && !keep) { + $timeout(function() { $timepicker.hide(true); }); + } + }; + + $timepicker.switchMeridian = function(date) { + if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) { + return; + } + var hours = (date || controller.$dateValue).getHours(); + controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12); + controller.$setViewValue(angular.copy(controller.$dateValue)); + controller.$render(); + }; + + // Protected methods + + $timepicker.$build = function() { + // console.warn('$timepicker.$build() viewDate=%o', viewDate); + var i, midIndex = scope.midIndex = parseInt(options.length / 2, 10); + var hours = [], hour; + for(i = 0; i < options.length; i++) { + hour = new Date(1970, 0, 1, viewDate.hour - (midIndex - i) * options.hourStep); + hours.push({date: hour, label: formatDate(hour, hoursFormat), selected: $timepicker.$date && $timepicker.$isSelected(hour, 0), disabled: $timepicker.$isDisabled(hour, 0)}); + } + var minutes = [], minute; + for(i = 0; i < options.length; i++) { + minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep); + minutes.push({date: minute, label: formatDate(minute, minutesFormat), selected: $timepicker.$date && $timepicker.$isSelected(minute, 1), disabled: $timepicker.$isDisabled(minute, 1)}); + } + + var rows = []; + for(i = 0; i < options.length; i++) { + rows.push([hours[i], minutes[i]]); + } + scope.rows = rows; + scope.showAM = showAM; + scope.isAM = ($timepicker.$date || hours[midIndex].date).getHours() < 12; + scope.timeSeparator = timeSeparator; + $timepicker.$isBuilt = true; + }; + + $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(); + } + }; + + $timepicker.$isDisabled = function(date, index) { + var selectedTime; + if(index === 0) { + selectedTime = date.getTime() + viewDate.minute * 6e4; + } else if(index === 1) { + selectedTime = date.getTime() + viewDate.hour * 36e5; + } + return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1; + }; + + scope.$arrowAction = function (value, index) { + if (options.arrowBehavior === 'picker') { + $timepicker.$setTimeByStep(value,index); + } else { + $timepicker.$moveIndex(value,index); + } + }; + + $timepicker.$setTimeByStep = function(value, index) { + var newDate = new Date($timepicker.$date); + var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length; + var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length; + if (index === 0) { + newDate.setHours(hours - (parseInt(options.hourStep, 10) * value)); + } + else { + newDate.setMinutes(minutes - (parseInt(options.minuteStep, 10) * value)); + } + $timepicker.select(newDate, index, true); + }; + + $timepicker.$moveIndex = function(value, index) { + var targetDate; + if(index === 0) { + targetDate = new Date(1970, 0, 1, viewDate.hour + (value * options.length), viewDate.minute); + angular.extend(viewDate, {hour: targetDate.getHours()}); + } else if(index === 1) { + targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + (value * options.length * options.minuteStep)); + angular.extend(viewDate, {minute: targetDate.getMinutes()}); + } + $timepicker.$build(); + }; + + $timepicker.$onMouseDown = function(evt) { + // Prevent blur on mousedown on .dropdown-menu + if(evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault(); + evt.stopPropagation(); + // Emulate click for mobile devices + if(isTouch) { + var targetEl = angular.element(evt.target); + if(targetEl[0].nodeName.toLowerCase() !== 'button') { + targetEl = targetEl.parent(); + } + targetEl.triggerHandler('click'); + } + }; + + $timepicker.$onKeyDown = function(evt) { + if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return; + evt.preventDefault(); + evt.stopPropagation(); + + // Close on enter + if(evt.keyCode === 13) return $timepicker.hide(true); + + // Navigate with keyboard + var newDate = new Date($timepicker.$date); + var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length; + var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length; + var lateralMove = /(37|39)/.test(evt.keyCode); + var count = 2 + showAM * 1; + + // Navigate indexes (left, right) + if (lateralMove) { + if(evt.keyCode === 37) selectedIndex = selectedIndex < 1 ? count - 1 : selectedIndex - 1; + else if(evt.keyCode === 39) selectedIndex = selectedIndex < count - 1 ? selectedIndex + 1 : 0; + } + + // Update values (up, down) + var selectRange = [0, hoursLength]; + if(selectedIndex === 0) { + if(evt.keyCode === 38) newDate.setHours(hours - parseInt(options.hourStep, 10)); + else if(evt.keyCode === 40) newDate.setHours(hours + parseInt(options.hourStep, 10)); + // re-calculate hours length because we have changed hours value + hoursLength = formatDate(newDate, hoursFormat).length; + selectRange = [0, hoursLength]; + } else if(selectedIndex === 1) { + if(evt.keyCode === 38) newDate.setMinutes(minutes - parseInt(options.minuteStep, 10)); + else if(evt.keyCode === 40) newDate.setMinutes(minutes + parseInt(options.minuteStep, 10)); + // re-calculate minutes length because we have changes minutes value + minutesLength = formatDate(newDate, minutesFormat).length; + selectRange = [hoursLength + 1, hoursLength + 1 + minutesLength]; + } else if(selectedIndex === 2) { + if(!lateralMove) $timepicker.switchMeridian(); + selectRange = [hoursLength + 1 + minutesLength + 1, hoursLength + 1 + minutesLength + 3]; + } + $timepicker.select(newDate, selectedIndex, true); + createSelection(selectRange[0], selectRange[1]); + parentScope.$digest(); + }; + + // Private + + function createSelection(start, end) { + if(element[0].createTextRange) { + var selRange = element[0].createTextRange(); + selRange.collapse(true); + selRange.moveStart('character', start); + selRange.moveEnd('character', end); + selRange.select(); + } else if(element[0].setSelectionRange) { + element[0].setSelectionRange(start, end); + } else if(angular.isUndefined(element[0].selectionStart)) { + element[0].selectionStart = start; + element[0].selectionEnd = end; + } + } + + function focusElement() { + element[0].focus(); + } + + // Overrides + + var _init = $timepicker.init; + $timepicker.init = function() { + if(isNative && options.useNative) { + element.prop('type', 'time'); + element.css('-webkit-appearance', 'textfield'); + return; + } else if(isTouch) { + element.prop('type', 'text'); + element.attr('readonly', 'true'); + element.on('click', focusElement); + } + _init(); + }; + + var _destroy = $timepicker.destroy; + $timepicker.destroy = function() { + if(isNative && options.useNative) { + element.off('click', focusElement); + } + _destroy(); + }; + + var _show = $timepicker.show; + $timepicker.show = function() { + _show(); + // use timeout to hookup the events to prevent + // event bubbling from being processed imediately. + $timeout(function() { + $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown); + if(options.keyboard) { + element.on('keydown', $timepicker.$onKeyDown); + } + }, 0, false); + }; + + var _hide = $timepicker.hide; + $timepicker.hide = function(blur) { + if(!$timepicker.$isShown) return; + $timepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown); + if(options.keyboard) { + element.off('keydown', $timepicker.$onKeyDown); + } + _hide(blur); + }; + + 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)/ig.test($window.navigator.userAgent); + var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout; + + return { + restrict: 'EAC', + require: 'ngModel', + link: function postLink(scope, element, attr, controller) { + + // Directive options + var options = {scope: scope, controller: controller}; + angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'timeType', 'timeFormat', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown', 'id'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + // Visibility binding support + attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) { + if(!timepicker || !angular.isDefined(newValue)) return; + if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(timepicker),?/i); + newValue === true ? timepicker.show() : timepicker.hide(); + }); + + // Initialize timepicker + if(isNative && (options.useNative || defaults.useNative)) options.timeFormat = 'HH:mm'; + var timepicker = $timepicker(element, controller, options); + options = timepicker.$options; + + var lang = options.lang; + var formatDate = function(date, format) { + return $dateFormatter.formatDate(date, format, lang); + }; + + // Initialize parser + var dateParser = $dateParser({format: options.timeFormat, lang: lang}); + + // Observe attributes for changes + angular.forEach(['minTime', 'maxTime'], function(key) { + // console.warn('attr.$observe(%s)', key, attr[key]); + angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) { + timepicker.$options[key] = dateParser.getTimeForAttribute(key, newValue); + !isNaN(timepicker.$options[key]) && timepicker.$build(); + validateAgainstMinMaxTime(controller.$dateValue); + }); + }); + + // Watch model for changes + scope.$watch(attr.ngModel, function(newValue, oldValue) { + // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue, controller.$dateValue); + timepicker.update(controller.$dateValue); + }, true); + + function validateAgainstMinMaxTime(parsedTime) { + if (!angular.isDate(parsedTime)) return; + var isMinValid = isNaN(options.minTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) >= options.minTime; + var isMaxValid = isNaN(options.maxTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) <= options.maxTime; + var isValid = isMinValid && isMaxValid; + controller.$setValidity('date', isValid); + controller.$setValidity('min', isMinValid); + controller.$setValidity('max', isMaxValid); + // Only update the model when we have a valid date + if(!isValid) { + return; + } + controller.$dateValue = parsedTime; + } + + // viewValue -> $parsers -> modelValue + controller.$parsers.unshift(function(viewValue) { + // console.warn('$parser("%s"): viewValue=%o', element.attr('ng-model'), viewValue); + // Null values should correctly reset the model value & validity + if(!viewValue) { + // BREAKING CHANGE: + // return null (not undefined) when input value is empty, so angularjs 1.3 + // ngModelController can go ahead and run validators, like ngRequired + controller.$setValidity('date', true); + return null; + } + var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue); + if(!parsedTime || isNaN(parsedTime.getTime())) { + controller.$setValidity('date', false); + // return undefined, causes ngModelController to + // invalidate model value + return; + } else { + validateAgainstMinMaxTime(parsedTime); + } + if(options.timeType === 'string') { + return formatDate(parsedTime, options.modelTimeFormat || options.timeFormat); + } else if(options.timeType === 'number') { + return controller.$dateValue.getTime(); + } else if(options.timeType === 'unix') { + return controller.$dateValue.getTime() / 1000; + } else if(options.timeType === 'iso') { + return controller.$dateValue.toISOString(); + } else { + return new Date(controller.$dateValue); + } + }); + + // modelValue -> $formatters -> viewValue + controller.$formatters.push(function(modelValue) { + // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue); + var date; + if(angular.isUndefined(modelValue) || modelValue === null) { + date = NaN; + } else if(angular.isDate(modelValue)) { + date = modelValue; + } else if(options.timeType === 'string') { + date = dateParser.parse(modelValue, null, options.modelTimeFormat); + } else if(options.timeType === 'unix') { + date = new Date(modelValue * 1000); + } else { + date = new Date(modelValue); + } + // Setup default value? + // if(isNaN(date.getTime())) date = new Date(new Date().setMinutes(0) + 36e5); + controller.$dateValue = date; + return getTimeFormattedString(); + }); + + // viewValue -> element + controller.$render = function() { + // console.warn('$render("%s"): viewValue=%o', element.attr('ng-model'), controller.$viewValue); + element.val(getTimeFormattedString()); + }; + + function getTimeFormattedString() { + return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat); + } + + // Garbage collection + scope.$on('$destroy', function() { + if (timepicker) timepicker.destroy(); + options = null; + timepicker = null; + }); + + } + }; + + }]); + +// Source: tooltip.js +angular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions']) + + .provider('$tooltip', function() { + + var defaults = this.defaults = { + animation: 'am-fade', + customClass: '', + prefixClass: 'tooltip', + prefixEvent: 'tooltip', + container: false, + target: false, + placement: 'top', + template: 'tooltip/tooltip.tpl.html', + contentTemplate: false, + trigger: 'hover focus', + keyboard: false, + html: false, + show: false, + title: '', + type: '', + delay: 0, + autoClose: false, + bsEnabled: true + }; + + this.$get = ["$window", "$rootScope", "$compile", "$q", "$templateCache", "$http", "$animate", "$sce", "dimensions", "$$rAF", "$timeout", function($window, $rootScope, $compile, $q, $templateCache, $http, $animate, $sce, dimensions, $$rAF, $timeout) { + + var trim = String.prototype.trim; + var isTouch = 'createTouch' in $window.document; + var htmlReplaceRegExp = /ng-bind="/ig; + var $body = angular.element($window.document); + + function TooltipFactory(element, config) { + + var $tooltip = {}; + + // Common vars + var nodeName = element[0].nodeName.toLowerCase(); + var options = $tooltip.$options = angular.extend({}, defaults, config); + $tooltip.$promise = fetchTemplate(options.template); + var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new(); + if(options.delay && angular.isString(options.delay)) { + var split = options.delay.split(',').map(parseFloat); + options.delay = split.length > 1 ? {show: split[0], hide: split[1]} : split[0]; + } + + // store $id to identify the triggering element in events + // give priority to options.id, otherwise, try to use + // element id if defined + $tooltip.$id = options.id || element.attr('id') || ''; + + // Support scope as string options + if(options.title) { + scope.title = $sce.trustAsHtml(options.title); + } + + // Provide scope helpers + scope.$setEnabled = function(isEnabled) { + scope.$$postDigest(function() { + $tooltip.setEnabled(isEnabled); + }); + }; + scope.$hide = function() { + scope.$$postDigest(function() { + $tooltip.hide(); + }); + }; + scope.$show = function() { + scope.$$postDigest(function() { + $tooltip.show(); + }); + }; + scope.$toggle = function() { + scope.$$postDigest(function() { + $tooltip.toggle(); + }); + }; + // Publish isShown as a protected var on scope + $tooltip.$isShown = scope.$isShown = false; + + // Private vars + var timeout, hoverState; + + // Support contentTemplate option + if(options.contentTemplate) { + $tooltip.$promise = $tooltip.$promise.then(function(template) { + var templateEl = angular.element(template); + return fetchTemplate(options.contentTemplate) + .then(function(contentTemplate) { + var contentEl = findElement('[ng-bind="content"]', templateEl[0]); + if(!contentEl.length) contentEl = findElement('[ng-bind="title"]', templateEl[0]); + contentEl.removeAttr('ng-bind').html(contentTemplate); + return templateEl[0].outerHTML; + }); + }); + } + + // Fetch, compile then initialize tooltip + var tipLinker, tipElement, tipTemplate, tipContainer, tipScope; + $tooltip.$promise.then(function(template) { + if(angular.isObject(template)) template = template.data; + if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html="'); + template = trim.apply(template); + tipTemplate = template; + tipLinker = $compile(template); + $tooltip.init(); + }); + + $tooltip.init = function() { + + // Options: delay + if (options.delay && angular.isNumber(options.delay)) { + options.delay = { + show: options.delay, + hide: options.delay + }; + } + + // Replace trigger on touch devices ? + // if(isTouch && options.trigger === defaults.trigger) { + // options.trigger.replace(/hover/g, 'click'); + // } + + // Options : container + if(options.container === 'self') { + tipContainer = element; + } else if(angular.isElement(options.container)) { + tipContainer = options.container; + } else if(options.container) { + tipContainer = findElement(options.container); + } + + // Options: trigger + bindTriggerEvents(); + + // Options: target + if(options.target) { + options.target = angular.isElement(options.target) ? options.target : findElement(options.target); + } + + // Options: show + if(options.show) { + scope.$$postDigest(function() { + options.trigger === 'focus' ? element[0].focus() : $tooltip.show(); + }); + } + + }; + + $tooltip.destroy = function() { + + // Unbind events + unbindTriggerEvents(); + + // Remove element + destroyTipElement(); + + // Destroy scope + 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; + } + + + // Hide any existing tipElement + if(tipElement) destroyTipElement(); + // Fetch a cloned element linked from template + tipScope = $tooltip.$scope.$new(); + tipElement = $tooltip.$element = tipLinker(tipScope, function(clonedElement, scope) {}); + + // Set the initial positioning. Make the tooltip invisible + // so IE doesn't try to focus on it off screen. + tipElement.css({top: '-9999px', left: '-9999px', display: 'block', visibility: 'hidden'}); + + // Options: animation + if(options.animation) tipElement.addClass(options.animation); + // Options: type + if(options.type) tipElement.addClass(options.prefixClass + '-' + options.type); + // Options: custom classes + if(options.customClass) tipElement.addClass(options.customClass); + + // Support v1.3+ $animate + // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9 + var promise = $animate.enter(tipElement, parent, after, enterAnimateCallback); + if(promise && promise.then) promise.then(enterAnimateCallback); + + $tooltip.$isShown = scope.$isShown = true; + safeDigest(scope); + $$rAF(function () { + $tooltip.$applyPlacement(); + + // Once placed, make the tooltip visible + if(tipElement) tipElement.css({visibility: 'visible'}); + }); // var a = bodyEl.offsetWidth + 1; ? + + // Bind events + if(options.keyboard) { + if(options.trigger !== 'focus') { + $tooltip.focus(); + } + bindKeyboardEvents(); + } + + if(options.autoClose) { + bindAutoCloseEvents(); + } + + }; + + function enterAnimateCallback() { + scope.$emit(options.prefixEvent + '.show', $tooltip); + } + + $tooltip.leave = function() { + + clearTimeout(timeout); + hoverState = 'out'; + if (!options.delay || !options.delay.hide) { + return $tooltip.hide(); + } + timeout = setTimeout(function () { + if (hoverState === 'out') { + $tooltip.hide(); + } + }, options.delay.hide); + + }; + + var _blur; + var _tipToHide; + $tooltip.hide = function(blur) { + + if(!$tooltip.$isShown) return; + scope.$emit(options.prefixEvent + '.hide.before', $tooltip); + + // store blur value for leaveAnimateCallback to use + _blur = blur; + + // store current tipElement reference to use + // in leaveAnimateCallback + _tipToHide = tipElement; + + // Support v1.3+ $animate + // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9 + var promise = $animate.leave(tipElement, leaveAnimateCallback); + if(promise && promise.then) promise.then(leaveAnimateCallback); + + $tooltip.$isShown = scope.$isShown = false; + safeDigest(scope); + + // Unbind events + if(options.keyboard && tipElement !== null) { + unbindKeyboardEvents(); + } + + if(options.autoClose && tipElement !== null) { + unbindAutoCloseEvents(); + } + }; + + function leaveAnimateCallback() { + scope.$emit(options.prefixEvent + '.hide', $tooltip); + + // check if current tipElement still references + // the same element when hide was called + if (tipElement === _tipToHide) { + // Allow to blur the input when hidden, like when pressing enter key + if(_blur && options.trigger === 'focus') { + return element[0].blur(); + } + + // clean up child scopes + destroyTipElement(); + } + } + + $tooltip.toggle = function() { + $tooltip.$isShown ? $tooltip.leave() : $tooltip.enter(); + }; + + $tooltip.focus = function() { + tipElement[0].focus(); + }; + + $tooltip.setEnabled = function(isEnabled) { + options.bsEnabled = isEnabled; + }; + + // Protected methods + + $tooltip.$applyPlacement = function() { + if(!tipElement) return; + + // Determine if we're doing an auto or normal placement + var placement = options.placement, + autoToken = /\s?auto?\s?/i, + autoPlace = autoToken.test(placement); + + if (autoPlace) { + placement = placement.replace(autoToken, '') || defaults.placement; + } + + // Need to add the position class before we get + // the offsets + tipElement.addClass(options.placement); + + // Get the position of the target element + // and the height and width of the tooltip so we can center it. + var elementPosition = getPosition(), + tipWidth = tipElement.prop('offsetWidth'), + tipHeight = tipElement.prop('offsetHeight'); + + // If we're auto placing, we need to check the positioning + if (autoPlace) { + var originalPlacement = placement; + var container = options.container ? angular.element(document.querySelector(options.container)) : element.parent(); + var containerPosition = getPosition(container); + + // Determine if the vertical placement + if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > containerPosition.bottom) { + placement = originalPlacement.replace('bottom', 'top'); + } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < containerPosition.top) { + placement = originalPlacement.replace('top', 'bottom'); + } + + // Determine the horizontal placement + // The exotic placements of left and right are opposite of the standard placements. Their arrows are put on the left/right + // and flow in the opposite direction of their placement. + if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') && + elementPosition.right + tipWidth > containerPosition.width) { + + placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right'); + } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') && + elementPosition.left - tipWidth < containerPosition.left) { + + placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left'); + } + + tipElement.removeClass(originalPlacement).addClass(placement); + } + + // Get the tooltip's top and left coordinates to center it with this directive. + var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight); + applyPlacementCss(tipPosition.top, tipPosition.left); + }; + + $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(); } }; @@ -4019,414 +4596,155 @@ angular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions']) return offset; } - // Add support for corners @todo css - if(split[0] === 'top' || split[0] === 'bottom') { - switch (split[1]) { - case 'left': - offset.left = position.left; - break; - case 'right': - offset.left = position.left + position.width - actualWidth; - } - } else if(split[0] === 'left' || split[0] === 'right') { - switch (split[1]) { - case 'top': - offset.top = position.top - actualHeight; - break; - case 'bottom': - offset.top = position.top + position.height; - } - } - - return offset; - } - - function applyPlacementCss(top, left) { - tipElement.css({ top: top + 'px', left: left + 'px' }); - } - - function destroyTipElement() { - // Cancel pending callbacks - clearTimeout(timeout); - - if($tooltip.$isShown && tipElement !== null) { - if(options.autoClose) { - unbindAutoCloseEvents(); - } - - if(options.keyboard) { - unbindKeyboardEvents(); - } - } - - if(tipScope) { - tipScope.$destroy(); - tipScope = null; - } - - if(tipElement) { - tipElement.remove(); - tipElement = $tooltip.$element = null; - } - } - - return $tooltip; - - } - - // Helper functions - - function safeDigest(scope) { - scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest(); - } - - function findElement(query, element) { - return angular.element((element || document).querySelectorAll(query)); - } - - var fetchPromises = {}; - function fetchTemplate(template) { - if(fetchPromises[template]) return fetchPromises[template]; - return (fetchPromises[template] = $q.when($templateCache.get(template) || $http.get(template)) - .then(function(res) { - if(angular.isObject(res)) { - $templateCache.put(template, res.data); - return res.data; - } - return res; - })); - } - - return TooltipFactory; - - }]; - - }) - - .directive('bsTooltip', ["$window", "$location", "$sce", "$tooltip", "$$rAF", function($window, $location, $sce, $tooltip, $$rAF) { - - return { - restrict: 'EAC', - scope: true, - link: function postLink(scope, element, attr, transclusion) { - - // Directive options - var options = {scope: scope}; - angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'backdropAnimation', 'type', 'customClass'], function(key) { - if(angular.isDefined(attr[key])) options[key] = attr[key]; - }); - - // overwrite inherited title value when no value specified - // fix for angular 1.3.1 531a8de72c439d8ddd064874bf364c00cedabb11 - if (!scope.hasOwnProperty('title')){ - scope.title = ''; - } - - // Observe scope attributes for change - attr.$observe('title', function(newValue) { - if (angular.isDefined(newValue) || !scope.hasOwnProperty('title')) { - var oldValue = scope.title; - scope.title = $sce.trustAsHtml(newValue); - angular.isDefined(oldValue) && $$rAF(function() { - tooltip && tooltip.$applyPlacement(); - }); - } - }); - - // Support scope as an object - attr.bsTooltip && scope.$watch(attr.bsTooltip, function(newValue, oldValue) { - if(angular.isObject(newValue)) { - angular.extend(scope, newValue); - } else { - scope.title = newValue; - } - angular.isDefined(oldValue) && $$rAF(function() { - tooltip && tooltip.$applyPlacement(); - }); - }, true); - - // Visibility binding support - attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) { - if(!tooltip || !angular.isDefined(newValue)) return; - if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(tooltip),?/i); - newValue === true ? tooltip.show() : tooltip.hide(); - }); - - // Enabled binding support - attr.bsEnabled && scope.$watch(attr.bsEnabled, function(newValue, oldValue) { - // console.warn('scope.$watch(%s)', attr.bsEnabled, newValue, oldValue); - if(!tooltip || !angular.isDefined(newValue)) return; - if(angular.isString(newValue)) newValue = !!newValue.match(/true|1|,?(tooltip),?/i); - newValue === false ? tooltip.setEnabled(false) : tooltip.setEnabled(true); - }); - - // Initialize popover - var tooltip = $tooltip(element, options); - - // Garbage collection - scope.$on('$destroy', function() { - if(tooltip) tooltip.destroy(); - options = null; - tooltip = null; - }); - - } - }; - - }]); - -// Source: typeahead.js -angular.module('mgcrea.ngStrap.typeahead', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions']) - - .provider('$typeahead', function() { - - var defaults = this.defaults = { - animation: 'am-fade', - prefixClass: 'typeahead', - prefixEvent: '$typeahead', - placement: 'bottom-left', - template: 'typeahead/typeahead.tpl.html', - trigger: 'focus', - container: false, - keyboard: true, - html: false, - delay: 0, - minLength: 1, - filter: 'filter', - limit: 6, - comparator: '' - }; - - this.$get = ["$window", "$rootScope", "$tooltip", "$timeout", function($window, $rootScope, $tooltip, $timeout) { - - var bodyEl = angular.element($window.document.body); - - function TypeaheadFactory(element, controller, config) { - - var $typeahead = {}; - - // Common vars - var options = angular.extend({}, defaults, config); - - $typeahead = $tooltip(element, options); - var parentScope = config.scope; - var scope = $typeahead.$scope; - - scope.$resetMatches = function(){ - scope.$matches = []; - scope.$activeIndex = 0; - }; - scope.$resetMatches(); - - scope.$activate = function(index) { - scope.$$postDigest(function() { - $typeahead.activate(index); - }); - }; - - scope.$select = function(index, evt) { - scope.$$postDigest(function() { - $typeahead.select(index); - }); - }; - - scope.$isVisible = function() { - return $typeahead.$isVisible(); - }; - - // Public methods - - $typeahead.update = function(matches) { - scope.$matches = matches; - if(scope.$activeIndex >= matches.length) { - scope.$activeIndex = 0; - } - }; - - $typeahead.activate = function(index) { - scope.$activeIndex = index; - }; - - $typeahead.select = function(index) { - var value = scope.$matches[index].value; - // console.log('$setViewValue', value); - controller.$setViewValue(value); - controller.$render(); - scope.$resetMatches(); - if(parentScope) parentScope.$digest(); - // Emit event - scope.$emit(options.prefixEvent + '.select', value, index); - }; + // Add support for corners @todo css + if(split[0] === 'top' || split[0] === 'bottom') { + switch (split[1]) { + case 'left': + offset.left = position.left; + break; + case 'right': + offset.left = position.left + position.width - actualWidth; + } + } else if(split[0] === 'left' || split[0] === 'right') { + switch (split[1]) { + case 'top': + offset.top = position.top - actualHeight; + break; + case 'bottom': + offset.top = position.top + position.height; + } + } - // Protected methods + return offset; + } - $typeahead.$isVisible = function() { - if(!options.minLength || !controller) { - return !!scope.$matches.length; - } - // minLength support - return scope.$matches.length && angular.isString(controller.$viewValue) && controller.$viewValue.length >= options.minLength; - }; + function applyPlacementCss(top, left) { + tipElement.css({ top: top + 'px', left: left + 'px' }); + } - $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(i < 0) return; - return i; - }; + function destroyTipElement() { + // Cancel pending callbacks + clearTimeout(timeout); - $typeahead.$onMouseDown = function(evt) { - // Prevent blur on mousedown - evt.preventDefault(); - evt.stopPropagation(); - }; + if($tooltip.$isShown && tipElement !== null) { + if(options.autoClose) { + unbindAutoCloseEvents(); + } - $typeahead.$onKeyDown = function(evt) { - if(!/(38|40|13)/.test(evt.keyCode)) return; + if(options.keyboard) { + unbindKeyboardEvents(); + } + } - // Let ngSubmit pass if the typeahead tip is hidden - if($typeahead.$isVisible()) { - evt.preventDefault(); - evt.stopPropagation(); + if(tipScope) { + tipScope.$destroy(); + tipScope = null; } - // Select with enter - if(evt.keyCode === 13 && scope.$matches.length) { - $typeahead.select(scope.$activeIndex); + if(tipElement) { + tipElement.remove(); + tipElement = $tooltip.$element = null; } + } - // Navigate with keyboard - 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(); - }; + return $tooltip; - // Overrides + } - var show = $typeahead.show; - $typeahead.show = function() { - show(); - // use timeout to hookup the events to prevent - // event bubbling from being processed imediately. - $timeout(function() { - $typeahead.$element.on('mousedown', $typeahead.$onMouseDown); - if(options.keyboard) { - element.on('keydown', $typeahead.$onKeyDown); - } - }, 0, false); - }; + // Helper functions - var hide = $typeahead.hide; - $typeahead.hide = function() { - $typeahead.$element.off('mousedown', $typeahead.$onMouseDown); - if(options.keyboard) { - element.off('keydown', $typeahead.$onKeyDown); - } - hide(); - }; + function safeDigest(scope) { + scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest(); + } - return $typeahead; + function findElement(query, element) { + return angular.element((element || document).querySelectorAll(query)); + } + var fetchPromises = {}; + function fetchTemplate(template) { + if(fetchPromises[template]) return fetchPromises[template]; + return (fetchPromises[template] = $q.when($templateCache.get(template) || $http.get(template)) + .then(function(res) { + if(angular.isObject(res)) { + $templateCache.put(template, res.data); + return res.data; + } + return res; + })); } - TypeaheadFactory.defaults = defaults; - return TypeaheadFactory; + return TooltipFactory; }]; }) - .directive('bsTypeahead', ["$window", "$parse", "$q", "$typeahead", "$parseOptions", function($window, $parse, $q, $typeahead, $parseOptions) { - - var defaults = $typeahead.defaults; + .directive('bsTooltip', ["$window", "$location", "$sce", "$tooltip", "$$rAF", function($window, $location, $sce, $tooltip, $$rAF) { return { restrict: 'EAC', - require: 'ngModel', - link: function postLink(scope, element, attr, controller) { + scope: true, + link: function postLink(scope, element, attr, transclusion) { // Directive options var options = {scope: scope}; - angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'filter', 'limit', 'minLength', 'watchOptions', 'selectMode', 'comparator'], function(key) { + angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'backdropAnimation', 'type', 'customClass', 'id'], function(key) { if(angular.isDefined(attr[key])) options[key] = attr[key]; }); - // Build proper ngOptions - var filter = options.filter || defaults.filter; - var limit = options.limit || defaults.limit; - var comparator = options.comparator || defaults.comparator; - - var ngOptions = attr.ngOptions; - if(filter) ngOptions += ' | ' + filter + ':$viewValue'; - if (comparator) ngOptions += ':' + comparator; - if(limit) ngOptions += ' | limitTo:' + limit; - var parsedOptions = $parseOptions(ngOptions); - - // Initialize typeahead - var typeahead = $typeahead(element, controller, options); + // overwrite inherited title value when no value specified + // fix for angular 1.3.1 531a8de72c439d8ddd064874bf364c00cedabb11 + if (!scope.hasOwnProperty('title')){ + scope.title = ''; + } - // Watch options on demand - if(options.watchOptions) { - // Watch ngOptions values before filtering for changes, drop function calls - var watchedOptions = parsedOptions.$match[7].replace(/\|.+/, '').replace(/\(.*\)/g, '').trim(); - scope.$watch(watchedOptions, function (newValue, oldValue) { - // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue); - parsedOptions.valuesFn(scope, controller).then(function (values) { - typeahead.update(values); - controller.$render(); + // Observe scope attributes for change + attr.$observe('title', function(newValue) { + if (angular.isDefined(newValue) || !scope.hasOwnProperty('title')) { + var oldValue = scope.title; + scope.title = $sce.trustAsHtml(newValue); + angular.isDefined(oldValue) && $$rAF(function() { + tooltip && tooltip.$applyPlacement(); }); - }, true); - } + } + }); - // Watch model for changes - scope.$watch(attr.ngModel, function(newValue, oldValue) { - // console.warn('$watch', element.attr('ng-model'), newValue); - scope.$modelValue = newValue; // Publish modelValue on scope for custom templates - parsedOptions.valuesFn(scope, controller) - .then(function(values) { - // Prevent input with no future prospect if selectMode is truthy - // @TODO test selectMode - 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); - // Do not re-queue an update if a correct value has been selected - if(values.length === 1 && values[0].value === newValue) return; - !isVisible && typeahead.update(values); - // Queue a new rendering that will leverage collection loading - controller.$render(); + // Support scope as an object + attr.bsTooltip && scope.$watch(attr.bsTooltip, function(newValue, oldValue) { + if(angular.isObject(newValue)) { + angular.extend(scope, newValue); + } else { + scope.title = newValue; + } + angular.isDefined(oldValue) && $$rAF(function() { + tooltip && tooltip.$applyPlacement(); }); + }, true); + + // Visibility binding support + attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) { + if(!tooltip || !angular.isDefined(newValue)) return; + if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(tooltip),?/i); + newValue === true ? tooltip.show() : tooltip.hide(); }); - // modelValue -> $formatters -> viewValue - controller.$formatters.push(function(modelValue) { - // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue); - var displayValue = parsedOptions.displayValue(modelValue); - return displayValue === undefined ? '' : displayValue; + // Enabled binding support + attr.bsEnabled && scope.$watch(attr.bsEnabled, function(newValue, oldValue) { + // console.warn('scope.$watch(%s)', attr.bsEnabled, newValue, oldValue); + if(!tooltip || !angular.isDefined(newValue)) return; + if(angular.isString(newValue)) newValue = !!newValue.match(/true|1|,?(tooltip),?/i); + newValue === false ? tooltip.setEnabled(false) : tooltip.setEnabled(true); }); - // Model rendering in view - controller.$render = function () { - // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue); - 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; - element.val(selected ? selected.toString().replace(/<(?:.|\n)*?>/gm, '').trim() : ''); - }; + // Initialize popover + var tooltip = $tooltip(element, options); // Garbage collection scope.$on('$destroy', function() { - if (typeahead) typeahead.destroy(); + if(tooltip) tooltip.destroy(); options = null; - typeahead = null; + tooltip = null; }); } @@ -4434,345 +4752,174 @@ angular.module('mgcrea.ngStrap.typeahead', ['mgcrea.ngStrap.tooltip', 'mgcrea.ng }]); -// Source: timepicker.js -angular.module('mgcrea.ngStrap.timepicker', [ - 'mgcrea.ngStrap.helpers.dateParser', - 'mgcrea.ngStrap.helpers.dateFormatter', - 'mgcrea.ngStrap.tooltip']) +// Source: typeahead.js +angular.module('mgcrea.ngStrap.typeahead', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions']) - .provider('$timepicker', function() { + .provider('$typeahead', function() { var defaults = this.defaults = { animation: 'am-fade', - prefixClass: 'timepicker', + prefixClass: 'typeahead', + prefixEvent: '$typeahead', placement: 'bottom-left', - template: 'timepicker/timepicker.tpl.html', + template: 'typeahead/typeahead.tpl.html', trigger: 'focus', container: false, keyboard: true, html: false, delay: 0, - // lang: $locale.id, - useNative: true, - timeType: 'date', - timeFormat: 'shortTime', - modelTimeFormat: null, - autoclose: false, - minTime: -Infinity, - maxTime: +Infinity, - length: 5, - hourStep: 1, - minuteStep: 5, - iconUp: 'glyphicon glyphicon-chevron-up', - iconDown: 'glyphicon glyphicon-chevron-down', - arrowBehavior: 'pager' + minLength: 1, + filter: 'filter', + limit: 6, + comparator: '' }; - this.$get = ["$window", "$document", "$rootScope", "$sce", "$dateFormatter", "$tooltip", "$timeout", function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) { + this.$get = ["$window", "$rootScope", "$tooltip", "$timeout", function($window, $rootScope, $tooltip, $timeout) { var bodyEl = angular.element($window.document.body); - var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent); - var isTouch = ('createTouch' in $window.document) && isNative; - if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale(); - - function timepickerFactory(element, controller, config) { - - var $timepicker = $tooltip(element, angular.extend({}, defaults, config)); - var parentScope = config.scope; - var options = $timepicker.$options; - var scope = $timepicker.$scope; - - var lang = options.lang; - var formatDate = function(date, format) { - return $dateFormatter.formatDate(date, format, lang); - }; - - // View vars - - var selectedIndex = 0; - var startDate = controller.$dateValue || new Date(); - var viewDate = {hour: startDate.getHours(), meridian: startDate.getHours() < 12, minute: startDate.getMinutes(), second: startDate.getSeconds(), millisecond: startDate.getMilliseconds()}; - - var format = $dateFormatter.getDatetimeFormat(options.timeFormat, lang); - - var hoursFormat = $dateFormatter.hoursFormat(format), - timeSeparator = $dateFormatter.timeSeparator(format), - minutesFormat = $dateFormatter.minutesFormat(format), - showAM = $dateFormatter.showAM(format); - - scope.$iconUp = options.iconUp; - scope.$iconDown = options.iconDown; - - // Scope methods - 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); - }; + function TypeaheadFactory(element, controller, config) { - // Public methods + var $typeahead = {}; - $timepicker.update = function(date) { - // console.warn('$timepicker.update() newValue=%o', date); - if(angular.isDate(date) && !isNaN(date.getTime())) { - $timepicker.$date = date; - angular.extend(viewDate, {hour: date.getHours(), minute: date.getMinutes(), second: date.getSeconds(), millisecond: date.getMilliseconds()}); - $timepicker.$build(); - } else if(!$timepicker.$isBuilt) { - $timepicker.$build(); - } - }; + // Common vars + var options = angular.extend({}, defaults, config); - $timepicker.select = function(date, index, keep) { - // console.warn('$timepicker.select', date, scope.$mode); - if(!controller.$dateValue || isNaN(controller.$dateValue.getTime())) controller.$dateValue = new Date(1970, 0, 1); - if(!angular.isDate(date)) date = new Date(date); - if(index === 0) controller.$dateValue.setHours(date.getHours()); - else if(index === 1) controller.$dateValue.setMinutes(date.getMinutes()); - controller.$setViewValue(angular.copy(controller.$dateValue)); - controller.$render(); - if(options.autoclose && !keep) { - $timeout(function() { $timepicker.hide(true); }); - } - }; + $typeahead = $tooltip(element, options); + var parentScope = config.scope; + var scope = $typeahead.$scope; - $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(); + scope.$resetMatches = function(){ + scope.$matches = []; + scope.$activeIndex = 0; }; + scope.$resetMatches(); - // Protected methods - - $timepicker.$build = function() { - // console.warn('$timepicker.$build() viewDate=%o', viewDate); - var i, midIndex = scope.midIndex = parseInt(options.length / 2, 10); - var hours = [], hour; - for(i = 0; i < options.length; i++) { - hour = new Date(1970, 0, 1, viewDate.hour - (midIndex - i) * options.hourStep); - hours.push({date: hour, label: formatDate(hour, hoursFormat), selected: $timepicker.$date && $timepicker.$isSelected(hour, 0), disabled: $timepicker.$isDisabled(hour, 0)}); - } - var minutes = [], minute; - for(i = 0; i < options.length; i++) { - minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep); - minutes.push({date: minute, label: formatDate(minute, minutesFormat), selected: $timepicker.$date && $timepicker.$isSelected(minute, 1), disabled: $timepicker.$isDisabled(minute, 1)}); - } - - var rows = []; - for(i = 0; i < options.length; i++) { - rows.push([hours[i], minutes[i]]); - } - scope.rows = rows; - scope.showAM = showAM; - scope.isAM = ($timepicker.$date || hours[midIndex].date).getHours() < 12; - scope.timeSeparator = timeSeparator; - $timepicker.$isBuilt = true; + scope.$activate = function(index) { + scope.$$postDigest(function() { + $typeahead.activate(index); + }); }; - $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(); - } + scope.$select = function(index, evt) { + scope.$$postDigest(function() { + $typeahead.select(index); + }); }; - $timepicker.$isDisabled = function(date, index) { - var selectedTime; - if(index === 0) { - selectedTime = date.getTime() + viewDate.minute * 6e4; - } else if(index === 1) { - selectedTime = date.getTime() + viewDate.hour * 36e5; - } - return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1; + scope.$isVisible = function() { + return $typeahead.$isVisible(); }; - scope.$arrowAction = function (value, index) { - if (options.arrowBehavior === 'picker') { - $timepicker.$setTimeByStep(value,index); - } else { - $timepicker.$moveIndex(value,index); - } - }; + // Public methods - $timepicker.$setTimeByStep = function(value, index) { - var newDate = new Date($timepicker.$date); - var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length; - var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length; - if (index === 0) { - newDate.setHours(hours - (parseInt(options.hourStep, 10) * value)); - } - else { - newDate.setMinutes(minutes - (parseInt(options.minuteStep, 10) * value)); + $typeahead.update = function(matches) { + scope.$matches = matches; + if(scope.$activeIndex >= matches.length) { + scope.$activeIndex = 0; } - $timepicker.select(newDate, index, true); }; - $timepicker.$moveIndex = function(value, index) { - var targetDate; - if(index === 0) { - targetDate = new Date(1970, 0, 1, viewDate.hour + (value * options.length), viewDate.minute); - angular.extend(viewDate, {hour: targetDate.getHours()}); - } else if(index === 1) { - targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + (value * options.length * options.minuteStep)); - angular.extend(viewDate, {minute: targetDate.getMinutes()}); - } - $timepicker.$build(); + $typeahead.activate = function(index) { + scope.$activeIndex = index; }; - $timepicker.$onMouseDown = function(evt) { - // Prevent blur on mousedown on .dropdown-menu - if(evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault(); - evt.stopPropagation(); - // Emulate click for mobile devices - if(isTouch) { - var targetEl = angular.element(evt.target); - if(targetEl[0].nodeName.toLowerCase() !== 'button') { - targetEl = targetEl.parent(); - } - targetEl.triggerHandler('click'); - } + $typeahead.select = function(index) { + var value = scope.$matches[index].value; + // console.log('$setViewValue', value); + controller.$setViewValue(value); + controller.$render(); + scope.$resetMatches(); + if(parentScope) parentScope.$digest(); + // Emit event + scope.$emit(options.prefixEvent + '.select', value, index, $typeahead); }; - $timepicker.$onKeyDown = function(evt) { - if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return; - evt.preventDefault(); - evt.stopPropagation(); - - // Close on enter - if(evt.keyCode === 13) return $timepicker.hide(true); - - // Navigate with keyboard - var newDate = new Date($timepicker.$date); - var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length; - var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length; - var lateralMove = /(37|39)/.test(evt.keyCode); - var count = 2 + showAM * 1; - - // Navigate indexes (left, right) - if (lateralMove) { - if(evt.keyCode === 37) selectedIndex = selectedIndex < 1 ? count - 1 : selectedIndex - 1; - else if(evt.keyCode === 39) selectedIndex = selectedIndex < count - 1 ? selectedIndex + 1 : 0; - } + // Protected methods - // Update values (up, down) - var selectRange = [0, hoursLength]; - if(selectedIndex === 0) { - if(evt.keyCode === 38) newDate.setHours(hours - parseInt(options.hourStep, 10)); - else if(evt.keyCode === 40) newDate.setHours(hours + parseInt(options.hourStep, 10)); - // re-calculate hours length because we have changed hours value - hoursLength = formatDate(newDate, hoursFormat).length; - selectRange = [0, hoursLength]; - } else if(selectedIndex === 1) { - if(evt.keyCode === 38) newDate.setMinutes(minutes - parseInt(options.minuteStep, 10)); - else if(evt.keyCode === 40) newDate.setMinutes(minutes + parseInt(options.minuteStep, 10)); - // re-calculate minutes length because we have changes minutes value - minutesLength = formatDate(newDate, minutesFormat).length; - selectRange = [hoursLength + 1, hoursLength + 1 + minutesLength]; - } else if(selectedIndex === 2) { - if(!lateralMove) $timepicker.switchMeridian(); - selectRange = [hoursLength + 1 + minutesLength + 1, hoursLength + 1 + minutesLength + 3]; + $typeahead.$isVisible = function() { + if(!options.minLength || !controller) { + return !!scope.$matches.length; } - $timepicker.select(newDate, selectedIndex, true); - createSelection(selectRange[0], selectRange[1]); - parentScope.$digest(); + // minLength support + return scope.$matches.length && angular.isString(controller.$viewValue) && controller.$viewValue.length >= options.minLength; }; - // Private - - function createSelection(start, end) { - if(element[0].createTextRange) { - var selRange = element[0].createTextRange(); - selRange.collapse(true); - selRange.moveStart('character', start); - selRange.moveEnd('character', end); - selRange.select(); - } else if(element[0].setSelectionRange) { - element[0].setSelectionRange(start, end); - } else if(angular.isUndefined(element[0].selectionStart)) { - element[0].selectionStart = start; - element[0].selectionEnd = end; + $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(i < 0) return; + return i; + }; - function focusElement() { - element[0].focus(); - } + $typeahead.$onMouseDown = function(evt) { + // Prevent blur on mousedown + evt.preventDefault(); + evt.stopPropagation(); + }; - // Overrides + $typeahead.$onKeyDown = function(evt) { + if(!/(38|40|13)/.test(evt.keyCode)) return; - 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); + // Let ngSubmit pass if the typeahead tip is hidden + if($typeahead.$isVisible()) { + evt.preventDefault(); + evt.stopPropagation(); } - _init(); - }; - var _destroy = $timepicker.destroy; - $timepicker.destroy = function() { - if(isNative && options.useNative) { - element.off('click', focusElement); + // Select with enter + if(evt.keyCode === 13 && scope.$matches.length) { + $typeahead.select(scope.$activeIndex); } - _destroy(); + + // Navigate with keyboard + else if(evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--; + else if(evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++; + else if(angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0; + scope.$digest(); }; - var _show = $timepicker.show; - $timepicker.show = function() { - _show(); - // use timeout to hookup the events to prevent - // event bubbling from being processed imediately. + // Overrides + + var show = $typeahead.show; + $typeahead.show = function() { + show(); + // use timeout to hookup the events to prevent + // event bubbling from being processed imediately. $timeout(function() { - $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown); + $typeahead.$element.on('mousedown', $typeahead.$onMouseDown); if(options.keyboard) { - element.on('keydown', $timepicker.$onKeyDown); + element.on('keydown', $typeahead.$onKeyDown); } }, 0, false); }; - var _hide = $timepicker.hide; - $timepicker.hide = function(blur) { - if(!$timepicker.$isShown) return; - $timepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown); + var hide = $typeahead.hide; + $typeahead.hide = function() { + $typeahead.$element.off('mousedown', $typeahead.$onMouseDown); if(options.keyboard) { - element.off('keydown', $timepicker.$onKeyDown); + element.off('keydown', $typeahead.$onKeyDown); } - _hide(blur); + hide(); }; - return $timepicker; + return $typeahead; } - timepickerFactory.defaults = defaults; - return timepickerFactory; + TypeaheadFactory.defaults = defaults; + return TypeaheadFactory; }]; }) + .directive('bsTypeahead', ["$window", "$parse", "$q", "$typeahead", "$parseOptions", function($window, $parse, $q, $typeahead, $parseOptions) { - .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)/ig.test($window.navigator.userAgent); - var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout; + var defaults = $typeahead.defaults; return { restrict: 'EAC', @@ -4780,131 +4927,83 @@ angular.module('mgcrea.ngStrap.timepicker', [ link: function postLink(scope, element, attr, controller) { // Directive options - var options = {scope: scope, controller: controller}; - angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'timeType', 'timeFormat', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown'], function(key) { + var options = {scope: scope}; + angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'filter', 'limit', 'minLength', 'watchOptions', 'selectMode', 'comparator', 'id'], function(key) { if(angular.isDefined(attr[key])) options[key] = attr[key]; }); - // Visibility binding support - attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) { - if(!timepicker || !angular.isDefined(newValue)) return; - if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(timepicker),?/i); - newValue === true ? timepicker.show() : timepicker.hide(); - }); - - // Initialize timepicker - if(isNative && (options.useNative || defaults.useNative)) options.timeFormat = 'HH:mm'; - var timepicker = $timepicker(element, controller, options); - options = timepicker.$options; + // Build proper ngOptions + var filter = options.filter || defaults.filter; + var limit = options.limit || defaults.limit; + var comparator = options.comparator || defaults.comparator; - var lang = options.lang; - var formatDate = function(date, format) { - return $dateFormatter.formatDate(date, format, lang); - }; + var ngOptions = attr.ngOptions; + if(filter) ngOptions += ' | ' + filter + ':$viewValue'; + if (comparator) ngOptions += ':' + comparator; + if(limit) ngOptions += ' | limitTo:' + limit; + var parsedOptions = $parseOptions(ngOptions); - // Initialize parser - var dateParser = $dateParser({format: options.timeFormat, lang: lang}); + // Initialize typeahead + var typeahead = $typeahead(element, controller, options); - // Observe attributes for changes - angular.forEach(['minTime', 'maxTime'], function(key) { - // console.warn('attr.$observe(%s)', key, attr[key]); - angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) { - timepicker.$options[key] = dateParser.getTimeForAttribute(key, newValue); - !isNaN(timepicker.$options[key]) && timepicker.$build(); - validateAgainstMinMaxTime(controller.$dateValue); - }); - }); + // Watch options on demand + if(options.watchOptions) { + // Watch ngOptions values before filtering for changes, drop function calls + var watchedOptions = parsedOptions.$match[7].replace(/\|.+/, '').replace(/\(.*\)/g, '').trim(); + scope.$watch(watchedOptions, function (newValue, oldValue) { + // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue); + parsedOptions.valuesFn(scope, controller).then(function (values) { + typeahead.update(values); + controller.$render(); + }); + }, true); + } // Watch model for changes scope.$watch(attr.ngModel, function(newValue, oldValue) { - // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue, controller.$dateValue); - timepicker.update(controller.$dateValue); - }, true); - - function validateAgainstMinMaxTime(parsedTime) { - if (!angular.isDate(parsedTime)) return; - var isMinValid = isNaN(options.minTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) >= options.minTime; - var isMaxValid = isNaN(options.maxTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) <= options.maxTime; - var isValid = isMinValid && isMaxValid; - controller.$setValidity('date', isValid); - controller.$setValidity('min', isMinValid); - controller.$setValidity('max', isMaxValid); - // Only update the model when we have a valid date - if(!isValid) { + // console.warn('$watch', element.attr('ng-model'), newValue); + scope.$modelValue = newValue; // Publish modelValue on scope for custom templates + parsedOptions.valuesFn(scope, controller) + .then(function(values) { + // Prevent input with no future prospect if selectMode is truthy + // @TODO test selectMode + if(options.selectMode && !values.length && newValue.length > 0) { + controller.$setViewValue(controller.$viewValue.substring(0, controller.$viewValue.length - 1)); return; - } - controller.$dateValue = parsedTime; - } - - // viewValue -> $parsers -> modelValue - controller.$parsers.unshift(function(viewValue) { - // console.warn('$parser("%s"): viewValue=%o', element.attr('ng-model'), viewValue); - // Null values should correctly reset the model value & validity - if(!viewValue) { - // BREAKING CHANGE: - // return null (not undefined) when input value is empty, so angularjs 1.3 - // ngModelController can go ahead and run validators, like ngRequired - controller.$setValidity('date', true); - return null; - } - var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue); - if(!parsedTime || isNaN(parsedTime.getTime())) { - controller.$setValidity('date', false); - // return undefined, causes ngModelController to - // invalidate model value - return; - } else { - validateAgainstMinMaxTime(parsedTime); - } - if(options.timeType === 'string') { - return formatDate(parsedTime, options.modelTimeFormat || options.timeFormat); - } else if(options.timeType === 'number') { - return controller.$dateValue.getTime(); - } else if(options.timeType === 'unix') { - return controller.$dateValue.getTime() / 1000; - } else if(options.timeType === 'iso') { - return controller.$dateValue.toISOString(); - } else { - return new Date(controller.$dateValue); - } + } + if(values.length > limit) values = values.slice(0, limit); + var isVisible = typeahead.$isVisible(); + isVisible && typeahead.update(values); + // Do not re-queue an update if a correct value has been selected + if(values.length === 1 && values[0].value === newValue) return; + !isVisible && typeahead.update(values); + // Queue a new rendering that will leverage collection loading + controller.$render(); + }); }); // modelValue -> $formatters -> viewValue controller.$formatters.push(function(modelValue) { // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue); - var date; - if(angular.isUndefined(modelValue) || modelValue === null) { - date = NaN; - } else if(angular.isDate(modelValue)) { - date = modelValue; - } else if(options.timeType === 'string') { - date = dateParser.parse(modelValue, null, options.modelTimeFormat); - } else if(options.timeType === 'unix') { - date = new Date(modelValue * 1000); - } else { - date = new Date(modelValue); - } - // Setup default value? - // if(isNaN(date.getTime())) date = new Date(new Date().setMinutes(0) + 36e5); - controller.$dateValue = date; - return getTimeFormattedString(); + var displayValue = parsedOptions.displayValue(modelValue); + return displayValue === undefined ? '' : displayValue; }); - // viewValue -> element - controller.$render = function() { - // console.warn('$render("%s"): viewValue=%o', element.attr('ng-model'), controller.$viewValue); - element.val(getTimeFormattedString()); + // Model rendering in view + controller.$render = function () { + // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue); + 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; + element.val(selected ? selected.toString().replace(/<(?:.|\n)*?>/gm, '').trim() : ''); }; - function getTimeFormattedString() { - return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat); - } - // Garbage collection scope.$on('$destroy', function() { - if (timepicker) timepicker.destroy(); + if (typeahead) typeahead.destroy(); options = null; - timepicker = null; + typeahead = null; }); } diff --git a/dist/angular-strap.min.js b/dist/angular-strap.min.js index fbbc2cf1f..4ec9e143e 100644 --- a/dist/angular-strap.min.js +++ b/dist/angular-strap.min.js @@ -1,11 +1,11 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT */ -!function(e,t,n){"use strict";angular.module("mgcrea.ngStrap",["mgcrea.ngStrap.modal","mgcrea.ngStrap.aside","mgcrea.ngStrap.alert","mgcrea.ngStrap.button","mgcrea.ngStrap.select","mgcrea.ngStrap.datepicker","mgcrea.ngStrap.timepicker","mgcrea.ngStrap.navbar","mgcrea.ngStrap.tooltip","mgcrea.ngStrap.popover","mgcrea.ngStrap.dropdown","mgcrea.ngStrap.typeahead","mgcrea.ngStrap.scrollspy","mgcrea.ngStrap.affix","mgcrea.ngStrap.tab","mgcrea.ngStrap.collapse"]),angular.module("mgcrea.ngStrap.affix",["mgcrea.ngStrap.helpers.dimensions","mgcrea.ngStrap.helpers.debounce"]).provider("$affix",function(){var e=this.defaults={offsetTop:"auto"};this.$get=["$window","debounce","dimensions",function(t,n,a){function o(o,s){function l(e,t,n){var a=u(),o=c();return v>=a?"top":null!==e&&a+e<=t.top?"middle":null!==y&&t.top+n+$>=o-y?"bottom":"middle"}function u(){return p[0]===t?t.pageYOffset:p[0].scrollTop}function c(){return p[0]===t?t.document.body.scrollHeight:p[0].scrollHeight}var d={},f=angular.extend({},e,s),p=f.target,g="affix affix-top affix-bottom",m=!1,$=0,h=0,v=0,y=0,w=null,b=null,D=o.parent();if(f.offsetParent)if(f.offsetParent.match(/^\d+$/))for(var k=0;k<1*f.offsetParent-1;k++)D=D.parent();else D=angular.element(f.offsetParent);return d.init=function(){this.$parseOffsets(),h=a.offset(o[0]).top+$,m=!o[0].style.width,p.on("scroll",this.checkPosition),p.on("click",this.checkPositionWithEventLoop),r.on("resize",this.$debouncedOnResize),this.checkPosition(),this.checkPositionWithEventLoop()},d.destroy=function(){p.off("scroll",this.checkPosition),p.off("click",this.checkPositionWithEventLoop),r.off("resize",this.$debouncedOnResize)},d.checkPositionWithEventLoop=function(){setTimeout(d.checkPosition,1)},d.checkPosition=function(){var e=u(),t=a.offset(o[0]),n=a.height(o[0]),r=l(b,t,n);w!==r&&(w=r,o.removeClass(g).addClass("affix"+("middle"!==r?"-"+r:"")),"top"===r?(b=null,o.css("position",f.offsetParent?"":"relative"),m&&o.css("width",""),o.css("top","")):"bottom"===r?(b=f.offsetUnpin?-(1*f.offsetUnpin):t.top-e,m&&o.css("width",""),o.css("position",f.offsetParent?"":"relative"),o.css("top",f.offsetParent?"":i[0].offsetHeight-y-n-h+"px")):(b=null,m&&o.css("width",o[0].offsetWidth+"px"),o.css("position","fixed"),o.css("top",$+"px")))},d.$onResize=function(){d.$parseOffsets(),d.checkPosition()},d.$debouncedOnResize=n(d.$onResize,50),d.$parseOffsets=function(){var e=o.css("position");o.css("position",f.offsetParent?"":"relative"),f.offsetTop&&("auto"===f.offsetTop&&(f.offsetTop="+0"),f.offsetTop.match(/^[-+]\d+$/)?($=1*-f.offsetTop,v=f.offsetParent?a.offset(D[0]).top+1*f.offsetTop:a.offset(o[0]).top-a.css(o[0],"marginTop",!0)+1*f.offsetTop):v=1*f.offsetTop),f.offsetBottom&&(y=f.offsetParent&&f.offsetBottom.match(/^[-+]\d+$/)?c()-(a.offset(D[0]).top+a.height(D[0]))+1*f.offsetBottom+1:1*f.offsetBottom),o.css("position",e)},d.init(),d}var i=angular.element(t.document.body),r=angular.element(t);return o}]}).directive("bsAffix",["$affix","$window",function(e,t){return{restrict:"EAC",require:"^?bsAffixTarget",link:function(n,a,o,i){var r={scope:n,offsetTop:"auto",target:i?i.$element:angular.element(t)};angular.forEach(["offsetTop","offsetBottom","offsetParent","offsetUnpin"],function(e){angular.isDefined(o[e])&&(r[e]=o[e])});var s=e(a,r);n.$on("$destroy",function(){s&&s.destroy(),r=null,s=null})}}}]).directive("bsAffixTarget",function(){return{controller:["$element",function(e){this.$element=e}]}}),angular.module("mgcrea.ngStrap.alert",["mgcrea.ngStrap.modal"]).provider("$alert",function(){var e=this.defaults={animation:"am-fade",prefixClass:"alert",prefixEvent:"alert",placement:null,template:"alert/alert.tpl.html",container:!1,element:null,backdrop:!1,keyboard:!0,show:!0,duration:!1,type:!1,dismissable:!0};this.$get=["$modal","$timeout",function(t,n){function a(a){var o={},i=angular.extend({},e,a);o=t(i),o.$scope.dismissable=!!i.dismissable,i.type&&(o.$scope.type=i.type);var r=o.show;return i.duration&&(o.show=function(){r(),n(function(){o.hide()},1e3*i.duration)}),o}return a}]}).directive("bsAlert",["$window","$sce","$alert",function(e,t,n){e.requestAnimationFrame||e.setTimeout;return{restrict:"EAC",scope:!0,link:function(e,a,o){var i={scope:e,element:a,show:!1};angular.forEach(["template","placement","keyboard","html","container","animation","duration","dismissable"],function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),angular.forEach(["title","content","type"],function(n){o[n]&&o.$observe(n,function(a){e[n]=t.trustAsHtml(a)})}),o.bsAlert&&e.$watch(o.bsAlert,function(t){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var r=n(i);a.on(o.trigger||"click",r.toggle),e.$on("$destroy",function(){r&&r.destroy(),i=null,r=null})}}}]),angular.module("mgcrea.ngStrap.aside",["mgcrea.ngStrap.modal"]).provider("$aside",function(){var e=this.defaults={animation:"am-fade-and-slide-right",prefixClass:"aside",prefixEvent:"aside",placement:"right",template:"aside/aside.tpl.html",contentTemplate:!1,container:!1,element:null,backdrop:!0,keyboard:!0,html:!1,show:!0};this.$get=["$modal",function(t){function n(n){var a={},o=angular.extend({},e,n);return a=t(o)}return n}]}).directive("bsAside",["$window","$sce","$aside",function(e,t,n){e.requestAnimationFrame||e.setTimeout;return{restrict:"EAC",scope:!0,link:function(e,a,o){var i={scope:e,element:a,show:!1};angular.forEach(["template","contentTemplate","placement","backdrop","keyboard","html","container","animation"],function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),angular.forEach(["title","content"],function(n){o[n]&&o.$observe(n,function(a){e[n]=t.trustAsHtml(a)})}),o.bsAside&&e.$watch(o.bsAside,function(t){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var r=n(i);a.on(o.trigger||"click",r.toggle),e.$on("$destroy",function(){r&&r.destroy(),i=null,r=null})}}}]),angular.module("mgcrea.ngStrap.button",[]).provider("$button",function(){var e=this.defaults={activeClass:"active",toggleEvent:"click"};this.$get=function(){return{defaults:e}}}).directive("bsCheckboxGroup",function(){return{restrict:"A",require:"ngModel",compile:function(e,t){e.attr("data-toggle","buttons"),e.removeAttr("ng-model");var n=e[0].querySelectorAll('input[type="checkbox"]');angular.forEach(n,function(e){var n=angular.element(e);n.attr("bs-checkbox",""),n.attr("ng-model",t.ngModel+"."+n.attr("value"))})}}}).directive("bsCheckbox",["$button","$$rAF",function(e,t){var n=e.defaults,a=/^(true|false|\d+)$/;return{restrict:"A",require:"ngModel",link:function(e,o,i,r){var s=n,l="INPUT"===o[0].nodeName,u=l?o.parent():o,c=angular.isDefined(i.trueValue)?i.trueValue:!0;a.test(i.trueValue)&&(c=e.$eval(i.trueValue));var d=angular.isDefined(i.falseValue)?i.falseValue:!1;a.test(i.falseValue)&&(d=e.$eval(i.falseValue));var f="boolean"!=typeof c||"boolean"!=typeof d;f&&(r.$parsers.push(function(e){return e?c:d}),r.$formatters.push(function(e){return angular.equals(e,c)}),e.$watch(i.ngModel,function(){r.$render()})),r.$render=function(){var e=angular.equals(r.$modelValue,c);t(function(){l&&(o[0].checked=e),u.toggleClass(s.activeClass,e)})},o.bind(s.toggleEvent,function(){e.$apply(function(){l||r.$setViewValue(!u.hasClass("active")),f||r.$render()})})}}}]).directive("bsRadioGroup",function(){return{restrict:"A",require:"ngModel",compile:function(e,t){e.attr("data-toggle","buttons"),e.removeAttr("ng-model");var n=e[0].querySelectorAll('input[type="radio"]');angular.forEach(n,function(e){angular.element(e).attr("bs-radio",""),angular.element(e).attr("ng-model",t.ngModel)})}}}).directive("bsRadio",["$button","$$rAF",function(e,t){var n=e.defaults,a=/^(true|false|\d+)$/;return{restrict:"A",require:"ngModel",link:function(e,o,i,r){var s=n,l="INPUT"===o[0].nodeName,u=l?o.parent():o,c=a.test(i.value)?e.$eval(i.value):i.value;r.$render=function(){var e=angular.equals(r.$modelValue,c);t(function(){l&&(o[0].checked=e),u.toggleClass(s.activeClass,e)})},o.bind(s.toggleEvent,function(){e.$apply(function(){r.$setViewValue(c),r.$render()})})}}}]),angular.module("mgcrea.ngStrap.collapse",[]).provider("$collapse",function(){var e=this.defaults={animation:"am-collapse",disallowToggle:!1,activeClass:"in",startCollapsed:!1},t=this.controller=function(t,n,a){var o=this;o.$options=angular.copy(e),angular.forEach(["animation","disallowToggle","activeClass","startCollapsed"],function(e){angular.isDefined(a[e])&&(o.$options[e]=a[e])}),o.$toggles=[],o.$targets=[],o.$viewChangeListeners=[],o.$registerToggle=function(e){o.$toggles.push(e)},o.$registerTarget=function(e){o.$targets.push(e)},o.$unregisterToggle=function(e){var t=o.$toggles.indexOf(e);o.$toggles.splice(t,1)},o.$unregisterTarget=function(e){var t=o.$targets.indexOf(e),n=o.$targets.$active;o.$targets.splice(t,1),n>t?n--:t===n&&n===o.$targets.length&&n--,o.$setActive(n)},o.$targets.$active=o.$options.startCollapsed?-1:0,o.$setActive=t.$setActive=function(e){o.$targets.$active=o.$options.disallowToggle?e:o.$targets.$active===e?-1:e,o.$viewChangeListeners.forEach(function(e){e()})}};this.$get=function(){var n={};return n.defaults=e,n.controller=t,n}}).directive("bsCollapse",["$window","$animate","$collapse",function(e,t,n){n.defaults;return{require:["?ngModel","bsCollapse"],controller:["$scope","$element","$attrs",n.controller],link:function(e,t,n,a){var o=a[0],i=a[1];o&&(i.$viewChangeListeners.push(function(){o.$setViewValue(i.$targets.$active)}),o.$formatters.push(function(e){return i.$targets.$active!==1*e&&i.$setActive(1*e),e}))}}}]).directive("bsCollapseToggle",function(){return{require:["^?ngModel","^bsCollapse"],link:function(e,t,n,a){var o=(a[0],a[1]);t.attr("data-toggle","collapse"),o.$registerToggle(t),e.$on("$destroy",function(){o.$unregisterToggle(t)}),t.on("click",function(){var a=n.bsCollapseToggle||o.$toggles.indexOf(t);o.$setActive(1*a),e.$apply()})}}}).directive("bsCollapseTarget",["$animate",function(e){return{require:["^?ngModel","^bsCollapse"],link:function(t,n,a,o){function i(){var t=r.$targets.indexOf(n),a=r.$targets.$active;e[t===a?"addClass":"removeClass"](n,r.$options.activeClass)}var r=(o[0],o[1]);n.addClass("collapse"),r.$options.animation&&n.addClass(r.$options.animation),r.$registerTarget(n),t.$on("$destroy",function(){r.$unregisterTarget(n)}),r.$viewChangeListeners.push(function(){i()}),i()}}}]),angular.module("mgcrea.ngStrap.datepicker",["mgcrea.ngStrap.helpers.dateParser","mgcrea.ngStrap.helpers.dateFormatter","mgcrea.ngStrap.tooltip"]).provider("$datepicker",function(){var e=this.defaults={animation:"am-fade",prefixClass:"datepicker",placement:"bottom-left",template:"datepicker/datepicker.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,useNative:!1,dateType:"date",dateFormat:"shortDate",modelDateFormat:null,dayFormat:"dd",monthFormat:"MMM",yearFormat:"yyyy",monthTitleFormat:"MMMM yyyy",yearTitleFormat:"yyyy",strictFormat:!1,autoclose:!1,minDate:-1/0,maxDate:+1/0,startView:0,minView:0,startWeek:0,daysOfWeekDisabled:"",iconLeft:"glyphicon glyphicon-chevron-left",iconRight:"glyphicon glyphicon-chevron-right"};this.$get=["$window","$document","$rootScope","$sce","$dateFormatter","datepickerViews","$tooltip","$timeout",function(t,n,a,o,i,r,s,l){function u(t,n,a){function o(e){e.selected=u.$isSelected(e.date)}function i(){t[0].focus()}var u=s(t,angular.extend({},e,a)),f=a.scope,p=u.$options,g=u.$scope;p.startView&&(p.startView-=p.minView);var m=r(u);u.$views=m.views;var $=m.viewDate;g.$mode=p.startView,g.$iconLeft=p.iconLeft,g.$iconRight=p.iconRight;var h=u.$views[g.$mode];g.$select=function(e){u.select(e)},g.$selectPane=function(e){u.$selectPane(e)},g.$toggleMode=function(){u.setMode((g.$mode+1)%u.$views.length)},u.update=function(e){angular.isDate(e)&&!isNaN(e.getTime())&&(u.$date=e,h.update.call(h,e)),u.$build(!0)},u.updateDisabledDates=function(e){p.disabledDateRanges=e;for(var t=0,n=g.rows.length;n>t;t++)angular.forEach(g.rows[t],u.$setDisabledEl)},u.select=function(e,t){angular.isDate(n.$dateValue)||(n.$dateValue=new Date(e)),!g.$mode||t?(n.$setViewValue(angular.copy(e)),n.$render(),p.autoclose&&!t&&l(function(){u.hide(!0)})):(angular.extend($,{year:e.getFullYear(),month:e.getMonth(),date:e.getDate()}),u.setMode(g.$mode-1),u.$build())},u.setMode=function(e){g.$mode=e,h=u.$views[g.$mode],u.$build()},u.$build=function(e){e===!0&&h.built||(e!==!1||h.built)&&h.build.call(h)},u.$updateSelected=function(){for(var e=0,t=g.rows.length;t>e;e++)angular.forEach(g.rows[e],o)},u.$isSelected=function(e){return h.isSelected(e)},u.$setDisabledEl=function(e){e.disabled=h.isDisabled(e.date)},u.$selectPane=function(e){var t=h.steps,n=new Date(Date.UTC($.year+(t.year||0)*e,$.month+(t.month||0)*e,1));angular.extend($,{year:n.getUTCFullYear(),month:n.getUTCMonth(),date:n.getUTCDate()}),u.$build()},u.$onMouseDown=function(e){if(e.preventDefault(),e.stopPropagation(),d){var t=angular.element(e.target);"button"!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler("click")}},u.$onKeyDown=function(e){if(/(38|37|39|40|13)/.test(e.keyCode)&&!e.shiftKey&&!e.altKey){if(e.preventDefault(),e.stopPropagation(),13===e.keyCode)return g.$mode?g.$apply(function(){u.setMode(g.$mode-1)}):u.hide(!0);h.onKeyDown(e),f.$digest()}};var v=u.init;u.init=function(){return c&&p.useNative?(t.prop("type","date"),void t.css("-webkit-appearance","textfield")):(d&&(t.prop("type","text"),t.attr("readonly","true"),t.on("click",i)),void v())};var y=u.destroy;u.destroy=function(){c&&p.useNative&&t.off("click",i),y()};var w=u.show;u.show=function(){w(),l(function(){u.$element.on(d?"touchstart":"mousedown",u.$onMouseDown),p.keyboard&&t.on("keydown",u.$onKeyDown)},0,!1)};var b=u.hide;return u.hide=function(e){u.$isShown&&(u.$element.off(d?"touchstart":"mousedown",u.$onMouseDown),p.keyboard&&t.off("keydown",u.$onKeyDown),b(e))},u}var c=(angular.element(t.document.body),/(ip(a|o)d|iphone|android)/gi.test(t.navigator.userAgent)),d="createTouch"in t.document&&c;return e.lang||(e.lang=i.getDefaultLocale()),u.defaults=e,u}]}).directive("bsDatepicker",["$window","$parse","$q","$dateFormatter","$dateParser","$datepicker",function(e,t,n,a,o,i){var r=(i.defaults,/(ip(a|o)d|iphone|android)/gi.test(e.navigator.userAgent));return{restrict:"EAC",require:"ngModel",link:function(e,t,n,s){function l(e){return e&&e.length?e:null}function u(e){if(angular.isDate(e)){var t=isNaN(f.$options.minDate)||e.getTime()>=f.$options.minDate,n=isNaN(f.$options.maxDate)||e.getTime()<=f.$options.maxDate,a=t&&n;s.$setValidity("date",a),s.$setValidity("min",t),s.$setValidity("max",n),a&&(s.$dateValue=e)}}function c(){return!s.$dateValue||isNaN(s.$dateValue.getTime())?"":g(s.$dateValue,d.dateFormat)}var d={scope:e,controller:s};angular.forEach(["placement","container","delay","trigger","keyboard","html","animation","template","autoclose","dateType","dateFormat","modelDateFormat","dayFormat","strictFormat","startWeek","startDate","useNative","lang","startView","minView","iconLeft","iconRight","daysOfWeekDisabled"],function(e){angular.isDefined(n[e])&&(d[e]=n[e])}),n.bsShow&&e.$watch(n.bsShow,function(e){f&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(datepicker),?/i)),e===!0?f.show():f.hide())});var f=i(t,s,d);d=f.$options,r&&d.useNative&&(d.dateFormat="yyyy-MM-dd");var p=d.lang,g=function(e,t){return a.formatDate(e,t,p)},m=o({format:d.dateFormat,lang:p,strict:d.strictFormat});angular.forEach(["minDate","maxDate"],function(e){angular.isDefined(n[e])&&n.$observe(e,function(t){f.$options[e]=m.getDateForAttribute(e,t),!isNaN(f.$options[e])&&f.$build(!1),u(s.$dateValue)})}),e.$watch(n.ngModel,function(){f.update(s.$dateValue)},!0),angular.isDefined(n.disabledDates)&&e.$watch(n.disabledDates,function(e,t){e=l(e),t=l(t),e&&f.updateDisabledDates(e)}),s.$parsers.unshift(function(e){if(!e)return s.$setValidity("date",!0),null;var t=m.parse(e,s.$dateValue);return!t||isNaN(t.getTime())?void s.$setValidity("date",!1):(u(t),"string"===d.dateType?g(t,d.modelDateFormat||d.dateFormat):"number"===d.dateType?s.$dateValue.getTime():"unix"===d.dateType?s.$dateValue.getTime()/1e3:"iso"===d.dateType?s.$dateValue.toISOString():new Date(s.$dateValue))}),s.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:"string"===d.dateType?m.parse(e,null,d.modelDateFormat):new Date("unix"===d.dateType?1e3*e:e),s.$dateValue=t,c()}),s.$render=function(){t.val(c())},e.$on("$destroy",function(){f&&f.destroy(),d=null,f=null})}}}]).provider("datepickerViews",function(){function e(e,t){for(var n=[];e.length>0;)n.push(e.splice(0,t));return n}function t(e,t){return(e%t+t)%t}this.defaults={dayFormat:"dd",daySplit:7};this.$get=["$dateFormatter","$dateParser","$sce",function(n,a,o){return function(i){var r=i.$scope,s=i.$options,l=s.lang,u=function(e,t){return n.formatDate(e,t,l)},c=a({format:s.dateFormat,lang:l,strict:s.strictFormat}),d=n.weekdaysShort(l),f=d.slice(s.startWeek).concat(d.slice(0,s.startWeek)),p=o.trustAsHtml(''+f.join('')+""),g=i.$date||(s.startDate?c.getDateForAttribute("startDate",s.startDate):new Date),m={year:g.getFullYear(),month:g.getMonth(),date:g.getDate()},$=(6e4*g.getTimezoneOffset(),[{format:s.dayFormat,split:7,steps:{month:1},update:function(e,t){!this.built||t||e.getFullYear()!==m.year||e.getMonth()!==m.month?(angular.extend(m,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$build()):e.getDate()!==m.date&&(m.date=i.$date.getDate(),i.$updateSelected())},build:function(){var n=new Date(m.year,m.month,1),a=n.getTimezoneOffset(),o=new Date(+n-864e5*t(n.getDay()-s.startWeek,7)),l=o.getTimezoneOffset(),d=(new Date).toDateString();l!==a&&(o=new Date(+o+6e4*(l-a)));for(var f,g=[],$=0;42>$;$++)f=c.daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth(),o.getDate()+$)),g.push({date:f,isToday:f.toDateString()===d,label:u(f,this.format),selected:i.$date&&this.isSelected(f),muted:f.getMonth()!==m.month,disabled:this.isDisabled(f)});r.title=u(n,s.monthTitleFormat),r.showLabels=!0,r.labels=p,r.rows=e(g,this.split),this.built=!0},isSelected:function(e){return i.$date&&e.getFullYear()===i.$date.getFullYear()&&e.getMonth()===i.$date.getMonth()&&e.getDate()===i.$date.getDate()},isDisabled:function(e){var t=e.getTime();if(ts.maxDate)return!0;if(-1!==s.daysOfWeekDisabled.indexOf(e.getDay()))return!0;if(s.disabledDateRanges)for(var n=0;n=s.disabledDateRanges[n].start&&t<=s.disabledDateRanges[n].end)return!0;return!1},onKeyDown:function(e){if(i.$date){var t,n=i.$date.getTime();37===e.keyCode?t=new Date(n-864e5):38===e.keyCode?t=new Date(n-6048e5):39===e.keyCode?t=new Date(n+864e5):40===e.keyCode&&(t=new Date(n+6048e5)),this.isDisabled(t)||i.select(t,!0)}}},{name:"month",format:s.monthFormat,split:4,steps:{year:1},update:function(e){this.built&&e.getFullYear()===m.year?e.getMonth()!==m.month&&(angular.extend(m,{month:i.$date.getMonth(),date:i.$date.getDate()}),i.$updateSelected()):(angular.extend(m,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$build())},build:function(){for(var t,n=(new Date(m.year,0,1),[]),a=0;12>a;a++)t=new Date(m.year,a,1),n.push({date:t,label:u(t,this.format),selected:i.$isSelected(t),disabled:this.isDisabled(t)});r.title=u(t,s.yearTitleFormat),r.showLabels=!1,r.rows=e(n,this.split),this.built=!0},isSelected:function(e){return i.$date&&e.getFullYear()===i.$date.getFullYear()&&e.getMonth()===i.$date.getMonth()},isDisabled:function(e){var t=+new Date(e.getFullYear(),e.getMonth()+1,0);return ts.maxDate},onKeyDown:function(e){if(i.$date){var t=i.$date.getMonth(),n=new Date(i.$date);37===e.keyCode?n.setMonth(t-1):38===e.keyCode?n.setMonth(t-4):39===e.keyCode?n.setMonth(t+1):40===e.keyCode&&n.setMonth(t+4),this.isDisabled(n)||i.select(n,!0)}}},{name:"year",format:s.yearFormat,split:4,steps:{year:12},update:function(e,t){!this.built||t||parseInt(e.getFullYear()/20,10)!==parseInt(m.year/20,10)?(angular.extend(m,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$build()):e.getFullYear()!==m.year&&(angular.extend(m,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$updateSelected())},build:function(){for(var t,n=m.year-m.year%(3*this.split),a=[],o=0;12>o;o++)t=new Date(n+o,0,1),a.push({date:t,label:u(t,this.format),selected:i.$isSelected(t),disabled:this.isDisabled(t)});r.title=a[0].label+"-"+a[a.length-1].label,r.showLabels=!1,r.rows=e(a,this.split),this.built=!0},isSelected:function(e){return i.$date&&e.getFullYear()===i.$date.getFullYear()},isDisabled:function(e){var t=+new Date(e.getFullYear()+1,0,0);return ts.maxDate},onKeyDown:function(e){if(i.$date){var t=i.$date.getFullYear(),n=new Date(i.$date);37===e.keyCode?n.setYear(t-1):38===e.keyCode?n.setYear(t-4):39===e.keyCode?n.setYear(t+1):40===e.keyCode&&n.setYear(t+4),this.isDisabled(n)||i.select(n,!0)}}}]);return{views:s.minView?Array.prototype.slice.call($,s.minView):$,viewDate:m}}}]}),angular.module("mgcrea.ngStrap.dropdown",["mgcrea.ngStrap.tooltip"]).provider("$dropdown",function(){var e=this.defaults={animation:"am-fade",prefixClass:"dropdown",placement:"bottom-left",template:"dropdown/dropdown.tpl.html",trigger:"click",container:!1,keyboard:!0,html:!1,delay:0};this.$get=["$window","$rootScope","$tooltip","$timeout",function(t,n,a,o){function i(t,i){function l(e){return e.target!==t[0]?e.target!==t[0]&&u.hide():void 0}{var u={},c=angular.extend({},e,i);u.$scope=c.scope&&c.scope.$new()||n.$new()}u=a(t,c);var d=t.parent();u.$onKeyDown=function(e){if(/(38|40)/.test(e.keyCode)){e.preventDefault(),e.stopPropagation();var t=angular.element(u.$element[0].querySelectorAll("li:not(.divider) a"));if(t.length){var n;angular.forEach(t,function(e,t){s&&s.call(e,":focus")&&(n=t)}),38===e.keyCode&&n>0?n--:40===e.keyCode&&no;o++)if(e[o].toLowerCase()===a)return o;return-1}e.prototype.setMilliseconds=function(e){this.milliseconds=e},e.prototype.setSeconds=function(e){this.seconds=e},e.prototype.setMinutes=function(e){this.minutes=e},e.prototype.setHours=function(e){this.hours=e},e.prototype.getHours=function(){return this.hours},e.prototype.setDate=function(e){this.day=e},e.prototype.setMonth=function(e){this.month=e},e.prototype.setFullYear=function(e){this.year=e},e.prototype.fromDate=function(e){return this.year=e.getFullYear(),this.month=e.getMonth(),this.day=e.getDate(),this.hours=e.getHours(),this.minutes=e.getMinutes(),this.seconds=e.getSeconds(),this.milliseconds=e.getMilliseconds(),this},e.prototype.toDate=function(){return new Date(this.year,this.month,this.day,this.hours,this.minutes,this.seconds,this.milliseconds)};var o=e.prototype,i=this.defaults={format:"shortDate",strict:!1};this.$get=["$locale","dateFilter",function(r,s){var l=function(l){function u(e){var t,n=Object.keys(h),a=[],o=[],i=e;for(t=0;t1){var r=i.search(n[t]);e=e.split(n[t]).join(""),h[n[t]]&&(a[r]=h[n[t]])}return angular.forEach(a,function(e){e&&o.push(e)}),o}function c(e){return e.replace(/\//g,"[\\/]").replace("/-/g","[-]").replace(/\./g,"[.]").replace(/\\s/g,"[\\s]")}function d(e){var t,n=Object.keys($),a=e;for(t=0;t12?e.getHours()+2:0),e):null},m.init(),m};return l}]}]),angular.module("mgcrea.ngStrap.helpers.debounce",[]).factory("debounce",["$timeout",function(e){return function(t,n,a){var o=null;return function(){var i=this,r=arguments,s=a&&!o;return o&&e.cancel(o),o=e(function(){o=null,a||t.apply(i,r)},n,!1),s&&t.apply(i,r),o}}}]).factory("throttle",["$timeout",function(e){return function(t,n,a){var o=null;return a||(a={}),function(){var i=this,r=arguments;o||(a.leading!==!1&&t.apply(i,r),o=e(function(){o=null,a.trailing!==!1&&t.apply(i,r)},n,!1))}}}]),angular.module("mgcrea.ngStrap.helpers.dimensions",[]).factory("dimensions",["$document","$window",function(){var t=(angular.element,{}),n=t.nodeName=function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()};t.css=function(t,n,a){var o;return o=t.currentStyle?t.currentStyle[n]:e.getComputedStyle?e.getComputedStyle(t)[n]:t.style[n],a===!0?parseFloat(o)||0:o},t.offset=function(t){var n=t.getBoundingClientRect(),a=t.ownerDocument;return{width:n.width||t.offsetWidth,height:n.height||t.offsetHeight,top:n.top+(e.pageYOffset||a.documentElement.scrollTop)-(a.documentElement.clientTop||0),left:n.left+(e.pageXOffset||a.documentElement.scrollLeft)-(a.documentElement.clientLeft||0)}},t.position=function(e){var o,i,r={top:0,left:0};return"fixed"===t.css(e,"position")?i=e.getBoundingClientRect():(o=a(e),i=t.offset(e),n(o,"html")||(r=t.offset(o)),r.top+=t.css(o,"borderTopWidth",!0),r.left+=t.css(o,"borderLeftWidth",!0)),{width:e.offsetWidth,height:e.offsetHeight,top:i.top-r.top-t.css(e,"marginTop",!0),left:i.left-r.left-t.css(e,"marginLeft",!0)}};var a=function(e){var a=e.ownerDocument,o=e.offsetParent||a;if(n(o,"#document"))return a.documentElement;for(;o&&!n(o,"html")&&"static"===t.css(o,"position");)o=o.offsetParent;return o||a.documentElement};return t.height=function(e,n){var a=e.offsetHeight;return n?a+=t.css(e,"marginTop",!0)+t.css(e,"marginBottom",!0):a-=t.css(e,"paddingTop",!0)+t.css(e,"paddingBottom",!0)+t.css(e,"borderTopWidth",!0)+t.css(e,"borderBottomWidth",!0),a},t.width=function(e,n){var a=e.offsetWidth;return n?a+=t.css(e,"marginLeft",!0)+t.css(e,"marginRight",!0):a-=t.css(e,"paddingLeft",!0)+t.css(e,"paddingRight",!0)+t.css(e,"borderLeftWidth",!0)+t.css(e,"borderRightWidth",!0),a},t}]),angular.module("mgcrea.ngStrap.helpers.parseOptions",[]).provider("$parseOptions",function(){var e=this.defaults={regexp:/^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/};this.$get=["$parse","$q",function(t,n){function a(a,o){function i(e,t){return e.map(function(e,n){var a,o,i={};return i[c]=e,a=u(t,i),o=p(t,i),{label:a,value:o,index:n}})}var r={},s=angular.extend({},e,o);r.$values=[];var l,u,c,d,f,p,g;return r.init=function(){r.$match=l=a.match(s.regexp),u=t(l[2]||l[1]),c=l[4]||l[6],d=l[5],f=t(l[3]||""),p=t(l[2]?l[1]:c),g=t(l[7])},r.valuesFn=function(e,t){return n.when(g(e,t)).then(function(t){return r.$values=t?i(t,e):{},r.$values})},r.displayValue=function(e){var t={};return t[c]=e,u(t)},r.init(),r}return a}]}),angular.version.minor<3&&angular.version.dot<14&&angular.module("ng").factory("$$rAF",["$window","$timeout",function(e,t){var n=e.requestAnimationFrame||e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame,a=e.cancelAnimationFrame||e.webkitCancelAnimationFrame||e.mozCancelAnimationFrame||e.webkitCancelRequestAnimationFrame,o=!!n,i=o?function(e){var t=n(e);return function(){a(t)}}:function(e){var n=t(e,16.66,!1);return function(){t.cancel(n)}};return i.supported=o,i}]),angular.module("mgcrea.ngStrap.modal",["mgcrea.ngStrap.helpers.dimensions"]).provider("$modal",function(){var e=this.defaults={animation:"am-fade",backdropAnimation:"am-fade",prefixClass:"modal",prefixEvent:"modal",placement:"top",template:"modal/modal.tpl.html",contentTemplate:!1,container:!1,element:null,backdrop:!0,keyboard:!0,html:!1,show:!0}; -this.$get=["$window","$rootScope","$compile","$q","$templateCache","$http","$animate","$timeout","$sce","dimensions",function(n,a,o,i,r,s,l,u,c){function d(t){function n(){w.$emit(d.prefixEvent+".show",u)}function i(){w.$emit(d.prefixEvent+".hide",u),v.removeClass(d.prefixClass+"-open"),d.animation&&v.removeClass(d.prefixClass+"-with-"+d.animation)}function r(e){e.target===e.currentTarget&&("static"===d.backdrop?u.focus():u.hide())}function s(e){e.preventDefault()}var u={},d=u.$options=angular.extend({},e,t);u.$promise=g(d.template);var w=u.$scope=d.scope&&d.scope.$new()||a.$new();d.element||d.container||(d.container="body"),m(["title","content"],function(e){d[e]&&(w[e]=c.trustAsHtml(d[e]))}),w.$hide=function(){w.$$postDigest(function(){u.hide()})},w.$show=function(){w.$$postDigest(function(){u.show()})},w.$toggle=function(){w.$$postDigest(function(){u.toggle()})},u.$isShown=w.$isShown=!1,d.contentTemplate&&(u.$promise=u.$promise.then(function(e){var n=angular.element(e);return g(d.contentTemplate).then(function(e){var a=p('[ng-bind="content"]',n[0]).removeAttr("ng-bind").html(e);return t.template||a.next().remove(),n[0].outerHTML})}));var b,D,k=angular.element('
');return u.$promise.then(function(e){angular.isObject(e)&&(e=e.data),d.html&&(e=e.replace(y,'ng-bind-html="')),e=$.apply(e),b=o(e),u.init()}),u.init=function(){d.show&&w.$$postDigest(function(){u.show()})},u.destroy=function(){D&&(D.remove(),D=null),k&&(k.remove(),k=null),w.$destroy()},u.show=function(){if(!u.$isShown&&!w.$emit(d.prefixEvent+".show.before",u).defaultPrevented){var e,t;angular.isElement(d.container)?(e=d.container,t=d.container[0].lastChild?angular.element(d.container[0].lastChild):null):d.container?(e=p(d.container),t=e[0].lastChild?angular.element(e[0].lastChild):null):(e=null,t=d.element),D=u.$element=b(w,function(){}),D.css({display:"block"}).addClass(d.placement),d.animation&&(d.backdrop&&k.addClass(d.backdropAnimation),D.addClass(d.animation)),d.backdrop&&l.enter(k,v,null);var a=l.enter(D,e,t,n);a&&a.then&&a.then(n),u.$isShown=w.$isShown=!0,f(w);var o=D[0];h(function(){o.focus()}),v.addClass(d.prefixClass+"-open"),d.animation&&v.addClass(d.prefixClass+"-with-"+d.animation),d.backdrop&&(D.on("click",r),k.on("click",r),k.on("wheel",s)),d.keyboard&&D.on("keyup",u.$onKeyUp)}},u.hide=function(){if(u.$isShown&&!w.$emit(d.prefixEvent+".hide.before",u).defaultPrevented){var e=l.leave(D,i);e&&e.then&&e.then(i),d.backdrop&&l.leave(k),u.$isShown=w.$isShown=!1,f(w),d.backdrop&&(D.off("click",r),k.off("click",r),k.off("wheel",s)),d.keyboard&&D.off("keyup",u.$onKeyUp)}},u.toggle=function(){u.$isShown?u.hide():u.show()},u.focus=function(){D[0].focus()},u.$onKeyUp=function(e){27===e.which&&u.$isShown&&(u.hide(),e.stopPropagation())},u}function f(e){e.$$phase||e.$root&&e.$root.$$phase||e.$digest()}function p(e,n){return angular.element((n||t).querySelectorAll(e))}function g(e){return w[e]?w[e]:w[e]=i.when(r.get(e)||s.get(e)).then(function(t){return angular.isObject(t)?(r.put(e,t.data),t.data):t})}var m=angular.forEach,$=String.prototype.trim,h=n.requestAnimationFrame||n.setTimeout,v=angular.element(n.document.body),y=/ng-bind="/gi,w={};return d}]}).directive("bsModal",["$window","$sce","$modal",function(e,t,n){return{restrict:"EAC",scope:!0,link:function(e,a,o){var i={scope:e,element:a,show:!1};angular.forEach(["template","contentTemplate","placement","backdrop","keyboard","html","container","animation"],function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),angular.forEach(["title","content"],function(n){o[n]&&o.$observe(n,function(a){e[n]=t.trustAsHtml(a)})}),o.bsModal&&e.$watch(o.bsModal,function(t){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var r=n(i);a.on(o.trigger||"click",r.toggle),e.$on("$destroy",function(){r&&r.destroy(),i=null,r=null})}}}]),angular.module("mgcrea.ngStrap.navbar",[]).provider("$navbar",function(){var e=this.defaults={activeClass:"active",routeAttr:"data-match-route",strict:!1};this.$get=function(){return{defaults:e}}}).directive("bsNavbar",["$window","$location","$navbar",function(e,t,n){var a=n.defaults;return{restrict:"A",link:function(e,n,o){var i=angular.copy(a);angular.forEach(Object.keys(a),function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),e.$watch(function(){return t.path()},function(e){var t=n[0].querySelectorAll("li["+i.routeAttr+"]");angular.forEach(t,function(t){var n=angular.element(t),a=n.attr(i.routeAttr).replace("/","\\/");i.strict&&(a="^"+a+"$");var o=new RegExp(a,["i"]);o.test(e)?n.addClass(i.activeClass):n.removeClass(i.activeClass)})})}}}]),angular.module("mgcrea.ngStrap.popover",["mgcrea.ngStrap.tooltip"]).provider("$popover",function(){var e=this.defaults={animation:"am-fade",customClass:"",container:!1,target:!1,placement:"right",template:"popover/popover.tpl.html",contentTemplate:!1,trigger:"click",keyboard:!0,html:!1,title:"",content:"",delay:0,autoClose:!1};this.$get=["$tooltip",function(t){function n(n,a){var o=angular.extend({},e,a),i=t(n,o);return o.content&&(i.$scope.content=o.content),i}return n}]}).directive("bsPopover",["$window","$sce","$popover",function(e,t,n){var a=e.requestAnimationFrame||e.setTimeout;return{restrict:"EAC",scope:!0,link:function(e,o,i){var r={scope:e};angular.forEach(["template","contentTemplate","placement","container","target","delay","trigger","keyboard","html","animation","customClass","autoClose"],function(e){angular.isDefined(i[e])&&(r[e]=i[e])}),angular.forEach(["title","content"],function(n){i[n]&&i.$observe(n,function(o,i){e[n]=t.trustAsHtml(o),angular.isDefined(i)&&a(function(){s&&s.$applyPlacement()})})}),i.bsPopover&&e.$watch(i.bsPopover,function(t,n){angular.isObject(t)?angular.extend(e,t):e.content=t,angular.isDefined(n)&&a(function(){s&&s.$applyPlacement()})},!0),i.bsShow&&e.$watch(i.bsShow,function(e){s&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(popover),?/i)),e===!0?s.show():s.hide())});var s=n(o,r);e.$on("$destroy",function(){s&&s.destroy(),r=null,s=null})}}}]),angular.module("mgcrea.ngStrap.scrollspy",["mgcrea.ngStrap.helpers.debounce","mgcrea.ngStrap.helpers.dimensions"]).provider("$scrollspy",function(){var e=this.$$spies={},n=this.defaults={debounce:150,throttle:100,offset:100};this.$get=["$window","$document","$rootScope","dimensions","debounce","throttle",function(a,o,i,r,s,l){function u(e,t){return e[0].nodeName&&e[0].nodeName.toLowerCase()===t.toLowerCase()}function c(o){var c=angular.extend({},n,o);c.element||(c.element=p);var g=u(c.element,"body"),m=g?d:c.element,$=g?"window":c.id;if(e[$])return e[$].$$count++,e[$];var h,v,y,w,b,D,k,T,S={},x=S.$trackedElements=[],C=[];return S.init=function(){this.$$count=1,w=s(this.checkPosition,c.debounce),b=l(this.checkPosition,c.throttle),m.on("click",this.checkPositionWithEventLoop),d.on("resize",w),m.on("scroll",b),D=s(this.checkOffsets,c.debounce),h=i.$on("$viewContentLoaded",D),v=i.$on("$includeContentLoaded",D),D(),$&&(e[$]=S)},S.destroy=function(){this.$$count--,this.$$count>0||(m.off("click",this.checkPositionWithEventLoop),d.off("resize",w),m.off("scroll",b),h(),v(),$&&delete e[$])},S.checkPosition=function(){if(C.length){if(T=(g?a.pageYOffset:m.prop("scrollTop"))||0,k=Math.max(a.innerHeight,f.prop("clientHeight")),TC[e+1].offsetTop))return S.$activateElement(C[e])}},S.checkPositionWithEventLoop=function(){setTimeout(S.checkPosition,1)},S.$activateElement=function(e){if(y){var t=S.$getTrackedElement(y);t&&(t.source.removeClass("active"),u(t.source,"li")&&u(t.source.parent().parent(),"li")&&t.source.parent().parent().removeClass("active"))}y=e.target,e.source.addClass("active"),u(e.source,"li")&&u(e.source.parent().parent(),"li")&&e.source.parent().parent().addClass("active")},S.$getTrackedElement=function(e){return x.filter(function(t){return t.target===e})[0]},S.checkOffsets=function(){angular.forEach(x,function(e){var n=t.querySelector(e.target);e.offsetTop=n?r.offset(n).top:null,c.offset&&null!==e.offsetTop&&(e.offsetTop-=1*c.offset)}),C=x.filter(function(e){return null!==e.offsetTop}).sort(function(e,t){return e.offsetTop-t.offsetTop}),w()},S.trackElement=function(e,t){x.push({target:e,source:t})},S.untrackElement=function(e,t){for(var n,a=x.length;a--;)if(x[a].target===e&&x[a].source===t){n=a;break}x=x.splice(n,1)},S.activate=function(e){x[e].addClass("active")},S.init(),S}var d=angular.element(a),f=angular.element(o.prop("documentElement")),p=angular.element(a.document.body);return c}]}).directive("bsScrollspy",["$rootScope","debounce","dimensions","$scrollspy",function(e,t,n,a){return{restrict:"EAC",link:function(e,t,n){var o={scope:e};angular.forEach(["offset","target"],function(e){angular.isDefined(n[e])&&(o[e]=n[e])});var i=a(o);i.trackElement(o.target,t),e.$on("$destroy",function(){i&&(i.untrackElement(o.target,t),i.destroy()),o=null,i=null})}}}]).directive("bsScrollspyList",["$rootScope","debounce","dimensions","$scrollspy",function(){return{restrict:"A",compile:function(e){var t=e[0].querySelectorAll("li > a[href]");angular.forEach(t,function(e){var t=angular.element(e);t.parent().attr("bs-scrollspy","").attr("data-target",t.attr("href"))})}}}]),angular.module("mgcrea.ngStrap.select",["mgcrea.ngStrap.tooltip","mgcrea.ngStrap.helpers.parseOptions"]).provider("$select",function(){var e=this.defaults={animation:"am-fade",prefixClass:"select",prefixEvent:"$select",placement:"bottom-left",template:"select/select.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,multiple:!1,allNoneButtons:!1,sort:!0,caretHtml:' ',placeholder:"Choose among the following...",allText:"All",noneText:"None",maxLength:3,maxLengthHtml:"selected",iconCheckmark:"glyphicon glyphicon-ok"};this.$get=["$window","$document","$rootScope","$tooltip","$timeout",function(t,n,a,o,i){function r(t,n,a){var r={},s=angular.extend({},e,a);r=o(t,s);var u=r.$scope;u.$matches=[],u.$activeIndex=0,u.$isMultiple=s.multiple,u.$showAllNoneButtons=s.allNoneButtons&&s.multiple,u.$iconCheckmark=s.iconCheckmark,u.$allText=s.allText,u.$noneText=s.noneText,u.$activate=function(e){u.$$postDigest(function(){r.activate(e)})},u.$select=function(e){u.$$postDigest(function(){r.select(e)})},u.$isVisible=function(){return r.$isVisible()},u.$isActive=function(e){return r.$isActive(e)},u.$selectAll=function(){for(var e=0;e=u.$matches.length&&(u.$activeIndex=s.multiple?[]:0)},r.$isVisible=function(){return s.minLength&&n?u.$matches.length&&n.$viewValue.length>=s.minLength:u.$matches.length},r.$isActive=function(e){return s.multiple?-1!==u.$activeIndex.indexOf(e):u.$activeIndex===e},r.$getIndex=function(e){var t=u.$matches.length,n=t;if(t){for(n=t;n--&&u.$matches[n].value!==e;);if(!(0>n))return n}},r.$onMouseDown=function(e){if(e.preventDefault(),e.stopPropagation(),l){var t=angular.element(e.target);t.triggerHandler("click")}},r.$onKeyDown=function(e){if(/(9|13|38|40)/.test(e.keyCode)){if(e.preventDefault(),e.stopPropagation(),!s.multiple&&(13===e.keyCode||9===e.keyCode))return r.select(u.$activeIndex);38===e.keyCode&&u.$activeIndex>0?u.$activeIndex--:40===e.keyCode&&u.$activeIndex'),l.after(t)}var u=o(n.ngOptions),c=a(t,r,s),d=u.$match[7].replace(/\|.+/,"").trim();e.$watch(d,function(){u.valuesFn(e,r).then(function(e){c.update(e),r.$render()})},!0),e.$watch(n.ngModel,function(){c.$updateActiveIndex(),r.$render()},!0),r.$render=function(){var e,n;s.multiple&&angular.isArray(r.$modelValue)?(e=r.$modelValue.map(function(e){return n=c.$getIndex(e),angular.isDefined(n)?c.$scope.$matches[n].label:!1}).filter(angular.isDefined),e=e.length>(s.maxLength||i.maxLength)?e.length+" "+(s.maxLengthHtml||i.maxLengthHtml):e.join(", ")):(n=c.$getIndex(r.$modelValue),e=angular.isDefined(n)?c.$scope.$matches[n].label:!1),t.html((e?e:s.placeholder)+i.caretHtml)},s.multiple&&(r.$isEmpty=function(e){return!e||0===e.length}),e.$on("$destroy",function(){c&&c.destroy(),s=null,c=null})}}}]),angular.module("mgcrea.ngStrap.tab",[]).provider("$tab",function(){var e=this.defaults={animation:"am-fade",template:"tab/tab.tpl.html",navClass:"nav-tabs",activeClass:"active"},t=this.controller=function(t,n,a){var o=this;o.$options=angular.copy(e),angular.forEach(["animation","navClass","activeClass"],function(e){angular.isDefined(a[e])&&(o.$options[e]=a[e])}),t.$navClass=o.$options.navClass,t.$activeClass=o.$options.activeClass,o.$panes=t.$panes=[],o.$activePaneChangeListeners=o.$viewChangeListeners=[],o.$push=function(e){o.$panes.push(e)},o.$remove=function(e){var t=o.$panes.indexOf(e),n=o.$panes.$active;o.$panes.splice(t,1),n>t?n--:t===n&&n===o.$panes.length&&n--,o.$setActive(n)},o.$panes.$active=0,o.$setActive=t.$setActive=function(e){o.$panes.$active=e,o.$activePaneChangeListeners.forEach(function(e){e()})}};this.$get=function(){var n={};return n.defaults=e,n.controller=t,n}}).directive("bsTabs",["$window","$animate","$tab","$parse",function(e,t,n,a){var o=n.defaults;return{require:["?ngModel","bsTabs"],transclude:!0,scope:!0,controller:["$scope","$element","$attrs",n.controller],templateUrl:function(e,t){return t.template||o.template},link:function(e,t,n,o){var i=o[0],r=o[1];if(i&&(console.warn("Usage of ngModel is deprecated, please use bsActivePane instead!"),r.$activePaneChangeListeners.push(function(){i.$setViewValue(r.$panes.$active)}),i.$formatters.push(function(e){return r.$setActive(1*e),e})),n.bsActivePane){var s=a(n.bsActivePane);r.$activePaneChangeListeners.push(function(){s.assign(e,r.$panes.$active)}),e.$watch(n.bsActivePane,function(e){r.$setActive(1*e)},!0)}}}}]).directive("bsPane",["$window","$animate","$sce",function(e,t,n){return{require:["^?ngModel","^bsTabs"],scope:!0,link:function(e,a,o,i){function r(){var n=s.$panes.indexOf(e),o=s.$panes.$active;t[n===o?"addClass":"removeClass"](a,s.$options.activeClass)}var s=(i[0],i[1]);a.addClass("tab-pane"),o.$observe("title",function(t){e.title=n.trustAsHtml(t)}),s.$options.animation&&a.addClass(s.$options.animation),s.$push(e),e.$on("$destroy",function(){s.$remove(e)}),s.$activePaneChangeListeners.push(function(){r()}),r()}}}]),angular.module("mgcrea.ngStrap.tooltip",["mgcrea.ngStrap.helpers.dimensions"]).provider("$tooltip",function(){var e=this.defaults={animation:"am-fade",customClass:"",prefixClass:"tooltip",prefixEvent:"tooltip",container:!1,target:!1,placement:"top",template:"tooltip/tooltip.tpl.html",contentTemplate:!1,trigger:"hover focus",keyboard:!1,html:!1,show:!1,title:"",type:"",delay:0,autoClose:!1,bsEnabled:!0};this.$get=["$window","$rootScope","$compile","$q","$templateCache","$http","$animate","$sce","dimensions","$$rAF","$timeout",function(n,a,o,i,r,s,l,u,c,d,f){function p(n,i){function r(){O.$emit(P.prefixEvent+".show",F)}function s(){return O.$emit(P.prefixEvent+".hide",F),U&&"focus"===P.trigger?n[0].blur():void A()}function p(){var e=P.trigger.split(" ");angular.forEach(e,function(e){"click"===e?n.on("click",F.toggle):"manual"!==e&&(n.on("hover"===e?"mouseenter":"focus",F.enter),n.on("hover"===e?"mouseleave":"blur",F.leave),"button"===V&&"hover"!==e&&n.on(v?"touchstart":"mousedown",F.$onFocusElementMouseDown))})}function b(){for(var e=P.trigger.split(" "),t=e.length;t--;){var a=e[t];"click"===a?n.off("click",F.toggle):"manual"!==a&&(n.off("hover"===a?"mouseenter":"focus",F.enter),n.off("hover"===a?"mouseleave":"blur",F.leave),"button"===V&&"hover"!==a&&n.off(v?"touchstart":"mousedown",F.$onFocusElementMouseDown))}}function D(){"focus"!==P.trigger?R.on("keyup",F.$onKeyUp):n.on("keyup",F.$onFocusKeyUp)}function k(){"focus"!==P.trigger?R.off("keyup",F.$onKeyUp):n.off("keyup",F.$onFocusKeyUp)}function T(){f(function(){R.on("click",x),w.on("click",F.hide),W=!0},0,!1)}function S(){W&&(R.off("click",x),w.off("click",F.hide),W=!1)}function x(e){e.stopPropagation()}function C(e){e=e||P.target||n;var t=e[0],a=t.getBoundingClientRect();null===a.width&&(a=angular.extend({},a,{width:a.right-a.left,height:a.bottom-a.top}));var o;return o="body"===P.container?c.offset(t):c.position(t),angular.extend({},a,o)}function M(e,t,n,a){var o,i=e.split("-");switch(i[0]){case"right":o={top:t.top+t.height/2-a/2,left:t.left+t.width};break;case"bottom":o={top:t.top+t.height,left:t.left+t.width/2-n/2};break;case"left":o={top:t.top+t.height/2-a/2,left:t.left-n};break;default:o={top:t.top-a,left:t.left+t.width/2-n/2}}if(!i[1])return o;if("top"===i[0]||"bottom"===i[0])switch(i[1]){case"left":o.left=t.left;break;case"right":o.left=t.left+t.width-n}else if("left"===i[0]||"right"===i[0])switch(i[1]){case"top":o.top=t.top-a;break;case"bottom":o.top=t.top+t.height}return o}function E(e,t){R.css({top:e+"px",left:t+"px"})}function A(){clearTimeout(I),F.$isShown&&null!==R&&(P.autoClose&&S(),P.keyboard&&k()),K&&(K.$destroy(),K=null),R&&(R.remove(),R=F.$element=null)}var F={},V=n[0].nodeName.toLowerCase(),P=F.$options=angular.extend({},e,i);F.$promise=$(P.template);var O=F.$scope=P.scope&&P.scope.$new()||a.$new();if(P.delay&&angular.isString(P.delay)){var H=P.delay.split(",").map(parseFloat);P.delay=H.length>1?{show:H[0],hide:H[1]}:H[0]}P.title&&(O.title=u.trustAsHtml(P.title)),O.$setEnabled=function(e){O.$$postDigest(function(){F.setEnabled(e)})},O.$hide=function(){O.$$postDigest(function(){F.hide()})},O.$show=function(){O.$$postDigest(function(){F.show()})},O.$toggle=function(){O.$$postDigest(function(){F.toggle()})},F.$isShown=O.$isShown=!1;var I,N;P.contentTemplate&&(F.$promise=F.$promise.then(function(e){var t=angular.element(e);return $(P.contentTemplate).then(function(e){var n=m('[ng-bind="content"]',t[0]);return n.length||(n=m('[ng-bind="title"]',t[0])),n.removeAttr("ng-bind").html(e),t[0].outerHTML})}));var L,R,q,Y,K;F.$promise.then(function(e){angular.isObject(e)&&(e=e.data),P.html&&(e=e.replace(y,'ng-bind-html="')),e=h.apply(e),q=e,L=o(e),F.init()}),F.init=function(){P.delay&&angular.isNumber(P.delay)&&(P.delay={show:P.delay,hide:P.delay}),"self"===P.container?Y=n:angular.isElement(P.container)?Y=P.container:P.container&&(Y=m(P.container)),p(),P.target&&(P.target=angular.isElement(P.target)?P.target:m(P.target)),P.show&&O.$$postDigest(function(){"focus"===P.trigger?n[0].focus():F.show()})},F.destroy=function(){b(),A(),O.$destroy()},F.enter=function(){return clearTimeout(I),N="in",P.delay&&P.delay.show?void(I=setTimeout(function(){"in"===N&&F.show()},P.delay.show)):F.show()},F.show=function(){if(P.bsEnabled&&!F.$isShown){O.$emit(P.prefixEvent+".show.before",F);var e,t;P.container?(e=Y,t=Y[0].lastChild?angular.element(Y[0].lastChild):null):(e=null,t=n),R&&A(),K=F.$scope.$new(),R=F.$element=L(K,function(){}),R.css({top:"-9999px",left:"-9999px",display:"block",visibility:"hidden"}),P.animation&&R.addClass(P.animation),P.type&&R.addClass(P.prefixClass+"-"+P.type),P.customClass&&R.addClass(P.customClass);var a=l.enter(R,e,t,r);a&&a.then&&a.then(r),F.$isShown=O.$isShown=!0,g(O),d(function(){F.$applyPlacement(),R&&R.css({visibility:"visible"})}),P.keyboard&&("focus"!==P.trigger&&F.focus(),D()),P.autoClose&&T()}},F.leave=function(){return clearTimeout(I),N="out",P.delay&&P.delay.hide?void(I=setTimeout(function(){"out"===N&&F.hide()},P.delay.hide)):F.hide()};var U;F.hide=function(e){if(F.$isShown){O.$emit(P.prefixEvent+".hide.before",F),U=e;var t=l.leave(R,s);t&&t.then&&t.then(s),F.$isShown=O.$isShown=!1,g(O),P.keyboard&&null!==R&&k(),P.autoClose&&null!==R&&S()}},F.toggle=function(){F.$isShown?F.leave():F.enter()},F.focus=function(){R[0].focus()},F.setEnabled=function(e){P.bsEnabled=e},F.$applyPlacement=function(){if(R){var a=P.placement,o=/\s?auto?\s?/i,i=o.test(a);i&&(a=a.replace(o,"")||e.placement),R.addClass(P.placement);var r=C(),s=R.prop("offsetWidth"),l=R.prop("offsetHeight");if(i){var u=a,c=P.container?angular.element(t.querySelector(P.container)):n.parent(),d=C(c);u.indexOf("bottom")>=0&&r.bottom+l>d.bottom?a=u.replace("bottom","top"):u.indexOf("top")>=0&&r.top-ld.width?a="right"===u?"left":a.replace("left","right"):("left"===u||"bottom-right"===u||"top-right"===u)&&r.left-s=e.length&&(u.$activeIndex=0)},r.activate=function(e){u.$activeIndex=e},r.select=function(e){var t=u.$matches[e].value;n.$setViewValue(t),n.$render(),u.$resetMatches(),l&&l.$digest(),u.$emit(s.prefixEvent+".select",t,e)},r.$isVisible=function(){return s.minLength&&n?u.$matches.length&&angular.isString(n.$viewValue)&&n.$viewValue.length>=s.minLength:!!u.$matches.length},r.$getIndex=function(e){var t=u.$matches.length,n=t;if(t){for(n=t;n--&&u.$matches[n].value!==e;);if(!(0>n))return n}},r.$onMouseDown=function(e){e.preventDefault(),e.stopPropagation()},r.$onKeyDown=function(e){/(38|40|13)/.test(e.keyCode)&&(r.$isVisible()&&(e.preventDefault(),e.stopPropagation()),13===e.keyCode&&u.$matches.length?r.select(u.$activeIndex):38===e.keyCode&&u.$activeIndex>0?u.$activeIndex--:40===e.keyCode&&u.$activeIndex0)return void s.$setViewValue(s.$viewValue.substring(0,s.$viewValue.length-1));e.length>c&&(e=e.slice(0,c));var n=g.$isVisible();n&&g.update(e),(1!==e.length||e[0].value!==t)&&(!n&&g.update(e),s.$render())})}),s.$formatters.push(function(e){var t=p.displayValue(e);return t===n?"":t}),s.$render=function(){if(s.$isEmpty(s.$viewValue))return t.val("");var e=g.$getIndex(s.$modelValue),n=angular.isDefined(e)?g.$scope.$matches[e].label:s.$viewValue;n=angular.isObject(n)?p.displayValue(n):n,t.val(n?n.toString().replace(/<(?:.|\n)*?>/gm,"").trim():"")},e.$on("$destroy",function(){g&&g.destroy(),l=null,g=null})}}}]),angular.module("mgcrea.ngStrap.timepicker",["mgcrea.ngStrap.helpers.dateParser","mgcrea.ngStrap.helpers.dateFormatter","mgcrea.ngStrap.tooltip"]).provider("$timepicker",function(){var e=this.defaults={animation:"am-fade",prefixClass:"timepicker",placement:"bottom-left",template:"timepicker/timepicker.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,useNative:!0,timeType:"date",timeFormat:"shortTime",modelTimeFormat:null,autoclose:!1,minTime:-1/0,maxTime:+1/0,length:5,hourStep:1,minuteStep:5,iconUp:"glyphicon glyphicon-chevron-up",iconDown:"glyphicon glyphicon-chevron-down",arrowBehavior:"pager"};this.$get=["$window","$document","$rootScope","$sce","$dateFormatter","$tooltip","$timeout",function(t,n,a,o,i,r,s){function l(t,n,a){function o(e,n){if(t[0].createTextRange){var a=t[0].createTextRange();a.collapse(!0),a.moveStart("character",e),a.moveEnd("character",n),a.select()}else t[0].setSelectionRange?t[0].setSelectionRange(e,n):angular.isUndefined(t[0].selectionStart)&&(t[0].selectionStart=e,t[0].selectionEnd=n)}function l(){t[0].focus()}var d=r(t,angular.extend({},e,a)),f=a.scope,p=d.$options,g=d.$scope,m=p.lang,$=function(e,t){return i.formatDate(e,t,m)},h=0,v=n.$dateValue||new Date,y={hour:v.getHours(),meridian:v.getHours()<12,minute:v.getMinutes(),second:v.getSeconds(),millisecond:v.getMilliseconds()},w=i.getDatetimeFormat(p.timeFormat,m),b=i.hoursFormat(w),D=i.timeSeparator(w),k=i.minutesFormat(w),T=i.showAM(w);g.$iconUp=p.iconUp,g.$iconDown=p.iconDown,g.$select=function(e,t){d.select(e,t)},g.$moveIndex=function(e,t){d.$moveIndex(e,t)},g.$switchMeridian=function(e){d.switchMeridian(e)},d.update=function(e){angular.isDate(e)&&!isNaN(e.getTime())?(d.$date=e,angular.extend(y,{hour:e.getHours(),minute:e.getMinutes(),second:e.getSeconds(),millisecond:e.getMilliseconds()}),d.$build()):d.$isBuilt||d.$build()},d.select=function(e,t,a){(!n.$dateValue||isNaN(n.$dateValue.getTime()))&&(n.$dateValue=new Date(1970,0,1)),angular.isDate(e)||(e=new Date(e)),0===t?n.$dateValue.setHours(e.getHours()):1===t&&n.$dateValue.setMinutes(e.getMinutes()),n.$setViewValue(angular.copy(n.$dateValue)),n.$render(),p.autoclose&&!a&&s(function(){d.hide(!0)})},d.switchMeridian=function(e){if(n.$dateValue&&!isNaN(n.$dateValue.getTime())){var t=(e||n.$dateValue).getHours();n.$dateValue.setHours(12>t?t+12:t-12),n.$setViewValue(angular.copy(n.$dateValue)),n.$render()}},d.$build=function(){var e,t,n=g.midIndex=parseInt(p.length/2,10),a=[];for(e=0;e1*p.maxTime},g.$arrowAction=function(e,t){"picker"===p.arrowBehavior?d.$setTimeByStep(e,t):d.$moveIndex(e,t)},d.$setTimeByStep=function(e,t){{var n=new Date(d.$date),a=n.getHours(),o=($(n,b).length,n.getMinutes());$(n,k).length}0===t?n.setHours(a-parseInt(p.hourStep,10)*e):n.setMinutes(o-parseInt(p.minuteStep,10)*e),d.select(n,t,!0)},d.$moveIndex=function(e,t){var n;0===t?(n=new Date(1970,0,1,y.hour+e*p.length,y.minute),angular.extend(y,{hour:n.getHours()})):1===t&&(n=new Date(1970,0,1,y.hour,y.minute+e*p.length*p.minuteStep),angular.extend(y,{minute:n.getMinutes()})),d.$build()},d.$onMouseDown=function(e){if("input"!==e.target.nodeName.toLowerCase()&&e.preventDefault(),e.stopPropagation(),c){var t=angular.element(e.target);"button"!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler("click")}},d.$onKeyDown=function(e){if(/(38|37|39|40|13)/.test(e.keyCode)&&!e.shiftKey&&!e.altKey){if(e.preventDefault(),e.stopPropagation(),13===e.keyCode)return d.hide(!0); -var t=new Date(d.$date),n=t.getHours(),a=$(t,b).length,i=t.getMinutes(),r=$(t,k).length,s=/(37|39)/.test(e.keyCode),l=2+1*T;s&&(37===e.keyCode?h=1>h?l-1:h-1:39===e.keyCode&&(h=l-1>h?h+1:0));var u=[0,a];0===h?(38===e.keyCode?t.setHours(n-parseInt(p.hourStep,10)):40===e.keyCode&&t.setHours(n+parseInt(p.hourStep,10)),a=$(t,b).length,u=[0,a]):1===h?(38===e.keyCode?t.setMinutes(i-parseInt(p.minuteStep,10)):40===e.keyCode&&t.setMinutes(i+parseInt(p.minuteStep,10)),r=$(t,k).length,u=[a+1,a+1+r]):2===h&&(s||d.switchMeridian(),u=[a+1+r+1,a+1+r+3]),d.select(t,h,!0),o(u[0],u[1]),f.$digest()}};var S=d.init;d.init=function(){return u&&p.useNative?(t.prop("type","time"),void t.css("-webkit-appearance","textfield")):(c&&(t.prop("type","text"),t.attr("readonly","true"),t.on("click",l)),void S())};var x=d.destroy;d.destroy=function(){u&&p.useNative&&t.off("click",l),x()};var C=d.show;d.show=function(){C(),s(function(){d.$element.on(c?"touchstart":"mousedown",d.$onMouseDown),p.keyboard&&t.on("keydown",d.$onKeyDown)},0,!1)};var M=d.hide;return d.hide=function(e){d.$isShown&&(d.$element.off(c?"touchstart":"mousedown",d.$onMouseDown),p.keyboard&&t.off("keydown",d.$onKeyDown),M(e))},d}var u=(angular.element(t.document.body),/(ip(a|o)d|iphone|android)/gi.test(t.navigator.userAgent)),c="createTouch"in t.document&&u;return e.lang||(e.lang=i.getDefaultLocale()),l.defaults=e,l}]}).directive("bsTimepicker",["$window","$parse","$q","$dateFormatter","$dateParser","$timepicker",function(e,t,n,a,o,i){{var r=i.defaults,s=/(ip(a|o)d|iphone|android)/gi.test(e.navigator.userAgent);e.requestAnimationFrame||e.setTimeout}return{restrict:"EAC",require:"ngModel",link:function(e,t,n,l){function u(e){if(angular.isDate(e)){var t=isNaN(d.minTime)||new Date(e.getTime()).setFullYear(1970,0,1)>=d.minTime,n=isNaN(d.maxTime)||new Date(e.getTime()).setFullYear(1970,0,1)<=d.maxTime,a=t&&n;l.$setValidity("date",a),l.$setValidity("min",t),l.$setValidity("max",n),a&&(l.$dateValue=e)}}function c(){return!l.$dateValue||isNaN(l.$dateValue.getTime())?"":g(l.$dateValue,d.timeFormat)}var d={scope:e,controller:l};angular.forEach(["placement","container","delay","trigger","keyboard","html","animation","template","autoclose","timeType","timeFormat","modelTimeFormat","useNative","hourStep","minuteStep","length","arrowBehavior","iconUp","iconDown"],function(e){angular.isDefined(n[e])&&(d[e]=n[e])}),n.bsShow&&e.$watch(n.bsShow,function(e){f&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(timepicker),?/i)),e===!0?f.show():f.hide())}),s&&(d.useNative||r.useNative)&&(d.timeFormat="HH:mm");var f=i(t,l,d);d=f.$options;var p=d.lang,g=function(e,t){return a.formatDate(e,t,p)},m=o({format:d.timeFormat,lang:p});angular.forEach(["minTime","maxTime"],function(e){angular.isDefined(n[e])&&n.$observe(e,function(t){f.$options[e]=m.getTimeForAttribute(e,t),!isNaN(f.$options[e])&&f.$build(),u(l.$dateValue)})}),e.$watch(n.ngModel,function(){f.update(l.$dateValue)},!0),l.$parsers.unshift(function(e){if(!e)return l.$setValidity("date",!0),null;var t=angular.isDate(e)?e:m.parse(e,l.$dateValue);return!t||isNaN(t.getTime())?void l.$setValidity("date",!1):(u(t),"string"===d.timeType?g(t,d.modelTimeFormat||d.timeFormat):"number"===d.timeType?l.$dateValue.getTime():"unix"===d.timeType?l.$dateValue.getTime()/1e3:"iso"===d.timeType?l.$dateValue.toISOString():new Date(l.$dateValue))}),l.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:"string"===d.timeType?m.parse(e,null,d.modelTimeFormat):new Date("unix"===d.timeType?1e3*e:e),l.$dateValue=t,c()}),l.$render=function(){t.val(c())},e.$on("$destroy",function(){f&&f.destroy(),d=null,f=null})}}}])}(window,document); +!function(e,t,n){"use strict";angular.module("mgcrea.ngStrap",["mgcrea.ngStrap.modal","mgcrea.ngStrap.aside","mgcrea.ngStrap.alert","mgcrea.ngStrap.button","mgcrea.ngStrap.select","mgcrea.ngStrap.datepicker","mgcrea.ngStrap.timepicker","mgcrea.ngStrap.navbar","mgcrea.ngStrap.tooltip","mgcrea.ngStrap.popover","mgcrea.ngStrap.dropdown","mgcrea.ngStrap.typeahead","mgcrea.ngStrap.scrollspy","mgcrea.ngStrap.affix","mgcrea.ngStrap.tab","mgcrea.ngStrap.collapse"]),angular.module("mgcrea.ngStrap.affix",["mgcrea.ngStrap.helpers.dimensions","mgcrea.ngStrap.helpers.debounce"]).provider("$affix",function(){var e=this.defaults={offsetTop:"auto"};this.$get=["$window","debounce","dimensions",function(t,n,a){function o(o,s){function l(e,t,n){var a=u(),o=c();return v>=a?"top":null!==e&&a+e<=t.top?"middle":null!==y&&t.top+n+$>=o-y?"bottom":"middle"}function u(){return p[0]===t?t.pageYOffset:p[0].scrollTop}function c(){return p[0]===t?t.document.body.scrollHeight:p[0].scrollHeight}var d={},f=angular.extend({},e,s),p=f.target,g="affix affix-top affix-bottom",m=!1,$=0,h=0,v=0,y=0,w=null,b=null,D=o.parent();if(f.offsetParent)if(f.offsetParent.match(/^\d+$/))for(var k=0;k<1*f.offsetParent-1;k++)D=D.parent();else D=angular.element(f.offsetParent);return d.init=function(){this.$parseOffsets(),h=a.offset(o[0]).top+$,m=!o[0].style.width,p.on("scroll",this.checkPosition),p.on("click",this.checkPositionWithEventLoop),r.on("resize",this.$debouncedOnResize),this.checkPosition(),this.checkPositionWithEventLoop()},d.destroy=function(){p.off("scroll",this.checkPosition),p.off("click",this.checkPositionWithEventLoop),r.off("resize",this.$debouncedOnResize)},d.checkPositionWithEventLoop=function(){setTimeout(d.checkPosition,1)},d.checkPosition=function(){var e=u(),t=a.offset(o[0]),n=a.height(o[0]),r=l(b,t,n);w!==r&&(w=r,o.removeClass(g).addClass("affix"+("middle"!==r?"-"+r:"")),"top"===r?(b=null,o.css("position",f.offsetParent?"":"relative"),m&&o.css("width",""),o.css("top","")):"bottom"===r?(b=f.offsetUnpin?-(1*f.offsetUnpin):t.top-e,m&&o.css("width",""),o.css("position",f.offsetParent?"":"relative"),o.css("top",f.offsetParent?"":i[0].offsetHeight-y-n-h+"px")):(b=null,m&&o.css("width",o[0].offsetWidth+"px"),o.css("position","fixed"),o.css("top",$+"px")))},d.$onResize=function(){d.$parseOffsets(),d.checkPosition()},d.$debouncedOnResize=n(d.$onResize,50),d.$parseOffsets=function(){var e=o.css("position");o.css("position",f.offsetParent?"":"relative"),f.offsetTop&&("auto"===f.offsetTop&&(f.offsetTop="+0"),f.offsetTop.match(/^[-+]\d+$/)?($=1*-f.offsetTop,v=f.offsetParent?a.offset(D[0]).top+1*f.offsetTop:a.offset(o[0]).top-a.css(o[0],"marginTop",!0)+1*f.offsetTop):v=1*f.offsetTop),f.offsetBottom&&(y=f.offsetParent&&f.offsetBottom.match(/^[-+]\d+$/)?c()-(a.offset(D[0]).top+a.height(D[0]))+1*f.offsetBottom+1:1*f.offsetBottom),o.css("position",e)},d.init(),d}var i=angular.element(t.document.body),r=angular.element(t);return o}]}).directive("bsAffix",["$affix","$window",function(e,t){return{restrict:"EAC",require:"^?bsAffixTarget",link:function(n,a,o,i){var r={scope:n,offsetTop:"auto",target:i?i.$element:angular.element(t)};angular.forEach(["offsetTop","offsetBottom","offsetParent","offsetUnpin"],function(e){angular.isDefined(o[e])&&(r[e]=o[e])});var s=e(a,r);n.$on("$destroy",function(){s&&s.destroy(),r=null,s=null})}}}]).directive("bsAffixTarget",function(){return{controller:["$element",function(e){this.$element=e}]}}),angular.module("mgcrea.ngStrap.alert",["mgcrea.ngStrap.modal"]).provider("$alert",function(){var e=this.defaults={animation:"am-fade",prefixClass:"alert",prefixEvent:"alert",placement:null,template:"alert/alert.tpl.html",container:!1,element:null,backdrop:!1,keyboard:!0,show:!0,duration:!1,type:!1,dismissable:!0};this.$get=["$modal","$timeout",function(t,n){function a(a){var o={},i=angular.extend({},e,a);o=t(i),o.$scope.dismissable=!!i.dismissable,i.type&&(o.$scope.type=i.type);var r=o.show;return i.duration&&(o.show=function(){r(),n(function(){o.hide()},1e3*i.duration)}),o}return a}]}).directive("bsAlert",["$window","$sce","$alert",function(e,t,n){e.requestAnimationFrame||e.setTimeout;return{restrict:"EAC",scope:!0,link:function(e,a,o){var i={scope:e,element:a,show:!1};angular.forEach(["template","placement","keyboard","html","container","animation","duration","dismissable"],function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),angular.forEach(["title","content","type"],function(n){o[n]&&o.$observe(n,function(a){e[n]=t.trustAsHtml(a)})}),o.bsAlert&&e.$watch(o.bsAlert,function(t){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var r=n(i);a.on(o.trigger||"click",r.toggle),e.$on("$destroy",function(){r&&r.destroy(),i=null,r=null})}}}]),angular.module("mgcrea.ngStrap.aside",["mgcrea.ngStrap.modal"]).provider("$aside",function(){var e=this.defaults={animation:"am-fade-and-slide-right",prefixClass:"aside",prefixEvent:"aside",placement:"right",template:"aside/aside.tpl.html",contentTemplate:!1,container:!1,element:null,backdrop:!0,keyboard:!0,html:!1,show:!0};this.$get=["$modal",function(t){function n(n){var a={},o=angular.extend({},e,n);return a=t(o)}return n}]}).directive("bsAside",["$window","$sce","$aside",function(e,t,n){e.requestAnimationFrame||e.setTimeout;return{restrict:"EAC",scope:!0,link:function(e,a,o){var i={scope:e,element:a,show:!1};angular.forEach(["template","contentTemplate","placement","backdrop","keyboard","html","container","animation"],function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),angular.forEach(["title","content"],function(n){o[n]&&o.$observe(n,function(a){e[n]=t.trustAsHtml(a)})}),o.bsAside&&e.$watch(o.bsAside,function(t){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var r=n(i);a.on(o.trigger||"click",r.toggle),e.$on("$destroy",function(){r&&r.destroy(),i=null,r=null})}}}]),angular.module("mgcrea.ngStrap.button",[]).provider("$button",function(){var e=this.defaults={activeClass:"active",toggleEvent:"click"};this.$get=function(){return{defaults:e}}}).directive("bsCheckboxGroup",function(){return{restrict:"A",require:"ngModel",compile:function(e,t){e.attr("data-toggle","buttons"),e.removeAttr("ng-model");var n=e[0].querySelectorAll('input[type="checkbox"]');angular.forEach(n,function(e){var n=angular.element(e);n.attr("bs-checkbox",""),n.attr("ng-model",t.ngModel+"."+n.attr("value"))})}}}).directive("bsCheckbox",["$button","$$rAF",function(e,t){var n=e.defaults,a=/^(true|false|\d+)$/;return{restrict:"A",require:"ngModel",link:function(e,o,i,r){var s=n,l="INPUT"===o[0].nodeName,u=l?o.parent():o,c=angular.isDefined(i.trueValue)?i.trueValue:!0;a.test(i.trueValue)&&(c=e.$eval(i.trueValue));var d=angular.isDefined(i.falseValue)?i.falseValue:!1;a.test(i.falseValue)&&(d=e.$eval(i.falseValue));var f="boolean"!=typeof c||"boolean"!=typeof d;f&&(r.$parsers.push(function(e){return e?c:d}),r.$formatters.push(function(e){return angular.equals(e,c)}),e.$watch(i.ngModel,function(){r.$render()})),r.$render=function(){var e=angular.equals(r.$modelValue,c);t(function(){l&&(o[0].checked=e),u.toggleClass(s.activeClass,e)})},o.bind(s.toggleEvent,function(){e.$apply(function(){l||r.$setViewValue(!u.hasClass("active")),f||r.$render()})})}}}]).directive("bsRadioGroup",function(){return{restrict:"A",require:"ngModel",compile:function(e,t){e.attr("data-toggle","buttons"),e.removeAttr("ng-model");var n=e[0].querySelectorAll('input[type="radio"]');angular.forEach(n,function(e){angular.element(e).attr("bs-radio",""),angular.element(e).attr("ng-model",t.ngModel)})}}}).directive("bsRadio",["$button","$$rAF",function(e,t){var n=e.defaults,a=/^(true|false|\d+)$/;return{restrict:"A",require:"ngModel",link:function(e,o,i,r){var s=n,l="INPUT"===o[0].nodeName,u=l?o.parent():o,c=a.test(i.value)?e.$eval(i.value):i.value;r.$render=function(){var e=angular.equals(r.$modelValue,c);t(function(){l&&(o[0].checked=e),u.toggleClass(s.activeClass,e)})},o.bind(s.toggleEvent,function(){e.$apply(function(){r.$setViewValue(c),r.$render()})})}}}]),angular.module("mgcrea.ngStrap.collapse",[]).provider("$collapse",function(){var e=this.defaults={animation:"am-collapse",disallowToggle:!1,activeClass:"in",startCollapsed:!1,allowMultiple:!1},t=this.controller=function(t,n,a){function o(e){for(var t=l.$targets.$active,n=0;nt;t++)angular.forEach(g.rows[t],u.$setDisabledEl)},u.select=function(e,t){angular.isDate(n.$dateValue)||(n.$dateValue=new Date(e)),!g.$mode||t?(n.$setViewValue(angular.copy(e)),n.$render(),p.autoclose&&!t&&l(function(){u.hide(!0)})):(angular.extend($,{year:e.getFullYear(),month:e.getMonth(),date:e.getDate()}),u.setMode(g.$mode-1),u.$build())},u.setMode=function(e){g.$mode=e,h=u.$views[g.$mode],u.$build()},u.$build=function(e){e===!0&&h.built||(e!==!1||h.built)&&h.build.call(h)},u.$updateSelected=function(){for(var e=0,t=g.rows.length;t>e;e++)angular.forEach(g.rows[e],o)},u.$isSelected=function(e){return h.isSelected(e)},u.$setDisabledEl=function(e){e.disabled=h.isDisabled(e.date)},u.$selectPane=function(e){var t=h.steps,n=new Date(Date.UTC($.year+(t.year||0)*e,$.month+(t.month||0)*e,1));angular.extend($,{year:n.getUTCFullYear(),month:n.getUTCMonth(),date:n.getUTCDate()}),u.$build()},u.$onMouseDown=function(e){if(e.preventDefault(),e.stopPropagation(),d){var t=angular.element(e.target);"button"!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler("click")}},u.$onKeyDown=function(e){if(/(38|37|39|40|13)/.test(e.keyCode)&&!e.shiftKey&&!e.altKey){if(e.preventDefault(),e.stopPropagation(),13===e.keyCode)return g.$mode?g.$apply(function(){u.setMode(g.$mode-1)}):u.hide(!0);h.onKeyDown(e),f.$digest()}};var v=u.init;u.init=function(){return c&&p.useNative?(t.prop("type","date"),void t.css("-webkit-appearance","textfield")):(d&&(t.prop("type","text"),t.attr("readonly","true"),t.on("click",i)),void v())};var y=u.destroy;u.destroy=function(){c&&p.useNative&&t.off("click",i),y()};var w=u.show;u.show=function(){w(),l(function(){u.$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(f.$options.minDate)||e.getTime()>=f.$options.minDate,n=isNaN(f.$options.maxDate)||e.getTime()<=f.$options.maxDate,a=t&&n;s.$setValidity("date",a),s.$setValidity("min",t),s.$setValidity("max",n),a&&(s.$dateValue=e)}}function c(){return!s.$dateValue||isNaN(s.$dateValue.getTime())?"":g(s.$dateValue,d.dateFormat)}var d={scope:e,controller:s};angular.forEach(["placement","container","delay","trigger","keyboard","html","animation","template","autoclose","dateType","dateFormat","modelDateFormat","dayFormat","strictFormat","startWeek","startDate","useNative","lang","startView","minView","iconLeft","iconRight","daysOfWeekDisabled","id"],function(e){angular.isDefined(n[e])&&(d[e]=n[e])}),n.bsShow&&e.$watch(n.bsShow,function(e){f&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(datepicker),?/i)),e===!0?f.show():f.hide())});var f=i(t,s,d);d=f.$options,r&&d.useNative&&(d.dateFormat="yyyy-MM-dd");var p=d.lang,g=function(e,t){return a.formatDate(e,t,p)},m=o({format:d.dateFormat,lang:p,strict:d.strictFormat});angular.forEach(["minDate","maxDate"],function(e){angular.isDefined(n[e])&&n.$observe(e,function(t){f.$options[e]=m.getDateForAttribute(e,t),!isNaN(f.$options[e])&&f.$build(!1),u(s.$dateValue)})}),e.$watch(n.ngModel,function(){f.update(s.$dateValue)},!0),angular.isDefined(n.disabledDates)&&e.$watch(n.disabledDates,function(e,t){e=l(e),t=l(t),e&&f.updateDisabledDates(e)}),s.$parsers.unshift(function(e){if(!e)return s.$setValidity("date",!0),null;var t=m.parse(e,s.$dateValue);return!t||isNaN(t.getTime())?void s.$setValidity("date",!1):(u(t),"string"===d.dateType?g(t,d.modelDateFormat||d.dateFormat):"number"===d.dateType?s.$dateValue.getTime():"unix"===d.dateType?s.$dateValue.getTime()/1e3:"iso"===d.dateType?s.$dateValue.toISOString():new Date(s.$dateValue))}),s.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:"string"===d.dateType?m.parse(e,null,d.modelDateFormat):new Date("unix"===d.dateType?1e3*e:e),s.$dateValue=t,c()}),s.$render=function(){t.val(c())},e.$on("$destroy",function(){f&&f.destroy(),d=null,f=null})}}}]).provider("datepickerViews",function(){function e(e,t){for(var n=[];e.length>0;)n.push(e.splice(0,t));return n}function t(e,t){return(e%t+t)%t}this.defaults={dayFormat:"dd",daySplit:7};this.$get=["$dateFormatter","$dateParser","$sce",function(n,a,o){return function(i){var r=i.$scope,s=i.$options,l=s.lang,u=function(e,t){return n.formatDate(e,t,l)},c=a({format:s.dateFormat,lang:l,strict:s.strictFormat}),d=n.weekdaysShort(l),f=d.slice(s.startWeek).concat(d.slice(0,s.startWeek)),p=o.trustAsHtml(''+f.join('')+""),g=i.$date||(s.startDate?c.getDateForAttribute("startDate",s.startDate):new Date),m={year:g.getFullYear(),month:g.getMonth(),date:g.getDate()},$=(6e4*g.getTimezoneOffset(),[{format:s.dayFormat,split:7,steps:{month:1},update:function(e,t){!this.built||t||e.getFullYear()!==m.year||e.getMonth()!==m.month?(angular.extend(m,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$build()):e.getDate()!==m.date&&(m.date=i.$date.getDate(),i.$updateSelected())},build:function(){var n=new Date(m.year,m.month,1),a=n.getTimezoneOffset(),o=new Date(+n-864e5*t(n.getDay()-s.startWeek,7)),l=o.getTimezoneOffset(),d=(new Date).toDateString();l!==a&&(o=new Date(+o+6e4*(l-a)));for(var f,g=[],$=0;42>$;$++)f=c.daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth(),o.getDate()+$)),g.push({date:f,isToday:f.toDateString()===d,label:u(f,this.format),selected:i.$date&&this.isSelected(f),muted:f.getMonth()!==m.month,disabled:this.isDisabled(f)});r.title=u(n,s.monthTitleFormat),r.showLabels=!0,r.labels=p,r.rows=e(g,this.split),this.built=!0},isSelected:function(e){return i.$date&&e.getFullYear()===i.$date.getFullYear()&&e.getMonth()===i.$date.getMonth()&&e.getDate()===i.$date.getDate()},isDisabled:function(e){var t=e.getTime();if(ts.maxDate)return!0;if(-1!==s.daysOfWeekDisabled.indexOf(e.getDay()))return!0;if(s.disabledDateRanges)for(var n=0;n=s.disabledDateRanges[n].start&&t<=s.disabledDateRanges[n].end)return!0;return!1},onKeyDown:function(e){if(i.$date){var t,n=i.$date.getTime();37===e.keyCode?t=new Date(n-864e5):38===e.keyCode?t=new Date(n-6048e5):39===e.keyCode?t=new Date(n+864e5):40===e.keyCode&&(t=new Date(n+6048e5)),this.isDisabled(t)||i.select(t,!0)}}},{name:"month",format:s.monthFormat,split:4,steps:{year:1},update:function(e){this.built&&e.getFullYear()===m.year?e.getMonth()!==m.month&&(angular.extend(m,{month:i.$date.getMonth(),date:i.$date.getDate()}),i.$updateSelected()):(angular.extend(m,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$build())},build:function(){for(var t,n=(new Date(m.year,0,1),[]),a=0;12>a;a++)t=new Date(m.year,a,1),n.push({date:t,label:u(t,this.format),selected:i.$isSelected(t),disabled:this.isDisabled(t)});r.title=u(t,s.yearTitleFormat),r.showLabels=!1,r.rows=e(n,this.split),this.built=!0},isSelected:function(e){return i.$date&&e.getFullYear()===i.$date.getFullYear()&&e.getMonth()===i.$date.getMonth()},isDisabled:function(e){var t=+new Date(e.getFullYear(),e.getMonth()+1,0);return ts.maxDate},onKeyDown:function(e){if(i.$date){var t=i.$date.getMonth(),n=new Date(i.$date);37===e.keyCode?n.setMonth(t-1):38===e.keyCode?n.setMonth(t-4):39===e.keyCode?n.setMonth(t+1):40===e.keyCode&&n.setMonth(t+4),this.isDisabled(n)||i.select(n,!0)}}},{name:"year",format:s.yearFormat,split:4,steps:{year:12},update:function(e,t){!this.built||t||parseInt(e.getFullYear()/20,10)!==parseInt(m.year/20,10)?(angular.extend(m,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$build()):e.getFullYear()!==m.year&&(angular.extend(m,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$updateSelected())},build:function(){for(var t,n=m.year-m.year%(3*this.split),a=[],o=0;12>o;o++)t=new Date(n+o,0,1),a.push({date:t,label:u(t,this.format),selected:i.$isSelected(t),disabled:this.isDisabled(t)});r.title=a[0].label+"-"+a[a.length-1].label,r.showLabels=!1,r.rows=e(a,this.split),this.built=!0},isSelected:function(e){return i.$date&&e.getFullYear()===i.$date.getFullYear()},isDisabled:function(e){var t=+new Date(e.getFullYear()+1,0,0);return ts.maxDate},onKeyDown:function(e){if(i.$date){var t=i.$date.getFullYear(),n=new Date(i.$date);37===e.keyCode?n.setYear(t-1):38===e.keyCode?n.setYear(t-4):39===e.keyCode?n.setYear(t+1):40===e.keyCode&&n.setYear(t+4),this.isDisabled(n)||i.select(n,!0)}}}]);return{views:s.minView?Array.prototype.slice.call($,s.minView):$,viewDate:m}}}]}),angular.module("mgcrea.ngStrap.dropdown",["mgcrea.ngStrap.tooltip"]).provider("$dropdown",function(){var e=this.defaults={animation:"am-fade",prefixClass:"dropdown",placement:"bottom-left",template:"dropdown/dropdown.tpl.html",trigger:"click",container:!1,keyboard:!0,html:!1,delay:0};this.$get=["$window","$rootScope","$tooltip","$timeout",function(t,n,a,o){function i(t,i){function l(e){return e.target!==t[0]?e.target!==t[0]&&u.hide():void 0}{var u={},c=angular.extend({},e,i);u.$scope=c.scope&&c.scope.$new()||n.$new()}u=a(t,c);var d=t.parent();u.$onKeyDown=function(e){if(/(38|40)/.test(e.keyCode)){e.preventDefault(),e.stopPropagation();var t=angular.element(u.$element[0].querySelectorAll("li:not(.divider) a"));if(t.length){var n;angular.forEach(t,function(e,t){s&&s.call(e,":focus")&&(n=t)}),38===e.keyCode&&n>0?n--:40===e.keyCode&&no;o++)if(e[o].toLowerCase()===a)return o;return-1}e.prototype.setMilliseconds=function(e){this.milliseconds=e},e.prototype.setSeconds=function(e){this.seconds=e},e.prototype.setMinutes=function(e){this.minutes=e},e.prototype.setHours=function(e){this.hours=e},e.prototype.getHours=function(){return this.hours},e.prototype.setDate=function(e){this.day=e},e.prototype.setMonth=function(e){this.month=e},e.prototype.setFullYear=function(e){this.year=e},e.prototype.fromDate=function(e){return this.year=e.getFullYear(),this.month=e.getMonth(),this.day=e.getDate(),this.hours=e.getHours(),this.minutes=e.getMinutes(),this.seconds=e.getSeconds(),this.milliseconds=e.getMilliseconds(),this},e.prototype.toDate=function(){return new Date(this.year,this.month,this.day,this.hours,this.minutes,this.seconds,this.milliseconds)};var o=e.prototype,i=this.defaults={format:"shortDate",strict:!1};this.$get=["$locale","dateFilter",function(r,s){var l=function(l){function u(e){var t,n=Object.keys(h),a=[],o=[],i=e;for(t=0;t1){var r=i.search(n[t]);e=e.split(n[t]).join(""),h[n[t]]&&(a[r]=h[n[t]])}return angular.forEach(a,function(e){e&&o.push(e)}),o}function c(e){return e.replace(/\//g,"[\\/]").replace("/-/g","[-]").replace(/\./g,"[.]").replace(/\\s/g,"[\\s]")}function d(e){var t,n=Object.keys($),a=e;for(t=0;t12?e.getHours()+2:0),e):null},m.init(),m};return l}]}]),angular.module("mgcrea.ngStrap.helpers.debounce",[]).factory("debounce",["$timeout",function(e){return function(t,n,a){var o=null;return function(){var i=this,r=arguments,s=a&&!o;return o&&e.cancel(o),o=e(function(){o=null,a||t.apply(i,r)},n,!1),s&&t.apply(i,r),o}}}]).factory("throttle",["$timeout",function(e){return function(t,n,a){var o=null;return a||(a={}),function(){var i=this,r=arguments;o||(a.leading!==!1&&t.apply(i,r),o=e(function(){o=null,a.trailing!==!1&&t.apply(i,r)},n,!1))}}}]),angular.module("mgcrea.ngStrap.helpers.dimensions",[]).factory("dimensions",["$document","$window",function(){var t=(angular.element,{}),n=t.nodeName=function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()};t.css=function(t,n,a){var o;return o=t.currentStyle?t.currentStyle[n]:e.getComputedStyle?e.getComputedStyle(t)[n]:t.style[n],a===!0?parseFloat(o)||0:o},t.offset=function(t){var n=t.getBoundingClientRect(),a=t.ownerDocument;return{width:n.width||t.offsetWidth,height:n.height||t.offsetHeight,top:n.top+(e.pageYOffset||a.documentElement.scrollTop)-(a.documentElement.clientTop||0),left:n.left+(e.pageXOffset||a.documentElement.scrollLeft)-(a.documentElement.clientLeft||0)}},t.position=function(e){var o,i,r={top:0,left:0};return"fixed"===t.css(e,"position")?i=e.getBoundingClientRect():(o=a(e),i=t.offset(e),n(o,"html")||(r=t.offset(o)),r.top+=t.css(o,"borderTopWidth",!0),r.left+=t.css(o,"borderLeftWidth",!0)),{width:e.offsetWidth,height:e.offsetHeight,top:i.top-r.top-t.css(e,"marginTop",!0),left:i.left-r.left-t.css(e,"marginLeft",!0)}};var a=function(e){var a=e.ownerDocument,o=e.offsetParent||a;if(n(o,"#document"))return a.documentElement;for(;o&&!n(o,"html")&&"static"===t.css(o,"position");)o=o.offsetParent;return o||a.documentElement};return t.height=function(e,n){var a=e.offsetHeight;return n?a+=t.css(e,"marginTop",!0)+t.css(e,"marginBottom",!0):a-=t.css(e,"paddingTop",!0)+t.css(e,"paddingBottom",!0)+t.css(e,"borderTopWidth",!0)+t.css(e,"borderBottomWidth",!0),a},t.width=function(e,n){var a=e.offsetWidth;return n?a+=t.css(e,"marginLeft",!0)+t.css(e,"marginRight",!0):a-=t.css(e,"paddingLeft",!0)+t.css(e,"paddingRight",!0)+t.css(e,"borderLeftWidth",!0)+t.css(e,"borderRightWidth",!0),a},t}]),angular.module("mgcrea.ngStrap.helpers.parseOptions",[]).provider("$parseOptions",function(){var e=this.defaults={regexp:/^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/};this.$get=["$parse","$q",function(t,n){function a(a,o){function i(e,t){return e.map(function(e,n){var a,o,i={};return i[c]=e,a=u(t,i),o=p(t,i),{label:a,value:o,index:n}})}var r={},s=angular.extend({},e,o);r.$values=[];var l,u,c,d,f,p,g;return r.init=function(){r.$match=l=a.match(s.regexp),u=t(l[2]||l[1]),c=l[4]||l[6],d=l[5],f=t(l[3]||""),p=t(l[2]?l[1]:c),g=t(l[7])},r.valuesFn=function(e,t){return n.when(g(e,t)).then(function(t){return r.$values=t?i(t,e):{},r.$values +})},r.displayValue=function(e){var t={};return t[c]=e,u(t)},r.init(),r}return a}]}),angular.version.minor<3&&angular.version.dot<14&&angular.module("ng").factory("$$rAF",["$window","$timeout",function(e,t){var n=e.requestAnimationFrame||e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame,a=e.cancelAnimationFrame||e.webkitCancelAnimationFrame||e.mozCancelAnimationFrame||e.webkitCancelRequestAnimationFrame,o=!!n,i=o?function(e){var t=n(e);return function(){a(t)}}:function(e){var n=t(e,16.66,!1);return function(){t.cancel(n)}};return i.supported=o,i}]),angular.module("mgcrea.ngStrap.modal",["mgcrea.ngStrap.helpers.dimensions"]).provider("$modal",function(){var e=this.defaults={animation:"am-fade",backdropAnimation:"am-fade",prefixClass:"modal",prefixEvent:"modal",placement:"top",template:"modal/modal.tpl.html",contentTemplate:!1,container:!1,element:null,backdrop:!0,keyboard:!0,html:!1,show:!0};this.$get=["$window","$rootScope","$compile","$q","$templateCache","$http","$animate","$timeout","$sce","dimensions",function(n,a,o,i,r,s,l,u,c){function d(t){function n(){w.$emit(d.prefixEvent+".show",u)}function i(){w.$emit(d.prefixEvent+".hide",u),v.removeClass(d.prefixClass+"-open"),d.animation&&v.removeClass(d.prefixClass+"-with-"+d.animation)}function r(e){e.target===e.currentTarget&&("static"===d.backdrop?u.focus():u.hide())}function s(e){e.preventDefault()}var u={},d=u.$options=angular.extend({},e,t);u.$promise=g(d.template);var w=u.$scope=d.scope&&d.scope.$new()||a.$new();d.element||d.container||(d.container="body"),u.$id=d.id||d.element&&d.element.attr("id")||"",m(["title","content"],function(e){d[e]&&(w[e]=c.trustAsHtml(d[e]))}),w.$hide=function(){w.$$postDigest(function(){u.hide()})},w.$show=function(){w.$$postDigest(function(){u.show()})},w.$toggle=function(){w.$$postDigest(function(){u.toggle()})},u.$isShown=w.$isShown=!1,d.contentTemplate&&(u.$promise=u.$promise.then(function(e){var n=angular.element(e);return g(d.contentTemplate).then(function(e){var a=p('[ng-bind="content"]',n[0]).removeAttr("ng-bind").html(e);return t.template||a.next().remove(),n[0].outerHTML})}));var b,D,k=angular.element('
');return u.$promise.then(function(e){angular.isObject(e)&&(e=e.data),d.html&&(e=e.replace(y,'ng-bind-html="')),e=$.apply(e),b=o(e),u.init()}),u.init=function(){d.show&&w.$$postDigest(function(){u.show()})},u.destroy=function(){D&&(D.remove(),D=null),k&&(k.remove(),k=null),w.$destroy()},u.show=function(){if(!u.$isShown&&!w.$emit(d.prefixEvent+".show.before",u).defaultPrevented){var e,t;angular.isElement(d.container)?(e=d.container,t=d.container[0].lastChild?angular.element(d.container[0].lastChild):null):d.container?(e=p(d.container),t=e[0].lastChild?angular.element(e[0].lastChild):null):(e=null,t=d.element),D=u.$element=b(w,function(){}),D.css({display:"block"}).addClass(d.placement),d.animation&&(d.backdrop&&k.addClass(d.backdropAnimation),D.addClass(d.animation)),d.backdrop&&l.enter(k,v,null);var a=l.enter(D,e,t,n);a&&a.then&&a.then(n),u.$isShown=w.$isShown=!0,f(w);var o=D[0];h(function(){o.focus()}),v.addClass(d.prefixClass+"-open"),d.animation&&v.addClass(d.prefixClass+"-with-"+d.animation),d.backdrop&&(D.on("click",r),k.on("click",r),k.on("wheel",s)),d.keyboard&&D.on("keyup",u.$onKeyUp)}},u.hide=function(){if(u.$isShown&&!w.$emit(d.prefixEvent+".hide.before",u).defaultPrevented){var e=l.leave(D,i);e&&e.then&&e.then(i),d.backdrop&&l.leave(k),u.$isShown=w.$isShown=!1,f(w),d.backdrop&&(D.off("click",r),k.off("click",r),k.off("wheel",s)),d.keyboard&&D.off("keyup",u.$onKeyUp)}},u.toggle=function(){u.$isShown?u.hide():u.show()},u.focus=function(){D[0].focus()},u.$onKeyUp=function(e){27===e.which&&u.$isShown&&(u.hide(),e.stopPropagation())},u}function f(e){e.$$phase||e.$root&&e.$root.$$phase||e.$digest()}function p(e,n){return angular.element((n||t).querySelectorAll(e))}function g(e){return w[e]?w[e]:w[e]=i.when(r.get(e)||s.get(e)).then(function(t){return angular.isObject(t)?(r.put(e,t.data),t.data):t})}var m=angular.forEach,$=String.prototype.trim,h=n.requestAnimationFrame||n.setTimeout,v=angular.element(n.document.body),y=/ng-bind="/gi,w={};return d}]}).directive("bsModal",["$window","$sce","$modal",function(e,t,n){return{restrict:"EAC",scope:!0,link:function(e,a,o){var i={scope:e,element:a,show:!1};angular.forEach(["template","contentTemplate","placement","backdrop","keyboard","html","container","animation","id"],function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),angular.forEach(["title","content"],function(n){o[n]&&o.$observe(n,function(a){e[n]=t.trustAsHtml(a)})}),o.bsModal&&e.$watch(o.bsModal,function(t){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var r=n(i);a.on(o.trigger||"click",r.toggle),e.$on("$destroy",function(){r&&r.destroy(),i=null,r=null})}}}]),angular.module("mgcrea.ngStrap.navbar",[]).provider("$navbar",function(){var e=this.defaults={activeClass:"active",routeAttr:"data-match-route",strict:!1};this.$get=function(){return{defaults:e}}}).directive("bsNavbar",["$window","$location","$navbar",function(e,t,n){var a=n.defaults;return{restrict:"A",link:function(e,n,o){var i=angular.copy(a);angular.forEach(Object.keys(a),function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),e.$watch(function(){return t.path()},function(e){var t=n[0].querySelectorAll("li["+i.routeAttr+"]");angular.forEach(t,function(t){var n=angular.element(t),a=n.attr(i.routeAttr).replace("/","\\/");i.strict&&(a="^"+a+"$");var o=new RegExp(a,["i"]);o.test(e)?n.addClass(i.activeClass):n.removeClass(i.activeClass)})})}}}]),angular.module("mgcrea.ngStrap.popover",["mgcrea.ngStrap.tooltip"]).provider("$popover",function(){var e=this.defaults={animation:"am-fade",customClass:"",container:!1,target:!1,placement:"right",template:"popover/popover.tpl.html",contentTemplate:!1,trigger:"click",keyboard:!0,html:!1,title:"",content:"",delay:0,autoClose:!1};this.$get=["$tooltip",function(t){function n(n,a){var o=angular.extend({},e,a),i=t(n,o);return o.content&&(i.$scope.content=o.content),i}return n}]}).directive("bsPopover",["$window","$sce","$popover",function(e,t,n){var a=e.requestAnimationFrame||e.setTimeout;return{restrict:"EAC",scope:!0,link:function(e,o,i){var r={scope:e};angular.forEach(["template","contentTemplate","placement","container","target","delay","trigger","keyboard","html","animation","customClass","autoClose","id"],function(e){angular.isDefined(i[e])&&(r[e]=i[e])}),angular.forEach(["title","content"],function(n){i[n]&&i.$observe(n,function(o,i){e[n]=t.trustAsHtml(o),angular.isDefined(i)&&a(function(){s&&s.$applyPlacement()})})}),i.bsPopover&&e.$watch(i.bsPopover,function(t,n){angular.isObject(t)?angular.extend(e,t):e.content=t,angular.isDefined(n)&&a(function(){s&&s.$applyPlacement()})},!0),i.bsShow&&e.$watch(i.bsShow,function(e){s&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(popover),?/i)),e===!0?s.show():s.hide())});var s=n(o,r);e.$on("$destroy",function(){s&&s.destroy(),r=null,s=null})}}}]),angular.module("mgcrea.ngStrap.select",["mgcrea.ngStrap.tooltip","mgcrea.ngStrap.helpers.parseOptions"]).provider("$select",function(){var e=this.defaults={animation:"am-fade",prefixClass:"select",prefixEvent:"$select",placement:"bottom-left",template:"select/select.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,multiple:!1,allNoneButtons:!1,sort:!0,caretHtml:' ',placeholder:"Choose among the following...",allText:"All",noneText:"None",maxLength:3,maxLengthHtml:"selected",iconCheckmark:"glyphicon glyphicon-ok"};this.$get=["$window","$document","$rootScope","$tooltip","$timeout",function(t,n,a,o,i){function r(t,n,a){var r={},s=angular.extend({},e,a);r=o(t,s);var u=r.$scope;u.$matches=[],u.$activeIndex=0,u.$isMultiple=s.multiple,u.$showAllNoneButtons=s.allNoneButtons&&s.multiple,u.$iconCheckmark=s.iconCheckmark,u.$allText=s.allText,u.$noneText=s.noneText,u.$activate=function(e){u.$$postDigest(function(){r.activate(e)})},u.$select=function(e){u.$$postDigest(function(){r.select(e)})},u.$isVisible=function(){return r.$isVisible()},u.$isActive=function(e){return r.$isActive(e)},u.$selectAll=function(){for(var e=0;e=u.$matches.length&&(u.$activeIndex=s.multiple?[]:0)},r.$isVisible=function(){return s.minLength&&n?u.$matches.length&&n.$viewValue.length>=s.minLength:u.$matches.length},r.$isActive=function(e){return s.multiple?-1!==u.$activeIndex.indexOf(e):u.$activeIndex===e},r.$getIndex=function(e){var t=u.$matches.length,n=t;if(t){for(n=t;n--&&u.$matches[n].value!==e;);if(!(0>n))return n}},r.$onMouseDown=function(e){if(e.preventDefault(),e.stopPropagation(),l){var t=angular.element(e.target);t.triggerHandler("click")}},r.$onKeyDown=function(e){if(/(9|13|38|40)/.test(e.keyCode)){if(e.preventDefault(),e.stopPropagation(),!s.multiple&&(13===e.keyCode||9===e.keyCode))return r.select(u.$activeIndex);38===e.keyCode&&u.$activeIndex>0?u.$activeIndex--:40===e.keyCode&&u.$activeIndex'),l.after(t)}var u=o(n.ngOptions),c=a(t,r,s),d=u.$match[7].replace(/\|.+/,"").trim();e.$watch(d,function(){u.valuesFn(e,r).then(function(e){c.update(e),r.$render()})},!0),e.$watch(n.ngModel,function(){c.$updateActiveIndex(),r.$render()},!0),r.$render=function(){var e,n;s.multiple&&angular.isArray(r.$modelValue)?(e=r.$modelValue.map(function(e){return n=c.$getIndex(e),angular.isDefined(n)?c.$scope.$matches[n].label:!1}).filter(angular.isDefined),e=e.length>(s.maxLength||i.maxLength)?e.length+" "+(s.maxLengthHtml||i.maxLengthHtml):e.join(", ")):(n=c.$getIndex(r.$modelValue),e=angular.isDefined(n)?c.$scope.$matches[n].label:!1),t.html((e?e:s.placeholder)+i.caretHtml)},s.multiple&&(r.$isEmpty=function(e){return!e||0===e.length}),e.$on("$destroy",function(){c&&c.destroy(),s=null,c=null})}}}]),angular.module("mgcrea.ngStrap.tab",[]).provider("$tab",function(){var e=this.defaults={animation:"am-fade",template:"tab/tab.tpl.html",navClass:"nav-tabs",activeClass:"active"},t=this.controller=function(t,n,a){var o=this;o.$options=angular.copy(e),angular.forEach(["animation","navClass","activeClass"],function(e){angular.isDefined(a[e])&&(o.$options[e]=a[e])}),t.$navClass=o.$options.navClass,t.$activeClass=o.$options.activeClass,o.$panes=t.$panes=[],o.$activePaneChangeListeners=o.$viewChangeListeners=[],o.$push=function(e){o.$panes.push(e)},o.$remove=function(e){var t=o.$panes.indexOf(e),n=o.$panes.$active;o.$panes.splice(t,1),n>t?n--:t===n&&n===o.$panes.length&&n--,o.$setActive(n)},o.$panes.$active=0,o.$setActive=t.$setActive=function(e){o.$panes.$active=e,o.$activePaneChangeListeners.forEach(function(e){e()})}};this.$get=function(){var n={};return n.defaults=e,n.controller=t,n}}).directive("bsTabs",["$window","$animate","$tab","$parse",function(e,t,n,a){var o=n.defaults;return{require:["?ngModel","bsTabs"],transclude:!0,scope:!0,controller:["$scope","$element","$attrs",n.controller],templateUrl:function(e,t){return t.template||o.template},link:function(e,t,n,o){var i=o[0],r=o[1];if(i&&(console.warn("Usage of ngModel is deprecated, please use bsActivePane instead!"),r.$activePaneChangeListeners.push(function(){i.$setViewValue(r.$panes.$active)}),i.$formatters.push(function(e){return r.$setActive(1*e),e})),n.bsActivePane){var s=a(n.bsActivePane);r.$activePaneChangeListeners.push(function(){s.assign(e,r.$panes.$active)}),e.$watch(n.bsActivePane,function(e){r.$setActive(1*e)},!0)}}}}]).directive("bsPane",["$window","$animate","$sce",function(e,t,n){return{require:["^?ngModel","^bsTabs"],scope:!0,link:function(e,a,o,i){function r(){var n=s.$panes.indexOf(e),o=s.$panes.$active;t[n===o?"addClass":"removeClass"](a,s.$options.activeClass)}var s=(i[0],i[1]);a.addClass("tab-pane"),o.$observe("title",function(t){e.title=n.trustAsHtml(t)}),s.$options.animation&&a.addClass(s.$options.animation),s.$push(e),e.$on("$destroy",function(){s.$remove(e)}),s.$activePaneChangeListeners.push(function(){r()}),r()}}}]),angular.module("mgcrea.ngStrap.scrollspy",["mgcrea.ngStrap.helpers.debounce","mgcrea.ngStrap.helpers.dimensions"]).provider("$scrollspy",function(){var e=this.$$spies={},n=this.defaults={debounce:150,throttle:100,offset:100};this.$get=["$window","$document","$rootScope","dimensions","debounce","throttle",function(a,o,i,r,s,l){function u(e,t){return e[0].nodeName&&e[0].nodeName.toLowerCase()===t.toLowerCase()}function c(o){var c=angular.extend({},n,o);c.element||(c.element=p);var g=u(c.element,"body"),m=g?d:c.element,$=g?"window":c.id;if(e[$])return e[$].$$count++,e[$];var h,v,y,w,b,D,k,T,S={},x=S.$trackedElements=[],C=[];return S.init=function(){this.$$count=1,w=s(this.checkPosition,c.debounce),b=l(this.checkPosition,c.throttle),m.on("click",this.checkPositionWithEventLoop),d.on("resize",w),m.on("scroll",b),D=s(this.checkOffsets,c.debounce),h=i.$on("$viewContentLoaded",D),v=i.$on("$includeContentLoaded",D),D(),$&&(e[$]=S)},S.destroy=function(){this.$$count--,this.$$count>0||(m.off("click",this.checkPositionWithEventLoop),d.off("resize",w),m.off("scroll",b),h(),v(),$&&delete e[$])},S.checkPosition=function(){if(C.length){if(T=(g?a.pageYOffset:m.prop("scrollTop"))||0,k=Math.max(a.innerHeight,f.prop("clientHeight")),TC[e+1].offsetTop))return S.$activateElement(C[e])}},S.checkPositionWithEventLoop=function(){setTimeout(S.checkPosition,1)},S.$activateElement=function(e){if(y){var t=S.$getTrackedElement(y);t&&(t.source.removeClass("active"),u(t.source,"li")&&u(t.source.parent().parent(),"li")&&t.source.parent().parent().removeClass("active"))}y=e.target,e.source.addClass("active"),u(e.source,"li")&&u(e.source.parent().parent(),"li")&&e.source.parent().parent().addClass("active")},S.$getTrackedElement=function(e){return x.filter(function(t){return t.target===e})[0]},S.checkOffsets=function(){angular.forEach(x,function(e){var n=t.querySelector(e.target);e.offsetTop=n?r.offset(n).top:null,c.offset&&null!==e.offsetTop&&(e.offsetTop-=1*c.offset)}),C=x.filter(function(e){return null!==e.offsetTop}).sort(function(e,t){return e.offsetTop-t.offsetTop}),w()},S.trackElement=function(e,t){x.push({target:e,source:t})},S.untrackElement=function(e,t){for(var n,a=x.length;a--;)if(x[a].target===e&&x[a].source===t){n=a;break}x=x.splice(n,1)},S.activate=function(e){x[e].addClass("active")},S.init(),S}var d=angular.element(a),f=angular.element(o.prop("documentElement")),p=angular.element(a.document.body);return c}]}).directive("bsScrollspy",["$rootScope","debounce","dimensions","$scrollspy",function(e,t,n,a){return{restrict:"EAC",link:function(e,t,n){var o={scope:e};angular.forEach(["offset","target"],function(e){angular.isDefined(n[e])&&(o[e]=n[e])});var i=a(o);i.trackElement(o.target,t),e.$on("$destroy",function(){i&&(i.untrackElement(o.target,t),i.destroy()),o=null,i=null})}}}]).directive("bsScrollspyList",["$rootScope","debounce","dimensions","$scrollspy",function(){return{restrict:"A",compile:function(e){var t=e[0].querySelectorAll("li > a[href]");angular.forEach(t,function(e){var t=angular.element(e);t.parent().attr("bs-scrollspy","").attr("data-target",t.attr("href"))})}}}]),angular.module("mgcrea.ngStrap.timepicker",["mgcrea.ngStrap.helpers.dateParser","mgcrea.ngStrap.helpers.dateFormatter","mgcrea.ngStrap.tooltip"]).provider("$timepicker",function(){var e=this.defaults={animation:"am-fade",prefixClass:"timepicker",placement:"bottom-left",template:"timepicker/timepicker.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,useNative:!0,timeType:"date",timeFormat:"shortTime",modelTimeFormat:null,autoclose:!1,minTime:-1/0,maxTime:+1/0,length:5,hourStep:1,minuteStep:5,iconUp:"glyphicon glyphicon-chevron-up",iconDown:"glyphicon glyphicon-chevron-down",arrowBehavior:"pager"};this.$get=["$window","$document","$rootScope","$sce","$dateFormatter","$tooltip","$timeout",function(t,n,a,o,i,r,s){function l(t,n,a){function o(e,n){if(t[0].createTextRange){var a=t[0].createTextRange();a.collapse(!0),a.moveStart("character",e),a.moveEnd("character",n),a.select()}else t[0].setSelectionRange?t[0].setSelectionRange(e,n):angular.isUndefined(t[0].selectionStart)&&(t[0].selectionStart=e,t[0].selectionEnd=n)}function l(){t[0].focus()}var d=r(t,angular.extend({},e,a)),f=a.scope,p=d.$options,g=d.$scope,m=p.lang,$=function(e,t){return i.formatDate(e,t,m)},h=0,v=n.$dateValue||new Date,y={hour:v.getHours(),meridian:v.getHours()<12,minute:v.getMinutes(),second:v.getSeconds(),millisecond:v.getMilliseconds()},w=i.getDatetimeFormat(p.timeFormat,m),b=i.hoursFormat(w),D=i.timeSeparator(w),k=i.minutesFormat(w),T=i.showAM(w);g.$iconUp=p.iconUp,g.$iconDown=p.iconDown,g.$select=function(e,t){d.select(e,t)},g.$moveIndex=function(e,t){d.$moveIndex(e,t)},g.$switchMeridian=function(e){d.switchMeridian(e)},d.update=function(e){angular.isDate(e)&&!isNaN(e.getTime())?(d.$date=e,angular.extend(y,{hour:e.getHours(),minute:e.getMinutes(),second:e.getSeconds(),millisecond:e.getMilliseconds()}),d.$build()):d.$isBuilt||d.$build()},d.select=function(e,t,a){(!n.$dateValue||isNaN(n.$dateValue.getTime()))&&(n.$dateValue=new Date(1970,0,1)),angular.isDate(e)||(e=new Date(e)),0===t?n.$dateValue.setHours(e.getHours()):1===t&&n.$dateValue.setMinutes(e.getMinutes()),n.$setViewValue(angular.copy(n.$dateValue)),n.$render(),p.autoclose&&!a&&s(function(){d.hide(!0)})},d.switchMeridian=function(e){if(n.$dateValue&&!isNaN(n.$dateValue.getTime())){var t=(e||n.$dateValue).getHours();n.$dateValue.setHours(12>t?t+12:t-12),n.$setViewValue(angular.copy(n.$dateValue)),n.$render()}},d.$build=function(){var e,t,n=g.midIndex=parseInt(p.length/2,10),a=[];for(e=0;e1*p.maxTime},g.$arrowAction=function(e,t){"picker"===p.arrowBehavior?d.$setTimeByStep(e,t):d.$moveIndex(e,t)},d.$setTimeByStep=function(e,t){{var n=new Date(d.$date),a=n.getHours(),o=($(n,b).length,n.getMinutes());$(n,k).length}0===t?n.setHours(a-parseInt(p.hourStep,10)*e):n.setMinutes(o-parseInt(p.minuteStep,10)*e),d.select(n,t,!0)},d.$moveIndex=function(e,t){var n;0===t?(n=new Date(1970,0,1,y.hour+e*p.length,y.minute),angular.extend(y,{hour:n.getHours()})):1===t&&(n=new Date(1970,0,1,y.hour,y.minute+e*p.length*p.minuteStep),angular.extend(y,{minute:n.getMinutes()})),d.$build()},d.$onMouseDown=function(e){if("input"!==e.target.nodeName.toLowerCase()&&e.preventDefault(),e.stopPropagation(),c){var t=angular.element(e.target);"button"!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler("click")}},d.$onKeyDown=function(e){if(/(38|37|39|40|13)/.test(e.keyCode)&&!e.shiftKey&&!e.altKey){if(e.preventDefault(),e.stopPropagation(),13===e.keyCode)return d.hide(!0);var t=new Date(d.$date),n=t.getHours(),a=$(t,b).length,i=t.getMinutes(),r=$(t,k).length,s=/(37|39)/.test(e.keyCode),l=2+1*T;s&&(37===e.keyCode?h=1>h?l-1:h-1:39===e.keyCode&&(h=l-1>h?h+1:0));var u=[0,a];0===h?(38===e.keyCode?t.setHours(n-parseInt(p.hourStep,10)):40===e.keyCode&&t.setHours(n+parseInt(p.hourStep,10)),a=$(t,b).length,u=[0,a]):1===h?(38===e.keyCode?t.setMinutes(i-parseInt(p.minuteStep,10)):40===e.keyCode&&t.setMinutes(i+parseInt(p.minuteStep,10)),r=$(t,k).length,u=[a+1,a+1+r]):2===h&&(s||d.switchMeridian(),u=[a+1+r+1,a+1+r+3]),d.select(t,h,!0),o(u[0],u[1]),f.$digest()}};var S=d.init;d.init=function(){return u&&p.useNative?(t.prop("type","time"),void t.css("-webkit-appearance","textfield")):(c&&(t.prop("type","text"),t.attr("readonly","true"),t.on("click",l)),void S())};var x=d.destroy;d.destroy=function(){u&&p.useNative&&t.off("click",l),x()};var C=d.show;d.show=function(){C(),s(function(){d.$element.on(c?"touchstart":"mousedown",d.$onMouseDown),p.keyboard&&t.on("keydown",d.$onKeyDown)},0,!1)};var M=d.hide;return d.hide=function(e){d.$isShown&&(d.$element.off(c?"touchstart":"mousedown",d.$onMouseDown),p.keyboard&&t.off("keydown",d.$onKeyDown),M(e))},d}var u=(angular.element(t.document.body),/(ip(a|o)d|iphone|android)/gi.test(t.navigator.userAgent)),c="createTouch"in t.document&&u;return e.lang||(e.lang=i.getDefaultLocale()),l.defaults=e,l}]}).directive("bsTimepicker",["$window","$parse","$q","$dateFormatter","$dateParser","$timepicker",function(e,t,n,a,o,i){{var r=i.defaults,s=/(ip(a|o)d|iphone|android)/gi.test(e.navigator.userAgent);e.requestAnimationFrame||e.setTimeout}return{restrict:"EAC",require:"ngModel",link:function(e,t,n,l){function u(e){if(angular.isDate(e)){var t=isNaN(d.minTime)||new Date(e.getTime()).setFullYear(1970,0,1)>=d.minTime,n=isNaN(d.maxTime)||new Date(e.getTime()).setFullYear(1970,0,1)<=d.maxTime,a=t&&n;l.$setValidity("date",a),l.$setValidity("min",t),l.$setValidity("max",n),a&&(l.$dateValue=e)}}function c(){return!l.$dateValue||isNaN(l.$dateValue.getTime())?"":g(l.$dateValue,d.timeFormat)}var d={scope:e,controller:l};angular.forEach(["placement","container","delay","trigger","keyboard","html","animation","template","autoclose","timeType","timeFormat","modelTimeFormat","useNative","hourStep","minuteStep","length","arrowBehavior","iconUp","iconDown","id"],function(e){angular.isDefined(n[e])&&(d[e]=n[e])}),n.bsShow&&e.$watch(n.bsShow,function(e){f&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(timepicker),?/i)),e===!0?f.show():f.hide())}),s&&(d.useNative||r.useNative)&&(d.timeFormat="HH:mm");var f=i(t,l,d);d=f.$options;var p=d.lang,g=function(e,t){return a.formatDate(e,t,p)},m=o({format:d.timeFormat,lang:p});angular.forEach(["minTime","maxTime"],function(e){angular.isDefined(n[e])&&n.$observe(e,function(t){f.$options[e]=m.getTimeForAttribute(e,t),!isNaN(f.$options[e])&&f.$build(),u(l.$dateValue)})}),e.$watch(n.ngModel,function(){f.update(l.$dateValue)},!0),l.$parsers.unshift(function(e){if(!e)return l.$setValidity("date",!0),null;var t=angular.isDate(e)?e:m.parse(e,l.$dateValue);return!t||isNaN(t.getTime())?void l.$setValidity("date",!1):(u(t),"string"===d.timeType?g(t,d.modelTimeFormat||d.timeFormat):"number"===d.timeType?l.$dateValue.getTime():"unix"===d.timeType?l.$dateValue.getTime()/1e3:"iso"===d.timeType?l.$dateValue.toISOString():new Date(l.$dateValue))}),l.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:"string"===d.timeType?m.parse(e,null,d.modelTimeFormat):new Date("unix"===d.timeType?1e3*e:e),l.$dateValue=t,c()}),l.$render=function(){t.val(c())},e.$on("$destroy",function(){f&&f.destroy(),d=null,f=null})}}}]),angular.module("mgcrea.ngStrap.tooltip",["mgcrea.ngStrap.helpers.dimensions"]).provider("$tooltip",function(){var e=this.defaults={animation:"am-fade",customClass:"",prefixClass:"tooltip",prefixEvent:"tooltip",container:!1,target:!1,placement:"top",template:"tooltip/tooltip.tpl.html",contentTemplate:!1,trigger:"hover focus",keyboard:!1,html:!1,show:!1,title:"",type:"",delay:0,autoClose:!1,bsEnabled:!0};this.$get=["$window","$rootScope","$compile","$q","$templateCache","$http","$animate","$sce","dimensions","$$rAF","$timeout",function(n,a,o,i,r,s,l,u,c,d,f){function p(n,i){function r(){O.$emit(P.prefixEvent+".show",F)}function s(){if(O.$emit(P.prefixEvent+".hide",F),R===W){if(U&&"focus"===P.trigger)return n[0].blur();A()}}function p(){var e=P.trigger.split(" ");angular.forEach(e,function(e){"click"===e?n.on("click",F.toggle):"manual"!==e&&(n.on("hover"===e?"mouseenter":"focus",F.enter),n.on("hover"===e?"mouseleave":"blur",F.leave),"button"===V&&"hover"!==e&&n.on(v?"touchstart":"mousedown",F.$onFocusElementMouseDown))})}function b(){for(var e=P.trigger.split(" "),t=e.length;t--;){var a=e[t];"click"===a?n.off("click",F.toggle):"manual"!==a&&(n.off("hover"===a?"mouseenter":"focus",F.enter),n.off("hover"===a?"mouseleave":"blur",F.leave),"button"===V&&"hover"!==a&&n.off(v?"touchstart":"mousedown",F.$onFocusElementMouseDown))}}function D(){"focus"!==P.trigger?R.on("keyup",F.$onKeyUp):n.on("keyup",F.$onFocusKeyUp)}function k(){"focus"!==P.trigger?R.off("keyup",F.$onKeyUp):n.off("keyup",F.$onFocusKeyUp)}function T(){f(function(){R.on("click",x),w.on("click",F.hide),j=!0},0,!1)}function S(){j&&(R.off("click",x),w.off("click",F.hide),j=!1)}function x(e){e.stopPropagation()}function C(e){e=e||P.target||n;var t=e[0],a=t.getBoundingClientRect();null===a.width&&(a=angular.extend({},a,{width:a.right-a.left,height:a.bottom-a.top}));var o;return o="body"===P.container?c.offset(t):c.position(t),angular.extend({},a,o)}function M(e,t,n,a){var o,i=e.split("-");switch(i[0]){case"right":o={top:t.top+t.height/2-a/2,left:t.left+t.width};break;case"bottom":o={top:t.top+t.height,left:t.left+t.width/2-n/2};break;case"left":o={top:t.top+t.height/2-a/2,left:t.left-n};break;default:o={top:t.top-a,left:t.left+t.width/2-n/2}}if(!i[1])return o;if("top"===i[0]||"bottom"===i[0])switch(i[1]){case"left":o.left=t.left;break;case"right":o.left=t.left+t.width-n}else if("left"===i[0]||"right"===i[0])switch(i[1]){case"top":o.top=t.top-a;break;case"bottom":o.top=t.top+t.height}return o}function E(e,t){R.css({top:e+"px",left:t+"px"})}function A(){clearTimeout(H),F.$isShown&&null!==R&&(P.autoClose&&S(),P.keyboard&&k()),K&&(K.$destroy(),K=null),R&&(R.remove(),R=F.$element=null)}var F={},V=n[0].nodeName.toLowerCase(),P=F.$options=angular.extend({},e,i);F.$promise=$(P.template);var O=F.$scope=P.scope&&P.scope.$new()||a.$new();if(P.delay&&angular.isString(P.delay)){var I=P.delay.split(",").map(parseFloat);P.delay=I.length>1?{show:I[0],hide:I[1]}:I[0]}F.$id=P.id||n.attr("id")||"",P.title&&(O.title=u.trustAsHtml(P.title)),O.$setEnabled=function(e){O.$$postDigest(function(){F.setEnabled(e)})},O.$hide=function(){O.$$postDigest(function(){F.hide()})},O.$show=function(){O.$$postDigest(function(){F.show()})},O.$toggle=function(){O.$$postDigest(function(){F.toggle()})},F.$isShown=O.$isShown=!1;var H,N;P.contentTemplate&&(F.$promise=F.$promise.then(function(e){var t=angular.element(e);return $(P.contentTemplate).then(function(e){var n=m('[ng-bind="content"]',t[0]);return n.length||(n=m('[ng-bind="title"]',t[0])),n.removeAttr("ng-bind").html(e),t[0].outerHTML})}));var L,R,q,Y,K;F.$promise.then(function(e){angular.isObject(e)&&(e=e.data),P.html&&(e=e.replace(y,'ng-bind-html="')),e=h.apply(e),q=e,L=o(e),F.init()}),F.init=function(){P.delay&&angular.isNumber(P.delay)&&(P.delay={show:P.delay,hide:P.delay}),"self"===P.container?Y=n:angular.isElement(P.container)?Y=P.container:P.container&&(Y=m(P.container)),p(),P.target&&(P.target=angular.isElement(P.target)?P.target:m(P.target)),P.show&&O.$$postDigest(function(){"focus"===P.trigger?n[0].focus():F.show()})},F.destroy=function(){b(),A(),O.$destroy()},F.enter=function(){return clearTimeout(H),N="in",P.delay&&P.delay.show?void(H=setTimeout(function(){"in"===N&&F.show()},P.delay.show)):F.show()},F.show=function(){if(P.bsEnabled&&!F.$isShown){O.$emit(P.prefixEvent+".show.before",F);var e,t;P.container?(e=Y,t=Y[0].lastChild?angular.element(Y[0].lastChild):null):(e=null,t=n),R&&A(),K=F.$scope.$new(),R=F.$element=L(K,function(){}),R.css({top:"-9999px",left:"-9999px",display:"block",visibility:"hidden"}),P.animation&&R.addClass(P.animation),P.type&&R.addClass(P.prefixClass+"-"+P.type),P.customClass&&R.addClass(P.customClass);var a=l.enter(R,e,t,r);a&&a.then&&a.then(r),F.$isShown=O.$isShown=!0,g(O),d(function(){F.$applyPlacement(),R&&R.css({visibility:"visible"})}),P.keyboard&&("focus"!==P.trigger&&F.focus(),D()),P.autoClose&&T()}},F.leave=function(){return clearTimeout(H),N="out",P.delay&&P.delay.hide?void(H=setTimeout(function(){"out"===N&&F.hide()},P.delay.hide)):F.hide()};var U,W;F.hide=function(e){if(F.$isShown){O.$emit(P.prefixEvent+".hide.before",F),U=e,W=R;var t=l.leave(R,s);t&&t.then&&t.then(s),F.$isShown=O.$isShown=!1,g(O),P.keyboard&&null!==R&&k(),P.autoClose&&null!==R&&S()}},F.toggle=function(){F.$isShown?F.leave():F.enter()},F.focus=function(){R[0].focus()},F.setEnabled=function(e){P.bsEnabled=e},F.$applyPlacement=function(){if(R){var a=P.placement,o=/\s?auto?\s?/i,i=o.test(a);i&&(a=a.replace(o,"")||e.placement),R.addClass(P.placement);var r=C(),s=R.prop("offsetWidth"),l=R.prop("offsetHeight");if(i){var u=a,c=P.container?angular.element(t.querySelector(P.container)):n.parent(),d=C(c);u.indexOf("bottom")>=0&&r.bottom+l>d.bottom?a=u.replace("bottom","top"):u.indexOf("top")>=0&&r.top-ld.width?a="right"===u?"left":a.replace("left","right"):("left"===u||"bottom-right"===u||"top-right"===u)&&r.left-s=e.length&&(u.$activeIndex=0)},r.activate=function(e){u.$activeIndex=e},r.select=function(e){var t=u.$matches[e].value;n.$setViewValue(t),n.$render(),u.$resetMatches(),l&&l.$digest(),u.$emit(s.prefixEvent+".select",t,e,r)},r.$isVisible=function(){return s.minLength&&n?u.$matches.length&&angular.isString(n.$viewValue)&&n.$viewValue.length>=s.minLength:!!u.$matches.length},r.$getIndex=function(e){var t=u.$matches.length,n=t;if(t){for(n=t;n--&&u.$matches[n].value!==e;);if(!(0>n))return n}},r.$onMouseDown=function(e){e.preventDefault(),e.stopPropagation()},r.$onKeyDown=function(e){/(38|40|13)/.test(e.keyCode)&&(r.$isVisible()&&(e.preventDefault(),e.stopPropagation()),13===e.keyCode&&u.$matches.length?r.select(u.$activeIndex):38===e.keyCode&&u.$activeIndex>0?u.$activeIndex--:40===e.keyCode&&u.$activeIndex0)return void s.$setViewValue(s.$viewValue.substring(0,s.$viewValue.length-1));e.length>c&&(e=e.slice(0,c));var n=g.$isVisible();n&&g.update(e),(1!==e.length||e[0].value!==t)&&(!n&&g.update(e),s.$render())})}),s.$formatters.push(function(e){var t=p.displayValue(e);return t===n?"":t}),s.$render=function(){if(s.$isEmpty(s.$viewValue))return t.val("");var e=g.$getIndex(s.$modelValue),n=angular.isDefined(e)?g.$scope.$matches[e].label:s.$viewValue;n=angular.isObject(n)?p.displayValue(n):n,t.val(n?n.toString().replace(/<(?:.|\n)*?>/gm,"").trim():"")},e.$on("$destroy",function(){g&&g.destroy(),l=null,g=null})}}}])}(window,document); //# sourceMappingURL=angular-strap.min.js.map \ No newline at end of file diff --git a/dist/angular-strap.min.js.map b/dist/angular-strap.min.js.map index 23a9007d2..94d507af9 100644 --- a/dist/angular-strap.min.js.map +++ b/dist/angular-strap.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["module.js","affix/affix.js","alert/alert.js","aside/aside.js","button/button.js","collapse/collapse.js","datepicker/datepicker.js","dropdown/dropdown.js","helpers/date-formatter.js","helpers/date-parser.js","helpers/debounce.js","helpers/dimensions.js","helpers/parse-options.js","helpers/raf.js","modal/modal.js","navbar/navbar.js","popover/popover.js","scrollspy/scrollspy.js","select/select.js","tab/tab.js","tooltip/tooltip.js","typeahead/typeahead.js","timepicker/timepicker.js"],"names":[],"mappings":"UAOE,EAAA,EAAA,wBAGA,OAAA,kBACA,uBACA,uBACA,uBACA,wBACA,wBACA,4BACA,6ECjBF,mDAEA,sIAQI,OAAK,wBAAA,oCAAyB,6CAExB,SAAS,gCAGb,UAAS,6FAwKH,GAAO,EAAA,EAAA,MAEP,GAAO,MACF,oDAMe,OAAf,GAAe,EAAA,IAAA,EAAA,GAAA,EAAA,EACf,kBAOT,QAAO,KACP,MAAO,GAAA,KAAA,EAAA,EAAA,YAAA,EAAA,GAAA,uBAIT,MAAO,GAAA,KAAA,EAAA,EAAA,SAAA,KAAA,aAAA,EAAA,GAAA,gBApLD,MAGA,EAAA,QAAY,UAAA,EAAA,GACZ,EAAA,EAAe,wCAIf,GAAS,MAET,EAAQ,EACV,EAAY,EACV,EAAa,IACX,cAGC,EAAA,iGAKP,EAAc,EAAA,aAIZ,GAAW,QAAC,QAAW,EAAM,uBAI7B,KAAY,kMAaZ,KAAA,gBACA,KAAA,qIASA,EAAA,IAAW,SAAO,KAAA,qBAIpB,EAAO,2BAA2B,WAIhC,WAAI,EAAW,cAAkB,MAI7B,cAAQ,WAGZ,GAAG,GAAY,IACf,EAAU,EAAA,OAAA,EAAA,+BAOR,KAAY,MACT,IAGH,YAAY,GAAO,SAAA,SAAA,WAAA,EAAA,IAAA,EAAA,KAEf,QAAJ,KACE,2EAKA,IAAQ,MAAS,mBAGjB,EADC,EAAA,cACoB,EAAb,EAAI,aAKN,EAAA,IAAA,EAEN,qBAGF,EAAQ,IAAI,WAAO,EAAkB,aAAA,GAAA,oFAKzC,EAAO,IAAA,QAAY,EAAW,GAAA,YAAA,MAE5B,EAAO,IAAA,WAAA,uDAOP,EAAA,qCAGK,mBAAQ,EAAsB,EAAA,UAAA,kCAGjC,GAAW,EAAgB,IAAA,cAEtB,IAAA,WAAQ,EAAc,aAAA,GAAA,0BAGpB,WAAA,cACH,UAAY,wCAGX,GAAA,EAAA,YACH,EAAA,8CAIO,EAAc,OAAA,EAAA,IAAA,IAAA,EAAA,IAAA,EAAA,GAAA,aAAA,GAAA,EAAA,EAAA,6CAWzB,oDAAY,KAAY,EAAA,OAAA,EAAA,IAAA,IAAA,EAAA,OAAA,EAAA,KAAA,EAAA,EAAA,aAAA,oBAQxB,EAAI,IAAA,WAAe,kBA9JrB,GAAI,QAAU,QAAQ,EAAW,SAAU,MAC3C,EAAI,QAAW,QAAQ,EAgM3B,OAAO,iBAMH,WAAiB,SAAA,UAAa,SAAgB,EAAA,iCAI1C,uBACJ,SAAsB,EAAA,EAAW,EAAA,MAE/B,IAAU,MAAA,EAAA,UAAA,OAAA,OAAA,EAAA,EAAA,SAAA,QAAA,QAAA,YACV,SAAQ,YAAA,eAAA,eAAA,eAAA,SAAA,yGAQf,EAAU,wHC7NP,OAAA,wBAAW,kCAEX,SAAW,cAEX,GAAU,KAAA,UACV,UAAU,UACV,YAAM,4BAEN,UAAU,KACV,SAAM,uBACN,WAAA,2BAGF,UAAK,4BAIG,6EAQJ,GAAA,wCAQE,OAAO,cAAkB,EAAA,cACvB,SACA,OAAS,KAAA,EAAW,uCAMxB,EAAO,KAAA,sCAIF,IAAA,EAAA,cAQT,MAAI,sEAQsB,EAAO,uBAAwB,EAAA,kEAQjD,IAAM,MAAY,EAAA,QAAY,EAAA,MAAA,0KAM7B,SAAQ,QAAS,UAAW,QAAA,SAAA,KAC7B,IAAQ,EAAO,SAAO,EAAA,SAAA,KACjB,GAAA,EAAA,YAAA,iDAML,QAAQ,SAAO,uBAGnB,EAAQ,QAAQ,UAKd,GAAU,EAAA,iEAOf,GAAA,EAAA,UChHL,EAAA,2BAUM,OAAA,wBAAW,kCAEX,SAAA,cAEA,GAAS,KAAA,UACT,UAAU,0BACV,YAAU,QACV,YAAM,QACN,UAAM,2DAGR,WAAK,eAEH,UAAS,oBAEH,kEAWN,EAAO,QAAA,UAAA,EAAA,iBAQT,MAAI,sEAQiB,EAAY,uBAAmB,EAAa,+CAK7D,SAAiB,EAAS,EAAY,MAElC,IAAM,MAAY,EAAA,QAAY,EAAA,MAAA,8KAM7B,SAAQ,QAAS,WAAW,SAAA,KAC7B,IAAQ,EAAO,SAAO,EAAA,SAAA,KACjB,GAAA,EAAA,YAAA,iDAML,QAAQ,SAAO,uBAGnB,EAAQ,QAAQ,UAKd,GAAU,EAAA,iEAOf,GAAA,EAAA,UCxFL,EAAA,uEAYM,UAAQ,yEAOV,MAAA,KAAO,WACL,OAAA,SAAU,gBAKJ,kBAAmB,2BAGrB,YACA,+NAQP,EAAU,KAAA,WAAA,EAAA,QAAc,IAAA,EAAS,KAAS,0BAQjC,cAAS,UAAgB,QAAS,SAAM,EAAY,MAExD,GAAI,EAAU,gDAIV,2BAEA,SAAY,EAAQ,EAAU,EAAK,MAErC,GAAY,EAGX,EAA8B,UAA9B,EAAA,GAAoB,SACrB,EAAa,EAAY,EAAK,SAAA,wEAIhC,EAAI,EAAA,MAAkB,EAAO,eAE3B,GAAW,QAAS,UAAK,EAAS,YAAW,EAAA,YAAA,2BAEpC,EAAA,MAAY,EAAA,4FAQrB,MAAM,GAAY,EAAS,gEAQ3B,EAAI,OAAA,EAAW,QAAQ,WACvB,EAAM,kCAOR,GAAA,GAAa,QAAQ,OAAA,EAAa,YAAW,EAC3C,GAAM,+BAEJ,EAAa,YAAA,EAAA,YAAA,sIAuBb,eAAW,2BAGb,6NAQP,QAAU,QAAA,GAAA,KAAA,WAAW,EAAS,yBAQrB,WAAS,UAAS,QAAO,SAAe,EAAA,MAE5C,GAAI,EAAU,gDAIV,2BAEA,SAAQ,EAAA,EAAyB,EAAK,WAKxC,EAA8B,UAA1B,EAAW,GAAQ,SACvB,EAAiB,EAAA,EAAA,SAAA,EAEf,EAAA,EAA0B,KAAA,EAAQ,OAAa,EAAA,MAAA,EAAA,OAAA,EAAA,2BAKnD,GAAA,GAAa,QAAQ,OAAA,EAAa,YAAW,EAC3C,GAAM,+BAEJ,EAAW,YAAc,EAAA,YAAA,6EAShC,EAAA,2BC/JC,OAAA,iEAIA,GAAW,KAAA,oDAGX,YAAK,KACL,gBAAgB,qCAIhB,GAAA,GAAK,IAGL,GAAK,SAAA,QAAA,KAAuB,6FAEvB,QAAA,UAAkB,EAAA,MAAS,EAAS,SAAA,GAAA,EAAA,MAGzC,EAAK,cACH,wCAIA,gBAAiB,SAAS,qDAI5B,EAAK,SAAA,KAAA,oJAUD,EAAA,EAAA,SAAA,+BAKA,EAAA,MAKC,IAAS,GAAgB,IAAS,EAAiB,SAAK,QAGzD,MAEA,WAAc,MAGd,SAAA,QAAA,EAAA,SAAA,eAAA,GAAA,mHAOJ,EAAI,qBAAY,QAAA,SAAA,GAChB,6BAOH,GAAA,0BAEC,EAAI,WAAqB,gFAQjB,EAAiB,8GAKnB,SAAe,EAAA,EAAqB,EAAK,oBAKzC,OAGI,qBAA0B,KAAA,4SAiClB,gBAAM,kJAUzB,EAAU,yBAQD,oBAAiB,WAAY,SAAA,mBAGzB,YAAS,mDAwBjB,GAAA,GAAA,EAAA,SAAA,QAAA,2FApBU,EAAS,QAInB,GAAA,SAAe,YAGf,EAAU,SAAY,WACpB,EAAA,SAAe,EAAA,SAAkB,aAIrB,gBAAe,wDAahC,EAAA,qBAAA,KAAA,WC5LL,MAEQ,iBAQF,OAAA,4IAKA,cAAW,cAEX,GAAM,KAAA,UACN,UAAO,mCAEP,UAAW,cACX,SAAU,iCACV,QAAA,QACA,WAAA,EACA,UAAA,EACA,MAAA,EACA,MAAA,EAEA,WAAA,EACA,SAAA,OACA,WAAW,YACX,gBAAU,KACV,UAAU,KACV,YAAW,MACX,WAAS,OACT,iBAAW,YACX,gBAAA,OACA,cAAU,EACV,WAAW,4BAGb,UAAK,YAEH,UAAI,EACJ,mBAAe,GACf,SAAI,mCACJ,UAAI,sPAyJG,OACD,GAAQ,QA9IZ,GAAI,GAAc,EAAA,EAAgB,QAAA,UAAA,EAAA,IAClC,EAAY,EAAS,MACjB,EAAA,EAAW,SACf,EAAM,EAAgB,MACtB,GAAM,YAAY,EAAQ,WAAA,EAAA,oCAM1B,IAAA,GAAM,EAAmB,WACvB,MAAY,EAAO,iCAErB,EAAM,WAAA,EAAc,aAClB,GAAY,EAAY,OAAA,EAAA,oEAQ1B,EAAY,YAAS,MAEhB,YAAe,aAChB,SAAY,EAAQ,MAAA,GAAA,EAAA,OAAA,8BAOxB,QAAY,OAAA,KAAA,MAAsB,EAAA,aAChC,EAAQ,MAAA,EACR,EAAQ,OAAO,KAAI,EAAW,oDAO9B,EAAI,mBAAe,CACnB,KAAI,GAAA,GAAM,EAAA,EAAS,EAAM,KAAA,OAAA,EAAA,EAAA,IACvB,QAAA,QAAW,EAAA,KAAc,GAAA,EAAa,wCAMtC,QAAQ,OAAO,EAAW,cAAW,EAAe,WAAY,GAAA,MAAA,KAChE,EAAA,OAAY,GACZ,EAAA,cAAY,QAAA,KAAA,6DAMd,QAAM,OAAQ,GAAA,KAAA,EAAA,cAAA,MAAA,EAAA,WAAA,KAAA,EAAA,YACd,EAAU,QAAY,EAAA,MAAa,GACnC,EAAY,2CAOZ,EAAG,EAAa,OAAQ,EAAQ,OAChC,EAAG,YAKK,OAAW,SAAM,yHAS3B,QAAY,QAAA,EAAA,KAAiB,GAAA,IAI7B,EAAY,YAAc,SAAS,GACjC,MAAI,GAAQ,WAAQ,iCAIpB,EAAA,SAAI,EAAiB,WAAU,EAAI,+CAQ/B,EAAA,GAAA,MAAA,KAAA,IAAA,EAAA,MAAA,EAAA,MAAA,GAAA,EAAA,EAAA,OAAA,EAAA,OAAA,GAAA,EAAA,0FAEJ,EAAY,YAGR,aAAoB,SAAA,QAEtB,wCAIJ,GAAA,GAAY,QAAa,QAAS,EAAK,OACJ,YAA5B,EAAA,GAAA,SAAmB,gBACpB,EAAA,EAAA,wCAMK,WAAA,SAAA,MACL,mBAAoB,KAAA,EAAA,WAAa,EAAY,WAAQ,EAAM,iEAK/D,MAAA,GAAQ,iDACR,EAAY,MAAA,mCAuBV,GAAQ,EAAK,OACL,KAAG,kCAEb,EAAA,KAAA,OAAA,uDAGE,IACJ,EAAY,KAAA,OAAU,QACpB,EAAG,KAAY,WAAQ,QACrB,EAAQ,GAAA,QAAI,QAEd,MAGF,IAAI,GAAQ,EAAY,OACxB,GAAY,QAAO,WACjB,GAAA,EAAA,4BAGA,WAGI,EAAW,2BAKjB,EAAI,WACJ,EAAY,SAAO,GAAS,EAAM,aAAA,YAAA,EAAA,cAC5B,EAAA,UACJ,EAAY,GAAA,UAAa,EAAU,aAEjC,GAAA,2CAKJ,EAAO,+GAKT,EAAO,UAnML,IADI,QAAc,QAAO,EAAA,SAAA,MACrB,8BAAsB,KAAA,EAAA,UAAA,YAC1B,EAAY,eAAY,GAAA,UAAA,CA0M5B,OAzMI,GAAW,OAAA,EAAW,KAAQ,EAAa,iCAyM3C,gBAMI,gBAAkB,UAAO,SAAS,KAAM,iBAAY,cAAA,cAAA,SAAA,EAAA,EAAA,EAAA,EAAA,EAAA,MAGxD,eAAI,8BAAqC,KAAA,EAAA,UAAA,mFAqDrC,GAAgB,sBAEZ,qBAeN,GAAG,QAAS,OAAA,GAAZ,qIAIF,GAAW,aAAS,OAAQ,mDAIxB,IAAA,EAAW,WAAqB,YAkElC,2FAxIA,IAAW,MAAS,EAAA,WAAW,WAC/B,SAAa,YAAO,YAAoB,QAAA,UAAW,WAAA,OAAA,YAAA,WAAA,YAAA,WAAA,aAAA,kBAAA,YAAA,eAAA,YAAA,YAAA,YAAA,OAAA,YAAA,UAAA,WAAA,YAAA,sBAAA,SAAA,0CAKrD,EAAA,QAAU,EAAW,OAAA,EAAA,OAAA,SAAA,6BAElB,QAAA,SAAY,KAAQ,IAAmB,EAAa,MAAA,0DAKrD,GAAO,EAAe,EAAW,EAAc,gBAGjD,GAAI,EAAa,YAAa,EAAQ,WAAQ,2CAK5C,MAAA,GAAkB,WAAc,EAAK,EAAS,gKAUhD,EAAa,SAAK,GAAS,EAAS,oBAAoB,EAAA,IAErD,MAAA,EAAA,SAAA,KAAA,EAAA,QAAA,yBAMD,OAAO,EAAA,QAAA,yHAcT,EAAS,EAA0B,GAE7B,GACA,EAAA,oBAA8B,OAkBzB,SAAA,QAAA,SAAA,GAGT,IAAI,QACF,GAAW,aAAa,QAAQ,GAI3B,kCAGP,QAAG,GAAQ,MAAa,EAAU,eAChC,GAAO,aAAW,QAAY,MAKd,GAEX,aAAA,SACE,EAAS,EAAW,EAAA,iBAAA,EAAA,wGAKH,QAAjB,EAAA,oCAGN,GAAQ,MAAA,EAAY,iBAKd,YAAW,KAAM,SAAA,MAExB,SAEA,WADK,YAAA,IAAA,OAAA,EACE,mHAQF,6CAcT,EAAU,IAAA,wDAWf,EAAS,qBAQR,kBAA0B,2BAUxB,IADF,GAAA,MACE,EAAS,OAAS,wBAGpB,OAAK,WAIG,GAAA,EAAQ,UACR,EAAA,EAAU,GAAO,EAhBb,KAAA,oBACD,sBAkBP,MAAI,iBAAsB,cAAc,OAAA,SAAA,EAAA,EAAA,qCAKpC,EAAA,EAAc,SAEd,EAAA,EAAA,qBAEJ,MAAI,GAAmB,WAAU,EAAQ,EAAA,IAErC,EAAA,GAAiB,OAAU,EAAA,WAAsB,KAAA,EAAA,OAAA,EAAA,eAEjD,EAAS,EAAA,cAAA,GACT,EAAgB,EAAA,MAAA,EAAA,WAAA,OAAA,EAAA,MAAA,EAAA,EAAA,YAChB,EAAO,EAAA,YAAA,+BAAA,EAAA,KAAA,qCAAA,SAEP,EAAQ,EAAS,QAAM,EAAO,UAAA,EAAA,oBAAA,YAAA,EAAA,WAAA,GAAA,UACnB,KAAA,EAAS,cAAc,MAAA,EAAkB,WAAiB,KAAK,EAAA,cACzB,IAArC,EAAO,6BAGf,EAAS,gBACT,wCAGJ,KAAO,OAAW,GAAA,EAAA,gBAAA,EAAA,MAAA,EAAA,aAAA,EAAA,OAChB,QAAI,OAAA,GAAsB,KAAK,EAAS,MAAM,cAAgB,MAAI,EAAA,MAAA,WAAwB,KAAA,EAAgB,MAAA,YAC1G,EAAI,UACA,EAAQ,YAAW,EAAA,gCAEvB,EAAG,0BAGD,cACA,GAAiB,GAAK,MAAA,EAAa,KAAA,EAAA,MAAmB,GAAO,EAAuB,EAAc,6FAEpG,GAAM,GAAQ,OAAA,cAEd,KAAe,IAAA,EAAA,GAAA,OAAA,EAAA,KAAA,EAAA,IAEf,KAAA,GADa,GAAb,KACK,EAAA,EAAQ,GAAA,EAAA,mFAEf,EAAA,MAAY,KAAS,EAAA,QAAM,EAAA,iBAAA,EAAA,MAAA,EAAA,EAAA,KAAA,QAAA,SAAA,EAAA,OAAA,KAAA,WAAA,GAAA,MAAA,EAAA,aAAA,EAAA,MAAA,SAAA,KAAA,WAAA,qCAG3B,EAAA,YAAqB,EACnB,EAAI,OAAO,wOAWP,EAAI,EAAQ,SAAQ,EAAA,EAAmB,QAAG,OAAS,2DAMvD,IAAA,EAAO,iEAET,GAAA,GAAW,EAAc,mBAAA,GAAA,OAAA,GAAA,EAAA,mBAAA,GAAA,IAClB,OAAO,sBAOJ,SAAI,MACP,EAAO,OAGZ,MAAI,EAAM,EAAW,MAAA,SAGjB,MAAN,EAAM,QAAA,EAAA,GAAA,MAAA,EAAA,OACU,KAAR,EAAA,QAAQ,EAAA,GAAA,MAAA,EAAA,QACT,KAAA,EAAA,QAAA,EAAA,GAAA,MAAA,EAAA,OACQ,KAAN,EAAA,UAAM,EAAA,GAAA,MAAA,EAAA,SAET,KAAK,WAAS,IAAK,EAAA,OAAkB,GAAS,2BAIhD,EAAQ,kBACR,oCAGJ,KAAO,OAAW,EAAA,gBAAA,EAAA,KAGP,EAAI,aAAgB,EAAA,QAC3B,QAAQ,OAAI,GAAc,MAAM,EAAG,MAAA,WAAA,KAAA,EAAA,MAAA,YACnC,EAAO,oBAJT,QAAI,OAAa,GAAS,KAAA,EAAe,MAAG,cAAA,MAAA,EAAA,MAAA,WAAA,KAAA,EAAA,MAAA,YAC5C,EAAI,iBAMJ,kBAEa,GAAb,GADa,GAAM,MAAA,EAAa,KAAA,EAAA,oBAGlC,EAAY,GAAA,MAAS,EAAM,KAAA,EAAA,GACzB,EAAO,MAAO,KAAA,EAAc,MAAA,EAAkB,EAAO,KAAA,QAAM,SAAiB,EAAK,YAAe,GAAO,SAAM,KAAA,WAAA,IAE/G,GAAA,MAAY,EAAe,EAAA,EAAA,iBACzB,EAAI,YAAY,EAChB,EAAA,KAAO,EAAW,EAAQ,KAAA,iCAGrB,SAAc,SACjB,GAAA,OAAA,EAAA,gBAAA,EAAA,MAAA,eAAA,EAAA,aAAA,EAAA,MAAA,uBAEE,SAAc,GAClB,GAAI,IAAU,GAAI,MAAK,EAAO,cAAA,EAAA,WAAA,EAAA,wDAGtB,SAAI,MACP,EAAO,OAGZ,GAAI,GAAM,EAAW,MAAU,8BAG3B,MAAN,EAAM,QAAA,EAAA,SAAA,EAAA,GACU,KAAR,EAAA,QAAQ,EAAA,SAAA,EAAA,GACT,KAAA,EAAA,QAAA,EAAA,SAAA,EAAA,GACQ,KAAN,EAAA,SAAM,EAAA,SAAA,EAAA,GAET,KAAK,WAAS,IAAS,EAAS,OAAK,GAAA,0BAIvC,EAAQ,iBACR,wCAGJ,KAAO,OAAW,GAAA,SAAA,EAAA,cAAA,GAAA,MAAA,SAAA,EAAA,KAAA,GAAA,KAChB,QAAI,OAAY,GAAS,KAAO,EAAS,MAAA,cAAqB,MAAA,EAAA,MAAA,WAAA,KAAA,EAAA,MAAA,YAC9D,EAAI,UACK,EAAI,gBAAgB,EAAA,OAC3B,QAAO,OAAI,GAAK,KAAe,EAAG,MAAA,cAAA,MAAA,EAAA,MAAA,WAAA,KAAA,EAAA,MAAA,YAClC,EAAM,0BAGR,kBAEa,GADb,EAAa,EAAM,KAAY,EAAA,MAAA,EAAA,KAAA,OAC/B,kBAEF,EAAA,GAAY,MAAA,EAAe,EAAA,EAAA,GACzB,EAAO,MAAO,KAAA,EAAS,MAAK,EAAA,EAAkB,KAAO,QAAM,SAAA,EAAA,YAAA,GAAA,SAAA,KAAA,WAAA,IAE7D,GAAA,MAAY,EAAS,GAAA,MAAM,IAAA,EAAA,EAAA,OAAA,GAAA,MACzB,EAAI,YAAY,EAChB,EAAA,KAAO,EAAW,EAAQ,KAAA,iCAGrB,SAAc,SACjB,GAAA,OAAA,EAAA,gBAAA,EAAA,MAAA,0BAEE,SAAa,MACb,IAAU,GAAI,MAAK,EAAO,cAAA,EAAA,EAAA,wDAGtB,SAAI,MACP,EAAO,OAGZ,GAAI,GAAM,EAAW,MAAA,gEAIpB,KAAA,EAAA,QAAA,EAAA,QAAA,EAAA,GACoB,KAAlB,EAAQ,QAAgB,EAAA,QAAgB,EAAY,GACjD,KAAA,EAAA,SAAA,EAAA,QAAA,EAAA,kDAOf,MAAA,EAAA,QAAA,MAAA,UAAA,MAAA,KAAA,EAAA,EAAA,SAAA,ECtnBL,SAAA,gBAUM,OAAA,2BAAU,oCAEV,YAAW,cAEX,GAAM,KAAA,UACN,UAAO,yDAGT,SAAK,6CAEH,WAAI,EACJ,UAAI,UAEJ,MAAA,qFAQE,GAAqB,EAAS,iBAkEhC,MAAO,GAAA,SAAA,EAAA,6BAAP,iBA7DE,EAAU,QAAA,UAAsB,EAAK,EAC9B,GAAe,OAAI,EAAU,OAAA,EAAA,MAAA,QAAA,EAAA,SAE9B,EAAA,EAAA,sBAKA,WAAA,SAAA,GACJ,GAAA,UAAQ,KAAQ,EAAO,SAAvB,GACE,oCAIF,IAAG,GAAI,QAAY,QAAM,EAAW,SAAA,GAAA,iBAAA,4BAC5B,aAER,SAAM,QAAU,EAAG,SAAA,EAAA,0DAMA,KAAjB,EAAO,SAAU,EAAA,EAAA,OAAA,EAAA,IACX,QAAO,YAAW,KAAA,EAAA,GAC1B,EAAA,GAAA,GAAA,GAAA,iBAMM,EAAA,OACN,KAAS,eAIX,EAAU,WACR,EAAI,UAAU,EAAU,SAAA,GAAA,UAAA,EAAA,YACxB,EAAQ,GAAA,QAAY,IACpB,GAAA,GACA,EAAS,SAAS,aAAe,EAAS,SAAA,qBAI5C,GAAI,KAAU,WACd,EAAU,WACR,EAAO,UAAa,EAAA,SAAA,IAAA,UAAA,EAAA,YACpB,EAAA,IAAA,QAAA,sDAKF,IAAA,GAAS,EAAY,iBACZ,QAAW,WAClB,EAAO,IAAI,QAAA,aA9Db,GAAI,QAAU,QAAQ,EAAW,SAAU,MAC3C,EAAY,QAAU,UAAS,iBAAyB,QAAM,UAAU,uBAAW,QAAA,UAAA,oBAAA,QAAA,UAAA,mBAAA,QAAA,UAAA,gBA4EvF,OAAO,iBAMC,cAAW,UAAO,OAAA,YAAA,SAAA,EAAA,EAAA,0DAQnB,IAAA,MAAA,6JAMD,YAAa,EAAO,OAAS,EAAA,WAAkB,SAAA,sFAOjD,QAAU,SAAY,KAAW,IAAA,EAAA,MAAA,yBAC/B,KAAI,EAAU,EAAS,OAAA,EAAA,mDAQ5B,GAAA,EAAA,UC7IL,EAAA,qFAYM,kBAAe,UAAA,aAAA,SAAA,EAAA,kHAajB,KAAA,kBAAyB,SAAQ,GAC/B,MAAO,GAAA,iBAAA,IAAiC,iCAI1C,MAAK,GAAA,iBAAuB,qIAmB5B,MAAK,GAAa,GAAe,SAIhC,OAAA,SAAA,GCrDL,QAAA,EAAA,GAAA,kCAIC,MAAS,GAAA,EAAA,eAMN,OAAK,iDAEA,eAAQ,kBAAA,uCAMf,KAAA,MAAU,EACV,KAAA,IAAU,EACV,KAAA,MAAU,EACV,KAAA,QAAU,EACV,KAAA,QAAU,EACV,KAAA,aAAoB,UA4Bd,oBAIJ,OAAQ,MAAA,WAAA,KAAA,SAAA,GAGV,QAAI,GAA2B,EAAA,GAE7B,IAAA,GADA,GAAQ,EAAA,OAAA,EAAA,EAAA,WAAA,cACA,EAAA,EAAA,EAAA,EAAA,sCAGV,OAAK,GArCL,EAAU,UAAU,gBAAW,SAAgB,GAAA,KAAA,aAAA,KACxC,UAAa,WAAA,SAAA,GAAA,KAAA,QAAA,KACb,UAAQ,WAAM,SAAA,GAAA,KAAA,QAAA,KACd,UAAY,SAAA,SAAA,GAAA,KAAA,MAAA,KACZ,UAAQ,SAAM,WAAA,MAAA,MAAA,SACd,UAAU,QAAM,SAAA,GAAA,KAAA,IAAA,KAChB,UAAU,SAAM,SAAA,GAAA,KAAA,MAAA,KAChB,UAAA,YAAqB,SAAA,GAAA,KAAA,KAAA,KACnB,UAAA,SAAA,SAAA,4DAGT,KAAA,IAAU,EAAA,UACR,KAAA,MAAW,EAAK,mEAGlB,KAAI,aAAkB,EAAA,sDAKtB,MAAS,IAAA,MAAA,KAAa,KAAA,KAAA,MAAA,KAAA,IAAA,KAAA,MAAA,KAAA,QAAA,KAAA,QAAA,KAAA,yDAqBd,4BAIJ,MAAI,UAAY,aAAA,SAAA,EAAA,MAEd,GAAU,SAAA,WAmJN,GAAgB,MACM,GAAtB,EAAG,OAAS,KAAK,QACX,2DAKV,GAAQ,GAAQ,EAAK,OAAY,EAAA,uCAG5B,EAAG,GAAU,EAAK,EAAA,KAUvB,MALF,SAAS,QAAA,EAAA,SAAsB,kBAKzB,gBAIJ,MAAI,GAAO,QAAS,MAAA,SAAa,QAAA,OAAA,OAAA,QAAA,MAAA,OAAA,QAAA,OAAA,uBAIjC,GAAiC,GAA7B,EAAO,OAAI,KAAK,8BAKpB,EAAO,EAAA,MAAI,EAAO,IAAM,KAAK,KAAM,EAAA,IAGrC,KAAA,EAAA,EAAY,EAAA,EAAA,OAAA,IACZ,EAAO,EAAA,MAAA,KAAA,EAAA,KAAA,KAAA,IAAA,EAAA,EAAA,IAAA,IAIT,eAAO,GAAA,QAAA,IAAA,EAAA,KAAA,SAtIL,GAAA,EApDE,EAAU,QAAA,UAAA,EAAA,GAEV,KAEA,GACA,IAAU,WACV,GAAU,aACV,EAAU,EAAQ,OAAA,cAAqB,mBACvC,GAAU,aACV,EAAU,EAAA,OAAA,cAAA,mBACV,GAAU,mBACV,EAAU,EAAQ,OAAA,iBAA4B,oBAC9C,GAAU,oBACV,EAAU,EAAA,OAAA,eAAA,iBACV,EAAU,QACV,KAAU,EAAA,iBAAA,IAAA,KAAA,KACV,IAAU,EAAA,iBAAA,SAAA,KAAA,KACV,GAAU,gIAGZ,IAAI,EAAW,iBAAA,WAAA,KAAA,KACb,GAAU,gBACV,EAAU,EAAM,OAAA,eAAA,iBAChB,KAAU,gCACV,GAAU,WACV,EAAU,EAAM,OAAA,wBAAA,kBAGhB,GACA,IAAU,EAAM,gBAChB,GAAU,EAAA,WACV,EAAU,EAAA,WACV,GAAU,EAAM,WAChB,EAAU,EAAM,WAChB,GAAU,EAAA,SACV,EAAU,EAAA,SACV,GAAU,EAAA,SACV,EAAU,EAAA,SACV,KAAU,EACV,IAAU,EACV,GAAU,EAAA,QACV,EAAU,EAAM,kKAGlB,IAAW,SAAA,GAAA,MAAA,MAAA,SAAA,EAAA,EAAA,iBAAA,WAAA,iDAEX,EAAY,SAAO,GAAW,MAAA,MAAA,SAAA,EAAA,EAAA,IAC5B,KAAA,EAAY,YACZ,GAAQ,SAAA,GAAgB,MAAA,MAAY,YAAA,IAAA,EAAA,IACpC,EAAS,EAAA,YA6Id,UAxIY,KAAM,2EAGf,EAAA,EAAoB,EAAgB,YAG/B,QAAe,SAAQ,GAC1B,MAAA,SAAI,OAAc,IAAS,MAAA,EAAgB,WACvC,EAAA,KAAA,4BAKJ,IAAQ,EAAW,EAAQ,iBAAiB,IAAA,GAC1C,QAAA,OAAa,KAAM,EAAa,EAAQ,EAAM,GAAU,EAAA,oCAGtD,EAAU,EAAK,KAAA,sBAIjB,GADE,IAA8C,GAAA,IAAA,SAA9C,IAAmB,MAAA,EAAgB,WAAW,EAAA,GAAA,MAAA,KAAA,EAAA,EAAA,IAChD,EAAO,EAAA,EAAA,EAAA,OAAA,EAAA,8CAOT,OAAI,UAAA,EAAA,IAAA,MAAA,EAAA,aAIF,KAGQ,oBAAkB,SAAA,EAAA,MAC1B,MAEO,UAAP,EAAe,OACV,GAAA,KACL,GAAO,GAAI,MAAK,EAAA,cAAA,EAAA,WAAA,EAAA,WAAA,YAAA,EAAA,EAAA,GAAA,EAAA,EAAA,EAAA,YAAA,EAAA,EAAA,mFAGX,EAAA,8DAGG,YAAZ,GAAY,KAA+B,sBAKlC,MAGE,oBAAkB,SAAY,EAAA,eAIrC,GADK,WACE,GAAA,OAAA,YAAkB,KAAW,EAAA,iGAG/B,EAAA,0LAwBP,EAAI,SAAU,EAAA,WAAY,GAAA,EAAA,WAAA,EAAA,MAFnB,eAqDZ,yBC/PG,OAAI,8CAIF,YAAS,WAAO,SAAA,6BAElB,GAAU,WACR,eACA,GAAI,OACG,iBAcd,OAZQ,IACH,EAAG,OAAS,kBAGZ,EAAO,4CAQJ,eAQD,YAAW,WAAY,SAAO,mBACvB,EAAM,EAAS,yBAEtB,MACE,cACA,GAAG,OACD,cAED,EAAM,WAAA,+BAId,EAAA,KCrDH,EAAA,YAAA,2IAcI,GACE,IADE,QAAc,4HAmBhB,GAAA,+dAoCE,GAAiB,IAAA,EAAA,KAAA,SAKK,UAAtB,EAAA,IAAA,EAAA,YAGA,EAAS,EAAG,2EAcZ,EAAY,KAAM,EAAA,IAAA,EAA8B,kBAAsB,GACtE,EAAa,MAAO,EAAA,IAAA,EAA+B,mBAAS,qmBC1FpE,ODgJI,yDClJJ,GAAA,EAAA,IAAA,EAAA,eAAA,GAAA,EAAA,IAAA,EAAA,gBAAA,GAAA,EAAA,IAAA,EAAA,mBAAA,GAAA,EAAA,IAAA,EAAA,oBAAA,GAEQ,gBAQJ,OAAK,mDAEH,gBAAS,cAEP,GAAI,KAAA,sMAIJ,MAAA,SAAc,KAAU,SAAA,EAAA,8DAyCxB,GAAc,GAAA,EAAd,WACA,GAAO,GAAA,yDAnCL,EAAY,QAAO,UAAY,EAAM,KACzB,cAGZ,GAAA,EAAiB,EAAW,EAAW,EAAA,EAAA,CAuC5C,uDAnCG,EAAc,EAAA,EAAW,IAAA,EAAS,IAChC,EAAU,EAAK,IAAS,EAAA,KAClB,EAAS,KACb,EAAc,EAAA,IAAU,MACjB,EAAA,EAAc,GAAA,EAAA,GAAA,cAIzB,EAAc,SAAA,SAAe,EAAS,GACpC,MAAI,GAAA,KAAQ,EAAA,EAAA,IACZ,KAAM,SAAA,SACN,GAAO,QAAU,EAAA,EAAA,EAAA,mBAKnB,EAAS,aAAoB,SAAO,GAClC,GAAA,eACM,GAAa,EACjB,EAAO,aAgBd,uBC1DC,QAAA,MAAA,GAAuB,QAAQ,QAAA,IAAA,IAAA,QAAA,OAAA,iCAER,WAAQ,SAAA,EAAA,kCAGd,EAAA,6BACX,EAAA,yBAEN,EAAS,EAAsB,sBACb,EAAA,4BACK,EAAA,6DAGzB,IAAa,EACX,EAAI,WACG,MACL,GAAA,EAAgB,wCAMtB,GAAO,GAAA,EAAA,EAAA,OAAA,qBAEN,EAAA,OAAA,uCCxBG,OAAA,wBAAa,+CAEb,SAAU,cAEV,GAAW,KAAA,UACX,UAAS,UACT,kBAAU,UACV,YAAU,QACV,YAAM,QACN,UAAM,yDAGR,WAAK,eAEH,UAAI,EACJ,UAAI,EACJ,MAAI,EACJ,MAAI;KAGJ,MAAS,UAAa,aAAQ,WAAA,KAAA,iBAAA,QAAA,WAAA,WAAA,OAAA,aAAA,SAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,WAQxB,GAAQ,WA4JR,sCAgCJ,QAAO,sCAEL,EAAO,YAAW,EAAO,YAAgB,sFA8B3C,EAAO,SAAA,EAAA,oGAvNP,EAAS,EAAS,SAAY,QAAS,UAAK,EAAA,KACvC,SAAQ,EAAmB,EAAK,0NAcrC,EAAM,wFASN,EAAG,aAAQ,WACT,EAAO,cAIH,SAAI,EAAY,UAAY,IAG5B,gMAQN,OADI,GAAA,UAAkB,EAAQ,OAAQ,SAC/B,EAAc,GAAA,4FAQrB,GAAO,SAAO,KAAA,SAAW,6EAGvB,EAAW,EAAA,MAAM,KACT,EAAa,KACjB,2BAMN,EAAO,8CAQH,QAAA,0BAKF,EAAM,qBAIR,EAAc,QAIV,cAIA,KAAS,eACT,EAAQ,WAER,EAAI,MAAQ,EAAA,YAAW,eAAA,GAAA,wBAGhB,UACL,UAAS,EAAA,cACT,EAAQ,mHAKZ,EAAA,EAAe,GAAO,UAAW,QAAA,QAAY,EAAO,GAAA,WAAS,cAG7D,EAAA,EAAkB,WAKd,EAAgB,SAAS,EAAQ,EAAA,6DAMnC,EAAS,wDAIX,EAAc,SAAS,EAAM,YAG7B,EAAO,UACP,EAAW,MAAA,EAAA,EAAA,KAIX,IAAA,GAAA,EAAsB,MAAA,EAAW,EAAA,EAAA,EAC/B,IAAG,EAAA,MAAA,EAAA,KAAA,4BAGL,EAAA,yCAQE,SAAmB,EAAA,YAAS,SAC5B,EAAA,uFAOJ,EAAS,GAAA,QAAuB,GAC9B,EAAY,GAAQ,QAAA,gBAGtB,EAAc,GAAA,QAAW,EAAA,8BASvB,GAAG,EAAA,WAEA,EAAA,MAAQ,EAAU,YAAA,eAAA,GAAA,iBAArB,CAGA,GAAA,GAAO,EAAW,MAAM,EAAW,wBAKjC,EAAA,UACA,EAAA,MAAA,4BAGF,EAAW,iCAKb,EAAS,IAAA,QAAuB,GAC9B,EAAY,IAAQ,QAAA,IAEjB,EAAQ,UACT,EAAY,IAAA,QAAY,EAAQ,gEAkB9B,MAAI,aACC,GAAA,2DAQX,EAAS,OACP,EAAG,sBAsBP,QAAI,GAAgB,GACpB,EAAA,SAAS,EAAc,OAAU,EAAA,MAAA,SAAA,EAAA,kBAGzB,GAAS,EAAK,SACf,SAAQ,SAAS,GAAM,GAAA,iBAAA,YAI1B,GAAO,qEAIX,MAAO,SAAA,SAAA,mCA7PL,GAAI,QAAS,wEAGb,EAAc,QAAO,QAAW,EAAQ,SAAO,MAC/C,EAAkB,kBAiQtB,OAAO,iBAMC,WAAW,UAAO,OAAO,SAAS,SAAe,EAAA,EAAA,0DAQjD,IAAM,MAAY,EAAA,QAAY,EAAA,MAAA,8KAM7B,SAAQ,QAAS,WAAW,SAAA,KAC7B,IAAQ,EAAO,SAAO,EAAA,SAAA,KACjB,GAAA,EAAA,YAAA,iDAML,QAAQ,SAAO,uBAGnB,EAAQ,QAAQ,UAKd,GAAU,EAAA,iEAOf,GAAA,EAAA,UChVL,EAAA,uEAYS,UAAO,4FAQZ,MAAI,KAAA,0GAQA,GAAQ,EAAQ,qDAOd,GAAO,QAAU,KAAA,8CAEhB,QAAS,UAAU,EAAA,MAAU,EAAA,GAAA,EAAA,QAI9B,OAAQ,iBAEF,GAAA,iBAED,uFAMD,GAAU,QAAS,QAAQ,KACtB,EAAA,KAAA,EAAA,WAAA,QAAA,IAAA,MACL,GAAA,kIC3CR,OAAQ,0BAAA,oCAER,WAAU,cAEV,GAAS,KAAA,UACT,UAAU,UACV,YAAM,GACN,WAAO,EACP,QAAA,EACA,UAAO,QACP,SAAA,8DAGF,UAAK,UAEH,MAAA,iCAGM,6CAKD,GAAiB,EAAA,+CAQtB,GAAO,wCAQT,MAAI,6EAQA,GAAsB,EAAA,uBAAA,EAAA,kEAQlB,IAAM,MAAY,WAClB,SAAQ,WAAU,kBAAa,YAAsB,YAAW,SAAA,QAAA,UAAA,WAAA,OAAA,YAAA,cAAA,aAAA,SAAA,WAC9D,UAAW,EAAQ,MAAA,EAAA,GAAA,EAAA,uFAMzB,EAAK,GAAA,EAAa,YAAa,GAC7B,QAAG,UAAiB,IAAW,EAAA,WAC7B,GAAQ,EAAO,wEAOhB,QAAA,SAAA,uBAGH,EAAK,QAAU,EAEb,QAAG,UAAQ,IAAoB,EAAsB,WACrD,GAAa,EAAO,2FAOtB,QAAU,SAAY,KAAW,IAAA,EAAA,MAAA,wBAC/B,KAAa,EAAA,EAAQ,OAAA,EAAA,mDAQ1B,GAAA,EAAA,UCxGL,EAAA,2BAUM,OAAA,4BAAU,kCAAA,+CAEV,aAAQ,WAGV,GAAA,GAAK,KAAA,WAEH,EAAI,KAAW,UACf,SAAI,IACJ,SAAI,qBAIJ,MAAS,UAAS,YAAe,aAAA,aAAA,WAAA,WAAA,SAAA,EAAA,EAAA,EAAA,EAAA,EAAA,WAQ3B,GAAQ,EAAS,GACrB,MAAI,GAAA,GAAc,UAAS,EAAQ,GAAA,SAAS,gBAAA,EAAA,+BAM1C,GAAM,QAAU,UAAA,EAAA,EAChB,GAAO,UAAM,EAAA,QAAA,6CAGX,EAAA,EAAa,SAAA,EAAA,EAGjB,IAAA,EAAI,GAEJ,MADA,GAAI,GAAA,UACA,EAAA,EAGJ,IAGI,GAAA,MAKF,MAGA,EAXE,6BAKJ,cAQW,KAAG,0BAMZ,EAAA,EAA6B,KAAA,cAAe,EAAA,UAC5C,EAAA,EAAA,KAAA,cAAA,EAAA,yEAGA,EAAG,GAAA,SAAU,gHASb,EAAK,GAAA,yBAQL,KAAA,UACA,KAAA,QAAA,qEAOF,EAAW,IAAA,SAAA,WAGL,uGAcJ,EAAa,KAAA,IAAA,EAAe,YAAc,EAAA,KAAA,iBAGxC,EAAG,EAAY,GAAe,WAAc,IAAA,EAAA,GAAA,OAC5C,MAAG,GAAe,iBAAU,EAAY,4FAM5C,IAAW,EAAA,GAA6B,wDAGtC,MAAA,GAAW,iBAA0B,EAAA,MAKvC,EAAW,2BAA4B,sBAGhC,EAAe,cAAA,yCAOpB,GAAA,GAAe,EAAQ,mBAAA,EACvB,KACG,EAAS,OAAQ,YAAiB,UACnC,EAAQ,EAAgB,OAAS,OAAS,EAAA,EAAA,OAAA,SAAA,SAAA,yDAK5C,EAAO,EAAgB,SACrB,OAAW,SAAW,UACrB,EAAA,EAAA,OAAA,OAAA,EAAA,EAAA,OAAA,SAAA,SAAA,sDAKL,EAAW,mBAAe,SAAW,+BAEnC,MAAQ,GAAA,SAAQ,IACd,MAKF,aAAiB,mBAEf,QAAU,EAAc,SAAA,kCAEzB,GAAc,UAAM,EAAA,EAAA,OAAA,GAAA,IAAA,KACnB,EAAS,QAAc,OAAF,EAAE,YAAA,EAAA,WAAA,EAAA,EAAA,UAGzB,EAAA,iDAIF,KAAA,SAAW,EAAA,GACT,MAAA,GAAA,UAAsB,EAAA,YAGxB,OAIM,aAAW,SAAA,EAAA,KACX,MAAA,OAAA,EAAA,OAAA,OAGJ,eAAkB,SAAgB,EAAO,6BAG3C,GAAA,EAAsB,GAAA,SAAY,GAAA,EAAA,GAAA,SAAA,EAAA,CAChC,EAAA,0JAvKJ,EAAS,QAAA,QAAiB,EAAQ,SAAA,KAyLpC,OAAO,iBAME,eAAQ,aAAsB,WAAQ,aAAY,aAAA,SAAA,EAAA,EAAA,EAAA,mBAGnD,WACJ,SAAU,EAAa,EAAQ,GAE/B,GAAA,IAAU,MAAY,WAChB,SAAW,SAAA,UAAA,SAAA,GACb,QAAA,UAAU,EAAA,MAAe,EAAQ,GAAQ,EAAA,SAG3C,GAAU,EAAA,KACV,aAAY,EAAA,OAAA,4GAiBZ,mBAAsB,aAAA,WAAyB,aAAe,aAAa,8FAMhF,SAAA,QAAA,EAAA,SAAA,GC7PL,GAAA,GAAA,QAAA,QAAA,wFAUM,OAAA,yBAAW,yBAAA,iDAEX,UAAS,cAET,GAAU,KAAA,UACV,UAAM,UACN,YAAO,SACP,YAAU,UACV,UAAA,cACA,SAAM,yBACN,QAAA,QACA,WAAA,EACA,UAAS,EACT,MAAA,EACA,MAAA,EACA,UAAA,EACA,gBAAe,wDAGjB,YAAK,8CAEH,SAAI,OACJ,UAAI,EACJ,cAAe,wDAIb,MAAI,UAAU,YAAA,aAAA,WAAA,WAAA,SAAA,EAAA,EAAA,EAAA,EAAA,WAMV,GAAgB,EAAA,EAAA,GAEpB,GAAA,MAGA,EAAM,QAAA,UAAsB,EAAQ,EAEpC,GAAM,EAAW,EAAQ,EACzB,IAAA,GAAM,EAAY,MAElB,GAAM,cACJ,aAAmB,IACjB,YAAQ,EAAS,kHAIrB,EAAM,UAAU,EAAS,WAErB,UAAQ,SAAO,8FAQnB,EAAM,OAAY,MAIlB,EAAM,WAAa,WACjB,MAAK,GAAQ,6DAOf,EAAM,WAAA,WACJ,IAAK,GAAI,GAAI,EAAG,EAAI,EAAM,SAAS,OAAQ,IACrC,EAAM,UAAU,IAClB,EAAM,QAAQ,iEAOZ,EAAA,UAAS,IACf,EAAM,QAAW,MAOf,OAAQ,SAAU,KACf,SAAQ,IACN,wBAGP,SAAa,SAAA,4CAGf,EAAQ,UAAS,GAAS,EAAO,aAAA,OAAA,EAAA,aAAA,QAAA,GAAA,GAAA,EAAA,aAAA,KAAA,GAC3B,EAAQ,MAAM,EAAA,aAAgB,QAEhC,EAAA,aAAiB,EAEf,EAAA,uBAGK,SAAA,MACL,GAAA,EAAW,SAAA,GAAc,4BAEzB,SAAQ,6HAYR,MAAM,EAAA,YAAe,UAAW,EAAgB,sCAM1C,aAAM,EAAgB,SAAM,sBACpC,EAAM,UAAe,QAAQ,QAAA,EAAgB,mEAKtB,EAAC,UAAY,EAAA,kFAOxC,EAAQ,WAAY,WAClB,MAAG,GAAQ,WAAU,sDACZ,EAAM,SAAA,QAMjB,EAAQ,UAAY,SAAS,GAC3B,MAAA,GAAQ,SACD,KAAA,EAAA,aAAA,QAAA,GAEF,EAAM,eAAY,sDAMzB,IAAA,EAAA,cAEM,EAAA,SAAA,GAAA,QAAA,cAGJ,MAAG,gCAQH,sBAFF,EAAA,kBAEE,EAAI,CACJ,GAAI,GAAA,QAAA,QAAA,EAAA,gGAWJ,sBAHA,EAAG,mBAGH,EAAM,WAAA,KAAA,EAAA,SAAA,IAAA,EAAA,wCAKY,MAAhB,EAAA,SAAgB,EAAA,aAAA,EAAA,EAAA,eACM,KAAlB,EAAA,SAAkB,EAAA,aAAA,EAAA,SAAA,OAAA,EAAA,EAAA,eACxB,QAAA,YAAA,EAAA,gBAAA,EAAA,aAAA,GACA,EAAG,eAKH,GAAS,EAAA,OACP,KAAQ,iBAEN,iDAKN,EAAI,WACJ,EAAQ,SAAO,GAAA,EAAW,aAAA,YAAA,EAAA,cACxB,EAAQ,UACL,EAAQ,GAAA,UAAU,EAAA,uCAMvB,GAAO,KAAA,+GAKT,GAAO,SA3LL,qCAAI,8BAAuC,KAAA,EAAA,UAAA,2CAmM/C,qBAAI,qGAQA,GAAI,EAAW,2EAQb,IAAY,MAAA,EAAW,YAAA,EAAA,YAMzB,YALE,SAAU,YAAgB,YAAA,QAAA,UAAA,WAAA,OAAA,YAAA,WAAA,cAAA,WAAA,iBAAA,YAAA,gBAAA,UAAA,YAAA,SAAA,GAC1B,QAAQ,UAAM,EAAA,MAAA,EAAA,GAAA,EAAA,MAIuB,WAAvC,EAAI,GAAA,SAAgB,cAAmB,iCAGvC,EAAI,QAAS,QAAQ,2FAQjB,EAAO,EAAO,EAAA,EAAA,GAGf,EAAA,EAAA,OAAA,GAAA,QAAA,OAAA,IAAA,6BAGH,EAAa,SAAK,EAAS,oBAEzB,EAAO,OAAA,GACP,EAAW,+CAOX,EAAG,uBACD,iBAIG,QAAS,iBAEL,IACL,UAAW,QAAc,QAAA,EAAA,8CAG3B,SADK,EAAA,UAAA,GACG,QAAO,UAAU,GAAW,EAAA,OAAA,SAAA,GAAA,OAAA,IACpC,OAAA,QAAW,WAEb,sCAAc,EAAA,OAAW,KAAW,EAAQ,eAAe,EAAS,8BAKlE,EAAQ,EAAA,UAAe,EAAW,4GAMpC,EAAI,WACJ,EAAU,SAAA,SAAA,GACV,OAAS,GAAA,IAAA,EAAA,qCAMd,GAAA,EAAA,UC7TL,EAAA,2BAUM,OAAA,uDAIA,GAAW,KAAA,0DAGX,SAAK,WACL,YAAQ,kFAQR,QAAK,SAAS,YAAgB,WAAA,eAAA,SAAA,mDAK9B,EAAK,UAAA,EAAA,SAAA,iDAGH,OAAY,EAAK,YAKjB,2BAA8B,EAAA,4CAG9B,EAAK,OAAO,KAAA,oDAKV,EAAA,EAAA,OAAA,6BAKA,EAAA,MAKC,IAAO,GAAU,IAAA,EAAA,OAAA,QAGpB,8EAOJ,EAAK,OAAO,QAAW,EACrB,EAAI,2BAAO,QAAA,SAAA,GACX,6BAOH,GAAA,0BAEC,EAAI,WAAgB,iBAMlB,UAAa,UAAU,WAAY,OAAU,SAAK,SAAA,EAAA,EAAA,EAAA,MAEhD,GAAO,EAAK,0DAIR,SACA,uHAKD,SAAa,EAAA,EAAA,EAAA,4BASd,QAAA,KAAY,sEAGH,2BAAA,KAAA,+CAKX,EAAU,YAAc,KAAA,SAAA,GAGtB,yBAAI,qBAQJ,GAAA,GAAmB,EAAA,EAAc,8HASxC,EAAU,WAAA,EAAA,wBAQD,UAAA,UAAa,WAAY,OAAA,SAAA,EAAA,EAAA,mBAGrB,YAAS,wDA6BjB,GAAA,GAAA,EAAA,OAAA,QAAA,yFAzBgB,EAAK,QAIrB,GAAG,SAAW,sEAQd,EAAU,SAAY,WACpB,EAAA,SAAW,EAAQ,SAAA,aAIf,MAAQ,8CAajB,EAAA,2BAAA,KAAA,WClLL,MAEQ,iBAQF,OAAA,0BAAa,+CAEb,WAAQ,cAER,GAAU,KAAA,UACV,UAAA,UACA,YAAS,GACT,YAAU,UACV,YAAM,UACN,WAAM,EACN,QAAO,EACP,UAAM,MACN,SAAO,2BACP,iBAAW,EACX,QAAA,kCAGF,MAAK,WAEH,KAAI,GACJ,MAAI,EACJ,WAAI,EACJ,WAAI,wKAUE,GAAiB,EAAS,WA0MvB,OACH,MAAO,EAAS,YAAA,QAAA,WA6ClB,KAGF,wCAAA,GAA6B,UAApB,EAAS,QACP,EAAA,GAAW,WAIpB,aA+FI,iGAKG,WAAA,IACH,EAAA,GAAmB,UAAR,EAAsB,aAAA,QAAA,EAAA,OACrC,EAAS,GAAa,UAAT,EAAuB,aAAA,OAAA,EAAA,OACpB,WAAd,GAAuB,UAAA,GAAA,EAAA,GAAA,EAAA,aAAA,YAAA,EAAA,qCAKrB,YACA,GAAA,EAAa,QAAY,MAAA,qEAKtB,WAAA,IACJ,EAAQ,IAAY,UAAZ,EAAqB,aAAA,QAAA,EAAA,OAC9B,EAAA,IAAuB,UAAT,EAAkB,aAAA,OAAA,EAAA,OAC3B,cAAA,UAAA,GAAA,EAAA,IAAA,EAAA,aAAA,YAAA,EAAA,4BAKT,QAAS,KACgB,UAApB,EAAQ,QACT,EAAW,GAAA,QAAI,EAAS,UAExB,EAAQ,GAAA,QAAI,EAAS,eAIzB,QAAI,KACK,UAAT,EAAS,kCAGP,EAAS,IAAA,QAAW,EAAA,uBAKlB,OAGI,2BAKJ,EAAA,GAAA,QAAe,EAAS,MAExB,GAAyB,SAI7B,QAAS,KACP,+DAQA,EAAI,0BAKF,GAAiB,mBAGnB,IAAI,GAAA,EAAA,GAEF,EAAQ,EAAA,uBACH,UAAA,kFAYP,OALF,wBAAS,EAAA,OAAoB,GAEvB,EAAQ,SAAgB,GAGvB,QAAA,UAAA,EAAA,WAGD,GAAsB,EAAS,EAAA,EAAA,SAEjC,EAAA,EAAA,MAAA,YAEA,EAAS,QACP,oCAGF,KAAA,EAAA,KAAA,EAAA,MAEA,WACE,+BAGF,KAAA,EAAA,KAAA,EAAA,MAAA,EAAA,EAAA,EAEA,WACE,mCAGF,KAAA,EAAA,KAAA,QAGF,SACE,8CAOE,EAAA,SACA,MAIY,UAAT,IAA0B,WAAV,EAAA,GACrB,OAAQ,EAAM,IACd,IAAK,OACH,EAAO,KAAM,EAAS,IACtB,MACF,KAAK,QACH,EAAO,KAAM,EAAS,KAAM,EAAS,MAAA,qDAIzC,IAAO,yBAGT,KAAS,SACP,EAAW,IAAM,EAAK,IAAM,EAAY,wBAOrC,GAAqB,EAAA,KACnB,KAAQ,IAAA,EAAW,KAAA,KAAA,EAAA,iCAKpB,uCAID,mFA7fH,uEAKF,GAAG,SAAe,EAAA,EAAA,aAChB,GAAM,EAAa,OAAA,EAAY,OAAQ,EAAA,MAAA,QAAA,EAAA,mOAczC,EAAM,WAAQ,mDAKd,EAAM,wFASN,EAAI,aAAS,2BAKL,SAAA,EAAa,UAAgB,QAG3B,IAGJ,kKAQD,OAFD,GAAW,SAAY,EAAa,EAAA,oBAAc,EAAA,KACtD,EAAS,WAAc,WAAS,KAAU,GAC7B,EAAS,GAAA,yDAQtB,QAAS,SAAO,KAAW,EAAA,EAAA,6DAGzB,EAAY,IACF,EAAQ,KACd,0HAoBJ,EAAA,+CAGG,EAAQ,YACT,EAAQ,EAAiB,EAAU,YAIrC,0EAQF,EAAS,0GAiBP,EAAK,cAIL,MAAU,+BAEC,6DAOS,OAAd,GAAc,EAAc,QAClC,EAAI,MAAQ,mBAIR,KAAQ,gBACH,YAAA,EAAA,wDAGF,CACL,GAAS,WACT,EAAQ,0DAOV,EAAW,KACX,EAAA,UAOA,EAAW,EAAA,OAAW,gHAQtB,EAAI,WAAU,EAAe,SAAY,EAAQ,wDAIjD,EAAW,aAAA,EAAA,SAAA,EAAA,mCAKT,IAAG,EAAY,MAAW,EAAK,KAAA,iCAIjC,EAAG,WACD,EAAG,kBAGH,GAAA,EAAA,KAAA,WAAA,cAIA,EAAA,oEAiBI,MAAA,oCAGK,iCAIb,EAAI,WAAA,WACY,QAAhB,aAGE,EAAM,MAAM,0CAOZ,GAAI,EAAA,SAAJ,CACA,EAAG,MAAA,EAAW,YAAc,eAAa,GAGzC,EAAA,KAIE,GAAA,EAAA,MAAA,EAAA,wBAGF,EAAG,SAAQ,EAAa,UAAA,IACtB,yBAIJ,IAGK,EAAA,WAA6B,OAAZ,GAClB,MAeJ,EAAS,OAAA,WACP,EAAQ,SAAY,EAAA,QAAA,EAAA,oFAahB,gBAAW,cACb,sCAKF,EAAW,EAAS,KAAQ,kEAY1B,GAAI,0DAKO,IACT,GAAY,4HAMd,EAAK,EAAsB,QAAW,SAAA,OAClC,EAAwB,QAAA,QAAW,GAAA,EAAyB,IAAA,EAAA,EAAA,2NAclE,EAAmC,SAAnC,EAA+C,QAAA,EAAA,QAAA,QAAA,SAGjD,EAAS,YAAW,GAAc,SAAA,wCAQ5B,SAAc,SAAI,GACT,KAAX,EAAA,OAAW,EAAA,WACX,EAAI,+BAKF,cAAA,SAAA,GACA,KAAA,EAAA,oBAEJ,EAAA,oBAIF,EAAS,yBAAoB,SAAA,GAC3B,EAAI,iBACJ,EAAA,oBAEI,SAAW,EAAS,GAAA,OAAS,EAAA,GAAA,2BA6LrC,QAAI,GAAgB,GACpB,EAAA,SAAS,EAAc,OAAU,EAAA,MAAA,SAAA,EAAA,kBAGzB,GAAS,EAAK,SACf,SAAQ,SAAS,GAAM,GAAA,iBAAA,YAI1B,GAAO,qEAIX,MAAO,SAAA,SAAA,yFAxiBL,EAAe,cACf,EAAI,QAAU,QAAS,EAAW,cA+iBtC,OAAO,iBAMC,aAAW,UAAO,YAAA,OAAA,WAAA,QAAA,SAAA,EAAA,EAAA,EAAA,EAAA,0DAQpB,IAAM,MAAQ,+NAOZ,EAAM,eAAa,aACnB,MAAQ,qGAOZ,GAAK,MAAa,EAAA,YAAa,GAC7B,QAAG,UAAiB,IAAW,EAAA,WAC7B,GAAQ,EAAO,uEAOhB,QAAA,SAAA,uBAGH,EAAK,MAAU,EAEb,QAAG,UAAQ,IAAoB,EAAA,WAC/B,GAAa,EAAO,iEAMhB,GAAY,QAAQ,UAAU,KAC/B,QAAQ,SAAS,KAAW,IAAa,EAAS,MAAM,wBAC3D,KAAa,EAAA,EAAQ,OAAQ,EAAW,UAI1C,EAAI,WAAU,EAAS,OAAA,EAAS,UAAA,SAAA,6BAGhC,QAAU,SAAY,KAAW,IAAA,EAAA,MAAA,0BACX,EAAA,WAApB,KAAY,GAAQ,GAAA,+CAQzB,GAAA,EAAA,UC3pBL,EAAA,2BAUM,OAAA,4BAAW,yBAAA,iDAEX,aAAS,cAET,GAAU,KAAA,UACV,UAAM,UACN,YAAO,YACP,YAAW,aACX,UAAQ,cACR,SAAO,+BACP,QAAA,iCAGF,MAAK,UAEH,UAAI,kBAEJ,MAAA,mGAQM,GAAc,EAAO,EAAA,YAKvB,EAAM,QAAA,UAAe,EAAA,EAEvB,GAAM,EAAA,EAAA,iBAEN,EAAM,EAAY,SAEd,cAAW,2CAIf,EAAM,kBAEF,UAAW,SAAO,+GAYjB,WAAM,iBACP,GAAM,gBAKF,OAAA,SAAe,2CAGvB,EAAA,aAAoB,MAIlB,SAAW,SAAA,GACX,EAAM,aAAA,KAGA,OAAM,SAAQ,4DAKtB,EAAA,gBACK,GAAS,EAAc,gDAO5B,EAAW,WAAY,WACrB,MAAI,GAAI,WAAe,wFAChB,EAAA,SAAA,2DAQT,IAAA,EAAA,cAEM,EAAA,SAAA,GAAA,QAAA,oDAQJ,EAAG,mBACD,oIAaI,KAAN,EAAM,SAAA,EAAA,SAAA,gCAKc,KAAlB,EAAO,SAAW,EAAA,aAAA,EAAA,EAAA,eACJ,KAAlB,EAAW,SAAkB,EAAA,aAAA,EAAA,SAAA,OAAA,EAAA,EAAA,eAC3B,QAAA,YAAA,EAAA,gBAAA,EAAA,aAAA,uBAMI,EAAW,2BAKjB,EAAW,WACX,EAAW,SAAO,GAAA,YAAW,EAAA,cAC3B,EAAW,UACR,EAAQ,GAAA,UAAU,EAAA,uCAMvB,GAAO,KAAA,gGAKT,uCAQF,qBAAI,2GAQA,GAAI,EAAkB,wEAQtB,GAAI,IAAA,MAAa,0LAEb,QAAA,UAAiB,EAAA,MAAA,EAAA,GAAA,EAAA,KAIrB,IAAI,GAAA,EAAgB,QAAA,EAAc,mGAM/B,IAAQ,GAAc,IAAA,8BAEvB,GAAI,EAAiB,GAGnB,EAAA,EAAuB,EAAO,EAAY,8GAQ9C,EAAkB,SAAS,EAAA,GAAmB,KAAA,SAAU,eAEtD,EAAM,cAEL,KAIG,OAAA,EAAW,QAAA,SAAc,qBAGjB,SAAS,EAAO,QACtB,SAAA,GAGJ,GAAG,EAAO,aAAgB,EAAO,QAAG,EAAU,OAAU,aACvD,GAAA,cAAuB,EAAO,WAAA,UAAA,EAAA,EAAA,WAAA,OAAA,sEAOZ,IAAvB,EAAW,QAAiB,EAAS,GAAA,QAAY,qBAG/C,EAAO,8CAOP,GAAI,GAAQ,EAAoB,aAAW,EAC3C,OAAI,KAAmB,EAAU,GAAA,yBAMnC,GAAA,EAAU,SAAY,EAAW,YAAA,MAAA,GAAA,IAAA,GAC/B,IAAI,GAAA,EAAW,UAAU,EAAA,aACzB,EAAU,QAAA,UAAA,GAAA,EAAA,OAAA,SAAA,GAAA,MAAA,EAAA,UACV,GAAA,QAAY,SAAA,GAAA,EAAA,aAAA,GAAA,4FAMjB,GAAA,EAAA,UClQL,EAAA,2BAUM,OAAA,4IAKA,cAAW,cAEX,GAAM,KAAA,UACN,UAAO,mCAEP,UAAW,cACX,SAAU,iCACV,QAAA,QACA,WAAA,EACA,UAAA,EACA,MAAA,EACA,MAAA,EAEA,WAAU,EACV,SAAA,OACA,WAAQ,YACR,gBAAU,KACV,WAAA,4BAGF,OAAK,aAEH,WAAI,EACJ,OAAI,iCACJ,SAAI,mCACJ,cAAa,qIAUP,GAAa,EAAe,EAAQ,WAuNpC,GAAW,EAAA,QACH,GAAA,gBAAoB,CAC5B,GAAA,GAAW,EAAA,GAAA,iBACX,GAAQ,UAAG,sEAIN,GAAA,GAAA,kBACP,EAAQ,GAAG,kBAAA,EAAA,iGAOR,OACD,GAAQ,4EAhOR,EAAA,EAAY,KACZ,EAAY,SAAM,EAAU,+BAM9B,EAAgB,EAChB,EAAS,EAAe,YAAO,GAAA,iIAGjC,EAAM,EAAoB,kBAAA,EAAA,WAAA,2CAI1B,EAAgB,EAAe,cAAO,GACpC,EAAA,EAAmB,OAAM,EAE3B,GAAM,QAAA,EAAa,SACjB,UAAY,EAAW,2EAQzB,EAAY,WAAS,EAAS,MAEzB,gBAAe,SAAU,KAC1B,eAAoB,iEAQxB,EAAY,MAAS,oHAEnB,EAAI,UACA,EAAe,UACnB,EAAa,YAIV,OAAQ,SAAc,EAAM,EAAA,kKAKrB,IAAZ,GAAY,EAAiB,WAAe,WAAA,EAAA,cAC1C,EAAK,cAAW,QAAc,KAAM,EAAW,eAC7C,2BAEF,EAAI,WAAiB,EAAW,MAAA,oFAQlC,GAAA,IAAY,GAAS,EAAW,YAAA,iDAE9B,EAAO,cAAiB,QAAA,KAAW,EAAS,aAC5C,EAAI,cAKA,OAAc,cAEhB,GACc,EADd,EAAa,EAAK,SAAe,SAAS,EAAA,OAAU,EAAA,IACpD,yEAGF,EAAI,MAAO,KAAA,EAAA,MAAA,EAAA,EAAA,GAAA,SAAA,EAAA,OAAA,EAAA,YAAA,EAAA,GAAA,SAAA,EAAA,YAAA,EAAA,QAEE,GAAX,4BAEF,EAAM,GAAO,MAAA,KAAA,EAAA,EAAA,EAAA,EAAA,QAAA,EAAA,GAAA,EAAA,YACb,EAAM,MAAS,KAAA,EAAA,MAAA,EAAA,EAAA,GAAA,SAAA,EAAA,OAAA,EAAA,YAAA,EAAA,GAAA,SAAA,EAAA,YAAA,EAAA,IAGf,IAAA,gDAIA,GAAI,KAAA,IACC,OAAG,IACN,MAAY,EAAA,OAAe,EAAY,GAAM,MAAA,WAAA,mBAC3B,IACX,UAAK,+BAIhB,MAAA,GAAY,MACN,IAAA,EACD,EAAU,aAAG,EAAA,MAAA,WACC,IAAf,EACK,EAAG,eAAa,EAAA,MAAA,aADrB,QAHsB,2CAUpB,KAAN,EACE,EAAY,EAAA,UAA4B,IAAV,EAAU,OAC1B,IAAZ,MACK,EAAA,UAAA,KAAA,EAAA,oCAKT,EAAA,aAAY,SAAiB,EAAS,GACb,WAAnB,EAAA,cACJ,EAAY,eAAQ,EAAY,GAEhC,EAAc,WAAG,EAAA,MAIP,eAAW,SAAW,EAAS,4BAEzC,EAAY,EAAO,cAAgB,EAAA,EAAA,GAAA,2CAGrC,EAAY,SAAA,EAAa,SAAS,EAAO,SAAO,IAAA,GAG5C,EAAA,WAAiB,EAAW,SAAM,EAAS,WAAgB,IAAA,KAEnD,OAAA,EAAa,GAAA,+BAIvB,GAAA,0DAGF,QAAY,OAAA,GAAe,KAAS,EAAK,sBAEvC,EAAc,GAAA,MAAS,KAAA,EAAA,EAAA,EAAkB,KAAS,EAAI,OAAA,EAAA,EAAA,OAAA,EAAA,YACtD,QAAI,OAAA,GAAA,OAAA,EAAA,gBAEJ,EAAY,YAGR,aAAoB,SAAA,MAEE,UAAxB,EAAA,OAAS,SAAA,eAAe,EAAA,wCAI5B,GAAA,GAAY,QAAa,QAAS,EAAK,OACJ,YAA5B,EAAA,GAAA,SAAmB,gBACpB,EAAA,EAAA,+DAOJ,GAAI,mBAAmB,KAAA,EAAA,WAAY,EAAA,WAAA,EAAA,OAAnC,IACA,EAAI,iBACJ,EAAI;GAMF,GAAO,GAAA,MAAY,EAAI,SACf,EAAI,WAAgB,EAAgB,EAAA,EAAgB,GAAY,2EAMxE,KACY,OAAP,QAAO,EAAyC,EAAjB,EAAiB,EAAS,EAAQ,EAAU,sCAKhF,IAAO,EAAY,EACP,6DAEI,KAAhB,EAAA,SAA2B,EAAS,SAAA,EAAe,SAAA,EAAA,SAAA,OAE3C,EAAA,EAAqB,GAAA,OAC7B,GAAI,EAAa,IACF,IAAf,4DAEiB,KAAnB,EAAY,SAAgB,EAAA,WAAe,EAAA,SAAA,EAAA,WAAA,KAE3C,EAAY,EAAA,EAAA,GAAA,yEAMZ,EAAW,OAAG,EAAA,GAAiB,KACzB,EAAsB,GAAA,EAAA,MACjB,eA0BT,GAAQ,EAAK,OACL,KAAG,kCAEb,EAAA,KAAA,OAAA,uDAGE,IACJ,EAAY,KAAA,OAAU,QACpB,EAAG,KAAY,WAAQ,QACrB,EAAQ,GAAA,QAAI,QAEd,MAGF,IAAI,GAAQ,EAAY,OACxB,GAAY,QAAO,WACjB,GAAA,EAAA,4BAGA,WAGI,EAAW,2BAKjB,EAAI,WACJ,EAAY,SAAO,GAAS,EAAM,aAAA,YAAA,EAAA,cAC5B,EAAA,UACJ,EAAY,GAAA,UAAa,EAAU,aAEjC,GAAA,2CAKJ,EAAO,+GAKT,EAAO,UA1RL,IADI,QAAc,QAAO,EAAA,SAAA,MACrB,8BAAsB,KAAA,EAAA,UAAA,YAC1B,EAAY,eAAY,GAAA,UAAA,+CAgS7B,EAAU,SAAA,kBAQP,gBAAS,UAAA,SAAA,KAAA,iBAAA,cAAA,cAAA,SAAA,EAAA,EAAA,EAAA,EAAA,EAAA,gFAIe,GAAO,uBAAY,EAAA,wFAkDvC,GAAI,QAAS,OAAA,GAAb,IACI,GAAA,MAAA,EAAA,UAAA,GAAA,MAAA,EAAA,WAAA,YAAA,KAAA,EAAA,IAAA,EAAA,mFAEJ,EAAW,GAAa,wGAuExB,2FApHA,IAAW,MAAS,EAAA,WAAW,WAC/B,SAAa,YAAO,YAAoB,QAAA,UAAW,WAAA,OAAA,YAAA,WAAA,YAAA,WAAA,aAAA,kBAAA,YAAA,WAAA,aAAA,SAAA,gBAAA,SAAA,YAAA,SAAA,0CAKrD,EAAI,QAAA,EAAa,OAAA,EAAY,OAAS,SAAY,GAClD,GAAqB,QAAA,UAAA,kEAErB,KAAW,EAAQ,EAAA,OAAA,EAAA,8EAMnB,GAAI,EAAa,sBAGjB,EAAiB,SAAA,EAAW,+BAKxB,EAAA,GAA0B,OAAA,EAAW,WAAA,KAAA,sDAKzC,QAAM,UAAY,EAAA,KAAS,EAAS,SAAU,EAAA,SAAU,6CAEtD,MAAA,EAAkB,SAAW,KAAA,EAAA,SAC5B,EAAA,EAAA,kBAKG,OAAA,EAAA,QAAmB,WAEvB,EAAW,OAAA,EAAa,cACxB,KAkBS,SAAA,QAAA,SAAA,GAGT,IAAI,QAIF,GAAA,aAAA,QAAA,GACK,sDAGP,QAAG,GAAQ,MAAa,EAAU,eAChC,GAAO,aAAW,QAAY,MAKd,GAEX,aAAA,SACE,EAAS,EAAW,EAAA,iBAAA,EAAA,wGAKH,QAAjB,EAAA,oCAGN,GAAQ,MAAA,EAAY,iBAKd,YAAW,KAAM,SAAA,MAExB,SAEA,WADK,YAAA,IAAA,OAAA,EACE,8CAIT,EAAW,MAAa,EAAA,KAAA,EAAA,0BACjB,SAAA,EAAA,4DAcT,EAAU,IAAA,kCASb,GAAA,EAAA","file":"angular-strap.min.js","sourcesContent":["\nangular.module('mgcrea.ngStrap', [\n 'mgcrea.ngStrap.modal',\n 'mgcrea.ngStrap.aside',\n 'mgcrea.ngStrap.alert',\n 'mgcrea.ngStrap.button',\n 'mgcrea.ngStrap.select',\n 'mgcrea.ngStrap.datepicker',\n 'mgcrea.ngStrap.timepicker',\n 'mgcrea.ngStrap.navbar',\n 'mgcrea.ngStrap.tooltip',\n 'mgcrea.ngStrap.popover',\n 'mgcrea.ngStrap.dropdown',\n 'mgcrea.ngStrap.typeahead',\n 'mgcrea.ngStrap.scrollspy',\n 'mgcrea.ngStrap.affix',\n 'mgcrea.ngStrap.tab',\n 'mgcrea.ngStrap.collapse'\n]);\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 };\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 element.css('position', (options.offsetParent) ? '' : 'relative');\n if(setWidth) {\n element.css('width', '');\n }\n element.css('top', '');\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 element.css('position', (options.offsetParent) ? '' : 'relative');\n element.css('top', (options.offsetParent) ? '' : ((bodyEl[0].offsetHeight - offsetBottom - elementHeight - initialOffsetTop) + 'px'));\n } else { // affix === 'middle'\n unpin = null;\n if(setWidth) {\n element.css('width', element[0].offsetWidth + 'px');\n }\n element.css('position', 'fixed');\n element.css('top', initialAffixTop + 'px');\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 element.css('position', (options.offsetParent) ? '' : 'relative');\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 element.css('position', initialPosition);\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, offsetTop: 'auto', target: affixTarget ? affixTarget.$element : angular.element($window)};\n angular.forEach(['offsetTop', 'offsetBottom', 'offsetParent', 'offsetUnpin'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 template: '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', 'placement', 'keyboard', 'html', 'container', 'animation', 'duration', 'dismissable'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 template: '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', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 = constantValueRegExp.test(attr.value) ? scope.$eval(attr.value) : attr.value;\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 };\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'], function (key) {\n if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];\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 var activeIndex = self.$targets.$active;\n\n // remove element from $targets array\n self.$targets.splice(index, 1);\n\n if (index < activeIndex) {\n // we removed a target before the active target, so we need to\n // decrement the active target index\n activeIndex--;\n }\n else if (index === activeIndex && activeIndex === self.$targets.length) {\n // we remove the active target and it was the one at the end,\n // so select the previous one\n activeIndex--;\n }\n self.$setActive(activeIndex);\n };\n\n self.$targets.$active = !self.$options.startCollapsed ? 0 : -1;\n self.$setActive = $scope.$setActive = function(value) {\n if(!self.$options.disallowToggle) {\n self.$targets.$active = self.$targets.$active === value ? -1 : value;\n } else {\n self.$targets.$active = value;\n }\n self.$viewChangeListeners.forEach(function(fn) {\n fn();\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.$targets.$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 if (bsCollapseCtrl.$targets.$active !== modelValue * 1) {\n bsCollapseCtrl.$setActive(modelValue * 1);\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 || 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.$targets.$active;\n $animate[index === active ? 'addClass' : 'removeClass'](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 prefixClass: 'datepicker',\n placement: 'bottom-left',\n template: '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 modelDateFormat: null,\n dayFormat: 'dd',\n monthFormat: 'MMM',\n yearFormat: 'yyyy',\n monthTitleFormat: 'MMMM yyyy',\n yearTitleFormat: 'yyyy',\n strictFormat: false,\n autoclose: false,\n minDate: -Infinity,\n maxDate: +Infinity,\n startView: 0,\n minView: 0,\n startWeek: 0,\n daysOfWeekDisabled: '',\n iconLeft: 'glyphicon glyphicon-chevron-left',\n iconRight: 'glyphicon glyphicon-chevron-right'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, datepickerViews, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\n\n function DatepickerFactory(element, controller, config) {\n\n var $datepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $datepicker.$options;\n var scope = $datepicker.$scope;\n if(options.startView) options.startView -= options.minView;\n\n // View vars\n\n var pickerViews = datepickerViews($datepicker);\n $datepicker.$views = pickerViews.views;\n var viewDate = pickerViews.viewDate;\n scope.$mode = options.startView;\n scope.$iconLeft = options.iconLeft;\n scope.$iconRight = options.iconRight;\n var $picker = $datepicker.$views[scope.$mode];\n\n // Scope methods\n\n scope.$select = function(date) {\n $datepicker.select(date);\n };\n scope.$selectPane = function(value) {\n $datepicker.$selectPane(value);\n };\n scope.$toggleMode = function() {\n $datepicker.setMode((scope.$mode + 1) % $datepicker.$views.length);\n };\n\n // Public methods\n\n $datepicker.update = function(date) {\n // console.warn('$datepicker.update() newValue=%o', date);\n if(angular.isDate(date) && !isNaN(date.getTime())) {\n $datepicker.$date = date;\n $picker.update.call($picker, date);\n }\n // Build only if pristine\n $datepicker.$build(true);\n };\n\n $datepicker.updateDisabledDates = function(dateRanges) {\n options.disabledDateRanges = dateRanges;\n for(var i = 0, l = scope.rows.length; i < l; i++) {\n angular.forEach(scope.rows[i], $datepicker.$setDisabledEl);\n }\n };\n\n $datepicker.select = function(date, keep) {\n // console.warn('$datepicker.select', date, scope.$mode);\n if(!angular.isDate(controller.$dateValue)) controller.$dateValue = new Date(date);\n if(!scope.$mode || keep) {\n controller.$setViewValue(angular.copy(date));\n controller.$render();\n if(options.autoclose && !keep) {\n $timeout(function() { $datepicker.hide(true); });\n }\n } else {\n angular.extend(viewDate, {year: date.getFullYear(), month: date.getMonth(), date: date.getDate()});\n $datepicker.setMode(scope.$mode - 1);\n $datepicker.$build();\n }\n };\n\n $datepicker.setMode = function(mode) {\n // console.warn('$datepicker.setMode', mode);\n scope.$mode = mode;\n $picker = $datepicker.$views[scope.$mode];\n $datepicker.$build();\n };\n\n // Protected methods\n\n $datepicker.$build = function(pristine) {\n // console.warn('$datepicker.$build() viewDate=%o', viewDate);\n if(pristine === true && $picker.built) return;\n if(pristine === false && !$picker.built) return;\n $picker.build.call($picker);\n };\n\n $datepicker.$updateSelected = function() {\n for(var i = 0, l = scope.rows.length; i < l; i++) {\n angular.forEach(scope.rows[i], updateSelected);\n }\n };\n\n $datepicker.$isSelected = function(date) {\n return $picker.isSelected(date);\n };\n\n $datepicker.$setDisabledEl = function(el) {\n el.disabled = $picker.isDisabled(el.date);\n };\n\n $datepicker.$selectPane = function(value) {\n var steps = $picker.steps;\n // set targetDate to first day of month to avoid problems with\n // date values rollover. This assumes the viewDate does not\n // depend on the day of the month \n var targetDate = new Date(Date.UTC(viewDate.year + ((steps.year || 0) * value), viewDate.month + ((steps.month || 0) * value), 1));\n angular.extend(viewDate, {year: targetDate.getUTCFullYear(), month: targetDate.getUTCMonth(), date: targetDate.getUTCDate()});\n $datepicker.$build();\n };\n\n $datepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $datepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n if(evt.keyCode === 13) {\n if(!scope.$mode) {\n return $datepicker.hide(true);\n } else {\n return scope.$apply(function() { $datepicker.setMode(scope.$mode - 1); });\n }\n }\n\n // Navigate with keyboard\n $picker.onKeyDown(evt);\n parentScope.$digest();\n };\n\n // Private\n\n function updateSelected(el) {\n el.selected = $datepicker.$isSelected(el.date);\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $datepicker.init;\n $datepicker.init = function() {\n if(isNative && options.useNative) {\n element.prop('type', 'date');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if(isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $datepicker.destroy;\n $datepicker.destroy = function() {\n if(isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $datepicker.show;\n $datepicker.show = function() {\n _show();\n // use timeout to hookup the events to prevent \n // event bubbling from being processed imediately. \n $timeout(function() {\n $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, controller: controller};\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'dateType', 'dateFormat', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 // 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 if(options.dateType === 'string') {\n return formatDate(parsedDate, options.modelDateFormat || options.dateFormat);\n } else if(options.dateType === 'number') {\n return controller.$dateValue.getTime();\n } else if(options.dateType === 'unix') {\n return controller.$dateValue.getTime() / 1000;\n } else if(options.dateType === 'iso') {\n return controller.$dateValue.toISOString();\n } else {\n return new Date(controller.$dateValue);\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 = date;\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 var timezoneOffset = startDate.getTimezoneOffset() * 6e4;\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) {\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 = new Date().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 placement: 'bottom-left',\n template: '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.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.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(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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.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+)[ ]?(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 a => :\n this.timeSeparator = function(timeFormat) {\n return splitTimeFormat(timeFormat)[1];\n };\n\n // h:mm a => true, H.mm => false\n this.showAM = function(timeFormat) {\n return !!splitTimeFormat(timeFormat)[3];\n };\n\n this.formatDate = function(date, format, lang){\n return dateFilter(date, format);\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 // 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 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 $parseOptions.$values = values ? 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.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 template: 'modal/modal.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($window, $rootScope, $compile, $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 var htmlReplaceRegExp = /ng-bind=\"/ig;\n\n function ModalFactory(config) {\n\n var $modal = {};\n\n // Common vars\n var options = $modal.$options = angular.extend({}, defaults, config);\n $modal.$promise = fetchTemplate(options.template);\n var scope = $modal.$scope = options.scope && options.scope.$new() || $rootScope.$new();\n if(!options.element && !options.container) {\n options.container = 'body';\n }\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 // Support contentTemplate option\n if(options.contentTemplate) {\n $modal.$promise = $modal.$promise.then(function(template) {\n var templateEl = angular.element(template);\n return fetchTemplate(options.contentTemplate)\n .then(function(contentTemplate) {\n var contentEl = findElement('[ng-bind=\"content\"]', templateEl[0]).removeAttr('ng-bind').html(contentTemplate);\n // Drop the default footer as you probably don't want it if you use a custom contentTemplate\n if(!config.template) contentEl.next().remove();\n return templateEl[0].outerHTML;\n });\n });\n }\n\n // Fetch, compile then initialize modal\n var modalLinker, modalElement;\n var backdropElement = angular.element('
');\n $modal.$promise.then(function(template) {\n if(angular.isObject(template)) template = template.data;\n if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html=\"');\n template = trim.apply(template);\n modalLinker = $compile(template);\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 if(modalElement) {\n modalElement.remove();\n modalElement = null;\n }\n if(backdropElement) {\n backdropElement.remove();\n backdropElement = null;\n }\n\n // Destroy scope\n scope.$destroy();\n\n };\n\n $modal.show = function() {\n if($modal.$isShown) return;\n\n if(scope.$emit(options.prefixEvent + '.show.before', $modal).defaultPrevented) {\n 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].lastChild ? angular.element(parent[0].lastChild) : null;\n } else {\n parent = null;\n after = options.element;\n }\n }\n\n // Fetch a cloned element linked from template\n modalElement = $modal.$element = modalLinker(scope, function(clonedElement, scope) {});\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 // Support v1.3+ $animate\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\n var promise = $animate.enter(modalElement, parent, after, enterAnimateCallback);\n if(promise && promise.then) promise.then(enterAnimateCallback);\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 if(options.backdrop) {\n modalElement.on('click', hideOnBackdropClick);\n backdropElement.on('click', hideOnBackdropClick);\n backdropElement.on('wheel', preventEventDefault);\n }\n if(options.keyboard) {\n modalElement.on('keyup', $modal.$onKeyUp);\n }\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 var promise = $animate.leave(modalElement, leaveAnimateCallback);\n // Support v1.3+ $animate\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\n if(promise && promise.then) promise.then(leaveAnimateCallback);\n\n if(options.backdrop) {\n $animate.leave(backdropElement);\n }\n $modal.$isShown = scope.$isShown = false;\n safeDigest(scope);\n\n // Unbind events\n if(options.backdrop) {\n modalElement.off('click', hideOnBackdropClick);\n backdropElement.off('click', hideOnBackdropClick);\n backdropElement.off('wheel', preventEventDefault);\n }\n if(options.keyboard) {\n modalElement.off('keyup', $modal.$onKeyUp);\n }\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 // 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 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 var fetchPromises = {};\n function fetchTemplate(template) {\n if(fetchPromises[template]) return fetchPromises[template];\n return (fetchPromises[template] = $q.when($templateCache.get(template) || $http.get(template))\n .then(function(res) {\n if(angular.isObject(res)) {\n $templateCache.put(template, res.data);\n return res.data;\n }\n return res;\n }));\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', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 container: false,\n target: false,\n placement: 'right',\n template: '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', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'customClass', 'autoClose'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 // 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 template: '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 scope.$activeIndex = 0;\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 scope.$activeIndex.sort();\n $select.$isActive(index) ? scope.$activeIndex.splice(scope.$activeIndex.indexOf(index), 1) : scope.$activeIndex.push(index);\n if(options.sort) scope.$activeIndex.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);\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 // Select with enter\n if(!options.multiple && (evt.keyCode === 13 || evt.keyCode === 9)) {\n return $select.select(scope.$activeIndex);\n }\n\n // Navigate with keyboard\n 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 = $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 $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(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'placeholder', 'multiple', 'allNoneButtons', 'maxLength', 'maxLengthHtml', 'allText', 'noneText'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 ngOptions\n var parsedOptions = $parseOptions(attr.ngOptions);\n\n // Initialize select\n var select = $select(element, controller, options);\n\n // Watch ngOptions values before filtering for changes\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').trim();\n scope.$watch(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 }, true);\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) + 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.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 // DEPRECATED: $viewChangeListeners, please use $activePaneChangeListeners\n // Because we deprecated ngModel usage, we rename viewChangeListeners to \n // activePaneChangeListeners to make more sense.\n self.$activePaneChangeListeners = self.$viewChangeListeners = [];\n\n self.$push = function(pane) {\n self.$panes.push(pane);\n };\n\n self.$remove = function(pane) {\n var index = self.$panes.indexOf(pane);\n var activeIndex = self.$panes.$active;\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 self.$setActive(activeIndex);\n };\n\n self.$panes.$active = 0;\n self.$setActive = $scope.$setActive = function(value) {\n self.$panes.$active = value;\n self.$activePaneChangeListeners.forEach(function(fn) {\n fn();\n });\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 // DEPRECATED: ngModel, please use bsActivePane\n // 'ngModel' is deprecated bacause if interferes with form validation\n // and status, so avoid using it here.\n if(ngModelCtrl) {\n console.warn('Usage of ngModel is deprecated, please use bsActivePane instead!');\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 * 1);\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 * 1);\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 // Add animation class\n if(bsTabsCtrl.$options.animation) {\n element.addClass(bsTabsCtrl.$options.animation);\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 var active = bsTabsCtrl.$panes.$active;\n $animate[index === active ? 'addClass' : 'removeClass'](element, bsTabsCtrl.$options.activeClass);\n }\n\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\n render();\n });\n render();\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.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 template: 'tooltip/tooltip.tpl.html',\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 };\n\n this.$get = function($window, $rootScope, $compile, $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 nodeName = element[0].nodeName.toLowerCase();\n var options = $tooltip.$options = angular.extend({}, defaults, config);\n $tooltip.$promise = fetchTemplate(options.template);\n var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new();\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 // 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 // Support contentTemplate option\n if(options.contentTemplate) {\n $tooltip.$promise = $tooltip.$promise.then(function(template) {\n var templateEl = angular.element(template);\n return fetchTemplate(options.contentTemplate)\n .then(function(contentTemplate) {\n var contentEl = findElement('[ng-bind=\"content\"]', templateEl[0]);\n if(!contentEl.length) contentEl = findElement('[ng-bind=\"title\"]', templateEl[0]);\n contentEl.removeAttr('ng-bind').html(contentTemplate);\n return templateEl[0].outerHTML;\n });\n });\n }\n\n // Fetch, compile then initialize tooltip\n var tipLinker, tipElement, tipTemplate, tipContainer, tipScope;\n $tooltip.$promise.then(function(template) {\n if(angular.isObject(template)) template = template.data;\n if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html=\"');\n template = trim.apply(template);\n tipTemplate = template;\n tipLinker = $compile(template);\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 = tipLinker(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', 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 // Support v1.3+ $animate\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\n var promise = $animate.enter(tipElement, parent, after, enterAnimateCallback);\n if(promise && promise.then) promise.then(enterAnimateCallback);\n\n $tooltip.$isShown = scope.$isShown = true;\n safeDigest(scope);\n $$rAF(function () {\n $tooltip.$applyPlacement();\n\n // Once placed, make the tooltip visible\n if(tipElement) tipElement.css({visibility: 'visible'});\n }); // var a = bodyEl.offsetWidth + 1; ?\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 $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 // Support v1.3+ $animate\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\n var promise = $animate.leave(tipElement, leaveAnimateCallback);\n if(promise && promise.then) promise.then(leaveAnimateCallback);\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 // 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 $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 // Protected methods\n\n $tooltip.$applyPlacement = function() {\n if(!tipElement) return;\n\n // Determine if we're doing an auto or normal placement\n var placement = options.placement,\n autoToken = /\\s?auto?\\s?/i,\n autoPlace = autoToken.test(placement);\n\n if (autoPlace) {\n placement = placement.replace(autoToken, '') || defaults.placement;\n }\n\n // Need to add the position class before we get\n // the offsets\n tipElement.addClass(options.placement);\n\n // Get the position of the target element\n // and the height and width of the tooltip so we can center it.\n var elementPosition = getPosition(),\n tipWidth = tipElement.prop('offsetWidth'),\n tipHeight = tipElement.prop('offsetHeight');\n\n // If we're auto placing, we need to check the positioning\n if (autoPlace) {\n var originalPlacement = placement;\n var container = options.container ? angular.element(document.querySelector(options.container)) : element.parent();\n var containerPosition = getPosition(container);\n\n // Determine if the vertical placement\n if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > containerPosition.bottom) {\n placement = originalPlacement.replace('bottom', 'top');\n } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < containerPosition.top) {\n placement = originalPlacement.replace('top', 'bottom');\n }\n\n // Determine the horizontal placement\n // The exotic placements of left and right are opposite of the standard placements. Their arrows are put on the left/right\n // and flow in the opposite direction of their placement.\n if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') &&\n elementPosition.right + tipWidth > containerPosition.width) {\n\n placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right');\n } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') &&\n elementPosition.left - tipWidth < containerPosition.left) {\n\n placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left');\n }\n\n tipElement.removeClass(originalPlacement).addClass(placement);\n }\n\n // Get the tooltip's top and left coordinates to center it with this directive.\n var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight);\n applyPlacementCss(tipPosition.top, tipPosition.left);\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\n var elRect = el.getBoundingClientRect();\n if (elRect.width === null) {\n // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093\n elRect = angular.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top });\n }\n\n var elPos;\n if (options.container === 'body') {\n elPos = dimensions.offset(el);\n } else {\n elPos = dimensions.position(el);\n }\n\n return angular.extend({}, elRect, elPos);\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 applyPlacementCss(top, left) {\n tipElement.css({ top: top + 'px', left: left + 'px' });\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] = $q.when($templateCache.get(template) || $http.get(template))\n .then(function(res) {\n if(angular.isObject(res)) {\n $templateCache.put(template, res.data);\n return res.data;\n }\n return res;\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', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'backdropAnimation', 'type', 'customClass'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 // 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.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 template: 'typeahead/typeahead.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n minLength: 1,\n filter: 'filter',\n limit: 6,\n comparator: ''\n };\n\n this.$get = function($window, $rootScope, $tooltip, $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 = 0;\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 = 0;\n }\n };\n\n $typeahead.activate = function(index) {\n scope.$activeIndex = index;\n };\n\n $typeahead.select = function(index) {\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);\n };\n\n // Protected methods\n\n $typeahead.$isVisible = function() {\n if(!options.minLength || !controller) {\n return !!scope.$matches.length;\n }\n // minLength support\n return scope.$matches.length && angular.isString(controller.$viewValue) && controller.$viewValue.length >= options.minLength;\n };\n\n $typeahead.$getIndex = function(value) {\n var l = scope.$matches.length, i = l;\n if(!l) return;\n for(i = l; i--;) {\n if(scope.$matches[i].value === value) break;\n }\n if(i < 0) return;\n return i;\n };\n\n $typeahead.$onMouseDown = function(evt) {\n // Prevent blur on mousedown\n evt.preventDefault();\n evt.stopPropagation();\n };\n\n $typeahead.$onKeyDown = function(evt) {\n if(!/(38|40|13)/.test(evt.keyCode)) return;\n\n // Let ngSubmit pass if the typeahead tip is hidden\n if($typeahead.$isVisible()) {\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 imediately.\n $timeout(function() {\n $typeahead.$element.on('mousedown', $typeahead.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $typeahead.$onKeyDown);\n }\n }, 0, false);\n };\n\n var hide = $typeahead.hide;\n $typeahead.hide = function() {\n $typeahead.$element.off('mousedown', $typeahead.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $typeahead.$onKeyDown);\n }\n hide();\n };\n\n return $typeahead;\n\n }\n\n TypeaheadFactory.defaults = defaults;\n return TypeaheadFactory;\n\n };\n\n })\n\n .directive('bsTypeahead', function($window, $parse, $q, $typeahead, $parseOptions) {\n\n var defaults = $typeahead.defaults;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'filter', 'limit', 'minLength', 'watchOptions', 'selectMode', 'comparator'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Build proper ngOptions\n var filter = options.filter || defaults.filter;\n var limit = options.limit || defaults.limit;\n var comparator = options.comparator || defaults.comparator;\n\n var ngOptions = attr.ngOptions;\n if(filter) ngOptions += ' | ' + filter + ':$viewValue';\n if (comparator) ngOptions += ':' + comparator;\n if(limit) ngOptions += ' | limitTo:' + limit;\n var parsedOptions = $parseOptions(ngOptions);\n\n // Initialize typeahead\n var typeahead = $typeahead(element, controller, options);\n\n // Watch options on demand\n if(options.watchOptions) {\n // Watch ngOptions values before filtering for changes, drop function calls\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').replace(/\\(.*\\)/g, '').trim();\n scope.$watch(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 }, true);\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 return displayValue === undefined ? '' : displayValue;\n });\n\n // Model rendering in view\n controller.$render = function () {\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n if(controller.$isEmpty(controller.$viewValue)) return element.val('');\n var index = typeahead.$getIndex(controller.$modelValue);\n var selected = angular.isDefined(index) ? typeahead.$scope.$matches[index].label : controller.$viewValue;\n selected = angular.isObject(selected) ? parsedOptions.displayValue(selected) : selected;\n element.val(selected ? selected.toString().replace(/<(?:.|\\n)*?>/gm, '').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.timepicker', [\n 'mgcrea.ngStrap.helpers.dateParser',\n 'mgcrea.ngStrap.helpers.dateFormatter',\n 'mgcrea.ngStrap.tooltip'])\n\n .provider('$timepicker', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'timepicker',\n placement: 'bottom-left',\n template: '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 modelTimeFormat: null,\n autoclose: false,\n minTime: -Infinity,\n maxTime: +Infinity,\n length: 5,\n hourStep: 1,\n minuteStep: 5,\n iconUp: 'glyphicon glyphicon-chevron-up',\n iconDown: 'glyphicon glyphicon-chevron-down',\n arrowBehavior: 'pager'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\n\n function timepickerFactory(element, controller, config) {\n\n var $timepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $timepicker.$options;\n var scope = $timepicker.$scope;\n\n var lang = options.lang;\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n\n // View vars\n\n var selectedIndex = 0;\n var startDate = controller.$dateValue || new Date();\n var viewDate = {hour: startDate.getHours(), meridian: startDate.getHours() < 12, minute: startDate.getMinutes(), second: startDate.getSeconds(), millisecond: startDate.getMilliseconds()};\n\n var format = $dateFormatter.getDatetimeFormat(options.timeFormat, lang);\n\n var hoursFormat = $dateFormatter.hoursFormat(format),\n timeSeparator = $dateFormatter.timeSeparator(format),\n minutesFormat = $dateFormatter.minutesFormat(format),\n showAM = $dateFormatter.showAM(format);\n\n scope.$iconUp = options.iconUp;\n scope.$iconDown = options.iconDown;\n\n // Scope methods\n\n scope.$select = function(date, index) {\n $timepicker.select(date, index);\n };\n scope.$moveIndex = function(value, index) {\n $timepicker.$moveIndex(value, index);\n };\n scope.$switchMeridian = function(date) {\n $timepicker.switchMeridian(date);\n };\n\n // Public methods\n\n $timepicker.update = function(date) {\n // console.warn('$timepicker.update() newValue=%o', date);\n if(angular.isDate(date) && !isNaN(date.getTime())) {\n $timepicker.$date = date;\n angular.extend(viewDate, {hour: date.getHours(), minute: date.getMinutes(), second: date.getSeconds(), millisecond: date.getMilliseconds()});\n $timepicker.$build();\n } else if(!$timepicker.$isBuilt) {\n $timepicker.$build();\n }\n };\n\n $timepicker.select = function(date, index, keep) {\n // console.warn('$timepicker.select', date, scope.$mode);\n if(!controller.$dateValue || isNaN(controller.$dateValue.getTime())) controller.$dateValue = new Date(1970, 0, 1);\n if(!angular.isDate(date)) date = new Date(date);\n if(index === 0) controller.$dateValue.setHours(date.getHours());\n else if(index === 1) controller.$dateValue.setMinutes(date.getMinutes());\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n if(options.autoclose && !keep) {\n $timeout(function() { $timepicker.hide(true); });\n }\n };\n\n $timepicker.switchMeridian = function(date) {\n if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) {\n return;\n }\n var hours = (date || controller.$dateValue).getHours();\n controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12);\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n };\n\n // Protected methods\n\n $timepicker.$build = function() {\n // console.warn('$timepicker.$build() viewDate=%o', viewDate);\n var i, midIndex = scope.midIndex = parseInt(options.length / 2, 10);\n var hours = [], hour;\n for(i = 0; i < options.length; i++) {\n hour = new Date(1970, 0, 1, viewDate.hour - (midIndex - i) * options.hourStep);\n hours.push({date: hour, label: formatDate(hour, hoursFormat), selected: $timepicker.$date && $timepicker.$isSelected(hour, 0), disabled: $timepicker.$isDisabled(hour, 0)});\n }\n var minutes = [], minute;\n for(i = 0; i < options.length; i++) {\n minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep);\n minutes.push({date: minute, label: formatDate(minute, minutesFormat), selected: $timepicker.$date && $timepicker.$isSelected(minute, 1), disabled: $timepicker.$isDisabled(minute, 1)});\n }\n\n var rows = [];\n for(i = 0; i < options.length; i++) {\n rows.push([hours[i], minutes[i]]);\n }\n scope.rows = rows;\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 }\n };\n\n $timepicker.$isDisabled = function(date, index) {\n var selectedTime;\n if(index === 0) {\n selectedTime = date.getTime() + viewDate.minute * 6e4;\n } else if(index === 1) {\n selectedTime = date.getTime() + viewDate.hour * 36e5;\n }\n return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1;\n };\n\n scope.$arrowAction = function (value, index) {\n if (options.arrowBehavior === 'picker') {\n $timepicker.$setTimeByStep(value,index);\n } else {\n $timepicker.$moveIndex(value,index);\n }\n };\n\n $timepicker.$setTimeByStep = function(value, index) {\n var newDate = new Date($timepicker.$date);\n var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;\n var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;\n if (index === 0) {\n newDate.setHours(hours - (parseInt(options.hourStep, 10) * value));\n }\n else {\n newDate.setMinutes(minutes - (parseInt(options.minuteStep, 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);\n angular.extend(viewDate, {hour: targetDate.getHours()});\n } else if(index === 1) {\n targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + (value * options.length * options.minuteStep));\n angular.extend(viewDate, {minute: targetDate.getMinutes()});\n }\n $timepicker.$build();\n };\n\n $timepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n if(evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $timepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // Close on enter\n if(evt.keyCode === 13) return $timepicker.hide(true);\n\n // Navigate with keyboard\n var newDate = new Date($timepicker.$date);\n var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;\n var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;\n var lateralMove = /(37|39)/.test(evt.keyCode);\n var count = 2 + 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 if(selectedIndex === 0) {\n if(evt.keyCode === 38) newDate.setHours(hours - parseInt(options.hourStep, 10));\n else if(evt.keyCode === 40) newDate.setHours(hours + 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 if(evt.keyCode === 38) newDate.setMinutes(minutes - parseInt(options.minuteStep, 10));\n else if(evt.keyCode === 40) newDate.setMinutes(minutes + parseInt(options.minuteStep, 10));\n // re-calculate minutes length because we have changes minutes value\n minutesLength = formatDate(newDate, minutesFormat).length;\n selectRange = [hoursLength + 1, hoursLength + 1 + minutesLength];\n } else if(selectedIndex === 2) {\n if(!lateralMove) $timepicker.switchMeridian();\n selectRange = [hoursLength + 1 + minutesLength + 1, hoursLength + 1 + minutesLength + 3];\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, end) {\n if(element[0].createTextRange) {\n var selRange = element[0].createTextRange();\n selRange.collapse(true);\n selRange.moveStart('character', start);\n selRange.moveEnd('character', end);\n selRange.select();\n } else if(element[0].setSelectionRange) {\n element[0].setSelectionRange(start, end);\n } else if(angular.isUndefined(element[0].selectionStart)) {\n element[0].selectionStart = start;\n element[0].selectionEnd = end;\n }\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $timepicker.init;\n $timepicker.init = function() {\n if(isNative && options.useNative) {\n element.prop('type', 'time');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if(isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $timepicker.destroy;\n $timepicker.destroy = function() {\n if(isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $timepicker.show;\n $timepicker.show = function() {\n _show();\n // use timeout to hookup the events to prevent \n // event bubbling from being processed imediately. \n $timeout(function() {\n $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if(options.keyboard) {\n 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.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $timepicker.$onKeyDown);\n }\n _hide(blur);\n };\n\n return $timepicker;\n\n }\n\n timepickerFactory.defaults = defaults;\n return timepickerFactory;\n\n };\n\n })\n\n\n .directive('bsTimepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) {\n\n var defaults = $timepicker.defaults;\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope, controller: controller};\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'timeType', 'timeFormat', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n\n // Initialize parser\n var dateParser = $dateParser({format: options.timeFormat, lang: lang});\n\n // Observe attributes for changes\n angular.forEach(['minTime', 'maxTime'], function(key) {\n // console.warn('attr.$observe(%s)', key, attr[key]);\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\n timepicker.$options[key] = dateParser.getTimeForAttribute(key, newValue);\n !isNaN(timepicker.$options[key]) && timepicker.$build();\n validateAgainstMinMaxTime(controller.$dateValue);\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue, controller.$dateValue);\n timepicker.update(controller.$dateValue);\n }, true);\n\n function validateAgainstMinMaxTime(parsedTime) {\n if (!angular.isDate(parsedTime)) return;\n var isMinValid = isNaN(options.minTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) >= options.minTime;\n var isMaxValid = isNaN(options.maxTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) <= options.maxTime;\n var isValid = isMinValid && isMaxValid;\n controller.$setValidity('date', isValid);\n controller.$setValidity('min', isMinValid);\n controller.$setValidity('max', isMaxValid);\n // Only update the model when we have a valid date\n if(!isValid) {\n return;\n }\n controller.$dateValue = parsedTime;\n }\n\n // viewValue -> $parsers -> modelValue\n controller.$parsers.unshift(function(viewValue) {\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\n // Null values should correctly reset the model value & validity\n if(!viewValue) {\n // BREAKING CHANGE:\n // return null (not undefined) when input value is empty, so angularjs 1.3 \n // ngModelController can go ahead and run validators, like ngRequired\n controller.$setValidity('date', true);\n return null;\n }\n var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue);\n if(!parsedTime || isNaN(parsedTime.getTime())) {\n controller.$setValidity('date', false);\n // return undefined, causes ngModelController to \n // invalidate model value \n return;\n } else {\n validateAgainstMinMaxTime(parsedTime);\n }\n if(options.timeType === 'string') {\n return formatDate(parsedTime, options.modelTimeFormat || options.timeFormat);\n } else if(options.timeType === 'number') {\n return controller.$dateValue.getTime();\n } else if(options.timeType === 'unix') {\n return controller.$dateValue.getTime() / 1000;\n } else if(options.timeType === 'iso') {\n return controller.$dateValue.toISOString();\n } else {\n return new Date(controller.$dateValue);\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 = date;\n return getTimeFormattedString();\n });\n\n // viewValue -> element\n controller.$render = function() {\n // console.warn('$render(\"%s\"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);\n element.val(getTimeFormattedString());\n };\n\n function getTimeFormattedString() {\n return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat);\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (timepicker) timepicker.destroy();\n options = null;\n timepicker = null;\n });\n\n }\n };\n\n });\n"],"sourceRoot":"/source/"} \ No newline at end of file +{"version":3,"sources":["module.js","affix/affix.js","alert/alert.js","aside/aside.js","button/button.js","collapse/collapse.js","datepicker/datepicker.js","dropdown/dropdown.js","helpers/date-formatter.js","helpers/date-parser.js","helpers/debounce.js","helpers/dimensions.js","helpers/parse-options.js","helpers/raf.js","modal/modal.js","navbar/navbar.js","popover/popover.js","select/select.js","tab/tab.js","scrollspy/scrollspy.js","timepicker/timepicker.js","tooltip/tooltip.js","typeahead/typeahead.js"],"names":[],"mappings":"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","file":"angular-strap.min.js","sourcesContent":["\nangular.module('mgcrea.ngStrap', [\n 'mgcrea.ngStrap.modal',\n 'mgcrea.ngStrap.aside',\n 'mgcrea.ngStrap.alert',\n 'mgcrea.ngStrap.button',\n 'mgcrea.ngStrap.select',\n 'mgcrea.ngStrap.datepicker',\n 'mgcrea.ngStrap.timepicker',\n 'mgcrea.ngStrap.navbar',\n 'mgcrea.ngStrap.tooltip',\n 'mgcrea.ngStrap.popover',\n 'mgcrea.ngStrap.dropdown',\n 'mgcrea.ngStrap.typeahead',\n 'mgcrea.ngStrap.scrollspy',\n 'mgcrea.ngStrap.affix',\n 'mgcrea.ngStrap.tab',\n 'mgcrea.ngStrap.collapse'\n]);\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 };\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 element.css('position', (options.offsetParent) ? '' : 'relative');\n if(setWidth) {\n element.css('width', '');\n }\n element.css('top', '');\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 element.css('position', (options.offsetParent) ? '' : 'relative');\n element.css('top', (options.offsetParent) ? '' : ((bodyEl[0].offsetHeight - offsetBottom - elementHeight - initialOffsetTop) + 'px'));\n } else { // affix === 'middle'\n unpin = null;\n if(setWidth) {\n element.css('width', element[0].offsetWidth + 'px');\n }\n element.css('position', 'fixed');\n element.css('top', initialAffixTop + 'px');\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 element.css('position', (options.offsetParent) ? '' : 'relative');\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 element.css('position', initialPosition);\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, offsetTop: 'auto', target: affixTarget ? affixTarget.$element : angular.element($window)};\n angular.forEach(['offsetTop', 'offsetBottom', 'offsetParent', 'offsetUnpin'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 template: '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', 'placement', 'keyboard', 'html', 'container', 'animation', 'duration', 'dismissable'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 template: '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', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 = constantValueRegExp.test(attr.value) ? scope.$eval(attr.value) : attr.value;\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 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 = angular.copy(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 || 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 prefixClass: 'datepicker',\n placement: 'bottom-left',\n template: '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 modelDateFormat: null,\n dayFormat: 'dd',\n monthFormat: 'MMM',\n yearFormat: 'yyyy',\n monthTitleFormat: 'MMMM yyyy',\n yearTitleFormat: 'yyyy',\n strictFormat: false,\n autoclose: false,\n minDate: -Infinity,\n maxDate: +Infinity,\n startView: 0,\n minView: 0,\n startWeek: 0,\n daysOfWeekDisabled: '',\n iconLeft: 'glyphicon glyphicon-chevron-left',\n iconRight: 'glyphicon glyphicon-chevron-right'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, datepickerViews, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\n\n function DatepickerFactory(element, controller, config) {\n\n var $datepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $datepicker.$options;\n var scope = $datepicker.$scope;\n if(options.startView) options.startView -= options.minView;\n\n // View vars\n\n var pickerViews = datepickerViews($datepicker);\n $datepicker.$views = pickerViews.views;\n var viewDate = pickerViews.viewDate;\n scope.$mode = options.startView;\n scope.$iconLeft = options.iconLeft;\n scope.$iconRight = options.iconRight;\n var $picker = $datepicker.$views[scope.$mode];\n\n // Scope methods\n\n scope.$select = function(date) {\n $datepicker.select(date);\n };\n scope.$selectPane = function(value) {\n $datepicker.$selectPane(value);\n };\n scope.$toggleMode = function() {\n $datepicker.setMode((scope.$mode + 1) % $datepicker.$views.length);\n };\n\n // Public methods\n\n $datepicker.update = function(date) {\n // console.warn('$datepicker.update() newValue=%o', date);\n if(angular.isDate(date) && !isNaN(date.getTime())) {\n $datepicker.$date = date;\n $picker.update.call($picker, date);\n }\n // Build only if pristine\n $datepicker.$build(true);\n };\n\n $datepicker.updateDisabledDates = function(dateRanges) {\n options.disabledDateRanges = dateRanges;\n for(var i = 0, l = scope.rows.length; i < l; i++) {\n angular.forEach(scope.rows[i], $datepicker.$setDisabledEl);\n }\n };\n\n $datepicker.select = function(date, keep) {\n // console.warn('$datepicker.select', date, scope.$mode);\n if(!angular.isDate(controller.$dateValue)) controller.$dateValue = new Date(date);\n if(!scope.$mode || keep) {\n controller.$setViewValue(angular.copy(date));\n controller.$render();\n if(options.autoclose && !keep) {\n $timeout(function() { $datepicker.hide(true); });\n }\n } else {\n angular.extend(viewDate, {year: date.getFullYear(), month: date.getMonth(), date: date.getDate()});\n $datepicker.setMode(scope.$mode - 1);\n $datepicker.$build();\n }\n };\n\n $datepicker.setMode = function(mode) {\n // console.warn('$datepicker.setMode', mode);\n scope.$mode = mode;\n $picker = $datepicker.$views[scope.$mode];\n $datepicker.$build();\n };\n\n // Protected methods\n\n $datepicker.$build = function(pristine) {\n // console.warn('$datepicker.$build() viewDate=%o', viewDate);\n if(pristine === true && $picker.built) return;\n if(pristine === false && !$picker.built) return;\n $picker.build.call($picker);\n };\n\n $datepicker.$updateSelected = function() {\n for(var i = 0, l = scope.rows.length; i < l; i++) {\n angular.forEach(scope.rows[i], updateSelected);\n }\n };\n\n $datepicker.$isSelected = function(date) {\n return $picker.isSelected(date);\n };\n\n $datepicker.$setDisabledEl = function(el) {\n el.disabled = $picker.isDisabled(el.date);\n };\n\n $datepicker.$selectPane = function(value) {\n var steps = $picker.steps;\n // set targetDate to first day of month to avoid problems with\n // date values rollover. This assumes the viewDate does not\n // depend on the day of the month\n var targetDate = new Date(Date.UTC(viewDate.year + ((steps.year || 0) * value), viewDate.month + ((steps.month || 0) * value), 1));\n angular.extend(viewDate, {year: targetDate.getUTCFullYear(), month: targetDate.getUTCMonth(), date: targetDate.getUTCDate()});\n $datepicker.$build();\n };\n\n $datepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $datepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n if(evt.keyCode === 13) {\n if(!scope.$mode) {\n return $datepicker.hide(true);\n } else {\n return scope.$apply(function() { $datepicker.setMode(scope.$mode - 1); });\n }\n }\n\n // Navigate with keyboard\n $picker.onKeyDown(evt);\n parentScope.$digest();\n };\n\n // Private\n\n function updateSelected(el) {\n el.selected = $datepicker.$isSelected(el.date);\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $datepicker.init;\n $datepicker.init = function() {\n if(isNative && options.useNative) {\n element.prop('type', 'date');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if(isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $datepicker.destroy;\n $datepicker.destroy = function() {\n if(isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $datepicker.show;\n $datepicker.show = function() {\n _show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n // if $datepicker is no longer showing, don't setup events\n if(!$datepicker.$isShown) return;\n $datepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $datepicker.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $datepicker.hide;\n $datepicker.hide = function(blur) {\n if(!$datepicker.$isShown) return;\n $datepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $datepicker.$onKeyDown);\n }\n _hide(blur);\n };\n\n return $datepicker;\n\n }\n\n DatepickerFactory.defaults = defaults;\n return DatepickerFactory;\n\n };\n\n })\n\n .directive('bsDatepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $datepicker) {\n\n var defaults = $datepicker.defaults;\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope, controller: controller};\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'dateType', 'dateFormat', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 // 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 if(options.dateType === 'string') {\n return formatDate(parsedDate, options.modelDateFormat || options.dateFormat);\n } else if(options.dateType === 'number') {\n return controller.$dateValue.getTime();\n } else if(options.dateType === 'unix') {\n return controller.$dateValue.getTime() / 1000;\n } else if(options.dateType === 'iso') {\n return controller.$dateValue.toISOString();\n } else {\n return new Date(controller.$dateValue);\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 = date;\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 var timezoneOffset = startDate.getTimezoneOffset() * 6e4;\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) {\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 = new Date().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 placement: 'bottom-left',\n template: '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.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.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(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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.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+)[ ]?(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 a => :\n this.timeSeparator = function(timeFormat) {\n return splitTimeFormat(timeFormat)[1];\n };\n\n // h:mm a => true, H.mm => false\n this.showAM = function(timeFormat) {\n return !!splitTimeFormat(timeFormat)[3];\n };\n\n this.formatDate = function(date, format, lang){\n return dateFilter(date, format);\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 // 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 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 $parseOptions.$values = values ? 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.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 template: 'modal/modal.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($window, $rootScope, $compile, $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 var htmlReplaceRegExp = /ng-bind=\"/ig;\n\n function ModalFactory(config) {\n\n var $modal = {};\n\n // Common vars\n var options = $modal.$options = angular.extend({}, defaults, config);\n $modal.$promise = fetchTemplate(options.template);\n var scope = $modal.$scope = options.scope && options.scope.$new() || $rootScope.$new();\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 // Support contentTemplate option\n if(options.contentTemplate) {\n $modal.$promise = $modal.$promise.then(function(template) {\n var templateEl = angular.element(template);\n return fetchTemplate(options.contentTemplate)\n .then(function(contentTemplate) {\n var contentEl = findElement('[ng-bind=\"content\"]', templateEl[0]).removeAttr('ng-bind').html(contentTemplate);\n // Drop the default footer as you probably don't want it if you use a custom contentTemplate\n if(!config.template) contentEl.next().remove();\n return templateEl[0].outerHTML;\n });\n });\n }\n\n // Fetch, compile then initialize modal\n var modalLinker, modalElement;\n var backdropElement = angular.element('
');\n $modal.$promise.then(function(template) {\n if(angular.isObject(template)) template = template.data;\n if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html=\"');\n template = trim.apply(template);\n modalLinker = $compile(template);\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 if(modalElement) {\n modalElement.remove();\n modalElement = null;\n }\n if(backdropElement) {\n backdropElement.remove();\n backdropElement = null;\n }\n\n // Destroy scope\n scope.$destroy();\n\n };\n\n $modal.show = function() {\n if($modal.$isShown) return;\n\n if(scope.$emit(options.prefixEvent + '.show.before', $modal).defaultPrevented) {\n 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].lastChild ? angular.element(parent[0].lastChild) : null;\n } else {\n parent = null;\n after = options.element;\n }\n }\n\n // Fetch a cloned element linked from template\n modalElement = $modal.$element = modalLinker(scope, function(clonedElement, scope) {});\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 // Support v1.3+ $animate\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\n var promise = $animate.enter(modalElement, parent, after, enterAnimateCallback);\n if(promise && promise.then) promise.then(enterAnimateCallback);\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 if(options.backdrop) {\n modalElement.on('click', hideOnBackdropClick);\n backdropElement.on('click', hideOnBackdropClick);\n backdropElement.on('wheel', preventEventDefault);\n }\n if(options.keyboard) {\n modalElement.on('keyup', $modal.$onKeyUp);\n }\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 var promise = $animate.leave(modalElement, leaveAnimateCallback);\n // Support v1.3+ $animate\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\n if(promise && promise.then) promise.then(leaveAnimateCallback);\n\n if(options.backdrop) {\n $animate.leave(backdropElement);\n }\n $modal.$isShown = scope.$isShown = false;\n safeDigest(scope);\n\n // Unbind events\n if(options.backdrop) {\n modalElement.off('click', hideOnBackdropClick);\n backdropElement.off('click', hideOnBackdropClick);\n backdropElement.off('wheel', preventEventDefault);\n }\n if(options.keyboard) {\n modalElement.off('keyup', $modal.$onKeyUp);\n }\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 // 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 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 var fetchPromises = {};\n function fetchTemplate(template) {\n if(fetchPromises[template]) return fetchPromises[template];\n return (fetchPromises[template] = $q.when($templateCache.get(template) || $http.get(template))\n .then(function(res) {\n if(angular.isObject(res)) {\n $templateCache.put(template, res.data);\n return res.data;\n }\n return res;\n }));\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', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 container: false,\n target: false,\n placement: 'right',\n template: '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', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'customClass', 'autoClose', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 // 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.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 template: '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 scope.$activeIndex = 0;\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 scope.$activeIndex.sort();\n $select.$isActive(index) ? scope.$activeIndex.splice(scope.$activeIndex.indexOf(index), 1) : scope.$activeIndex.push(index);\n if(options.sort) scope.$activeIndex.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 // Select with enter\n if(!options.multiple && (evt.keyCode === 13 || evt.keyCode === 9)) {\n return $select.select(scope.$activeIndex);\n }\n\n // Navigate with keyboard\n 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 = $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 $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(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'placeholder', 'multiple', 'allNoneButtons', 'maxLength', 'maxLengthHtml', 'allText', 'noneText', 'iconCheckmark', 'autoClose', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 ngOptions\n var parsedOptions = $parseOptions(attr.ngOptions);\n\n // Initialize select\n var select = $select(element, controller, options);\n\n // Watch ngOptions values before filtering for changes\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').trim();\n scope.$watch(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 }, true);\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) + 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.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 // DEPRECATED: $viewChangeListeners, please use $activePaneChangeListeners\n // Because we deprecated ngModel usage, we rename viewChangeListeners to \n // activePaneChangeListeners to make more sense.\n self.$activePaneChangeListeners = self.$viewChangeListeners = [];\n\n self.$push = function(pane) {\n self.$panes.push(pane);\n };\n\n self.$remove = function(pane) {\n var index = self.$panes.indexOf(pane);\n var activeIndex = self.$panes.$active;\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 self.$setActive(activeIndex);\n };\n\n self.$panes.$active = 0;\n self.$setActive = $scope.$setActive = function(value) {\n self.$panes.$active = value;\n self.$activePaneChangeListeners.forEach(function(fn) {\n fn();\n });\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 // DEPRECATED: ngModel, please use bsActivePane\n // 'ngModel' is deprecated bacause if interferes with form validation\n // and status, so avoid using it here.\n if(ngModelCtrl) {\n console.warn('Usage of ngModel is deprecated, please use bsActivePane instead!');\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 * 1);\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 * 1);\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 // Add animation class\n if(bsTabsCtrl.$options.animation) {\n element.addClass(bsTabsCtrl.$options.animation);\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 var active = bsTabsCtrl.$panes.$active;\n $animate[index === active ? '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.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.timepicker', [\n 'mgcrea.ngStrap.helpers.dateParser',\n 'mgcrea.ngStrap.helpers.dateFormatter',\n 'mgcrea.ngStrap.tooltip'])\n\n .provider('$timepicker', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'timepicker',\n placement: 'bottom-left',\n template: '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 modelTimeFormat: null,\n autoclose: false,\n minTime: -Infinity,\n maxTime: +Infinity,\n length: 5,\n hourStep: 1,\n minuteStep: 5,\n iconUp: 'glyphicon glyphicon-chevron-up',\n iconDown: 'glyphicon glyphicon-chevron-down',\n arrowBehavior: 'pager'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\n\n function timepickerFactory(element, controller, config) {\n\n var $timepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $timepicker.$options;\n var scope = $timepicker.$scope;\n\n var lang = options.lang;\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n\n // View vars\n\n var selectedIndex = 0;\n var startDate = controller.$dateValue || new Date();\n var viewDate = {hour: startDate.getHours(), meridian: startDate.getHours() < 12, minute: startDate.getMinutes(), second: startDate.getSeconds(), millisecond: startDate.getMilliseconds()};\n\n var format = $dateFormatter.getDatetimeFormat(options.timeFormat, lang);\n\n var hoursFormat = $dateFormatter.hoursFormat(format),\n timeSeparator = $dateFormatter.timeSeparator(format),\n minutesFormat = $dateFormatter.minutesFormat(format),\n showAM = $dateFormatter.showAM(format);\n\n scope.$iconUp = options.iconUp;\n scope.$iconDown = options.iconDown;\n\n // Scope methods\n\n scope.$select = function(date, index) {\n $timepicker.select(date, index);\n };\n scope.$moveIndex = function(value, index) {\n $timepicker.$moveIndex(value, index);\n };\n scope.$switchMeridian = function(date) {\n $timepicker.switchMeridian(date);\n };\n\n // Public methods\n\n $timepicker.update = function(date) {\n // console.warn('$timepicker.update() newValue=%o', date);\n if(angular.isDate(date) && !isNaN(date.getTime())) {\n $timepicker.$date = date;\n angular.extend(viewDate, {hour: date.getHours(), minute: date.getMinutes(), second: date.getSeconds(), millisecond: date.getMilliseconds()});\n $timepicker.$build();\n } else if(!$timepicker.$isBuilt) {\n $timepicker.$build();\n }\n };\n\n $timepicker.select = function(date, index, keep) {\n // console.warn('$timepicker.select', date, scope.$mode);\n if(!controller.$dateValue || isNaN(controller.$dateValue.getTime())) controller.$dateValue = new Date(1970, 0, 1);\n if(!angular.isDate(date)) date = new Date(date);\n if(index === 0) controller.$dateValue.setHours(date.getHours());\n else if(index === 1) controller.$dateValue.setMinutes(date.getMinutes());\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n if(options.autoclose && !keep) {\n $timeout(function() { $timepicker.hide(true); });\n }\n };\n\n $timepicker.switchMeridian = function(date) {\n if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) {\n return;\n }\n var hours = (date || controller.$dateValue).getHours();\n controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12);\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n };\n\n // Protected methods\n\n $timepicker.$build = function() {\n // console.warn('$timepicker.$build() viewDate=%o', viewDate);\n var i, midIndex = scope.midIndex = parseInt(options.length / 2, 10);\n var hours = [], hour;\n for(i = 0; i < options.length; i++) {\n hour = new Date(1970, 0, 1, viewDate.hour - (midIndex - i) * options.hourStep);\n hours.push({date: hour, label: formatDate(hour, hoursFormat), selected: $timepicker.$date && $timepicker.$isSelected(hour, 0), disabled: $timepicker.$isDisabled(hour, 0)});\n }\n var minutes = [], minute;\n for(i = 0; i < options.length; i++) {\n minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep);\n minutes.push({date: minute, label: formatDate(minute, minutesFormat), selected: $timepicker.$date && $timepicker.$isSelected(minute, 1), disabled: $timepicker.$isDisabled(minute, 1)});\n }\n\n var rows = [];\n for(i = 0; i < options.length; i++) {\n rows.push([hours[i], minutes[i]]);\n }\n scope.rows = rows;\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 }\n };\n\n $timepicker.$isDisabled = function(date, index) {\n var selectedTime;\n if(index === 0) {\n selectedTime = date.getTime() + viewDate.minute * 6e4;\n } else if(index === 1) {\n selectedTime = date.getTime() + viewDate.hour * 36e5;\n }\n return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1;\n };\n\n scope.$arrowAction = function (value, index) {\n if (options.arrowBehavior === 'picker') {\n $timepicker.$setTimeByStep(value,index);\n } else {\n $timepicker.$moveIndex(value,index);\n }\n };\n\n $timepicker.$setTimeByStep = function(value, index) {\n var newDate = new Date($timepicker.$date);\n var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;\n var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;\n if (index === 0) {\n newDate.setHours(hours - (parseInt(options.hourStep, 10) * value));\n }\n else {\n newDate.setMinutes(minutes - (parseInt(options.minuteStep, 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);\n angular.extend(viewDate, {hour: targetDate.getHours()});\n } else if(index === 1) {\n targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + (value * options.length * options.minuteStep));\n angular.extend(viewDate, {minute: targetDate.getMinutes()});\n }\n $timepicker.$build();\n };\n\n $timepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n if(evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $timepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // Close on enter\n if(evt.keyCode === 13) return $timepicker.hide(true);\n\n // Navigate with keyboard\n var newDate = new Date($timepicker.$date);\n var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;\n var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;\n var lateralMove = /(37|39)/.test(evt.keyCode);\n var count = 2 + 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 if(selectedIndex === 0) {\n if(evt.keyCode === 38) newDate.setHours(hours - parseInt(options.hourStep, 10));\n else if(evt.keyCode === 40) newDate.setHours(hours + 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 if(evt.keyCode === 38) newDate.setMinutes(minutes - parseInt(options.minuteStep, 10));\n else if(evt.keyCode === 40) newDate.setMinutes(minutes + parseInt(options.minuteStep, 10));\n // re-calculate minutes length because we have changes minutes value\n minutesLength = formatDate(newDate, minutesFormat).length;\n selectRange = [hoursLength + 1, hoursLength + 1 + minutesLength];\n } else if(selectedIndex === 2) {\n if(!lateralMove) $timepicker.switchMeridian();\n selectRange = [hoursLength + 1 + minutesLength + 1, hoursLength + 1 + minutesLength + 3];\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, end) {\n if(element[0].createTextRange) {\n var selRange = element[0].createTextRange();\n selRange.collapse(true);\n selRange.moveStart('character', start);\n selRange.moveEnd('character', end);\n selRange.select();\n } else if(element[0].setSelectionRange) {\n element[0].setSelectionRange(start, end);\n } else if(angular.isUndefined(element[0].selectionStart)) {\n element[0].selectionStart = start;\n element[0].selectionEnd = end;\n }\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $timepicker.init;\n $timepicker.init = function() {\n if(isNative && options.useNative) {\n element.prop('type', 'time');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if(isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $timepicker.destroy;\n $timepicker.destroy = function() {\n if(isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $timepicker.show;\n $timepicker.show = function() {\n _show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if(options.keyboard) {\n 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.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $timepicker.$onKeyDown);\n }\n _hide(blur);\n };\n\n return $timepicker;\n\n }\n\n timepickerFactory.defaults = defaults;\n return timepickerFactory;\n\n };\n\n })\n\n\n .directive('bsTimepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) {\n\n var defaults = $timepicker.defaults;\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope, controller: controller};\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'timeType', 'timeFormat', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n\n // Initialize parser\n var dateParser = $dateParser({format: options.timeFormat, lang: lang});\n\n // Observe attributes for changes\n angular.forEach(['minTime', 'maxTime'], function(key) {\n // console.warn('attr.$observe(%s)', key, attr[key]);\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\n timepicker.$options[key] = dateParser.getTimeForAttribute(key, newValue);\n !isNaN(timepicker.$options[key]) && timepicker.$build();\n validateAgainstMinMaxTime(controller.$dateValue);\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue, controller.$dateValue);\n timepicker.update(controller.$dateValue);\n }, true);\n\n function validateAgainstMinMaxTime(parsedTime) {\n if (!angular.isDate(parsedTime)) return;\n var isMinValid = isNaN(options.minTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) >= options.minTime;\n var isMaxValid = isNaN(options.maxTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) <= options.maxTime;\n var isValid = isMinValid && isMaxValid;\n controller.$setValidity('date', isValid);\n controller.$setValidity('min', isMinValid);\n controller.$setValidity('max', isMaxValid);\n // Only update the model when we have a valid date\n if(!isValid) {\n return;\n }\n controller.$dateValue = parsedTime;\n }\n\n // viewValue -> $parsers -> modelValue\n controller.$parsers.unshift(function(viewValue) {\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\n // Null values should correctly reset the model value & validity\n if(!viewValue) {\n // BREAKING CHANGE:\n // return null (not undefined) when input value is empty, so angularjs 1.3\n // ngModelController can go ahead and run validators, like ngRequired\n controller.$setValidity('date', true);\n return null;\n }\n var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue);\n if(!parsedTime || isNaN(parsedTime.getTime())) {\n controller.$setValidity('date', false);\n // return undefined, causes ngModelController to\n // invalidate model value\n return;\n } else {\n validateAgainstMinMaxTime(parsedTime);\n }\n if(options.timeType === 'string') {\n return formatDate(parsedTime, options.modelTimeFormat || options.timeFormat);\n } else if(options.timeType === 'number') {\n return controller.$dateValue.getTime();\n } else if(options.timeType === 'unix') {\n return controller.$dateValue.getTime() / 1000;\n } else if(options.timeType === 'iso') {\n return controller.$dateValue.toISOString();\n } else {\n return new Date(controller.$dateValue);\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 = date;\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.tooltip', ['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 template: 'tooltip/tooltip.tpl.html',\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 };\n\n this.$get = function($window, $rootScope, $compile, $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 nodeName = element[0].nodeName.toLowerCase();\n var options = $tooltip.$options = angular.extend({}, defaults, config);\n $tooltip.$promise = fetchTemplate(options.template);\n var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new();\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 // Support contentTemplate option\n if(options.contentTemplate) {\n $tooltip.$promise = $tooltip.$promise.then(function(template) {\n var templateEl = angular.element(template);\n return fetchTemplate(options.contentTemplate)\n .then(function(contentTemplate) {\n var contentEl = findElement('[ng-bind=\"content\"]', templateEl[0]);\n if(!contentEl.length) contentEl = findElement('[ng-bind=\"title\"]', templateEl[0]);\n contentEl.removeAttr('ng-bind').html(contentTemplate);\n return templateEl[0].outerHTML;\n });\n });\n }\n\n // Fetch, compile then initialize tooltip\n var tipLinker, tipElement, tipTemplate, tipContainer, tipScope;\n $tooltip.$promise.then(function(template) {\n if(angular.isObject(template)) template = template.data;\n if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html=\"');\n template = trim.apply(template);\n tipTemplate = template;\n tipLinker = $compile(template);\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 = tipLinker(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', 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 // Support v1.3+ $animate\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\n var promise = $animate.enter(tipElement, parent, after, enterAnimateCallback);\n if(promise && promise.then) promise.then(enterAnimateCallback);\n\n $tooltip.$isShown = scope.$isShown = true;\n safeDigest(scope);\n $$rAF(function () {\n $tooltip.$applyPlacement();\n\n // Once placed, make the tooltip visible\n if(tipElement) tipElement.css({visibility: 'visible'});\n }); // var a = bodyEl.offsetWidth + 1; ?\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.3+ $animate\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\n var promise = $animate.leave(tipElement, leaveAnimateCallback);\n if(promise && promise.then) promise.then(leaveAnimateCallback);\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 // Protected methods\n\n $tooltip.$applyPlacement = function() {\n if(!tipElement) return;\n\n // Determine if we're doing an auto or normal placement\n var placement = options.placement,\n autoToken = /\\s?auto?\\s?/i,\n autoPlace = autoToken.test(placement);\n\n if (autoPlace) {\n placement = placement.replace(autoToken, '') || defaults.placement;\n }\n\n // Need to add the position class before we get\n // the offsets\n tipElement.addClass(options.placement);\n\n // Get the position of the target element\n // and the height and width of the tooltip so we can center it.\n var elementPosition = getPosition(),\n tipWidth = tipElement.prop('offsetWidth'),\n tipHeight = tipElement.prop('offsetHeight');\n\n // If we're auto placing, we need to check the positioning\n if (autoPlace) {\n var originalPlacement = placement;\n var container = options.container ? angular.element(document.querySelector(options.container)) : element.parent();\n var containerPosition = getPosition(container);\n\n // Determine if the vertical placement\n if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > containerPosition.bottom) {\n placement = originalPlacement.replace('bottom', 'top');\n } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < containerPosition.top) {\n placement = originalPlacement.replace('top', 'bottom');\n }\n\n // Determine the horizontal placement\n // The exotic placements of left and right are opposite of the standard placements. Their arrows are put on the left/right\n // and flow in the opposite direction of their placement.\n if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') &&\n elementPosition.right + tipWidth > containerPosition.width) {\n\n placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right');\n } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') &&\n elementPosition.left - tipWidth < containerPosition.left) {\n\n placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left');\n }\n\n tipElement.removeClass(originalPlacement).addClass(placement);\n }\n\n // Get the tooltip's top and left coordinates to center it with this directive.\n var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight);\n applyPlacementCss(tipPosition.top, tipPosition.left);\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\n var elRect = el.getBoundingClientRect();\n if (elRect.width === null) {\n // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093\n elRect = angular.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top });\n }\n\n var elPos;\n if (options.container === 'body') {\n elPos = dimensions.offset(el);\n } else {\n elPos = dimensions.position(el);\n }\n\n return angular.extend({}, elRect, elPos);\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 applyPlacementCss(top, left) {\n tipElement.css({ top: top + 'px', left: left + 'px' });\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] = $q.when($templateCache.get(template) || $http.get(template))\n .then(function(res) {\n if(angular.isObject(res)) {\n $templateCache.put(template, res.data);\n return res.data;\n }\n return res;\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', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'backdropAnimation', 'type', 'customClass', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 // 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.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 template: 'typeahead/typeahead.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n minLength: 1,\n filter: 'filter',\n limit: 6,\n comparator: ''\n };\n\n this.$get = function($window, $rootScope, $tooltip, $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 = 0;\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 = 0;\n }\n };\n\n $typeahead.activate = function(index) {\n scope.$activeIndex = index;\n };\n\n $typeahead.select = function(index) {\n var value = scope.$matches[index].value;\n // console.log('$setViewValue', value);\n controller.$setViewValue(value);\n controller.$render();\n scope.$resetMatches();\n if(parentScope) parentScope.$digest();\n // Emit event\n scope.$emit(options.prefixEvent + '.select', value, index, $typeahead);\n };\n\n // Protected methods\n\n $typeahead.$isVisible = function() {\n if(!options.minLength || !controller) {\n return !!scope.$matches.length;\n }\n // minLength support\n return scope.$matches.length && angular.isString(controller.$viewValue) && controller.$viewValue.length >= options.minLength;\n };\n\n $typeahead.$getIndex = function(value) {\n var l = scope.$matches.length, i = l;\n if(!l) return;\n for(i = l; i--;) {\n if(scope.$matches[i].value === value) break;\n }\n if(i < 0) return;\n return i;\n };\n\n $typeahead.$onMouseDown = function(evt) {\n // Prevent blur on mousedown\n evt.preventDefault();\n evt.stopPropagation();\n };\n\n $typeahead.$onKeyDown = function(evt) {\n if(!/(38|40|13)/.test(evt.keyCode)) return;\n\n // Let ngSubmit pass if the typeahead tip is hidden\n if($typeahead.$isVisible()) {\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 imediately.\n $timeout(function() {\n $typeahead.$element.on('mousedown', $typeahead.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $typeahead.$onKeyDown);\n }\n }, 0, false);\n };\n\n var hide = $typeahead.hide;\n $typeahead.hide = function() {\n $typeahead.$element.off('mousedown', $typeahead.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $typeahead.$onKeyDown);\n }\n hide();\n };\n\n return $typeahead;\n\n }\n\n TypeaheadFactory.defaults = defaults;\n return TypeaheadFactory;\n\n };\n\n })\n\n .directive('bsTypeahead', function($window, $parse, $q, $typeahead, $parseOptions) {\n\n var defaults = $typeahead.defaults;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'filter', 'limit', 'minLength', 'watchOptions', 'selectMode', 'comparator', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Build proper ngOptions\n var filter = options.filter || defaults.filter;\n var limit = options.limit || defaults.limit;\n var comparator = options.comparator || defaults.comparator;\n\n var ngOptions = attr.ngOptions;\n if(filter) ngOptions += ' | ' + filter + ':$viewValue';\n if (comparator) ngOptions += ':' + comparator;\n if(limit) ngOptions += ' | limitTo:' + limit;\n var parsedOptions = $parseOptions(ngOptions);\n\n // Initialize typeahead\n var typeahead = $typeahead(element, controller, options);\n\n // Watch options on demand\n if(options.watchOptions) {\n // Watch ngOptions values before filtering for changes, drop function calls\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').replace(/\\(.*\\)/g, '').trim();\n scope.$watch(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 }, true);\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 return displayValue === undefined ? '' : displayValue;\n });\n\n // Model rendering in view\n controller.$render = function () {\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n if(controller.$isEmpty(controller.$viewValue)) return element.val('');\n var index = typeahead.$getIndex(controller.$modelValue);\n var selected = angular.isDefined(index) ? typeahead.$scope.$matches[index].label : controller.$viewValue;\n selected = angular.isObject(selected) ? parsedOptions.displayValue(selected) : selected;\n element.val(selected ? selected.toString().replace(/<(?:.|\\n)*?>/gm, '').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/angular-strap.tpl.js b/dist/angular-strap.tpl.js index f1458b4f3..d85aa5323 100644 --- a/dist/angular-strap.tpl.js +++ b/dist/angular-strap.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -53,7 +53,7 @@ angular.module('mgcrea.ngStrap.popover').run(['$templateCache', function($templa // Source: select.tpl.js angular.module('mgcrea.ngStrap.select').run(['$templateCache', function($templateCache) { - $templateCache.put('select/select.tpl.html', ''); + $templateCache.put('select/select.tpl.html', ''); }]); @@ -64,6 +64,13 @@ angular.module('mgcrea.ngStrap.tab').run(['$templateCache', function($templateCa }]); +// Source: timepicker.tpl.js +angular.module('mgcrea.ngStrap.timepicker').run(['$templateCache', function($templateCache) { + + $templateCache.put('timepicker/timepicker.tpl.html', ''); + +}]); + // Source: tooltip.tpl.js angular.module('mgcrea.ngStrap.tooltip').run(['$templateCache', function($templateCache) { @@ -78,12 +85,5 @@ angular.module('mgcrea.ngStrap.typeahead').run(['$templateCache', function($temp }]); -// Source: timepicker.tpl.js -angular.module('mgcrea.ngStrap.timepicker').run(['$templateCache', function($templateCache) { - - $templateCache.put('timepicker/timepicker.tpl.html', ''); - -}]); - })(window, document); diff --git a/dist/angular-strap.tpl.min.js b/dist/angular-strap.tpl.min.js index 99c9e15ce..c8f44b6ea 100644 --- a/dist/angular-strap.tpl.min.js +++ b/dist/angular-strap.tpl.min.js @@ -1,8 +1,8 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT */ -!function(){"use strict";angular.module("mgcrea.ngStrap.alert").run(["$templateCache",function(t){t.put("alert/alert.tpl.html",'
 
')}]),angular.module("mgcrea.ngStrap.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.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",'')}]),angular.module("mgcrea.ngStrap.timepicker").run(["$templateCache",function(t){t.put("timepicker/timepicker.tpl.html",'')}])}(window,document); \ No newline at end of file +!function(){"use strict";angular.module("mgcrea.ngStrap.alert").run(["$templateCache",function(t){t.put("alert/alert.tpl.html",'
 
')}]),angular.module("mgcrea.ngStrap.aside").run(["$templateCache",function(t){t.put("aside/aside.tpl.html",'')}]),angular.module("mgcrea.ngStrap.datepicker").run(["$templateCache",function(t){t.put("datepicker/datepicker.tpl.html",'')}]),angular.module("mgcrea.ngStrap.dropdown").run(["$templateCache",function(t){t.put("dropdown/dropdown.tpl.html",'')}]),angular.module("mgcrea.ngStrap.modal").run(["$templateCache",function(t){t.put("modal/modal.tpl.html",'')}]),angular.module("mgcrea.ngStrap.popover").run(["$templateCache",function(t){t.put("popover/popover.tpl.html",'

')}]),angular.module("mgcrea.ngStrap.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 217c6f5bc..b5204a363 100644 --- a/dist/modules/affix.js +++ b/dist/modules/affix.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/affix.min.js b/dist/modules/affix.min.js index fe5198560..6c3fe016d 100644 --- a/dist/modules/affix.min.js +++ b/dist/modules/affix.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/alert.js b/dist/modules/alert.js index bc3f85c60..847a0fa45 100644 --- a/dist/modules/alert.js +++ b/dist/modules/alert.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/alert.min.js b/dist/modules/alert.min.js index 88f74c1be..15332863a 100644 --- a/dist/modules/alert.min.js +++ b/dist/modules/alert.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/alert.tpl.js b/dist/modules/alert.tpl.js index 6dcb59ab9..4aa781acf 100644 --- a/dist/modules/alert.tpl.js +++ b/dist/modules/alert.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/alert.tpl.min.js b/dist/modules/alert.tpl.min.js index e7de1359b..c7637430f 100644 --- a/dist/modules/alert.tpl.min.js +++ b/dist/modules/alert.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/aside.js b/dist/modules/aside.js index cfeb4f1c3..ffb84e16a 100644 --- a/dist/modules/aside.js +++ b/dist/modules/aside.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/aside.min.js b/dist/modules/aside.min.js index f8f8cdf16..890776273 100644 --- a/dist/modules/aside.min.js +++ b/dist/modules/aside.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/aside.tpl.js b/dist/modules/aside.tpl.js index 7dc40f873..7832318ac 100644 --- a/dist/modules/aside.tpl.js +++ b/dist/modules/aside.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/aside.tpl.min.js b/dist/modules/aside.tpl.min.js index 9b0030e0b..59bf618fb 100644 --- a/dist/modules/aside.tpl.min.js +++ b/dist/modules/aside.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/button.js b/dist/modules/button.js index 5112587b0..f4dd51023 100644 --- a/dist/modules/button.js +++ b/dist/modules/button.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/button.min.js b/dist/modules/button.min.js index fc504f3e0..9dedf97f1 100644 --- a/dist/modules/button.min.js +++ b/dist/modules/button.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/collapse.js b/dist/modules/collapse.js index c8212f4d5..c56206f20 100644 --- a/dist/modules/collapse.js +++ b/dist/modules/collapse.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -15,7 +15,8 @@ angular.module('mgcrea.ngStrap.collapse', []) animation: 'am-collapse', disallowToggle: false, activeClass: 'in', - startCollapsed: false + startCollapsed: false, + allowMultiple: false }; var controller = this.controller = function($scope, $element, $attrs) { @@ -23,7 +24,7 @@ angular.module('mgcrea.ngStrap.collapse', []) // Attributes options self.$options = angular.copy(defaults); - angular.forEach(['animation', 'disallowToggle', 'activeClass', 'startCollapsed'], function (key) { + angular.forEach(['animation', 'disallowToggle', 'activeClass', 'startCollapsed', 'allowMultiple'], function (key) { if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key]; }); @@ -46,36 +47,86 @@ angular.module('mgcrea.ngStrap.collapse', []) }; self.$unregisterTarget = function(element) { var index = self.$targets.indexOf(element); - var activeIndex = self.$targets.$active; // remove element from $targets array self.$targets.splice(index, 1); - if (index < activeIndex) { - // we removed a target before the active target, so we need to - // decrement the active target index - activeIndex--; + if (self.$options.allowMultiple) { + // remove target index from $active array values + deactivateItem(element); } - else if (index === activeIndex && activeIndex === self.$targets.length) { - // we remove the active target and it was the one at the end, - // so select the previous one - activeIndex--; - } - self.$setActive(activeIndex); + + // fix active item indexes + fixActiveItemIndexes(index); + + self.$viewChangeListeners.forEach(function(fn) { + fn(); + }); }; - self.$targets.$active = !self.$options.startCollapsed ? 0 : -1; + // use array to store all the currently open panels + self.$targets.$active = !self.$options.startCollapsed ? [0] : []; self.$setActive = $scope.$setActive = function(value) { - if(!self.$options.disallowToggle) { - self.$targets.$active = self.$targets.$active === value ? -1 : value; + if(angular.isArray(value)) { + self.$targets.$active = angular.copy(value); + } + else if(!self.$options.disallowToggle) { + // toogle element active status + isActive(value) ? deactivateItem(value) : activateItem(value); } else { - self.$targets.$active = value; + 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) { + // item with index was removed, so we + // need to adjust other items index values + var activeIndexes = self.$targets.$active; + for(var i = 0; i < activeIndexes.length; i++) { + if (index < activeIndexes[i]) { + activeIndexes[i] = activeIndexes[i] - 1; + } + + // the last item is active, so we need to + // adjust its index + if (activeIndexes[i] === self.$targets.length) { + activeIndexes[i] = self.$targets.length - 1; + } + } + } + + 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) { + // remove current selected item + self.$targets.$active.splice(0, 1); + } + + if (self.$targets.$active.indexOf(value) === -1) { + self.$targets.$active.push(value); + } + } + }; this.$get = function() { @@ -103,14 +154,30 @@ angular.module('mgcrea.ngStrap.collapse', []) // Update the modelValue following bsCollapseCtrl.$viewChangeListeners.push(function() { - ngModelCtrl.$setViewValue(bsCollapseCtrl.$targets.$active); + ngModelCtrl.$setViewValue(bsCollapseCtrl.$activeIndexes()); }); // modelValue -> $formatters -> viewValue ngModelCtrl.$formatters.push(function(modelValue) { // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue); - if (bsCollapseCtrl.$targets.$active !== modelValue * 1) { - bsCollapseCtrl.$setActive(modelValue * 1); + if (angular.isArray(modelValue)) { + // model value is an array, so just replace + // the active items directly + bsCollapseCtrl.$setActive(modelValue); + } + else { + var activeIndexes = bsCollapseCtrl.$activeIndexes(); + + if (angular.isArray(activeIndexes)) { + // we have an array of selected indexes + if (activeIndexes.indexOf(modelValue * 1) === -1) { + // item with modelValue index is not active + bsCollapseCtrl.$setActive(modelValue * 1); + } + } + else if (activeIndexes !== modelValue * 1) { + bsCollapseCtrl.$setActive(modelValue * 1); + } } return modelValue; }); @@ -181,8 +248,18 @@ angular.module('mgcrea.ngStrap.collapse', []) function render() { var index = bsCollapseCtrl.$targets.indexOf(element); - var active = bsCollapseCtrl.$targets.$active; - $animate[index === active ? 'addClass' : 'removeClass'](element, bsCollapseCtrl.$options.activeClass); + 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); } bsCollapseCtrl.$viewChangeListeners.push(function() { diff --git a/dist/modules/collapse.min.js b/dist/modules/collapse.min.js index 44334e872..29b9d19ad 100644 --- a/dist/modules/collapse.min.js +++ b/dist/modules/collapse.min.js @@ -1,9 +1,9 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT */ -"use strict";angular.module("mgcrea.ngStrap.collapse",[]).provider("$collapse",function(){var e=this.defaults={animation:"am-collapse",disallowToggle:!1,activeClass:"in",startCollapsed:!1},t=this.controller=function(t,s,a){var n=this;n.$options=angular.copy(e),angular.forEach(["animation","disallowToggle","activeClass","startCollapsed"],function(e){angular.isDefined(a[e])&&(n.$options[e]=a[e])}),n.$toggles=[],n.$targets=[],n.$viewChangeListeners=[],n.$registerToggle=function(e){n.$toggles.push(e)},n.$registerTarget=function(e){n.$targets.push(e)},n.$unregisterToggle=function(e){var t=n.$toggles.indexOf(e);n.$toggles.splice(t,1)},n.$unregisterTarget=function(e){var t=n.$targets.indexOf(e),s=n.$targets.$active;n.$targets.splice(t,1),s>t?s--:t===s&&s===n.$targets.length&&s--,n.$setActive(s)},n.$targets.$active=n.$options.startCollapsed?-1:0,n.$setActive=t.$setActive=function(e){n.$targets.$active=n.$options.disallowToggle?e:n.$targets.$active===e?-1:e,n.$viewChangeListeners.forEach(function(e){e()})}};this.$get=function(){var s={};return s.defaults=e,s.controller=t,s}}).directive("bsCollapse",["$window","$animate","$collapse",function(e,t,s){s.defaults;return{require:["?ngModel","bsCollapse"],controller:["$scope","$element","$attrs",s.controller],link:function(e,t,s,a){var n=a[0],i=a[1];n&&(i.$viewChangeListeners.push(function(){n.$setViewValue(i.$targets.$active)}),n.$formatters.push(function(e){return i.$targets.$active!==1*e&&i.$setActive(1*e),e}))}}}]).directive("bsCollapseToggle",function(){return{require:["^?ngModel","^bsCollapse"],link:function(e,t,s,a){var n=(a[0],a[1]);t.attr("data-toggle","collapse"),n.$registerToggle(t),e.$on("$destroy",function(){n.$unregisterToggle(t)}),t.on("click",function(){var a=s.bsCollapseToggle||n.$toggles.indexOf(t);n.$setActive(1*a),e.$apply()})}}}).directive("bsCollapseTarget",["$animate",function(e){return{require:["^?ngModel","^bsCollapse"],link:function(t,s,a,n){function i(){var t=o.$targets.indexOf(s),a=o.$targets.$active;e[t===a?"addClass":"removeClass"](s,o.$options.activeClass)}var o=(n[0],n[1]);s.addClass("collapse"),o.$options.animation&&s.addClass(o.$options.animation),o.$registerTarget(s),t.$on("$destroy",function(){o.$unregisterTarget(s)}),o.$viewChangeListeners.push(function(){i()}),i()}}}]); +"use strict";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,a,n){function i(e){for(var t=o.$targets.$active,a=0;a $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 (bsCollapseCtrl.$targets.$active !== modelValue * 1) {\n bsCollapseCtrl.$setActive(modelValue * 1);\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 || 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.$targets.$active;\n $animate[index === active ? 'addClass' : 'removeClass'](element, bsCollapseCtrl.$options.activeClass);\n }\n\n bsCollapseCtrl.$viewChangeListeners.push(function() {\n render();\n });\n render();\n\n }\n };\n\n });\n"],"sourceRoot":"/source/"} \ No newline at end of file +{"version":3,"sources":["collapse/collapse.js"],"names":[],"mappings":"qBASM,OAAA,uCAEA,YAAe,gCAGjB,UAAI,cACF,gBAAW,qCAGX,eAAK,uDA2ED,yBAAI,EAAA,EAAA,EAAA,EAA0B,OAAS,IACrC,EAAA,EAAwB,kBAMxB,EAAc,KAAK,EAAS,SAAA,SAChC,EAAO,GAAY,EAAQ,SAAA,OAAgB,WAKvC,GAAW,MACb,GAAc,EAAA,SAAe,sCAIjC,QAAS,GAAa,GACpB,GAAI,GAAM,EAAA,SAAS,QAAe,QAAA,WAEhC,EAAK,SAAS,QAAQ,OAAO,EAAG,WAI3B,GAAS,4DAMG,KAAlB,EAAO,SAAA,QAAW,QAAA,IACjB,EAAA,SAAY,QAAA,KAAA,yCAnGhB,QAAK,SAAA,YAAuB,iBAAA,cAAA,iBAAA,iBAAA,SAAA,iEAK5B,EAAK,sCAIL,EAAK,gBAAA,SAAoB,GACvB,EAAI,SAAQ,KAAK,MAEjB,gBAAqB,SAAO,8IAU1B,GAAA,EAAe,SAAA,QAAA,oDAOf,EAAA,QAMJ,EAAK,qBAAoB,QAAA,SAAa,GACpC,SAKE,SAAS,QAAS,EAAA,SAAe,mBAAS,gBACrC,EAAA,WAAA,SAAA,GACL,QAAA,QAAa,sCAGV,EAAA,SAAA,qCAOH,qBAAsB,QAAA,SAAe,sCAMvC,MAAI,GAAA,SAAgB,cAAc,EAAA,SAAA,QACD,IAAjC,EAAI,SAAW,QAAI,OAAc,EAAQ,SAAK,QAAA,GAAA,kCAiDlD,OAFD,GAAU,SAAA,iBAEL,eAKI,cAAS,UAAgB,WAAS,YAAO,SAAa,EAAA,EAAA,GAEtD,EAAc,yBAGf,WAAa,+FAIZ,GAAY,EAAc,gBAMd,qBAAqB,KAAA,mDAK5B,YAAA,KAAA,SAAA,2BAKG,WAAc,yCAKX,QAAA,wBAIX,EAAO,WAAA,EAAA,yDAiBP,mBAAiB,2BAGb,YAAK,sCAGb,OAAe,EAAA,WAIb,KAAA,cAAe,YAGjB,EAAW,gBAAoB,KAG7B,IAAM,WAAA,yJAeJ,oBAAc,WAAY,SAAA,gHA4BnB,EAAkB,iBACzB,EAAS,qDAGX,EAAS,YAGX,IAAe,IACb,EAAA,2CA7BF,GACE,IADgB,EAAS,GACR,EAAA,iDAOnB,EAAU,SAAA,EAAuB,SAAA,WAIjC,EAAS,gBAAS,KAGZ,IAAA,WAAS,WACb,EAAY,kBAAiB,4CAoBlC","file":"collapse.min.js","sourcesContent":["'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 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 = angular.copy(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 || 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"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/dist/modules/date-formatter.js b/dist/modules/date-formatter.js index 5b9efbf32..3a5ea177f 100644 --- a/dist/modules/date-formatter.js +++ b/dist/modules/date-formatter.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/date-formatter.min.js b/dist/modules/date-formatter.min.js index b36d7b41a..052113ca6 100644 --- a/dist/modules/date-formatter.min.js +++ b/dist/modules/date-formatter.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/date-parser.js b/dist/modules/date-parser.js index 7ced2a27d..98380a459 100644 --- a/dist/modules/date-parser.js +++ b/dist/modules/date-parser.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/date-parser.min.js b/dist/modules/date-parser.min.js index 10982b902..8170a9674 100644 --- a/dist/modules/date-parser.min.js +++ b/dist/modules/date-parser.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/datepicker.js b/dist/modules/datepicker.js index 8e7df83e5..22afdd936 100644 --- a/dist/modules/datepicker.js +++ b/dist/modules/datepicker.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -152,7 +152,7 @@ angular.module('mgcrea.ngStrap.datepicker', [ var steps = $picker.steps; // set targetDate to first day of month to avoid problems with // date values rollover. This assumes the viewDate does not - // depend on the day of the month + // depend on the day of the month var targetDate = new Date(Date.UTC(viewDate.year + ((steps.year || 0) * value), viewDate.month + ((steps.month || 0) * value), 1)); angular.extend(viewDate, {year: targetDate.getUTCFullYear(), month: targetDate.getUTCMonth(), date: targetDate.getUTCDate()}); $datepicker.$build(); @@ -227,9 +227,11 @@ angular.module('mgcrea.ngStrap.datepicker', [ var _show = $datepicker.show; $datepicker.show = function() { _show(); - // use timeout to hookup the events to prevent - // event bubbling from being processed imediately. + // use timeout to hookup the events to prevent + // event bubbling from being processed imediately. $timeout(function() { + // if $datepicker is no longer showing, don't setup events + if(!$datepicker.$isShown) return; $datepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown); if(options.keyboard) { element.on('keydown', $datepicker.$onKeyDown); @@ -270,7 +272,7 @@ angular.module('mgcrea.ngStrap.datepicker', [ // Directive options var options = {scope: scope, controller: controller}; - angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'dateType', 'dateFormat', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled'], function(key) { + angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'dateType', 'dateFormat', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled', 'id'], function(key) { if(angular.isDefined(attr[key])) options[key] = attr[key]; }); @@ -292,7 +294,7 @@ angular.module('mgcrea.ngStrap.datepicker', [ var formatDate = function(date, format) { return $dateFormatter.formatDate(date, format, lang); }; - + var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat}); // Observe attributes for changes @@ -349,15 +351,15 @@ angular.module('mgcrea.ngStrap.datepicker', [ if(!viewValue) { controller.$setValidity('date', true); // BREAKING CHANGE: - // return null (not undefined) when input value is empty, so angularjs 1.3 + // return null (not undefined) when input value is empty, so angularjs 1.3 // ngModelController can go ahead and run validators, like ngRequired return null; } var parsedDate = dateParser.parse(viewValue, controller.$dateValue); if(!parsedDate || isNaN(parsedDate.getTime())) { controller.$setValidity('date', false); - // return undefined, causes ngModelController to - // invalidate model value + // return undefined, causes ngModelController to + // invalidate model value return; } else { validateAgainstMinMaxDate(parsedDate); diff --git a/dist/modules/datepicker.min.js b/dist/modules/datepicker.min.js index 88d467544..7dd668aa4 100644 --- a/dist/modules/datepicker.min.js +++ b/dist/modules/datepicker.min.js @@ -1,9 +1,9 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT */ -"use strict";angular.module("mgcrea.ngStrap.datepicker",["mgcrea.ngStrap.helpers.dateParser","mgcrea.ngStrap.helpers.dateFormatter","mgcrea.ngStrap.tooltip"]).provider("$datepicker",function(){var e=this.defaults={animation:"am-fade",prefixClass:"datepicker",placement:"bottom-left",template:"datepicker/datepicker.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,useNative:!1,dateType:"date",dateFormat:"shortDate",modelDateFormat:null,dayFormat:"dd",monthFormat:"MMM",yearFormat:"yyyy",monthTitleFormat:"MMMM yyyy",yearTitleFormat:"yyyy",strictFormat:!1,autoclose:!1,minDate:-1/0,maxDate:+1/0,startView:0,minView:0,startWeek:0,daysOfWeekDisabled:"",iconLeft:"glyphicon glyphicon-chevron-left",iconRight:"glyphicon glyphicon-chevron-right"};this.$get=["$window","$document","$rootScope","$sce","$dateFormatter","datepickerViews","$tooltip","$timeout",function(t,a,n,i,o,r,d,s){function l(t,a,n){function i(e){e.selected=l.$isSelected(e.date)}function o(){t[0].focus()}var l=d(t,angular.extend({},e,n)),g=n.scope,$=l.$options,m=l.$scope;$.startView&&($.startView-=$.minView);var f=r(l);l.$views=f.views;var h=f.viewDate;m.$mode=$.startView,m.$iconLeft=$.iconLeft,m.$iconRight=$.iconRight;var D=l.$views[m.$mode];m.$select=function(e){l.select(e)},m.$selectPane=function(e){l.$selectPane(e)},m.$toggleMode=function(){l.setMode((m.$mode+1)%l.$views.length)},l.update=function(e){angular.isDate(e)&&!isNaN(e.getTime())&&(l.$date=e,D.update.call(D,e)),l.$build(!0)},l.updateDisabledDates=function(e){$.disabledDateRanges=e;for(var t=0,a=m.rows.length;a>t;t++)angular.forEach(m.rows[t],l.$setDisabledEl)},l.select=function(e,t){angular.isDate(a.$dateValue)||(a.$dateValue=new Date(e)),!m.$mode||t?(a.$setViewValue(angular.copy(e)),a.$render(),$.autoclose&&!t&&s(function(){l.hide(!0)})):(angular.extend(h,{year:e.getFullYear(),month:e.getMonth(),date:e.getDate()}),l.setMode(m.$mode-1),l.$build())},l.setMode=function(e){m.$mode=e,D=l.$views[m.$mode],l.$build()},l.$build=function(e){e===!0&&D.built||(e!==!1||D.built)&&D.build.call(D)},l.$updateSelected=function(){for(var e=0,t=m.rows.length;t>e;e++)angular.forEach(m.rows[e],i)},l.$isSelected=function(e){return D.isSelected(e)},l.$setDisabledEl=function(e){e.disabled=D.isDisabled(e.date)},l.$selectPane=function(e){var t=D.steps,a=new Date(Date.UTC(h.year+(t.year||0)*e,h.month+(t.month||0)*e,1));angular.extend(h,{year:a.getUTCFullYear(),month:a.getUTCMonth(),date:a.getUTCDate()}),l.$build()},l.$onMouseDown=function(e){if(e.preventDefault(),e.stopPropagation(),c){var t=angular.element(e.target);"button"!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler("click")}},l.$onKeyDown=function(e){if(/(38|37|39|40|13)/.test(e.keyCode)&&!e.shiftKey&&!e.altKey){if(e.preventDefault(),e.stopPropagation(),13===e.keyCode)return m.$mode?m.$apply(function(){l.setMode(m.$mode-1)}):l.hide(!0);D.onKeyDown(e),g.$digest()}};var y=l.init;l.init=function(){return u&&$.useNative?(t.prop("type","date"),void t.css("-webkit-appearance","textfield")):(c&&(t.prop("type","text"),t.attr("readonly","true"),t.on("click",o)),void y())};var p=l.destroy;l.destroy=function(){u&&$.useNative&&t.off("click",o),p()};var w=l.show;l.show=function(){w(),s(function(){l.$element.on(c?"touchstart":"mousedown",l.$onMouseDown),$.keyboard&&t.on("keydown",l.$onKeyDown)},0,!1)};var b=l.hide;return l.hide=function(e){l.$isShown&&(l.$element.off(c?"touchstart":"mousedown",l.$onMouseDown),$.keyboard&&t.off("keydown",l.$onKeyDown),b(e))},l}var u=(angular.element(t.document.body),/(ip(a|o)d|iphone|android)/gi.test(t.navigator.userAgent)),c="createTouch"in t.document&&u;return e.lang||(e.lang=o.getDefaultLocale()),l.defaults=e,l}]}).directive("bsDatepicker",["$window","$parse","$q","$dateFormatter","$dateParser","$datepicker",function(e,t,a,n,i,o){var r=(o.defaults,/(ip(a|o)d|iphone|android)/gi.test(e.navigator.userAgent));return{restrict:"EAC",require:"ngModel",link:function(e,t,a,d){function s(e){return e&&e.length?e:null}function l(e){if(angular.isDate(e)){var t=isNaN(g.$options.minDate)||e.getTime()>=g.$options.minDate,a=isNaN(g.$options.maxDate)||e.getTime()<=g.$options.maxDate,n=t&&a;d.$setValidity("date",n),d.$setValidity("min",t),d.$setValidity("max",a),n&&(d.$dateValue=e)}}function u(){return!d.$dateValue||isNaN(d.$dateValue.getTime())?"":m(d.$dateValue,c.dateFormat)}var c={scope:e,controller:d};angular.forEach(["placement","container","delay","trigger","keyboard","html","animation","template","autoclose","dateType","dateFormat","modelDateFormat","dayFormat","strictFormat","startWeek","startDate","useNative","lang","startView","minView","iconLeft","iconRight","daysOfWeekDisabled"],function(e){angular.isDefined(a[e])&&(c[e]=a[e])}),a.bsShow&&e.$watch(a.bsShow,function(e){g&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(datepicker),?/i)),e===!0?g.show():g.hide())});var g=o(t,d,c);c=g.$options,r&&c.useNative&&(c.dateFormat="yyyy-MM-dd");var $=c.lang,m=function(e,t){return n.formatDate(e,t,$)},f=i({format:c.dateFormat,lang:$,strict:c.strictFormat});angular.forEach(["minDate","maxDate"],function(e){angular.isDefined(a[e])&&a.$observe(e,function(t){g.$options[e]=f.getDateForAttribute(e,t),!isNaN(g.$options[e])&&g.$build(!1),l(d.$dateValue)})}),e.$watch(a.ngModel,function(){g.update(d.$dateValue)},!0),angular.isDefined(a.disabledDates)&&e.$watch(a.disabledDates,function(e,t){e=s(e),t=s(t),e&&g.updateDisabledDates(e)}),d.$parsers.unshift(function(e){if(!e)return d.$setValidity("date",!0),null;var t=f.parse(e,d.$dateValue);return!t||isNaN(t.getTime())?void d.$setValidity("date",!1):(l(t),"string"===c.dateType?m(t,c.modelDateFormat||c.dateFormat):"number"===c.dateType?d.$dateValue.getTime():"unix"===c.dateType?d.$dateValue.getTime()/1e3:"iso"===c.dateType?d.$dateValue.toISOString():new Date(d.$dateValue))}),d.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:"string"===c.dateType?f.parse(e,null,c.modelDateFormat):new Date("unix"===c.dateType?1e3*e:e),d.$dateValue=t,u()}),d.$render=function(){t.val(u())},e.$on("$destroy",function(){g&&g.destroy(),c=null,g=null})}}}]).provider("datepickerViews",function(){function e(e,t){for(var a=[];e.length>0;)a.push(e.splice(0,t));return a}function t(e,t){return(e%t+t)%t}this.defaults={dayFormat:"dd",daySplit:7};this.$get=["$dateFormatter","$dateParser","$sce",function(a,n,i){return function(o){var r=o.$scope,d=o.$options,s=d.lang,l=function(e,t){return a.formatDate(e,t,s)},u=n({format:d.dateFormat,lang:s,strict:d.strictFormat}),c=a.weekdaysShort(s),g=c.slice(d.startWeek).concat(c.slice(0,d.startWeek)),$=i.trustAsHtml(''+g.join('')+""),m=o.$date||(d.startDate?u.getDateForAttribute("startDate",d.startDate):new Date),f={year:m.getFullYear(),month:m.getMonth(),date:m.getDate()},h=(6e4*m.getTimezoneOffset(),[{format:d.dayFormat,split:7,steps:{month:1},update:function(e,t){!this.built||t||e.getFullYear()!==f.year||e.getMonth()!==f.month?(angular.extend(f,{year:o.$date.getFullYear(),month:o.$date.getMonth(),date:o.$date.getDate()}),o.$build()):e.getDate()!==f.date&&(f.date=o.$date.getDate(),o.$updateSelected())},build:function(){var a=new Date(f.year,f.month,1),n=a.getTimezoneOffset(),i=new Date(+a-864e5*t(a.getDay()-d.startWeek,7)),s=i.getTimezoneOffset(),c=(new Date).toDateString();s!==n&&(i=new Date(+i+6e4*(s-n)));for(var g,m=[],h=0;42>h;h++)g=u.daylightSavingAdjust(new Date(i.getFullYear(),i.getMonth(),i.getDate()+h)),m.push({date:g,isToday:g.toDateString()===c,label:l(g,this.format),selected:o.$date&&this.isSelected(g),muted:g.getMonth()!==f.month,disabled:this.isDisabled(g)});r.title=l(a,d.monthTitleFormat),r.showLabels=!0,r.labels=$,r.rows=e(m,this.split),this.built=!0},isSelected:function(e){return o.$date&&e.getFullYear()===o.$date.getFullYear()&&e.getMonth()===o.$date.getMonth()&&e.getDate()===o.$date.getDate()},isDisabled:function(e){var t=e.getTime();if(td.maxDate)return!0;if(-1!==d.daysOfWeekDisabled.indexOf(e.getDay()))return!0;if(d.disabledDateRanges)for(var a=0;a=d.disabledDateRanges[a].start&&t<=d.disabledDateRanges[a].end)return!0;return!1},onKeyDown:function(e){if(o.$date){var t,a=o.$date.getTime();37===e.keyCode?t=new Date(a-864e5):38===e.keyCode?t=new Date(a-6048e5):39===e.keyCode?t=new Date(a+864e5):40===e.keyCode&&(t=new Date(a+6048e5)),this.isDisabled(t)||o.select(t,!0)}}},{name:"month",format:d.monthFormat,split:4,steps:{year:1},update:function(e){this.built&&e.getFullYear()===f.year?e.getMonth()!==f.month&&(angular.extend(f,{month:o.$date.getMonth(),date:o.$date.getDate()}),o.$updateSelected()):(angular.extend(f,{year:o.$date.getFullYear(),month:o.$date.getMonth(),date:o.$date.getDate()}),o.$build())},build:function(){for(var t,a=(new Date(f.year,0,1),[]),n=0;12>n;n++)t=new Date(f.year,n,1),a.push({date:t,label:l(t,this.format),selected:o.$isSelected(t),disabled:this.isDisabled(t)});r.title=l(t,d.yearTitleFormat),r.showLabels=!1,r.rows=e(a,this.split),this.built=!0},isSelected:function(e){return o.$date&&e.getFullYear()===o.$date.getFullYear()&&e.getMonth()===o.$date.getMonth()},isDisabled:function(e){var t=+new Date(e.getFullYear(),e.getMonth()+1,0);return td.maxDate},onKeyDown:function(e){if(o.$date){var t=o.$date.getMonth(),a=new Date(o.$date);37===e.keyCode?a.setMonth(t-1):38===e.keyCode?a.setMonth(t-4):39===e.keyCode?a.setMonth(t+1):40===e.keyCode&&a.setMonth(t+4),this.isDisabled(a)||o.select(a,!0)}}},{name:"year",format:d.yearFormat,split:4,steps:{year:12},update:function(e,t){!this.built||t||parseInt(e.getFullYear()/20,10)!==parseInt(f.year/20,10)?(angular.extend(f,{year:o.$date.getFullYear(),month:o.$date.getMonth(),date:o.$date.getDate()}),o.$build()):e.getFullYear()!==f.year&&(angular.extend(f,{year:o.$date.getFullYear(),month:o.$date.getMonth(),date:o.$date.getDate()}),o.$updateSelected())},build:function(){for(var t,a=f.year-f.year%(3*this.split),n=[],i=0;12>i;i++)t=new Date(a+i,0,1),n.push({date:t,label:l(t,this.format),selected:o.$isSelected(t),disabled:this.isDisabled(t)});r.title=n[0].label+"-"+n[n.length-1].label,r.showLabels=!1,r.rows=e(n,this.split),this.built=!0},isSelected:function(e){return o.$date&&e.getFullYear()===o.$date.getFullYear()},isDisabled:function(e){var t=+new Date(e.getFullYear()+1,0,0);return td.maxDate},onKeyDown:function(e){if(o.$date){var t=o.$date.getFullYear(),a=new Date(o.$date);37===e.keyCode?a.setYear(t-1):38===e.keyCode?a.setYear(t-4):39===e.keyCode?a.setYear(t+1):40===e.keyCode&&a.setYear(t+4),this.isDisabled(a)||o.select(a,!0)}}}]);return{views:d.minView?Array.prototype.slice.call(h,d.minView):h,viewDate:f}}}]}); +"use strict";angular.module("mgcrea.ngStrap.datepicker",["mgcrea.ngStrap.helpers.dateParser","mgcrea.ngStrap.helpers.dateFormatter","mgcrea.ngStrap.tooltip"]).provider("$datepicker",function(){var e=this.defaults={animation:"am-fade",prefixClass:"datepicker",placement:"bottom-left",template:"datepicker/datepicker.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,useNative:!1,dateType:"date",dateFormat:"shortDate",modelDateFormat:null,dayFormat:"dd",monthFormat:"MMM",yearFormat:"yyyy",monthTitleFormat:"MMMM yyyy",yearTitleFormat:"yyyy",strictFormat:!1,autoclose:!1,minDate:-1/0,maxDate:+1/0,startView:0,minView:0,startWeek:0,daysOfWeekDisabled:"",iconLeft:"glyphicon glyphicon-chevron-left",iconRight:"glyphicon glyphicon-chevron-right"};this.$get=["$window","$document","$rootScope","$sce","$dateFormatter","datepickerViews","$tooltip","$timeout",function(t,a,n,i,o,r,d,s){function l(t,a,n){function i(e){e.selected=l.$isSelected(e.date)}function o(){t[0].focus()}var l=d(t,angular.extend({},e,n)),g=n.scope,$=l.$options,m=l.$scope;$.startView&&($.startView-=$.minView);var f=r(l);l.$views=f.views;var h=f.viewDate;m.$mode=$.startView,m.$iconLeft=$.iconLeft,m.$iconRight=$.iconRight;var D=l.$views[m.$mode];m.$select=function(e){l.select(e)},m.$selectPane=function(e){l.$selectPane(e)},m.$toggleMode=function(){l.setMode((m.$mode+1)%l.$views.length)},l.update=function(e){angular.isDate(e)&&!isNaN(e.getTime())&&(l.$date=e,D.update.call(D,e)),l.$build(!0)},l.updateDisabledDates=function(e){$.disabledDateRanges=e;for(var t=0,a=m.rows.length;a>t;t++)angular.forEach(m.rows[t],l.$setDisabledEl)},l.select=function(e,t){angular.isDate(a.$dateValue)||(a.$dateValue=new Date(e)),!m.$mode||t?(a.$setViewValue(angular.copy(e)),a.$render(),$.autoclose&&!t&&s(function(){l.hide(!0)})):(angular.extend(h,{year:e.getFullYear(),month:e.getMonth(),date:e.getDate()}),l.setMode(m.$mode-1),l.$build())},l.setMode=function(e){m.$mode=e,D=l.$views[m.$mode],l.$build()},l.$build=function(e){e===!0&&D.built||(e!==!1||D.built)&&D.build.call(D)},l.$updateSelected=function(){for(var e=0,t=m.rows.length;t>e;e++)angular.forEach(m.rows[e],i)},l.$isSelected=function(e){return D.isSelected(e)},l.$setDisabledEl=function(e){e.disabled=D.isDisabled(e.date)},l.$selectPane=function(e){var t=D.steps,a=new Date(Date.UTC(h.year+(t.year||0)*e,h.month+(t.month||0)*e,1));angular.extend(h,{year:a.getUTCFullYear(),month:a.getUTCMonth(),date:a.getUTCDate()}),l.$build()},l.$onMouseDown=function(e){if(e.preventDefault(),e.stopPropagation(),c){var t=angular.element(e.target);"button"!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler("click")}},l.$onKeyDown=function(e){if(/(38|37|39|40|13)/.test(e.keyCode)&&!e.shiftKey&&!e.altKey){if(e.preventDefault(),e.stopPropagation(),13===e.keyCode)return m.$mode?m.$apply(function(){l.setMode(m.$mode-1)}):l.hide(!0);D.onKeyDown(e),g.$digest()}};var y=l.init;l.init=function(){return u&&$.useNative?(t.prop("type","date"),void t.css("-webkit-appearance","textfield")):(c&&(t.prop("type","text"),t.attr("readonly","true"),t.on("click",o)),void y())};var p=l.destroy;l.destroy=function(){u&&$.useNative&&t.off("click",o),p()};var w=l.show;l.show=function(){w(),s(function(){l.$isShown&&(l.$element.on(c?"touchstart":"mousedown",l.$onMouseDown),$.keyboard&&t.on("keydown",l.$onKeyDown))},0,!1)};var b=l.hide;return l.hide=function(e){l.$isShown&&(l.$element.off(c?"touchstart":"mousedown",l.$onMouseDown),$.keyboard&&t.off("keydown",l.$onKeyDown),b(e))},l}var u=(angular.element(t.document.body),/(ip(a|o)d|iphone|android)/gi.test(t.navigator.userAgent)),c="createTouch"in t.document&&u;return e.lang||(e.lang=o.getDefaultLocale()),l.defaults=e,l}]}).directive("bsDatepicker",["$window","$parse","$q","$dateFormatter","$dateParser","$datepicker",function(e,t,a,n,i,o){var r=(o.defaults,/(ip(a|o)d|iphone|android)/gi.test(e.navigator.userAgent));return{restrict:"EAC",require:"ngModel",link:function(e,t,a,d){function s(e){return e&&e.length?e:null}function l(e){if(angular.isDate(e)){var t=isNaN(g.$options.minDate)||e.getTime()>=g.$options.minDate,a=isNaN(g.$options.maxDate)||e.getTime()<=g.$options.maxDate,n=t&&a;d.$setValidity("date",n),d.$setValidity("min",t),d.$setValidity("max",a),n&&(d.$dateValue=e)}}function u(){return!d.$dateValue||isNaN(d.$dateValue.getTime())?"":m(d.$dateValue,c.dateFormat)}var c={scope:e,controller:d};angular.forEach(["placement","container","delay","trigger","keyboard","html","animation","template","autoclose","dateType","dateFormat","modelDateFormat","dayFormat","strictFormat","startWeek","startDate","useNative","lang","startView","minView","iconLeft","iconRight","daysOfWeekDisabled","id"],function(e){angular.isDefined(a[e])&&(c[e]=a[e])}),a.bsShow&&e.$watch(a.bsShow,function(e){g&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(datepicker),?/i)),e===!0?g.show():g.hide())});var g=o(t,d,c);c=g.$options,r&&c.useNative&&(c.dateFormat="yyyy-MM-dd");var $=c.lang,m=function(e,t){return n.formatDate(e,t,$)},f=i({format:c.dateFormat,lang:$,strict:c.strictFormat});angular.forEach(["minDate","maxDate"],function(e){angular.isDefined(a[e])&&a.$observe(e,function(t){g.$options[e]=f.getDateForAttribute(e,t),!isNaN(g.$options[e])&&g.$build(!1),l(d.$dateValue)})}),e.$watch(a.ngModel,function(){g.update(d.$dateValue)},!0),angular.isDefined(a.disabledDates)&&e.$watch(a.disabledDates,function(e,t){e=s(e),t=s(t),e&&g.updateDisabledDates(e)}),d.$parsers.unshift(function(e){if(!e)return d.$setValidity("date",!0),null;var t=f.parse(e,d.$dateValue);return!t||isNaN(t.getTime())?void d.$setValidity("date",!1):(l(t),"string"===c.dateType?m(t,c.modelDateFormat||c.dateFormat):"number"===c.dateType?d.$dateValue.getTime():"unix"===c.dateType?d.$dateValue.getTime()/1e3:"iso"===c.dateType?d.$dateValue.toISOString():new Date(d.$dateValue))}),d.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:"string"===c.dateType?f.parse(e,null,c.modelDateFormat):new Date("unix"===c.dateType?1e3*e:e),d.$dateValue=t,u()}),d.$render=function(){t.val(u())},e.$on("$destroy",function(){g&&g.destroy(),c=null,g=null})}}}]).provider("datepickerViews",function(){function e(e,t){for(var a=[];e.length>0;)a.push(e.splice(0,t));return a}function t(e,t){return(e%t+t)%t}this.defaults={dayFormat:"dd",daySplit:7};this.$get=["$dateFormatter","$dateParser","$sce",function(a,n,i){return function(o){var r=o.$scope,d=o.$options,s=d.lang,l=function(e,t){return a.formatDate(e,t,s)},u=n({format:d.dateFormat,lang:s,strict:d.strictFormat}),c=a.weekdaysShort(s),g=c.slice(d.startWeek).concat(c.slice(0,d.startWeek)),$=i.trustAsHtml(''+g.join('')+""),m=o.$date||(d.startDate?u.getDateForAttribute("startDate",d.startDate):new Date),f={year:m.getFullYear(),month:m.getMonth(),date:m.getDate()},h=(6e4*m.getTimezoneOffset(),[{format:d.dayFormat,split:7,steps:{month:1},update:function(e,t){!this.built||t||e.getFullYear()!==f.year||e.getMonth()!==f.month?(angular.extend(f,{year:o.$date.getFullYear(),month:o.$date.getMonth(),date:o.$date.getDate()}),o.$build()):e.getDate()!==f.date&&(f.date=o.$date.getDate(),o.$updateSelected())},build:function(){var a=new Date(f.year,f.month,1),n=a.getTimezoneOffset(),i=new Date(+a-864e5*t(a.getDay()-d.startWeek,7)),s=i.getTimezoneOffset(),c=(new Date).toDateString();s!==n&&(i=new Date(+i+6e4*(s-n)));for(var g,m=[],h=0;42>h;h++)g=u.daylightSavingAdjust(new Date(i.getFullYear(),i.getMonth(),i.getDate()+h)),m.push({date:g,isToday:g.toDateString()===c,label:l(g,this.format),selected:o.$date&&this.isSelected(g),muted:g.getMonth()!==f.month,disabled:this.isDisabled(g)});r.title=l(a,d.monthTitleFormat),r.showLabels=!0,r.labels=$,r.rows=e(m,this.split),this.built=!0},isSelected:function(e){return o.$date&&e.getFullYear()===o.$date.getFullYear()&&e.getMonth()===o.$date.getMonth()&&e.getDate()===o.$date.getDate()},isDisabled:function(e){var t=e.getTime();if(td.maxDate)return!0;if(-1!==d.daysOfWeekDisabled.indexOf(e.getDay()))return!0;if(d.disabledDateRanges)for(var a=0;a=d.disabledDateRanges[a].start&&t<=d.disabledDateRanges[a].end)return!0;return!1},onKeyDown:function(e){if(o.$date){var t,a=o.$date.getTime();37===e.keyCode?t=new Date(a-864e5):38===e.keyCode?t=new Date(a-6048e5):39===e.keyCode?t=new Date(a+864e5):40===e.keyCode&&(t=new Date(a+6048e5)),this.isDisabled(t)||o.select(t,!0)}}},{name:"month",format:d.monthFormat,split:4,steps:{year:1},update:function(e){this.built&&e.getFullYear()===f.year?e.getMonth()!==f.month&&(angular.extend(f,{month:o.$date.getMonth(),date:o.$date.getDate()}),o.$updateSelected()):(angular.extend(f,{year:o.$date.getFullYear(),month:o.$date.getMonth(),date:o.$date.getDate()}),o.$build())},build:function(){for(var t,a=(new Date(f.year,0,1),[]),n=0;12>n;n++)t=new Date(f.year,n,1),a.push({date:t,label:l(t,this.format),selected:o.$isSelected(t),disabled:this.isDisabled(t)});r.title=l(t,d.yearTitleFormat),r.showLabels=!1,r.rows=e(a,this.split),this.built=!0},isSelected:function(e){return o.$date&&e.getFullYear()===o.$date.getFullYear()&&e.getMonth()===o.$date.getMonth()},isDisabled:function(e){var t=+new Date(e.getFullYear(),e.getMonth()+1,0);return td.maxDate},onKeyDown:function(e){if(o.$date){var t=o.$date.getMonth(),a=new Date(o.$date);37===e.keyCode?a.setMonth(t-1):38===e.keyCode?a.setMonth(t-4):39===e.keyCode?a.setMonth(t+1):40===e.keyCode&&a.setMonth(t+4),this.isDisabled(a)||o.select(a,!0)}}},{name:"year",format:d.yearFormat,split:4,steps:{year:12},update:function(e,t){!this.built||t||parseInt(e.getFullYear()/20,10)!==parseInt(f.year/20,10)?(angular.extend(f,{year:o.$date.getFullYear(),month:o.$date.getMonth(),date:o.$date.getDate()}),o.$build()):e.getFullYear()!==f.year&&(angular.extend(f,{year:o.$date.getFullYear(),month:o.$date.getMonth(),date:o.$date.getDate()}),o.$updateSelected())},build:function(){for(var t,a=f.year-f.year%(3*this.split),n=[],i=0;12>i;i++)t=new Date(a+i,0,1),n.push({date:t,label:l(t,this.format),selected:o.$isSelected(t),disabled:this.isDisabled(t)});r.title=n[0].label+"-"+n[n.length-1].label,r.showLabels=!1,r.rows=e(n,this.split),this.built=!0},isSelected:function(e){return o.$date&&e.getFullYear()===o.$date.getFullYear()},isDisabled:function(e){var t=+new Date(e.getFullYear()+1,0,0);return td.maxDate},onKeyDown:function(e){if(o.$date){var t=o.$date.getFullYear(),a=new Date(o.$date);37===e.keyCode?a.setYear(t-1):38===e.keyCode?a.setYear(t-4):39===e.keyCode?a.setYear(t+1):40===e.keyCode&&a.setYear(t+4),this.isDisabled(a)||o.select(a,!0)}}}]);return{views:d.minView?Array.prototype.slice.call(h,d.minView):h,viewDate:f}}}]}); //# sourceMappingURL=datepicker.min.js.map \ No newline at end of file diff --git a/dist/modules/datepicker.min.js.map b/dist/modules/datepicker.min.js.map index 138500e0f..729a60e86 100644 --- a/dist/modules/datepicker.min.js.map +++ b/dist/modules/datepicker.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["datepicker/datepicker.js"],"names":[],"mappings":"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","file":"datepicker.min.js","sourcesContent":["'use strict';\n\nangular.module('mgcrea.ngStrap.datepicker', [\n 'mgcrea.ngStrap.helpers.dateParser',\n 'mgcrea.ngStrap.helpers.dateFormatter',\n 'mgcrea.ngStrap.tooltip'])\n\n .provider('$datepicker', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'datepicker',\n placement: 'bottom-left',\n template: '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 modelDateFormat: null,\n dayFormat: 'dd',\n monthFormat: 'MMM',\n yearFormat: 'yyyy',\n monthTitleFormat: 'MMMM yyyy',\n yearTitleFormat: 'yyyy',\n strictFormat: false,\n autoclose: false,\n minDate: -Infinity,\n maxDate: +Infinity,\n startView: 0,\n minView: 0,\n startWeek: 0,\n daysOfWeekDisabled: '',\n iconLeft: 'glyphicon glyphicon-chevron-left',\n iconRight: 'glyphicon glyphicon-chevron-right'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, datepickerViews, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\n\n function DatepickerFactory(element, controller, config) {\n\n var $datepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $datepicker.$options;\n var scope = $datepicker.$scope;\n if(options.startView) options.startView -= options.minView;\n\n // View vars\n\n var pickerViews = datepickerViews($datepicker);\n $datepicker.$views = pickerViews.views;\n var viewDate = pickerViews.viewDate;\n scope.$mode = options.startView;\n scope.$iconLeft = options.iconLeft;\n scope.$iconRight = options.iconRight;\n var $picker = $datepicker.$views[scope.$mode];\n\n // Scope methods\n\n scope.$select = function(date) {\n $datepicker.select(date);\n };\n scope.$selectPane = function(value) {\n $datepicker.$selectPane(value);\n };\n scope.$toggleMode = function() {\n $datepicker.setMode((scope.$mode + 1) % $datepicker.$views.length);\n };\n\n // Public methods\n\n $datepicker.update = function(date) {\n // console.warn('$datepicker.update() newValue=%o', date);\n if(angular.isDate(date) && !isNaN(date.getTime())) {\n $datepicker.$date = date;\n $picker.update.call($picker, date);\n }\n // Build only if pristine\n $datepicker.$build(true);\n };\n\n $datepicker.updateDisabledDates = function(dateRanges) {\n options.disabledDateRanges = dateRanges;\n for(var i = 0, l = scope.rows.length; i < l; i++) {\n angular.forEach(scope.rows[i], $datepicker.$setDisabledEl);\n }\n };\n\n $datepicker.select = function(date, keep) {\n // console.warn('$datepicker.select', date, scope.$mode);\n if(!angular.isDate(controller.$dateValue)) controller.$dateValue = new Date(date);\n if(!scope.$mode || keep) {\n controller.$setViewValue(angular.copy(date));\n controller.$render();\n if(options.autoclose && !keep) {\n $timeout(function() { $datepicker.hide(true); });\n }\n } else {\n angular.extend(viewDate, {year: date.getFullYear(), month: date.getMonth(), date: date.getDate()});\n $datepicker.setMode(scope.$mode - 1);\n $datepicker.$build();\n }\n };\n\n $datepicker.setMode = function(mode) {\n // console.warn('$datepicker.setMode', mode);\n scope.$mode = mode;\n $picker = $datepicker.$views[scope.$mode];\n $datepicker.$build();\n };\n\n // Protected methods\n\n $datepicker.$build = function(pristine) {\n // console.warn('$datepicker.$build() viewDate=%o', viewDate);\n if(pristine === true && $picker.built) return;\n if(pristine === false && !$picker.built) return;\n $picker.build.call($picker);\n };\n\n $datepicker.$updateSelected = function() {\n for(var i = 0, l = scope.rows.length; i < l; i++) {\n angular.forEach(scope.rows[i], updateSelected);\n }\n };\n\n $datepicker.$isSelected = function(date) {\n return $picker.isSelected(date);\n };\n\n $datepicker.$setDisabledEl = function(el) {\n el.disabled = $picker.isDisabled(el.date);\n };\n\n $datepicker.$selectPane = function(value) {\n var steps = $picker.steps;\n // set targetDate to first day of month to avoid problems with\n // date values rollover. This assumes the viewDate does not\n // depend on the day of the month \n var targetDate = new Date(Date.UTC(viewDate.year + ((steps.year || 0) * value), viewDate.month + ((steps.month || 0) * value), 1));\n angular.extend(viewDate, {year: targetDate.getUTCFullYear(), month: targetDate.getUTCMonth(), date: targetDate.getUTCDate()});\n $datepicker.$build();\n };\n\n $datepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $datepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n if(evt.keyCode === 13) {\n if(!scope.$mode) {\n return $datepicker.hide(true);\n } else {\n return scope.$apply(function() { $datepicker.setMode(scope.$mode - 1); });\n }\n }\n\n // Navigate with keyboard\n $picker.onKeyDown(evt);\n parentScope.$digest();\n };\n\n // Private\n\n function updateSelected(el) {\n el.selected = $datepicker.$isSelected(el.date);\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $datepicker.init;\n $datepicker.init = function() {\n if(isNative && options.useNative) {\n element.prop('type', 'date');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if(isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $datepicker.destroy;\n $datepicker.destroy = function() {\n if(isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $datepicker.show;\n $datepicker.show = function() {\n _show();\n // use timeout to hookup the events to prevent \n // event bubbling from being processed imediately. \n $timeout(function() {\n $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, controller: controller};\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'dateType', 'dateFormat', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 // 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 if(options.dateType === 'string') {\n return formatDate(parsedDate, options.modelDateFormat || options.dateFormat);\n } else if(options.dateType === 'number') {\n return controller.$dateValue.getTime();\n } else if(options.dateType === 'unix') {\n return controller.$dateValue.getTime() / 1000;\n } else if(options.dateType === 'iso') {\n return controller.$dateValue.toISOString();\n } else {\n return new Date(controller.$dateValue);\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 = date;\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 var timezoneOffset = startDate.getTimezoneOffset() * 6e4;\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) {\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 = new Date().toDateString();\n // Handle daylight time switch\n if(firstDateOffset !== firstDayOfMonthOffset) firstDate = new Date(+firstDate + (firstDateOffset - firstDayOfMonthOffset) * 60e3);\n var days = [], day;\n for(var i = 0; i < 42; i++) { // < 7 * 6\n day = dateParser.daylightSavingAdjust(new Date(firstDate.getFullYear(), firstDate.getMonth(), firstDate.getDate() + i));\n days.push({date: day, isToday: day.toDateString() === today, label: formatDate(day, this.format), selected: picker.$date && this.isSelected(day), muted: day.getMonth() !== viewDate.month, disabled: this.isDisabled(day)});\n }\n scope.title = formatDate(firstDayOfMonth, options.monthTitleFormat);\n scope.showLabels = true;\n scope.labels = weekDaysLabelsHtml;\n scope.rows = split(days, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth() && date.getDate() === picker.$date.getDate();\n },\n isDisabled: function(date) {\n var time = date.getTime();\n\n // Disabled because of min/max date.\n if (time < options.minDate || time > options.maxDate) return true;\n\n // Disabled due to being a disabled day of the week\n if (options.daysOfWeekDisabled.indexOf(date.getDay()) !== -1) return true;\n\n // Disabled because of disabled date range.\n if (options.disabledDateRanges) {\n for (var i = 0; i < options.disabledDateRanges.length; i++) {\n if (time >= options.disabledDateRanges[i].start && time <= options.disabledDateRanges[i].end) {\n return true;\n }\n }\n }\n\n return false;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualTime = picker.$date.getTime();\n var newDate;\n\n if(evt.keyCode === 37) newDate = new Date(actualTime - 1 * 864e5);\n else if(evt.keyCode === 38) newDate = new Date(actualTime - 7 * 864e5);\n else if(evt.keyCode === 39) newDate = new Date(actualTime + 1 * 864e5);\n else if(evt.keyCode === 40) newDate = new Date(actualTime + 7 * 864e5);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }, {\n name: 'month',\n format: options.monthFormat,\n split: 4,\n steps: { year: 1 },\n update: function(date, force) {\n if(!this.built || date.getFullYear() !== viewDate.year) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getMonth() !== viewDate.month) {\n angular.extend(viewDate, {month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstMonth = new Date(viewDate.year, 0, 1);\n var months = [], month;\n for (var i = 0; i < 12; i++) {\n month = new Date(viewDate.year, i, 1);\n months.push({date: month, label: formatDate(month, this.format), selected: picker.$isSelected(month), disabled: this.isDisabled(month)});\n }\n scope.title = formatDate(month, options.yearTitleFormat);\n scope.showLabels = false;\n scope.rows = split(months, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth();\n },\n isDisabled: function(date) {\n var lastDate = +new Date(date.getFullYear(), date.getMonth() + 1, 0);\n return lastDate < options.minDate || date.getTime() > options.maxDate;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualMonth = picker.$date.getMonth();\n var newDate = new Date(picker.$date);\n\n if(evt.keyCode === 37) newDate.setMonth(actualMonth - 1);\n else if(evt.keyCode === 38) newDate.setMonth(actualMonth - 4);\n else if(evt.keyCode === 39) newDate.setMonth(actualMonth + 1);\n else if(evt.keyCode === 40) newDate.setMonth(actualMonth + 4);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }, {\n name: 'year',\n format: options.yearFormat,\n split: 4,\n steps: { year: 12 },\n update: function(date, force) {\n if(!this.built || force || parseInt(date.getFullYear()/20, 10) !== parseInt(viewDate.year/20, 10)) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getFullYear() !== viewDate.year) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstYear = viewDate.year - viewDate.year % (this.split * 3);\n var years = [], year;\n for (var i = 0; i < 12; i++) {\n year = new Date(firstYear + i, 0, 1);\n years.push({date: year, label: formatDate(year, this.format), selected: picker.$isSelected(year), disabled: this.isDisabled(year)});\n }\n scope.title = years[0].label + '-' + years[years.length - 1].label;\n scope.showLabels = false;\n scope.rows = split(years, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear();\n },\n isDisabled: function(date) {\n var lastDate = +new Date(date.getFullYear() + 1, 0, 0);\n return lastDate < options.minDate || date.getTime() > options.maxDate;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualYear = picker.$date.getFullYear(),\n newDate = new Date(picker.$date);\n\n if(evt.keyCode === 37) newDate.setYear(actualYear - 1);\n else if(evt.keyCode === 38) newDate.setYear(actualYear - 4);\n else if(evt.keyCode === 39) newDate.setYear(actualYear + 1);\n else if(evt.keyCode === 40) newDate.setYear(actualYear + 4);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }];\n\n return {\n views: options.minView ? Array.prototype.slice.call(views, options.minView) : views,\n viewDate: viewDate\n };\n\n };\n\n };\n\n });\n"],"sourceRoot":"/source/"} \ No newline at end of file +{"version":3,"sources":["datepicker/datepicker.js"],"names":[],"mappings":"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","file":"datepicker.min.js","sourcesContent":["'use strict';\n\nangular.module('mgcrea.ngStrap.datepicker', [\n 'mgcrea.ngStrap.helpers.dateParser',\n 'mgcrea.ngStrap.helpers.dateFormatter',\n 'mgcrea.ngStrap.tooltip'])\n\n .provider('$datepicker', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'datepicker',\n placement: 'bottom-left',\n template: '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 modelDateFormat: null,\n dayFormat: 'dd',\n monthFormat: 'MMM',\n yearFormat: 'yyyy',\n monthTitleFormat: 'MMMM yyyy',\n yearTitleFormat: 'yyyy',\n strictFormat: false,\n autoclose: false,\n minDate: -Infinity,\n maxDate: +Infinity,\n startView: 0,\n minView: 0,\n startWeek: 0,\n daysOfWeekDisabled: '',\n iconLeft: 'glyphicon glyphicon-chevron-left',\n iconRight: 'glyphicon glyphicon-chevron-right'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, datepickerViews, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\n\n function DatepickerFactory(element, controller, config) {\n\n var $datepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $datepicker.$options;\n var scope = $datepicker.$scope;\n if(options.startView) options.startView -= options.minView;\n\n // View vars\n\n var pickerViews = datepickerViews($datepicker);\n $datepicker.$views = pickerViews.views;\n var viewDate = pickerViews.viewDate;\n scope.$mode = options.startView;\n scope.$iconLeft = options.iconLeft;\n scope.$iconRight = options.iconRight;\n var $picker = $datepicker.$views[scope.$mode];\n\n // Scope methods\n\n scope.$select = function(date) {\n $datepicker.select(date);\n };\n scope.$selectPane = function(value) {\n $datepicker.$selectPane(value);\n };\n scope.$toggleMode = function() {\n $datepicker.setMode((scope.$mode + 1) % $datepicker.$views.length);\n };\n\n // Public methods\n\n $datepicker.update = function(date) {\n // console.warn('$datepicker.update() newValue=%o', date);\n if(angular.isDate(date) && !isNaN(date.getTime())) {\n $datepicker.$date = date;\n $picker.update.call($picker, date);\n }\n // Build only if pristine\n $datepicker.$build(true);\n };\n\n $datepicker.updateDisabledDates = function(dateRanges) {\n options.disabledDateRanges = dateRanges;\n for(var i = 0, l = scope.rows.length; i < l; i++) {\n angular.forEach(scope.rows[i], $datepicker.$setDisabledEl);\n }\n };\n\n $datepicker.select = function(date, keep) {\n // console.warn('$datepicker.select', date, scope.$mode);\n if(!angular.isDate(controller.$dateValue)) controller.$dateValue = new Date(date);\n if(!scope.$mode || keep) {\n controller.$setViewValue(angular.copy(date));\n controller.$render();\n if(options.autoclose && !keep) {\n $timeout(function() { $datepicker.hide(true); });\n }\n } else {\n angular.extend(viewDate, {year: date.getFullYear(), month: date.getMonth(), date: date.getDate()});\n $datepicker.setMode(scope.$mode - 1);\n $datepicker.$build();\n }\n };\n\n $datepicker.setMode = function(mode) {\n // console.warn('$datepicker.setMode', mode);\n scope.$mode = mode;\n $picker = $datepicker.$views[scope.$mode];\n $datepicker.$build();\n };\n\n // Protected methods\n\n $datepicker.$build = function(pristine) {\n // console.warn('$datepicker.$build() viewDate=%o', viewDate);\n if(pristine === true && $picker.built) return;\n if(pristine === false && !$picker.built) return;\n $picker.build.call($picker);\n };\n\n $datepicker.$updateSelected = function() {\n for(var i = 0, l = scope.rows.length; i < l; i++) {\n angular.forEach(scope.rows[i], updateSelected);\n }\n };\n\n $datepicker.$isSelected = function(date) {\n return $picker.isSelected(date);\n };\n\n $datepicker.$setDisabledEl = function(el) {\n el.disabled = $picker.isDisabled(el.date);\n };\n\n $datepicker.$selectPane = function(value) {\n var steps = $picker.steps;\n // set targetDate to first day of month to avoid problems with\n // date values rollover. This assumes the viewDate does not\n // depend on the day of the month\n var targetDate = new Date(Date.UTC(viewDate.year + ((steps.year || 0) * value), viewDate.month + ((steps.month || 0) * value), 1));\n angular.extend(viewDate, {year: targetDate.getUTCFullYear(), month: targetDate.getUTCMonth(), date: targetDate.getUTCDate()});\n $datepicker.$build();\n };\n\n $datepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $datepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n if(evt.keyCode === 13) {\n if(!scope.$mode) {\n return $datepicker.hide(true);\n } else {\n return scope.$apply(function() { $datepicker.setMode(scope.$mode - 1); });\n }\n }\n\n // Navigate with keyboard\n $picker.onKeyDown(evt);\n parentScope.$digest();\n };\n\n // Private\n\n function updateSelected(el) {\n el.selected = $datepicker.$isSelected(el.date);\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $datepicker.init;\n $datepicker.init = function() {\n if(isNative && options.useNative) {\n element.prop('type', 'date');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if(isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $datepicker.destroy;\n $datepicker.destroy = function() {\n if(isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $datepicker.show;\n $datepicker.show = function() {\n _show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n // if $datepicker is no longer showing, don't setup events\n if(!$datepicker.$isShown) return;\n $datepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $datepicker.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $datepicker.hide;\n $datepicker.hide = function(blur) {\n if(!$datepicker.$isShown) return;\n $datepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $datepicker.$onKeyDown);\n }\n _hide(blur);\n };\n\n return $datepicker;\n\n }\n\n DatepickerFactory.defaults = defaults;\n return DatepickerFactory;\n\n };\n\n })\n\n .directive('bsDatepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $datepicker) {\n\n var defaults = $datepicker.defaults;\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope, controller: controller};\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'dateType', 'dateFormat', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 // 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 if(options.dateType === 'string') {\n return formatDate(parsedDate, options.modelDateFormat || options.dateFormat);\n } else if(options.dateType === 'number') {\n return controller.$dateValue.getTime();\n } else if(options.dateType === 'unix') {\n return controller.$dateValue.getTime() / 1000;\n } else if(options.dateType === 'iso') {\n return controller.$dateValue.toISOString();\n } else {\n return new Date(controller.$dateValue);\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 = date;\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 var timezoneOffset = startDate.getTimezoneOffset() * 6e4;\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) {\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 = new Date().toDateString();\n // Handle daylight time switch\n if(firstDateOffset !== firstDayOfMonthOffset) firstDate = new Date(+firstDate + (firstDateOffset - firstDayOfMonthOffset) * 60e3);\n var days = [], day;\n for(var i = 0; i < 42; i++) { // < 7 * 6\n day = dateParser.daylightSavingAdjust(new Date(firstDate.getFullYear(), firstDate.getMonth(), firstDate.getDate() + i));\n days.push({date: day, isToday: day.toDateString() === today, label: formatDate(day, this.format), selected: picker.$date && this.isSelected(day), muted: day.getMonth() !== viewDate.month, disabled: this.isDisabled(day)});\n }\n scope.title = formatDate(firstDayOfMonth, options.monthTitleFormat);\n scope.showLabels = true;\n scope.labels = weekDaysLabelsHtml;\n scope.rows = split(days, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth() && date.getDate() === picker.$date.getDate();\n },\n isDisabled: function(date) {\n var time = date.getTime();\n\n // Disabled because of min/max date.\n if (time < options.minDate || time > options.maxDate) return true;\n\n // Disabled due to being a disabled day of the week\n if (options.daysOfWeekDisabled.indexOf(date.getDay()) !== -1) return true;\n\n // Disabled because of disabled date range.\n if (options.disabledDateRanges) {\n for (var i = 0; i < options.disabledDateRanges.length; i++) {\n if (time >= options.disabledDateRanges[i].start && time <= options.disabledDateRanges[i].end) {\n return true;\n }\n }\n }\n\n return false;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualTime = picker.$date.getTime();\n var newDate;\n\n if(evt.keyCode === 37) newDate = new Date(actualTime - 1 * 864e5);\n else if(evt.keyCode === 38) newDate = new Date(actualTime - 7 * 864e5);\n else if(evt.keyCode === 39) newDate = new Date(actualTime + 1 * 864e5);\n else if(evt.keyCode === 40) newDate = new Date(actualTime + 7 * 864e5);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }, {\n name: 'month',\n format: options.monthFormat,\n split: 4,\n steps: { year: 1 },\n update: function(date, force) {\n if(!this.built || date.getFullYear() !== viewDate.year) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getMonth() !== viewDate.month) {\n angular.extend(viewDate, {month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstMonth = new Date(viewDate.year, 0, 1);\n var months = [], month;\n for (var i = 0; i < 12; i++) {\n month = new Date(viewDate.year, i, 1);\n months.push({date: month, label: formatDate(month, this.format), selected: picker.$isSelected(month), disabled: this.isDisabled(month)});\n }\n scope.title = formatDate(month, options.yearTitleFormat);\n scope.showLabels = false;\n scope.rows = split(months, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth();\n },\n isDisabled: function(date) {\n var lastDate = +new Date(date.getFullYear(), date.getMonth() + 1, 0);\n return lastDate < options.minDate || date.getTime() > options.maxDate;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualMonth = picker.$date.getMonth();\n var newDate = new Date(picker.$date);\n\n if(evt.keyCode === 37) newDate.setMonth(actualMonth - 1);\n else if(evt.keyCode === 38) newDate.setMonth(actualMonth - 4);\n else if(evt.keyCode === 39) newDate.setMonth(actualMonth + 1);\n else if(evt.keyCode === 40) newDate.setMonth(actualMonth + 4);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }, {\n name: 'year',\n format: options.yearFormat,\n split: 4,\n steps: { year: 12 },\n update: function(date, force) {\n if(!this.built || force || parseInt(date.getFullYear()/20, 10) !== parseInt(viewDate.year/20, 10)) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getFullYear() !== viewDate.year) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstYear = viewDate.year - viewDate.year % (this.split * 3);\n var years = [], year;\n for (var i = 0; i < 12; i++) {\n year = new Date(firstYear + i, 0, 1);\n years.push({date: year, label: formatDate(year, this.format), selected: picker.$isSelected(year), disabled: this.isDisabled(year)});\n }\n scope.title = years[0].label + '-' + years[years.length - 1].label;\n scope.showLabels = false;\n scope.rows = split(years, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear();\n },\n isDisabled: function(date) {\n var lastDate = +new Date(date.getFullYear() + 1, 0, 0);\n return lastDate < options.minDate || date.getTime() > options.maxDate;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualYear = picker.$date.getFullYear(),\n newDate = new Date(picker.$date);\n\n if(evt.keyCode === 37) newDate.setYear(actualYear - 1);\n else if(evt.keyCode === 38) newDate.setYear(actualYear - 4);\n else if(evt.keyCode === 39) newDate.setYear(actualYear + 1);\n else if(evt.keyCode === 40) newDate.setYear(actualYear + 4);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }];\n\n return {\n views: options.minView ? Array.prototype.slice.call(views, options.minView) : views,\n viewDate: viewDate\n };\n\n };\n\n };\n\n });\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/dist/modules/datepicker.tpl.js b/dist/modules/datepicker.tpl.js index 31a79962c..0f562f721 100644 --- a/dist/modules/datepicker.tpl.js +++ b/dist/modules/datepicker.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/datepicker.tpl.min.js b/dist/modules/datepicker.tpl.min.js index 30f05058f..2813d33ff 100644 --- a/dist/modules/datepicker.tpl.min.js +++ b/dist/modules/datepicker.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/debounce.js b/dist/modules/debounce.js index 9eabead3c..0f08b87cd 100644 --- a/dist/modules/debounce.js +++ b/dist/modules/debounce.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/debounce.min.js b/dist/modules/debounce.min.js index 956ecf8ae..ae394fe64 100644 --- a/dist/modules/debounce.min.js +++ b/dist/modules/debounce.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/dimensions.js b/dist/modules/dimensions.js index d07bdc140..eaa2b7e7a 100644 --- a/dist/modules/dimensions.js +++ b/dist/modules/dimensions.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/dimensions.min.js b/dist/modules/dimensions.min.js index d9a630c17..8bb8647f4 100644 --- a/dist/modules/dimensions.min.js +++ b/dist/modules/dimensions.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/dropdown.js b/dist/modules/dropdown.js index 8b9bd8736..ac02cf8cb 100644 --- a/dist/modules/dropdown.js +++ b/dist/modules/dropdown.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -67,8 +67,8 @@ angular.module('mgcrea.ngStrap.dropdown', ['mgcrea.ngStrap.tooltip']) var show = $dropdown.show; $dropdown.show = function() { show(); - // use timeout to hookup the events to prevent - // event bubbling from being processed imediately. + // use timeout to hookup the events to prevent + // event bubbling from being processed imediately. $timeout(function() { options.keyboard && $dropdown.$element.on('keydown', $dropdown.$onKeyDown); bodyEl.on('click', onBodyClick); @@ -117,7 +117,7 @@ angular.module('mgcrea.ngStrap.dropdown', ['mgcrea.ngStrap.tooltip']) // Directive options var options = {scope: scope}; - angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template'], function(key) { + angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'id'], function(key) { if(angular.isDefined(attr[key])) options[key] = attr[key]; }); diff --git a/dist/modules/dropdown.min.js b/dist/modules/dropdown.min.js index 43c9d043d..85436af4a 100644 --- a/dist/modules/dropdown.min.js +++ b/dist/modules/dropdown.min.js @@ -1,9 +1,9 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT */ -"use strict";angular.module("mgcrea.ngStrap.dropdown",["mgcrea.ngStrap.tooltip"]).provider("$dropdown",function(){var e=this.defaults={animation:"am-fade",prefixClass:"dropdown",placement:"bottom-left",template:"dropdown/dropdown.tpl.html",trigger:"click",container:!1,keyboard:!0,html:!1,delay:0};this.$get=["$window","$rootScope","$tooltip","$timeout",function(o,n,t,r){function a(o,a){function c(e){return e.target!==o[0]?e.target!==o[0]&&d.hide():void 0}{var d={},s=angular.extend({},e,a);d.$scope=s.scope&&s.scope.$new()||n.$new()}d=t(o,s);var p=o.parent();d.$onKeyDown=function(e){if(/(38|40)/.test(e.keyCode)){e.preventDefault(),e.stopPropagation();var o=angular.element(d.$element[0].querySelectorAll("li:not(.divider) a"));if(o.length){var n;angular.forEach(o,function(e,o){l&&l.call(e,":focus")&&(n=o)}),38===e.keyCode&&n>0?n--:40===e.keyCode&&n0?n--:40===e.keyCode&&n 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.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.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(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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"],"sourceRoot":"/source/"} \ No newline at end of file +{"version":3,"sources":["dropdown/dropdown.js"],"names":[],"mappings":"qBASM,OAAA,2BAAW,oCAEX,YAAS,cAET,GAAU,KAAA,UACV,UAAM,UACN,YAAO,yEAGT,QAAK,qBAEH,UAAI,EACJ,MAAI,gBAIF,MAAI,UAAY,aAAA,WAAA,WAAA,SAAA,EAAA,EAAA,EAAA,wDAwEX,EAAA,SAAA,EAAA,IAAA,EAAA,cAjEL,CAAA,GAAI,8BAIM,GAAA,OAAa,EAAc,OAAA,EAAA,MAAA,QAAA,EAAA,SAE/B,EAAA,EAAA,MACJ,GAAI,EAAA,WAIA,WAAc,SAAA,GAClB,GAAI,UAAA,KAAA,EAAA,SAAJ,CACA,EAAA,mBACE,6FAIF,IAAG,EAAI,OAAP,eAEQ,QAAQ,EAAA,SAAY,EAAQ,GACpC,GAAmB,EAAA,KAAA,EAAA,YAAA,EAAA,8DAMjB,QAAO,YAAU,KAAA,EAAA,GACrB,EAAA,GAAU,GAAO,GAAA,cAMb,GAAO,EAAG,OACN,KAAA,WACN,IAGF,EAAW,WACX,EAAU,UAAO,EAAW,SAAA,GAAA,UAAA,EAAA,YAC1B,EAAI,GAAA,QAAU,IACd,GAAA,GACA,EAAO,SAAI,aAAS,EAAA,SAAA,wCAKlB,EAAU,WACd,EAAU,UAAU,EAAW,SAAA,IAAA,UAAA,EAAA,YAC7B,EAAO,IAAI,QAAS,GACpB,EAAA,SAAA,aAAA,EAAA,YAAA,oCAKF,GAAS,QAAA,WACP,EAAO,IAAA,QAAW,GAClB,8CA9DF,EAAc,QAAQ,UAAW,iBAAU,QAAA,UAAA,uBAAA,QAAA,UAAA,oBAAA,QAAA,UAAA,mBAAA,QAAA,UAAA,mHAqFtC,uCAKH,IAAM,MAAU,WACf,SAAA,YAAA,YAAA,QAAA,UAAA,WAAA,OAAA,YAAA,WAAA,MAAA,SAAA,4CAKE,YAAQ,EAAS,OAAA,EAAW,WAAa,SAAS,GACrD,EAAA,QAAa,OAIf,EAAI,QAAW,EAAA,OAAU,EAAA,OAAS,SAAA,wFAGlC,KAAU,EAAY,EAAA,OAAW,EAAA,kEASpC,EAAA","file":"dropdown.min.js","sourcesContent":["'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 placement: 'bottom-left',\n template: '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.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.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(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/dist/modules/dropdown.tpl.js b/dist/modules/dropdown.tpl.js index ac9385a6e..ba922be0f 100644 --- a/dist/modules/dropdown.tpl.js +++ b/dist/modules/dropdown.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/dropdown.tpl.min.js b/dist/modules/dropdown.tpl.min.js index 76f037207..a49666dc3 100644 --- a/dist/modules/dropdown.tpl.min.js +++ b/dist/modules/dropdown.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/modal.js b/dist/modules/modal.js index a5187d58b..9c1f36453 100644 --- a/dist/modules/modal.js +++ b/dist/modules/modal.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -47,6 +47,11 @@ angular.module('mgcrea.ngStrap.modal', ['mgcrea.ngStrap.helpers.dimensions']) options.container = 'body'; } + // store $id to identify the triggering element in events + // give priority to options.id, otherwise, try to use + // element id if defined + $modal.$id = options.id || options.element && options.element.attr('id') || ''; + // Support scope as string options forEach(['title', 'content'], function(key) { if(options[key]) scope[key] = $sce.trustAsHtml(options[key]); @@ -305,7 +310,7 @@ angular.module('mgcrea.ngStrap.modal', ['mgcrea.ngStrap.helpers.dimensions']) // Directive options var options = {scope: scope, element: element, show: false}; - angular.forEach(['template', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation'], function(key) { + angular.forEach(['template', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation', 'id'], function(key) { if(angular.isDefined(attr[key])) options[key] = attr[key]; }); diff --git a/dist/modules/modal.min.js b/dist/modules/modal.min.js index 1506c012b..0e186a341 100644 --- a/dist/modules/modal.min.js +++ b/dist/modules/modal.min.js @@ -1,9 +1,9 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT */ -"use strict";angular.module("mgcrea.ngStrap.modal",["mgcrea.ngStrap.helpers.dimensions"]).provider("$modal",function(){var e=this.defaults={animation:"am-fade",backdropAnimation:"am-fade",prefixClass:"modal",prefixEvent:"modal",placement:"top",template:"modal/modal.tpl.html",contentTemplate:!1,container:!1,element:null,backdrop:!0,keyboard:!0,html:!1,show:!0};this.$get=["$window","$rootScope","$compile","$q","$templateCache","$http","$animate","$timeout","$sce","dimensions",function(n,t,o,a,i,r,l,c,s){function u(n){function a(){b.$emit(w.prefixEvent+".show",u)}function i(){b.$emit(w.prefixEvent+".hide",u),g.removeClass(w.prefixClass+"-open"),w.animation&&g.removeClass(w.prefixClass+"-with-"+w.animation)}function r(e){e.target===e.currentTarget&&("static"===w.backdrop?u.focus():u.hide())}function c(e){e.preventDefault()}var u={},w=u.$options=angular.extend({},e,n);u.$promise=p(w.template);var b=u.$scope=w.scope&&w.scope.$new()||t.$new();w.element||w.container||(w.container="body"),f(["title","content"],function(e){w[e]&&(b[e]=s.trustAsHtml(w[e]))}),b.$hide=function(){b.$$postDigest(function(){u.hide()})},b.$show=function(){b.$$postDigest(function(){u.show()})},b.$toggle=function(){b.$$postDigest(function(){u.toggle()})},u.$isShown=b.$isShown=!1,w.contentTemplate&&(u.$promise=u.$promise.then(function(e){var t=angular.element(e);return p(w.contentTemplate).then(function(e){var o=m('[ng-bind="content"]',t[0]).removeAttr("ng-bind").html(e);return n.template||o.next().remove(),t[0].outerHTML})}));var k,y,C=angular.element('
');return u.$promise.then(function(e){angular.isObject(e)&&(e=e.data),w.html&&(e=e.replace(v,'ng-bind-html="')),e=h.apply(e),k=o(e),u.init()}),u.init=function(){w.show&&b.$$postDigest(function(){u.show()})},u.destroy=function(){y&&(y.remove(),y=null),C&&(C.remove(),C=null),b.$destroy()},u.show=function(){if(!u.$isShown&&!b.$emit(w.prefixEvent+".show.before",u).defaultPrevented){var e,n;angular.isElement(w.container)?(e=w.container,n=w.container[0].lastChild?angular.element(w.container[0].lastChild):null):w.container?(e=m(w.container),n=e[0].lastChild?angular.element(e[0].lastChild):null):(e=null,n=w.element),y=u.$element=k(b,function(){}),y.css({display:"block"}).addClass(w.placement),w.animation&&(w.backdrop&&C.addClass(w.backdropAnimation),y.addClass(w.animation)),w.backdrop&&l.enter(C,g,null);var t=l.enter(y,e,n,a);t&&t.then&&t.then(a),u.$isShown=b.$isShown=!0,d(b);var o=y[0];$(function(){o.focus()}),g.addClass(w.prefixClass+"-open"),w.animation&&g.addClass(w.prefixClass+"-with-"+w.animation),w.backdrop&&(y.on("click",r),C.on("click",r),C.on("wheel",c)),w.keyboard&&y.on("keyup",u.$onKeyUp)}},u.hide=function(){if(u.$isShown&&!b.$emit(w.prefixEvent+".hide.before",u).defaultPrevented){var e=l.leave(y,i);e&&e.then&&e.then(i),w.backdrop&&l.leave(C),u.$isShown=b.$isShown=!1,d(b),w.backdrop&&(y.off("click",r),C.off("click",r),C.off("wheel",c)),w.keyboard&&y.off("keyup",u.$onKeyUp)}},u.toggle=function(){u.$isShown?u.hide():u.show()},u.focus=function(){y[0].focus()},u.$onKeyUp=function(e){27===e.which&&u.$isShown&&(u.hide(),e.stopPropagation())},u}function d(e){e.$$phase||e.$root&&e.$root.$$phase||e.$digest()}function m(e,n){return angular.element((n||document).querySelectorAll(e))}function p(e){return w[e]?w[e]:w[e]=a.when(i.get(e)||r.get(e)).then(function(n){return angular.isObject(n)?(i.put(e,n.data),n.data):n})}var f=angular.forEach,h=String.prototype.trim,$=n.requestAnimationFrame||n.setTimeout,g=angular.element(n.document.body),v=/ng-bind="/gi,w={};return u}]}).directive("bsModal",["$window","$sce","$modal",function(e,n,t){return{restrict:"EAC",scope:!0,link:function(e,o,a){var i={scope:e,element:o,show:!1};angular.forEach(["template","contentTemplate","placement","backdrop","keyboard","html","container","animation"],function(e){angular.isDefined(a[e])&&(i[e]=a[e])}),angular.forEach(["title","content"],function(t){a[t]&&a.$observe(t,function(o){e[t]=n.trustAsHtml(o)})}),a.bsModal&&e.$watch(a.bsModal,function(n){angular.isObject(n)?angular.extend(e,n):e.content=n},!0);var r=t(i);o.on(a.trigger||"click",r.toggle),e.$on("$destroy",function(){r&&r.destroy(),i=null,r=null})}}}]); +"use strict";angular.module("mgcrea.ngStrap.modal",["mgcrea.ngStrap.helpers.dimensions"]).provider("$modal",function(){var e=this.defaults={animation:"am-fade",backdropAnimation:"am-fade",prefixClass:"modal",prefixEvent:"modal",placement:"top",template:"modal/modal.tpl.html",contentTemplate:!1,container:!1,element:null,backdrop:!0,keyboard:!0,html:!1,show:!0};this.$get=["$window","$rootScope","$compile","$q","$templateCache","$http","$animate","$timeout","$sce","dimensions",function(n,t,o,a,i,r,l,c,s){function u(n){function a(){b.$emit(w.prefixEvent+".show",u)}function i(){b.$emit(w.prefixEvent+".hide",u),g.removeClass(w.prefixClass+"-open"),w.animation&&g.removeClass(w.prefixClass+"-with-"+w.animation)}function r(e){e.target===e.currentTarget&&("static"===w.backdrop?u.focus():u.hide())}function c(e){e.preventDefault()}var u={},w=u.$options=angular.extend({},e,n);u.$promise=p(w.template);var b=u.$scope=w.scope&&w.scope.$new()||t.$new();w.element||w.container||(w.container="body"),u.$id=w.id||w.element&&w.element.attr("id")||"",f(["title","content"],function(e){w[e]&&(b[e]=s.trustAsHtml(w[e]))}),b.$hide=function(){b.$$postDigest(function(){u.hide()})},b.$show=function(){b.$$postDigest(function(){u.show()})},b.$toggle=function(){b.$$postDigest(function(){u.toggle()})},u.$isShown=b.$isShown=!1,w.contentTemplate&&(u.$promise=u.$promise.then(function(e){var t=angular.element(e);return p(w.contentTemplate).then(function(e){var o=m('[ng-bind="content"]',t[0]).removeAttr("ng-bind").html(e);return n.template||o.next().remove(),t[0].outerHTML})}));var k,y,C=angular.element('
');return u.$promise.then(function(e){angular.isObject(e)&&(e=e.data),w.html&&(e=e.replace(v,'ng-bind-html="')),e=h.apply(e),k=o(e),u.init()}),u.init=function(){w.show&&b.$$postDigest(function(){u.show()})},u.destroy=function(){y&&(y.remove(),y=null),C&&(C.remove(),C=null),b.$destroy()},u.show=function(){if(!u.$isShown&&!b.$emit(w.prefixEvent+".show.before",u).defaultPrevented){var e,n;angular.isElement(w.container)?(e=w.container,n=w.container[0].lastChild?angular.element(w.container[0].lastChild):null):w.container?(e=m(w.container),n=e[0].lastChild?angular.element(e[0].lastChild):null):(e=null,n=w.element),y=u.$element=k(b,function(){}),y.css({display:"block"}).addClass(w.placement),w.animation&&(w.backdrop&&C.addClass(w.backdropAnimation),y.addClass(w.animation)),w.backdrop&&l.enter(C,g,null);var t=l.enter(y,e,n,a);t&&t.then&&t.then(a),u.$isShown=b.$isShown=!0,d(b);var o=y[0];$(function(){o.focus()}),g.addClass(w.prefixClass+"-open"),w.animation&&g.addClass(w.prefixClass+"-with-"+w.animation),w.backdrop&&(y.on("click",r),C.on("click",r),C.on("wheel",c)),w.keyboard&&y.on("keyup",u.$onKeyUp)}},u.hide=function(){if(u.$isShown&&!b.$emit(w.prefixEvent+".hide.before",u).defaultPrevented){var e=l.leave(y,i);e&&e.then&&e.then(i),w.backdrop&&l.leave(C),u.$isShown=b.$isShown=!1,d(b),w.backdrop&&(y.off("click",r),C.off("click",r),C.off("wheel",c)),w.keyboard&&y.off("keyup",u.$onKeyUp)}},u.toggle=function(){u.$isShown?u.hide():u.show()},u.focus=function(){y[0].focus()},u.$onKeyUp=function(e){27===e.which&&u.$isShown&&(u.hide(),e.stopPropagation())},u}function d(e){e.$$phase||e.$root&&e.$root.$$phase||e.$digest()}function m(e,n){return angular.element((n||document).querySelectorAll(e))}function p(e){return w[e]?w[e]:w[e]=a.when(i.get(e)||r.get(e)).then(function(n){return angular.isObject(n)?(i.put(e,n.data),n.data):n})}var f=angular.forEach,h=String.prototype.trim,$=n.requestAnimationFrame||n.setTimeout,g=angular.element(n.document.body),v=/ng-bind="/gi,w={};return u}]}).directive("bsModal",["$window","$sce","$modal",function(e,n,t){return{restrict:"EAC",scope:!0,link:function(e,o,a){var i={scope:e,element:o,show:!1};angular.forEach(["template","contentTemplate","placement","backdrop","keyboard","html","container","animation","id"],function(e){angular.isDefined(a[e])&&(i[e]=a[e])}),angular.forEach(["title","content"],function(t){a[t]&&a.$observe(t,function(o){e[t]=n.trustAsHtml(o)})}),a.bsModal&&e.$watch(a.bsModal,function(n){angular.isObject(n)?angular.extend(e,n):e.content=n},!0);var r=t(i);o.on(a.trigger||"click",r.toggle),e.$on("$destroy",function(){r&&r.destroy(),i=null,r=null})}}}]); //# sourceMappingURL=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 23f5ea7b8..094306fb0 100644 --- a/dist/modules/modal.min.js.map +++ b/dist/modules/modal.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["modal/modal.js"],"names":[],"mappings":"qBASM,OAAA,wBAAa,+CAEb,SAAW,cAEX,GAAA,KAAiB,UACjB,UAAW,UACX,kBAAS,UACT,YAAU,QACV,YAAU,QACV,UAAM,MACN,SAAM,uDAGR,QAAK,iBAEH,UAAI,EACJ,MAAI,EACJ,MAAI,4JAWE,GAAe,WA4Jd,OACD,MAAA,EAAA,YAAA,QAAA,gBAgCJ,EAAO,MAAA,EAAS,YAAW,QAAA,wCAEzB,EAAO,wGA8BF,WAAP,EAAO,SAAA,EAAA,QAAA,EAAA,4CA3NL,yCAIF,GAAA,SAAkB,EAAY,EAAS,aACrC,GAAG,EAAc,OAAM,EAAO,OAAK,EAAY,MAAQ,QAAA,EAAA,uDAMrD,QAAO,WAAA,SAAA,wCAKP,MAAO,mDAKP,MAAO,gGAOR,EAAQ,cAIN,SAAK,EAAS,UAAA,IAGT,oBACJ,SAAO,EAAc,SAAA,KAAA,SAAA,0IAOvB,OADA,GAAa,UAAA,EAAA,OAAA,SACb,EAAkB,GAAA,kBAMpB,GAAO,gEAiLT,oCA9KA,QAAO,SAAO,KAAW,EAAA,EAAA,6DAGvB,EAAW,EAAM,KACf,mCAOJ,EAAO,aAAU,yBAOZ,QAAA,yDAaH,EAAG,cAIA,KAAQ,eACT,EAAA,aAEK,MAAA,EAAA,YAAA,eAAA,GAAA,qBAGH,GAAQ,UACH,UAAA,EAAA,cACL,EAAS,YACT,EAAQ,UAAQ,GAAA,UAAA,QAAA,QAAA,EAAA,UAAA,GAAA,WAAA,kHAYP,EAAA,SAAU,EAAA,EAAA,gBAGrB,KAAa,QAAS,UAAQ,SAAA,EAAA,WAG7B,EAAQ,YACT,EAAS,+EAOX,EAAO,MAAA,EAAiB,EAAW,KAInC,IAAI,GAAK,EAAa,MAAA,EAAA,EAAA,EAAA,EACtB,IAAA,EAAsB,MAAA,EAAW,KAAA,oCAM/B,GAAA,EAAY,8BAKZ,SAAgB,EAAS,YAAA,SACzB,EAAA,WACA,EAAA,SAAmB,EAAS,YAAA,SAAA,EAAA,wDAOhC,EAAS,GAAA,QAAuB,+KAsB3B,EAAQ,UACT,EAAA,MAAa,KAEb,SAAgB,EAAI,UAAS,sDAOjC,EAAS,IAAA,QAAuB,IAE9B,EAAA,UACA,EAAW,IAAA,QAAW,EAAA,cAYtB,OAAa,4DAOb,EAAQ,GAAA,oEASV,EAAA,oBAgBM,gBAOR,EAAI,SAAgB,EAAA,OAAA,EAAA,MAAA,SAAA,EAAA,kBAGlB,GAAQ,EAAc,SAChB,SAAS,SAAK,GAAA,UAAA,iBAAA,wBAKlB,GAAO,GAAA,EAAA,gFAIX,EAAO,IAAA,EAAA,EAAA,wCA7PL,EAAI,OAAS,UAAA,gFAGb,EAAqB,+GA0QhB,uCAKH,IAAa,MAAK,EAAS,QAAK,EAAS,MAAU,WACjD,SAAa,WAAK,kBAAY,YAAA,WAAA,WAAA,OAAA,YAAA,aAAA,SAAA,0CAKlC,QAAK,SAAW,QAAM,WAAY,SAAS,GACzC,EAAG,IAAQ,EAAA,SAAS,EAAW,SAAA,GAC7B,EAAA,GAAQ,EAAO,YAAO,qEAOtB,QAAQ,OAAO,EAAA,uBAOjB,GAAI,EAAa,gFAQtB,EAAA","file":"modal.min.js","sourcesContent":["'use strict';\n\nangular.module('mgcrea.ngStrap.modal', ['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 template: 'modal/modal.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($window, $rootScope, $compile, $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 var htmlReplaceRegExp = /ng-bind=\"/ig;\n\n function ModalFactory(config) {\n\n var $modal = {};\n\n // Common vars\n var options = $modal.$options = angular.extend({}, defaults, config);\n $modal.$promise = fetchTemplate(options.template);\n var scope = $modal.$scope = options.scope && options.scope.$new() || $rootScope.$new();\n if(!options.element && !options.container) {\n options.container = 'body';\n }\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 // Support contentTemplate option\n if(options.contentTemplate) {\n $modal.$promise = $modal.$promise.then(function(template) {\n var templateEl = angular.element(template);\n return fetchTemplate(options.contentTemplate)\n .then(function(contentTemplate) {\n var contentEl = findElement('[ng-bind=\"content\"]', templateEl[0]).removeAttr('ng-bind').html(contentTemplate);\n // Drop the default footer as you probably don't want it if you use a custom contentTemplate\n if(!config.template) contentEl.next().remove();\n return templateEl[0].outerHTML;\n });\n });\n }\n\n // Fetch, compile then initialize modal\n var modalLinker, modalElement;\n var backdropElement = angular.element('
');\n $modal.$promise.then(function(template) {\n if(angular.isObject(template)) template = template.data;\n if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html=\"');\n template = trim.apply(template);\n modalLinker = $compile(template);\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 if(modalElement) {\n modalElement.remove();\n modalElement = null;\n }\n if(backdropElement) {\n backdropElement.remove();\n backdropElement = null;\n }\n\n // Destroy scope\n scope.$destroy();\n\n };\n\n $modal.show = function() {\n if($modal.$isShown) return;\n\n if(scope.$emit(options.prefixEvent + '.show.before', $modal).defaultPrevented) {\n 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].lastChild ? angular.element(parent[0].lastChild) : null;\n } else {\n parent = null;\n after = options.element;\n }\n }\n\n // Fetch a cloned element linked from template\n modalElement = $modal.$element = modalLinker(scope, function(clonedElement, scope) {});\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 // Support v1.3+ $animate\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\n var promise = $animate.enter(modalElement, parent, after, enterAnimateCallback);\n if(promise && promise.then) promise.then(enterAnimateCallback);\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 if(options.backdrop) {\n modalElement.on('click', hideOnBackdropClick);\n backdropElement.on('click', hideOnBackdropClick);\n backdropElement.on('wheel', preventEventDefault);\n }\n if(options.keyboard) {\n modalElement.on('keyup', $modal.$onKeyUp);\n }\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 var promise = $animate.leave(modalElement, leaveAnimateCallback);\n // Support v1.3+ $animate\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\n if(promise && promise.then) promise.then(leaveAnimateCallback);\n\n if(options.backdrop) {\n $animate.leave(backdropElement);\n }\n $modal.$isShown = scope.$isShown = false;\n safeDigest(scope);\n\n // Unbind events\n if(options.backdrop) {\n modalElement.off('click', hideOnBackdropClick);\n backdropElement.off('click', hideOnBackdropClick);\n backdropElement.off('wheel', preventEventDefault);\n }\n if(options.keyboard) {\n modalElement.off('keyup', $modal.$onKeyUp);\n }\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 // 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 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 var fetchPromises = {};\n function fetchTemplate(template) {\n if(fetchPromises[template]) return fetchPromises[template];\n return (fetchPromises[template] = $q.when($templateCache.get(template) || $http.get(template))\n .then(function(res) {\n if(angular.isObject(res)) {\n $templateCache.put(template, res.data);\n return res.data;\n }\n return res;\n }));\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', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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":["modal/modal.js"],"names":[],"mappings":"qBASM,OAAA,wBAAa,+CAEb,SAAW,cAEX,GAAA,KAAiB,UACjB,UAAW,UACX,kBAAS,UACT,YAAU,QACV,YAAU,QACV,UAAM,MACN,SAAM,uDAGR,QAAK,iBAEH,UAAI,EACJ,MAAI,EACJ,MAAI,4JAWE,GAAe,WAiKd,OACD,MAAA,EAAA,YAAA,QAAA,gBAgCJ,EAAO,MAAA,EAAS,YAAW,QAAA,wCAEzB,EAAO,wGA8BF,WAAP,EAAO,SAAA,EAAA,QAAA,EAAA,4CAhOL,mHAMF,GAAO,SAAc,EAAM,mFAUvB,QAAO,WAAA,SAAA,wCAKP,MAAO,mDAKP,MAAO,gGAOR,EAAQ,cAIN,SAAK,EAAS,UAAA,IAGT,oBACJ,SAAO,EAAc,SAAA,KAAA,SAAA,0IAOvB,OADA,GAAa,UAAA,EAAA,OAAA,SACb,EAAkB,GAAA,kBAMpB,GAAO,gEAiLT,oCA9KA,QAAO,SAAO,KAAW,EAAA,EAAA,6DAGvB,EAAW,EAAM,KACf,mCAOJ,EAAO,aAAU,yBAOZ,QAAA,yDAaH,EAAG,cAIA,KAAQ,eACT,EAAA,aAEK,MAAA,EAAA,YAAA,eAAA,GAAA,qBAGH,GAAQ,UACH,UAAA,EAAA,cACL,EAAS,YACT,EAAQ,UAAQ,GAAA,UAAA,QAAA,QAAA,EAAA,UAAA,GAAA,WAAA,kHAYP,EAAA,SAAU,EAAA,EAAA,gBAGrB,KAAa,QAAS,UAAQ,SAAA,EAAA,WAG7B,EAAQ,YACT,EAAS,+EAOX,EAAO,MAAA,EAAiB,EAAW,KAInC,IAAI,GAAK,EAAa,MAAA,EAAA,EAAA,EAAA,EACtB,IAAA,EAAsB,MAAA,EAAW,KAAA,oCAM/B,GAAA,EAAY,8BAKZ,SAAgB,EAAS,YAAA,SACzB,EAAA,WACA,EAAA,SAAmB,EAAS,YAAA,SAAA,EAAA,wDAOhC,EAAS,GAAA,QAAuB,+KAsB3B,EAAQ,UACT,EAAA,MAAa,KAEb,SAAgB,EAAI,UAAS,sDAOjC,EAAS,IAAA,QAAuB,IAE9B,EAAA,UACA,EAAW,IAAA,QAAW,EAAA,cAYtB,OAAa,4DAOb,EAAQ,GAAA,oEASV,EAAA,oBAgBM,gBAOR,EAAI,SAAgB,EAAA,OAAA,EAAA,MAAA,SAAA,EAAA,kBAGlB,GAAQ,EAAc,SAChB,SAAS,SAAK,GAAA,UAAA,iBAAA,wBAKlB,GAAO,GAAA,EAAA,gFAIX,EAAO,IAAA,EAAA,EAAA,wCAlQL,EAAI,OAAS,UAAA,gFAGb,EAAqB,+GA+QhB,uCAKH,IAAa,MAAK,EAAS,QAAK,EAAS,MAAU,WACjD,SAAa,WAAK,kBAAY,YAAA,WAAA,WAAA,OAAA,YAAA,YAAA,MAAA,SAAA,0CAKlC,QAAK,SAAW,QAAM,WAAY,SAAS,GACzC,EAAG,IAAQ,EAAA,SAAS,EAAW,SAAA,GAC7B,EAAA,GAAQ,EAAO,YAAO,qEAOtB,QAAQ,OAAO,EAAA,uBAOjB,GAAI,EAAa,gFAQtB,EAAA","file":"modal.min.js","sourcesContent":["'use strict';\n\nangular.module('mgcrea.ngStrap.modal', ['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 template: 'modal/modal.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($window, $rootScope, $compile, $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 var htmlReplaceRegExp = /ng-bind=\"/ig;\n\n function ModalFactory(config) {\n\n var $modal = {};\n\n // Common vars\n var options = $modal.$options = angular.extend({}, defaults, config);\n $modal.$promise = fetchTemplate(options.template);\n var scope = $modal.$scope = options.scope && options.scope.$new() || $rootScope.$new();\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 // Support contentTemplate option\n if(options.contentTemplate) {\n $modal.$promise = $modal.$promise.then(function(template) {\n var templateEl = angular.element(template);\n return fetchTemplate(options.contentTemplate)\n .then(function(contentTemplate) {\n var contentEl = findElement('[ng-bind=\"content\"]', templateEl[0]).removeAttr('ng-bind').html(contentTemplate);\n // Drop the default footer as you probably don't want it if you use a custom contentTemplate\n if(!config.template) contentEl.next().remove();\n return templateEl[0].outerHTML;\n });\n });\n }\n\n // Fetch, compile then initialize modal\n var modalLinker, modalElement;\n var backdropElement = angular.element('
');\n $modal.$promise.then(function(template) {\n if(angular.isObject(template)) template = template.data;\n if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html=\"');\n template = trim.apply(template);\n modalLinker = $compile(template);\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 if(modalElement) {\n modalElement.remove();\n modalElement = null;\n }\n if(backdropElement) {\n backdropElement.remove();\n backdropElement = null;\n }\n\n // Destroy scope\n scope.$destroy();\n\n };\n\n $modal.show = function() {\n if($modal.$isShown) return;\n\n if(scope.$emit(options.prefixEvent + '.show.before', $modal).defaultPrevented) {\n 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].lastChild ? angular.element(parent[0].lastChild) : null;\n } else {\n parent = null;\n after = options.element;\n }\n }\n\n // Fetch a cloned element linked from template\n modalElement = $modal.$element = modalLinker(scope, function(clonedElement, scope) {});\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 // Support v1.3+ $animate\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\n var promise = $animate.enter(modalElement, parent, after, enterAnimateCallback);\n if(promise && promise.then) promise.then(enterAnimateCallback);\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 if(options.backdrop) {\n modalElement.on('click', hideOnBackdropClick);\n backdropElement.on('click', hideOnBackdropClick);\n backdropElement.on('wheel', preventEventDefault);\n }\n if(options.keyboard) {\n modalElement.on('keyup', $modal.$onKeyUp);\n }\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 var promise = $animate.leave(modalElement, leaveAnimateCallback);\n // Support v1.3+ $animate\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\n if(promise && promise.then) promise.then(leaveAnimateCallback);\n\n if(options.backdrop) {\n $animate.leave(backdropElement);\n }\n $modal.$isShown = scope.$isShown = false;\n safeDigest(scope);\n\n // Unbind events\n if(options.backdrop) {\n modalElement.off('click', hideOnBackdropClick);\n backdropElement.off('click', hideOnBackdropClick);\n backdropElement.off('wheel', preventEventDefault);\n }\n if(options.keyboard) {\n modalElement.off('keyup', $modal.$onKeyUp);\n }\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 // 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 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 var fetchPromises = {};\n function fetchTemplate(template) {\n if(fetchPromises[template]) return fetchPromises[template];\n return (fetchPromises[template] = $q.when($templateCache.get(template) || $http.get(template))\n .then(function(res) {\n if(angular.isObject(res)) {\n $templateCache.put(template, res.data);\n return res.data;\n }\n return res;\n }));\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', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 5c2911684..eea308771 100644 --- a/dist/modules/modal.tpl.js +++ b/dist/modules/modal.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/modal.tpl.min.js b/dist/modules/modal.tpl.min.js index e814ada12..607cada06 100644 --- a/dist/modules/modal.tpl.min.js +++ b/dist/modules/modal.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/navbar.js b/dist/modules/navbar.js index 8c1713ebd..26d1aeb43 100644 --- a/dist/modules/navbar.js +++ b/dist/modules/navbar.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/navbar.min.js b/dist/modules/navbar.min.js index 97a0af366..bb1a625e8 100644 --- a/dist/modules/navbar.min.js +++ b/dist/modules/navbar.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/parse-options.js b/dist/modules/parse-options.js index 4199bd5a0..b5da332c8 100644 --- a/dist/modules/parse-options.js +++ b/dist/modules/parse-options.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/parse-options.min.js b/dist/modules/parse-options.min.js index 8bffcce39..3d20a23e4 100644 --- a/dist/modules/parse-options.min.js +++ b/dist/modules/parse-options.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/popover.js b/dist/modules/popover.js index b085bcef1..8a175d9e2 100644 --- a/dist/modules/popover.js +++ b/dist/modules/popover.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -63,7 +63,7 @@ angular.module('mgcrea.ngStrap.popover', ['mgcrea.ngStrap.tooltip']) // Directive options var options = {scope: scope}; - angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'customClass', 'autoClose'], function(key) { + angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'customClass', 'autoClose', 'id'], function(key) { if(angular.isDefined(attr[key])) options[key] = attr[key]; }); diff --git a/dist/modules/popover.min.js b/dist/modules/popover.min.js index e3f53379a..57632469d 100644 --- a/dist/modules/popover.min.js +++ b/dist/modules/popover.min.js @@ -1,9 +1,9 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT */ -"use strict";angular.module("mgcrea.ngStrap.popover",["mgcrea.ngStrap.tooltip"]).provider("$popover",function(){var t=this.defaults={animation:"am-fade",customClass:"",container:!1,target:!1,placement:"right",template:"popover/popover.tpl.html",contentTemplate:!1,trigger:"click",keyboard:!0,html:!1,title:"",content:"",delay:0,autoClose:!1};this.$get=["$tooltip",function(e){function n(n,o){var a=angular.extend({},t,o),r=e(n,a);return a.content&&(r.$scope.content=a.content),r}return n}]}).directive("bsPopover",["$window","$sce","$popover",function(t,e,n){var o=t.requestAnimationFrame||t.setTimeout;return{restrict:"EAC",scope:!0,link:function(t,a,r){var i={scope:t};angular.forEach(["template","contentTemplate","placement","container","target","delay","trigger","keyboard","html","animation","customClass","autoClose"],function(t){angular.isDefined(r[t])&&(i[t]=r[t])}),angular.forEach(["title","content"],function(n){r[n]&&r.$observe(n,function(a,r){t[n]=e.trustAsHtml(a),angular.isDefined(r)&&o(function(){c&&c.$applyPlacement()})})}),r.bsPopover&&t.$watch(r.bsPopover,function(e,n){angular.isObject(e)?angular.extend(t,e):t.content=e,angular.isDefined(n)&&o(function(){c&&c.$applyPlacement()})},!0),r.bsShow&&t.$watch(r.bsShow,function(t){c&&angular.isDefined(t)&&(angular.isString(t)&&(t=!!t.match(/true|,?(popover),?/i)),t===!0?c.show():c.hide())});var c=n(a,i);t.$on("$destroy",function(){c&&c.destroy(),i=null,c=null})}}}]); +"use strict";angular.module("mgcrea.ngStrap.popover",["mgcrea.ngStrap.tooltip"]).provider("$popover",function(){var t=this.defaults={animation:"am-fade",customClass:"",container:!1,target:!1,placement:"right",template:"popover/popover.tpl.html",contentTemplate:!1,trigger:"click",keyboard:!0,html:!1,title:"",content:"",delay:0,autoClose:!1};this.$get=["$tooltip",function(e){function n(n,o){var a=angular.extend({},t,o),r=e(n,a);return a.content&&(r.$scope.content=a.content),r}return n}]}).directive("bsPopover",["$window","$sce","$popover",function(t,e,n){var o=t.requestAnimationFrame||t.setTimeout;return{restrict:"EAC",scope:!0,link:function(t,a,r){var i={scope:t};angular.forEach(["template","contentTemplate","placement","container","target","delay","trigger","keyboard","html","animation","customClass","autoClose","id"],function(t){angular.isDefined(r[t])&&(i[t]=r[t])}),angular.forEach(["title","content"],function(n){r[n]&&r.$observe(n,function(a,r){t[n]=e.trustAsHtml(a),angular.isDefined(r)&&o(function(){c&&c.$applyPlacement()})})}),r.bsPopover&&t.$watch(r.bsPopover,function(e,n){angular.isObject(e)?angular.extend(t,e):t.content=e,angular.isDefined(n)&&o(function(){c&&c.$applyPlacement()})},!0),r.bsShow&&t.$watch(r.bsShow,function(t){c&&angular.isDefined(t)&&(angular.isString(t)&&(t=!!t.match(/true|,?(popover),?/i)),t===!0?c.show():c.hide())});var c=n(a,i);t.$on("$destroy",function(){c&&c.destroy(),i=null,c=null})}}}]); //# sourceMappingURL=popover.min.js.map \ No newline at end of file diff --git a/dist/modules/popover.min.js.map b/dist/modules/popover.min.js.map index 319e11de8..5f47ceae1 100644 --- a/dist/modules/popover.min.js.map +++ b/dist/modules/popover.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["popover/popover.js"],"names":[],"mappings":"qBASM,OAAA,0BAAW,oCAEX,WAAW,cAEX,GAAA,KAAiB,UACjB,UAAS,UACT,YAAU,GACV,WAAM,EACN,QAAO,EACP,UAAS,QACT,SAAO,2BACP,iBAAW,8BAGb,MAAK,WAEH,QAAS,8BAKP,MAAI,WAAW,SAAS,gDAOxB,EAAO,EAAA,EAAA,sBAIT,EAAO,OAAA,QAAA,EAAA,kCAaD,aAAS,UAAgB,OAAS,WAAM,SAAA,EAAA,EAAA,+DAKvC,uCAKH,IAAa,MAAK,WAChB,SAAa,WAAK,kBAAY,YAAA,YAAA,SAAA,QAAA,UAAA,WAAA,OAAA,YAAA,cAAA,aAAA,SAAA,GAC9B,QAAQ,UAAU,EAAA,MAAa,EAAA,GAAA,EAAA,6GAOnC,QAAK,UAAa,IAAa,EAAyB,WACnD,GAAQ,EAAS,0BAMlB,WAAW,EAAQ,OAAA,EAAA,UAAA,SAAA,EAAA,uBAEpB,QAAA,OAAA,EAAA,eAID,QAAI,UAAY,IAAQ,EAAqB,WAC7C,GAAW,EAAS,yBAKtB,EAAI,QAAU,EAAA,OAAS,EAAS,OAAA,SAAA,uFAGhC,KAAU,EAAY,EAAA,OAAW,EAAA,kEASpC,EAAA","file":"popover.min.js","sourcesContent":["'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 container: false,\n target: false,\n placement: 'right',\n template: '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', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'customClass', 'autoClose'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 // 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"],"sourceRoot":"/source/"} \ No newline at end of file +{"version":3,"sources":["popover/popover.js"],"names":[],"mappings":"qBASM,OAAA,0BAAW,oCAEX,WAAW,cAEX,GAAA,KAAiB,UACjB,UAAS,UACT,YAAU,GACV,WAAM,EACN,QAAO,EACP,UAAS,QACT,SAAO,2BACP,iBAAW,8BAGb,MAAK,WAEH,QAAS,8BAKP,MAAI,WAAW,SAAS,gDAOxB,EAAO,EAAA,EAAA,sBAIT,EAAO,OAAA,QAAA,EAAA,kCAaD,aAAS,UAAgB,OAAS,WAAM,SAAA,EAAA,EAAA,+DAKvC,uCAKH,IAAa,MAAK,WAChB,SAAa,WAAK,kBAAY,YAAA,YAAA,SAAA,QAAA,UAAA,WAAA,OAAA,YAAA,cAAA,YAAA,MAAA,SAAA,GAC9B,QAAQ,UAAU,EAAA,MAAa,EAAA,GAAA,EAAA,6GAOnC,QAAK,UAAa,IAAa,EAAyB,WACnD,GAAQ,EAAS,0BAMlB,WAAW,EAAQ,OAAA,EAAA,UAAA,SAAA,EAAA,uBAEpB,QAAA,OAAA,EAAA,eAID,QAAI,UAAY,IAAQ,EAAqB,WAC7C,GAAW,EAAS,yBAKtB,EAAI,QAAU,EAAA,OAAS,EAAS,OAAA,SAAA,uFAGhC,KAAU,EAAY,EAAA,OAAW,EAAA,kEASpC,EAAA","file":"popover.min.js","sourcesContent":["'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 container: false,\n target: false,\n placement: 'right',\n template: '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', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'customClass', 'autoClose', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 // 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"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/dist/modules/popover.tpl.js b/dist/modules/popover.tpl.js index fe1b02e58..35deac3c3 100644 --- a/dist/modules/popover.tpl.js +++ b/dist/modules/popover.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/popover.tpl.min.js b/dist/modules/popover.tpl.min.js index e0c39e6cb..080dbc1c6 100644 --- a/dist/modules/popover.tpl.min.js +++ b/dist/modules/popover.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/raf.js b/dist/modules/raf.js index 270e3c5b7..194fbc8ef 100644 --- a/dist/modules/raf.js +++ b/dist/modules/raf.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/raf.min.js b/dist/modules/raf.min.js index 9b8f87e94..e07641b54 100644 --- a/dist/modules/raf.min.js +++ b/dist/modules/raf.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/scrollspy.js b/dist/modules/scrollspy.js index 9424de7a3..759a2508b 100644 --- a/dist/modules/scrollspy.js +++ b/dist/modules/scrollspy.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/scrollspy.min.js b/dist/modules/scrollspy.min.js index 4308ecd99..c9809e4c6 100644 --- a/dist/modules/scrollspy.min.js +++ b/dist/modules/scrollspy.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/select.js b/dist/modules/select.js index 40e0a6a66..f85c34b93 100644 --- a/dist/modules/select.js +++ b/dist/modules/select.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -127,7 +127,7 @@ angular.module('mgcrea.ngStrap.select', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStr } }); // Emit event - scope.$emit(options.prefixEvent + '.select', value, index); + scope.$emit(options.prefixEvent + '.select', value, index, $select); }; // Protected methods @@ -249,7 +249,7 @@ angular.module('mgcrea.ngStrap.select', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStr // Directive options var options = {scope: scope, placeholder: defaults.placeholder}; - angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'placeholder', 'multiple', 'allNoneButtons', 'maxLength', 'maxLengthHtml', 'allText', 'noneText'], function(key) { + angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'placeholder', 'multiple', 'allNoneButtons', 'maxLength', 'maxLengthHtml', 'allText', 'noneText', 'iconCheckmark', 'autoClose', 'id'], function(key) { if(angular.isDefined(attr[key])) options[key] = attr[key]; }); diff --git a/dist/modules/select.min.js b/dist/modules/select.min.js index 7fa179348..4a8e07c5b 100644 --- a/dist/modules/select.min.js +++ b/dist/modules/select.min.js @@ -1,9 +1,9 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT */ -"use strict";angular.module("mgcrea.ngStrap.select",["mgcrea.ngStrap.tooltip","mgcrea.ngStrap.helpers.parseOptions"]).provider("$select",function(){var e=this.defaults={animation:"am-fade",prefixClass:"select",prefixEvent:"$select",placement:"bottom-left",template:"select/select.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,multiple:!1,allNoneButtons:!1,sort:!0,caretHtml:' ',placeholder:"Choose among the following...",allText:"All",noneText:"None",maxLength:3,maxLengthHtml:"selected",iconCheckmark:"glyphicon glyphicon-ok"};this.$get=["$window","$document","$rootScope","$tooltip","$timeout",function(t,n,a,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=0,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){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){if(/(9|13|38|40)/.test(e.keyCode)){if(e.preventDefault(),e.stopPropagation(),!c.multiple&&(13===e.keyCode||9===e.keyCode))return o.select(u.$activeIndex);38===e.keyCode&&u.$activeIndex>0?u.$activeIndex--:40===e.keyCode&&u.$activeIndex'),r.after(t)}var u=l(n.ngOptions),s=a(t,o,c),$=u.$match[7].replace(/\|.+/,"").trim();e.$watch($,function(){u.valuesFn(e,o).then(function(e){s.update(e),o.$render()})},!0),e.$watch(n.ngModel,function(){s.$updateActiveIndex(),o.$render()},!0),o.$render=function(){var e,n;c.multiple&&angular.isArray(o.$modelValue)?(e=o.$modelValue.map(function(e){return n=s.$getIndex(e),angular.isDefined(n)?s.$scope.$matches[n].label:!1}).filter(angular.isDefined),e=e.length>(c.maxLength||i.maxLength)?e.length+" "+(c.maxLengthHtml||i.maxLengthHtml):e.join(", ")):(n=s.$getIndex(o.$modelValue),e=angular.isDefined(n)?s.$scope.$matches[n].label:!1),t.html((e?e:c.placeholder)+i.caretHtml)},c.multiple&&(o.$isEmpty=function(e){return!e||0===e.length}),e.$on("$destroy",function(){s&&s.destroy(),c=null,s=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",template:"select/select.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,multiple:!1,allNoneButtons:!1,sort:!0,caretHtml:' ',placeholder:"Choose among the following...",allText:"All",noneText:"None",maxLength:3,maxLengthHtml:"selected",iconCheckmark:"glyphicon glyphicon-ok"};this.$get=["$window","$document","$rootScope","$tooltip","$timeout",function(t,n,a,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=0,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){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){if(/(9|13|38|40)/.test(e.keyCode)){if(e.preventDefault(),e.stopPropagation(),!c.multiple&&(13===e.keyCode||9===e.keyCode))return o.select(u.$activeIndex);38===e.keyCode&&u.$activeIndex>0?u.$activeIndex--:40===e.keyCode&&u.$activeIndex'),r.after(t)}var u=l(n.ngOptions),s=a(t,o,c),$=u.$match[7].replace(/\|.+/,"").trim();e.$watch($,function(){u.valuesFn(e,o).then(function(e){s.update(e),o.$render()})},!0),e.$watch(n.ngModel,function(){s.$updateActiveIndex(),o.$render()},!0),o.$render=function(){var e,n;c.multiple&&angular.isArray(o.$modelValue)?(e=o.$modelValue.map(function(e){return n=s.$getIndex(e),angular.isDefined(n)?s.$scope.$matches[n].label:!1}).filter(angular.isDefined),e=e.length>(c.maxLength||i.maxLength)?e.length+" "+(c.maxLengthHtml||i.maxLengthHtml):e.join(", ")):(n=s.$getIndex(o.$modelValue),e=angular.isDefined(n)?s.$scope.$matches[n].label:!1),t.html((e?e:c.placeholder)+i.caretHtml)},c.multiple&&(o.$isEmpty=function(e){return!e||0===e.length}),e.$on("$destroy",function(){s&&s.destroy(),c=null,s=null})}}}]); //# sourceMappingURL=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 94539275f..ebae120c8 100644 --- a/dist/modules/select.min.js.map +++ b/dist/modules/select.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["select/select.js"],"names":[],"mappings":"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","file":"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 template: '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 scope.$activeIndex = 0;\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 scope.$activeIndex.sort();\n $select.$isActive(index) ? scope.$activeIndex.splice(scope.$activeIndex.indexOf(index), 1) : scope.$activeIndex.push(index);\n if(options.sort) scope.$activeIndex.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);\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 // Select with enter\n if(!options.multiple && (evt.keyCode === 13 || evt.keyCode === 9)) {\n return $select.select(scope.$activeIndex);\n }\n\n // Navigate with keyboard\n 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 = $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 $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(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'placeholder', 'multiple', 'allNoneButtons', 'maxLength', 'maxLengthHtml', 'allText', 'noneText'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 ngOptions\n var parsedOptions = $parseOptions(attr.ngOptions);\n\n // Initialize select\n var select = $select(element, controller, options);\n\n // Watch ngOptions values before filtering for changes\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').trim();\n scope.$watch(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 }, true);\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) + 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":["select/select.js"],"names":[],"mappings":"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","file":"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 template: '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 scope.$activeIndex = 0;\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 scope.$activeIndex.sort();\n $select.$isActive(index) ? scope.$activeIndex.splice(scope.$activeIndex.indexOf(index), 1) : scope.$activeIndex.push(index);\n if(options.sort) scope.$activeIndex.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 // Select with enter\n if(!options.multiple && (evt.keyCode === 13 || evt.keyCode === 9)) {\n return $select.select(scope.$activeIndex);\n }\n\n // Navigate with keyboard\n 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 = $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 $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(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'placeholder', 'multiple', 'allNoneButtons', 'maxLength', 'maxLengthHtml', 'allText', 'noneText', 'iconCheckmark', 'autoClose', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 ngOptions\n var parsedOptions = $parseOptions(attr.ngOptions);\n\n // Initialize select\n var select = $select(element, controller, options);\n\n // Watch ngOptions values before filtering for changes\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').trim();\n scope.$watch(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 }, true);\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) + 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 b3fc3bf83..cf771376e 100644 --- a/dist/modules/select.tpl.js +++ b/dist/modules/select.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -9,6 +9,6 @@ angular.module('mgcrea.ngStrap.select').run(['$templateCache', function($templateCache) { - $templateCache.put('select/select.tpl.html', ''); + $templateCache.put('select/select.tpl.html', ''); }]); \ No newline at end of file diff --git a/dist/modules/select.tpl.min.js b/dist/modules/select.tpl.min.js index 5273d986e..5ec4b3721 100644 --- a/dist/modules/select.tpl.min.js +++ b/dist/modules/select.tpl.min.js @@ -1,8 +1,8 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT */ -"use strict";angular.module("mgcrea.ngStrap.select").run(["$templateCache",function(t){t.put("select/select.tpl.html",'')}]); \ No newline at end of file +"use strict";angular.module("mgcrea.ngStrap.select").run(["$templateCache",function(t){t.put("select/select.tpl.html",'')}]); \ No newline at end of file diff --git a/dist/modules/tab.js b/dist/modules/tab.js index b33c58d4f..ccadfbe85 100644 --- a/dist/modules/tab.js +++ b/dist/modules/tab.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/tab.min.js b/dist/modules/tab.min.js index 32a74f204..b8f4ea0fb 100644 --- a/dist/modules/tab.min.js +++ b/dist/modules/tab.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/tab.tpl.js b/dist/modules/tab.tpl.js index 4882306aa..831a6e5fb 100644 --- a/dist/modules/tab.tpl.js +++ b/dist/modules/tab.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/tab.tpl.min.js b/dist/modules/tab.tpl.min.js index 292323ce6..a495ae304 100644 --- a/dist/modules/tab.tpl.min.js +++ b/dist/modules/tab.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/timepicker.js b/dist/modules/timepicker.js index 4072c1222..d9dd54c64 100644 --- a/dist/modules/timepicker.js +++ b/dist/modules/timepicker.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -308,8 +308,8 @@ angular.module('mgcrea.ngStrap.timepicker', [ var _show = $timepicker.show; $timepicker.show = function() { _show(); - // use timeout to hookup the events to prevent - // event bubbling from being processed imediately. + // use timeout to hookup the events to prevent + // event bubbling from being processed imediately. $timeout(function() { $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown); if(options.keyboard) { @@ -353,7 +353,7 @@ angular.module('mgcrea.ngStrap.timepicker', [ // Directive options var options = {scope: scope, controller: controller}; - angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'timeType', 'timeFormat', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown'], function(key) { + angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'timeType', 'timeFormat', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown', 'id'], function(key) { if(angular.isDefined(attr[key])) options[key] = attr[key]; }); @@ -414,7 +414,7 @@ angular.module('mgcrea.ngStrap.timepicker', [ // Null values should correctly reset the model value & validity if(!viewValue) { // BREAKING CHANGE: - // return null (not undefined) when input value is empty, so angularjs 1.3 + // return null (not undefined) when input value is empty, so angularjs 1.3 // ngModelController can go ahead and run validators, like ngRequired controller.$setValidity('date', true); return null; @@ -422,8 +422,8 @@ angular.module('mgcrea.ngStrap.timepicker', [ var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue); if(!parsedTime || isNaN(parsedTime.getTime())) { controller.$setValidity('date', false); - // return undefined, causes ngModelController to - // invalidate model value + // return undefined, causes ngModelController to + // invalidate model value return; } else { validateAgainstMinMaxTime(parsedTime); diff --git a/dist/modules/timepicker.min.js b/dist/modules/timepicker.min.js index 6e3f41f6e..2f1ba60b0 100644 --- a/dist/modules/timepicker.min.js +++ b/dist/modules/timepicker.min.js @@ -1,9 +1,9 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT */ -"use strict";angular.module("mgcrea.ngStrap.timepicker",["mgcrea.ngStrap.helpers.dateParser","mgcrea.ngStrap.helpers.dateFormatter","mgcrea.ngStrap.tooltip"]).provider("$timepicker",function(){var e=this.defaults={animation:"am-fade",prefixClass:"timepicker",placement:"bottom-left",template:"timepicker/timepicker.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,useNative:!0,timeType:"date",timeFormat:"shortTime",modelTimeFormat:null,autoclose:!1,minTime:-1/0,maxTime:+1/0,length:5,hourStep:1,minuteStep:5,iconUp:"glyphicon glyphicon-chevron-up",iconDown:"glyphicon glyphicon-chevron-down",arrowBehavior:"pager"};this.$get=["$window","$document","$rootScope","$sce","$dateFormatter","$tooltip","$timeout",function(t,a,n,i,o,r,u){function s(t,a,n){function i(e,a){if(t[0].createTextRange){var n=t[0].createTextRange();n.collapse(!0),n.moveStart("character",e),n.moveEnd("character",a),n.select()}else t[0].setSelectionRange?t[0].setSelectionRange(e,a):angular.isUndefined(t[0].selectionStart)&&(t[0].selectionStart=e,t[0].selectionEnd=a)}function s(){t[0].focus()}var m=r(t,angular.extend({},e,n)),c=n.scope,g=m.$options,p=m.$scope,$=g.lang,f=function(e,t){return o.formatDate(e,t,$)},h=0,w=a.$dateValue||new Date,v={hour:w.getHours(),meridian:w.getHours()<12,minute:w.getMinutes(),second:w.getSeconds(),millisecond:w.getMilliseconds()},y=o.getDatetimeFormat(g.timeFormat,$),T=o.hoursFormat(y),D=o.timeSeparator(y),S=o.minutesFormat(y),V=o.showAM(y);p.$iconUp=g.iconUp,p.$iconDown=g.iconDown,p.$select=function(e,t){m.select(e,t)},p.$moveIndex=function(e,t){m.$moveIndex(e,t)},p.$switchMeridian=function(e){m.switchMeridian(e)},m.update=function(e){angular.isDate(e)&&!isNaN(e.getTime())?(m.$date=e,angular.extend(v,{hour:e.getHours(),minute:e.getMinutes(),second:e.getSeconds(),millisecond:e.getMilliseconds()}),m.$build()):m.$isBuilt||m.$build()},m.select=function(e,t,n){(!a.$dateValue||isNaN(a.$dateValue.getTime()))&&(a.$dateValue=new Date(1970,0,1)),angular.isDate(e)||(e=new Date(e)),0===t?a.$dateValue.setHours(e.getHours()):1===t&&a.$dateValue.setMinutes(e.getMinutes()),a.$setViewValue(angular.copy(a.$dateValue)),a.$render(),g.autoclose&&!n&&u(function(){m.hide(!0)})},m.switchMeridian=function(e){if(a.$dateValue&&!isNaN(a.$dateValue.getTime())){var t=(e||a.$dateValue).getHours();a.$dateValue.setHours(12>t?t+12:t-12),a.$setViewValue(angular.copy(a.$dateValue)),a.$render()}},m.$build=function(){var e,t,a=p.midIndex=parseInt(g.length/2,10),n=[];for(e=0;e1*g.maxTime},p.$arrowAction=function(e,t){"picker"===g.arrowBehavior?m.$setTimeByStep(e,t):m.$moveIndex(e,t)},m.$setTimeByStep=function(e,t){{var a=new Date(m.$date),n=a.getHours(),i=(f(a,T).length,a.getMinutes());f(a,S).length}0===t?a.setHours(n-parseInt(g.hourStep,10)*e):a.setMinutes(i-parseInt(g.minuteStep,10)*e),m.select(a,t,!0)},m.$moveIndex=function(e,t){var a;0===t?(a=new Date(1970,0,1,v.hour+e*g.length,v.minute),angular.extend(v,{hour:a.getHours()})):1===t&&(a=new Date(1970,0,1,v.hour,v.minute+e*g.length*g.minuteStep),angular.extend(v,{minute:a.getMinutes()})),m.$build()},m.$onMouseDown=function(e){if("input"!==e.target.nodeName.toLowerCase()&&e.preventDefault(),e.stopPropagation(),d){var t=angular.element(e.target);"button"!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler("click")}},m.$onKeyDown=function(e){if(/(38|37|39|40|13)/.test(e.keyCode)&&!e.shiftKey&&!e.altKey){if(e.preventDefault(),e.stopPropagation(),13===e.keyCode)return m.hide(!0);var t=new Date(m.$date),a=t.getHours(),n=f(t,T).length,o=t.getMinutes(),r=f(t,S).length,u=/(37|39)/.test(e.keyCode),s=2+1*V;u&&(37===e.keyCode?h=1>h?s-1:h-1:39===e.keyCode&&(h=s-1>h?h+1:0));var l=[0,n];0===h?(38===e.keyCode?t.setHours(a-parseInt(g.hourStep,10)):40===e.keyCode&&t.setHours(a+parseInt(g.hourStep,10)),n=f(t,T).length,l=[0,n]):1===h?(38===e.keyCode?t.setMinutes(o-parseInt(g.minuteStep,10)):40===e.keyCode&&t.setMinutes(o+parseInt(g.minuteStep,10)),r=f(t,S).length,l=[n+1,n+1+r]):2===h&&(u||m.switchMeridian(),l=[n+1+r+1,n+1+r+3]),m.select(t,h,!0),i(l[0],l[1]),c.$digest()}};var k=m.init;m.init=function(){return l&&g.useNative?(t.prop("type","time"),void t.css("-webkit-appearance","textfield")):(d&&(t.prop("type","text"),t.attr("readonly","true"),t.on("click",s)),void k())};var b=m.destroy;m.destroy=function(){l&&g.useNative&&t.off("click",s),b()};var M=m.show;m.show=function(){M(),u(function(){m.$element.on(d?"touchstart":"mousedown",m.$onMouseDown),g.keyboard&&t.on("keydown",m.$onKeyDown)},0,!1)};var N=m.hide;return m.hide=function(e){m.$isShown&&(m.$element.off(d?"touchstart":"mousedown",m.$onMouseDown),g.keyboard&&t.off("keydown",m.$onKeyDown),N(e))},m}var l=(angular.element(t.document.body),/(ip(a|o)d|iphone|android)/gi.test(t.navigator.userAgent)),d="createTouch"in t.document&&l;return e.lang||(e.lang=o.getDefaultLocale()),s.defaults=e,s}]}).directive("bsTimepicker",["$window","$parse","$q","$dateFormatter","$dateParser","$timepicker",function(e,t,a,n,i,o){{var r=o.defaults,u=/(ip(a|o)d|iphone|android)/gi.test(e.navigator.userAgent);e.requestAnimationFrame||e.setTimeout}return{restrict:"EAC",require:"ngModel",link:function(e,t,a,s){function l(e){if(angular.isDate(e)){var t=isNaN(m.minTime)||new Date(e.getTime()).setFullYear(1970,0,1)>=m.minTime,a=isNaN(m.maxTime)||new Date(e.getTime()).setFullYear(1970,0,1)<=m.maxTime,n=t&&a;s.$setValidity("date",n),s.$setValidity("min",t),s.$setValidity("max",a),n&&(s.$dateValue=e)}}function d(){return!s.$dateValue||isNaN(s.$dateValue.getTime())?"":p(s.$dateValue,m.timeFormat)}var m={scope:e,controller:s};angular.forEach(["placement","container","delay","trigger","keyboard","html","animation","template","autoclose","timeType","timeFormat","modelTimeFormat","useNative","hourStep","minuteStep","length","arrowBehavior","iconUp","iconDown"],function(e){angular.isDefined(a[e])&&(m[e]=a[e])}),a.bsShow&&e.$watch(a.bsShow,function(e){c&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(timepicker),?/i)),e===!0?c.show():c.hide())}),u&&(m.useNative||r.useNative)&&(m.timeFormat="HH:mm");var c=o(t,s,m);m=c.$options;var g=m.lang,p=function(e,t){return n.formatDate(e,t,g)},$=i({format:m.timeFormat,lang:g});angular.forEach(["minTime","maxTime"],function(e){angular.isDefined(a[e])&&a.$observe(e,function(t){c.$options[e]=$.getTimeForAttribute(e,t),!isNaN(c.$options[e])&&c.$build(),l(s.$dateValue)})}),e.$watch(a.ngModel,function(){c.update(s.$dateValue)},!0),s.$parsers.unshift(function(e){if(!e)return s.$setValidity("date",!0),null;var t=angular.isDate(e)?e:$.parse(e,s.$dateValue);return!t||isNaN(t.getTime())?void s.$setValidity("date",!1):(l(t),"string"===m.timeType?p(t,m.modelTimeFormat||m.timeFormat):"number"===m.timeType?s.$dateValue.getTime():"unix"===m.timeType?s.$dateValue.getTime()/1e3:"iso"===m.timeType?s.$dateValue.toISOString():new Date(s.$dateValue))}),s.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:"string"===m.timeType?$.parse(e,null,m.modelTimeFormat):new Date("unix"===m.timeType?1e3*e:e),s.$dateValue=t,d()}),s.$render=function(){t.val(d())},e.$on("$destroy",function(){c&&c.destroy(),m=null,c=null})}}}]); +"use strict";angular.module("mgcrea.ngStrap.timepicker",["mgcrea.ngStrap.helpers.dateParser","mgcrea.ngStrap.helpers.dateFormatter","mgcrea.ngStrap.tooltip"]).provider("$timepicker",function(){var e=this.defaults={animation:"am-fade",prefixClass:"timepicker",placement:"bottom-left",template:"timepicker/timepicker.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,useNative:!0,timeType:"date",timeFormat:"shortTime",modelTimeFormat:null,autoclose:!1,minTime:-1/0,maxTime:+1/0,length:5,hourStep:1,minuteStep:5,iconUp:"glyphicon glyphicon-chevron-up",iconDown:"glyphicon glyphicon-chevron-down",arrowBehavior:"pager"};this.$get=["$window","$document","$rootScope","$sce","$dateFormatter","$tooltip","$timeout",function(t,a,n,i,o,r,u){function s(t,a,n){function i(e,a){if(t[0].createTextRange){var n=t[0].createTextRange();n.collapse(!0),n.moveStart("character",e),n.moveEnd("character",a),n.select()}else t[0].setSelectionRange?t[0].setSelectionRange(e,a):angular.isUndefined(t[0].selectionStart)&&(t[0].selectionStart=e,t[0].selectionEnd=a)}function s(){t[0].focus()}var m=r(t,angular.extend({},e,n)),c=n.scope,g=m.$options,p=m.$scope,$=g.lang,f=function(e,t){return o.formatDate(e,t,$)},h=0,w=a.$dateValue||new Date,v={hour:w.getHours(),meridian:w.getHours()<12,minute:w.getMinutes(),second:w.getSeconds(),millisecond:w.getMilliseconds()},y=o.getDatetimeFormat(g.timeFormat,$),T=o.hoursFormat(y),D=o.timeSeparator(y),S=o.minutesFormat(y),V=o.showAM(y);p.$iconUp=g.iconUp,p.$iconDown=g.iconDown,p.$select=function(e,t){m.select(e,t)},p.$moveIndex=function(e,t){m.$moveIndex(e,t)},p.$switchMeridian=function(e){m.switchMeridian(e)},m.update=function(e){angular.isDate(e)&&!isNaN(e.getTime())?(m.$date=e,angular.extend(v,{hour:e.getHours(),minute:e.getMinutes(),second:e.getSeconds(),millisecond:e.getMilliseconds()}),m.$build()):m.$isBuilt||m.$build()},m.select=function(e,t,n){(!a.$dateValue||isNaN(a.$dateValue.getTime()))&&(a.$dateValue=new Date(1970,0,1)),angular.isDate(e)||(e=new Date(e)),0===t?a.$dateValue.setHours(e.getHours()):1===t&&a.$dateValue.setMinutes(e.getMinutes()),a.$setViewValue(angular.copy(a.$dateValue)),a.$render(),g.autoclose&&!n&&u(function(){m.hide(!0)})},m.switchMeridian=function(e){if(a.$dateValue&&!isNaN(a.$dateValue.getTime())){var t=(e||a.$dateValue).getHours();a.$dateValue.setHours(12>t?t+12:t-12),a.$setViewValue(angular.copy(a.$dateValue)),a.$render()}},m.$build=function(){var e,t,a=p.midIndex=parseInt(g.length/2,10),n=[];for(e=0;e1*g.maxTime},p.$arrowAction=function(e,t){"picker"===g.arrowBehavior?m.$setTimeByStep(e,t):m.$moveIndex(e,t)},m.$setTimeByStep=function(e,t){{var a=new Date(m.$date),n=a.getHours(),i=(f(a,T).length,a.getMinutes());f(a,S).length}0===t?a.setHours(n-parseInt(g.hourStep,10)*e):a.setMinutes(i-parseInt(g.minuteStep,10)*e),m.select(a,t,!0)},m.$moveIndex=function(e,t){var a;0===t?(a=new Date(1970,0,1,v.hour+e*g.length,v.minute),angular.extend(v,{hour:a.getHours()})):1===t&&(a=new Date(1970,0,1,v.hour,v.minute+e*g.length*g.minuteStep),angular.extend(v,{minute:a.getMinutes()})),m.$build()},m.$onMouseDown=function(e){if("input"!==e.target.nodeName.toLowerCase()&&e.preventDefault(),e.stopPropagation(),d){var t=angular.element(e.target);"button"!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler("click")}},m.$onKeyDown=function(e){if(/(38|37|39|40|13)/.test(e.keyCode)&&!e.shiftKey&&!e.altKey){if(e.preventDefault(),e.stopPropagation(),13===e.keyCode)return m.hide(!0);var t=new Date(m.$date),a=t.getHours(),n=f(t,T).length,o=t.getMinutes(),r=f(t,S).length,u=/(37|39)/.test(e.keyCode),s=2+1*V;u&&(37===e.keyCode?h=1>h?s-1:h-1:39===e.keyCode&&(h=s-1>h?h+1:0));var l=[0,n];0===h?(38===e.keyCode?t.setHours(a-parseInt(g.hourStep,10)):40===e.keyCode&&t.setHours(a+parseInt(g.hourStep,10)),n=f(t,T).length,l=[0,n]):1===h?(38===e.keyCode?t.setMinutes(o-parseInt(g.minuteStep,10)):40===e.keyCode&&t.setMinutes(o+parseInt(g.minuteStep,10)),r=f(t,S).length,l=[n+1,n+1+r]):2===h&&(u||m.switchMeridian(),l=[n+1+r+1,n+1+r+3]),m.select(t,h,!0),i(l[0],l[1]),c.$digest()}};var k=m.init;m.init=function(){return l&&g.useNative?(t.prop("type","time"),void t.css("-webkit-appearance","textfield")):(d&&(t.prop("type","text"),t.attr("readonly","true"),t.on("click",s)),void k())};var b=m.destroy;m.destroy=function(){l&&g.useNative&&t.off("click",s),b()};var M=m.show;m.show=function(){M(),u(function(){m.$element.on(d?"touchstart":"mousedown",m.$onMouseDown),g.keyboard&&t.on("keydown",m.$onKeyDown)},0,!1)};var N=m.hide;return m.hide=function(e){m.$isShown&&(m.$element.off(d?"touchstart":"mousedown",m.$onMouseDown),g.keyboard&&t.off("keydown",m.$onKeyDown),N(e))},m}var l=(angular.element(t.document.body),/(ip(a|o)d|iphone|android)/gi.test(t.navigator.userAgent)),d="createTouch"in t.document&&l;return e.lang||(e.lang=o.getDefaultLocale()),s.defaults=e,s}]}).directive("bsTimepicker",["$window","$parse","$q","$dateFormatter","$dateParser","$timepicker",function(e,t,a,n,i,o){{var r=o.defaults,u=/(ip(a|o)d|iphone|android)/gi.test(e.navigator.userAgent);e.requestAnimationFrame||e.setTimeout}return{restrict:"EAC",require:"ngModel",link:function(e,t,a,s){function l(e){if(angular.isDate(e)){var t=isNaN(m.minTime)||new Date(e.getTime()).setFullYear(1970,0,1)>=m.minTime,a=isNaN(m.maxTime)||new Date(e.getTime()).setFullYear(1970,0,1)<=m.maxTime,n=t&&a;s.$setValidity("date",n),s.$setValidity("min",t),s.$setValidity("max",a),n&&(s.$dateValue=e)}}function d(){return!s.$dateValue||isNaN(s.$dateValue.getTime())?"":p(s.$dateValue,m.timeFormat)}var m={scope:e,controller:s};angular.forEach(["placement","container","delay","trigger","keyboard","html","animation","template","autoclose","timeType","timeFormat","modelTimeFormat","useNative","hourStep","minuteStep","length","arrowBehavior","iconUp","iconDown","id"],function(e){angular.isDefined(a[e])&&(m[e]=a[e])}),a.bsShow&&e.$watch(a.bsShow,function(e){c&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(timepicker),?/i)),e===!0?c.show():c.hide())}),u&&(m.useNative||r.useNative)&&(m.timeFormat="HH:mm");var c=o(t,s,m);m=c.$options;var g=m.lang,p=function(e,t){return n.formatDate(e,t,g)},$=i({format:m.timeFormat,lang:g});angular.forEach(["minTime","maxTime"],function(e){angular.isDefined(a[e])&&a.$observe(e,function(t){c.$options[e]=$.getTimeForAttribute(e,t),!isNaN(c.$options[e])&&c.$build(),l(s.$dateValue)})}),e.$watch(a.ngModel,function(){c.update(s.$dateValue)},!0),s.$parsers.unshift(function(e){if(!e)return s.$setValidity("date",!0),null;var t=angular.isDate(e)?e:$.parse(e,s.$dateValue);return!t||isNaN(t.getTime())?void s.$setValidity("date",!1):(l(t),"string"===m.timeType?p(t,m.modelTimeFormat||m.timeFormat):"number"===m.timeType?s.$dateValue.getTime():"unix"===m.timeType?s.$dateValue.getTime()/1e3:"iso"===m.timeType?s.$dateValue.toISOString():new Date(s.$dateValue))}),s.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:"string"===m.timeType?$.parse(e,null,m.modelTimeFormat):new Date("unix"===m.timeType?1e3*e:e),s.$dateValue=t,d()}),s.$render=function(){t.val(d())},e.$on("$destroy",function(){c&&c.destroy(),m=null,c=null})}}}]); //# sourceMappingURL=timepicker.min.js.map \ No newline at end of file diff --git a/dist/modules/timepicker.min.js.map b/dist/modules/timepicker.min.js.map index bc5bf8de3..4e8900b83 100644 --- a/dist/modules/timepicker.min.js.map +++ b/dist/modules/timepicker.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["timepicker/timepicker.js"],"names":[],"mappings":"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","file":"timepicker.min.js","sourcesContent":["'use strict';\n\nangular.module('mgcrea.ngStrap.timepicker', [\n 'mgcrea.ngStrap.helpers.dateParser',\n 'mgcrea.ngStrap.helpers.dateFormatter',\n 'mgcrea.ngStrap.tooltip'])\n\n .provider('$timepicker', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'timepicker',\n placement: 'bottom-left',\n template: '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 modelTimeFormat: null,\n autoclose: false,\n minTime: -Infinity,\n maxTime: +Infinity,\n length: 5,\n hourStep: 1,\n minuteStep: 5,\n iconUp: 'glyphicon glyphicon-chevron-up',\n iconDown: 'glyphicon glyphicon-chevron-down',\n arrowBehavior: 'pager'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\n\n function timepickerFactory(element, controller, config) {\n\n var $timepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $timepicker.$options;\n var scope = $timepicker.$scope;\n\n var lang = options.lang;\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n\n // View vars\n\n var selectedIndex = 0;\n var startDate = controller.$dateValue || new Date();\n var viewDate = {hour: startDate.getHours(), meridian: startDate.getHours() < 12, minute: startDate.getMinutes(), second: startDate.getSeconds(), millisecond: startDate.getMilliseconds()};\n\n var format = $dateFormatter.getDatetimeFormat(options.timeFormat, lang);\n\n var hoursFormat = $dateFormatter.hoursFormat(format),\n timeSeparator = $dateFormatter.timeSeparator(format),\n minutesFormat = $dateFormatter.minutesFormat(format),\n showAM = $dateFormatter.showAM(format);\n\n scope.$iconUp = options.iconUp;\n scope.$iconDown = options.iconDown;\n\n // Scope methods\n\n scope.$select = function(date, index) {\n $timepicker.select(date, index);\n };\n scope.$moveIndex = function(value, index) {\n $timepicker.$moveIndex(value, index);\n };\n scope.$switchMeridian = function(date) {\n $timepicker.switchMeridian(date);\n };\n\n // Public methods\n\n $timepicker.update = function(date) {\n // console.warn('$timepicker.update() newValue=%o', date);\n if(angular.isDate(date) && !isNaN(date.getTime())) {\n $timepicker.$date = date;\n angular.extend(viewDate, {hour: date.getHours(), minute: date.getMinutes(), second: date.getSeconds(), millisecond: date.getMilliseconds()});\n $timepicker.$build();\n } else if(!$timepicker.$isBuilt) {\n $timepicker.$build();\n }\n };\n\n $timepicker.select = function(date, index, keep) {\n // console.warn('$timepicker.select', date, scope.$mode);\n if(!controller.$dateValue || isNaN(controller.$dateValue.getTime())) controller.$dateValue = new Date(1970, 0, 1);\n if(!angular.isDate(date)) date = new Date(date);\n if(index === 0) controller.$dateValue.setHours(date.getHours());\n else if(index === 1) controller.$dateValue.setMinutes(date.getMinutes());\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n if(options.autoclose && !keep) {\n $timeout(function() { $timepicker.hide(true); });\n }\n };\n\n $timepicker.switchMeridian = function(date) {\n if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) {\n return;\n }\n var hours = (date || controller.$dateValue).getHours();\n controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12);\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n };\n\n // Protected methods\n\n $timepicker.$build = function() {\n // console.warn('$timepicker.$build() viewDate=%o', viewDate);\n var i, midIndex = scope.midIndex = parseInt(options.length / 2, 10);\n var hours = [], hour;\n for(i = 0; i < options.length; i++) {\n hour = new Date(1970, 0, 1, viewDate.hour - (midIndex - i) * options.hourStep);\n hours.push({date: hour, label: formatDate(hour, hoursFormat), selected: $timepicker.$date && $timepicker.$isSelected(hour, 0), disabled: $timepicker.$isDisabled(hour, 0)});\n }\n var minutes = [], minute;\n for(i = 0; i < options.length; i++) {\n minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep);\n minutes.push({date: minute, label: formatDate(minute, minutesFormat), selected: $timepicker.$date && $timepicker.$isSelected(minute, 1), disabled: $timepicker.$isDisabled(minute, 1)});\n }\n\n var rows = [];\n for(i = 0; i < options.length; i++) {\n rows.push([hours[i], minutes[i]]);\n }\n scope.rows = rows;\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 }\n };\n\n $timepicker.$isDisabled = function(date, index) {\n var selectedTime;\n if(index === 0) {\n selectedTime = date.getTime() + viewDate.minute * 6e4;\n } else if(index === 1) {\n selectedTime = date.getTime() + viewDate.hour * 36e5;\n }\n return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1;\n };\n\n scope.$arrowAction = function (value, index) {\n if (options.arrowBehavior === 'picker') {\n $timepicker.$setTimeByStep(value,index);\n } else {\n $timepicker.$moveIndex(value,index);\n }\n };\n\n $timepicker.$setTimeByStep = function(value, index) {\n var newDate = new Date($timepicker.$date);\n var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;\n var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;\n if (index === 0) {\n newDate.setHours(hours - (parseInt(options.hourStep, 10) * value));\n }\n else {\n newDate.setMinutes(minutes - (parseInt(options.minuteStep, 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);\n angular.extend(viewDate, {hour: targetDate.getHours()});\n } else if(index === 1) {\n targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + (value * options.length * options.minuteStep));\n angular.extend(viewDate, {minute: targetDate.getMinutes()});\n }\n $timepicker.$build();\n };\n\n $timepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n if(evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $timepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // Close on enter\n if(evt.keyCode === 13) return $timepicker.hide(true);\n\n // Navigate with keyboard\n var newDate = new Date($timepicker.$date);\n var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;\n var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;\n var lateralMove = /(37|39)/.test(evt.keyCode);\n var count = 2 + 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 if(selectedIndex === 0) {\n if(evt.keyCode === 38) newDate.setHours(hours - parseInt(options.hourStep, 10));\n else if(evt.keyCode === 40) newDate.setHours(hours + 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 if(evt.keyCode === 38) newDate.setMinutes(minutes - parseInt(options.minuteStep, 10));\n else if(evt.keyCode === 40) newDate.setMinutes(minutes + parseInt(options.minuteStep, 10));\n // re-calculate minutes length because we have changes minutes value\n minutesLength = formatDate(newDate, minutesFormat).length;\n selectRange = [hoursLength + 1, hoursLength + 1 + minutesLength];\n } else if(selectedIndex === 2) {\n if(!lateralMove) $timepicker.switchMeridian();\n selectRange = [hoursLength + 1 + minutesLength + 1, hoursLength + 1 + minutesLength + 3];\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, end) {\n if(element[0].createTextRange) {\n var selRange = element[0].createTextRange();\n selRange.collapse(true);\n selRange.moveStart('character', start);\n selRange.moveEnd('character', end);\n selRange.select();\n } else if(element[0].setSelectionRange) {\n element[0].setSelectionRange(start, end);\n } else if(angular.isUndefined(element[0].selectionStart)) {\n element[0].selectionStart = start;\n element[0].selectionEnd = end;\n }\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $timepicker.init;\n $timepicker.init = function() {\n if(isNative && options.useNative) {\n element.prop('type', 'time');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if(isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $timepicker.destroy;\n $timepicker.destroy = function() {\n if(isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $timepicker.show;\n $timepicker.show = function() {\n _show();\n // use timeout to hookup the events to prevent \n // event bubbling from being processed imediately. \n $timeout(function() {\n $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if(options.keyboard) {\n 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.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $timepicker.$onKeyDown);\n }\n _hide(blur);\n };\n\n return $timepicker;\n\n }\n\n timepickerFactory.defaults = defaults;\n return timepickerFactory;\n\n };\n\n })\n\n\n .directive('bsTimepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) {\n\n var defaults = $timepicker.defaults;\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope, controller: controller};\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'timeType', 'timeFormat', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n\n // Initialize parser\n var dateParser = $dateParser({format: options.timeFormat, lang: lang});\n\n // Observe attributes for changes\n angular.forEach(['minTime', 'maxTime'], function(key) {\n // console.warn('attr.$observe(%s)', key, attr[key]);\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\n timepicker.$options[key] = dateParser.getTimeForAttribute(key, newValue);\n !isNaN(timepicker.$options[key]) && timepicker.$build();\n validateAgainstMinMaxTime(controller.$dateValue);\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue, controller.$dateValue);\n timepicker.update(controller.$dateValue);\n }, true);\n\n function validateAgainstMinMaxTime(parsedTime) {\n if (!angular.isDate(parsedTime)) return;\n var isMinValid = isNaN(options.minTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) >= options.minTime;\n var isMaxValid = isNaN(options.maxTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) <= options.maxTime;\n var isValid = isMinValid && isMaxValid;\n controller.$setValidity('date', isValid);\n controller.$setValidity('min', isMinValid);\n controller.$setValidity('max', isMaxValid);\n // Only update the model when we have a valid date\n if(!isValid) {\n return;\n }\n controller.$dateValue = parsedTime;\n }\n\n // viewValue -> $parsers -> modelValue\n controller.$parsers.unshift(function(viewValue) {\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\n // Null values should correctly reset the model value & validity\n if(!viewValue) {\n // BREAKING CHANGE:\n // return null (not undefined) when input value is empty, so angularjs 1.3 \n // ngModelController can go ahead and run validators, like ngRequired\n controller.$setValidity('date', true);\n return null;\n }\n var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue);\n if(!parsedTime || isNaN(parsedTime.getTime())) {\n controller.$setValidity('date', false);\n // return undefined, causes ngModelController to \n // invalidate model value \n return;\n } else {\n validateAgainstMinMaxTime(parsedTime);\n }\n if(options.timeType === 'string') {\n return formatDate(parsedTime, options.modelTimeFormat || options.timeFormat);\n } else if(options.timeType === 'number') {\n return controller.$dateValue.getTime();\n } else if(options.timeType === 'unix') {\n return controller.$dateValue.getTime() / 1000;\n } else if(options.timeType === 'iso') {\n return controller.$dateValue.toISOString();\n } else {\n return new Date(controller.$dateValue);\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 = date;\n return getTimeFormattedString();\n });\n\n // viewValue -> element\n controller.$render = function() {\n // console.warn('$render(\"%s\"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);\n element.val(getTimeFormattedString());\n };\n\n function getTimeFormattedString() {\n return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat);\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (timepicker) timepicker.destroy();\n options = null;\n timepicker = null;\n });\n\n }\n };\n\n });\n"],"sourceRoot":"/source/"} \ No newline at end of file +{"version":3,"sources":["timepicker/timepicker.js"],"names":[],"mappings":"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","file":"timepicker.min.js","sourcesContent":["'use strict';\n\nangular.module('mgcrea.ngStrap.timepicker', [\n 'mgcrea.ngStrap.helpers.dateParser',\n 'mgcrea.ngStrap.helpers.dateFormatter',\n 'mgcrea.ngStrap.tooltip'])\n\n .provider('$timepicker', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'timepicker',\n placement: 'bottom-left',\n template: '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 modelTimeFormat: null,\n autoclose: false,\n minTime: -Infinity,\n maxTime: +Infinity,\n length: 5,\n hourStep: 1,\n minuteStep: 5,\n iconUp: 'glyphicon glyphicon-chevron-up',\n iconDown: 'glyphicon glyphicon-chevron-down',\n arrowBehavior: 'pager'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\n\n function timepickerFactory(element, controller, config) {\n\n var $timepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $timepicker.$options;\n var scope = $timepicker.$scope;\n\n var lang = options.lang;\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n\n // View vars\n\n var selectedIndex = 0;\n var startDate = controller.$dateValue || new Date();\n var viewDate = {hour: startDate.getHours(), meridian: startDate.getHours() < 12, minute: startDate.getMinutes(), second: startDate.getSeconds(), millisecond: startDate.getMilliseconds()};\n\n var format = $dateFormatter.getDatetimeFormat(options.timeFormat, lang);\n\n var hoursFormat = $dateFormatter.hoursFormat(format),\n timeSeparator = $dateFormatter.timeSeparator(format),\n minutesFormat = $dateFormatter.minutesFormat(format),\n showAM = $dateFormatter.showAM(format);\n\n scope.$iconUp = options.iconUp;\n scope.$iconDown = options.iconDown;\n\n // Scope methods\n\n scope.$select = function(date, index) {\n $timepicker.select(date, index);\n };\n scope.$moveIndex = function(value, index) {\n $timepicker.$moveIndex(value, index);\n };\n scope.$switchMeridian = function(date) {\n $timepicker.switchMeridian(date);\n };\n\n // Public methods\n\n $timepicker.update = function(date) {\n // console.warn('$timepicker.update() newValue=%o', date);\n if(angular.isDate(date) && !isNaN(date.getTime())) {\n $timepicker.$date = date;\n angular.extend(viewDate, {hour: date.getHours(), minute: date.getMinutes(), second: date.getSeconds(), millisecond: date.getMilliseconds()});\n $timepicker.$build();\n } else if(!$timepicker.$isBuilt) {\n $timepicker.$build();\n }\n };\n\n $timepicker.select = function(date, index, keep) {\n // console.warn('$timepicker.select', date, scope.$mode);\n if(!controller.$dateValue || isNaN(controller.$dateValue.getTime())) controller.$dateValue = new Date(1970, 0, 1);\n if(!angular.isDate(date)) date = new Date(date);\n if(index === 0) controller.$dateValue.setHours(date.getHours());\n else if(index === 1) controller.$dateValue.setMinutes(date.getMinutes());\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n if(options.autoclose && !keep) {\n $timeout(function() { $timepicker.hide(true); });\n }\n };\n\n $timepicker.switchMeridian = function(date) {\n if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) {\n return;\n }\n var hours = (date || controller.$dateValue).getHours();\n controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12);\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n };\n\n // Protected methods\n\n $timepicker.$build = function() {\n // console.warn('$timepicker.$build() viewDate=%o', viewDate);\n var i, midIndex = scope.midIndex = parseInt(options.length / 2, 10);\n var hours = [], hour;\n for(i = 0; i < options.length; i++) {\n hour = new Date(1970, 0, 1, viewDate.hour - (midIndex - i) * options.hourStep);\n hours.push({date: hour, label: formatDate(hour, hoursFormat), selected: $timepicker.$date && $timepicker.$isSelected(hour, 0), disabled: $timepicker.$isDisabled(hour, 0)});\n }\n var minutes = [], minute;\n for(i = 0; i < options.length; i++) {\n minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep);\n minutes.push({date: minute, label: formatDate(minute, minutesFormat), selected: $timepicker.$date && $timepicker.$isSelected(minute, 1), disabled: $timepicker.$isDisabled(minute, 1)});\n }\n\n var rows = [];\n for(i = 0; i < options.length; i++) {\n rows.push([hours[i], minutes[i]]);\n }\n scope.rows = rows;\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 }\n };\n\n $timepicker.$isDisabled = function(date, index) {\n var selectedTime;\n if(index === 0) {\n selectedTime = date.getTime() + viewDate.minute * 6e4;\n } else if(index === 1) {\n selectedTime = date.getTime() + viewDate.hour * 36e5;\n }\n return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1;\n };\n\n scope.$arrowAction = function (value, index) {\n if (options.arrowBehavior === 'picker') {\n $timepicker.$setTimeByStep(value,index);\n } else {\n $timepicker.$moveIndex(value,index);\n }\n };\n\n $timepicker.$setTimeByStep = function(value, index) {\n var newDate = new Date($timepicker.$date);\n var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;\n var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;\n if (index === 0) {\n newDate.setHours(hours - (parseInt(options.hourStep, 10) * value));\n }\n else {\n newDate.setMinutes(minutes - (parseInt(options.minuteStep, 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);\n angular.extend(viewDate, {hour: targetDate.getHours()});\n } else if(index === 1) {\n targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + (value * options.length * options.minuteStep));\n angular.extend(viewDate, {minute: targetDate.getMinutes()});\n }\n $timepicker.$build();\n };\n\n $timepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n if(evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $timepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // Close on enter\n if(evt.keyCode === 13) return $timepicker.hide(true);\n\n // Navigate with keyboard\n var newDate = new Date($timepicker.$date);\n var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;\n var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;\n var lateralMove = /(37|39)/.test(evt.keyCode);\n var count = 2 + 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 if(selectedIndex === 0) {\n if(evt.keyCode === 38) newDate.setHours(hours - parseInt(options.hourStep, 10));\n else if(evt.keyCode === 40) newDate.setHours(hours + 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 if(evt.keyCode === 38) newDate.setMinutes(minutes - parseInt(options.minuteStep, 10));\n else if(evt.keyCode === 40) newDate.setMinutes(minutes + parseInt(options.minuteStep, 10));\n // re-calculate minutes length because we have changes minutes value\n minutesLength = formatDate(newDate, minutesFormat).length;\n selectRange = [hoursLength + 1, hoursLength + 1 + minutesLength];\n } else if(selectedIndex === 2) {\n if(!lateralMove) $timepicker.switchMeridian();\n selectRange = [hoursLength + 1 + minutesLength + 1, hoursLength + 1 + minutesLength + 3];\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, end) {\n if(element[0].createTextRange) {\n var selRange = element[0].createTextRange();\n selRange.collapse(true);\n selRange.moveStart('character', start);\n selRange.moveEnd('character', end);\n selRange.select();\n } else if(element[0].setSelectionRange) {\n element[0].setSelectionRange(start, end);\n } else if(angular.isUndefined(element[0].selectionStart)) {\n element[0].selectionStart = start;\n element[0].selectionEnd = end;\n }\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $timepicker.init;\n $timepicker.init = function() {\n if(isNative && options.useNative) {\n element.prop('type', 'time');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if(isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $timepicker.destroy;\n $timepicker.destroy = function() {\n if(isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $timepicker.show;\n $timepicker.show = function() {\n _show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if(options.keyboard) {\n 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.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $timepicker.$onKeyDown);\n }\n _hide(blur);\n };\n\n return $timepicker;\n\n }\n\n timepickerFactory.defaults = defaults;\n return timepickerFactory;\n\n };\n\n })\n\n\n .directive('bsTimepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) {\n\n var defaults = $timepicker.defaults;\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope, controller: controller};\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'timeType', 'timeFormat', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n\n // Initialize parser\n var dateParser = $dateParser({format: options.timeFormat, lang: lang});\n\n // Observe attributes for changes\n angular.forEach(['minTime', 'maxTime'], function(key) {\n // console.warn('attr.$observe(%s)', key, attr[key]);\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\n timepicker.$options[key] = dateParser.getTimeForAttribute(key, newValue);\n !isNaN(timepicker.$options[key]) && timepicker.$build();\n validateAgainstMinMaxTime(controller.$dateValue);\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue, controller.$dateValue);\n timepicker.update(controller.$dateValue);\n }, true);\n\n function validateAgainstMinMaxTime(parsedTime) {\n if (!angular.isDate(parsedTime)) return;\n var isMinValid = isNaN(options.minTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) >= options.minTime;\n var isMaxValid = isNaN(options.maxTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) <= options.maxTime;\n var isValid = isMinValid && isMaxValid;\n controller.$setValidity('date', isValid);\n controller.$setValidity('min', isMinValid);\n controller.$setValidity('max', isMaxValid);\n // Only update the model when we have a valid date\n if(!isValid) {\n return;\n }\n controller.$dateValue = parsedTime;\n }\n\n // viewValue -> $parsers -> modelValue\n controller.$parsers.unshift(function(viewValue) {\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\n // Null values should correctly reset the model value & validity\n if(!viewValue) {\n // BREAKING CHANGE:\n // return null (not undefined) when input value is empty, so angularjs 1.3\n // ngModelController can go ahead and run validators, like ngRequired\n controller.$setValidity('date', true);\n return null;\n }\n var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue);\n if(!parsedTime || isNaN(parsedTime.getTime())) {\n controller.$setValidity('date', false);\n // return undefined, causes ngModelController to\n // invalidate model value\n return;\n } else {\n validateAgainstMinMaxTime(parsedTime);\n }\n if(options.timeType === 'string') {\n return formatDate(parsedTime, options.modelTimeFormat || options.timeFormat);\n } else if(options.timeType === 'number') {\n return controller.$dateValue.getTime();\n } else if(options.timeType === 'unix') {\n return controller.$dateValue.getTime() / 1000;\n } else if(options.timeType === 'iso') {\n return controller.$dateValue.toISOString();\n } else {\n return new Date(controller.$dateValue);\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 = date;\n return getTimeFormattedString();\n });\n\n // viewValue -> element\n controller.$render = function() {\n // console.warn('$render(\"%s\"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);\n element.val(getTimeFormattedString());\n };\n\n function getTimeFormattedString() {\n return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat);\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (timepicker) timepicker.destroy();\n options = null;\n timepicker = null;\n });\n\n }\n };\n\n });\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/dist/modules/timepicker.tpl.js b/dist/modules/timepicker.tpl.js index 92ca20e63..acd184fb9 100644 --- a/dist/modules/timepicker.tpl.js +++ b/dist/modules/timepicker.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/timepicker.tpl.min.js b/dist/modules/timepicker.tpl.min.js index 5592318e2..e8e4923f0 100644 --- a/dist/modules/timepicker.tpl.min.js +++ b/dist/modules/timepicker.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/tooltip.js b/dist/modules/tooltip.js index d1ac220a4..5077cc777 100644 --- a/dist/modules/tooltip.js +++ b/dist/modules/tooltip.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -53,6 +53,11 @@ angular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions']) options.delay = split.length > 1 ? {show: split[0], hide: split[1]} : split[0]; } + // store $id to identify the triggering element in events + // give priority to options.id, otherwise, try to use + // element id if defined + $tooltip.$id = options.id || element.attr('id') || ''; + // Support scope as string options if(options.title) { scope.title = $sce.trustAsHtml(options.title); @@ -261,6 +266,7 @@ angular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions']) }; var _blur; + var _tipToHide; $tooltip.hide = function(blur) { if(!$tooltip.$isShown) return; @@ -269,6 +275,10 @@ angular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions']) // store blur value for leaveAnimateCallback to use _blur = blur; + // store current tipElement reference to use + // in leaveAnimateCallback + _tipToHide = tipElement; + // Support v1.3+ $animate // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9 var promise = $animate.leave(tipElement, leaveAnimateCallback); @@ -289,13 +299,18 @@ angular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions']) function leaveAnimateCallback() { scope.$emit(options.prefixEvent + '.hide', $tooltip); - // Allow to blur the input when hidden, like when pressing enter key - if(_blur && options.trigger === 'focus') { - return element[0].blur(); - } - // clean up child scopes - destroyTipElement(); + // check if current tipElement still references + // the same element when hide was called + if (tipElement === _tipToHide) { + // Allow to blur the input when hidden, like when pressing enter key + if(_blur && options.trigger === 'focus') { + return element[0].blur(); + } + + // clean up child scopes + destroyTipElement(); + } } $tooltip.toggle = function() { @@ -611,7 +626,7 @@ angular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions']) // Directive options var options = {scope: scope}; - angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'backdropAnimation', 'type', 'customClass'], function(key) { + angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'backdropAnimation', 'type', 'customClass', 'id'], function(key) { if(angular.isDefined(attr[key])) options[key] = attr[key]; }); diff --git a/dist/modules/tooltip.min.js b/dist/modules/tooltip.min.js index 50742d87d..d266c108a 100644 --- a/dist/modules/tooltip.min.js +++ b/dist/modules/tooltip.min.js @@ -1,9 +1,9 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT */ -"use strict";angular.module("mgcrea.ngStrap.tooltip",["mgcrea.ngStrap.helpers.dimensions"]).provider("$tooltip",function(){var t=this.defaults={animation:"am-fade",customClass:"",prefixClass:"tooltip",prefixEvent:"tooltip",container:!1,target:!1,placement:"top",template:"tooltip/tooltip.tpl.html",contentTemplate:!1,trigger:"hover focus",keyboard:!1,html:!1,show:!1,title:"",type:"",delay:0,autoClose:!1,bsEnabled:!0};this.$get=["$window","$rootScope","$compile","$q","$templateCache","$http","$animate","$sce","dimensions","$$rAF","$timeout",function(e,o,n,i,a,l,r,s,u,c,f){function p(e,i){function a(){K.$emit(O.prefixEvent+".show",F)}function l(){return K.$emit(O.prefixEvent+".hide",F),R&&"focus"===O.trigger?e[0].blur():void P()}function p(){var t=O.trigger.split(" ");angular.forEach(t,function(t){"click"===t?e.on("click",F.toggle):"manual"!==t&&(e.on("hover"===t?"mouseenter":"focus",F.enter),e.on("hover"===t?"mouseleave":"blur",F.leave),"button"===A&&"hover"!==t&&e.on($?"touchstart":"mousedown",F.$onFocusElementMouseDown))})}function v(){for(var t=O.trigger.split(" "),o=t.length;o--;){var n=t[o];"click"===n?e.off("click",F.toggle):"manual"!==n&&(e.off("hover"===n?"mouseenter":"focus",F.enter),e.off("hover"===n?"mouseleave":"blur",F.leave),"button"===A&&"hover"!==n&&e.off($?"touchstart":"mousedown",F.$onFocusElementMouseDown))}}function y(){"focus"!==O.trigger?q.on("keyup",F.$onKeyUp):e.on("keyup",F.$onFocusKeyUp)}function k(){"focus"!==O.trigger?q.off("keyup",F.$onKeyUp):e.off("keyup",F.$onFocusKeyUp)}function S(){f(function(){q.on("click",E),w.on("click",F.hide),W=!0},0,!1)}function C(){W&&(q.off("click",E),w.off("click",F.hide),W=!1)}function E(t){t.stopPropagation()}function x(t){t=t||O.target||e;var o=t[0],n=o.getBoundingClientRect();null===n.width&&(n=angular.extend({},n,{width:n.right-n.left,height:n.bottom-n.top}));var i;return i="body"===O.container?u.offset(o):u.position(o),angular.extend({},n,i)}function D(t,e,o,n){var i,a=t.split("-");switch(a[0]){case"right":i={top:e.top+e.height/2-n/2,left:e.left+e.width};break;case"bottom":i={top:e.top+e.height,left:e.left+e.width/2-o/2};break;case"left":i={top:e.top+e.height/2-n/2,left:e.left-o};break;default:i={top:e.top-n,left:e.left+e.width/2-o/2}}if(!a[1])return i;if("top"===a[0]||"bottom"===a[0])switch(a[1]){case"left":i.left=e.left;break;case"right":i.left=e.left+e.width-o}else if("left"===a[0]||"right"===a[0])switch(a[1]){case"top":i.top=e.top-n;break;case"bottom":i.top=e.top+e.height}return i}function T(t,e){q.css({top:t+"px",left:e+"px"})}function P(){clearTimeout(H),F.$isShown&&null!==q&&(O.autoClose&&C(),O.keyboard&&k()),B&&(B.$destroy(),B=null),q&&(q.remove(),q=F.$element=null)}var F={},A=e[0].nodeName.toLowerCase(),O=F.$options=angular.extend({},t,i);F.$promise=g(O.template);var K=F.$scope=O.scope&&O.scope.$new()||o.$new();if(O.delay&&angular.isString(O.delay)){var U=O.delay.split(",").map(parseFloat);O.delay=U.length>1?{show:U[0],hide:U[1]}:U[0]}O.title&&(K.title=s.trustAsHtml(O.title)),K.$setEnabled=function(t){K.$$postDigest(function(){F.setEnabled(t)})},K.$hide=function(){K.$$postDigest(function(){F.hide()})},K.$show=function(){K.$$postDigest(function(){F.show()})},K.$toggle=function(){K.$$postDigest(function(){F.toggle()})},F.$isShown=K.$isShown=!1;var H,M;O.contentTemplate&&(F.$promise=F.$promise.then(function(t){var e=angular.element(t);return g(O.contentTemplate).then(function(t){var o=d('[ng-bind="content"]',e[0]);return o.length||(o=d('[ng-bind="title"]',e[0])),o.removeAttr("ng-bind").html(t),e[0].outerHTML})}));var j,q,L,N,B;F.$promise.then(function(t){angular.isObject(t)&&(t=t.data),O.html&&(t=t.replace(b,'ng-bind-html="')),t=m.apply(t),L=t,j=n(t),F.init()}),F.init=function(){O.delay&&angular.isNumber(O.delay)&&(O.delay={show:O.delay,hide:O.delay}),"self"===O.container?N=e:angular.isElement(O.container)?N=O.container:O.container&&(N=d(O.container)),p(),O.target&&(O.target=angular.isElement(O.target)?O.target:d(O.target)),O.show&&K.$$postDigest(function(){"focus"===O.trigger?e[0].focus():F.show()})},F.destroy=function(){v(),P(),K.$destroy()},F.enter=function(){return clearTimeout(H),M="in",O.delay&&O.delay.show?void(H=setTimeout(function(){"in"===M&&F.show()},O.delay.show)):F.show()},F.show=function(){if(O.bsEnabled&&!F.$isShown){K.$emit(O.prefixEvent+".show.before",F);var t,o;O.container?(t=N,o=N[0].lastChild?angular.element(N[0].lastChild):null):(t=null,o=e),q&&P(),B=F.$scope.$new(),q=F.$element=j(B,function(){}),q.css({top:"-9999px",left:"-9999px",display:"block",visibility:"hidden"}),O.animation&&q.addClass(O.animation),O.type&&q.addClass(O.prefixClass+"-"+O.type),O.customClass&&q.addClass(O.customClass);var n=r.enter(q,t,o,a);n&&n.then&&n.then(a),F.$isShown=K.$isShown=!0,h(K),c(function(){F.$applyPlacement(),q&&q.css({visibility:"visible"})}),O.keyboard&&("focus"!==O.trigger&&F.focus(),y()),O.autoClose&&S()}},F.leave=function(){return clearTimeout(H),M="out",O.delay&&O.delay.hide?void(H=setTimeout(function(){"out"===M&&F.hide()},O.delay.hide)):F.hide()};var R;F.hide=function(t){if(F.$isShown){K.$emit(O.prefixEvent+".hide.before",F),R=t;var e=r.leave(q,l);e&&e.then&&e.then(l),F.$isShown=K.$isShown=!1,h(K),O.keyboard&&null!==q&&k(),O.autoClose&&null!==q&&C()}},F.toggle=function(){F.$isShown?F.leave():F.enter()},F.focus=function(){q[0].focus()},F.setEnabled=function(t){O.bsEnabled=t},F.$applyPlacement=function(){if(q){var o=O.placement,n=/\s?auto?\s?/i,i=n.test(o);i&&(o=o.replace(n,"")||t.placement),q.addClass(O.placement);var a=x(),l=q.prop("offsetWidth"),r=q.prop("offsetHeight");if(i){var s=o,u=O.container?angular.element(document.querySelector(O.container)):e.parent(),c=x(u);s.indexOf("bottom")>=0&&a.bottom+r>c.bottom?o=s.replace("bottom","top"):s.indexOf("top")>=0&&a.top-rc.width?o="right"===s?"left":o.replace("left","right"):("left"===s||"bottom-right"===s||"top-right"===s)&&a.left-l1?{show:U[0],hide:U[1]}:U[0]}F.$id=O.id||e.attr("id")||"",O.title&&(K.title=s.trustAsHtml(O.title)),K.$setEnabled=function(t){K.$$postDigest(function(){F.setEnabled(t)})},K.$hide=function(){K.$$postDigest(function(){F.hide()})},K.$show=function(){K.$$postDigest(function(){F.show()})},K.$toggle=function(){K.$$postDigest(function(){F.toggle()})},F.$isShown=K.$isShown=!1;var H,M;O.contentTemplate&&(F.$promise=F.$promise.then(function(t){var e=angular.element(t);return g(O.contentTemplate).then(function(t){var n=d('[ng-bind="content"]',e[0]);return n.length||(n=d('[ng-bind="title"]',e[0])),n.removeAttr("ng-bind").html(t),e[0].outerHTML})}));var j,q,L,N,B;F.$promise.then(function(t){angular.isObject(t)&&(t=t.data),O.html&&(t=t.replace(b,'ng-bind-html="')),t=m.apply(t),L=t,j=o(t),F.init()}),F.init=function(){O.delay&&angular.isNumber(O.delay)&&(O.delay={show:O.delay,hide:O.delay}),"self"===O.container?N=e:angular.isElement(O.container)?N=O.container:O.container&&(N=d(O.container)),p(),O.target&&(O.target=angular.isElement(O.target)?O.target:d(O.target)),O.show&&K.$$postDigest(function(){"focus"===O.trigger?e[0].focus():F.show()})},F.destroy=function(){v(),P(),K.$destroy()},F.enter=function(){return clearTimeout(H),M="in",O.delay&&O.delay.show?void(H=setTimeout(function(){"in"===M&&F.show()},O.delay.show)):F.show()},F.show=function(){if(O.bsEnabled&&!F.$isShown){K.$emit(O.prefixEvent+".show.before",F);var t,n;O.container?(t=N,n=N[0].lastChild?angular.element(N[0].lastChild):null):(t=null,n=e),q&&P(),B=F.$scope.$new(),q=F.$element=j(B,function(){}),q.css({top:"-9999px",left:"-9999px",display:"block",visibility:"hidden"}),O.animation&&q.addClass(O.animation),O.type&&q.addClass(O.prefixClass+"-"+O.type),O.customClass&&q.addClass(O.customClass);var o=r.enter(q,t,n,a);o&&o.then&&o.then(a),F.$isShown=K.$isShown=!0,h(K),c(function(){F.$applyPlacement(),q&&q.css({visibility:"visible"})}),O.keyboard&&("focus"!==O.trigger&&F.focus(),y()),O.autoClose&&S()}},F.leave=function(){return clearTimeout(H),M="out",O.delay&&O.delay.hide?void(H=setTimeout(function(){"out"===M&&F.hide()},O.delay.hide)):F.hide()};var R,W;F.hide=function(t){if(F.$isShown){K.$emit(O.prefixEvent+".hide.before",F),R=t,W=q;var e=r.leave(q,l);e&&e.then&&e.then(l),F.$isShown=K.$isShown=!1,h(K),O.keyboard&&null!==q&&k(),O.autoClose&&null!==q&&C()}},F.toggle=function(){F.$isShown?F.leave():F.enter()},F.focus=function(){q[0].focus()},F.setEnabled=function(t){O.bsEnabled=t},F.$applyPlacement=function(){if(q){var n=O.placement,o=/\s?auto?\s?/i,i=o.test(n);i&&(n=n.replace(o,"")||t.placement),q.addClass(O.placement);var a=x(),l=q.prop("offsetWidth"),r=q.prop("offsetHeight");if(i){var s=n,u=O.container?angular.element(document.querySelector(O.container)):e.parent(),c=x(u);s.indexOf("bottom")>=0&&a.bottom+r>c.bottom?n=s.replace("bottom","top"):s.indexOf("top")>=0&&a.top-rc.width?n="right"===s?"left":n.replace("left","right"):("left"===s||"bottom-right"===s||"top-right"===s)&&a.left-l 1 ? {show: split[0], hide: split[1]} : split[0];\n }\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 // Support contentTemplate option\n if(options.contentTemplate) {\n $tooltip.$promise = $tooltip.$promise.then(function(template) {\n var templateEl = angular.element(template);\n return fetchTemplate(options.contentTemplate)\n .then(function(contentTemplate) {\n var contentEl = findElement('[ng-bind=\"content\"]', templateEl[0]);\n if(!contentEl.length) contentEl = findElement('[ng-bind=\"title\"]', templateEl[0]);\n contentEl.removeAttr('ng-bind').html(contentTemplate);\n return templateEl[0].outerHTML;\n });\n });\n }\n\n // Fetch, compile then initialize tooltip\n var tipLinker, tipElement, tipTemplate, tipContainer, tipScope;\n $tooltip.$promise.then(function(template) {\n if(angular.isObject(template)) template = template.data;\n if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html=\"');\n template = trim.apply(template);\n tipTemplate = template;\n tipLinker = $compile(template);\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 = tipLinker(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', 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 // Support v1.3+ $animate\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\n var promise = $animate.enter(tipElement, parent, after, enterAnimateCallback);\n if(promise && promise.then) promise.then(enterAnimateCallback);\n\n $tooltip.$isShown = scope.$isShown = true;\n safeDigest(scope);\n $$rAF(function () {\n $tooltip.$applyPlacement();\n\n // Once placed, make the tooltip visible\n if(tipElement) tipElement.css({visibility: 'visible'});\n }); // var a = bodyEl.offsetWidth + 1; ?\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 $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 // Support v1.3+ $animate\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\n var promise = $animate.leave(tipElement, leaveAnimateCallback);\n if(promise && promise.then) promise.then(leaveAnimateCallback);\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 // 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 $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 // Protected methods\n\n $tooltip.$applyPlacement = function() {\n if(!tipElement) return;\n\n // Determine if we're doing an auto or normal placement\n var placement = options.placement,\n autoToken = /\\s?auto?\\s?/i,\n autoPlace = autoToken.test(placement);\n\n if (autoPlace) {\n placement = placement.replace(autoToken, '') || defaults.placement;\n }\n\n // Need to add the position class before we get\n // the offsets\n tipElement.addClass(options.placement);\n\n // Get the position of the target element\n // and the height and width of the tooltip so we can center it.\n var elementPosition = getPosition(),\n tipWidth = tipElement.prop('offsetWidth'),\n tipHeight = tipElement.prop('offsetHeight');\n\n // If we're auto placing, we need to check the positioning\n if (autoPlace) {\n var originalPlacement = placement;\n var container = options.container ? angular.element(document.querySelector(options.container)) : element.parent();\n var containerPosition = getPosition(container);\n\n // Determine if the vertical placement\n if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > containerPosition.bottom) {\n placement = originalPlacement.replace('bottom', 'top');\n } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < containerPosition.top) {\n placement = originalPlacement.replace('top', 'bottom');\n }\n\n // Determine the horizontal placement\n // The exotic placements of left and right are opposite of the standard placements. Their arrows are put on the left/right\n // and flow in the opposite direction of their placement.\n if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') &&\n elementPosition.right + tipWidth > containerPosition.width) {\n\n placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right');\n } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') &&\n elementPosition.left - tipWidth < containerPosition.left) {\n\n placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left');\n }\n\n tipElement.removeClass(originalPlacement).addClass(placement);\n }\n\n // Get the tooltip's top and left coordinates to center it with this directive.\n var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight);\n applyPlacementCss(tipPosition.top, tipPosition.left);\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\n var elRect = el.getBoundingClientRect();\n if (elRect.width === null) {\n // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093\n elRect = angular.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top });\n }\n\n var elPos;\n if (options.container === 'body') {\n elPos = dimensions.offset(el);\n } else {\n elPos = dimensions.position(el);\n }\n\n return angular.extend({}, elRect, elPos);\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 applyPlacementCss(top, left) {\n tipElement.css({ top: top + 'px', left: left + 'px' });\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] = $q.when($templateCache.get(template) || $http.get(template))\n .then(function(res) {\n if(angular.isObject(res)) {\n $templateCache.put(template, res.data);\n return res.data;\n }\n return res;\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', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'backdropAnimation', 'type', 'customClass'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 // 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":["tooltip/tooltip.js"],"names":[],"mappings":"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","file":"tooltip.min.js","sourcesContent":["'use strict';\n\nangular.module('mgcrea.ngStrap.tooltip', ['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 template: 'tooltip/tooltip.tpl.html',\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 };\n\n this.$get = function($window, $rootScope, $compile, $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 nodeName = element[0].nodeName.toLowerCase();\n var options = $tooltip.$options = angular.extend({}, defaults, config);\n $tooltip.$promise = fetchTemplate(options.template);\n var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new();\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 // Support contentTemplate option\n if(options.contentTemplate) {\n $tooltip.$promise = $tooltip.$promise.then(function(template) {\n var templateEl = angular.element(template);\n return fetchTemplate(options.contentTemplate)\n .then(function(contentTemplate) {\n var contentEl = findElement('[ng-bind=\"content\"]', templateEl[0]);\n if(!contentEl.length) contentEl = findElement('[ng-bind=\"title\"]', templateEl[0]);\n contentEl.removeAttr('ng-bind').html(contentTemplate);\n return templateEl[0].outerHTML;\n });\n });\n }\n\n // Fetch, compile then initialize tooltip\n var tipLinker, tipElement, tipTemplate, tipContainer, tipScope;\n $tooltip.$promise.then(function(template) {\n if(angular.isObject(template)) template = template.data;\n if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html=\"');\n template = trim.apply(template);\n tipTemplate = template;\n tipLinker = $compile(template);\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 = tipLinker(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', 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 // Support v1.3+ $animate\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\n var promise = $animate.enter(tipElement, parent, after, enterAnimateCallback);\n if(promise && promise.then) promise.then(enterAnimateCallback);\n\n $tooltip.$isShown = scope.$isShown = true;\n safeDigest(scope);\n $$rAF(function () {\n $tooltip.$applyPlacement();\n\n // Once placed, make the tooltip visible\n if(tipElement) tipElement.css({visibility: 'visible'});\n }); // var a = bodyEl.offsetWidth + 1; ?\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.3+ $animate\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\n var promise = $animate.leave(tipElement, leaveAnimateCallback);\n if(promise && promise.then) promise.then(leaveAnimateCallback);\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 // Protected methods\n\n $tooltip.$applyPlacement = function() {\n if(!tipElement) return;\n\n // Determine if we're doing an auto or normal placement\n var placement = options.placement,\n autoToken = /\\s?auto?\\s?/i,\n autoPlace = autoToken.test(placement);\n\n if (autoPlace) {\n placement = placement.replace(autoToken, '') || defaults.placement;\n }\n\n // Need to add the position class before we get\n // the offsets\n tipElement.addClass(options.placement);\n\n // Get the position of the target element\n // and the height and width of the tooltip so we can center it.\n var elementPosition = getPosition(),\n tipWidth = tipElement.prop('offsetWidth'),\n tipHeight = tipElement.prop('offsetHeight');\n\n // If we're auto placing, we need to check the positioning\n if (autoPlace) {\n var originalPlacement = placement;\n var container = options.container ? angular.element(document.querySelector(options.container)) : element.parent();\n var containerPosition = getPosition(container);\n\n // Determine if the vertical placement\n if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > containerPosition.bottom) {\n placement = originalPlacement.replace('bottom', 'top');\n } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < containerPosition.top) {\n placement = originalPlacement.replace('top', 'bottom');\n }\n\n // Determine the horizontal placement\n // The exotic placements of left and right are opposite of the standard placements. Their arrows are put on the left/right\n // and flow in the opposite direction of their placement.\n if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') &&\n elementPosition.right + tipWidth > containerPosition.width) {\n\n placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right');\n } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') &&\n elementPosition.left - tipWidth < containerPosition.left) {\n\n placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left');\n }\n\n tipElement.removeClass(originalPlacement).addClass(placement);\n }\n\n // Get the tooltip's top and left coordinates to center it with this directive.\n var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight);\n applyPlacementCss(tipPosition.top, tipPosition.left);\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\n var elRect = el.getBoundingClientRect();\n if (elRect.width === null) {\n // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093\n elRect = angular.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top });\n }\n\n var elPos;\n if (options.container === 'body') {\n elPos = dimensions.offset(el);\n } else {\n elPos = dimensions.position(el);\n }\n\n return angular.extend({}, elRect, elPos);\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 applyPlacementCss(top, left) {\n tipElement.css({ top: top + 'px', left: left + 'px' });\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] = $q.when($templateCache.get(template) || $http.get(template))\n .then(function(res) {\n if(angular.isObject(res)) {\n $templateCache.put(template, res.data);\n return res.data;\n }\n return res;\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', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'backdropAnimation', 'type', 'customClass', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\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 // Initialize popover\n var tooltip = $tooltip(element, options);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if(tooltip) tooltip.destroy();\n options = null;\n tooltip = null;\n });\n\n }\n };\n\n });\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/dist/modules/tooltip.tpl.js b/dist/modules/tooltip.tpl.js index 5df7c7009..6417c1d45 100644 --- a/dist/modules/tooltip.tpl.js +++ b/dist/modules/tooltip.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/tooltip.tpl.min.js b/dist/modules/tooltip.tpl.min.js index f11bdd674..95efef67d 100644 --- a/dist/modules/tooltip.tpl.min.js +++ b/dist/modules/tooltip.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/typeahead.js b/dist/modules/typeahead.js index 5b702a9aa..38a6f25b4 100644 --- a/dist/modules/typeahead.js +++ b/dist/modules/typeahead.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT @@ -86,7 +86,7 @@ angular.module('mgcrea.ngStrap.typeahead', ['mgcrea.ngStrap.tooltip', 'mgcrea.ng scope.$resetMatches(); if(parentScope) parentScope.$digest(); // Emit event - scope.$emit(options.prefixEvent + '.select', value, index); + scope.$emit(options.prefixEvent + '.select', value, index, $typeahead); }; // Protected methods @@ -182,7 +182,7 @@ angular.module('mgcrea.ngStrap.typeahead', ['mgcrea.ngStrap.tooltip', 'mgcrea.ng // Directive options var options = {scope: scope}; - angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'filter', 'limit', 'minLength', 'watchOptions', 'selectMode', 'comparator'], function(key) { + angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'filter', 'limit', 'minLength', 'watchOptions', 'selectMode', 'comparator', 'id'], function(key) { if(angular.isDefined(attr[key])) options[key] = attr[key]; }); diff --git a/dist/modules/typeahead.min.js b/dist/modules/typeahead.min.js index b93863687..d26dfb018 100644 --- a/dist/modules/typeahead.min.js +++ b/dist/modules/typeahead.min.js @@ -1,9 +1,9 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT */ -"use strict";angular.module("mgcrea.ngStrap.typeahead",["mgcrea.ngStrap.tooltip","mgcrea.ngStrap.helpers.parseOptions"]).provider("$typeahead",function(){var e=this.defaults={animation:"am-fade",prefixClass:"typeahead",prefixEvent:"$typeahead",placement:"bottom-left",template:"typeahead/typeahead.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,minLength:1,filter:"filter",limit:6,comparator:""};this.$get=["$window","$rootScope","$tooltip","$timeout",function(t,n,a,i){function o(t,n,o){var r={},l=angular.extend({},e,o);r=a(t,l);var c=o.scope,s=r.$scope;s.$resetMatches=function(){s.$matches=[],s.$activeIndex=0},s.$resetMatches(),s.$activate=function(e){s.$$postDigest(function(){r.activate(e)})},s.$select=function(e){s.$$postDigest(function(){r.select(e)})},s.$isVisible=function(){return r.$isVisible()},r.update=function(e){s.$matches=e,s.$activeIndex>=e.length&&(s.$activeIndex=0)},r.activate=function(e){s.$activeIndex=e},r.select=function(e){var t=s.$matches[e].value;n.$setViewValue(t),n.$render(),s.$resetMatches(),c&&c.$digest(),s.$emit(l.prefixEvent+".select",t,e)},r.$isVisible=function(){return l.minLength&&n?s.$matches.length&&angular.isString(n.$viewValue)&&n.$viewValue.length>=l.minLength:!!s.$matches.length},r.$getIndex=function(e){var t=s.$matches.length,n=t;if(t){for(n=t;n--&&s.$matches[n].value!==e;);if(!(0>n))return n}},r.$onMouseDown=function(e){e.preventDefault(),e.stopPropagation()},r.$onKeyDown=function(e){/(38|40|13)/.test(e.keyCode)&&(r.$isVisible()&&(e.preventDefault(),e.stopPropagation()),13===e.keyCode&&s.$matches.length?r.select(s.$activeIndex):38===e.keyCode&&s.$activeIndex>0?s.$activeIndex--:40===e.keyCode&&s.$activeIndex0)return void r.$setViewValue(r.$viewValue.substring(0,r.$viewValue.length-1));e.length>s&&(e=e.slice(0,s));var n=f.$isVisible();n&&f.update(e),(1!==e.length||e[0].value!==t)&&(!n&&f.update(e),r.$render())})}),r.$formatters.push(function(e){var t=d.displayValue(e);return void 0===t?"":t}),r.$render=function(){if(r.$isEmpty(r.$viewValue))return t.val("");var e=f.$getIndex(r.$modelValue),n=angular.isDefined(e)?f.$scope.$matches[e].label:r.$viewValue;n=angular.isObject(n)?d.displayValue(n):n,t.val(n?n.toString().replace(/<(?:.|\n)*?>/gm,"").trim():"")},e.$on("$destroy",function(){f&&f.destroy(),l=null,f=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",template:"typeahead/typeahead.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,minLength:1,filter:"filter",limit:6,comparator:""};this.$get=["$window","$rootScope","$tooltip","$timeout",function(t,n,a,i){function o(t,n,o){var r={},l=angular.extend({},e,o);r=a(t,l);var c=o.scope,s=r.$scope;s.$resetMatches=function(){s.$matches=[],s.$activeIndex=0},s.$resetMatches(),s.$activate=function(e){s.$$postDigest(function(){r.activate(e)})},s.$select=function(e){s.$$postDigest(function(){r.select(e)})},s.$isVisible=function(){return r.$isVisible()},r.update=function(e){s.$matches=e,s.$activeIndex>=e.length&&(s.$activeIndex=0)},r.activate=function(e){s.$activeIndex=e},r.select=function(e){var t=s.$matches[e].value;n.$setViewValue(t),n.$render(),s.$resetMatches(),c&&c.$digest(),s.$emit(l.prefixEvent+".select",t,e,r)},r.$isVisible=function(){return l.minLength&&n?s.$matches.length&&angular.isString(n.$viewValue)&&n.$viewValue.length>=l.minLength:!!s.$matches.length},r.$getIndex=function(e){var t=s.$matches.length,n=t;if(t){for(n=t;n--&&s.$matches[n].value!==e;);if(!(0>n))return n}},r.$onMouseDown=function(e){e.preventDefault(),e.stopPropagation()},r.$onKeyDown=function(e){/(38|40|13)/.test(e.keyCode)&&(r.$isVisible()&&(e.preventDefault(),e.stopPropagation()),13===e.keyCode&&s.$matches.length?r.select(s.$activeIndex):38===e.keyCode&&s.$activeIndex>0?s.$activeIndex--:40===e.keyCode&&s.$activeIndex0)return void r.$setViewValue(r.$viewValue.substring(0,r.$viewValue.length-1));e.length>s&&(e=e.slice(0,s));var n=f.$isVisible();n&&f.update(e),(1!==e.length||e[0].value!==t)&&(!n&&f.update(e),r.$render())})}),r.$formatters.push(function(e){var t=d.displayValue(e);return void 0===t?"":t}),r.$render=function(){if(r.$isEmpty(r.$viewValue))return t.val("");var e=f.$getIndex(r.$modelValue),n=angular.isDefined(e)?f.$scope.$matches[e].label:r.$viewValue;n=angular.isObject(n)?d.displayValue(n):n,t.val(n?n.toString().replace(/<(?:.|\n)*?>/gm,"").trim():"")},e.$on("$destroy",function(){f&&f.destroy(),l=null,f=null})}}}]); //# sourceMappingURL=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 95e2fc864..c57ed0593 100644 --- a/dist/modules/typeahead.min.js.map +++ b/dist/modules/typeahead.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["typeahead/typeahead.js"],"names":[],"mappings":"qBASM,OAAA,4BAAa,yBAAA,iDAEb,aAAU,cAEV,GAAW,KAAA,UACX,UAAU,UACV,YAAM,YACN,YAAO,aACP,UAAW,cACX,SAAQ,+BACR,QAAO,QACP,WAAA,sBAGF,MAAK,cAEH,OAAI,iBAEJ,WAAS,sFAOP,GAAsB,EAAS,EAAA,GAE/B,GAAI,MAGF,EAAM,QAAW,UAAA,EAAA,WAGnB,IAAA,GAAM,EAAA,mBAGJ,cAAmB,aACjB,kDAKF,UAAM,SAAa,KACjB,aAAW,8BAKb,QAAO,SAAW,8CAMlB,WAAiB,WACjB,MAAG,GAAM,cAKX,EAAW,OAAA,SAAW,GACpB,EAAM,SAAA,kDAMN,SAAW,SAAc,GACzB,EAAA,aAAW,wBAIX,GAAA,GAAY,EAAA,SAAQ,GAAc,uDAKpC,GAAW,EAAa,YAEpB,MAAS,EAAM,YAAS,UAAA,EAAA,4BAM5B,MAAA,GAAW,WAAY,EAIhB,EAAM,SAAS,QAAG,QAAiB,SAAA,EAAA,aAAA,EAAA,WAAA,QAAA,EAAA,YAHhC,EAAM,SAAS,UAMhB,UAAA,SAAA,qCAGT,IAAA,EAAA,EAAW,+BAGT,KAAI,EAAJ,gBAII,aAAkB,SAAI,sBAG1B,EAAG,2EAOD,EAAW,uDAMG,OAAX,SAAW,EAAY,SAAM,OAClC,EAAM,OAAA,EAAA,gEAKc,KAAlB,EAAO,SAAW,EAAA,aAAA,EAAA,SAAA,OAAA,EAAA,EAAA,eACtB,QAAkB,YAAW,EAAA,gBAAA,EAAA,aAAA,GAC3B,EAAA,eAKE,GAAG,EAAQ,OACT,KAAW,4BAKb,EAAO,SAAW,GAAA,YAAA,EAAA,cACtB,EAAW,UACT,EAAW,GAAA,UAAa,EAAa,aAEnC,GAAA,0CAKJ,EAAO,SAAA,IAAA,YAAA,EAAA,wDAIT,OA/HM,QAAU,QAAQ,EAAW,SAAU,YAsIhD,GAAU,SAAA,kBAOD,eAAS,UAAgB,SAAS,KAAM,aAAY,gBAAA,SAAA,EAAA,EAAA,EAAA,EAAA,oCAKnD,+CAKL,GAAI,IAAQ,MAAQ,EACpB,SAAI,SAAa,YAAQ,YAAc,QAAS,UAAA,WAAA,OAAA,YAAA,WAAA,SAAA,QAAA,YAAA,eAAA,aAAA,cAAA,SAAA,yCAKhD,IAAG,GAAO,EAAA,QAAa,EAAgB,OACnC,EAAA,EAAgB,OAAA,EAAc,mCAG9B,EAAY,EAAA,sDAGb,IAAA,GAAQ,cAAc,8BAOnB,aAAW,IAEZ,GAAA,EAAA,OAAA,GAAA,QAAA,OAAA,IAAA,QAAA,UAAA,IAAA,8DAIC,EAAO,OAAK,mBAGhB,KAIE,OAAG,EAAQ,QAAA,SAAe,KAExB,YAAA,uBAEC,SAAO,0CAKT,WADD,GAAU,cAAgB,EAAU,WAAU,UAAU,EAAA,EAAA,WAAA,OAAA,GAGxD,GAAA,OAAW,IAAA,EAAA,EAAA,MAAA,EAAA,0EAKf,GAAW,EAAiB,OAAA,GAE1B,EAAI,eAKN,EAAW,YAAU,KAAA,SAAY,GAE/B,GAAG,GAAW,EAAS,aAAW,EAClC,OAAsB,UAAlB,EAA4B,GAAA,qEAOlC,IAAM,GAAI,EAAY,UAAW,EAAA,aAC3B,EAAW,QAAA,UAAU,GAAA,EAAA,OAAA,SAAA,GAAA,MAAA,EAAA,UACzB,GAAU,QAAA,SAAA,GAAA,EAAA,aAAA,GAAA,EACV,EAAA,IAAY,EAAA,EAAA,WAAA,QAAA,iBAAA,IAAA,OAAA,gDAMjB,EAAA","file":"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 template: 'typeahead/typeahead.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n minLength: 1,\n filter: 'filter',\n limit: 6,\n comparator: ''\n };\n\n this.$get = function($window, $rootScope, $tooltip, $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 = 0;\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 = 0;\n }\n };\n\n $typeahead.activate = function(index) {\n scope.$activeIndex = index;\n };\n\n $typeahead.select = function(index) {\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);\n };\n\n // Protected methods\n\n $typeahead.$isVisible = function() {\n if(!options.minLength || !controller) {\n return !!scope.$matches.length;\n }\n // minLength support\n return scope.$matches.length && angular.isString(controller.$viewValue) && controller.$viewValue.length >= options.minLength;\n };\n\n $typeahead.$getIndex = function(value) {\n var l = scope.$matches.length, i = l;\n if(!l) return;\n for(i = l; i--;) {\n if(scope.$matches[i].value === value) break;\n }\n if(i < 0) return;\n return i;\n };\n\n $typeahead.$onMouseDown = function(evt) {\n // Prevent blur on mousedown\n evt.preventDefault();\n evt.stopPropagation();\n };\n\n $typeahead.$onKeyDown = function(evt) {\n if(!/(38|40|13)/.test(evt.keyCode)) return;\n\n // Let ngSubmit pass if the typeahead tip is hidden\n if($typeahead.$isVisible()) {\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 imediately.\n $timeout(function() {\n $typeahead.$element.on('mousedown', $typeahead.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $typeahead.$onKeyDown);\n }\n }, 0, false);\n };\n\n var hide = $typeahead.hide;\n $typeahead.hide = function() {\n $typeahead.$element.off('mousedown', $typeahead.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $typeahead.$onKeyDown);\n }\n hide();\n };\n\n return $typeahead;\n\n }\n\n TypeaheadFactory.defaults = defaults;\n return TypeaheadFactory;\n\n };\n\n })\n\n .directive('bsTypeahead', function($window, $parse, $q, $typeahead, $parseOptions) {\n\n var defaults = $typeahead.defaults;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'filter', 'limit', 'minLength', 'watchOptions', 'selectMode', 'comparator'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Build proper ngOptions\n var filter = options.filter || defaults.filter;\n var limit = options.limit || defaults.limit;\n var comparator = options.comparator || defaults.comparator;\n\n var ngOptions = attr.ngOptions;\n if(filter) ngOptions += ' | ' + filter + ':$viewValue';\n if (comparator) ngOptions += ':' + comparator;\n if(limit) ngOptions += ' | limitTo:' + limit;\n var parsedOptions = $parseOptions(ngOptions);\n\n // Initialize typeahead\n var typeahead = $typeahead(element, controller, options);\n\n // Watch options on demand\n if(options.watchOptions) {\n // Watch ngOptions values before filtering for changes, drop function calls\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').replace(/\\(.*\\)/g, '').trim();\n scope.$watch(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 }, true);\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 return displayValue === undefined ? '' : displayValue;\n });\n\n // Model rendering in view\n controller.$render = function () {\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n if(controller.$isEmpty(controller.$viewValue)) return element.val('');\n var index = typeahead.$getIndex(controller.$modelValue);\n var selected = angular.isDefined(index) ? typeahead.$scope.$matches[index].label : controller.$viewValue;\n selected = angular.isObject(selected) ? parsedOptions.displayValue(selected) : selected;\n element.val(selected ? selected.toString().replace(/<(?:.|\\n)*?>/gm, '').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":["typeahead/typeahead.js"],"names":[],"mappings":"qBASM,OAAA,4BAAa,yBAAA,iDAEb,aAAU,cAEV,GAAW,KAAA,UACX,UAAU,UACV,YAAM,YACN,YAAO,aACP,UAAW,cACX,SAAQ,+BACR,QAAO,QACP,WAAA,sBAGF,MAAK,cAEH,OAAI,iBAEJ,WAAS,sFAOP,GAAsB,EAAS,EAAA,GAE/B,GAAI,MAGF,EAAM,QAAW,UAAA,EAAA,WAGnB,IAAA,GAAM,EAAA,mBAGJ,cAAmB,aACjB,kDAKF,UAAM,SAAa,KACjB,aAAW,8BAKb,QAAO,SAAW,8CAMlB,WAAiB,WACjB,MAAG,GAAM,cAKX,EAAW,OAAA,SAAW,GACpB,EAAM,SAAA,kDAMN,SAAW,SAAc,GACzB,EAAA,aAAW,wBAIX,GAAA,GAAY,EAAA,SAAQ,GAAc,uDAKpC,GAAW,EAAa,YAEpB,MAAS,EAAM,YAAS,UAAA,EAAA,EAAA,4BAM5B,MAAA,GAAW,WAAY,EAIhB,EAAM,SAAS,QAAG,QAAiB,SAAA,EAAA,aAAA,EAAA,WAAA,QAAA,EAAA,YAHhC,EAAM,SAAS,UAMhB,UAAA,SAAA,qCAGT,IAAA,EAAA,EAAW,+BAGT,KAAI,EAAJ,gBAII,aAAkB,SAAI,sBAG1B,EAAG,2EAOD,EAAW,uDAMG,OAAX,SAAW,EAAY,SAAM,OAClC,EAAM,OAAA,EAAA,gEAKc,KAAlB,EAAO,SAAW,EAAA,aAAA,EAAA,SAAA,OAAA,EAAA,EAAA,eACtB,QAAkB,YAAW,EAAA,gBAAA,EAAA,aAAA,GAC3B,EAAA,eAKE,GAAG,EAAQ,OACT,KAAW,4BAKb,EAAO,SAAW,GAAA,YAAA,EAAA,cACtB,EAAW,UACT,EAAW,GAAA,UAAa,EAAa,aAEnC,GAAA,0CAKJ,EAAO,SAAA,IAAA,YAAA,EAAA,wDAIT,OA/HM,QAAU,QAAQ,EAAW,SAAU,YAsIhD,GAAU,SAAA,kBAOD,eAAS,UAAgB,SAAS,KAAM,aAAY,gBAAA,SAAA,EAAA,EAAA,EAAA,EAAA,oCAKnD,+CAKL,GAAI,IAAQ,MAAQ,EACpB,SAAI,SAAa,YAAQ,YAAc,QAAS,UAAA,WAAA,OAAA,YAAA,WAAA,SAAA,QAAA,YAAA,eAAA,aAAA,aAAA,MAAA,SAAA,yCAKhD,IAAG,GAAO,EAAA,QAAa,EAAgB,OACnC,EAAA,EAAgB,OAAA,EAAc,mCAG9B,EAAY,EAAA,sDAGb,IAAA,GAAQ,cAAc,8BAOnB,aAAW,IAEZ,GAAA,EAAA,OAAA,GAAA,QAAA,OAAA,IAAA,QAAA,UAAA,IAAA,8DAIC,EAAO,OAAK,mBAGhB,KAIE,OAAG,EAAQ,QAAA,SAAe,KAExB,YAAA,uBAEC,SAAO,0CAKT,WADD,GAAU,cAAgB,EAAU,WAAU,UAAU,EAAA,EAAA,WAAA,OAAA,GAGxD,GAAA,OAAW,IAAA,EAAA,EAAA,MAAA,EAAA,0EAKf,GAAW,EAAiB,OAAA,GAE1B,EAAI,eAKN,EAAW,YAAU,KAAA,SAAY,GAE/B,GAAG,GAAW,EAAS,aAAW,EAClC,OAAsB,UAAlB,EAA4B,GAAA,qEAOlC,IAAM,GAAI,EAAY,UAAW,EAAA,aAC3B,EAAW,QAAA,UAAU,GAAA,EAAA,OAAA,SAAA,GAAA,MAAA,EAAA,UACzB,GAAU,QAAA,SAAA,GAAA,EAAA,aAAA,GAAA,EACV,EAAA,IAAY,EAAA,EAAA,WAAA,QAAA,iBAAA,IAAA,OAAA,gDAMjB,EAAA","file":"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 template: 'typeahead/typeahead.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n minLength: 1,\n filter: 'filter',\n limit: 6,\n comparator: ''\n };\n\n this.$get = function($window, $rootScope, $tooltip, $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 = 0;\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 = 0;\n }\n };\n\n $typeahead.activate = function(index) {\n scope.$activeIndex = index;\n };\n\n $typeahead.select = function(index) {\n var value = scope.$matches[index].value;\n // console.log('$setViewValue', value);\n controller.$setViewValue(value);\n controller.$render();\n scope.$resetMatches();\n if(parentScope) parentScope.$digest();\n // Emit event\n scope.$emit(options.prefixEvent + '.select', value, index, $typeahead);\n };\n\n // Protected methods\n\n $typeahead.$isVisible = function() {\n if(!options.minLength || !controller) {\n return !!scope.$matches.length;\n }\n // minLength support\n return scope.$matches.length && angular.isString(controller.$viewValue) && controller.$viewValue.length >= options.minLength;\n };\n\n $typeahead.$getIndex = function(value) {\n var l = scope.$matches.length, i = l;\n if(!l) return;\n for(i = l; i--;) {\n if(scope.$matches[i].value === value) break;\n }\n if(i < 0) return;\n return i;\n };\n\n $typeahead.$onMouseDown = function(evt) {\n // Prevent blur on mousedown\n evt.preventDefault();\n evt.stopPropagation();\n };\n\n $typeahead.$onKeyDown = function(evt) {\n if(!/(38|40|13)/.test(evt.keyCode)) return;\n\n // Let ngSubmit pass if the typeahead tip is hidden\n if($typeahead.$isVisible()) {\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 imediately.\n $timeout(function() {\n $typeahead.$element.on('mousedown', $typeahead.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $typeahead.$onKeyDown);\n }\n }, 0, false);\n };\n\n var hide = $typeahead.hide;\n $typeahead.hide = function() {\n $typeahead.$element.off('mousedown', $typeahead.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $typeahead.$onKeyDown);\n }\n hide();\n };\n\n return $typeahead;\n\n }\n\n TypeaheadFactory.defaults = defaults;\n return TypeaheadFactory;\n\n };\n\n })\n\n .directive('bsTypeahead', function($window, $parse, $q, $typeahead, $parseOptions) {\n\n var defaults = $typeahead.defaults;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'filter', 'limit', 'minLength', 'watchOptions', 'selectMode', 'comparator', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Build proper ngOptions\n var filter = options.filter || defaults.filter;\n var limit = options.limit || defaults.limit;\n var comparator = options.comparator || defaults.comparator;\n\n var ngOptions = attr.ngOptions;\n if(filter) ngOptions += ' | ' + filter + ':$viewValue';\n if (comparator) ngOptions += ':' + comparator;\n if(limit) ngOptions += ' | limitTo:' + limit;\n var parsedOptions = $parseOptions(ngOptions);\n\n // Initialize typeahead\n var typeahead = $typeahead(element, controller, options);\n\n // Watch options on demand\n if(options.watchOptions) {\n // Watch ngOptions values before filtering for changes, drop function calls\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').replace(/\\(.*\\)/g, '').trim();\n scope.$watch(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 }, true);\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 return displayValue === undefined ? '' : displayValue;\n });\n\n // Model rendering in view\n controller.$render = function () {\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n if(controller.$isEmpty(controller.$viewValue)) return element.val('');\n var index = typeahead.$getIndex(controller.$modelValue);\n var selected = angular.isDefined(index) ? typeahead.$scope.$matches[index].label : controller.$viewValue;\n selected = angular.isObject(selected) ? parsedOptions.displayValue(selected) : selected;\n element.val(selected ? selected.toString().replace(/<(?:.|\\n)*?>/gm, '').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 dda2e1f27..e92645dea 100644 --- a/dist/modules/typeahead.tpl.js +++ b/dist/modules/typeahead.tpl.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/dist/modules/typeahead.tpl.min.js b/dist/modules/typeahead.tpl.min.js index a724bddac..9d8b4544c 100644 --- a/dist/modules/typeahead.tpl.min.js +++ b/dist/modules/typeahead.tpl.min.js @@ -1,6 +1,6 @@ /** * angular-strap - * @version v2.1.5 - 2014-12-23 + * @version v2.1.6 - 2015-01-11 * @link http://mgcrea.github.io/angular-strap * @author Olivier Louvignes (olivier@mg-crea.com) * @license MIT License, http://www.opensource.org/licenses/MIT diff --git a/package.json b/package.json index 3a21a5dd7..8aa80796e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "angular-strap", "description": "AngularStrap - AngularJS directives for Bootstrap", - "version": "2.1.5", + "version": "2.1.6", "keywords": [ "angular", "bootstrap"