source: cats/SCHEMAcat/trunk/urn.org.isocat.schemacat.site/site/lib/UI-bootstrap/ui-bootstrap-tpls-0.7.0.js @ 4091

Last change on this file since 4091 was 4091, checked in by andmor, 10 years ago

Updated to angularJS 1.2.2 and ui-bootstrap 0.7.0
Fixed editing user info when editing a field and having another field under edition (without saving).

File size: 120.0 KB
Line 
1angular.module("ui.bootstrap", ["ui.bootstrap.tpls", "ui.bootstrap.transition","ui.bootstrap.collapse","ui.bootstrap.accordion","ui.bootstrap.alert","ui.bootstrap.bindHtml","ui.bootstrap.buttons","ui.bootstrap.carousel","ui.bootstrap.position","ui.bootstrap.datepicker","ui.bootstrap.dropdownToggle","ui.bootstrap.modal","ui.bootstrap.pagination","ui.bootstrap.tooltip","ui.bootstrap.popover","ui.bootstrap.progressbar","ui.bootstrap.rating","ui.bootstrap.tabs","ui.bootstrap.timepicker","ui.bootstrap.typeahead"]);
2angular.module("ui.bootstrap.tpls", ["template/accordion/accordion-group.html","template/accordion/accordion.html","template/alert/alert.html","template/carousel/carousel.html","template/carousel/slide.html","template/datepicker/datepicker.html","template/datepicker/popup.html","template/modal/backdrop.html","template/modal/window.html","template/pagination/pager.html","template/pagination/pagination.html","template/tooltip/tooltip-html-unsafe-popup.html","template/tooltip/tooltip-popup.html","template/popover/popover.html","template/progressbar/bar.html","template/progressbar/progress.html","template/rating/rating.html","template/tabs/tab.html","template/tabs/tabset-titles.html","template/tabs/tabset.html","template/timepicker/timepicker.html","template/typeahead/typeahead-match.html","template/typeahead/typeahead-popup.html"]);
3angular.module('ui.bootstrap.transition', [])
4
5/**
6 * $transition service provides a consistent interface to trigger CSS 3 transitions and to be informed when they complete.
7 * @param  {DOMElement} element  The DOMElement that will be animated.
8 * @param  {string|object|function} trigger  The thing that will cause the transition to start:
9 *   - As a string, it represents the css class to be added to the element.
10 *   - As an object, it represents a hash of style attributes to be applied to the element.
11 *   - As a function, it represents a function to be called that will cause the transition to occur.
12 * @return {Promise}  A promise that is resolved when the transition finishes.
13 */
14.factory('$transition', ['$q', '$timeout', '$rootScope', function($q, $timeout, $rootScope) {
15
16  var $transition = function(element, trigger, options) {
17    options = options || {};
18    var deferred = $q.defer();
19    var endEventName = $transition[options.animation ? "animationEndEventName" : "transitionEndEventName"];
20
21    var transitionEndHandler = function(event) {
22      $rootScope.$apply(function() {
23        element.unbind(endEventName, transitionEndHandler);
24        deferred.resolve(element);
25      });
26    };
27
28    if (endEventName) {
29      element.bind(endEventName, transitionEndHandler);
30    }
31
32    // Wrap in a timeout to allow the browser time to update the DOM before the transition is to occur
33    $timeout(function() {
34      if ( angular.isString(trigger) ) {
35        element.addClass(trigger);
36      } else if ( angular.isFunction(trigger) ) {
37        trigger(element);
38      } else if ( angular.isObject(trigger) ) {
39        element.css(trigger);
40      }
41      //If browser does not support transitions, instantly resolve
42      if ( !endEventName ) {
43        deferred.resolve(element);
44      }
45    });
46
47    // Add our custom cancel function to the promise that is returned
48    // We can call this if we are about to run a new transition, which we know will prevent this transition from ending,
49    // i.e. it will therefore never raise a transitionEnd event for that transition
50    deferred.promise.cancel = function() {
51      if ( endEventName ) {
52        element.unbind(endEventName, transitionEndHandler);
53      }
54      deferred.reject('Transition cancelled');
55    };
56
57    return deferred.promise;
58  };
59
60  // Work out the name of the transitionEnd event
61  var transElement = document.createElement('trans');
62  var transitionEndEventNames = {
63    'WebkitTransition': 'webkitTransitionEnd',
64    'MozTransition': 'transitionend',
65    'OTransition': 'oTransitionEnd',
66    'transition': 'transitionend'
67  };
68  var animationEndEventNames = {
69    'WebkitTransition': 'webkitAnimationEnd',
70    'MozTransition': 'animationend',
71    'OTransition': 'oAnimationEnd',
72    'transition': 'animationend'
73  };
74  function findEndEventName(endEventNames) {
75    for (var name in endEventNames){
76      if (transElement.style[name] !== undefined) {
77        return endEventNames[name];
78      }
79    }
80  }
81  $transition.transitionEndEventName = findEndEventName(transitionEndEventNames);
82  $transition.animationEndEventName = findEndEventName(animationEndEventNames);
83  return $transition;
84}]);
85
86angular.module('ui.bootstrap.collapse',['ui.bootstrap.transition'])
87
88// The collapsible directive indicates a block of html that will expand and collapse
89.directive('collapse', ['$transition', function($transition) {
90  // CSS transitions don't work with height: auto, so we have to manually change the height to a
91  // specific value and then once the animation completes, we can reset the height to auto.
92  // Unfortunately if you do this while the CSS transitions are specified (i.e. in the CSS class
93  // "collapse") then you trigger a change to height 0 in between.
94  // The fix is to remove the "collapse" CSS class while changing the height back to auto - phew!
95  var fixUpHeight = function(scope, element, height) {
96    // We remove the collapse CSS class to prevent a transition when we change to height: auto
97    element.removeClass('collapse');
98    element.css({ height: height });
99    // It appears that  reading offsetWidth makes the browser realise that we have changed the
100    // height already :-/
101    var x = element[0].offsetWidth;
102    element.addClass('collapse');
103  };
104
105  return {
106    link: function(scope, element, attrs) {
107
108      var isCollapsed;
109      var initialAnimSkip = true;
110
111      scope.$watch(attrs.collapse, function(value) {
112        if (value) {
113          collapse();
114        } else {
115          expand();
116        }
117      });
118     
119
120      var currentTransition;
121      var doTransition = function(change) {
122        if ( currentTransition ) {
123          currentTransition.cancel();
124        }
125        currentTransition = $transition(element,change);
126        currentTransition.then(
127          function() { currentTransition = undefined; },
128          function() { currentTransition = undefined; }
129        );
130        return currentTransition;
131      };
132
133      var expand = function() {
134        if (initialAnimSkip) {
135          initialAnimSkip = false;
136          if ( !isCollapsed ) {
137            fixUpHeight(scope, element, 'auto');
138            element.addClass('in');
139          }
140        } else {
141          doTransition({ height : element[0].scrollHeight + 'px' })
142          .then(function() {
143            // This check ensures that we don't accidentally update the height if the user has closed
144            // the group while the animation was still running
145            if ( !isCollapsed ) {
146              fixUpHeight(scope, element, 'auto');
147              element.addClass('in');
148            }
149          });
150        }
151        isCollapsed = false;
152      };
153     
154      var collapse = function() {
155        isCollapsed = true;
156        element.removeClass('in');
157        if (initialAnimSkip) {
158          initialAnimSkip = false;
159          fixUpHeight(scope, element, 0);
160        } else {
161          fixUpHeight(scope, element, element[0].scrollHeight + 'px');
162          doTransition({'height':'0'});
163        }
164      };
165    }
166  };
167}]);
168
169angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
170
171.constant('accordionConfig', {
172  closeOthers: true
173})
174
175.controller('AccordionController', ['$scope', '$attrs', 'accordionConfig', function ($scope, $attrs, accordionConfig) {
176
177  // This array keeps track of the accordion groups
178  this.groups = [];
179
180  // Keep reference to user's scope to properly assign `is-open`
181  this.scope = $scope;
182
183  // Ensure that all the groups in this accordion are closed, unless close-others explicitly says not to
184  this.closeOthers = function(openGroup) {
185    var closeOthers = angular.isDefined($attrs.closeOthers) ? $scope.$eval($attrs.closeOthers) : accordionConfig.closeOthers;
186    if ( closeOthers ) {
187      angular.forEach(this.groups, function (group) {
188        if ( group !== openGroup ) {
189          group.isOpen = false;
190        }
191      });
192    }
193  };
194 
195  // This is called from the accordion-group directive to add itself to the accordion
196  this.addGroup = function(groupScope) {
197    var that = this;
198    this.groups.push(groupScope);
199
200    groupScope.$on('$destroy', function (event) {
201      that.removeGroup(groupScope);
202    });
203  };
204
205  // This is called from the accordion-group directive when to remove itself
206  this.removeGroup = function(group) {
207    var index = this.groups.indexOf(group);
208    if ( index !== -1 ) {
209      this.groups.splice(this.groups.indexOf(group), 1);
210    }
211  };
212
213}])
214
215// The accordion directive simply sets up the directive controller
216// and adds an accordion CSS class to itself element.
217.directive('accordion', function () {
218  return {
219    restrict:'EA',
220    controller:'AccordionController',
221    transclude: true,
222    replace: false,
223    templateUrl: 'template/accordion/accordion.html'
224  };
225})
226
227// The accordion-group directive indicates a block of html that will expand and collapse in an accordion
228.directive('accordionGroup', ['$parse', '$transition', '$timeout', function($parse, $transition, $timeout) {
229  return {
230    require:'^accordion',         // We need this directive to be inside an accordion
231    restrict:'EA',
232    transclude:true,              // It transcludes the contents of the directive into the template
233    replace: true,                // The element containing the directive will be replaced with the template
234    templateUrl:'template/accordion/accordion-group.html',
235    scope:{ heading:'@' },        // Create an isolated scope and interpolate the heading attribute onto this scope
236    controller: ['$scope', function($scope) {
237      this.setHeading = function(element) {
238        this.heading = element;
239      };
240    }],
241    link: function(scope, element, attrs, accordionCtrl) {
242      var getIsOpen, setIsOpen;
243
244      accordionCtrl.addGroup(scope);
245
246      scope.isOpen = false;
247     
248      if ( attrs.isOpen ) {
249        getIsOpen = $parse(attrs.isOpen);
250        setIsOpen = getIsOpen.assign;
251
252        accordionCtrl.scope.$watch(getIsOpen, function(value) {
253          scope.isOpen = !!value;
254        });
255      }
256
257      scope.$watch('isOpen', function(value) {
258        if ( value ) {
259          accordionCtrl.closeOthers(scope);
260        }
261        if ( setIsOpen ) {
262          setIsOpen(accordionCtrl.scope, value);
263        }
264      });
265    }
266  };
267}])
268
269// Use accordion-heading below an accordion-group to provide a heading containing HTML
270// <accordion-group>
271//   <accordion-heading>Heading containing HTML - <img src="..."></accordion-heading>
272// </accordion-group>
273.directive('accordionHeading', function() {
274  return {
275    restrict: 'EA',
276    transclude: true,   // Grab the contents to be used as the heading
277    template: '',       // In effect remove this element!
278    replace: true,
279    require: '^accordionGroup',
280    compile: function(element, attr, transclude) {
281      return function link(scope, element, attr, accordionGroupCtrl) {
282        // Pass the heading to the accordion-group controller
283        // so that it can be transcluded into the right place in the template
284        // [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat]
285        accordionGroupCtrl.setHeading(transclude(scope, function() {}));
286      };
287    }
288  };
289})
290
291// Use in the accordion-group template to indicate where you want the heading to be transcluded
292// You must provide the property on the accordion-group controller that will hold the transcluded element
293// <div class="accordion-group">
294//   <div class="accordion-heading" ><a ... accordion-transclude="heading">...</a></div>
295//   ...
296// </div>
297.directive('accordionTransclude', function() {
298  return {
299    require: '^accordionGroup',
300    link: function(scope, element, attr, controller) {
301      scope.$watch(function() { return controller[attr.accordionTransclude]; }, function(heading) {
302        if ( heading ) {
303          element.html('');
304          element.append(heading);
305        }
306      });
307    }
308  };
309});
310
311angular.module("ui.bootstrap.alert", []).directive('alert', function () {
312  return {
313    restrict:'EA',
314    templateUrl:'template/alert/alert.html',
315    transclude:true,
316    replace:true,
317    scope: {
318      type: '=',
319      close: '&'
320    },
321    link: function(scope, iElement, iAttrs) {
322      scope.closeable = "close" in iAttrs;
323    }
324  };
325});
326
327angular.module('ui.bootstrap.bindHtml', [])
328
329  .directive('bindHtmlUnsafe', function () {
330    return function (scope, element, attr) {
331      element.addClass('ng-binding').data('$binding', attr.bindHtmlUnsafe);
332      scope.$watch(attr.bindHtmlUnsafe, function bindHtmlUnsafeWatchAction(value) {
333        element.html(value || '');
334      });
335    };
336  });
337angular.module('ui.bootstrap.buttons', [])
338
339.constant('buttonConfig', {
340  activeClass: 'active',
341  toggleEvent: 'click'
342})
343
344.directive('btnRadio', ['buttonConfig', function (buttonConfig) {
345  var activeClass = buttonConfig.activeClass || 'active';
346  var toggleEvent = buttonConfig.toggleEvent || 'click';
347
348  return {
349    require: 'ngModel',
350    link: function (scope, element, attrs, ngModelCtrl) {
351
352      //model -> UI
353      ngModelCtrl.$render = function () {
354        element.toggleClass(activeClass, angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.btnRadio)));
355      };
356
357      //ui->model
358      element.bind(toggleEvent, function () {
359        if (!element.hasClass(activeClass)) {
360          scope.$apply(function () {
361            ngModelCtrl.$setViewValue(scope.$eval(attrs.btnRadio));
362            ngModelCtrl.$render();
363          });
364        }
365      });
366    }
367  };
368}])
369
370.directive('btnCheckbox', ['buttonConfig', function (buttonConfig) {
371  var activeClass = buttonConfig.activeClass || 'active';
372  var toggleEvent = buttonConfig.toggleEvent || 'click';
373
374  return {
375    require: 'ngModel',
376    link: function (scope, element, attrs, ngModelCtrl) {
377
378      function getTrueValue() {
379        var trueValue = scope.$eval(attrs.btnCheckboxTrue);
380        return angular.isDefined(trueValue) ? trueValue : true;
381      }
382
383      function getFalseValue() {
384        var falseValue = scope.$eval(attrs.btnCheckboxFalse);
385        return angular.isDefined(falseValue) ? falseValue : false;
386      }
387
388      //model -> UI
389      ngModelCtrl.$render = function () {
390        element.toggleClass(activeClass, angular.equals(ngModelCtrl.$modelValue, getTrueValue()));
391      };
392
393      //ui->model
394      element.bind(toggleEvent, function () {
395        scope.$apply(function () {
396          ngModelCtrl.$setViewValue(element.hasClass(activeClass) ? getFalseValue() : getTrueValue());
397          ngModelCtrl.$render();
398        });
399      });
400    }
401  };
402}]);
403
404/**
405* @ngdoc overview
406* @name ui.bootstrap.carousel
407*
408* @description
409* AngularJS version of an image carousel.
410*
411*/
412angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition'])
413.controller('CarouselController', ['$scope', '$timeout', '$transition', '$q', function ($scope, $timeout, $transition, $q) {
414  var self = this,
415    slides = self.slides = [],
416    currentIndex = -1,
417    currentTimeout, isPlaying;
418  self.currentSlide = null;
419
420  /* direction: "prev" or "next" */
421  self.select = function(nextSlide, direction) {
422    var nextIndex = slides.indexOf(nextSlide);
423    //Decide direction if it's not given
424    if (direction === undefined) {
425      direction = nextIndex > currentIndex ? "next" : "prev";
426    }
427    if (nextSlide && nextSlide !== self.currentSlide) {
428      if ($scope.$currentTransition) {
429        $scope.$currentTransition.cancel();
430        //Timeout so ng-class in template has time to fix classes for finished slide
431        $timeout(goNext);
432      } else {
433        goNext();
434      }
435    }
436    function goNext() {
437      //If we have a slide to transition from and we have a transition type and we're allowed, go
438      if (self.currentSlide && angular.isString(direction) && !$scope.noTransition && nextSlide.$element) {
439        //We shouldn't do class manip in here, but it's the same weird thing bootstrap does. need to fix sometime
440        nextSlide.$element.addClass(direction);
441        var reflow = nextSlide.$element[0].offsetWidth; //force reflow
442
443        //Set all other slides to stop doing their stuff for the new transition
444        angular.forEach(slides, function(slide) {
445          angular.extend(slide, {direction: '', entering: false, leaving: false, active: false});
446        });
447        angular.extend(nextSlide, {direction: direction, active: true, entering: true});
448        angular.extend(self.currentSlide||{}, {direction: direction, leaving: true});
449
450        $scope.$currentTransition = $transition(nextSlide.$element, {});
451        //We have to create new pointers inside a closure since next & current will change
452        (function(next,current) {
453          $scope.$currentTransition.then(
454            function(){ transitionDone(next, current); },
455            function(){ transitionDone(next, current); }
456          );
457        }(nextSlide, self.currentSlide));
458      } else {
459        transitionDone(nextSlide, self.currentSlide);
460      }
461      self.currentSlide = nextSlide;
462      currentIndex = nextIndex;
463      //every time you change slides, reset the timer
464      restartTimer();
465    }
466    function transitionDone(next, current) {
467      angular.extend(next, {direction: '', active: true, leaving: false, entering: false});
468      angular.extend(current||{}, {direction: '', active: false, leaving: false, entering: false});
469      $scope.$currentTransition = null;
470    }
471  };
472
473  /* Allow outside people to call indexOf on slides array */
474  self.indexOfSlide = function(slide) {
475    return slides.indexOf(slide);
476  };
477
478  $scope.next = function() {
479    var newIndex = (currentIndex + 1) % slides.length;
480
481    //Prevent this user-triggered transition from occurring if there is already one in progress
482    if (!$scope.$currentTransition) {
483      return self.select(slides[newIndex], 'next');
484    }
485  };
486
487  $scope.prev = function() {
488    var newIndex = currentIndex - 1 < 0 ? slides.length - 1 : currentIndex - 1;
489
490    //Prevent this user-triggered transition from occurring if there is already one in progress
491    if (!$scope.$currentTransition) {
492      return self.select(slides[newIndex], 'prev');
493    }
494  };
495
496  $scope.select = function(slide) {
497    self.select(slide);
498  };
499
500  $scope.isActive = function(slide) {
501     return self.currentSlide === slide;
502  };
503
504  $scope.slides = function() {
505    return slides;
506  };
507
508  $scope.$watch('interval', restartTimer);
509  function restartTimer() {
510    if (currentTimeout) {
511      $timeout.cancel(currentTimeout);
512    }
513    function go() {
514      if (isPlaying) {
515        $scope.next();
516        restartTimer();
517      } else {
518        $scope.pause();
519      }
520    }
521    var interval = +$scope.interval;
522    if (!isNaN(interval) && interval>=0) {
523      currentTimeout = $timeout(go, interval);
524    }
525  }
526  $scope.play = function() {
527    if (!isPlaying) {
528      isPlaying = true;
529      restartTimer();
530    }
531  };
532  $scope.pause = function() {
533    if (!$scope.noPause) {
534      isPlaying = false;
535      if (currentTimeout) {
536        $timeout.cancel(currentTimeout);
537      }
538    }
539  };
540
541  self.addSlide = function(slide, element) {
542    slide.$element = element;
543    slides.push(slide);
544    //if this is the first slide or the slide is set to active, select it
545    if(slides.length === 1 || slide.active) {
546      self.select(slides[slides.length-1]);
547      if (slides.length == 1) {
548        $scope.play();
549      }
550    } else {
551      slide.active = false;
552    }
553  };
554
555  self.removeSlide = function(slide) {
556    //get the index of the slide inside the carousel
557    var index = slides.indexOf(slide);
558    slides.splice(index, 1);
559    if (slides.length > 0 && slide.active) {
560      if (index >= slides.length) {
561        self.select(slides[index-1]);
562      } else {
563        self.select(slides[index]);
564      }
565    } else if (currentIndex > index) {
566      currentIndex--;
567    }
568  };
569}])
570
571/**
572 * @ngdoc directive
573 * @name ui.bootstrap.carousel.directive:carousel
574 * @restrict EA
575 *
576 * @description
577 * Carousel is the outer container for a set of image 'slides' to showcase.
578 *
579 * @param {number=} interval The time, in milliseconds, that it will take the carousel to go to the next slide.
580 * @param {boolean=} noTransition Whether to disable transitions on the carousel.
581 * @param {boolean=} noPause Whether to disable pausing on the carousel (by default, the carousel interval pauses on hover).
582 *
583 * @example
584<example module="ui.bootstrap">
585  <file name="index.html">
586    <carousel>
587      <slide>
588        <img src="http://placekitten.com/150/150" style="margin:auto;">
589        <div class="carousel-caption">
590          <p>Beautiful!</p>
591        </div>
592      </slide>
593      <slide>
594        <img src="http://placekitten.com/100/150" style="margin:auto;">
595        <div class="carousel-caption">
596          <p>D'aww!</p>
597        </div>
598      </slide>
599    </carousel>
600  </file>
601  <file name="demo.css">
602    .carousel-indicators {
603      top: auto;
604      bottom: 15px;
605    }
606  </file>
607</example>
608 */
609.directive('carousel', [function() {
610  return {
611    restrict: 'EA',
612    transclude: true,
613    replace: true,
614    controller: 'CarouselController',
615    require: 'carousel',
616    templateUrl: 'template/carousel/carousel.html',
617    scope: {
618      interval: '=',
619      noTransition: '=',
620      noPause: '='
621    }
622  };
623}])
624
625/**
626 * @ngdoc directive
627 * @name ui.bootstrap.carousel.directive:slide
628 * @restrict EA
629 *
630 * @description
631 * Creates a slide inside a {@link ui.bootstrap.carousel.directive:carousel carousel}.  Must be placed as a child of a carousel element.
632 *
633 * @param {boolean=} active Model binding, whether or not this slide is currently active.
634 *
635 * @example
636<example module="ui.bootstrap">
637  <file name="index.html">
638<div ng-controller="CarouselDemoCtrl">
639  <carousel>
640    <slide ng-repeat="slide in slides" active="slide.active">
641      <img ng-src="{{slide.image}}" style="margin:auto;">
642      <div class="carousel-caption">
643        <h4>Slide {{$index}}</h4>
644        <p>{{slide.text}}</p>
645      </div>
646    </slide>
647  </carousel>
648  <div class="row-fluid">
649    <div class="span6">
650      <ul>
651        <li ng-repeat="slide in slides">
652          <button class="btn btn-mini" ng-class="{'btn-info': !slide.active, 'btn-success': slide.active}" ng-disabled="slide.active" ng-click="slide.active = true">select</button>
653          {{$index}}: {{slide.text}}
654        </li>
655      </ul>
656      <a class="btn" ng-click="addSlide()">Add Slide</a>
657    </div>
658    <div class="span6">
659      Interval, in milliseconds: <input type="number" ng-model="myInterval">
660      <br />Enter a negative number to stop the interval.
661    </div>
662  </div>
663</div>
664  </file>
665  <file name="script.js">
666function CarouselDemoCtrl($scope) {
667  $scope.myInterval = 5000;
668  var slides = $scope.slides = [];
669  $scope.addSlide = function() {
670    var newWidth = 200 + ((slides.length + (25 * slides.length)) % 150);
671    slides.push({
672      image: 'http://placekitten.com/' + newWidth + '/200',
673      text: ['More','Extra','Lots of','Surplus'][slides.length % 4] + ' '
674        ['Cats', 'Kittys', 'Felines', 'Cutes'][slides.length % 4]
675    });
676  };
677  for (var i=0; i<4; i++) $scope.addSlide();
678}
679  </file>
680  <file name="demo.css">
681    .carousel-indicators {
682      top: auto;
683      bottom: 15px;
684    }
685  </file>
686</example>
687*/
688
689.directive('slide', ['$parse', function($parse) {
690  return {
691    require: '^carousel',
692    restrict: 'EA',
693    transclude: true,
694    replace: true,
695    templateUrl: 'template/carousel/slide.html',
696    scope: {
697    },
698    link: function (scope, element, attrs, carouselCtrl) {
699      //Set up optional 'active' = binding
700      if (attrs.active) {
701        var getActive = $parse(attrs.active);
702        var setActive = getActive.assign;
703        var lastValue = scope.active = getActive(scope.$parent);
704        scope.$watch(function parentActiveWatch() {
705          var parentActive = getActive(scope.$parent);
706
707          if (parentActive !== scope.active) {
708            // we are out of sync and need to copy
709            if (parentActive !== lastValue) {
710              // parent changed and it has precedence
711              lastValue = scope.active = parentActive;
712            } else {
713              // if the parent can be assigned then do so
714              setActive(scope.$parent, parentActive = lastValue = scope.active);
715            }
716          }
717          return parentActive;
718        });
719      }
720
721      carouselCtrl.addSlide(scope, element);
722      //when the scope is destroyed then remove the slide from the current slides array
723      scope.$on('$destroy', function() {
724        carouselCtrl.removeSlide(scope);
725      });
726
727      scope.$watch('active', function(active) {
728        if (active) {
729          carouselCtrl.select(scope);
730        }
731      });
732    }
733  };
734}]);
735
736angular.module('ui.bootstrap.position', [])
737
738/**
739 * A set of utility methods that can be use to retrieve position of DOM elements.
740 * It is meant to be used where we need to absolute-position DOM elements in
741 * relation to other, existing elements (this is the case for tooltips, popovers,
742 * typeahead suggestions etc.).
743 */
744  .factory('$position', ['$document', '$window', function ($document, $window) {
745
746    function getStyle(el, cssprop) {
747      if (el.currentStyle) { //IE
748        return el.currentStyle[cssprop];
749      } else if ($window.getComputedStyle) {
750        return $window.getComputedStyle(el)[cssprop];
751      }
752      // finally try and get inline style
753      return el.style[cssprop];
754    }
755
756    /**
757     * Checks if a given element is statically positioned
758     * @param element - raw DOM element
759     */
760    function isStaticPositioned(element) {
761      return (getStyle(element, "position") || 'static' ) === 'static';
762    }
763
764    /**
765     * returns the closest, non-statically positioned parentOffset of a given element
766     * @param element
767     */
768    var parentOffsetEl = function (element) {
769      var docDomEl = $document[0];
770      var offsetParent = element.offsetParent || docDomEl;
771      while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent) ) {
772        offsetParent = offsetParent.offsetParent;
773      }
774      return offsetParent || docDomEl;
775    };
776
777    return {
778      /**
779       * Provides read-only equivalent of jQuery's position function:
780       * http://api.jquery.com/position/
781       */
782      position: function (element) {
783        var elBCR = this.offset(element);
784        var offsetParentBCR = { top: 0, left: 0 };
785        var offsetParentEl = parentOffsetEl(element[0]);
786        if (offsetParentEl != $document[0]) {
787          offsetParentBCR = this.offset(angular.element(offsetParentEl));
788          offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop;
789          offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft;
790        }
791
792        var boundingClientRect = element[0].getBoundingClientRect();
793        return {
794          width: boundingClientRect.width || element.prop('offsetWidth'),
795          height: boundingClientRect.height || element.prop('offsetHeight'),
796          top: elBCR.top - offsetParentBCR.top,
797          left: elBCR.left - offsetParentBCR.left
798        };
799      },
800
801      /**
802       * Provides read-only equivalent of jQuery's offset function:
803       * http://api.jquery.com/offset/
804       */
805      offset: function (element) {
806        var boundingClientRect = element[0].getBoundingClientRect();
807        return {
808          width: boundingClientRect.width || element.prop('offsetWidth'),
809          height: boundingClientRect.height || element.prop('offsetHeight'),
810          top: boundingClientRect.top + ($window.pageYOffset || $document[0].body.scrollTop || $document[0].documentElement.scrollTop),
811          left: boundingClientRect.left + ($window.pageXOffset || $document[0].body.scrollLeft  || $document[0].documentElement.scrollLeft)
812        };
813      }
814    };
815  }]);
816
817angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.position'])
818
819.constant('datepickerConfig', {
820  dayFormat: 'dd',
821  monthFormat: 'MMMM',
822  yearFormat: 'yyyy',
823  dayHeaderFormat: 'EEE',
824  dayTitleFormat: 'MMMM yyyy',
825  monthTitleFormat: 'yyyy',
826  showWeeks: true,
827  startingDay: 0,
828  yearRange: 20,
829  minDate: null,
830  maxDate: null
831})
832
833.controller('DatepickerController', ['$scope', '$attrs', 'dateFilter', 'datepickerConfig', function($scope, $attrs, dateFilter, dtConfig) {
834  var format = {
835    day:        getValue($attrs.dayFormat,        dtConfig.dayFormat),
836    month:      getValue($attrs.monthFormat,      dtConfig.monthFormat),
837    year:       getValue($attrs.yearFormat,       dtConfig.yearFormat),
838    dayHeader:  getValue($attrs.dayHeaderFormat,  dtConfig.dayHeaderFormat),
839    dayTitle:   getValue($attrs.dayTitleFormat,   dtConfig.dayTitleFormat),
840    monthTitle: getValue($attrs.monthTitleFormat, dtConfig.monthTitleFormat)
841  },
842  startingDay = getValue($attrs.startingDay,      dtConfig.startingDay),
843  yearRange =   getValue($attrs.yearRange,        dtConfig.yearRange);
844
845  this.minDate = dtConfig.minDate ? new Date(dtConfig.minDate) : null;
846  this.maxDate = dtConfig.maxDate ? new Date(dtConfig.maxDate) : null;
847
848  function getValue(value, defaultValue) {
849    return angular.isDefined(value) ? $scope.$parent.$eval(value) : defaultValue;
850  }
851
852  function getDaysInMonth( year, month ) {
853    return new Date(year, month, 0).getDate();
854  }
855
856  function getDates(startDate, n) {
857    var dates = new Array(n);
858    var current = startDate, i = 0;
859    while (i < n) {
860      dates[i++] = new Date(current);
861      current.setDate( current.getDate() + 1 );
862    }
863    return dates;
864  }
865
866  function makeDate(date, format, isSelected, isSecondary) {
867    return { date: date, label: dateFilter(date, format), selected: !!isSelected, secondary: !!isSecondary };
868  }
869
870  this.modes = [
871    {
872      name: 'day',
873      getVisibleDates: function(date, selected) {
874        var year = date.getFullYear(), month = date.getMonth(), firstDayOfMonth = new Date(year, month, 1);
875        var difference = startingDay - firstDayOfMonth.getDay(),
876        numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : - difference,
877        firstDate = new Date(firstDayOfMonth), numDates = 0;
878
879        if ( numDisplayedFromPreviousMonth > 0 ) {
880          firstDate.setDate( - numDisplayedFromPreviousMonth + 1 );
881          numDates += numDisplayedFromPreviousMonth; // Previous
882        }
883        numDates += getDaysInMonth(year, month + 1); // Current
884        numDates += (7 - numDates % 7) % 7; // Next
885
886        var days = getDates(firstDate, numDates), labels = new Array(7);
887        for (var i = 0; i < numDates; i ++) {
888          var dt = new Date(days[i]);
889          days[i] = makeDate(dt, format.day, (selected && selected.getDate() === dt.getDate() && selected.getMonth() === dt.getMonth() && selected.getFullYear() === dt.getFullYear()), dt.getMonth() !== month);
890        }
891        for (var j = 0; j < 7; j++) {
892          labels[j] = dateFilter(days[j].date, format.dayHeader);
893        }
894        return { objects: days, title: dateFilter(date, format.dayTitle), labels: labels };
895      },
896      compare: function(date1, date2) {
897        return (new Date( date1.getFullYear(), date1.getMonth(), date1.getDate() ) - new Date( date2.getFullYear(), date2.getMonth(), date2.getDate() ) );
898      },
899      split: 7,
900      step: { months: 1 }
901    },
902    {
903      name: 'month',
904      getVisibleDates: function(date, selected) {
905        var months = new Array(12), year = date.getFullYear();
906        for ( var i = 0; i < 12; i++ ) {
907          var dt = new Date(year, i, 1);
908          months[i] = makeDate(dt, format.month, (selected && selected.getMonth() === i && selected.getFullYear() === year));
909        }
910        return { objects: months, title: dateFilter(date, format.monthTitle) };
911      },
912      compare: function(date1, date2) {
913        return new Date( date1.getFullYear(), date1.getMonth() ) - new Date( date2.getFullYear(), date2.getMonth() );
914      },
915      split: 3,
916      step: { years: 1 }
917    },
918    {
919      name: 'year',
920      getVisibleDates: function(date, selected) {
921        var years = new Array(yearRange), year = date.getFullYear(), startYear = parseInt((year - 1) / yearRange, 10) * yearRange + 1;
922        for ( var i = 0; i < yearRange; i++ ) {
923          var dt = new Date(startYear + i, 0, 1);
924          years[i] = makeDate(dt, format.year, (selected && selected.getFullYear() === dt.getFullYear()));
925        }
926        return { objects: years, title: [years[0].label, years[yearRange - 1].label].join(' - ') };
927      },
928      compare: function(date1, date2) {
929        return date1.getFullYear() - date2.getFullYear();
930      },
931      split: 5,
932      step: { years: yearRange }
933    }
934  ];
935
936  this.isDisabled = function(date, mode) {
937    var currentMode = this.modes[mode || 0];
938    return ((this.minDate && currentMode.compare(date, this.minDate) < 0) || (this.maxDate && currentMode.compare(date, this.maxDate) > 0) || ($scope.dateDisabled && $scope.dateDisabled({date: date, mode: currentMode.name})));
939  };
940}])
941
942.directive( 'datepicker', ['dateFilter', '$parse', 'datepickerConfig', '$log', function (dateFilter, $parse, datepickerConfig, $log) {
943  return {
944    restrict: 'EA',
945    replace: true,
946    templateUrl: 'template/datepicker/datepicker.html',
947    scope: {
948      dateDisabled: '&'
949    },
950    require: ['datepicker', '?^ngModel'],
951    controller: 'DatepickerController',
952    link: function(scope, element, attrs, ctrls) {
953      var datepickerCtrl = ctrls[0], ngModel = ctrls[1];
954
955      if (!ngModel) {
956        return; // do nothing if no ng-model
957      }
958
959      // Configuration parameters
960      var mode = 0, selected = new Date(), showWeeks = datepickerConfig.showWeeks;
961
962      if (attrs.showWeeks) {
963        scope.$parent.$watch($parse(attrs.showWeeks), function(value) {
964          showWeeks = !! value;
965          updateShowWeekNumbers();
966        });
967      } else {
968        updateShowWeekNumbers();
969      }
970
971      if (attrs.min) {
972        scope.$parent.$watch($parse(attrs.min), function(value) {
973          datepickerCtrl.minDate = value ? new Date(value) : null;
974          refill();
975        });
976      }
977      if (attrs.max) {
978        scope.$parent.$watch($parse(attrs.max), function(value) {
979          datepickerCtrl.maxDate = value ? new Date(value) : null;
980          refill();
981        });
982      }
983
984      function updateShowWeekNumbers() {
985        scope.showWeekNumbers = mode === 0 && showWeeks;
986      }
987
988      // Split array into smaller arrays
989      function split(arr, size) {
990        var arrays = [];
991        while (arr.length > 0) {
992          arrays.push(arr.splice(0, size));
993        }
994        return arrays;
995      }
996
997      function refill( updateSelected ) {
998        var date = null, valid = true;
999
1000        if ( ngModel.$modelValue ) {
1001          date = new Date( ngModel.$modelValue );
1002
1003          if ( isNaN(date) ) {
1004            valid = false;
1005            $log.error('Datepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.');
1006          } else if ( updateSelected ) {
1007            selected = date;
1008          }
1009        }
1010        ngModel.$setValidity('date', valid);
1011
1012        var currentMode = datepickerCtrl.modes[mode], data = currentMode.getVisibleDates(selected, date);
1013        angular.forEach(data.objects, function(obj) {
1014          obj.disabled = datepickerCtrl.isDisabled(obj.date, mode);
1015        });
1016
1017        ngModel.$setValidity('date-disabled', (!date || !datepickerCtrl.isDisabled(date)));
1018
1019        scope.rows = split(data.objects, currentMode.split);
1020        scope.labels = data.labels || [];
1021        scope.title = data.title;
1022      }
1023
1024      function setMode(value) {
1025        mode = value;
1026        updateShowWeekNumbers();
1027        refill();
1028      }
1029
1030      ngModel.$render = function() {
1031        refill( true );
1032      };
1033
1034      scope.select = function( date ) {
1035        if ( mode === 0 ) {
1036          var dt = new Date( ngModel.$modelValue );
1037          dt.setFullYear( date.getFullYear(), date.getMonth(), date.getDate() );
1038          ngModel.$setViewValue( dt );
1039          refill( true );
1040        } else {
1041          selected = date;
1042          setMode( mode - 1 );
1043        }
1044      };
1045      scope.move = function(direction) {
1046        var step = datepickerCtrl.modes[mode].step;
1047        selected.setMonth( selected.getMonth() + direction * (step.months || 0) );
1048        selected.setFullYear( selected.getFullYear() + direction * (step.years || 0) );
1049        refill();
1050      };
1051      scope.toggleMode = function() {
1052        setMode( (mode + 1) % datepickerCtrl.modes.length );
1053      };
1054      scope.getWeekNumber = function(row) {
1055        return ( mode === 0 && scope.showWeekNumbers && row.length === 7 ) ? getISO8601WeekNumber(row[0].date) : null;
1056      };
1057
1058      function getISO8601WeekNumber(date) {
1059        var checkDate = new Date(date);
1060        checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); // Thursday
1061        var time = checkDate.getTime();
1062        checkDate.setMonth(0); // Compare with Jan 1
1063        checkDate.setDate(1);
1064        return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
1065      }
1066    }
1067  };
1068}])
1069
1070.constant('datepickerPopupConfig', {
1071  dateFormat: 'yyyy-MM-dd',
1072  currentText: 'Today',
1073  toggleWeeksText: 'Weeks',
1074  clearText: 'Clear',
1075  closeText: 'Done',
1076  closeOnDateSelection: true,
1077  appendToBody: false
1078})
1079
1080.directive('datepickerPopup', ['$compile', '$parse', '$document', '$position', 'dateFilter', 'datepickerPopupConfig', 'datepickerConfig',
1081function ($compile, $parse, $document, $position, dateFilter, datepickerPopupConfig, datepickerConfig) {
1082  return {
1083    restrict: 'EA',
1084    require: 'ngModel',
1085    link: function(originalScope, element, attrs, ngModel) {
1086      var dateFormat;
1087      attrs.$observe('datepickerPopup', function(value) {
1088          dateFormat = value || datepickerPopupConfig.dateFormat;
1089          ngModel.$render();
1090      });
1091
1092      var closeOnDateSelection = angular.isDefined(attrs.closeOnDateSelection) ? originalScope.$eval(attrs.closeOnDateSelection) : datepickerPopupConfig.closeOnDateSelection;
1093      var appendToBody = angular.isDefined(attrs.datepickerAppendToBody) ? originalScope.$eval(attrs.datepickerAppendToBody) : datepickerPopupConfig.appendToBody;
1094
1095      // create a child scope for the datepicker directive so we are not polluting original scope
1096      var scope = originalScope.$new();
1097
1098      originalScope.$on('$destroy', function() {
1099        scope.$destroy();
1100      });
1101
1102      attrs.$observe('currentText', function(text) {
1103        scope.currentText = angular.isDefined(text) ? text : datepickerPopupConfig.currentText;
1104      });
1105      attrs.$observe('toggleWeeksText', function(text) {
1106        scope.toggleWeeksText = angular.isDefined(text) ? text : datepickerPopupConfig.toggleWeeksText;
1107      });
1108      attrs.$observe('clearText', function(text) {
1109        scope.clearText = angular.isDefined(text) ? text : datepickerPopupConfig.clearText;
1110      });
1111      attrs.$observe('closeText', function(text) {
1112        scope.closeText = angular.isDefined(text) ? text : datepickerPopupConfig.closeText;
1113      });
1114
1115      var getIsOpen, setIsOpen;
1116      if ( attrs.isOpen ) {
1117        getIsOpen = $parse(attrs.isOpen);
1118        setIsOpen = getIsOpen.assign;
1119
1120        originalScope.$watch(getIsOpen, function updateOpen(value) {
1121          scope.isOpen = !! value;
1122        });
1123      }
1124      scope.isOpen = getIsOpen ? getIsOpen(originalScope) : false; // Initial state
1125
1126      function setOpen( value ) {
1127        if (setIsOpen) {
1128          setIsOpen(originalScope, !!value);
1129        } else {
1130          scope.isOpen = !!value;
1131        }
1132      }
1133
1134      var documentClickBind = function(event) {
1135        if (scope.isOpen && event.target !== element[0]) {
1136          scope.$apply(function() {
1137            setOpen(false);
1138          });
1139        }
1140      };
1141
1142      var elementFocusBind = function() {
1143        scope.$apply(function() {
1144          setOpen( true );
1145        });
1146      };
1147
1148      // popup element used to display calendar
1149      var popupEl = angular.element('<div datepicker-popup-wrap><div datepicker></div></div>');
1150      popupEl.attr({
1151        'ng-model': 'date',
1152        'ng-change': 'dateSelection()'
1153      });
1154      var datepickerEl = angular.element(popupEl.children()[0]);
1155      if (attrs.datepickerOptions) {
1156        datepickerEl.attr(angular.extend({}, originalScope.$eval(attrs.datepickerOptions)));
1157      }
1158
1159      // TODO: reverse from dateFilter string to Date object
1160      function parseDate(viewValue) {
1161        if (!viewValue) {
1162          ngModel.$setValidity('date', true);
1163          return null;
1164        } else if (angular.isDate(viewValue)) {
1165          ngModel.$setValidity('date', true);
1166          return viewValue;
1167        } else if (angular.isString(viewValue)) {
1168          var date = new Date(viewValue);
1169          if (isNaN(date)) {
1170            ngModel.$setValidity('date', false);
1171            return undefined;
1172          } else {
1173            ngModel.$setValidity('date', true);
1174            return date;
1175          }
1176        } else {
1177          ngModel.$setValidity('date', false);
1178          return undefined;
1179        }
1180      }
1181      ngModel.$parsers.unshift(parseDate);
1182
1183      // Inner change
1184      scope.dateSelection = function() {
1185        ngModel.$setViewValue(scope.date);
1186        ngModel.$render();
1187
1188        if (closeOnDateSelection) {
1189          setOpen( false );
1190        }
1191      };
1192
1193      element.bind('input change keyup', function() {
1194        scope.$apply(function() {
1195          updateCalendar();
1196        });
1197      });
1198
1199      // Outter change
1200      ngModel.$render = function() {
1201        var date = ngModel.$viewValue ? dateFilter(ngModel.$viewValue, dateFormat) : '';
1202        element.val(date);
1203
1204        updateCalendar();
1205      };
1206
1207      function updateCalendar() {
1208        scope.date = ngModel.$modelValue;
1209        updatePosition();
1210      }
1211
1212      function addWatchableAttribute(attribute, scopeProperty, datepickerAttribute) {
1213        if (attribute) {
1214          originalScope.$watch($parse(attribute), function(value){
1215            scope[scopeProperty] = value;
1216          });
1217          datepickerEl.attr(datepickerAttribute || scopeProperty, scopeProperty);
1218        }
1219      }
1220      addWatchableAttribute(attrs.min, 'min');
1221      addWatchableAttribute(attrs.max, 'max');
1222      if (attrs.showWeeks) {
1223        addWatchableAttribute(attrs.showWeeks, 'showWeeks', 'show-weeks');
1224      } else {
1225        scope.showWeeks = datepickerConfig.showWeeks;
1226        datepickerEl.attr('show-weeks', 'showWeeks');
1227      }
1228      if (attrs.dateDisabled) {
1229        datepickerEl.attr('date-disabled', attrs.dateDisabled);
1230      }
1231
1232      function updatePosition() {
1233        scope.position = appendToBody ? $position.offset(element) : $position.position(element);
1234        scope.position.top = scope.position.top + element.prop('offsetHeight');
1235      }
1236
1237      var documentBindingInitialized = false, elementFocusInitialized = false;
1238      scope.$watch('isOpen', function(value) {
1239        if (value) {
1240          updatePosition();
1241          $document.bind('click', documentClickBind);
1242          if(elementFocusInitialized) {
1243            element.unbind('focus', elementFocusBind);
1244          }
1245          element[0].focus();
1246          documentBindingInitialized = true;
1247        } else {
1248          if(documentBindingInitialized) {
1249            $document.unbind('click', documentClickBind);
1250          }
1251          element.bind('focus', elementFocusBind);
1252          elementFocusInitialized = true;
1253        }
1254
1255        if ( setIsOpen ) {
1256          setIsOpen(originalScope, value);
1257        }
1258      });
1259
1260      var $setModelValue = $parse(attrs.ngModel).assign;
1261
1262      scope.today = function() {
1263        $setModelValue(originalScope, new Date());
1264      };
1265      scope.clear = function() {
1266        $setModelValue(originalScope, null);
1267      };
1268
1269      var $popup = $compile(popupEl)(scope);
1270      if ( appendToBody ) {
1271        $document.find('body').append($popup);
1272      } else {
1273        element.after($popup);
1274      }
1275    }
1276  };
1277}])
1278
1279.directive('datepickerPopupWrap', function() {
1280  return {
1281    restrict:'EA',
1282    replace: true,
1283    transclude: true,
1284    templateUrl: 'template/datepicker/popup.html',
1285    link:function (scope, element, attrs) {
1286      element.bind('click', function(event) {
1287        event.preventDefault();
1288        event.stopPropagation();
1289      });
1290    }
1291  };
1292});
1293
1294/*
1295 * dropdownToggle - Provides dropdown menu functionality in place of bootstrap js
1296 * @restrict class or attribute
1297 * @example:
1298   <li class="dropdown">
1299     <a class="dropdown-toggle">My Dropdown Menu</a>
1300     <ul class="dropdown-menu">
1301       <li ng-repeat="choice in dropChoices">
1302         <a ng-href="{{choice.href}}">{{choice.text}}</a>
1303       </li>
1304     </ul>
1305   </li>
1306 */
1307
1308angular.module('ui.bootstrap.dropdownToggle', []).directive('dropdownToggle', ['$document', '$location', function ($document, $location) {
1309  var openElement = null,
1310      closeMenu   = angular.noop;
1311  return {
1312    restrict: 'CA',
1313    link: function(scope, element, attrs) {
1314      scope.$watch('$location.path', function() { closeMenu(); });
1315      element.parent().bind('click', function() { closeMenu(); });
1316      element.bind('click', function (event) {
1317
1318        var elementWasOpen = (element === openElement);
1319
1320        event.preventDefault();
1321        event.stopPropagation();
1322
1323        if (!!openElement) {
1324          closeMenu();
1325        }
1326
1327        if (!elementWasOpen && !element.hasClass('disabled') && !element.prop('disabled')) {
1328          element.parent().addClass('open');
1329          openElement = element;
1330          closeMenu = function (event) {
1331            if (event) {
1332              event.preventDefault();
1333              event.stopPropagation();
1334            }
1335            $document.unbind('click', closeMenu);
1336            element.parent().removeClass('open');
1337            closeMenu = angular.noop;
1338            openElement = null;
1339          };
1340          $document.bind('click', closeMenu);
1341        }
1342      });
1343    }
1344  };
1345}]);
1346
1347angular.module('ui.bootstrap.modal', [])
1348
1349/**
1350 * A helper, internal data structure that acts as a map but also allows getting / removing
1351 * elements in the LIFO order
1352 */
1353  .factory('$$stackedMap', function () {
1354    return {
1355      createNew: function () {
1356        var stack = [];
1357
1358        return {
1359          add: function (key, value) {
1360            stack.push({
1361              key: key,
1362              value: value
1363            });
1364          },
1365          get: function (key) {
1366            for (var i = 0; i < stack.length; i++) {
1367              if (key == stack[i].key) {
1368                return stack[i];
1369              }
1370            }
1371          },
1372          keys: function() {
1373            var keys = [];
1374            for (var i = 0; i < stack.length; i++) {
1375              keys.push(stack[i].key);
1376            }
1377            return keys;
1378          },
1379          top: function () {
1380            return stack[stack.length - 1];
1381          },
1382          remove: function (key) {
1383            var idx = -1;
1384            for (var i = 0; i < stack.length; i++) {
1385              if (key == stack[i].key) {
1386                idx = i;
1387                break;
1388              }
1389            }
1390            return stack.splice(idx, 1)[0];
1391          },
1392          removeTop: function () {
1393            return stack.splice(stack.length - 1, 1)[0];
1394          },
1395          length: function () {
1396            return stack.length;
1397          }
1398        };
1399      }
1400    };
1401  })
1402
1403/**
1404 * A helper directive for the $modal service. It creates a backdrop element.
1405 */
1406  .directive('modalBackdrop', ['$modalStack', '$timeout', function ($modalStack, $timeout) {
1407    return {
1408      restrict: 'EA',
1409      replace: true,
1410      templateUrl: 'template/modal/backdrop.html',
1411      link: function (scope, element, attrs) {
1412
1413        //trigger CSS transitions
1414        $timeout(function () {
1415          scope.animate = true;
1416        });
1417
1418        scope.close = function (evt) {
1419          var modal = $modalStack.getTop();
1420          if (modal && modal.value.backdrop && modal.value.backdrop != 'static') {
1421            evt.preventDefault();
1422            evt.stopPropagation();
1423            $modalStack.dismiss(modal.key, 'backdrop click');
1424          }
1425        };
1426      }
1427    };
1428  }])
1429
1430  .directive('modalWindow', ['$timeout', function ($timeout) {
1431    return {
1432      restrict: 'EA',
1433      scope: {
1434        index: '@'
1435      },
1436      replace: true,
1437      transclude: true,
1438      templateUrl: 'template/modal/window.html',
1439      link: function (scope, element, attrs) {
1440        scope.windowClass = attrs.windowClass || '';
1441
1442        //trigger CSS transitions
1443        $timeout(function () {
1444          scope.animate = true;
1445        });
1446      }
1447    };
1448  }])
1449
1450  .factory('$modalStack', ['$document', '$compile', '$rootScope', '$$stackedMap',
1451    function ($document, $compile, $rootScope, $$stackedMap) {
1452
1453      var backdropjqLiteEl, backdropDomEl;
1454      var backdropScope = $rootScope.$new(true);
1455      var body = $document.find('body').eq(0);
1456      var openedWindows = $$stackedMap.createNew();
1457      var $modalStack = {};
1458
1459      function backdropIndex() {
1460        var topBackdropIndex = -1;
1461        var opened = openedWindows.keys();
1462        for (var i = 0; i < opened.length; i++) {
1463          if (openedWindows.get(opened[i]).value.backdrop) {
1464            topBackdropIndex = i;
1465          }
1466        }
1467        return topBackdropIndex;
1468      }
1469
1470      $rootScope.$watch(backdropIndex, function(newBackdropIndex){
1471        backdropScope.index = newBackdropIndex;
1472      });
1473
1474      function removeModalWindow(modalInstance) {
1475
1476        var modalWindow = openedWindows.get(modalInstance).value;
1477
1478        //clean up the stack
1479        openedWindows.remove(modalInstance);
1480
1481        //remove window DOM element
1482        modalWindow.modalDomEl.remove();
1483
1484        //remove backdrop if no longer needed
1485        if (backdropDomEl && backdropIndex() == -1) {
1486          backdropDomEl.remove();
1487          backdropDomEl = undefined;
1488        }
1489
1490        //destroy scope
1491        modalWindow.modalScope.$destroy();
1492      }
1493
1494      $document.bind('keydown', function (evt) {
1495        var modal;
1496
1497        if (evt.which === 27) {
1498          modal = openedWindows.top();
1499          if (modal && modal.value.keyboard) {
1500            $rootScope.$apply(function () {
1501              $modalStack.dismiss(modal.key);
1502            });
1503          }
1504        }
1505      });
1506
1507      $modalStack.open = function (modalInstance, modal) {
1508
1509        openedWindows.add(modalInstance, {
1510          deferred: modal.deferred,
1511          modalScope: modal.scope,
1512          backdrop: modal.backdrop,
1513          keyboard: modal.keyboard
1514        });
1515
1516        var angularDomEl = angular.element('<div modal-window></div>');
1517        angularDomEl.attr('window-class', modal.windowClass);
1518        angularDomEl.attr('index', openedWindows.length() - 1);
1519        angularDomEl.html(modal.content);
1520
1521        var modalDomEl = $compile(angularDomEl)(modal.scope);
1522        openedWindows.top().value.modalDomEl = modalDomEl;
1523        body.append(modalDomEl);
1524
1525        if (backdropIndex() >= 0 && !backdropDomEl) {
1526            backdropjqLiteEl = angular.element('<div modal-backdrop></div>');
1527            backdropDomEl = $compile(backdropjqLiteEl)(backdropScope);
1528            body.append(backdropDomEl);
1529        }
1530      };
1531
1532      $modalStack.close = function (modalInstance, result) {
1533        var modal = openedWindows.get(modalInstance);
1534        if (modal) {
1535          modal.value.deferred.resolve(result);
1536          removeModalWindow(modalInstance);
1537        }
1538      };
1539
1540      $modalStack.dismiss = function (modalInstance, reason) {
1541        var modalWindow = openedWindows.get(modalInstance).value;
1542        if (modalWindow) {
1543          modalWindow.deferred.reject(reason);
1544          removeModalWindow(modalInstance);
1545        }
1546      };
1547
1548      $modalStack.getTop = function () {
1549        return openedWindows.top();
1550      };
1551
1552      return $modalStack;
1553    }])
1554
1555  .provider('$modal', function () {
1556
1557    var $modalProvider = {
1558      options: {
1559        backdrop: true, //can be also false or 'static'
1560        keyboard: true
1561      },
1562      $get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack',
1563        function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) {
1564
1565          var $modal = {};
1566
1567          function getTemplatePromise(options) {
1568            return options.template ? $q.when(options.template) :
1569              $http.get(options.templateUrl, {cache: $templateCache}).then(function (result) {
1570                return result.data;
1571              });
1572          }
1573
1574          function getResolvePromises(resolves) {
1575            var promisesArr = [];
1576            angular.forEach(resolves, function (value, key) {
1577              if (angular.isFunction(value) || angular.isArray(value)) {
1578                promisesArr.push($q.when($injector.invoke(value)));
1579              }
1580            });
1581            return promisesArr;
1582          }
1583
1584          $modal.open = function (modalOptions) {
1585
1586            var modalResultDeferred = $q.defer();
1587            var modalOpenedDeferred = $q.defer();
1588
1589            //prepare an instance of a modal to be injected into controllers and returned to a caller
1590            var modalInstance = {
1591              result: modalResultDeferred.promise,
1592              opened: modalOpenedDeferred.promise,
1593              close: function (result) {
1594                $modalStack.close(modalInstance, result);
1595              },
1596              dismiss: function (reason) {
1597                $modalStack.dismiss(modalInstance, reason);
1598              }
1599            };
1600
1601            //merge and clean up options
1602            modalOptions = angular.extend({}, $modalProvider.options, modalOptions);
1603            modalOptions.resolve = modalOptions.resolve || {};
1604
1605            //verify options
1606            if (!modalOptions.template && !modalOptions.templateUrl) {
1607              throw new Error('One of template or templateUrl options is required.');
1608            }
1609
1610            var templateAndResolvePromise =
1611              $q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve)));
1612
1613
1614            templateAndResolvePromise.then(function resolveSuccess(tplAndVars) {
1615
1616              var modalScope = (modalOptions.scope || $rootScope).$new();
1617              modalScope.$close = modalInstance.close;
1618              modalScope.$dismiss = modalInstance.dismiss;
1619
1620              var ctrlInstance, ctrlLocals = {};
1621              var resolveIter = 1;
1622
1623              //controllers
1624              if (modalOptions.controller) {
1625                ctrlLocals.$scope = modalScope;
1626                ctrlLocals.$modalInstance = modalInstance;
1627                angular.forEach(modalOptions.resolve, function (value, key) {
1628                  ctrlLocals[key] = tplAndVars[resolveIter++];
1629                });
1630
1631                ctrlInstance = $controller(modalOptions.controller, ctrlLocals);
1632              }
1633
1634              $modalStack.open(modalInstance, {
1635                scope: modalScope,
1636                deferred: modalResultDeferred,
1637                content: tplAndVars[0],
1638                backdrop: modalOptions.backdrop,
1639                keyboard: modalOptions.keyboard,
1640                windowClass: modalOptions.windowClass
1641              });
1642
1643            }, function resolveError(reason) {
1644              modalResultDeferred.reject(reason);
1645            });
1646
1647            templateAndResolvePromise.then(function () {
1648              modalOpenedDeferred.resolve(true);
1649            }, function () {
1650              modalOpenedDeferred.reject(false);
1651            });
1652
1653            return modalInstance;
1654          };
1655
1656          return $modal;
1657        }]
1658    };
1659
1660    return $modalProvider;
1661  });
1662
1663angular.module('ui.bootstrap.pagination', [])
1664
1665.controller('PaginationController', ['$scope', '$attrs', '$parse', '$interpolate', function ($scope, $attrs, $parse, $interpolate) {
1666  var self = this,
1667      setNumPages = $attrs.numPages ? $parse($attrs.numPages).assign : angular.noop;
1668
1669  this.init = function(defaultItemsPerPage) {
1670    if ($attrs.itemsPerPage) {
1671      $scope.$parent.$watch($parse($attrs.itemsPerPage), function(value) {
1672        self.itemsPerPage = parseInt(value, 10);
1673        $scope.totalPages = self.calculateTotalPages();
1674      });
1675    } else {
1676      this.itemsPerPage = defaultItemsPerPage;
1677    }
1678  };
1679
1680  this.noPrevious = function() {
1681    return this.page === 1;
1682  };
1683  this.noNext = function() {
1684    return this.page === $scope.totalPages;
1685  };
1686
1687  this.isActive = function(page) {
1688    return this.page === page;
1689  };
1690
1691  this.calculateTotalPages = function() {
1692    var totalPages = this.itemsPerPage < 1 ? 1 : Math.ceil($scope.totalItems / this.itemsPerPage);
1693    return Math.max(totalPages || 0, 1);
1694  };
1695
1696  this.getAttributeValue = function(attribute, defaultValue, interpolate) {
1697    return angular.isDefined(attribute) ? (interpolate ? $interpolate(attribute)($scope.$parent) : $scope.$parent.$eval(attribute)) : defaultValue;
1698  };
1699
1700  this.render = function() {
1701    this.page = parseInt($scope.page, 10) || 1;
1702    if (this.page > 0 && this.page <= $scope.totalPages) {
1703      $scope.pages = this.getPages(this.page, $scope.totalPages);
1704    }
1705  };
1706
1707  $scope.selectPage = function(page) {
1708    if ( ! self.isActive(page) && page > 0 && page <= $scope.totalPages) {
1709      $scope.page = page;
1710      $scope.onSelectPage({ page: page });
1711    }
1712  };
1713
1714  $scope.$watch('page', function() {
1715    self.render();
1716  });
1717
1718  $scope.$watch('totalItems', function() {
1719    $scope.totalPages = self.calculateTotalPages();
1720  });
1721
1722  $scope.$watch('totalPages', function(value) {
1723    setNumPages($scope.$parent, value); // Readonly variable
1724
1725    if ( self.page > value ) {
1726      $scope.selectPage(value);
1727    } else {
1728      self.render();
1729    }
1730  });
1731}])
1732
1733.constant('paginationConfig', {
1734  itemsPerPage: 10,
1735  boundaryLinks: false,
1736  directionLinks: true,
1737  firstText: 'First',
1738  previousText: 'Previous',
1739  nextText: 'Next',
1740  lastText: 'Last',
1741  rotate: true
1742})
1743
1744.directive('pagination', ['$parse', 'paginationConfig', function($parse, config) {
1745  return {
1746    restrict: 'EA',
1747    scope: {
1748      page: '=',
1749      totalItems: '=',
1750      onSelectPage:' &'
1751    },
1752    controller: 'PaginationController',
1753    templateUrl: 'template/pagination/pagination.html',
1754    replace: true,
1755    link: function(scope, element, attrs, paginationCtrl) {
1756
1757      // Setup configuration parameters
1758      var maxSize,
1759      boundaryLinks  = paginationCtrl.getAttributeValue(attrs.boundaryLinks,  config.boundaryLinks      ),
1760      directionLinks = paginationCtrl.getAttributeValue(attrs.directionLinks, config.directionLinks     ),
1761      firstText      = paginationCtrl.getAttributeValue(attrs.firstText,      config.firstText,     true),
1762      previousText   = paginationCtrl.getAttributeValue(attrs.previousText,   config.previousText,  true),
1763      nextText       = paginationCtrl.getAttributeValue(attrs.nextText,       config.nextText,      true),
1764      lastText       = paginationCtrl.getAttributeValue(attrs.lastText,       config.lastText,      true),
1765      rotate         = paginationCtrl.getAttributeValue(attrs.rotate,         config.rotate);
1766
1767      paginationCtrl.init(config.itemsPerPage);
1768
1769      if (attrs.maxSize) {
1770        scope.$parent.$watch($parse(attrs.maxSize), function(value) {
1771          maxSize = parseInt(value, 10);
1772          paginationCtrl.render();
1773        });
1774      }
1775
1776      // Create page object used in template
1777      function makePage(number, text, isActive, isDisabled) {
1778        return {
1779          number: number,
1780          text: text,
1781          active: isActive,
1782          disabled: isDisabled
1783        };
1784      }
1785
1786      paginationCtrl.getPages = function(currentPage, totalPages) {
1787        var pages = [];
1788
1789        // Default page limits
1790        var startPage = 1, endPage = totalPages;
1791        var isMaxSized = ( angular.isDefined(maxSize) && maxSize < totalPages );
1792
1793        // recompute if maxSize
1794        if ( isMaxSized ) {
1795          if ( rotate ) {
1796            // Current page is displayed in the middle of the visible ones
1797            startPage = Math.max(currentPage - Math.floor(maxSize/2), 1);
1798            endPage   = startPage + maxSize - 1;
1799
1800            // Adjust if limit is exceeded
1801            if (endPage > totalPages) {
1802              endPage   = totalPages;
1803              startPage = endPage - maxSize + 1;
1804            }
1805          } else {
1806            // Visible pages are paginated with maxSize
1807            startPage = ((Math.ceil(currentPage / maxSize) - 1) * maxSize) + 1;
1808
1809            // Adjust last page if limit is exceeded
1810            endPage = Math.min(startPage + maxSize - 1, totalPages);
1811          }
1812        }
1813
1814        // Add page number links
1815        for (var number = startPage; number <= endPage; number++) {
1816          var page = makePage(number, number, paginationCtrl.isActive(number), false);
1817          pages.push(page);
1818        }
1819
1820        // Add links to move between page sets
1821        if ( isMaxSized && ! rotate ) {
1822          if ( startPage > 1 ) {
1823            var previousPageSet = makePage(startPage - 1, '...', false, false);
1824            pages.unshift(previousPageSet);
1825          }
1826
1827          if ( endPage < totalPages ) {
1828            var nextPageSet = makePage(endPage + 1, '...', false, false);
1829            pages.push(nextPageSet);
1830          }
1831        }
1832
1833        // Add previous & next links
1834        if (directionLinks) {
1835          var previousPage = makePage(currentPage - 1, previousText, false, paginationCtrl.noPrevious());
1836          pages.unshift(previousPage);
1837
1838          var nextPage = makePage(currentPage + 1, nextText, false, paginationCtrl.noNext());
1839          pages.push(nextPage);
1840        }
1841
1842        // Add first & last links
1843        if (boundaryLinks) {
1844          var firstPage = makePage(1, firstText, false, paginationCtrl.noPrevious());
1845          pages.unshift(firstPage);
1846
1847          var lastPage = makePage(totalPages, lastText, false, paginationCtrl.noNext());
1848          pages.push(lastPage);
1849        }
1850
1851        return pages;
1852      };
1853    }
1854  };
1855}])
1856
1857.constant('pagerConfig', {
1858  itemsPerPage: 10,
1859  previousText: '« Previous',
1860  nextText: 'Next »',
1861  align: true
1862})
1863
1864.directive('pager', ['pagerConfig', function(config) {
1865  return {
1866    restrict: 'EA',
1867    scope: {
1868      page: '=',
1869      totalItems: '=',
1870      onSelectPage:' &'
1871    },
1872    controller: 'PaginationController',
1873    templateUrl: 'template/pagination/pager.html',
1874    replace: true,
1875    link: function(scope, element, attrs, paginationCtrl) {
1876
1877      // Setup configuration parameters
1878      var previousText = paginationCtrl.getAttributeValue(attrs.previousText, config.previousText, true),
1879      nextText         = paginationCtrl.getAttributeValue(attrs.nextText,     config.nextText,     true),
1880      align            = paginationCtrl.getAttributeValue(attrs.align,        config.align);
1881
1882      paginationCtrl.init(config.itemsPerPage);
1883
1884      // Create page object used in template
1885      function makePage(number, text, isDisabled, isPrevious, isNext) {
1886        return {
1887          number: number,
1888          text: text,
1889          disabled: isDisabled,
1890          previous: ( align && isPrevious ),
1891          next: ( align && isNext )
1892        };
1893      }
1894
1895      paginationCtrl.getPages = function(currentPage) {
1896        return [
1897          makePage(currentPage - 1, previousText, paginationCtrl.noPrevious(), true, false),
1898          makePage(currentPage + 1, nextText, paginationCtrl.noNext(), false, true)
1899        ];
1900      };
1901    }
1902  };
1903}]);
1904
1905/**
1906 * The following features are still outstanding: animation as a
1907 * function, placement as a function, inside, support for more triggers than
1908 * just mouse enter/leave, html tooltips, and selector delegation.
1909 */
1910angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap.bindHtml' ] )
1911
1912/**
1913 * The $tooltip service creates tooltip- and popover-like directives as well as
1914 * houses global options for them.
1915 */
1916.provider( '$tooltip', function () {
1917  // The default options tooltip and popover.
1918  var defaultOptions = {
1919    placement: 'top',
1920    animation: true,
1921    popupDelay: 0
1922  };
1923
1924  // Default hide triggers for each show trigger
1925  var triggerMap = {
1926    'mouseenter': 'mouseleave',
1927    'click': 'click',
1928    'focus': 'blur'
1929  };
1930
1931  // The options specified to the provider globally.
1932  var globalOptions = {};
1933 
1934  /**
1935   * `options({})` allows global configuration of all tooltips in the
1936   * application.
1937   *
1938   *   var app = angular.module( 'App', ['ui.bootstrap.tooltip'], function( $tooltipProvider ) {
1939   *     // place tooltips left instead of top by default
1940   *     $tooltipProvider.options( { placement: 'left' } );
1941   *   });
1942   */
1943        this.options = function( value ) {
1944                angular.extend( globalOptions, value );
1945        };
1946
1947  /**
1948   * This allows you to extend the set of trigger mappings available. E.g.:
1949   *
1950   *   $tooltipProvider.setTriggers( 'openTrigger': 'closeTrigger' );
1951   */
1952  this.setTriggers = function setTriggers ( triggers ) {
1953    angular.extend( triggerMap, triggers );
1954  };
1955
1956  /**
1957   * This is a helper function for translating camel-case to snake-case.
1958   */
1959  function snake_case(name){
1960    var regexp = /[A-Z]/g;
1961    var separator = '-';
1962    return name.replace(regexp, function(letter, pos) {
1963      return (pos ? separator : '') + letter.toLowerCase();
1964    });
1965  }
1966
1967  /**
1968   * Returns the actual instance of the $tooltip service.
1969   * TODO support multiple triggers
1970   */
1971  this.$get = [ '$window', '$compile', '$timeout', '$parse', '$document', '$position', '$interpolate', function ( $window, $compile, $timeout, $parse, $document, $position, $interpolate ) {
1972    return function $tooltip ( type, prefix, defaultTriggerShow ) {
1973      var options = angular.extend( {}, defaultOptions, globalOptions );
1974
1975      /**
1976       * Returns an object of show and hide triggers.
1977       *
1978       * If a trigger is supplied,
1979       * it is used to show the tooltip; otherwise, it will use the `trigger`
1980       * option passed to the `$tooltipProvider.options` method; else it will
1981       * default to the trigger supplied to this directive factory.
1982       *
1983       * The hide trigger is based on the show trigger. If the `trigger` option
1984       * was passed to the `$tooltipProvider.options` method, it will use the
1985       * mapped trigger from `triggerMap` or the passed trigger if the map is
1986       * undefined; otherwise, it uses the `triggerMap` value of the show
1987       * trigger; else it will just use the show trigger.
1988       */
1989      function getTriggers ( trigger ) {
1990        var show = trigger || options.trigger || defaultTriggerShow;
1991        var hide = triggerMap[show] || show;
1992        return {
1993          show: show,
1994          hide: hide
1995        };
1996      }
1997
1998      var directiveName = snake_case( type );
1999
2000      var startSym = $interpolate.startSymbol();
2001      var endSym = $interpolate.endSymbol();
2002      var template = 
2003        '<'+ directiveName +'-popup '+
2004          'title="'+startSym+'tt_title'+endSym+'" '+
2005          'content="'+startSym+'tt_content'+endSym+'" '+
2006          'placement="'+startSym+'tt_placement'+endSym+'" '+
2007          'animation="tt_animation" '+
2008          'is-open="tt_isOpen"'+
2009          '>'+
2010        '</'+ directiveName +'-popup>';
2011
2012      return {
2013        restrict: 'EA',
2014        scope: true,
2015        link: function link ( scope, element, attrs ) {
2016          var tooltip = $compile( template )( scope );
2017          var transitionTimeout;
2018          var popupTimeout;
2019          var $body = $document.find( 'body' );
2020          var appendToBody = angular.isDefined( options.appendToBody ) ? options.appendToBody : false;
2021          var triggers = getTriggers( undefined );
2022          var hasRegisteredTriggers = false;
2023          var hasEnableExp = angular.isDefined(attrs[prefix+'Enable']);
2024
2025          // By default, the tooltip is not open.
2026          // TODO add ability to start tooltip opened
2027          scope.tt_isOpen = false;
2028
2029          function toggleTooltipBind () {
2030            if ( ! scope.tt_isOpen ) {
2031              showTooltipBind();
2032            } else {
2033              hideTooltipBind();
2034            }
2035          }
2036         
2037          // Show the tooltip with delay if specified, otherwise show it immediately
2038          function showTooltipBind() {
2039            if(hasEnableExp && !scope.$eval(attrs[prefix+'Enable'])) {
2040              return;
2041            }
2042            if ( scope.tt_popupDelay ) {
2043              popupTimeout = $timeout( show, scope.tt_popupDelay );
2044            } else {
2045              scope.$apply( show );
2046            }
2047          }
2048
2049          function hideTooltipBind () {
2050            scope.$apply(function () {
2051              hide();
2052            });
2053          }
2054         
2055          // Show the tooltip popup element.
2056          function show() {
2057            var position,
2058                ttWidth,
2059                ttHeight,
2060                ttPosition;
2061
2062            // Don't show empty tooltips.
2063            if ( ! scope.tt_content ) {
2064              return;
2065            }
2066
2067            // If there is a pending remove transition, we must cancel it, lest the
2068            // tooltip be mysteriously removed.
2069            if ( transitionTimeout ) {
2070              $timeout.cancel( transitionTimeout );
2071            }
2072           
2073            // Set the initial positioning.
2074            tooltip.css({ top: 0, left: 0, display: 'block' });
2075           
2076            // Now we add it to the DOM because need some info about it. But it's not
2077            // visible yet anyway.
2078            if ( appendToBody ) {
2079                $body.append( tooltip );
2080            } else {
2081              element.after( tooltip );
2082            }
2083
2084            // Get the position of the directive element.
2085            position = appendToBody ? $position.offset( element ) : $position.position( element );
2086
2087            // Get the height and width of the tooltip so we can center it.
2088            ttWidth = tooltip.prop( 'offsetWidth' );
2089            ttHeight = tooltip.prop( 'offsetHeight' );
2090           
2091            // Calculate the tooltip's top and left coordinates to center it with
2092            // this directive.
2093            switch ( scope.tt_placement ) {
2094              case 'right':
2095                ttPosition = {
2096                  top: position.top + position.height / 2 - ttHeight / 2,
2097                  left: position.left + position.width
2098                };
2099                break;
2100              case 'bottom':
2101                ttPosition = {
2102                  top: position.top + position.height,
2103                  left: position.left + position.width / 2 - ttWidth / 2
2104                };
2105                break;
2106              case 'left':
2107                ttPosition = {
2108                  top: position.top + position.height / 2 - ttHeight / 2,
2109                  left: position.left - ttWidth
2110                };
2111                break;
2112              default:
2113                ttPosition = {
2114                  top: position.top - ttHeight,
2115                  left: position.left + position.width / 2 - ttWidth / 2
2116                };
2117                break;
2118            }
2119
2120            ttPosition.top += 'px';
2121            ttPosition.left += 'px';
2122
2123            // Now set the calculated positioning.
2124            tooltip.css( ttPosition );
2125             
2126            // And show the tooltip.
2127            scope.tt_isOpen = true;
2128          }
2129         
2130          // Hide the tooltip popup element.
2131          function hide() {
2132            // First things first: we don't show it anymore.
2133            scope.tt_isOpen = false;
2134
2135            //if tooltip is going to be shown after delay, we must cancel this
2136            $timeout.cancel( popupTimeout );
2137           
2138            // And now we remove it from the DOM. However, if we have animation, we
2139            // need to wait for it to expire beforehand.
2140            // FIXME: this is a placeholder for a port of the transitions library.
2141            if ( scope.tt_animation ) {
2142              transitionTimeout = $timeout(function () {
2143                tooltip.remove();
2144              }, 500);
2145            } else {
2146              tooltip.remove();
2147            }
2148          }
2149
2150          /**
2151           * Observe the relevant attributes.
2152           */
2153          attrs.$observe( type, function ( val ) {
2154            if (val) {
2155              scope.tt_content = val;
2156            } else {
2157              if ( scope.tt_isOpen ) {
2158                hide();
2159              }
2160            }
2161          });
2162
2163          attrs.$observe( prefix+'Title', function ( val ) {
2164            scope.tt_title = val;
2165          });
2166
2167          attrs.$observe( prefix+'Placement', function ( val ) {
2168            scope.tt_placement = angular.isDefined( val ) ? val : options.placement;
2169          });
2170
2171          attrs.$observe(prefix + 'Animation', function (val) {
2172            scope.tt_animation = angular.isDefined(val) ? !!val : options.animation;
2173          });
2174
2175          attrs.$observe( prefix+'PopupDelay', function ( val ) {
2176            var delay = parseInt( val, 10 );
2177            scope.tt_popupDelay = ! isNaN(delay) ? delay : options.popupDelay;
2178          });
2179
2180          attrs.$observe( prefix+'Trigger', function ( val ) {
2181
2182            if (hasRegisteredTriggers) {
2183              element.unbind( triggers.show, showTooltipBind );
2184              element.unbind( triggers.hide, hideTooltipBind );
2185            }
2186
2187            triggers = getTriggers( val );
2188
2189            if ( triggers.show === triggers.hide ) {
2190              element.bind( triggers.show, toggleTooltipBind );
2191            } else {
2192              element.bind( triggers.show, showTooltipBind );
2193              element.bind( triggers.hide, hideTooltipBind );
2194            }
2195
2196            hasRegisteredTriggers = true;
2197          });
2198
2199          attrs.$observe( prefix+'AppendToBody', function ( val ) {
2200            appendToBody = angular.isDefined( val ) ? $parse( val )( scope ) : appendToBody;
2201          });
2202
2203          // if a tooltip is attached to <body> we need to remove it on
2204          // location change as its parent scope will probably not be destroyed
2205          // by the change.
2206          if ( appendToBody ) {
2207            scope.$on('$locationChangeSuccess', function closeTooltipOnLocationChangeSuccess () {
2208            if ( scope.tt_isOpen ) {
2209              hide();
2210            }
2211          });
2212          }
2213
2214          // Make sure tooltip is destroyed and removed.
2215          scope.$on('$destroy', function onDestroyTooltip() {
2216            $timeout.cancel( popupTimeout );
2217            tooltip.remove();
2218            tooltip.unbind();
2219            tooltip = null;
2220            $body = null;
2221          });
2222        }
2223      };
2224    };
2225  }];
2226})
2227
2228.directive( 'tooltipPopup', function () {
2229  return {
2230    restrict: 'E',
2231    replace: true,
2232    scope: { content: '@', placement: '@', animation: '&', isOpen: '&' },
2233    templateUrl: 'template/tooltip/tooltip-popup.html'
2234  };
2235})
2236
2237.directive( 'tooltip', [ '$tooltip', function ( $tooltip ) {
2238  return $tooltip( 'tooltip', 'tooltip', 'mouseenter' );
2239}])
2240
2241.directive( 'tooltipHtmlUnsafePopup', function () {
2242  return {
2243    restrict: 'E',
2244    replace: true,
2245    scope: { content: '@', placement: '@', animation: '&', isOpen: '&' },
2246    templateUrl: 'template/tooltip/tooltip-html-unsafe-popup.html'
2247  };
2248})
2249
2250.directive( 'tooltipHtmlUnsafe', [ '$tooltip', function ( $tooltip ) {
2251  return $tooltip( 'tooltipHtmlUnsafe', 'tooltip', 'mouseenter' );
2252}]);
2253
2254/**
2255 * The following features are still outstanding: popup delay, animation as a
2256 * function, placement as a function, inside, support for more triggers than
2257 * just mouse enter/leave, html popovers, and selector delegatation.
2258 */
2259angular.module( 'ui.bootstrap.popover', [ 'ui.bootstrap.tooltip' ] )
2260.directive( 'popoverPopup', function () {
2261  return {
2262    restrict: 'EA',
2263    replace: true,
2264    scope: { title: '@', content: '@', placement: '@', animation: '&', isOpen: '&' },
2265    templateUrl: 'template/popover/popover.html'
2266  };
2267})
2268.directive( 'popover', [ '$compile', '$timeout', '$parse', '$window', '$tooltip', function ( $compile, $timeout, $parse, $window, $tooltip ) {
2269  return $tooltip( 'popover', 'popover', 'click' );
2270}]);
2271
2272
2273angular.module('ui.bootstrap.progressbar', ['ui.bootstrap.transition'])
2274
2275.constant('progressConfig', {
2276  animate: true,
2277  autoType: false,
2278  stackedTypes: ['success', 'info', 'warning', 'danger']
2279})
2280
2281.controller('ProgressBarController', ['$scope', '$attrs', 'progressConfig', function($scope, $attrs, progressConfig) {
2282
2283    // Whether bar transitions should be animated
2284    var animate = angular.isDefined($attrs.animate) ? $scope.$eval($attrs.animate) : progressConfig.animate;
2285    var autoType = angular.isDefined($attrs.autoType) ? $scope.$eval($attrs.autoType) : progressConfig.autoType;
2286    var stackedTypes = angular.isDefined($attrs.stackedTypes) ? $scope.$eval('[' + $attrs.stackedTypes + ']') : progressConfig.stackedTypes;
2287
2288    // Create bar object
2289    this.makeBar = function(newBar, oldBar, index) {
2290        var newValue = (angular.isObject(newBar)) ? newBar.value : (newBar || 0);
2291        var oldValue =  (angular.isObject(oldBar)) ? oldBar.value : (oldBar || 0);
2292        var type = (angular.isObject(newBar) && angular.isDefined(newBar.type)) ? newBar.type : (autoType) ? getStackedType(index || 0) : null;
2293
2294        return {
2295            from: oldValue,
2296            to: newValue,
2297            type: type,
2298            animate: animate
2299        };
2300    };
2301
2302    function getStackedType(index) {
2303        return stackedTypes[index];
2304    }
2305
2306    this.addBar = function(bar) {
2307        $scope.bars.push(bar);
2308        $scope.totalPercent += bar.to;
2309    };
2310
2311    this.clearBars = function() {
2312        $scope.bars = [];
2313        $scope.totalPercent = 0;
2314    };
2315    this.clearBars();
2316}])
2317
2318.directive('progress', function() {
2319    return {
2320        restrict: 'EA',
2321        replace: true,
2322        controller: 'ProgressBarController',
2323        scope: {
2324            value: '=percent',
2325            onFull: '&',
2326            onEmpty: '&'
2327        },
2328        templateUrl: 'template/progressbar/progress.html',
2329        link: function(scope, element, attrs, controller) {
2330            scope.$watch('value', function(newValue, oldValue) {
2331                controller.clearBars();
2332
2333                if (angular.isArray(newValue)) {
2334                    // Stacked progress bar
2335                    for (var i=0, n=newValue.length; i < n; i++) {
2336                        controller.addBar(controller.makeBar(newValue[i], oldValue[i], i));
2337                    }
2338                } else {
2339                    // Simple bar
2340                    controller.addBar(controller.makeBar(newValue, oldValue));
2341                }
2342            }, true);
2343
2344            // Total percent listeners
2345            scope.$watch('totalPercent', function(value) {
2346              if (value >= 100) {
2347                scope.onFull();
2348              } else if (value <= 0) {
2349                scope.onEmpty();
2350              }
2351            }, true);
2352        }
2353    };
2354})
2355
2356.directive('progressbar', ['$transition', function($transition) {
2357    return {
2358        restrict: 'EA',
2359        replace: true,
2360        scope: {
2361            width: '=',
2362            old: '=',
2363            type: '=',
2364            animate: '='
2365        },
2366        templateUrl: 'template/progressbar/bar.html',
2367        link: function(scope, element) {
2368            scope.$watch('width', function(value) {
2369                if (scope.animate) {
2370                    element.css('width', scope.old + '%');
2371                    $transition(element, {width: value + '%'});
2372                } else {
2373                    element.css('width', value + '%');
2374                }
2375            });
2376        }
2377    };
2378}]);
2379angular.module('ui.bootstrap.rating', [])
2380
2381.constant('ratingConfig', {
2382  max: 5,
2383  stateOn: null,
2384  stateOff: null
2385})
2386
2387.controller('RatingController', ['$scope', '$attrs', '$parse', 'ratingConfig', function($scope, $attrs, $parse, ratingConfig) {
2388
2389  this.maxRange = angular.isDefined($attrs.max) ? $scope.$parent.$eval($attrs.max) : ratingConfig.max;
2390  this.stateOn = angular.isDefined($attrs.stateOn) ? $scope.$parent.$eval($attrs.stateOn) : ratingConfig.stateOn;
2391  this.stateOff = angular.isDefined($attrs.stateOff) ? $scope.$parent.$eval($attrs.stateOff) : ratingConfig.stateOff;
2392
2393  this.createRateObjects = function(states) {
2394    var defaultOptions = {
2395      stateOn: this.stateOn,
2396      stateOff: this.stateOff
2397    };
2398
2399    for (var i = 0, n = states.length; i < n; i++) {
2400      states[i] = angular.extend({ index: i }, defaultOptions, states[i]);
2401    }
2402    return states;
2403  };
2404
2405  // Get objects used in template
2406  $scope.range = angular.isDefined($attrs.ratingStates) ?  this.createRateObjects(angular.copy($scope.$parent.$eval($attrs.ratingStates))): this.createRateObjects(new Array(this.maxRange));
2407
2408  $scope.rate = function(value) {
2409    if ( $scope.readonly || $scope.value === value) {
2410      return;
2411    }
2412
2413    $scope.value = value;
2414  };
2415
2416  $scope.enter = function(value) {
2417    if ( ! $scope.readonly ) {
2418      $scope.val = value;
2419    }
2420    $scope.onHover({value: value});
2421  };
2422
2423  $scope.reset = function() {
2424    $scope.val = angular.copy($scope.value);
2425    $scope.onLeave();
2426  };
2427
2428  $scope.$watch('value', function(value) {
2429    $scope.val = value;
2430  });
2431
2432  $scope.readonly = false;
2433  if ($attrs.readonly) {
2434    $scope.$parent.$watch($parse($attrs.readonly), function(value) {
2435      $scope.readonly = !!value;
2436    });
2437  }
2438}])
2439
2440.directive('rating', function() {
2441  return {
2442    restrict: 'EA',
2443    scope: {
2444      value: '=',
2445      onHover: '&',
2446      onLeave: '&'
2447    },
2448    controller: 'RatingController',
2449    templateUrl: 'template/rating/rating.html',
2450    replace: true
2451  };
2452});
2453
2454/**
2455 * @ngdoc overview
2456 * @name ui.bootstrap.tabs
2457 *
2458 * @description
2459 * AngularJS version of the tabs directive.
2460 */
2461
2462angular.module('ui.bootstrap.tabs', [])
2463
2464.directive('tabs', function() {
2465  return function() {
2466    throw new Error("The `tabs` directive is deprecated, please migrate to `tabset`. Instructions can be found at http://github.com/angular-ui/bootstrap/tree/master/CHANGELOG.md");
2467  };
2468})
2469
2470.controller('TabsetController', ['$scope', function TabsetCtrl($scope) {
2471  var ctrl = this,
2472      tabs = ctrl.tabs = $scope.tabs = [];
2473
2474  ctrl.select = function(tab) {
2475    angular.forEach(tabs, function(tab) {
2476      tab.active = false;
2477    });
2478    tab.active = true;
2479  };
2480
2481  ctrl.addTab = function addTab(tab) {
2482    tabs.push(tab);
2483    if (tabs.length === 1 || tab.active) {
2484      ctrl.select(tab);
2485    }
2486  };
2487
2488  ctrl.removeTab = function removeTab(tab) {
2489    var index = tabs.indexOf(tab);
2490    //Select a new tab if the tab to be removed is selected
2491    if (tab.active && tabs.length > 1) {
2492      //If this is the last tab, select the previous tab. else, the next tab.
2493      var newActiveIndex = index == tabs.length - 1 ? index - 1 : index + 1;
2494      ctrl.select(tabs[newActiveIndex]);
2495    }
2496    tabs.splice(index, 1);
2497  };
2498}])
2499
2500/**
2501 * @ngdoc directive
2502 * @name ui.bootstrap.tabs.directive:tabset
2503 * @restrict EA
2504 *
2505 * @description
2506 * Tabset is the outer container for the tabs directive
2507 *
2508 * @param {boolean=} vertical Whether or not to use vertical styling for the tabs.
2509 * @param {string=} direction  What direction the tabs should be rendered. Available:
2510 * 'right', 'left', 'below'.
2511 *
2512 * @example
2513<example module="ui.bootstrap">
2514  <file name="index.html">
2515    <tabset>
2516      <tab heading="Vertical Tab 1"><b>First</b> Content!</tab>
2517      <tab heading="Vertical Tab 2"><i>Second</i> Content!</tab>
2518    </tabset>
2519    <hr />
2520    <tabset vertical="true">
2521      <tab heading="Vertical Tab 1"><b>First</b> Vertical Content!</tab>
2522      <tab heading="Vertical Tab 2"><i>Second</i> Vertical Content!</tab>
2523    </tabset>
2524  </file>
2525</example>
2526 */
2527.directive('tabset', function() {
2528  return {
2529    restrict: 'EA',
2530    transclude: true,
2531    replace: true,
2532    require: '^tabset',
2533    scope: {},
2534    controller: 'TabsetController',
2535    templateUrl: 'template/tabs/tabset.html',
2536    compile: function(elm, attrs, transclude) {
2537      return function(scope, element, attrs, tabsetCtrl) {
2538        scope.vertical = angular.isDefined(attrs.vertical) ? scope.$parent.$eval(attrs.vertical) : false;
2539        scope.type = angular.isDefined(attrs.type) ? scope.$parent.$eval(attrs.type) : 'tabs';
2540        scope.direction = angular.isDefined(attrs.direction) ? scope.$parent.$eval(attrs.direction) : 'top';
2541        scope.tabsAbove = (scope.direction != 'below');
2542        tabsetCtrl.$scope = scope;
2543        tabsetCtrl.$transcludeFn = transclude;
2544      };
2545    }
2546  };
2547})
2548
2549/**
2550 * @ngdoc directive
2551 * @name ui.bootstrap.tabs.directive:tab
2552 * @restrict EA
2553 *
2554 * @param {string=} heading The visible heading, or title, of the tab. Set HTML headings with {@link ui.bootstrap.tabs.directive:tabHeading tabHeading}.
2555 * @param {string=} select An expression to evaluate when the tab is selected.
2556 * @param {boolean=} active A binding, telling whether or not this tab is selected.
2557 * @param {boolean=} disabled A binding, telling whether or not this tab is disabled.
2558 *
2559 * @description
2560 * Creates a tab with a heading and content. Must be placed within a {@link ui.bootstrap.tabs.directive:tabset tabset}.
2561 *
2562 * @example
2563<example module="ui.bootstrap">
2564  <file name="index.html">
2565    <div ng-controller="TabsDemoCtrl">
2566      <button class="btn btn-small" ng-click="items[0].active = true">
2567        Select item 1, using active binding
2568      </button>
2569      <button class="btn btn-small" ng-click="items[1].disabled = !items[1].disabled">
2570        Enable/disable item 2, using disabled binding
2571      </button>
2572      <br />
2573      <tabset>
2574        <tab heading="Tab 1">First Tab</tab>
2575        <tab select="alertMe()">
2576          <tab-heading><i class="icon-bell"></i> Alert me!</tab-heading>
2577          Second Tab, with alert callback and html heading!
2578        </tab>
2579        <tab ng-repeat="item in items"
2580          heading="{{item.title}}"
2581          disabled="item.disabled"
2582          active="item.active">
2583          {{item.content}}
2584        </tab>
2585      </tabset>
2586    </div>
2587  </file>
2588  <file name="script.js">
2589    function TabsDemoCtrl($scope) {
2590      $scope.items = [
2591        { title:"Dynamic Title 1", content:"Dynamic Item 0" },
2592        { title:"Dynamic Title 2", content:"Dynamic Item 1", disabled: true }
2593      ];
2594
2595      $scope.alertMe = function() {
2596        setTimeout(function() {
2597          alert("You've selected the alert tab!");
2598        });
2599      };
2600    };
2601  </file>
2602</example>
2603 */
2604
2605/**
2606 * @ngdoc directive
2607 * @name ui.bootstrap.tabs.directive:tabHeading
2608 * @restrict EA
2609 *
2610 * @description
2611 * Creates an HTML heading for a {@link ui.bootstrap.tabs.directive:tab tab}. Must be placed as a child of a tab element.
2612 *
2613 * @example
2614<example module="ui.bootstrap">
2615  <file name="index.html">
2616    <tabset>
2617      <tab>
2618        <tab-heading><b>HTML</b> in my titles?!</tab-heading>
2619        And some content, too!
2620      </tab>
2621      <tab>
2622        <tab-heading><i class="icon-heart"></i> Icon heading?!?</tab-heading>
2623        That's right.
2624      </tab>
2625    </tabset>
2626  </file>
2627</example>
2628 */
2629.directive('tab', ['$parse', function($parse) {
2630  return {
2631    require: '^tabset',
2632    restrict: 'EA',
2633    replace: true,
2634    templateUrl: 'template/tabs/tab.html',
2635    transclude: true,
2636    scope: {
2637      heading: '@',
2638      onSelect: '&select', //This callback is called in contentHeadingTransclude
2639                          //once it inserts the tab's content into the dom
2640      onDeselect: '&deselect'
2641    },
2642    controller: function() {
2643      //Empty controller so other directives can require being 'under' a tab
2644    },
2645    compile: function(elm, attrs, transclude) {
2646      return function postLink(scope, elm, attrs, tabsetCtrl) {
2647        var getActive, setActive;
2648        if (attrs.active) {
2649          getActive = $parse(attrs.active);
2650          setActive = getActive.assign;
2651          scope.$parent.$watch(getActive, function updateActive(value, oldVal) {
2652            // Avoid re-initializing scope.active as it is already initialized
2653            // below. (watcher is called async during init with value ===
2654            // oldVal)
2655            if (value !== oldVal) {
2656              scope.active = !!value;
2657            }
2658          });
2659          scope.active = getActive(scope.$parent);
2660        } else {
2661          setActive = getActive = angular.noop;
2662        }
2663
2664        scope.$watch('active', function(active) {
2665          // Note this watcher also initializes and assigns scope.active to the
2666          // attrs.active expression.
2667          setActive(scope.$parent, active);
2668          if (active) {
2669            tabsetCtrl.select(scope);
2670            scope.onSelect();
2671          } else {
2672            scope.onDeselect();
2673          }
2674        });
2675
2676        scope.disabled = false;
2677        if ( attrs.disabled ) {
2678          scope.$parent.$watch($parse(attrs.disabled), function(value) {
2679            scope.disabled = !! value;
2680          });
2681        }
2682
2683        scope.select = function() {
2684          if ( ! scope.disabled ) {
2685            scope.active = true;
2686          }
2687        };
2688
2689        tabsetCtrl.addTab(scope);
2690        scope.$on('$destroy', function() {
2691          tabsetCtrl.removeTab(scope);
2692        });
2693
2694
2695        //We need to transclude later, once the content container is ready.
2696        //when this link happens, we're inside a tab heading.
2697        scope.$transcludeFn = transclude;
2698      };
2699    }
2700  };
2701}])
2702
2703.directive('tabHeadingTransclude', [function() {
2704  return {
2705    restrict: 'A',
2706    require: '^tab',
2707    link: function(scope, elm, attrs, tabCtrl) {
2708      scope.$watch('headingElement', function updateHeadingElement(heading) {
2709        if (heading) {
2710          elm.html('');
2711          elm.append(heading);
2712        }
2713      });
2714    }
2715  };
2716}])
2717
2718.directive('tabContentTransclude', function() {
2719  return {
2720    restrict: 'A',
2721    require: '^tabset',
2722    link: function(scope, elm, attrs) {
2723      var tab = scope.$eval(attrs.tabContentTransclude);
2724
2725      //Now our tab is ready to be transcluded: both the tab heading area
2726      //and the tab content area are loaded.  Transclude 'em both.
2727      tab.$transcludeFn(tab.$parent, function(contents) {
2728        angular.forEach(contents, function(node) {
2729          if (isTabHeading(node)) {
2730            //Let tabHeadingTransclude know.
2731            tab.headingElement = node;
2732          } else {
2733            elm.append(node);
2734          }
2735        });
2736      });
2737    }
2738  };
2739  function isTabHeading(node) {
2740    return node.tagName &&  (
2741      node.hasAttribute('tab-heading') ||
2742      node.hasAttribute('data-tab-heading') ||
2743      node.tagName.toLowerCase() === 'tab-heading' ||
2744      node.tagName.toLowerCase() === 'data-tab-heading'
2745    );
2746  }
2747})
2748
2749.directive('tabsetTitles', function() {
2750  return {
2751    restrict: 'A',
2752    require: '^tabset',
2753    templateUrl: 'template/tabs/tabset-titles.html',
2754    replace: true,
2755    link: function(scope, elm, attrs, tabsetCtrl) {
2756      if (!scope.$eval(attrs.tabsetTitles)) {
2757        elm.remove();
2758      } else {
2759        //now that tabs location has been decided, transclude the tab titles in
2760        tabsetCtrl.$transcludeFn(tabsetCtrl.$scope.$parent, function(node) {
2761          elm.append(node);
2762        });
2763      }
2764    }
2765  };
2766});
2767
2768angular.module('ui.bootstrap.timepicker', [])
2769
2770.constant('timepickerConfig', {
2771  hourStep: 1,
2772  minuteStep: 1,
2773  showMeridian: true,
2774  meridians: ['AM', 'PM'],
2775  readonlyInput: false,
2776  mousewheel: true
2777})
2778
2779.directive('timepicker', ['$parse', '$log', 'timepickerConfig', function ($parse, $log, timepickerConfig) {
2780  return {
2781    restrict: 'EA',
2782    require:'?^ngModel',
2783    replace: true,
2784    scope: {},
2785    templateUrl: 'template/timepicker/timepicker.html',
2786    link: function(scope, element, attrs, ngModel) {
2787      if ( !ngModel ) {
2788        return; // do nothing if no ng-model
2789      }
2790
2791      var selected = new Date(), meridians = timepickerConfig.meridians;
2792
2793      var hourStep = timepickerConfig.hourStep;
2794      if (attrs.hourStep) {
2795        scope.$parent.$watch($parse(attrs.hourStep), function(value) {
2796          hourStep = parseInt(value, 10);
2797        });
2798      }
2799
2800      var minuteStep = timepickerConfig.minuteStep;
2801      if (attrs.minuteStep) {
2802        scope.$parent.$watch($parse(attrs.minuteStep), function(value) {
2803          minuteStep = parseInt(value, 10);
2804        });
2805      }
2806
2807      // 12H / 24H mode
2808      scope.showMeridian = timepickerConfig.showMeridian;
2809      if (attrs.showMeridian) {
2810        scope.$parent.$watch($parse(attrs.showMeridian), function(value) {
2811          scope.showMeridian = !!value;
2812
2813          if ( ngModel.$error.time ) {
2814            // Evaluate from template
2815            var hours = getHoursFromTemplate(), minutes = getMinutesFromTemplate();
2816            if (angular.isDefined( hours ) && angular.isDefined( minutes )) {
2817              selected.setHours( hours );
2818              refresh();
2819            }
2820          } else {
2821            updateTemplate();
2822          }
2823        });
2824      }
2825
2826      // Get scope.hours in 24H mode if valid
2827      function getHoursFromTemplate ( ) {
2828        var hours = parseInt( scope.hours, 10 );
2829        var valid = ( scope.showMeridian ) ? (hours > 0 && hours < 13) : (hours >= 0 && hours < 24);
2830        if ( !valid ) {
2831          return undefined;
2832        }
2833
2834        if ( scope.showMeridian ) {
2835          if ( hours === 12 ) {
2836            hours = 0;
2837          }
2838          if ( scope.meridian === meridians[1] ) {
2839            hours = hours + 12;
2840          }
2841        }
2842        return hours;
2843      }
2844
2845      function getMinutesFromTemplate() {
2846        var minutes = parseInt(scope.minutes, 10);
2847        return ( minutes >= 0 && minutes < 60 ) ? minutes : undefined;
2848      }
2849
2850      function pad( value ) {
2851        return ( angular.isDefined(value) && value.toString().length < 2 ) ? '0' + value : value;
2852      }
2853
2854      // Input elements
2855      var inputs = element.find('input'), hoursInputEl = inputs.eq(0), minutesInputEl = inputs.eq(1);
2856
2857      // Respond on mousewheel spin
2858      var mousewheel = (angular.isDefined(attrs.mousewheel)) ? scope.$eval(attrs.mousewheel) : timepickerConfig.mousewheel;
2859      if ( mousewheel ) {
2860
2861        var isScrollingUp = function(e) {
2862          if (e.originalEvent) {
2863            e = e.originalEvent;
2864          }
2865          //pick correct delta variable depending on event
2866          var delta = (e.wheelDelta) ? e.wheelDelta : -e.deltaY;
2867          return (e.detail || delta > 0);
2868        };
2869
2870        hoursInputEl.bind('mousewheel wheel', function(e) {
2871          scope.$apply( (isScrollingUp(e)) ? scope.incrementHours() : scope.decrementHours() );
2872          e.preventDefault();
2873        });
2874
2875        minutesInputEl.bind('mousewheel wheel', function(e) {
2876          scope.$apply( (isScrollingUp(e)) ? scope.incrementMinutes() : scope.decrementMinutes() );
2877          e.preventDefault();
2878        });
2879      }
2880
2881      scope.readonlyInput = (angular.isDefined(attrs.readonlyInput)) ? scope.$eval(attrs.readonlyInput) : timepickerConfig.readonlyInput;
2882      if ( ! scope.readonlyInput ) {
2883
2884        var invalidate = function(invalidHours, invalidMinutes) {
2885          ngModel.$setViewValue( null );
2886          ngModel.$setValidity('time', false);
2887          if (angular.isDefined(invalidHours)) {
2888            scope.invalidHours = invalidHours;
2889          }
2890          if (angular.isDefined(invalidMinutes)) {
2891            scope.invalidMinutes = invalidMinutes;
2892          }
2893        };
2894
2895        scope.updateHours = function() {
2896          var hours = getHoursFromTemplate();
2897
2898          if ( angular.isDefined(hours) ) {
2899            selected.setHours( hours );
2900            refresh( 'h' );
2901          } else {
2902            invalidate(true);
2903          }
2904        };
2905
2906        hoursInputEl.bind('blur', function(e) {
2907          if ( !scope.validHours && scope.hours < 10) {
2908            scope.$apply( function() {
2909              scope.hours = pad( scope.hours );
2910            });
2911          }
2912        });
2913
2914        scope.updateMinutes = function() {
2915          var minutes = getMinutesFromTemplate();
2916
2917          if ( angular.isDefined(minutes) ) {
2918            selected.setMinutes( minutes );
2919            refresh( 'm' );
2920          } else {
2921            invalidate(undefined, true);
2922          }
2923        };
2924
2925        minutesInputEl.bind('blur', function(e) {
2926          if ( !scope.invalidMinutes && scope.minutes < 10 ) {
2927            scope.$apply( function() {
2928              scope.minutes = pad( scope.minutes );
2929            });
2930          }
2931        });
2932      } else {
2933        scope.updateHours = angular.noop;
2934        scope.updateMinutes = angular.noop;
2935      }
2936
2937      ngModel.$render = function() {
2938        var date = ngModel.$modelValue ? new Date( ngModel.$modelValue ) : null;
2939
2940        if ( isNaN(date) ) {
2941          ngModel.$setValidity('time', false);
2942          $log.error('Timepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.');
2943        } else {
2944          if ( date ) {
2945            selected = date;
2946          }
2947          makeValid();
2948          updateTemplate();
2949        }
2950      };
2951
2952      // Call internally when we know that model is valid.
2953      function refresh( keyboardChange ) {
2954        makeValid();
2955        ngModel.$setViewValue( new Date(selected) );
2956        updateTemplate( keyboardChange );
2957      }
2958
2959      function makeValid() {
2960        ngModel.$setValidity('time', true);
2961        scope.invalidHours = false;
2962        scope.invalidMinutes = false;
2963      }
2964
2965      function updateTemplate( keyboardChange ) {
2966        var hours = selected.getHours(), minutes = selected.getMinutes();
2967
2968        if ( scope.showMeridian ) {
2969          hours = ( hours === 0 || hours === 12 ) ? 12 : hours % 12; // Convert 24 to 12 hour system
2970        }
2971        scope.hours =  keyboardChange === 'h' ? hours : pad(hours);
2972        scope.minutes = keyboardChange === 'm' ? minutes : pad(minutes);
2973        scope.meridian = selected.getHours() < 12 ? meridians[0] : meridians[1];
2974      }
2975
2976      function addMinutes( minutes ) {
2977        var dt = new Date( selected.getTime() + minutes * 60000 );
2978        selected.setHours( dt.getHours(), dt.getMinutes() );
2979        refresh();
2980      }
2981
2982      scope.incrementHours = function() {
2983        addMinutes( hourStep * 60 );
2984      };
2985      scope.decrementHours = function() {
2986        addMinutes( - hourStep * 60 );
2987      };
2988      scope.incrementMinutes = function() {
2989        addMinutes( minuteStep );
2990      };
2991      scope.decrementMinutes = function() {
2992        addMinutes( - minuteStep );
2993      };
2994      scope.toggleMeridian = function() {
2995        addMinutes( 12 * 60 * (( selected.getHours() < 12 ) ? 1 : -1) );
2996      };
2997    }
2998  };
2999}]);
3000
3001angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap.bindHtml'])
3002
3003/**
3004 * A helper service that can parse typeahead's syntax (string provided by users)
3005 * Extracted to a separate service for ease of unit testing
3006 */
3007  .factory('typeaheadParser', ['$parse', function ($parse) {
3008
3009  //                      00000111000000000000022200000000000000003333333333333330000000000044000
3010  var TYPEAHEAD_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?\s+for\s+(?:([\$\w][\$\w\d]*))\s+in\s+(.*)$/;
3011
3012  return {
3013    parse:function (input) {
3014
3015      var match = input.match(TYPEAHEAD_REGEXP), modelMapper, viewMapper, source;
3016      if (!match) {
3017        throw new Error(
3018          "Expected typeahead specification in form of '_modelValue_ (as _label_)? for _item_ in _collection_'" +
3019            " but got '" + input + "'.");
3020      }
3021
3022      return {
3023        itemName:match[3],
3024        source:$parse(match[4]),
3025        viewMapper:$parse(match[2] || match[1]),
3026        modelMapper:$parse(match[1])
3027      };
3028    }
3029  };
3030}])
3031
3032  .directive('typeahead', ['$compile', '$parse', '$q', '$timeout', '$document', '$position', 'typeaheadParser',
3033    function ($compile, $parse, $q, $timeout, $document, $position, typeaheadParser) {
3034
3035  var HOT_KEYS = [9, 13, 27, 38, 40];
3036
3037  return {
3038    require:'ngModel',
3039    link:function (originalScope, element, attrs, modelCtrl) {
3040
3041      //SUPPORTED ATTRIBUTES (OPTIONS)
3042
3043      //minimal no of characters that needs to be entered before typeahead kicks-in
3044      var minSearch = originalScope.$eval(attrs.typeaheadMinLength) || 1;
3045
3046      //minimal wait time after last character typed before typehead kicks-in
3047      var waitTime = originalScope.$eval(attrs.typeaheadWaitMs) || 0;
3048
3049      //should it restrict model values to the ones selected from the popup only?
3050      var isEditable = originalScope.$eval(attrs.typeaheadEditable) !== false;
3051
3052      //binding to a variable that indicates if matches are being retrieved asynchronously
3053      var isLoadingSetter = $parse(attrs.typeaheadLoading).assign || angular.noop;
3054
3055      //a callback executed when a match is selected
3056      var onSelectCallback = $parse(attrs.typeaheadOnSelect);
3057
3058      var inputFormatter = attrs.typeaheadInputFormatter ? $parse(attrs.typeaheadInputFormatter) : undefined;
3059
3060      //INTERNAL VARIABLES
3061
3062      //model setter executed upon match selection
3063      var $setModelValue = $parse(attrs.ngModel).assign;
3064
3065      //expressions used by typeahead
3066      var parserResult = typeaheadParser.parse(attrs.typeahead);
3067
3068      var hasFocus;
3069
3070      //pop-up element used to display matches
3071      var popUpEl = angular.element('<div typeahead-popup></div>');
3072      popUpEl.attr({
3073        matches: 'matches',
3074        active: 'activeIdx',
3075        select: 'select(activeIdx)',
3076        query: 'query',
3077        position: 'position'
3078      });
3079      //custom item template
3080      if (angular.isDefined(attrs.typeaheadTemplateUrl)) {
3081        popUpEl.attr('template-url', attrs.typeaheadTemplateUrl);
3082      }
3083
3084      //create a child scope for the typeahead directive so we are not polluting original scope
3085      //with typeahead-specific data (matches, query etc.)
3086      var scope = originalScope.$new();
3087      originalScope.$on('$destroy', function(){
3088        scope.$destroy();
3089      });
3090
3091      var resetMatches = function() {
3092        scope.matches = [];
3093        scope.activeIdx = -1;
3094      };
3095
3096      var getMatchesAsync = function(inputValue) {
3097
3098        var locals = {$viewValue: inputValue};
3099        isLoadingSetter(originalScope, true);
3100        $q.when(parserResult.source(originalScope, locals)).then(function(matches) {
3101
3102          //it might happen that several async queries were in progress if a user were typing fast
3103          //but we are interested only in responses that correspond to the current view value
3104          if (inputValue === modelCtrl.$viewValue && hasFocus) {
3105            if (matches.length > 0) {
3106
3107              scope.activeIdx = 0;
3108              scope.matches.length = 0;
3109
3110              //transform labels
3111              for(var i=0; i<matches.length; i++) {
3112                locals[parserResult.itemName] = matches[i];
3113                scope.matches.push({
3114                  label: parserResult.viewMapper(scope, locals),
3115                  model: matches[i]
3116                });
3117              }
3118
3119              scope.query = inputValue;
3120              //position pop-up with matches - we need to re-calculate its position each time we are opening a window
3121              //with matches as a pop-up might be absolute-positioned and position of an input might have changed on a page
3122              //due to other elements being rendered
3123              scope.position = $position.position(element);
3124              scope.position.top = scope.position.top + element.prop('offsetHeight');
3125
3126            } else {
3127              resetMatches();
3128            }
3129            isLoadingSetter(originalScope, false);
3130          }
3131        }, function(){
3132          resetMatches();
3133          isLoadingSetter(originalScope, false);
3134        });
3135      };
3136
3137      resetMatches();
3138
3139      //we need to propagate user's query so we can higlight matches
3140      scope.query = undefined;
3141
3142      //Declare the timeout promise var outside the function scope so that stacked calls can be cancelled later
3143      var timeoutPromise;
3144
3145      //plug into $parsers pipeline to open a typeahead on view changes initiated from DOM
3146      //$parsers kick-in on all the changes coming from the view as well as manually triggered by $setViewValue
3147      modelCtrl.$parsers.unshift(function (inputValue) {
3148
3149        hasFocus = true;
3150
3151        if (inputValue && inputValue.length >= minSearch) {
3152          if (waitTime > 0) {
3153            if (timeoutPromise) {
3154              $timeout.cancel(timeoutPromise);//cancel previous timeout
3155            }
3156            timeoutPromise = $timeout(function () {
3157              getMatchesAsync(inputValue);
3158            }, waitTime);
3159          } else {
3160            getMatchesAsync(inputValue);
3161          }
3162        } else {
3163          isLoadingSetter(originalScope, false);
3164          resetMatches();
3165        }
3166
3167        if (isEditable) {
3168          return inputValue;
3169        } else {
3170          if (!inputValue) {
3171            // Reset in case user had typed something previously.
3172            modelCtrl.$setValidity('editable', true);
3173            return inputValue;
3174          } else {
3175            modelCtrl.$setValidity('editable', false);
3176            return undefined;
3177          }
3178        }
3179      });
3180
3181      modelCtrl.$formatters.push(function (modelValue) {
3182
3183        var candidateViewValue, emptyViewValue;
3184        var locals = {};
3185
3186        if (inputFormatter) {
3187
3188          locals['$model'] = modelValue;
3189          return inputFormatter(originalScope, locals);
3190
3191        } else {
3192
3193          //it might happen that we don't have enough info to properly render input value
3194          //we need to check for this situation and simply return model value if we can't apply custom formatting
3195          locals[parserResult.itemName] = modelValue;
3196          candidateViewValue = parserResult.viewMapper(originalScope, locals);
3197          locals[parserResult.itemName] = undefined;
3198          emptyViewValue = parserResult.viewMapper(originalScope, locals);
3199
3200          return candidateViewValue!== emptyViewValue ? candidateViewValue : modelValue;
3201        }
3202      });
3203
3204      scope.select = function (activeIdx) {
3205        //called from within the $digest() cycle
3206        var locals = {};
3207        var model, item;
3208
3209        locals[parserResult.itemName] = item = scope.matches[activeIdx].model;
3210        model = parserResult.modelMapper(originalScope, locals);
3211        $setModelValue(originalScope, model);
3212        modelCtrl.$setValidity('editable', true);
3213
3214        onSelectCallback(originalScope, {
3215          $item: item,
3216          $model: model,
3217          $label: parserResult.viewMapper(originalScope, locals)
3218        });
3219
3220        resetMatches();
3221
3222        //return focus to the input element if a mach was selected via a mouse click event
3223        element[0].focus();
3224      };
3225
3226      //bind keyboard events: arrows up(38) / down(40), enter(13) and tab(9), esc(27)
3227      element.bind('keydown', function (evt) {
3228
3229        //typeahead is open and an "interesting" key was pressed
3230        if (scope.matches.length === 0 || HOT_KEYS.indexOf(evt.which) === -1) {
3231          if (evt.which === 13) {
3232            evt.preventDefault();
3233          }
3234          return;
3235        }
3236
3237        evt.preventDefault();
3238
3239        if (evt.which === 40) {
3240          scope.activeIdx = (scope.activeIdx + 1) % scope.matches.length;
3241          scope.$digest();
3242
3243        } else if (evt.which === 38) {
3244          scope.activeIdx = (scope.activeIdx ? scope.activeIdx : scope.matches.length) - 1;
3245          scope.$digest();
3246
3247        } else if (evt.which === 13 || evt.which === 9) {
3248          scope.$apply(function () {
3249            scope.select(scope.activeIdx);
3250          });
3251
3252        } else if (evt.which === 27) {
3253          evt.stopPropagation();
3254
3255          resetMatches();
3256          scope.$digest();
3257        }
3258      });
3259
3260      element.bind('blur', function (evt) {
3261        hasFocus = false;
3262      });
3263
3264      // Keep reference to click handler to unbind it.
3265      var dismissClickHandler = function (evt) {
3266        if (element[0] !== evt.target) {
3267          resetMatches();
3268          scope.$digest();
3269        }
3270      };
3271
3272      $document.bind('click', dismissClickHandler);
3273
3274      originalScope.$on('$destroy', function(){
3275        $document.unbind('click', dismissClickHandler);
3276      });
3277
3278      element.after($compile(popUpEl)(scope));
3279    }
3280  };
3281
3282}])
3283
3284  .directive('typeaheadPopup', function () {
3285    return {
3286      restrict:'EA',
3287      scope:{
3288        matches:'=',
3289        query:'=',
3290        active:'=',
3291        position:'=',
3292        select:'&'
3293      },
3294      replace:true,
3295      templateUrl:'template/typeahead/typeahead-popup.html',
3296      link:function (scope, element, attrs) {
3297
3298        scope.templateUrl = attrs.templateUrl;
3299
3300        scope.isOpen = function () {
3301          return scope.matches.length > 0;
3302        };
3303
3304        scope.isActive = function (matchIdx) {
3305          return scope.active == matchIdx;
3306        };
3307
3308        scope.selectActive = function (matchIdx) {
3309          scope.active = matchIdx;
3310        };
3311
3312        scope.selectMatch = function (activeIdx) {
3313          scope.select({activeIdx:activeIdx});
3314        };
3315      }
3316    };
3317  })
3318
3319  .directive('typeaheadMatch', ['$http', '$templateCache', '$compile', '$parse', function ($http, $templateCache, $compile, $parse) {
3320    return {
3321      restrict:'EA',
3322      scope:{
3323        index:'=',
3324        match:'=',
3325        query:'='
3326      },
3327      link:function (scope, element, attrs) {
3328        var tplUrl = $parse(attrs.templateUrl)(scope.$parent) || 'template/typeahead/typeahead-match.html';
3329        $http.get(tplUrl, {cache: $templateCache}).success(function(tplContent){
3330           element.replaceWith($compile(tplContent.trim())(scope));
3331        });
3332      }
3333    };
3334  }])
3335
3336  .filter('typeaheadHighlight', function() {
3337
3338    function escapeRegexp(queryToEscape) {
3339      return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
3340    }
3341
3342    return function(matchItem, query) {
3343      return query ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '<strong>$&</strong>') : matchItem;
3344    };
3345  });
3346angular.module("template/accordion/accordion-group.html", []).run(["$templateCache", function($templateCache) {
3347  $templateCache.put("template/accordion/accordion-group.html",
3348    "<div class=\"accordion-group\">\n" +
3349    "  <div class=\"accordion-heading\" ><a class=\"accordion-toggle\" ng-click=\"isOpen = !isOpen\" accordion-transclude=\"heading\">{{heading}}</a></div>\n" +
3350    "  <div class=\"accordion-body\" collapse=\"!isOpen\">\n" +
3351    "    <div class=\"accordion-inner\" ng-transclude></div>  </div>\n" +
3352    "</div>");
3353}]);
3354
3355angular.module("template/accordion/accordion.html", []).run(["$templateCache", function($templateCache) {
3356  $templateCache.put("template/accordion/accordion.html",
3357    "<div class=\"accordion\" ng-transclude></div>");
3358}]);
3359
3360angular.module("template/alert/alert.html", []).run(["$templateCache", function($templateCache) {
3361  $templateCache.put("template/alert/alert.html",
3362    "<div class='alert' ng-class='type && \"alert-\" + type'>\n" +
3363    "    <button ng-show='closeable' type='button' class='close' ng-click='close()'>&times;</button>\n" +
3364    "    <div ng-transclude></div>\n" +
3365    "</div>\n" +
3366    "");
3367}]);
3368
3369angular.module("template/carousel/carousel.html", []).run(["$templateCache", function($templateCache) {
3370  $templateCache.put("template/carousel/carousel.html",
3371    "<div ng-mouseenter=\"pause()\" ng-mouseleave=\"play()\" class=\"carousel\">\n" +
3372    "    <ol class=\"carousel-indicators\" ng-show=\"slides().length > 1\">\n" +
3373    "        <li ng-repeat=\"slide in slides()\" ng-class=\"{active: isActive(slide)}\" ng-click=\"select(slide)\"></li>\n" +
3374    "    </ol>\n" +
3375    "    <div class=\"carousel-inner\" ng-transclude></div>\n" +
3376    "    <a ng-click=\"prev()\" class=\"carousel-control left\" ng-show=\"slides().length > 1\">&lsaquo;</a>\n" +
3377    "    <a ng-click=\"next()\" class=\"carousel-control right\" ng-show=\"slides().length > 1\">&rsaquo;</a>\n" +
3378    "</div>\n" +
3379    "");
3380}]);
3381
3382angular.module("template/carousel/slide.html", []).run(["$templateCache", function($templateCache) {
3383  $templateCache.put("template/carousel/slide.html",
3384    "<div ng-class=\"{\n" +
3385    "    'active': leaving || (active && !entering),\n" +
3386    "    'prev': (next || active) && direction=='prev',\n" +
3387    "    'next': (next || active) && direction=='next',\n" +
3388    "    'right': direction=='prev',\n" +
3389    "    'left': direction=='next'\n" +
3390    "  }\" class=\"item\" ng-transclude></div>\n" +
3391    "");
3392}]);
3393
3394angular.module("template/datepicker/datepicker.html", []).run(["$templateCache", function($templateCache) {
3395  $templateCache.put("template/datepicker/datepicker.html",
3396    "<table>\n" +
3397    "  <thead>\n" +
3398    "    <tr class=\"text-center\">\n" +
3399    "      <th><button type=\"button\" class=\"btn pull-left\" ng-click=\"move(-1)\"><i class=\"icon-chevron-left\"></i></button></th>\n" +
3400    "      <th colspan=\"{{rows[0].length - 2 + showWeekNumbers}}\"><button type=\"button\" class=\"btn btn-block\" ng-click=\"toggleMode()\"><strong>{{title}}</strong></button></th>\n" +
3401    "      <th><button type=\"button\" class=\"btn pull-right\" ng-click=\"move(1)\"><i class=\"icon-chevron-right\"></i></button></th>\n" +
3402    "    </tr>\n" +
3403    "    <tr class=\"text-center\" ng-show=\"labels.length > 0\">\n" +
3404    "      <th ng-show=\"showWeekNumbers\">#</th>\n" +
3405    "      <th ng-repeat=\"label in labels\">{{label}}</th>\n" +
3406    "    </tr>\n" +
3407    "  </thead>\n" +
3408    "  <tbody>\n" +
3409    "    <tr ng-repeat=\"row in rows\">\n" +
3410    "      <td ng-show=\"showWeekNumbers\" class=\"text-center\"><em>{{ getWeekNumber(row) }}</em></td>\n" +
3411    "      <td ng-repeat=\"dt in row\" class=\"text-center\">\n" +
3412    "        <button type=\"button\" style=\"width:100%;\" class=\"btn\" ng-class=\"{'btn-info': dt.selected}\" ng-click=\"select(dt.date)\" ng-disabled=\"dt.disabled\"><span ng-class=\"{muted: dt.secondary}\">{{dt.label}}</span></button>\n" +
3413    "      </td>\n" +
3414    "    </tr>\n" +
3415    "  </tbody>\n" +
3416    "</table>\n" +
3417    "");
3418}]);
3419
3420angular.module("template/datepicker/popup.html", []).run(["$templateCache", function($templateCache) {
3421  $templateCache.put("template/datepicker/popup.html",
3422    "<ul class=\"dropdown-menu\" ng-style=\"{display: (isOpen && 'block') || 'none', top: position.top+'px', left: position.left+'px'}\">\n" +
3423    "   <li ng-transclude></li>\n" +
3424    "   <li class=\"divider\"></li>\n" +
3425    "   <li style=\"padding: 9px;\">\n" +
3426    "           <span class=\"btn-group\">\n" +
3427    "                   <button type=\"button\" class=\"btn btn-small btn-inverse\" ng-click=\"today()\">{{currentText}}</button>\n" +
3428    "                   <button type=\"button\" class=\"btn btn-small btn-info\" ng-click=\"showWeeks = ! showWeeks\" ng-class=\"{active: showWeeks}\">{{toggleWeeksText}}</button>\n" +
3429    "                   <button type=\"button\" class=\"btn btn-small btn-danger\" ng-click=\"clear()\">{{clearText}}</button>\n" +
3430    "           </span>\n" +
3431    "           <button type=\"button\" class=\"btn btn-small btn-success pull-right\" ng-click=\"isOpen = false\">{{closeText}}</button>\n" +
3432    "   </li>\n" +
3433    "</ul>\n" +
3434    "");
3435}]);
3436
3437angular.module("template/modal/backdrop.html", []).run(["$templateCache", function($templateCache) {
3438  $templateCache.put("template/modal/backdrop.html",
3439    "<div class=\"modal-backdrop fade\" ng-class=\"{in: animate}\" ng-style=\"{'z-index': 1040 + index*10}\" ng-click=\"close($event)\"></div>");
3440}]);
3441
3442angular.module("template/modal/window.html", []).run(["$templateCache", function($templateCache) {
3443  $templateCache.put("template/modal/window.html",
3444    "<div class=\"modal fade {{ windowClass }}\" ng-class=\"{in: animate}\" ng-style=\"{'z-index': 1050 + index*10}\" ng-transclude></div>");
3445}]);
3446
3447angular.module("template/pagination/pager.html", []).run(["$templateCache", function($templateCache) {
3448  $templateCache.put("template/pagination/pager.html",
3449    "<div class=\"pager\">\n" +
3450    "  <ul>\n" +
3451    "    <li ng-repeat=\"page in pages\" ng-class=\"{disabled: page.disabled, previous: page.previous, next: page.next}\"><a ng-click=\"selectPage(page.number)\">{{page.text}}</a></li>\n" +
3452    "  </ul>\n" +
3453    "</div>\n" +
3454    "");
3455}]);
3456
3457angular.module("template/pagination/pagination.html", []).run(["$templateCache", function($templateCache) {
3458  $templateCache.put("template/pagination/pagination.html",
3459    "<div class=\"pagination\"><ul>\n" +
3460    "  <li ng-repeat=\"page in pages\" ng-class=\"{active: page.active, disabled: page.disabled}\"><a ng-click=\"selectPage(page.number)\">{{page.text}}</a></li>\n" +
3461    "  </ul>\n" +
3462    "</div>\n" +
3463    "");
3464}]);
3465
3466angular.module("template/tooltip/tooltip-html-unsafe-popup.html", []).run(["$templateCache", function($templateCache) {
3467  $templateCache.put("template/tooltip/tooltip-html-unsafe-popup.html",
3468    "<div class=\"tooltip {{placement}}\" ng-class=\"{ in: isOpen(), fade: animation() }\">\n" +
3469    "  <div class=\"tooltip-arrow\"></div>\n" +
3470    "  <div class=\"tooltip-inner\" bind-html-unsafe=\"content\"></div>\n" +
3471    "</div>\n" +
3472    "");
3473}]);
3474
3475angular.module("template/tooltip/tooltip-popup.html", []).run(["$templateCache", function($templateCache) {
3476  $templateCache.put("template/tooltip/tooltip-popup.html",
3477    "<div class=\"tooltip {{placement}}\" ng-class=\"{ in: isOpen(), fade: animation() }\">\n" +
3478    "  <div class=\"tooltip-arrow\"></div>\n" +
3479    "  <div class=\"tooltip-inner\" ng-bind=\"content\"></div>\n" +
3480    "</div>\n" +
3481    "");
3482}]);
3483
3484angular.module("template/popover/popover.html", []).run(["$templateCache", function($templateCache) {
3485  $templateCache.put("template/popover/popover.html",
3486    "<div class=\"popover {{placement}}\" ng-class=\"{ in: isOpen(), fade: animation() }\">\n" +
3487    "  <div class=\"arrow\"></div>\n" +
3488    "\n" +
3489    "  <div class=\"popover-inner\">\n" +
3490    "      <h3 class=\"popover-title\" ng-bind=\"title\" ng-show=\"title\"></h3>\n" +
3491    "      <div class=\"popover-content\" ng-bind=\"content\"></div>\n" +
3492    "  </div>\n" +
3493    "</div>\n" +
3494    "");
3495}]);
3496
3497angular.module("template/progressbar/bar.html", []).run(["$templateCache", function($templateCache) {
3498  $templateCache.put("template/progressbar/bar.html",
3499    "<div class=\"bar\" ng-class='type && \"bar-\" + type'></div>");
3500}]);
3501
3502angular.module("template/progressbar/progress.html", []).run(["$templateCache", function($templateCache) {
3503  $templateCache.put("template/progressbar/progress.html",
3504    "<div class=\"progress\"><progressbar ng-repeat=\"bar in bars\" width=\"bar.to\" old=\"bar.from\" animate=\"bar.animate\" type=\"bar.type\"></progressbar></div>");
3505}]);
3506
3507angular.module("template/rating/rating.html", []).run(["$templateCache", function($templateCache) {
3508  $templateCache.put("template/rating/rating.html",
3509    "<span ng-mouseleave=\"reset()\">\n" +
3510    "   <i ng-repeat=\"r in range\" ng-mouseenter=\"enter($index + 1)\" ng-click=\"rate($index + 1)\" ng-class=\"$index < val && (r.stateOn || 'icon-star') || (r.stateOff || 'icon-star-empty')\"></i>\n" +
3511    "</span>");
3512}]);
3513
3514angular.module("template/tabs/tab.html", []).run(["$templateCache", function($templateCache) {
3515  $templateCache.put("template/tabs/tab.html",
3516    "<li ng-class=\"{active: active, disabled: disabled}\">\n" +
3517    "  <a ng-click=\"select()\" tab-heading-transclude>{{heading}}</a>\n" +
3518    "</li>\n" +
3519    "");
3520}]);
3521
3522angular.module("template/tabs/tabset-titles.html", []).run(["$templateCache", function($templateCache) {
3523  $templateCache.put("template/tabs/tabset-titles.html",
3524    "<ul class=\"nav {{type && 'nav-' + type}}\" ng-class=\"{'nav-stacked': vertical}\">\n" +
3525    "</ul>\n" +
3526    "");
3527}]);
3528
3529angular.module("template/tabs/tabset.html", []).run(["$templateCache", function($templateCache) {
3530  $templateCache.put("template/tabs/tabset.html",
3531    "\n" +
3532    "<div class=\"tabbable\" ng-class=\"{'tabs-right': direction == 'right', 'tabs-left': direction == 'left', 'tabs-below': direction == 'below'}\">\n" +
3533    "  <div tabset-titles=\"tabsAbove\"></div>\n" +
3534    "  <div class=\"tab-content\">\n" +
3535    "    <div class=\"tab-pane\" \n" +
3536    "         ng-repeat=\"tab in tabs\" \n" +
3537    "         ng-class=\"{active: tab.active}\"\n" +
3538    "         tab-content-transclude=\"tab\">\n" +
3539    "    </div>\n" +
3540    "  </div>\n" +
3541    "  <div tabset-titles=\"!tabsAbove\"></div>\n" +
3542    "</div>\n" +
3543    "");
3544}]);
3545
3546angular.module("template/timepicker/timepicker.html", []).run(["$templateCache", function($templateCache) {
3547  $templateCache.put("template/timepicker/timepicker.html",
3548    "<table class=\"form-inline\">\n" +
3549    "   <tr class=\"text-center\">\n" +
3550    "           <td><a ng-click=\"incrementHours()\" class=\"btn btn-link\"><i class=\"icon-chevron-up\"></i></a></td>\n" +
3551    "           <td>&nbsp;</td>\n" +
3552    "           <td><a ng-click=\"incrementMinutes()\" class=\"btn btn-link\"><i class=\"icon-chevron-up\"></i></a></td>\n" +
3553    "           <td ng-show=\"showMeridian\"></td>\n" +
3554    "   </tr>\n" +
3555    "   <tr>\n" +
3556    "           <td class=\"control-group\" ng-class=\"{'error': invalidHours}\"><input type=\"text\" ng-model=\"hours\" ng-change=\"updateHours()\" class=\"span1 text-center\" ng-mousewheel=\"incrementHours()\" ng-readonly=\"readonlyInput\" maxlength=\"2\"></td>\n" +
3557    "           <td>:</td>\n" +
3558    "           <td class=\"control-group\" ng-class=\"{'error': invalidMinutes}\"><input type=\"text\" ng-model=\"minutes\" ng-change=\"updateMinutes()\" class=\"span1 text-center\" ng-readonly=\"readonlyInput\" maxlength=\"2\"></td>\n" +
3559    "           <td ng-show=\"showMeridian\"><button type=\"button\" ng-click=\"toggleMeridian()\" class=\"btn text-center\">{{meridian}}</button></td>\n" +
3560    "   </tr>\n" +
3561    "   <tr class=\"text-center\">\n" +
3562    "           <td><a ng-click=\"decrementHours()\" class=\"btn btn-link\"><i class=\"icon-chevron-down\"></i></a></td>\n" +
3563    "           <td>&nbsp;</td>\n" +
3564    "           <td><a ng-click=\"decrementMinutes()\" class=\"btn btn-link\"><i class=\"icon-chevron-down\"></i></a></td>\n" +
3565    "           <td ng-show=\"showMeridian\"></td>\n" +
3566    "   </tr>\n" +
3567    "</table>\n" +
3568    "");
3569}]);
3570
3571angular.module("template/typeahead/typeahead-match.html", []).run(["$templateCache", function($templateCache) {
3572  $templateCache.put("template/typeahead/typeahead-match.html",
3573    "<a tabindex=\"-1\" bind-html-unsafe=\"match.label | typeaheadHighlight:query\"></a>");
3574}]);
3575
3576angular.module("template/typeahead/typeahead-popup.html", []).run(["$templateCache", function($templateCache) {
3577  $templateCache.put("template/typeahead/typeahead-popup.html",
3578    "<ul class=\"typeahead dropdown-menu\" ng-style=\"{display: isOpen()&&'block' || 'none', top: position.top+'px', left: position.left+'px'}\">\n" +
3579    "    <li ng-repeat=\"match in matches\" ng-class=\"{active: isActive($index) }\" ng-mouseenter=\"selectActive($index)\" ng-click=\"selectMatch($index)\">\n" +
3580    "        <div typeahead-match index=\"$index\" match=\"match\" query=\"query\" template-url=\"templateUrl\"></div>\n" +
3581    "    </li>\n" +
3582    "</ul>");
3583}]);
Note: See TracBrowser for help on using the repository browser.