diff --git a/ui/index.html b/ui/index.html index 50f390ca3..2559612c6 100755 --- a/ui/index.html +++ b/ui/index.html @@ -100,7 +100,7 @@ - + diff --git a/ui/js/controllers/jobs.js b/ui/js/controllers/jobs.js index 4ca3a1150..5abb2cc71 100644 --- a/ui/js/controllers/jobs.js +++ b/ui/js/controllers/jobs.js @@ -29,13 +29,27 @@ treeherder.controller('JobsCtrl', } }); - thResultSets.getResultSets(). - success(function(data) { - $scope.result_sets = data; - }). - error(function(data, status, header, config) { - $scope.statusError("Error getting result sets and jobs from service"); - }); + $scope.totalItems=100; + $scope.currentPage=1; + $scope.maxSize=10; + $scope.offset = 0; + + $scope.setPage = function(pageNo) { + $scope.currentPage = pageNo; + $scope.offset = ($scope.currentPage - 1) * 10; + + + thResultSets.getResultSets($scope.offset). + success(function(data) { + $scope.result_sets = data; + }). + error(function(data, status, header, config) { + $scope.statusError("Error getting result sets and jobs from service"); + }); + + }; + + $scope.setPage($scope.currentPage); } ); diff --git a/ui/js/services.js b/ui/js/services.js index 7736f8416..df3146100 100755 --- a/ui/js/services.js +++ b/ui/js/services.js @@ -38,9 +38,13 @@ treeherder.factory('thResultSets', // get the resultsets for this repo return { - getResultSets: function() { + getResultSets: function(offset=0) { +// offset = typeof offset == 'undefined'? offset : 0; return $http.get(thUrl.getProjectUrl("/resultset/"), - {params: {exclude_empty: 1}} + {params: { + exclude_empty: 1, + offset: offset + }} ); } } diff --git a/ui/partials/jobs.html b/ui/partials/jobs.html index d508c12f5..c3256f7f4 100755 --- a/ui/partials/jobs.html +++ b/ui/partials/jobs.html @@ -1,5 +1,5 @@ - +
@@ -67,3 +67,7 @@
+
+
first
+ + \ No newline at end of file diff --git a/ui/vendor/ui-bootstrap-tpls-0.4.0.min.js b/ui/vendor/ui-bootstrap-tpls-0.4.0.min.js deleted file mode 100755 index 009c43ac6..000000000 --- a/ui/vendor/ui-bootstrap-tpls-0.4.0.min.js +++ /dev/null @@ -1,2 +0,0 @@ -angular.module("ui.bootstrap",["ui.bootstrap.tpls","ui.bootstrap.transition","ui.bootstrap.collapse","ui.bootstrap.accordion","ui.bootstrap.alert","ui.bootstrap.buttons","ui.bootstrap.carousel","ui.bootstrap.datepicker","ui.bootstrap.dialog","ui.bootstrap.dropdownToggle","ui.bootstrap.modal","ui.bootstrap.pagination","ui.bootstrap.position","ui.bootstrap.tooltip","ui.bootstrap.popover","ui.bootstrap.progressbar","ui.bootstrap.rating","ui.bootstrap.tabs","ui.bootstrap.timepicker","ui.bootstrap.typeahead"]),angular.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/dialog/message.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.html","template/timepicker/timepicker.html","template/typeahead/typeahead.html"]),angular.module("ui.bootstrap.transition",[]).factory("$transition",["$q","$timeout","$rootScope",function(e,t,n){function a(e){for(var t in e)if(void 0!==i.style[t])return e[t]}var o=function(a,i,r){r=r||{};var l=e.defer(),s=o[r.animation?"animationEndEventName":"transitionEndEventName"],c=function(){n.$apply(function(){a.unbind(s,c),l.resolve(a)})};return s&&a.bind(s,c),t(function(){angular.isString(i)?a.addClass(i):angular.isFunction(i)?i(a):angular.isObject(i)&&a.css(i),s||l.resolve(a)}),l.promise.cancel=function(){s&&a.unbind(s,c),l.reject("Transition cancelled")},l.promise},i=document.createElement("trans"),r={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",transition:"transitionend"},l={WebkitTransition:"webkitAnimationEnd",MozTransition:"animationend",OTransition:"oAnimationEnd",transition:"animationend"};return o.transitionEndEventName=a(r),o.animationEndEventName=a(l),o}]),angular.module("ui.bootstrap.collapse",["ui.bootstrap.transition"]).directive("collapse",["$transition",function(e){var t=function(e,t,n){t.removeClass("collapse"),t.css({height:n}),t[0].offsetWidth,t.addClass("collapse")};return{link:function(n,a,o){var i,r=!0;n.$watch(function(){return a[0].scrollHeight},function(){0!==a[0].scrollHeight&&(i||(r?t(n,a,a[0].scrollHeight+"px"):t(n,a,"auto")))}),n.$watch(o.collapse,function(e){e?u():c()});var l,s=function(t){return l&&l.cancel(),l=e(a,t),l.then(function(){l=void 0},function(){l=void 0}),l},c=function(){r?(r=!1,i||t(n,a,"auto")):s({height:a[0].scrollHeight+"px"}).then(function(){i||t(n,a,"auto")}),i=!1},u=function(){i=!0,r?(r=!1,t(n,a,0)):(t(n,a,a[0].scrollHeight+"px"),s({height:"0"}))}}}}]),angular.module("ui.bootstrap.accordion",["ui.bootstrap.collapse"]).constant("accordionConfig",{closeOthers:!0}).controller("AccordionController",["$scope","$attrs","accordionConfig",function(e,t,n){this.groups=[],this.closeOthers=function(a){var o=angular.isDefined(t.closeOthers)?e.$eval(t.closeOthers):n.closeOthers;o&&angular.forEach(this.groups,function(e){e!==a&&(e.isOpen=!1)})},this.addGroup=function(e){var t=this;this.groups.push(e),e.$on("$destroy",function(){t.removeGroup(e)})},this.removeGroup=function(e){var t=this.groups.indexOf(e);-1!==t&&this.groups.splice(this.groups.indexOf(e),1)}}]).directive("accordion",function(){return{restrict:"EA",controller:"AccordionController",transclude:!0,replace:!1,templateUrl:"template/accordion/accordion.html"}}).directive("accordionGroup",["$parse","$transition","$timeout",function(e){return{require:"^accordion",restrict:"EA",transclude:!0,replace:!0,templateUrl:"template/accordion/accordion-group.html",scope:{heading:"@"},controller:["$scope",function(){this.setHeading=function(e){this.heading=e}}],link:function(t,n,a,o){var i,r;o.addGroup(t),t.isOpen=!1,a.isOpen&&(i=e(a.isOpen),r=i.assign,t.$watch(function(){return i(t.$parent)},function(e){t.isOpen=e}),t.isOpen=i?i(t.$parent):!1),t.$watch("isOpen",function(e){e&&o.closeOthers(t),r&&r(t.$parent,e)})}}}]).directive("accordionHeading",function(){return{restrict:"EA",transclude:!0,template:"",replace:!0,require:"^accordionGroup",compile:function(e,t,n){return function(e,t,a,o){o.setHeading(n(e,function(){}))}}}}).directive("accordionTransclude",function(){return{require:"^accordionGroup",link:function(e,t,n,a){e.$watch(function(){return a[n.accordionTransclude]},function(e){e&&(t.html(""),t.append(e))})}}}),angular.module("ui.bootstrap.alert",[]).directive("alert",function(){return{restrict:"EA",templateUrl:"template/alert/alert.html",transclude:!0,replace:!0,scope:{type:"=",close:"&"},link:function(e,t,n){e.closeable="close"in n}}}),angular.module("ui.bootstrap.buttons",[]).constant("buttonConfig",{activeClass:"active",toggleEvent:"click"}).directive("btnRadio",["buttonConfig",function(e){var t=e.activeClass||"active",n=e.toggleEvent||"click";return{require:"ngModel",link:function(e,a,o,i){i.$render=function(){a.toggleClass(t,angular.equals(i.$modelValue,e.$eval(o.btnRadio)))},a.bind(n,function(){a.hasClass(t)||e.$apply(function(){i.$setViewValue(e.$eval(o.btnRadio)),i.$render()})})}}}]).directive("btnCheckbox",["buttonConfig",function(e){var t=e.activeClass||"active",n=e.toggleEvent||"click";return{require:"ngModel",link:function(e,a,o,i){var r=e.$eval(o.btnCheckboxTrue),l=e.$eval(o.btnCheckboxFalse);r=angular.isDefined(r)?r:!0,l=angular.isDefined(l)?l:!1,i.$render=function(){a.toggleClass(t,angular.equals(i.$modelValue,r))},a.bind(n,function(){e.$apply(function(){i.$setViewValue(a.hasClass(t)?l:r),i.$render()})})}}}]),angular.module("ui.bootstrap.carousel",["ui.bootstrap.transition"]).controller("CarouselController",["$scope","$timeout","$transition","$q",function(e,t,n){function a(){function n(){i?(e.next(),a()):e.pause()}o&&t.cancel(o);var r=+e.interval;!isNaN(r)&&r>=0&&(o=t(n,r))}var o,i,r=this,l=r.slides=[],s=-1;r.currentSlide=null,r.select=function(o,i){function c(){r.currentSlide&&angular.isString(i)&&!e.noTransition&&o.$element?(o.$element.addClass(i),o.$element[0].offsetWidth=o.$element[0].offsetWidth,angular.forEach(l,function(e){angular.extend(e,{direction:"",entering:!1,leaving:!1,active:!1})}),angular.extend(o,{direction:i,active:!0,entering:!0}),angular.extend(r.currentSlide||{},{direction:i,leaving:!0}),e.$currentTransition=n(o.$element,{}),function(t,n){e.$currentTransition.then(function(){u(t,n)},function(){u(t,n)})}(o,r.currentSlide)):u(o,r.currentSlide),r.currentSlide=o,s=p,a()}function u(t,n){angular.extend(t,{direction:"",active:!0,leaving:!1,entering:!1}),angular.extend(n||{},{direction:"",active:!1,leaving:!1,entering:!1}),e.$currentTransition=null}var p=l.indexOf(o);void 0===i&&(i=p>s?"next":"prev"),o&&o!==r.currentSlide&&(e.$currentTransition?(e.$currentTransition.cancel(),t(c)):c())},r.indexOfSlide=function(e){return l.indexOf(e)},e.next=function(){var t=(s+1)%l.length;return e.$currentTransition?void 0:r.select(l[t],"next")},e.prev=function(){var t=0>s-1?l.length-1:s-1;return e.$currentTransition?void 0:r.select(l[t],"prev")},e.select=function(e){r.select(e)},e.isActive=function(e){return r.currentSlide===e},e.slides=function(){return l},e.$watch("interval",a),e.play=function(){i||(i=!0,a())},e.pause=function(){e.noPause||(i=!1,o&&t.cancel(o))},r.addSlide=function(t,n){t.$element=n,l.push(t),1===l.length||t.active?(r.select(l[l.length-1]),1==l.length&&e.play()):t.active=!1},r.removeSlide=function(e){var t=l.indexOf(e);l.splice(t,1),l.length>0&&e.active?t>=l.length?r.select(l[t-1]):r.select(l[t]):s>t&&s--}}]).directive("carousel",[function(){return{restrict:"EA",transclude:!0,replace:!0,controller:"CarouselController",require:"carousel",templateUrl:"template/carousel/carousel.html",scope:{interval:"=",noTransition:"=",noPause:"="}}}]).directive("slide",["$parse",function(e){return{require:"^carousel",restrict:"EA",transclude:!0,replace:!0,templateUrl:"template/carousel/slide.html",scope:{},link:function(t,n,a,o){if(a.active){var i=e(a.active),r=i.assign,l=t.active=i(t.$parent);t.$watch(function(){var e=i(t.$parent);return e!==t.active&&(e!==l?l=t.active=e:r(t.$parent,e=l=t.active)),e})}o.addSlide(t,n),t.$on("$destroy",function(){o.removeSlide(t)}),t.$watch("active",function(e){e&&o.select(t)})}}}]),angular.module("ui.bootstrap.datepicker",[]).constant("datepickerConfig",{dayFormat:"dd",monthFormat:"MMMM",yearFormat:"yyyy",dayHeaderFormat:"EEE",dayTitleFormat:"MMMM yyyy",monthTitleFormat:"yyyy",showWeeks:!0,startingDay:0,yearRange:20}).directive("datepicker",["dateFilter","$parse","datepickerConfig",function(e,t,n){return{restrict:"EA",replace:!0,scope:{model:"=ngModel",dateDisabled:"&"},templateUrl:"template/datepicker/datepicker.html",link:function(a,o,r){function l(e,t,n){a.rows=e,a.labels=t,a.title=n}function s(){a.showWeekNumbers="day"===a.mode&&p}function c(e,t){return"year"===a.mode?t.getFullYear()-e.getFullYear():"month"===a.mode?new Date(t.getFullYear(),t.getMonth())-new Date(e.getFullYear(),e.getMonth()):"day"===a.mode?new Date(t.getFullYear(),t.getMonth(),t.getDate())-new Date(e.getFullYear(),e.getMonth(),e.getDate()):void 0}function u(e){return d&&c(e,d)>0||m&&0>c(e,m)||a.dateDisabled&&a.dateDisabled({date:e,mode:a.mode})}a.mode="day";var p,d,m,g=new Date,f={};f.day=angular.isDefined(r.dayFormat)?a.$eval(r.dayFormat):n.dayFormat,f.month=angular.isDefined(r.monthFormat)?a.$eval(r.monthFormat):n.monthFormat,f.year=angular.isDefined(r.yearFormat)?a.$eval(r.yearFormat):n.yearFormat,f.dayHeader=angular.isDefined(r.dayHeaderFormat)?a.$eval(r.dayHeaderFormat):n.dayHeaderFormat,f.dayTitle=angular.isDefined(r.dayTitleFormat)?a.$eval(r.dayTitleFormat):n.dayTitleFormat,f.monthTitle=angular.isDefined(r.monthTitleFormat)?a.$eval(r.monthTitleFormat):n.monthTitleFormat;var h=angular.isDefined(r.startingDay)?a.$eval(r.startingDay):n.startingDay,v=angular.isDefined(r.yearRange)?a.$eval(r.yearRange):n.yearRange;r.showWeeks?a.$parent.$watch(t(r.showWeeks),function(e){p=!!e,s()}):(p=n.showWeeks,s()),r.min&&a.$parent.$watch(t(r.min),function(e){d=new Date(e),w()}),r.max&&a.$parent.$watch(t(r.max),function(e){m=new Date(e),w()});var b=function(e,t){for(var n=[];e.length>0;)n.push(e.splice(0,t));return n},$=function(e,t){return new Date(e,t+1,0).getDate()},y={day:function(){function t(t,a,i){for(var r=0;a>r;r++)n.push({date:new Date(t),isCurrent:i,isSelected:k(t),label:e(t,f.day),disabled:u(t)}),t.setDate(t.getDate()+1);o=t}var n=[],a=[],o=null,r=new Date(g);r.setDate(1);var s=h-r.getDay(),c=s>0?7-s:-s;for(c>0&&(r.setDate(-c+1),t(r,c,!1)),t(o||r,$(g.getFullYear(),g.getMonth()),!0),t(o,(7-n.length%7)%7,!1),i=0;7>i;i++)a.push(e(n[i].date,f.dayHeader));l(b(n,7),a,e(g,f.dayTitle))},month:function(){for(var t=[],n=0,a=g.getFullYear();12>n;){var o=new Date(a,n++,1);t.push({date:o,isCurrent:!0,isSelected:k(o),label:e(o,f.month),disabled:u(o)})}l(b(t,3),[],e(g,f.monthTitle))},year:function(){for(var t=[],n=parseInt((g.getFullYear()-1)/v,10)*v+1,a=0;v>a;a++){var o=new Date(n+a,0,1);t.push({date:o,isCurrent:!0,isSelected:k(o),label:e(o,f.year),disabled:u(o)})}var i=t[0].label+" - "+t[t.length-1].label;l(b(t,5),[],i)}},w=function(){y[a.mode]()},k=function(e){if(a.model&&a.model.getFullYear()===e.getFullYear()){if("year"===a.mode)return!0;if(a.model.getMonth()===e.getMonth())return"month"===a.mode||"day"===a.mode&&a.model.getDate()===e.getDate()}return!1};a.$watch("model",function(e,t){angular.isDate(e)&&(g=angular.copy(e)),angular.equals(e,t)||w()}),a.$watch("mode",function(){s(),w()}),a.select=function(e){g=new Date(e),"year"===a.mode?(a.mode="month",g.setFullYear(e.getFullYear())):"month"===a.mode?(a.mode="day",g.setMonth(e.getMonth())):"day"===a.mode&&(a.model=new Date(g))},a.move=function(e){"day"===a.mode?g.setMonth(g.getMonth()+e):"month"===a.mode?g.setFullYear(g.getFullYear()+e):"year"===a.mode&&g.setFullYear(g.getFullYear()+e*v),w()},a.toggleMode=function(){a.mode="day"===a.mode?"month":"month"===a.mode?"year":"day"},a.getWeekNumber=function(e){if("day"===a.mode&&a.showWeekNumbers&&7===e.length){var t=h>4?11-h:4-h,n=new Date(e[t].date);return n.setHours(0,0,0),Math.ceil(((n-new Date(n.getFullYear(),0,1))/864e5+1)/7)}}}}}]);var dialogModule=angular.module("ui.bootstrap.dialog",["ui.bootstrap.transition"]);dialogModule.controller("MessageBoxController",["$scope","dialog","model",function(e,t,n){e.title=n.title,e.message=n.message,e.buttons=n.buttons,e.close=function(e){t.close(e)}}]),dialogModule.provider("$dialog",function(){var e={backdrop:!0,dialogClass:"modal",backdropClass:"modal-backdrop",transitionClass:"fade",triggerClass:"in",resolve:{},backdropFade:!1,dialogFade:!1,keyboard:!0,backdropClick:!0},t={},n={value:0};this.options=function(e){t=e},this.$get=["$http","$document","$compile","$rootScope","$controller","$templateCache","$q","$transition","$injector",function(a,o,i,r,l,s,c,u,p){function d(e){var t=angular.element("
");return t.addClass(e),t}function m(n){var a=this,o=this.options=angular.extend({},e,t,n);this._open=!1,this.backdropEl=d(o.backdropClass),o.backdropFade&&(this.backdropEl.addClass(o.transitionClass),this.backdropEl.removeClass(o.triggerClass)),this.modalEl=d(o.dialogClass),o.dialogFade&&(this.modalEl.addClass(o.transitionClass),this.modalEl.removeClass(o.triggerClass)),this.handledEscapeKey=function(e){27===e.which&&(a.close(),e.preventDefault(),a.$scope.$apply())},this.handleBackDropClick=function(e){a.close(),e.preventDefault(),a.$scope.$apply()},this.handleLocationChange=function(){a.close()}}var g=o.find("body");return m.prototype.isOpen=function(){return this._open},m.prototype.open=function(e,t){var n=this,a=this.options;if(e&&(a.templateUrl=e),t&&(a.controller=t),!a.template&&!a.templateUrl)throw Error("Dialog.open expected template or templateUrl, neither found. Use options or open method to specify them.");return this._loadResolves().then(function(e){var t=e.$scope=n.$scope=e.$scope?e.$scope:r.$new();if(n.modalEl.html(e.$template),n.options.controller){var a=l(n.options.controller,e);n.modalEl.children().data("ngControllerController",a)}i(n.modalEl)(t),n._addElementsToDom(),setTimeout(function(){n.options.dialogFade&&n.modalEl.addClass(n.options.triggerClass),n.options.backdropFade&&n.backdropEl.addClass(n.options.triggerClass)}),n._bindEvents()}),this.deferred=c.defer(),this.deferred.promise},m.prototype.close=function(e){function t(e){e.removeClass(a.options.triggerClass)}function n(){a._open&&a._onCloseComplete(e)}var a=this,o=this._getFadingElements();if(o.length>0)for(var i=o.length-1;i>=0;i--)u(o[i],t).then(n);else this._onCloseComplete(e)},m.prototype._getFadingElements=function(){var e=[];return this.options.dialogFade&&e.push(this.modalEl),this.options.backdropFade&&e.push(this.backdropEl),e},m.prototype._bindEvents=function(){this.options.keyboard&&g.bind("keydown",this.handledEscapeKey),this.options.backdrop&&this.options.backdropClick&&this.backdropEl.bind("click",this.handleBackDropClick)},m.prototype._unbindEvents=function(){this.options.keyboard&&g.unbind("keydown",this.handledEscapeKey),this.options.backdrop&&this.options.backdropClick&&this.backdropEl.unbind("click",this.handleBackDropClick)},m.prototype._onCloseComplete=function(e){this._removeElementsFromDom(),this._unbindEvents(),this.deferred.resolve(e)},m.prototype._addElementsToDom=function(){g.append(this.modalEl),this.options.backdrop&&(0===n.value&&g.append(this.backdropEl),n.value++),this._open=!0},m.prototype._removeElementsFromDom=function(){this.modalEl.remove(),this.options.backdrop&&(n.value--,0===n.value&&this.backdropEl.remove()),this._open=!1},m.prototype._loadResolves=function(){var e,t=[],n=[],o=this;return this.options.template?e=c.when(this.options.template):this.options.templateUrl&&(e=a.get(this.options.templateUrl,{cache:s}).then(function(e){return e.data})),angular.forEach(this.options.resolve||[],function(e,a){n.push(a),t.push(angular.isString(e)?p.get(e):p.invoke(e))}),n.push("$template"),t.push(e),c.all(t).then(function(e){var t={};return angular.forEach(e,function(e,a){t[n[a]]=e}),t.dialog=o,t})},{dialog:function(e){return new m(e)},messageBox:function(e,t,n){return new m({templateUrl:"template/dialog/message.html",controller:"MessageBoxController",resolve:{model:function(){return{title:e,message:t,buttons:n}}}})}}}]}),angular.module("ui.bootstrap.dropdownToggle",[]).directive("dropdownToggle",["$document","$location",function(e){var t=null,n=angular.noop;return{restrict:"CA",link:function(a,o){a.$watch("$location.path",function(){n()}),o.parent().bind("click",function(){n()}),o.bind("click",function(a){var i=o===t;a.preventDefault(),a.stopPropagation(),t&&n(),i||(o.parent().addClass("open"),t=o,n=function(a){a&&(a.preventDefault(),a.stopPropagation()),e.unbind("click",n),o.parent().removeClass("open"),n=angular.noop,t=null},e.bind("click",n))})}}}]),angular.module("ui.bootstrap.modal",["ui.bootstrap.dialog"]).directive("modal",["$parse","$dialog",function(e,t){return{restrict:"EA",terminal:!0,link:function(n,a,o){var i,r=angular.extend({},n.$eval(o.uiOptions||o.bsOptions||o.options)),l=o.modal||o.show;r=angular.extend(r,{template:a.html(),resolve:{$scope:function(){return n}}});var s=t.dialog(r);a.remove(),i=o.close?function(){e(o.close)(n)}:function(){angular.isFunction(e(l).assign)&&e(l).assign(n,!1)},n.$watch(l,function(e){e?s.open().then(function(){i()}):s.isOpen()&&s.close()})}}}]),angular.module("ui.bootstrap.pagination",[]).controller("PaginationController",["$scope",function(e){e.noPrevious=function(){return 1===e.currentPage},e.noNext=function(){return e.currentPage===e.numPages},e.isActive=function(t){return e.currentPage===t},e.selectPage=function(t){!e.isActive(t)&&t>0&&e.numPages>=t&&(e.currentPage=t,e.onSelectPage({page:t}))}}]).constant("paginationConfig",{boundaryLinks:!1,directionLinks:!0,firstText:"First",previousText:"Previous",nextText:"Next",lastText:"Last",rotate:!0}).directive("pagination",["paginationConfig",function(e){return{restrict:"EA",scope:{numPages:"=",currentPage:"=",maxSize:"=",onSelectPage:"&"},controller:"PaginationController",templateUrl:"template/pagination/pagination.html",replace:!0,link:function(t,n,a){function o(e,t,n,a){return{number:e,text:t,active:n,disabled:a}}var i=angular.isDefined(a.boundaryLinks)?t.$eval(a.boundaryLinks):e.boundaryLinks,r=angular.isDefined(a.directionLinks)?t.$eval(a.directionLinks):e.directionLinks,l=angular.isDefined(a.firstText)?t.$parent.$eval(a.firstText):e.firstText,s=angular.isDefined(a.previousText)?t.$parent.$eval(a.previousText):e.previousText,c=angular.isDefined(a.nextText)?t.$parent.$eval(a.nextText):e.nextText,u=angular.isDefined(a.lastText)?t.$parent.$eval(a.lastText):e.lastText,p=angular.isDefined(a.rotate)?t.$eval(a.rotate):e.rotate;t.$watch("numPages + currentPage + maxSize",function(){t.pages=[];var e=1,n=t.numPages,a=angular.isDefined(t.maxSize)&&t.maxSizet.numPages&&(n=t.numPages,e=n-t.maxSize+1)):(e=(Math.ceil(t.currentPage/t.maxSize)-1)*t.maxSize+1,n=Math.min(e+t.maxSize-1,t.numPages)));for(var d=e;n>=d;d++){var m=o(d,d,t.isActive(d),!1);t.pages.push(m)}if(a&&!p){if(e>1){var g=o(e-1,"...",!1,!1);t.pages.unshift(g)}if(t.numPages>n){var f=o(n+1,"...",!1,!1);t.pages.push(f)}}if(r){var h=o(t.currentPage-1,s,!1,t.noPrevious());t.pages.unshift(h);var v=o(t.currentPage+1,c,!1,t.noNext());t.pages.push(v)}if(i){var b=o(1,l,!1,t.noPrevious());t.pages.unshift(b);var $=o(t.numPages,u,!1,t.noNext());t.pages.push($)}t.currentPage>t.numPages&&t.selectPage(t.numPages)})}}}]).constant("pagerConfig",{previousText:"« Previous",nextText:"Next »",align:!0}).directive("pager",["pagerConfig",function(e){return{restrict:"EA",scope:{numPages:"=",currentPage:"=",onSelectPage:"&"},controller:"PaginationController",templateUrl:"template/pagination/pager.html",replace:!0,link:function(t,n,a){function o(e,t,n,a,o){return{number:e,text:t,disabled:n,previous:l&&a,next:l&&o}}var i=angular.isDefined(a.previousText)?t.$parent.$eval(a.previousText):e.previousText,r=angular.isDefined(a.nextText)?t.$parent.$eval(a.nextText):e.nextText,l=angular.isDefined(a.align)?t.$parent.$eval(a.align):e.align;t.$watch("numPages + currentPage",function(){t.pages=[];var e=o(t.currentPage-1,i,t.noPrevious(),!0,!1);t.pages.unshift(e);var n=o(t.currentPage+1,r,t.noNext(),!1,!0);t.pages.push(n),t.currentPage>t.numPages&&t.selectPage(t.numPages)})}}}]),angular.module("ui.bootstrap.position",[]).factory("$position",["$document","$window",function(e,t){function n(e,n){return e.currentStyle?e.currentStyle[n]:t.getComputedStyle?t.getComputedStyle(e)[n]:e.style[n]}function a(e){return"static"===(n(e,"position")||"static")}var o,i;e.bind("mousemove",function(e){o=e.pageX,i=e.pageY});var r=function(t){for(var n=e[0],o=t.offsetParent||n;o&&o!==n&&a(o);)o=o.offsetParent;return o||n};return{position:function(t){var n=this.offset(t),a={top:0,left:0},o=r(t[0]);return o!=e[0]&&(a=this.offset(angular.element(o)),a.top+=o.clientTop,a.left+=o.clientLeft),{width:t.prop("offsetWidth"),height:t.prop("offsetHeight"),top:n.top-a.top,left:n.left-a.left}},offset:function(n){var a=n[0].getBoundingClientRect();return{width:n.prop("offsetWidth"),height:n.prop("offsetHeight"),top:a.top+(t.pageYOffset||e[0].body.scrollTop),left:a.left+(t.pageXOffset||e[0].body.scrollLeft)}},mouse:function(){return{x:o,y:i}}}}]),angular.module("ui.bootstrap.tooltip",["ui.bootstrap.position"]).provider("$tooltip",function(){function e(e){var t=/[A-Z]/g,n="-";return e.replace(t,function(e,t){return(t?n:"")+e.toLowerCase()})}var t={placement:"top",animation:!0,popupDelay:0},n={mouseenter:"mouseleave",click:"click",focus:"blur"},a={};this.options=function(e){angular.extend(a,e)},this.setTriggers=function(e){angular.extend(n,e)},this.$get=["$window","$compile","$timeout","$parse","$document","$position","$interpolate",function(o,i,r,l,s,c,u){return function(o,p,d){function m(e){var t,a;return t=e||g.trigger||d,a=angular.isDefined(g.trigger)?n[g.trigger]||t:n[t]||t,{show:t,hide:a}}var g=angular.extend({},t,a),f=e(o),h=m(void 0),v=u.startSymbol(),b=u.endSymbol(),$="<"+f+"-popup "+'title="'+v+"tt_title"+b+'" '+'content="'+v+"tt_content"+b+'" '+'placement="'+v+"tt_placement"+b+'" '+'animation="tt_animation()" '+'is-open="tt_isOpen"'+">"+"";return{restrict:"EA",scope:!0,link:function(e,t,n){function a(){e.tt_isOpen?d():u()}function u(){e.tt_popupDelay?y=r(f,e.tt_popupDelay):e.$apply(f)}function d(){e.$apply(function(){v()})}function f(){var n,a,o,i;if(e.tt_content){switch(b&&r.cancel(b),k.css({top:0,left:0,display:"block"}),x?(w=w||s.find("body"),w.append(k)):t.after(k),n=g.appendToBody?c.offset(t):c.position(t),a=k.prop("offsetWidth"),o=k.prop("offsetHeight"),e.tt_placement){case"mouse":var l=c.mouse();i={top:l.y,left:l.x};break;case"right":i={top:n.top+n.height/2-o/2,left:n.left+n.width};break;case"bottom":i={top:n.top+n.height,left:n.left+n.width/2-a/2};break;case"left":i={top:n.top+n.height/2-o/2,left:n.left-a};break;default:i={top:n.top-o,left:n.left+n.width/2-a/2}}i.top+="px",i.left+="px",k.css(i),e.tt_isOpen=!0}}function v(){e.tt_isOpen=!1,r.cancel(y),angular.isDefined(e.tt_animation)&&e.tt_animation()?b=r(function(){k.remove()},500):k.remove()}var b,y,w,k=i($)(e),x=angular.isDefined(g.appendToBody)?g.appendToBody:!1;e.tt_isOpen=!1,n.$observe(o,function(t){e.tt_content=t}),n.$observe(p+"Title",function(t){e.tt_title=t}),n.$observe(p+"Placement",function(t){e.tt_placement=angular.isDefined(t)?t:g.placement}),n.$observe(p+"Animation",function(t){e.tt_animation=angular.isDefined(t)?l(t):function(){return g.animation}}),n.$observe(p+"PopupDelay",function(t){var n=parseInt(t,10);e.tt_popupDelay=isNaN(n)?g.popupDelay:n}),n.$observe(p+"Trigger",function(e){t.unbind(h.show),t.unbind(h.hide),h=m(e),h.show===h.hide?t.bind(h.show,a):(t.bind(h.show,u),t.bind(h.hide,d))}),n.$observe(p+"AppendToBody",function(t){x=angular.isDefined(t)?l(t)(e):x}),x&&e.$on("$locationChangeSuccess",function(){e.tt_isOpen&&v()}),e.$on("$destroy",function(){e.tt_isOpen?v():k.remove()})}}}}]}).directive("tooltipPopup",function(){return{restrict:"E",replace:!0,scope:{content:"@",placement:"@",animation:"&",isOpen:"&"},templateUrl:"template/tooltip/tooltip-popup.html"}}).directive("tooltip",["$tooltip",function(e){return e("tooltip","tooltip","mouseenter")}]).directive("tooltipHtmlUnsafePopup",function(){return{restrict:"E",replace:!0,scope:{content:"@",placement:"@",animation:"&",isOpen:"&"},templateUrl:"template/tooltip/tooltip-html-unsafe-popup.html"}}).directive("tooltipHtmlUnsafe",["$tooltip",function(e){return e("tooltipHtmlUnsafe","tooltip","mouseenter")}]),angular.module("ui.bootstrap.popover",["ui.bootstrap.tooltip"]).directive("popoverPopup",function(){return{restrict:"EA",replace:!0,scope:{title:"@",content:"@",placement:"@",animation:"&",isOpen:"&"},templateUrl:"template/popover/popover.html"}}).directive("popover",["$compile","$timeout","$parse","$window","$tooltip",function(e,t,n,a,o){return o("popover","popover","click")}]),angular.module("ui.bootstrap.progressbar",["ui.bootstrap.transition"]).constant("progressConfig",{animate:!0,autoType:!1,stackedTypes:["success","info","warning","danger"]}).controller("ProgressBarController",["$scope","$attrs","progressConfig",function(e,t,n){function a(e){return r[e]}var o=angular.isDefined(t.animate)?e.$eval(t.animate):n.animate,i=angular.isDefined(t.autoType)?e.$eval(t.autoType):n.autoType,r=angular.isDefined(t.stackedTypes)?e.$eval("["+t.stackedTypes+"]"):n.stackedTypes;this.makeBar=function(e,t,n){var r=angular.isObject(e)?e.value:e||0,l=angular.isObject(t)?t.value:t||0,s=angular.isObject(e)&&angular.isDefined(e.type)?e.type:i?a(n||0):null;return{from:l,to:r,type:s,animate:o}},this.addBar=function(t){e.bars.push(t),e.totalPercent+=t.to},this.clearBars=function(){e.bars=[],e.totalPercent=0},this.clearBars()}]).directive("progress",function(){return{restrict:"EA",replace:!0,controller:"ProgressBarController",scope:{value:"=percent",onFull:"&",onEmpty:"&"},templateUrl:"template/progressbar/progress.html",link:function(e,t,n,a){e.$watch("value",function(e,t){if(a.clearBars(),angular.isArray(e))for(var n=0,o=e.length;o>n;n++)a.addBar(a.makeBar(e[n],t[n],n));else a.addBar(a.makeBar(e,t))},!0),e.$watch("totalPercent",function(t){t>=100?e.onFull():0>=t&&e.onEmpty()},!0)}}}).directive("progressbar",["$transition",function(e){return{restrict:"EA",replace:!0,scope:{width:"=",old:"=",type:"=",animate:"="},templateUrl:"template/progressbar/bar.html",link:function(t,n){t.$watch("width",function(a){t.animate?(n.css("width",t.old+"%"),e(n,{width:a+"%"})):n.css("width",a+"%")})}}}]),angular.module("ui.bootstrap.rating",[]).constant("ratingConfig",{max:5}).directive("rating",["ratingConfig","$parse",function(e,t){return{restrict:"EA",scope:{value:"="},templateUrl:"template/rating/rating.html",replace:!0,link:function(n,a,o){var i=angular.isDefined(o.max)?n.$eval(o.max):e.max;n.range=[];for(var r=1;i>=r;r++)n.range.push(r);n.rate=function(e){n.readonly||(n.value=e)},n.enter=function(e){n.readonly||(n.val=e)},n.reset=function(){n.val=angular.copy(n.value)},n.reset(),n.$watch("value",function(e){n.val=e}),n.readonly=!1,o.readonly&&n.$parent.$watch(t(o.readonly),function(e){n.readonly=!!e})}}}]),angular.module("ui.bootstrap.tabs",[]).directive("tabs",function(){return function(){throw 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")}}).controller("TabsetController",["$scope","$element",function(e){var t=this,n=t.tabs=e.tabs=[];t.select=function(e){angular.forEach(n,function(e){e.active=!1}),e.active=!0},t.addTab=function(e){n.push(e),1==n.length&&t.select(e)},t.removeTab=function(e){var a=n.indexOf(e);if(e.active&&n.length>1){var o=a==n.length-1?a-1:a+1;t.select(n[o])}n.splice(a,1)}}]).directive("tabset",function(){return{restrict:"EA",transclude:!0,scope:{},controller:"TabsetController",templateUrl:"template/tabs/tabset.html",link:function(e,t,n){e.vertical=angular.isDefined(n.vertical)?e.$eval(n.vertical):!1,e.type=angular.isDefined(n.type)?e.$parent.$eval(n.type):"tabs"}}}).directive("tab",["$parse","$http","$templateCache","$compile",function(e){return{require:"^tabset",restrict:"EA",replace:!0,templateUrl:"template/tabs/tab.html",transclude:!0,scope:{heading:"@",onSelect:"&select"},controller:function(){},compile:function(t,n,a){return function(t,n,o,i){var r,l;t.active=!1,o.active?(r=e(o.active),l=r.assign,t.$parent.$watch(r,function(e){e&&t.disabled?l(t.$parent,!1):t.active=!!e})):l=r=angular.noop,t.$watch("active",function(e){l(t.$parent,e),e&&(i.select(t),t.onSelect())}),t.disabled=!1,o.disabled&&t.$parent.$watch(e(o.disabled),function(e){t.disabled=!!e}),t.select=function(){t.disabled||(t.active=!0)},i.addTab(t),t.$on("$destroy",function(){i.removeTab(t)}),t.active&&l(t.$parent,!0),a(t.$parent,function(e){var n,a=[];angular.forEach(e,function(e){e.tagName&&(e.hasAttribute("tab-heading")||e.hasAttribute("data-tab-heading")||"tab-heading"==e.tagName.toLowerCase()||"data-tab-heading"==e.tagName.toLowerCase())?n=e:a.push(e)}),n&&(t.headingElement=angular.element(n)),t.contentElement=angular.element(a)})}}}}]).directive("tabHeadingTransclude",[function(){return{restrict:"A",require:"^tab",link:function(e,t){e.$watch("headingElement",function(e){e&&(t.html(""),t.append(e))})}}}]).directive("tabContentTransclude",["$parse",function(e){return{restrict:"A",require:"^tabset",link:function(t,n,a){t.$watch(e(a.tabContentTransclude),function(e){n.html(""),e&&n.append(e.contentElement)})}}}]),angular.module("ui.bootstrap.timepicker",[]).filter("pad",function(){return function(e){return angular.isDefined(e)&&2>(""+e).length&&(e="0"+e),e}}).constant("timepickerConfig",{hourStep:1,minuteStep:1,showMeridian:!0,meridians:["AM","PM"],readonlyInput:!1,mousewheel:!0}).directive("timepicker",["padFilter","$parse","timepickerConfig",function(e,t,n){return{restrict:"EA",require:"ngModel",replace:!0,templateUrl:"template/timepicker/timepicker.html",scope:{model:"=ngModel"},link:function(a,o,i){function r(){var e=parseInt(a.hours,10),t=a.showMeridian?e>0&&13>e:e>=0&&24>e;return t?(a.showMeridian&&(12===e&&(e=0),a.meridian===u[1]&&(e+=12)),e):void 0}function l(){var t=c.getHours();a.showMeridian&&(t=0===t||12===t?12:t%12),a.hours="h"===b?t:e(t),a.validHours=!0;var n=c.getMinutes();a.minutes="m"===b?n:e(n),a.validMinutes=!0,a.meridian=a.showMeridian?12>c.getHours()?u[0]:u[1]:"",b=!1}function s(e){var t=new Date(c.getTime()+6e4*e);t.getDate()!==c.getDate()&&t.setDate(t.getDate()-1),c.setTime(t.getTime()),a.model=new Date(c)}var c=new Date,u=n.meridians,p=n.hourStep;i.hourStep&&a.$parent.$watch(t(i.hourStep),function(e){p=parseInt(e,10)});var d=n.minuteStep;i.minuteStep&&a.$parent.$watch(t(i.minuteStep),function(e){d=parseInt(e,10)}),a.showMeridian=n.showMeridian,i.showMeridian&&a.$parent.$watch(t(i.showMeridian),function(e){if(a.showMeridian=!!e,a.model)l();else{var t=new Date(c),n=r();angular.isDefined(n)&&t.setHours(n),a.model=new Date(t)}});var m=o.find("input"),g=m.eq(0),f=m.eq(1),h=angular.isDefined(i.mousewheel)?a.$eval(i.mousewheel):n.mousewheel;if(h){var v=function(e){return e.originalEvent&&(e=e.originalEvent),e.detail||e.wheelDelta>0};g.bind("mousewheel",function(e){a.$apply(v(e)?a.incrementHours():a.decrementHours()),e.preventDefault()}),f.bind("mousewheel",function(e){a.$apply(v(e)?a.incrementMinutes():a.decrementMinutes()),e.preventDefault()})}var b=!1;a.readonlyInput=angular.isDefined(i.readonlyInput)?a.$eval(i.readonlyInput):n.readonlyInput,a.readonlyInput?(a.updateHours=angular.noop,a.updateMinutes=angular.noop):(a.updateHours=function(){var e=r();angular.isDefined(e)?(b="h",null===a.model&&(a.model=new Date(c)),a.model.setHours(e)):(a.model=null,a.validHours=!1)},g.bind("blur",function(){a.validHours&&10>a.hours&&a.$apply(function(){a.hours=e(a.hours) -})}),a.updateMinutes=function(){var e=parseInt(a.minutes,10);e>=0&&60>e?(b="m",null===a.model&&(a.model=new Date(c)),a.model.setMinutes(e)):(a.model=null,a.validMinutes=!1)},f.bind("blur",function(){a.validMinutes&&10>a.minutes&&a.$apply(function(){a.minutes=e(a.minutes)})})),a.$watch(function(){return+a.model},function(e){!isNaN(e)&&e>0&&(c=new Date(e),l())}),a.incrementHours=function(){s(60*p)},a.decrementHours=function(){s(60*-p)},a.incrementMinutes=function(){s(d)},a.decrementMinutes=function(){s(-d)},a.toggleMeridian=function(){s(720*(12>c.getHours()?1:-1))}}}}]),angular.module("ui.bootstrap.typeahead",["ui.bootstrap.position"]).factory("typeaheadParser",["$parse",function(e){var t=/^\s*(.*?)(?:\s+as\s+(.*?))?\s+for\s+(?:([\$\w][\$\w\d]*))\s+in\s+(.*)$/;return{parse:function(n){var a=n.match(t);if(!a)throw Error("Expected typeahead specification in form of '_modelValue_ (as _label_)? for _item_ in _collection_' but got '"+n+"'.");return{itemName:a[3],source:e(a[4]),viewMapper:e(a[2]||a[1]),modelMapper:e(a[1])}}}}]).directive("typeahead",["$compile","$parse","$q","$timeout","$document","$position","typeaheadParser",function(e,t,n,a,o,i,r){var l=[9,13,27,38,40];return{require:"ngModel",link:function(s,c,u,p){var d,m=s.$eval(u.typeaheadMinLength)||1,g=s.$eval(u.typeaheadWaitMs)||0,f=r.parse(u.typeahead),h=s.$eval(u.typeaheadEditable)!==!1,v=t(u.typeaheadLoading).assign||angular.noop,b=t(u.typeaheadOnSelect),$=angular.element("");$.attr({matches:"matches",active:"activeIdx",select:"select(activeIdx)",query:"query",position:"position"});var y=s.$new();s.$on("$destroy",function(){y.$destroy()});var w=function(){y.matches=[],y.activeIdx=-1},k=function(e){var t={$viewValue:e};v(s,!0),n.when(f.source(y,t)).then(function(n){if(e===p.$viewValue){if(n.length>0){y.activeIdx=0,y.matches.length=0;for(var a=0;n.length>a;a++)t[f.itemName]=n[a],y.matches.push({label:f.viewMapper(y,t),model:n[a]});y.query=e,y.position=i.position(c),y.position.top=y.position.top+c.prop("offsetHeight")}else w();v(s,!1)}},function(){w(),v(s,!1)})};w(),y.query=void 0,p.$parsers.push(function(e){var t;return w(),d?e:(e&&e.length>=m&&(g>0?(t&&a.cancel(t),t=a(function(){k(e)},g)):k(e)),h?e:void 0)}),p.$render=function(){var e={};e[f.itemName]=d||p.$viewValue,c.val(f.viewMapper(y,e)||p.$viewValue),d=void 0},y.select=function(e){var t,n,a={};a[f.itemName]=n=d=y.matches[e].model,t=f.modelMapper(y,a),p.$setViewValue(t),p.$render(),b(y,{$item:n,$model:t,$label:f.viewMapper(y,a)}),c[0].focus()},c.bind("keydown",function(e){0!==y.matches.length&&-1!==l.indexOf(e.which)&&(e.preventDefault(),40===e.which?(y.activeIdx=(y.activeIdx+1)%y.matches.length,y.$digest()):38===e.which?(y.activeIdx=(y.activeIdx?y.activeIdx:y.matches.length)-1,y.$digest()):13===e.which||9===e.which?y.$apply(function(){y.select(y.activeIdx)}):27===e.which&&(e.stopPropagation(),w(),y.$digest()))}),o.bind("click",function(){w(),y.$digest()}),c.after(e($)(y))}}}]).directive("typeaheadPopup",function(){return{restrict:"E",scope:{matches:"=",query:"=",active:"=",position:"=",select:"&"},replace:!0,templateUrl:"template/typeahead/typeahead.html",link:function(e){e.isOpen=function(){return e.matches.length>0},e.isActive=function(t){return e.active==t},e.selectActive=function(t){e.active=t},e.selectMatch=function(t){e.select({activeIdx:t})}}}}).filter("typeaheadHighlight",function(){function e(e){return e.replace(/([.?*+^$[\]\\(){}|-])/g,"\\$1")}return function(t,n){return n?t.replace(RegExp(e(n),"gi"),"$&"):n}}),angular.module("template/accordion/accordion-group.html",[]).run(["$templateCache",function(e){e.put("template/accordion/accordion-group.html",'
\n \n
\n
\n
')}]),angular.module("template/accordion/accordion.html",[]).run(["$templateCache",function(e){e.put("template/accordion/accordion.html",'
')}]),angular.module("template/alert/alert.html",[]).run(["$templateCache",function(e){e.put("template/alert/alert.html","
\n \n
\n
\n")}]),angular.module("template/carousel/carousel.html",[]).run(["$templateCache",function(e){e.put("template/carousel/carousel.html",'\n')}]),angular.module("template/carousel/slide.html",[]).run(["$templateCache",function(e){e.put("template/carousel/slide.html","
\n")}]),angular.module("template/datepicker/datepicker.html",[]).run(["$templateCache",function(e){e.put("template/datepicker/datepicker.html",'\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
#{{label}}
{{ getWeekNumber(row) }}\n \n
\n')}]),angular.module("template/dialog/message.html",[]).run(["$templateCache",function(e){e.put("template/dialog/message.html",'\n\n\n')}]),angular.module("template/modal/backdrop.html",[]).run(["$templateCache",function(e){e.put("template/modal/backdrop.html",'')}]),angular.module("template/modal/window.html",[]).run(["$templateCache",function(e){e.put("template/modal/window.html",'')}]),angular.module("template/pagination/pager.html",[]).run(["$templateCache",function(e){e.put("template/pagination/pager.html",'
\n \n
\n')}]),angular.module("template/pagination/pagination.html",[]).run(["$templateCache",function(e){e.put("template/pagination/pagination.html",'\n')}]),angular.module("template/tooltip/tooltip-html-unsafe-popup.html",[]).run(["$templateCache",function(e){e.put("template/tooltip/tooltip-html-unsafe-popup.html",'
\n
\n
\n
\n')}]),angular.module("template/tooltip/tooltip-popup.html",[]).run(["$templateCache",function(e){e.put("template/tooltip/tooltip-popup.html",'
\n
\n
\n
\n')}]),angular.module("template/popover/popover.html",[]).run(["$templateCache",function(e){e.put("template/popover/popover.html",'
\n
\n\n
\n

\n
\n
\n
\n')}]),angular.module("template/progressbar/bar.html",[]).run(["$templateCache",function(e){e.put("template/progressbar/bar.html",'
')}]),angular.module("template/progressbar/progress.html",[]).run(["$templateCache",function(e){e.put("template/progressbar/progress.html",'
')}]),angular.module("template/rating/rating.html",[]).run(["$templateCache",function(e){e.put("template/rating/rating.html",'\n \n\n')}]),angular.module("template/tabs/pane.html",[]).run(["$templateCache",function(e){e.put("template/tabs/pane.html",'
\n')}]),angular.module("template/tabs/tab.html",[]).run(["$templateCache",function(e){e.put("template/tabs/tab.html",'
  • \n {{heading}}\n
  • \n')}]),angular.module("template/tabs/tabs.html",[]).run(["$templateCache",function(e){e.put("template/tabs/tabs.html",'
    \n \n
    \n
    \n')}]),angular.module("template/tabs/tabset.html",[]).run(["$templateCache",function(e){e.put("template/tabs/tabset.html",'\n
    \n \n
    \n
    \n
    \n
    \n
    \n')}]),angular.module("template/timepicker/timepicker.html",[]).run(["$templateCache",function(e){e.put("template/timepicker/timepicker.html",'\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
     
    :
     
    ')}]),angular.module("template/typeahead/typeahead.html",[]).run(["$templateCache",function(e){e.put("template/typeahead/typeahead.html",'')}]); \ No newline at end of file diff --git a/ui/vendor/ui-bootstrap-tpls-0.4.0.js b/ui/vendor/ui-bootstrap-tpls-0.6.0.js similarity index 61% rename from ui/vendor/ui-bootstrap-tpls-0.4.0.js rename to ui/vendor/ui-bootstrap-tpls-0.6.0.js index 2e9eeb984..ed018f8fe 100755 --- a/ui/vendor/ui-bootstrap-tpls-0.4.0.js +++ b/ui/vendor/ui-bootstrap-tpls-0.6.0.js @@ -1,5 +1,5 @@ -angular.module("ui.bootstrap", ["ui.bootstrap.tpls", "ui.bootstrap.transition","ui.bootstrap.collapse","ui.bootstrap.accordion","ui.bootstrap.alert","ui.bootstrap.buttons","ui.bootstrap.carousel","ui.bootstrap.datepicker","ui.bootstrap.dialog","ui.bootstrap.dropdownToggle","ui.bootstrap.modal","ui.bootstrap.pagination","ui.bootstrap.position","ui.bootstrap.tooltip","ui.bootstrap.popover","ui.bootstrap.progressbar","ui.bootstrap.rating","ui.bootstrap.tabs","ui.bootstrap.timepicker","ui.bootstrap.typeahead"]); -angular.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/dialog/message.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.html","template/timepicker/timepicker.html","template/typeahead/typeahead.html"]); +angular.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"]); +angular.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"]); angular.module('ui.bootstrap.transition', []) /** @@ -337,6 +337,16 @@ angular.module("ui.bootstrap.alert", []).directive('alert', function () { }; }); +angular.module('ui.bootstrap.bindHtml', []) + + .directive('bindHtmlUnsafe', function () { + return function (scope, element, attr) { + element.addClass('ng-binding').data('$binding', attr.bindHtmlUnsafe); + scope.$watch(attr.bindHtmlUnsafe, function bindHtmlUnsafeWatchAction(value) { + element.html(value || ''); + }); + }; + }); angular.module('ui.bootstrap.buttons', []) .constant('buttonConfig', { @@ -380,21 +390,25 @@ angular.module('ui.bootstrap.buttons', []) require:'ngModel', link:function (scope, element, attrs, ngModelCtrl) { - var trueValue = scope.$eval(attrs.btnCheckboxTrue); - var falseValue = scope.$eval(attrs.btnCheckboxFalse); + function getTrueValue() { + var trueValue = scope.$eval(attrs.btnCheckboxTrue); + return angular.isDefined(trueValue) ? trueValue : true; + } - trueValue = angular.isDefined(trueValue) ? trueValue : true; - falseValue = angular.isDefined(falseValue) ? falseValue : false; + function getFalseValue() { + var falseValue = scope.$eval(attrs.btnCheckboxFalse); + return angular.isDefined(falseValue) ? falseValue : false; + } //model -> UI ngModelCtrl.$render = function () { - element.toggleClass(activeClass, angular.equals(ngModelCtrl.$modelValue, trueValue)); + element.toggleClass(activeClass, angular.equals(ngModelCtrl.$modelValue, getTrueValue())); }; //ui->model element.bind(toggleEvent, function () { scope.$apply(function () { - ngModelCtrl.$setViewValue(element.hasClass(activeClass) ? falseValue : trueValue); + ngModelCtrl.$setViewValue(element.hasClass(activeClass) ? getFalseValue() : getTrueValue()); ngModelCtrl.$render(); }); }); @@ -404,7 +418,7 @@ angular.module('ui.bootstrap.buttons', []) /** * @ngdoc overview * @name ui.bootstrap.carousel -* +* * @description * AngularJS version of an image carousel. * @@ -435,10 +449,10 @@ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition']) } function goNext() { //If we have a slide to transition from and we have a transition type and we're allowed, go - if (self.currentSlide && angular.isString(direction) && !$scope.noTransition && nextSlide.$element) { + if (self.currentSlide && angular.isString(direction) && !$scope.noTransition && nextSlide.$element) { //We shouldn't do class manip in here, but it's the same weird thing bootstrap does. need to fix sometime nextSlide.$element.addClass(direction); - nextSlide.$element[0].offsetWidth = nextSlide.$element[0].offsetWidth; //force reflow + var reflow = nextSlide.$element[0].offsetWidth; //force reflow //Set all other slides to stop doing their stuff for the new transition angular.forEach(slides, function(slide) { @@ -477,7 +491,7 @@ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition']) $scope.next = function() { var newIndex = (currentIndex + 1) % slides.length; - + //Prevent this user-triggered transition from occurring if there is already one in progress if (!$scope.$currentTransition) { return self.select(slides[newIndex], 'next'); @@ -486,7 +500,7 @@ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition']) $scope.prev = function() { var newIndex = currentIndex - 1 < 0 ? slides.length - 1 : currentIndex - 1; - + //Prevent this user-triggered transition from occurring if there is already one in progress if (!$scope.$currentTransition) { return self.select(slides[newIndex], 'prev'); @@ -703,7 +717,7 @@ function CarouselDemoCtrl($scope) { var lastValue = scope.active = getActive(scope.$parent); scope.$watch(function parentActiveWatch() { var parentActive = getActive(scope.$parent); - + if (parentActive !== scope.active) { // we are out of sync and need to copy if (parentActive !== lastValue) { @@ -733,7 +747,87 @@ function CarouselDemoCtrl($scope) { }; }]); -angular.module('ui.bootstrap.datepicker', []) +angular.module('ui.bootstrap.position', []) + +/** + * A set of utility methods that can be use to retrieve position of DOM elements. + * It is meant to be used where we need to absolute-position DOM elements in + * relation to other, existing elements (this is the case for tooltips, popovers, + * typeahead suggestions etc.). + */ + .factory('$position', ['$document', '$window', function ($document, $window) { + + function getStyle(el, cssprop) { + if (el.currentStyle) { //IE + return el.currentStyle[cssprop]; + } else if ($window.getComputedStyle) { + return $window.getComputedStyle(el)[cssprop]; + } + // finally try and get inline style + return el.style[cssprop]; + } + + /** + * Checks if a given element is statically positioned + * @param element - raw DOM element + */ + function isStaticPositioned(element) { + return (getStyle(element, "position") || 'static' ) === 'static'; + } + + /** + * returns the closest, non-statically positioned parentOffset of a given element + * @param element + */ + var parentOffsetEl = function (element) { + var docDomEl = $document[0]; + var offsetParent = element.offsetParent || docDomEl; + while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent) ) { + offsetParent = offsetParent.offsetParent; + } + return offsetParent || docDomEl; + }; + + return { + /** + * Provides read-only equivalent of jQuery's position function: + * http://api.jquery.com/position/ + */ + position: function (element) { + var elBCR = this.offset(element); + var offsetParentBCR = { top: 0, left: 0 }; + var offsetParentEl = parentOffsetEl(element[0]); + if (offsetParentEl != $document[0]) { + offsetParentBCR = this.offset(angular.element(offsetParentEl)); + offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop; + offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft; + } + + return { + width: element.prop('offsetWidth'), + height: element.prop('offsetHeight'), + top: elBCR.top - offsetParentBCR.top, + left: elBCR.left - offsetParentBCR.left + }; + }, + + /** + * Provides read-only equivalent of jQuery's offset function: + * http://api.jquery.com/offset/ + */ + offset: function (element) { + var boundingClientRect = element[0].getBoundingClientRect(); + return { + width: element.prop('offsetWidth'), + height: element.prop('offsetHeight'), + top: boundingClientRect.top + ($window.pageYOffset || $document[0].body.scrollTop || $document[0].documentElement.scrollTop), + left: boundingClientRect.left + ($window.pageXOffset || $document[0].body.scrollLeft || $document[0].documentElement.scrollLeft) + }; + } + }; + }]); + +angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.position']) .constant('datepickerConfig', { dayFormat: 'dd', @@ -744,31 +838,139 @@ angular.module('ui.bootstrap.datepicker', []) monthTitleFormat: 'yyyy', showWeeks: true, startingDay: 0, - yearRange: 20 + yearRange: 20, + minDate: null, + maxDate: null }) -.directive( 'datepicker', ['dateFilter', '$parse', 'datepickerConfig', function (dateFilter, $parse, datepickerConfig) { +.controller('DatepickerController', ['$scope', '$attrs', 'dateFilter', 'datepickerConfig', function($scope, $attrs, dateFilter, dtConfig) { + var format = { + day: getValue($attrs.dayFormat, dtConfig.dayFormat), + month: getValue($attrs.monthFormat, dtConfig.monthFormat), + year: getValue($attrs.yearFormat, dtConfig.yearFormat), + dayHeader: getValue($attrs.dayHeaderFormat, dtConfig.dayHeaderFormat), + dayTitle: getValue($attrs.dayTitleFormat, dtConfig.dayTitleFormat), + monthTitle: getValue($attrs.monthTitleFormat, dtConfig.monthTitleFormat) + }, + startingDay = getValue($attrs.startingDay, dtConfig.startingDay), + yearRange = getValue($attrs.yearRange, dtConfig.yearRange); + + this.minDate = dtConfig.minDate ? new Date(dtConfig.minDate) : null; + this.maxDate = dtConfig.maxDate ? new Date(dtConfig.maxDate) : null; + + function getValue(value, defaultValue) { + return angular.isDefined(value) ? $scope.$parent.$eval(value) : defaultValue; + } + + function getDaysInMonth( year, month ) { + return new Date(year, month, 0).getDate(); + } + + function getDates(startDate, n) { + var dates = new Array(n); + var current = startDate, i = 0; + while (i < n) { + dates[i++] = new Date(current); + current.setDate( current.getDate() + 1 ); + } + return dates; + } + + function makeDate(date, format, isSelected, isSecondary) { + return { date: date, label: dateFilter(date, format), selected: !!isSelected, secondary: !!isSecondary }; + } + + this.modes = [ + { + name: 'day', + getVisibleDates: function(date, selected) { + var year = date.getFullYear(), month = date.getMonth(), firstDayOfMonth = new Date(year, month, 1); + var difference = startingDay - firstDayOfMonth.getDay(), + numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : - difference, + firstDate = new Date(firstDayOfMonth), numDates = 0; + + if ( numDisplayedFromPreviousMonth > 0 ) { + firstDate.setDate( - numDisplayedFromPreviousMonth + 1 ); + numDates += numDisplayedFromPreviousMonth; // Previous + } + numDates += getDaysInMonth(year, month + 1); // Current + numDates += (7 - numDates % 7) % 7; // Next + + var days = getDates(firstDate, numDates), labels = new Array(7); + for (var i = 0; i < numDates; i ++) { + var dt = new Date(days[i]); + days[i] = makeDate(dt, format.day, (selected && selected.getDate() === dt.getDate() && selected.getMonth() === dt.getMonth() && selected.getFullYear() === dt.getFullYear()), dt.getMonth() !== month); + } + for (var j = 0; j < 7; j++) { + labels[j] = dateFilter(days[j].date, format.dayHeader); + } + return { objects: days, title: dateFilter(date, format.dayTitle), labels: labels }; + }, + compare: function(date1, date2) { + return (new Date( date1.getFullYear(), date1.getMonth(), date1.getDate() ) - new Date( date2.getFullYear(), date2.getMonth(), date2.getDate() ) ); + }, + split: 7, + step: { months: 1 } + }, + { + name: 'month', + getVisibleDates: function(date, selected) { + var months = new Array(12), year = date.getFullYear(); + for ( var i = 0; i < 12; i++ ) { + var dt = new Date(year, i, 1); + months[i] = makeDate(dt, format.month, (selected && selected.getMonth() === i && selected.getFullYear() === year)); + } + return { objects: months, title: dateFilter(date, format.monthTitle) }; + }, + compare: function(date1, date2) { + return new Date( date1.getFullYear(), date1.getMonth() ) - new Date( date2.getFullYear(), date2.getMonth() ); + }, + split: 3, + step: { years: 1 } + }, + { + name: 'year', + getVisibleDates: function(date, selected) { + var years = new Array(yearRange), year = date.getFullYear(), startYear = parseInt((year - 1) / yearRange, 10) * yearRange + 1; + for ( var i = 0; i < yearRange; i++ ) { + var dt = new Date(startYear + i, 0, 1); + years[i] = makeDate(dt, format.year, (selected && selected.getFullYear() === dt.getFullYear())); + } + return { objects: years, title: [years[0].label, years[yearRange - 1].label].join(' - ') }; + }, + compare: function(date1, date2) { + return date1.getFullYear() - date2.getFullYear(); + }, + split: 5, + step: { years: yearRange } + } + ]; + + this.isDisabled = function(date, mode) { + var currentMode = this.modes[mode || 0]; + 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}))); + }; +}]) + +.directive( 'datepicker', ['dateFilter', '$parse', 'datepickerConfig', '$log', function (dateFilter, $parse, datepickerConfig, $log) { return { restrict: 'EA', replace: true, + templateUrl: 'template/datepicker/datepicker.html', scope: { - model: '=ngModel', dateDisabled: '&' }, - templateUrl: 'template/datepicker/datepicker.html', - link: function(scope, element, attrs) { - scope.mode = 'day'; // Initial mode + require: ['datepicker', '?^ngModel'], + controller: 'DatepickerController', + link: function(scope, element, attrs, ctrls) { + var datepickerCtrl = ctrls[0], ngModel = ctrls[1]; + + if (!ngModel) { + return; // do nothing if no ng-model + } // Configuration parameters - var selected = new Date(), showWeeks, minDate, maxDate, format = {}; - format.day = angular.isDefined(attrs.dayFormat) ? scope.$eval(attrs.dayFormat) : datepickerConfig.dayFormat; - format.month = angular.isDefined(attrs.monthFormat) ? scope.$eval(attrs.monthFormat) : datepickerConfig.monthFormat; - format.year = angular.isDefined(attrs.yearFormat) ? scope.$eval(attrs.yearFormat) : datepickerConfig.yearFormat; - format.dayHeader = angular.isDefined(attrs.dayHeaderFormat) ? scope.$eval(attrs.dayHeaderFormat) : datepickerConfig.dayHeaderFormat; - format.dayTitle = angular.isDefined(attrs.dayTitleFormat) ? scope.$eval(attrs.dayTitleFormat) : datepickerConfig.dayTitleFormat; - format.monthTitle = angular.isDefined(attrs.monthTitleFormat) ? scope.$eval(attrs.monthTitleFormat) : datepickerConfig.monthTitleFormat; - var startingDay = angular.isDefined(attrs.startingDay) ? scope.$eval(attrs.startingDay) : datepickerConfig.startingDay; - var yearRange = angular.isDefined(attrs.yearRange) ? scope.$eval(attrs.yearRange) : datepickerConfig.yearRange; + var mode = 0, selected = new Date(), showWeeks = datepickerConfig.showWeeks; if (attrs.showWeeks) { scope.$parent.$watch($parse(attrs.showWeeks), function(value) { @@ -776,461 +978,302 @@ angular.module('ui.bootstrap.datepicker', []) updateShowWeekNumbers(); }); } else { - showWeeks = datepickerConfig.showWeeks; updateShowWeekNumbers(); } if (attrs.min) { scope.$parent.$watch($parse(attrs.min), function(value) { - minDate = new Date(value); + datepickerCtrl.minDate = value ? new Date(value) : null; refill(); }); } if (attrs.max) { scope.$parent.$watch($parse(attrs.max), function(value) { - maxDate = new Date(value); + datepickerCtrl.maxDate = value ? new Date(value) : null; refill(); }); } - function updateCalendar (rows, labels, title) { - scope.rows = rows; - scope.labels = labels; - scope.title = title; - } - - // Define whether the week number are visible function updateShowWeekNumbers() { - scope.showWeekNumbers = ( scope.mode === 'day' && showWeeks ); - } - - function compare( date1, date2 ) { - if ( scope.mode === 'year') { - return date2.getFullYear() - date1.getFullYear(); - } else if ( scope.mode === 'month' ) { - return new Date( date2.getFullYear(), date2.getMonth() ) - new Date( date1.getFullYear(), date1.getMonth() ); - } else if ( scope.mode === 'day' ) { - return (new Date( date2.getFullYear(), date2.getMonth(), date2.getDate() ) - new Date( date1.getFullYear(), date1.getMonth(), date1.getDate() ) ); - } - } - - function isDisabled(date) { - return ((minDate && compare(date, minDate) > 0) || (maxDate && compare(date, maxDate) < 0) || (scope.dateDisabled && scope.dateDisabled({ date: date, mode: scope.mode }))); + scope.showWeekNumbers = mode === 0 && showWeeks; } // Split array into smaller arrays - var split = function(a, size) { + function split(arr, size) { var arrays = []; - while (a.length > 0) { - arrays.push(a.splice(0, size)); + while (arr.length > 0) { + arrays.push(arr.splice(0, size)); } return arrays; - }; - var getDaysInMonth = function( year, month ) { - return new Date(year, month + 1, 0).getDate(); - }; + } - var fill = { - day: function() { - var days = [], labels = [], lastDate = null; + function refill( updateSelected ) { + var date = null, valid = true; - function addDays( dt, n, isCurrentMonth ) { - for (var i =0; i < n; i ++) { - days.push( {date: new Date(dt), isCurrent: isCurrentMonth, isSelected: isSelected(dt), label: dateFilter(dt, format.day), disabled: isDisabled(dt) } ); - dt.setDate( dt.getDate() + 1 ); - } - lastDate = dt; - } + if ( ngModel.$modelValue ) { + date = new Date( ngModel.$modelValue ); - var d = new Date(selected); - d.setDate(1); - - var difference = startingDay - d.getDay(); - var numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : - difference; - - if ( numDisplayedFromPreviousMonth > 0 ) { - d.setDate( - numDisplayedFromPreviousMonth + 1 ); - addDays(d, numDisplayedFromPreviousMonth, false); - } - addDays(lastDate || d, getDaysInMonth(selected.getFullYear(), selected.getMonth()), true); - addDays(lastDate, (7 - days.length % 7) % 7, false); - - // Day labels - for (i = 0; i < 7; i++) { - labels.push( dateFilter(days[i].date, format.dayHeader) ); - } - updateCalendar( split( days, 7 ), labels, dateFilter(selected, format.dayTitle) ); - }, - month: function() { - var months = [], i = 0, year = selected.getFullYear(); - while ( i < 12 ) { - var dt = new Date(year, i++, 1); - months.push( {date: dt, isCurrent: true, isSelected: isSelected(dt), label: dateFilter(dt, format.month), disabled: isDisabled(dt)} ); - } - updateCalendar( split( months, 3 ), [], dateFilter(selected, format.monthTitle) ); - }, - year: function() { - var years = [], year = parseInt((selected.getFullYear() - 1) / yearRange, 10) * yearRange + 1; - for ( var i = 0; i < yearRange; i++ ) { - var dt = new Date(year + i, 0, 1); - years.push( {date: dt, isCurrent: true, isSelected: isSelected(dt), label: dateFilter(dt, format.year), disabled: isDisabled(dt)} ); - } - var title = years[0].label + ' - ' + years[years.length - 1].label; - updateCalendar( split( years, 5 ), [], title ); - } - }; - var refill = function() { - fill[scope.mode](); - }; - var isSelected = function( dt ) { - if ( scope.model && scope.model.getFullYear() === dt.getFullYear() ) { - if ( scope.mode === 'year' ) { - return true; - } - if ( scope.model.getMonth() === dt.getMonth() ) { - return ( scope.mode === 'month' || (scope.mode === 'day' && scope.model.getDate() === dt.getDate()) ); + if ( isNaN(date) ) { + valid = false; + $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.'); + } else if ( updateSelected ) { + selected = date; } } - return false; - }; + ngModel.$setValidity('date', valid); - scope.$watch('model', function ( dt, olddt ) { - if ( angular.isDate(dt) ) { - selected = angular.copy(dt); - } + var currentMode = datepickerCtrl.modes[mode], data = currentMode.getVisibleDates(selected, date); + angular.forEach(data.objects, function(obj) { + obj.disabled = datepickerCtrl.isDisabled(obj.date, mode); + }); - if ( ! angular.equals(dt, olddt) ) { - refill(); - } - }); - scope.$watch('mode', function() { + ngModel.$setValidity('date-disabled', (!date || !datepickerCtrl.isDisabled(date))); + + scope.rows = split(data.objects, currentMode.split); + scope.labels = data.labels || []; + scope.title = data.title; + } + + function setMode(value) { + mode = value; updateShowWeekNumbers(); refill(); - }); + } - scope.select = function( dt ) { - selected = new Date(dt); + ngModel.$render = function() { + refill( true ); + }; - if ( scope.mode === 'year' ) { - scope.mode = 'month'; - selected.setFullYear( dt.getFullYear() ); - } else if ( scope.mode === 'month' ) { - scope.mode = 'day'; - selected.setMonth( dt.getMonth() ); - } else if ( scope.mode === 'day' ) { - scope.model = new Date(selected); + scope.select = function( date ) { + if ( mode === 0 ) { + var dt = new Date( ngModel.$modelValue ); + dt.setFullYear( date.getFullYear(), date.getMonth(), date.getDate() ); + ngModel.$setViewValue( dt ); + refill( true ); + } else { + selected = date; + setMode( mode - 1 ); } }; - scope.move = function(step) { - if (scope.mode === 'day') { - selected.setMonth( selected.getMonth() + step ); - } else if (scope.mode === 'month') { - selected.setFullYear( selected.getFullYear() + step ); - } else if (scope.mode === 'year') { - selected.setFullYear( selected.getFullYear() + step * yearRange ); - } + scope.move = function(direction) { + var step = datepickerCtrl.modes[mode].step; + selected.setMonth( selected.getMonth() + direction * (step.months || 0) ); + selected.setFullYear( selected.getFullYear() + direction * (step.years || 0) ); refill(); }; scope.toggleMode = function() { - scope.mode = ( scope.mode === 'day' ) ? 'month' : ( scope.mode === 'month' ) ? 'year' : 'day'; + setMode( (mode + 1) % datepickerCtrl.modes.length ); }; scope.getWeekNumber = function(row) { - if ( scope.mode !== 'day' || ! scope.showWeekNumbers || row.length !== 7 ) { - return; - } - - var index = ( startingDay > 4 ) ? 11 - startingDay : 4 - startingDay; // Thursday - var d = new Date( row[ index ].date ); - d.setHours(0, 0, 0); - return Math.ceil((((d - new Date(d.getFullYear(), 0, 1)) / 86400000) + 1) / 7); // 86400000 = 1000*60*60*24; + return ( mode === 0 && scope.showWeekNumbers && row.length === 7 ) ? getISO8601WeekNumber(row[0].date) : null; }; + + function getISO8601WeekNumber(date) { + var checkDate = new Date(date); + checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); // Thursday + var time = checkDate.getTime(); + checkDate.setMonth(0); // Compare with Jan 1 + checkDate.setDate(1); + return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; + } } }; -}]); -// The `$dialogProvider` can be used to configure global defaults for your -// `$dialog` service. -var dialogModule = angular.module('ui.bootstrap.dialog', ['ui.bootstrap.transition']); +}]) -dialogModule.controller('MessageBoxController', ['$scope', 'dialog', 'model', function($scope, dialog, model){ - $scope.title = model.title; - $scope.message = model.message; - $scope.buttons = model.buttons; - $scope.close = function(res){ - dialog.close(res); - }; -}]); +.constant('datepickerPopupConfig', { + dateFormat: 'yyyy-MM-dd', + closeOnDateSelection: true +}) -dialogModule.provider("$dialog", function(){ +.directive('datepickerPopup', ['$compile', '$parse', '$document', '$position', 'dateFilter', 'datepickerPopupConfig', +function ($compile, $parse, $document, $position, dateFilter, datepickerPopupConfig) { + return { + restrict: 'EA', + require: 'ngModel', + link: function(originalScope, element, attrs, ngModel) { - // The default options for all dialogs. - var defaults = { - backdrop: true, - dialogClass: 'modal', - backdropClass: 'modal-backdrop', - transitionClass: 'fade', - triggerClass: 'in', - resolve:{}, - backdropFade: false, - dialogFade:false, - keyboard: true, // close with esc key - backdropClick: true // only in conjunction with backdrop=true - /* other options: template, templateUrl, controller */ - }; + var closeOnDateSelection = angular.isDefined(attrs.closeOnDateSelection) ? scope.$eval(attrs.closeOnDateSelection) : datepickerPopupConfig.closeOnDateSelection; + var dateFormat = attrs.datepickerPopup || datepickerPopupConfig.dateFormat; - var globalOptions = {}; + // create a child scope for the datepicker directive so we are not polluting original scope + var scope = originalScope.$new(); + originalScope.$on('$destroy', function() { + scope.$destroy(); + }); - var activeBackdrops = {value : 0}; + var getIsOpen, setIsOpen; + if ( attrs.isOpen ) { + getIsOpen = $parse(attrs.isOpen); + setIsOpen = getIsOpen.assign; - // The `options({})` allows global configuration of all dialogs in the application. - // - // var app = angular.module('App', ['ui.bootstrap.dialog'], function($dialogProvider){ - // // don't close dialog when backdrop is clicked by default - // $dialogProvider.options({backdropClick: false}); - // }); - this.options = function(value){ - globalOptions = value; - }; - - // Returns the actual `$dialog` service that is injected in controllers - this.$get = ["$http", "$document", "$compile", "$rootScope", "$controller", "$templateCache", "$q", "$transition", "$injector", - function ($http, $document, $compile, $rootScope, $controller, $templateCache, $q, $transition, $injector) { - - var body = $document.find('body'); - - function createElement(clazz) { - var el = angular.element("
    "); - el.addClass(clazz); - return el; - } - - // The `Dialog` class represents a modal dialog. The dialog class can be invoked by providing an options object - // containing at lest template or templateUrl and controller: - // - // var d = new Dialog({templateUrl: 'foo.html', controller: 'BarController'}); - // - // Dialogs can also be created using templateUrl and controller as distinct arguments: - // - // var d = new Dialog('path/to/dialog.html', MyDialogController); - function Dialog(opts) { - - var self = this, options = this.options = angular.extend({}, defaults, globalOptions, opts); - this._open = false; - - this.backdropEl = createElement(options.backdropClass); - if(options.backdropFade){ - this.backdropEl.addClass(options.transitionClass); - this.backdropEl.removeClass(options.triggerClass); - } - - this.modalEl = createElement(options.dialogClass); - if(options.dialogFade){ - this.modalEl.addClass(options.transitionClass); - this.modalEl.removeClass(options.triggerClass); - } - - this.handledEscapeKey = function(e) { - if (e.which === 27) { - self.close(); - e.preventDefault(); - self.$scope.$apply(); - } - }; - - this.handleBackDropClick = function(e) { - self.close(); - e.preventDefault(); - self.$scope.$apply(); - }; - - this.handleLocationChange = function() { - self.close(); - }; - } - - // The `isOpen()` method returns wether the dialog is currently visible. - Dialog.prototype.isOpen = function(){ - return this._open; - }; - - // The `open(templateUrl, controller)` method opens the dialog. - // Use the `templateUrl` and `controller` arguments if specifying them at dialog creation time is not desired. - Dialog.prototype.open = function(templateUrl, controller){ - var self = this, options = this.options; - - if(templateUrl){ - options.templateUrl = templateUrl; - } - if(controller){ - options.controller = controller; - } - - if(!(options.template || options.templateUrl)) { - throw new Error('Dialog.open expected template or templateUrl, neither found. Use options or open method to specify them.'); - } - - this._loadResolves().then(function(locals) { - var $scope = locals.$scope = self.$scope = locals.$scope ? locals.$scope : $rootScope.$new(); - - self.modalEl.html(locals.$template); - - if (self.options.controller) { - var ctrl = $controller(self.options.controller, locals); - self.modalEl.children().data('ngControllerController', ctrl); - } - - $compile(self.modalEl)($scope); - self._addElementsToDom(); - - // trigger tranisitions - setTimeout(function(){ - if(self.options.dialogFade){ self.modalEl.addClass(self.options.triggerClass); } - if(self.options.backdropFade){ self.backdropEl.addClass(self.options.triggerClass); } + originalScope.$watch(getIsOpen, function updateOpen(value) { + scope.isOpen = !! value; }); - - self._bindEvents(); - }); - - this.deferred = $q.defer(); - return this.deferred.promise; - }; - - // closes the dialog and resolves the promise returned by the `open` method with the specified result. - Dialog.prototype.close = function(result){ - var self = this; - var fadingElements = this._getFadingElements(); - - if(fadingElements.length > 0){ - for (var i = fadingElements.length - 1; i >= 0; i--) { - $transition(fadingElements[i], removeTriggerClass).then(onCloseComplete); - } - return; } + scope.isOpen = getIsOpen ? getIsOpen(originalScope) : false; // Initial state - this._onCloseComplete(result); - - function removeTriggerClass(el){ - el.removeClass(self.options.triggerClass); - } - - function onCloseComplete(){ - if(self._open){ - self._onCloseComplete(result); + function setOpen( value ) { + if (setIsOpen) { + setIsOpen(originalScope, !!value); + } else { + scope.isOpen = !!value; } } - }; - Dialog.prototype._getFadingElements = function(){ - var elements = []; - if(this.options.dialogFade){ - elements.push(this.modalEl); - } - if(this.options.backdropFade){ - elements.push(this.backdropEl); - } - - return elements; - }; - - Dialog.prototype._bindEvents = function() { - if(this.options.keyboard){ body.bind('keydown', this.handledEscapeKey); } - if(this.options.backdrop && this.options.backdropClick){ this.backdropEl.bind('click', this.handleBackDropClick); } - }; - - Dialog.prototype._unbindEvents = function() { - if(this.options.keyboard){ body.unbind('keydown', this.handledEscapeKey); } - if(this.options.backdrop && this.options.backdropClick){ this.backdropEl.unbind('click', this.handleBackDropClick); } - }; - - Dialog.prototype._onCloseComplete = function(result) { - this._removeElementsFromDom(); - this._unbindEvents(); - - this.deferred.resolve(result); - }; - - Dialog.prototype._addElementsToDom = function(){ - body.append(this.modalEl); - - if(this.options.backdrop) { - if (activeBackdrops.value === 0) { - body.append(this.backdropEl); + var documentClickBind = function(event) { + if (scope.isOpen && event.target !== element[0]) { + scope.$apply(function() { + setOpen(false); + }); } - activeBackdrops.value++; - } + }; - this._open = true; - }; - - Dialog.prototype._removeElementsFromDom = function(){ - this.modalEl.remove(); - - if(this.options.backdrop) { - activeBackdrops.value--; - if (activeBackdrops.value === 0) { - this.backdropEl.remove(); - } - } - this._open = false; - }; - - // Loads all `options.resolve` members to be used as locals for the controller associated with the dialog. - Dialog.prototype._loadResolves = function(){ - var values = [], keys = [], templatePromise, self = this; - - if (this.options.template) { - templatePromise = $q.when(this.options.template); - } else if (this.options.templateUrl) { - templatePromise = $http.get(this.options.templateUrl, {cache:$templateCache}) - .then(function(response) { return response.data; }); - } - - angular.forEach(this.options.resolve || [], function(value, key) { - keys.push(key); - values.push(angular.isString(value) ? $injector.get(value) : $injector.invoke(value)); - }); - - keys.push('$template'); - values.push(templatePromise); - - return $q.all(values).then(function(values) { - var locals = {}; - angular.forEach(values, function(value, index) { - locals[keys[index]] = value; + var elementFocusBind = function() { + scope.$apply(function() { + setOpen( true ); }); - locals.dialog = self; - return locals; - }); - }; + }; - // The actual `$dialog` service that is injected in controllers. - return { - // Creates a new `Dialog` with the specified options. - dialog: function(opts){ - return new Dialog(opts); - }, - // creates a new `Dialog` tied to the default message box template and controller. - // - // Arguments `title` and `message` are rendered in the modal header and body sections respectively. - // The `buttons` array holds an object with the following members for each button to include in the - // modal footer section: - // - // * `result`: the result to pass to the `close` method of the dialog when the button is clicked - // * `label`: the label of the button - // * `cssClass`: additional css class(es) to apply to the button for styling - messageBox: function(title, message, buttons){ - return new Dialog({templateUrl: 'template/dialog/message.html', controller: 'MessageBoxController', resolve: - {model: function() { - return { - title: title, - message: message, - buttons: buttons - }; + // popup element used to display calendar + var popupEl = angular.element(''); + popupEl.attr({ + 'ng-model': 'date', + 'ng-change': 'dateSelection()' + }); + var datepickerEl = popupEl.find('datepicker'); + if (attrs.datepickerOptions) { + datepickerEl.attr(angular.extend({}, originalScope.$eval(attrs.datepickerOptions))); + } + + // TODO: reverse from dateFilter string to Date object + function parseDate(viewValue) { + if (!viewValue) { + ngModel.$setValidity('date', true); + return null; + } else if (angular.isDate(viewValue)) { + ngModel.$setValidity('date', true); + return viewValue; + } else if (angular.isString(viewValue)) { + var date = new Date(viewValue); + if (isNaN(date)) { + ngModel.$setValidity('date', false); + return undefined; + } else { + ngModel.$setValidity('date', true); + return date; } - }}); + } else { + ngModel.$setValidity('date', false); + return undefined; + } } - }; - }]; -}); + ngModel.$parsers.unshift(parseDate); + + // Inner change + scope.dateSelection = function() { + ngModel.$setViewValue(scope.date); + ngModel.$render(); + + if (closeOnDateSelection) { + setOpen( false ); + } + }; + + element.bind('input change keyup', function() { + scope.$apply(function() { + updateCalendar(); + }); + }); + + // Outter change + ngModel.$render = function() { + var date = ngModel.$viewValue ? dateFilter(ngModel.$viewValue, dateFormat) : ''; + element.val(date); + + updateCalendar(); + }; + + function updateCalendar() { + scope.date = ngModel.$modelValue; + updatePosition(); + } + + function addWatchableAttribute(attribute, scopeProperty, datepickerAttribute) { + if (attribute) { + originalScope.$watch($parse(attribute), function(value){ + scope[scopeProperty] = value; + }); + datepickerEl.attr(datepickerAttribute || scopeProperty, scopeProperty); + } + } + addWatchableAttribute(attrs.min, 'min'); + addWatchableAttribute(attrs.max, 'max'); + if (attrs.showWeeks) { + addWatchableAttribute(attrs.showWeeks, 'showWeeks', 'show-weeks'); + } else { + scope.showWeeks = true; + datepickerEl.attr('show-weeks', 'showWeeks'); + } + if (attrs.dateDisabled) { + datepickerEl.attr('date-disabled', attrs.dateDisabled); + } + + function updatePosition() { + scope.position = $position.position(element); + scope.position.top = scope.position.top + element.prop('offsetHeight'); + } + + var documentBindingInitialized = false, elementFocusInitialized = false; + scope.$watch('isOpen', function(value) { + if (value) { + updatePosition(); + $document.bind('click', documentClickBind); + if(elementFocusInitialized) { + element.unbind('focus', elementFocusBind); + } + element[0].focus(); + documentBindingInitialized = true; + } else { + if(documentBindingInitialized) { + $document.unbind('click', documentClickBind); + } + element.bind('focus', elementFocusBind); + elementFocusInitialized = true; + } + + if ( setIsOpen ) { + setIsOpen(originalScope, value); + } + }); + + var $setModelValue = $parse(attrs.ngModel).assign; + + scope.today = function() { + $setModelValue(originalScope, new Date()); + }; + scope.clear = function() { + $setModelValue(originalScope, null); + }; + + element.after($compile(popupEl)(scope)); + } + }; +}]) + +.directive('datepickerPopupWrap', [function() { + return { + restrict:'E', + replace: true, + transclude: true, + templateUrl: 'template/datepicker/popup.html', + link:function (scope, element, attrs) { + element.bind('click', function(event) { + event.preventDefault(); + event.stopPropagation(); + }); + } + }; +}]); /* * dropdownToggle - Provides dropdown menu functionality in place of bootstrap js @@ -1284,77 +1327,391 @@ angular.module('ui.bootstrap.dropdownToggle', []).directive('dropdownToggle', [' } }; }]); -angular.module('ui.bootstrap.modal', ['ui.bootstrap.dialog']) -.directive('modal', ['$parse', '$dialog', function($parse, $dialog) { - return { - restrict: 'EA', - terminal: true, - link: function(scope, elm, attrs) { - var opts = angular.extend({}, scope.$eval(attrs.uiOptions || attrs.bsOptions || attrs.options)); - var shownExpr = attrs.modal || attrs.show; - var setClosed; +angular.module('ui.bootstrap.modal', []) - // Create a dialog with the template as the contents of the directive - // Add the current scope as the resolve in order to make the directive scope as a dialog controller scope - opts = angular.extend(opts, { - template: elm.html(), - resolve: { $scope: function() { return scope; } } - }); - var dialog = $dialog.dialog(opts); +/** + * A helper, internal data structure that acts as a map but also allows getting / removing + * elements in the LIFO order + */ + .factory('$$stackedMap', function () { + return { + createNew: function () { + var stack = []; - elm.remove(); - - if (attrs.close) { - setClosed = function() { - $parse(attrs.close)(scope); - }; - } else { - setClosed = function() { - if (angular.isFunction($parse(shownExpr).assign)) { - $parse(shownExpr).assign(scope, false); + return { + add: function (key, value) { + stack.push({ + key: key, + value: value + }); + }, + get: function (key) { + for (var i = 0; i < stack.length; i++) { + if (key == stack[i].key) { + return stack[i]; + } + } + }, + keys: function() { + var keys = []; + for (var i = 0; i < stack.length; i++) { + keys.push(stack[i].key); + } + return keys; + }, + top: function () { + return stack[stack.length - 1]; + }, + remove: function (key) { + var idx = -1; + for (var i = 0; i < stack.length; i++) { + if (key == stack[i].key) { + idx = i; + break; + } + } + return stack.splice(idx, 1)[0]; + }, + removeTop: function () { + return stack.splice(stack.length - 1, 1)[0]; + }, + length: function () { + return stack.length; } }; } + }; + }) - scope.$watch(shownExpr, function(isShown, oldShown) { - if (isShown) { - dialog.open().then(function(){ - setClosed(); - }); - } else { - //Make sure it is not opened - if (dialog.isOpen()){ - dialog.close(); +/** + * A helper directive for the $modal service. It creates a backdrop element. + */ + .directive('modalBackdrop', ['$modalStack', '$timeout', function ($modalStack, $timeout) { + return { + restrict: 'EA', + replace: true, + templateUrl: 'template/modal/backdrop.html', + link: function (scope, element, attrs) { + + //trigger CSS transitions + $timeout(function () { + scope.animate = true; + }); + + scope.close = function (evt) { + var modal = $modalStack.getTop(); + if (modal && modal.value.backdrop && modal.value.backdrop != 'static') { + evt.preventDefault(); + evt.stopPropagation(); + $modalStack.dismiss(modal.key, 'backdrop click'); + } + }; + } + }; + }]) + + .directive('modalWindow', ['$timeout', function ($timeout) { + return { + restrict: 'EA', + scope: { + index: '@' + }, + replace: true, + transclude: true, + templateUrl: 'template/modal/window.html', + link: function (scope, element, attrs) { + scope.windowClass = attrs.windowClass || ''; + + //trigger CSS transitions + $timeout(function () { + scope.animate = true; + }); + } + }; + }]) + + .factory('$modalStack', ['$document', '$compile', '$rootScope', '$$stackedMap', + function ($document, $compile, $rootScope, $$stackedMap) { + + var backdropjqLiteEl, backdropDomEl; + var backdropScope = $rootScope.$new(true); + var body = $document.find('body').eq(0); + var openedWindows = $$stackedMap.createNew(); + var $modalStack = {}; + + function backdropIndex() { + var topBackdropIndex = -1; + var opened = openedWindows.keys(); + for (var i = 0; i < opened.length; i++) { + if (openedWindows.get(opened[i]).value.backdrop) { + topBackdropIndex = i; + } + } + return topBackdropIndex; + } + + $rootScope.$watch(backdropIndex, function(newBackdropIndex){ + backdropScope.index = newBackdropIndex; + }); + + function removeModalWindow(modalInstance) { + + var modalWindow = openedWindows.get(modalInstance).value; + + //clean up the stack + openedWindows.remove(modalInstance); + + //remove window DOM element + modalWindow.modalDomEl.remove(); + + //remove backdrop if no longer needed + if (backdropIndex() == -1) { + backdropDomEl.remove(); + backdropDomEl = undefined; + } + + //destroy scope + modalWindow.modalScope.$destroy(); + } + + $document.bind('keydown', function (evt) { + var modal; + + if (evt.which === 27) { + modal = openedWindows.top(); + if (modal && modal.value.keyboard) { + $rootScope.$apply(function () { + $modalStack.dismiss(modal.key); + }); } } }); - } - }; -}]); + + $modalStack.open = function (modalInstance, modal) { + + openedWindows.add(modalInstance, { + deferred: modal.deferred, + modalScope: modal.scope, + backdrop: modal.backdrop, + keyboard: modal.keyboard + }); + + var angularDomEl = angular.element('
    '); + angularDomEl.attr('window-class', modal.windowClass); + angularDomEl.attr('index', openedWindows.length() - 1); + angularDomEl.html(modal.content); + + var modalDomEl = $compile(angularDomEl)(modal.scope); + openedWindows.top().value.modalDomEl = modalDomEl; + body.append(modalDomEl); + + if (backdropIndex() >= 0 && !backdropDomEl) { + backdropjqLiteEl = angular.element('
    '); + backdropDomEl = $compile(backdropjqLiteEl)(backdropScope); + body.append(backdropDomEl); + } + }; + + $modalStack.close = function (modalInstance, result) { + var modal = openedWindows.get(modalInstance); + if (modal) { + modal.value.deferred.resolve(result); + removeModalWindow(modalInstance); + } + }; + + $modalStack.dismiss = function (modalInstance, reason) { + var modalWindow = openedWindows.get(modalInstance).value; + if (modalWindow) { + modalWindow.deferred.reject(reason); + removeModalWindow(modalInstance); + } + }; + + $modalStack.getTop = function () { + return openedWindows.top(); + }; + + return $modalStack; + }]) + + .provider('$modal', function () { + + var $modalProvider = { + options: { + backdrop: true, //can be also false or 'static' + keyboard: true + }, + $get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack', + function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) { + + var $modal = {}; + + function getTemplatePromise(options) { + return options.template ? $q.when(options.template) : + $http.get(options.templateUrl, {cache: $templateCache}).then(function (result) { + return result.data; + }); + } + + function getResolvePromises(resolves) { + var promisesArr = []; + angular.forEach(resolves, function (value, key) { + if (angular.isFunction(value) || angular.isArray(value)) { + promisesArr.push($q.when($injector.invoke(value))); + } + }); + return promisesArr; + } + + $modal.open = function (modalOptions) { + + var modalResultDeferred = $q.defer(); + var modalOpenedDeferred = $q.defer(); + + //prepare an instance of a modal to be injected into controllers and returned to a caller + var modalInstance = { + result: modalResultDeferred.promise, + opened: modalOpenedDeferred.promise, + close: function (result) { + $modalStack.close(modalInstance, result); + }, + dismiss: function (reason) { + $modalStack.dismiss(modalInstance, reason); + } + }; + + //merge and clean up options + modalOptions = angular.extend({}, $modalProvider.options, modalOptions); + modalOptions.resolve = modalOptions.resolve || {}; + + //verify options + if (!modalOptions.template && !modalOptions.templateUrl) { + throw new Error('One of template or templateUrl options is required.'); + } + + var templateAndResolvePromise = + $q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve))); + + + templateAndResolvePromise.then(function resolveSuccess(tplAndVars) { + + var modalScope = (modalOptions.scope || $rootScope).$new(); + modalScope.$close = modalInstance.close; + modalScope.$dismiss = modalInstance.dismiss; + + var ctrlInstance, ctrlLocals = {}; + var resolveIter = 1; + + //controllers + if (modalOptions.controller) { + ctrlLocals.$scope = modalScope; + ctrlLocals.$modalInstance = modalInstance; + angular.forEach(modalOptions.resolve, function (value, key) { + ctrlLocals[key] = tplAndVars[resolveIter++]; + }); + + ctrlInstance = $controller(modalOptions.controller, ctrlLocals); + } + + $modalStack.open(modalInstance, { + scope: modalScope, + deferred: modalResultDeferred, + content: tplAndVars[0], + backdrop: modalOptions.backdrop, + keyboard: modalOptions.keyboard, + windowClass: modalOptions.windowClass + }); + + }, function resolveError(reason) { + modalResultDeferred.reject(reason); + }); + + templateAndResolvePromise.then(function () { + modalOpenedDeferred.resolve(true); + }, function () { + modalOpenedDeferred.reject(false); + }); + + return modalInstance; + }; + + return $modal; + }] + }; + + return $modalProvider; + }); angular.module('ui.bootstrap.pagination', []) -.controller('PaginationController', ['$scope', function (scope) { +.controller('PaginationController', ['$scope', '$attrs', '$parse', '$interpolate', function ($scope, $attrs, $parse, $interpolate) { + var self = this; - scope.noPrevious = function() { - return scope.currentPage === 1; - }; - scope.noNext = function() { - return scope.currentPage === scope.numPages; - }; - - scope.isActive = function(page) { - return scope.currentPage === page; - }; - - scope.selectPage = function(page) { - if ( ! scope.isActive(page) && page > 0 && page <= scope.numPages) { - scope.currentPage = page; - scope.onSelectPage({ page: page }); + this.init = function(defaultItemsPerPage) { + if ($attrs.itemsPerPage) { + $scope.$parent.$watch($parse($attrs.itemsPerPage), function(value) { + self.itemsPerPage = parseInt(value, 10); + $scope.totalPages = self.calculateTotalPages(); + }); + } else { + this.itemsPerPage = defaultItemsPerPage; } }; + + this.noPrevious = function() { + return this.page === 1; + }; + this.noNext = function() { + return this.page === $scope.totalPages; + }; + + this.isActive = function(page) { + return this.page === page; + }; + + this.calculateTotalPages = function() { + return this.itemsPerPage < 1 ? 1 : Math.ceil($scope.totalItems / this.itemsPerPage); + }; + + this.getAttributeValue = function(attribute, defaultValue, interpolate) { + return angular.isDefined(attribute) ? (interpolate ? $interpolate(attribute)($scope.$parent) : $scope.$parent.$eval(attribute)) : defaultValue; + }; + + this.render = function() { + this.page = parseInt($scope.page, 10) || 1; + $scope.pages = this.getPages(this.page, $scope.totalPages); + }; + + $scope.selectPage = function(page) { + if ( ! self.isActive(page) && page > 0 && page <= $scope.totalPages) { + $scope.page = page; + $scope.onSelectPage({ page: page }); + } + }; + + $scope.$watch('totalItems', function() { + $scope.totalPages = self.calculateTotalPages(); + }); + + $scope.$watch('totalPages', function(value) { + if ( $attrs.numPages ) { + $scope.numPages = value; // Readonly variable + } + + if ( self.page > value ) { + $scope.selectPage(value); + } else { + self.render(); + } + }); + + $scope.$watch('page', function() { + self.render(); + }); }]) .constant('paginationConfig', { + itemsPerPage: 10, boundaryLinks: false, directionLinks: true, firstText: 'First', @@ -1364,28 +1721,38 @@ angular.module('ui.bootstrap.pagination', []) rotate: true }) -.directive('pagination', ['paginationConfig', function(paginationConfig) { +.directive('pagination', ['$parse', 'paginationConfig', function($parse, config) { return { restrict: 'EA', scope: { - numPages: '=', - currentPage: '=', - maxSize: '=', - onSelectPage: '&' + page: '=', + totalItems: '=', + onSelectPage:' &', + numPages: '=' }, controller: 'PaginationController', templateUrl: 'template/pagination/pagination.html', replace: true, - link: function(scope, element, attrs) { + link: function(scope, element, attrs, paginationCtrl) { // Setup configuration parameters - var boundaryLinks = angular.isDefined(attrs.boundaryLinks) ? scope.$eval(attrs.boundaryLinks) : paginationConfig.boundaryLinks; - var directionLinks = angular.isDefined(attrs.directionLinks) ? scope.$eval(attrs.directionLinks) : paginationConfig.directionLinks; - var firstText = angular.isDefined(attrs.firstText) ? scope.$parent.$eval(attrs.firstText) : paginationConfig.firstText; - var previousText = angular.isDefined(attrs.previousText) ? scope.$parent.$eval(attrs.previousText) : paginationConfig.previousText; - var nextText = angular.isDefined(attrs.nextText) ? scope.$parent.$eval(attrs.nextText) : paginationConfig.nextText; - var lastText = angular.isDefined(attrs.lastText) ? scope.$parent.$eval(attrs.lastText) : paginationConfig.lastText; - var rotate = angular.isDefined(attrs.rotate) ? scope.$eval(attrs.rotate) : paginationConfig.rotate; + var maxSize, + boundaryLinks = paginationCtrl.getAttributeValue(attrs.boundaryLinks, config.boundaryLinks ), + directionLinks = paginationCtrl.getAttributeValue(attrs.directionLinks, config.directionLinks ), + firstText = paginationCtrl.getAttributeValue(attrs.firstText, config.firstText, true), + previousText = paginationCtrl.getAttributeValue(attrs.previousText, config.previousText, true), + nextText = paginationCtrl.getAttributeValue(attrs.nextText, config.nextText, true), + lastText = paginationCtrl.getAttributeValue(attrs.lastText, config.lastText, true), + rotate = paginationCtrl.getAttributeValue(attrs.rotate, config.rotate); + + paginationCtrl.init(config.itemsPerPage); + + if (attrs.maxSize) { + scope.$parent.$watch($parse(attrs.maxSize), function(value) { + maxSize = parseInt(value, 10); + paginationCtrl.render(); + }); + } // Create page object used in template function makePage(number, text, isActive, isDisabled) { @@ -1397,80 +1764,79 @@ angular.module('ui.bootstrap.pagination', []) }; } - scope.$watch('numPages + currentPage + maxSize', function() { - scope.pages = []; - + paginationCtrl.getPages = function(currentPage, totalPages) { + var pages = []; + // Default page limits - var startPage = 1, endPage = scope.numPages; - var isMaxSized = ( angular.isDefined(scope.maxSize) && scope.maxSize < scope.numPages ); + var startPage = 1, endPage = totalPages; + var isMaxSized = ( angular.isDefined(maxSize) && maxSize < totalPages ); // recompute if maxSize if ( isMaxSized ) { if ( rotate ) { // Current page is displayed in the middle of the visible ones - startPage = Math.max(scope.currentPage - Math.floor(scope.maxSize/2), 1); - endPage = startPage + scope.maxSize - 1; + startPage = Math.max(currentPage - Math.floor(maxSize/2), 1); + endPage = startPage + maxSize - 1; // Adjust if limit is exceeded - if (endPage > scope.numPages) { - endPage = scope.numPages; - startPage = endPage - scope.maxSize + 1; + if (endPage > totalPages) { + endPage = totalPages; + startPage = endPage - maxSize + 1; } } else { // Visible pages are paginated with maxSize - startPage = ((Math.ceil(scope.currentPage / scope.maxSize) - 1) * scope.maxSize) + 1; + startPage = ((Math.ceil(currentPage / maxSize) - 1) * maxSize) + 1; // Adjust last page if limit is exceeded - endPage = Math.min(startPage + scope.maxSize - 1, scope.numPages); + endPage = Math.min(startPage + maxSize - 1, totalPages); } } // Add page number links for (var number = startPage; number <= endPage; number++) { - var page = makePage(number, number, scope.isActive(number), false); - scope.pages.push(page); + var page = makePage(number, number, paginationCtrl.isActive(number), false); + pages.push(page); } // Add links to move between page sets if ( isMaxSized && ! rotate ) { if ( startPage > 1 ) { var previousPageSet = makePage(startPage - 1, '...', false, false); - scope.pages.unshift(previousPageSet); + pages.unshift(previousPageSet); } - if ( endPage < scope.numPages ) { + if ( endPage < totalPages ) { var nextPageSet = makePage(endPage + 1, '...', false, false); - scope.pages.push(nextPageSet); + pages.push(nextPageSet); } } // Add previous & next links if (directionLinks) { - var previousPage = makePage(scope.currentPage - 1, previousText, false, scope.noPrevious()); - scope.pages.unshift(previousPage); + var previousPage = makePage(currentPage - 1, previousText, false, paginationCtrl.noPrevious()); + pages.unshift(previousPage); - var nextPage = makePage(scope.currentPage + 1, nextText, false, scope.noNext()); - scope.pages.push(nextPage); + var nextPage = makePage(currentPage + 1, nextText, false, paginationCtrl.noNext()); + pages.push(nextPage); } // Add first & last links if (boundaryLinks) { - var firstPage = makePage(1, firstText, false, scope.noPrevious()); - scope.pages.unshift(firstPage); + var firstPage = makePage(1, firstText, false, paginationCtrl.noPrevious()); + pages.unshift(firstPage); - var lastPage = makePage(scope.numPages, lastText, false, scope.noNext()); - scope.pages.push(lastPage); + var lastPage = makePage(totalPages, lastText, false, paginationCtrl.noNext()); + pages.push(lastPage); } - if ( scope.currentPage > scope.numPages ) { - scope.selectPage(scope.numPages); - } - }); + return pages; + }; } }; }]) .constant('pagerConfig', { + itemsPerPage: 10, previousText: '« Previous', nextText: 'Next »', align: true @@ -1480,9 +1846,10 @@ angular.module('ui.bootstrap.pagination', []) return { restrict: 'EA', scope: { - numPages: '=', - currentPage: '=', - onSelectPage: '&' + page: '=', + totalItems: '=', + onSelectPage:' &', + numPages: '=' }, controller: 'PaginationController', templateUrl: 'template/pagination/pager.html', @@ -1490,9 +1857,11 @@ angular.module('ui.bootstrap.pagination', []) link: function(scope, element, attrs, paginationCtrl) { // Setup configuration parameters - var previousText = angular.isDefined(attrs.previousText) ? scope.$parent.$eval(attrs.previousText) : config.previousText; - var nextText = angular.isDefined(attrs.nextText) ? scope.$parent.$eval(attrs.nextText) : config.nextText; - var align = angular.isDefined(attrs.align) ? scope.$parent.$eval(attrs.align) : config.align; + var previousText = paginationCtrl.getAttributeValue(attrs.previousText, config.previousText, true), + nextText = paginationCtrl.getAttributeValue(attrs.nextText, config.nextText, true), + align = paginationCtrl.getAttributeValue(attrs.align, config.align); + + paginationCtrl.init(config.itemsPerPage); // Create page object used in template function makePage(number, text, isDisabled, isPrevious, isNext) { @@ -1505,124 +1874,22 @@ angular.module('ui.bootstrap.pagination', []) }; } - scope.$watch('numPages + currentPage', function() { - scope.pages = []; - - // Add previous & next links - var previousPage = makePage(scope.currentPage - 1, previousText, scope.noPrevious(), true, false); - scope.pages.unshift(previousPage); - - var nextPage = makePage(scope.currentPage + 1, nextText, scope.noNext(), false, true); - scope.pages.push(nextPage); - - if ( scope.currentPage > scope.numPages ) { - scope.selectPage(scope.numPages); - } - }); + paginationCtrl.getPages = function(currentPage) { + return [ + makePage(currentPage - 1, previousText, paginationCtrl.noPrevious(), true, false), + makePage(currentPage + 1, nextText, paginationCtrl.noNext(), false, true) + ]; + }; } }; }]); -angular.module('ui.bootstrap.position', []) - -/** - * A set of utility methods that can be use to retrieve position of DOM elements. - * It is meant to be used where we need to absolute-position DOM elements in - * relation to other, existing elements (this is the case for tooltips, popovers, - * typeahead suggestions etc.). - */ - .factory('$position', ['$document', '$window', function ($document, $window) { - - var mouseX, mouseY; - - $document.bind('mousemove', function mouseMoved(event) { - mouseX = event.pageX; - mouseY = event.pageY; - }); - - function getStyle(el, cssprop) { - if (el.currentStyle) { //IE - return el.currentStyle[cssprop]; - } else if ($window.getComputedStyle) { - return $window.getComputedStyle(el)[cssprop]; - } - // finally try and get inline style - return el.style[cssprop]; - } - - /** - * Checks if a given element is statically positioned - * @param element - raw DOM element - */ - function isStaticPositioned(element) { - return (getStyle(element, "position") || 'static' ) === 'static'; - } - - /** - * returns the closest, non-statically positioned parentOffset of a given element - * @param element - */ - var parentOffsetEl = function (element) { - var docDomEl = $document[0]; - var offsetParent = element.offsetParent || docDomEl; - while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent) ) { - offsetParent = offsetParent.offsetParent; - } - return offsetParent || docDomEl; - }; - - return { - /** - * Provides read-only equivalent of jQuery's position function: - * http://api.jquery.com/position/ - */ - position: function (element) { - var elBCR = this.offset(element); - var offsetParentBCR = { top: 0, left: 0 }; - var offsetParentEl = parentOffsetEl(element[0]); - if (offsetParentEl != $document[0]) { - offsetParentBCR = this.offset(angular.element(offsetParentEl)); - offsetParentBCR.top += offsetParentEl.clientTop; - offsetParentBCR.left += offsetParentEl.clientLeft; - } - - return { - width: element.prop('offsetWidth'), - height: element.prop('offsetHeight'), - top: elBCR.top - offsetParentBCR.top, - left: elBCR.left - offsetParentBCR.left - }; - }, - - /** - * Provides read-only equivalent of jQuery's offset function: - * http://api.jquery.com/offset/ - */ - offset: function (element) { - var boundingClientRect = element[0].getBoundingClientRect(); - return { - width: element.prop('offsetWidth'), - height: element.prop('offsetHeight'), - top: boundingClientRect.top + ($window.pageYOffset || $document[0].body.scrollTop), - left: boundingClientRect.left + ($window.pageXOffset || $document[0].body.scrollLeft) - }; - }, - - /** - * Provides the coordinates of the mouse - */ - mouse: function () { - return {x: mouseX, y: mouseY}; - } - }; - }]); - /** * The following features are still outstanding: animation as a * function, placement as a function, inside, support for more triggers than * just mouse enter/leave, html tooltips, and selector delegation. */ -angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] ) +angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap.bindHtml' ] ) /** * The $tooltip service creates tooltip- and popover-like directives as well as @@ -1701,16 +1968,9 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] ) * undefined; otherwise, it uses the `triggerMap` value of the show * trigger; else it will just use the show trigger. */ - function setTriggers ( trigger ) { - var show, hide; - - show = trigger || options.trigger || defaultTriggerShow; - if ( angular.isDefined ( options.trigger ) ) { - hide = triggerMap[options.trigger] || show; - } else { - hide = triggerMap[show] || show; - } - + function getTriggers ( trigger ) { + var show = trigger || options.trigger || defaultTriggerShow; + var hide = triggerMap[show] || show; return { show: show, hide: hide @@ -1718,7 +1978,6 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] ) } var directiveName = snake_case( type ); - var triggers = setTriggers( undefined ); var startSym = $interpolate.startSymbol(); var endSym = $interpolate.endSymbol(); @@ -1741,6 +2000,8 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] ) var popupTimeout; var $body; var appendToBody = angular.isDefined( options.appendToBody ) ? options.appendToBody : false; + var triggers = getTriggers( undefined ); + var hasRegisteredTriggers = false; // By default, the tooltip is not open. // TODO add ability to start tooltip opened @@ -1800,7 +2061,7 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] ) } // Get the position of the directive element. - position = options.appendToBody ? $position.offset( element ) : $position.position( element ); + position = appendToBody ? $position.offset( element ) : $position.position( element ); // Get the height and width of the tooltip so we can center it. ttWidth = tooltip.prop( 'offsetWidth' ); @@ -1809,13 +2070,6 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] ) // Calculate the tooltip's top and left coordinates to center it with // this directive. switch ( scope.tt_placement ) { - case 'mouse': - var mousePos = $position.mouse(); - ttPosition = { - top: mousePos.y, - left: mousePos.x - }; - break; case 'right': ttPosition = { top: position.top + position.height / 2 - ttHeight / 2, @@ -1895,10 +2149,13 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] ) }); attrs.$observe( prefix+'Trigger', function ( val ) { - element.unbind( triggers.show ); - element.unbind( triggers.hide ); - triggers = setTriggers( val ); + if (hasRegisteredTriggers) { + element.unbind( triggers.show, showTooltipBind ); + element.unbind( triggers.hide, hideTooltipBind ); + } + + triggers = getTriggers( val ); if ( triggers.show === triggers.hide ) { element.bind( triggers.show, toggleTooltipBind ); @@ -1906,6 +2163,8 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] ) element.bind( triggers.show, showTooltipBind ); element.bind( triggers.hide, hideTooltipBind ); } + + hasRegisteredTriggers = true; }); attrs.$observe( prefix+'AppendToBody', function ( val ) { @@ -2091,56 +2350,86 @@ angular.module('ui.bootstrap.progressbar', ['ui.bootstrap.transition']) angular.module('ui.bootstrap.rating', []) .constant('ratingConfig', { - max: 5 + max: 5, + stateOn: null, + stateOff: null }) -.directive('rating', ['ratingConfig', '$parse', function(ratingConfig, $parse) { +.controller('RatingController', ['$scope', '$attrs', '$parse', 'ratingConfig', function($scope, $attrs, $parse, ratingConfig) { + + this.maxRange = angular.isDefined($attrs.max) ? $scope.$parent.$eval($attrs.max) : ratingConfig.max; + this.stateOn = angular.isDefined($attrs.stateOn) ? $scope.$parent.$eval($attrs.stateOn) : ratingConfig.stateOn; + this.stateOff = angular.isDefined($attrs.stateOff) ? $scope.$parent.$eval($attrs.stateOff) : ratingConfig.stateOff; + + this.createDefaultRange = function(len) { + var defaultStateObject = { + stateOn: this.stateOn, + stateOff: this.stateOff + }; + + var states = new Array(len); + for (var i = 0; i < len; i++) { + states[i] = defaultStateObject; + } + return states; + }; + + this.normalizeRange = function(states) { + for (var i = 0, n = states.length; i < n; i++) { + states[i].stateOn = states[i].stateOn || this.stateOn; + states[i].stateOff = states[i].stateOff || this.stateOff; + } + return states; + }; + + // Get objects used in template + $scope.range = angular.isDefined($attrs.ratingStates) ? this.normalizeRange(angular.copy($scope.$parent.$eval($attrs.ratingStates))): this.createDefaultRange(this.maxRange); + + $scope.rate = function(value) { + if ( $scope.readonly || $scope.value === value) { + return; + } + + $scope.value = value; + }; + + $scope.enter = function(value) { + if ( ! $scope.readonly ) { + $scope.val = value; + } + $scope.onHover({value: value}); + }; + + $scope.reset = function() { + $scope.val = angular.copy($scope.value); + $scope.onLeave(); + }; + + $scope.$watch('value', function(value) { + $scope.val = value; + }); + + $scope.readonly = false; + if ($attrs.readonly) { + $scope.$parent.$watch($parse($attrs.readonly), function(value) { + $scope.readonly = !!value; + }); + } +}]) + +.directive('rating', function() { return { restrict: 'EA', scope: { - value: '=' + value: '=', + onHover: '&', + onLeave: '&' }, + controller: 'RatingController', templateUrl: 'template/rating/rating.html', - replace: true, - link: function(scope, element, attrs) { - - var maxRange = angular.isDefined(attrs.max) ? scope.$eval(attrs.max) : ratingConfig.max; - - scope.range = []; - for (var i = 1; i <= maxRange; i++) { - scope.range.push(i); - } - - scope.rate = function(value) { - if ( ! scope.readonly ) { - scope.value = value; - } - }; - - scope.enter = function(value) { - if ( ! scope.readonly ) { - scope.val = value; - } - }; - - scope.reset = function() { - scope.val = angular.copy(scope.value); - }; - scope.reset(); - - scope.$watch('value', function(value) { - scope.val = value; - }); - - scope.readonly = false; - if (attrs.readonly) { - scope.$parent.$watch($parse(attrs.readonly), function(value) { - scope.readonly = !!value; - }); - } - } + replace: true }; -}]); +}); /** * @ngdoc overview @@ -2158,26 +2447,27 @@ angular.module('ui.bootstrap.tabs', []) }; }) -.controller('TabsetController', ['$scope', '$element', +.controller('TabsetController', ['$scope', '$element', function TabsetCtrl($scope, $element) { + var ctrl = this, tabs = ctrl.tabs = $scope.tabs = []; ctrl.select = function(tab) { angular.forEach(tabs, function(tab) { tab.active = false; - }); + }); tab.active = true; }; ctrl.addTab = function addTab(tab) { tabs.push(tab); - if (tabs.length == 1) { + if (tabs.length === 1 || tab.active) { ctrl.select(tab); } }; - ctrl.removeTab = function removeTab(tab) { + ctrl.removeTab = function removeTab(tab) { var index = tabs.indexOf(tab); //Select a new tab if the tab to be removed is selected if (tab.active && tabs.length > 1) { @@ -2198,6 +2488,8 @@ function TabsetCtrl($scope, $element) { * Tabset is the outer container for the tabs directive * * @param {boolean=} vertical Whether or not to use vertical styling for the tabs. + * @param {string=} direction What direction the tabs should be rendered. Available: + * 'right', 'left', 'below'. * * @example @@ -2218,12 +2510,20 @@ function TabsetCtrl($scope, $element) { return { restrict: 'EA', transclude: true, + replace: true, + require: '^tabset', scope: {}, controller: 'TabsetController', templateUrl: 'template/tabs/tabset.html', - link: function(scope, element, attrs) { - scope.vertical = angular.isDefined(attrs.vertical) ? scope.$eval(attrs.vertical) : false; - scope.type = angular.isDefined(attrs.type) ? scope.$parent.$eval(attrs.type) : 'tabs'; + compile: function(elm, attrs, transclude) { + return function(scope, element, attrs, tabsetCtrl) { + scope.vertical = angular.isDefined(attrs.vertical) ? scope.$parent.$eval(attrs.vertical) : false; + scope.type = angular.isDefined(attrs.type) ? scope.$parent.$eval(attrs.type) : 'tabs'; + scope.direction = angular.isDefined(attrs.direction) ? scope.$parent.$eval(attrs.direction) : 'top'; + scope.tabsAbove = (scope.direction != 'below'); + tabsetCtrl.$scope = scope; + tabsetCtrl.$transcludeFn = transclude; + }; } }; }) @@ -2238,7 +2538,7 @@ function TabsetCtrl($scope, $element) { * @param {boolean=} active A binding, telling whether or not this tab is selected. * @param {boolean=} disabled A binding, telling whether or not this tab is disabled. * - * @description + * @description * Creates a tab with a heading and content. Must be placed within a {@link ui.bootstrap.tabs.directive:tabset tabset}. * * @example @@ -2318,8 +2618,9 @@ function($parse, $http, $templateCache, $compile) { transclude: true, scope: { heading: '@', - onSelect: '&select' //This callback is called in contentHeadingTransclude + onSelect: '&select', //This callback is called in contentHeadingTransclude //once it inserts the tab's content into the dom + onDeselect: '&deselect' }, controller: function() { //Empty controller so other directives can require being 'under' a tab @@ -2327,17 +2628,13 @@ function($parse, $http, $templateCache, $compile) { compile: function(elm, attrs, transclude) { return function postLink(scope, elm, attrs, tabsetCtrl) { var getActive, setActive; - scope.active = false; // default value if (attrs.active) { getActive = $parse(attrs.active); setActive = getActive.assign; scope.$parent.$watch(getActive, function updateActive(value) { - if ( !!value && scope.disabled ) { - setActive(scope.$parent, false); // Prevent active assignment - } else { - scope.active = !!value; - } + scope.active = !!value; }); + scope.active = getActive(scope.$parent); } else { setActive = getActive = angular.noop; } @@ -2347,6 +2644,8 @@ function($parse, $http, $templateCache, $compile) { if (active) { tabsetCtrl.select(scope); scope.onSelect(); + } else { + scope.onDeselect(); } }); @@ -2367,42 +2666,14 @@ function($parse, $http, $templateCache, $compile) { scope.$on('$destroy', function() { tabsetCtrl.removeTab(scope); }); - //If the tabset sets this tab to active, set the parent scope's active - //binding too. We do this so the watch for the parent's initial active - //value won't overwrite what is initially set by the tabset if (scope.active) { setActive(scope.$parent, true); - } + } - //Transclude the collection of sibling elements. Use forEach to find - //the heading if it exists. We don't use a directive for tab-heading - //because it is problematic. Discussion @ http://git.io/MSNPwQ - transclude(scope.$parent, function(clone) { - //Look at every element in the clone collection. If it's tab-heading, - //mark it as that. If it's not tab-heading, mark it as tab contents - var contents = [], heading; - angular.forEach(clone, function(el) { - //See if it's a tab-heading attr or element directive - //First make sure it's a normal element, one that has a tagName - if (el.tagName && - (el.hasAttribute("tab-heading") || - el.hasAttribute("data-tab-heading") || - el.tagName.toLowerCase() == "tab-heading" || - el.tagName.toLowerCase() == "data-tab-heading" - )) { - heading = el; - } else { - contents.push(el); - } - }); - //Share what we found on the scope, so our tabHeadingTransclude and - //tabContentTransclude directives can find out what the heading and - //contents are. - if (heading) { - scope.headingElement = angular.element(heading); - } - scope.contentElement = angular.element(contents); - }); + + //We need to transclude later, once the content container is ready. + //when this link happens, we're inside a tab heading. + scope.$transcludeFn = transclude; }; } }; @@ -2411,7 +2682,7 @@ function($parse, $http, $templateCache, $compile) { .directive('tabHeadingTransclude', [function() { return { restrict: 'A', - require: '^tab', + require: '^tab', link: function(scope, elm, attrs, tabCtrl) { scope.$watch('headingElement', function updateHeadingElement(heading) { if (heading) { @@ -2423,19 +2694,54 @@ function($parse, $http, $templateCache, $compile) { }; }]) -.directive('tabContentTransclude', ['$parse', function($parse) { +.directive('tabContentTransclude', ['$compile', '$parse', function($compile, $parse) { return { restrict: 'A', require: '^tabset', - link: function(scope, elm, attrs, tabsetCtrl) { - scope.$watch($parse(attrs.tabContentTransclude), function(tab) { - elm.html(''); - if (tab) { - elm.append(tab.contentElement); - } + link: function(scope, elm, attrs) { + var tab = scope.$eval(attrs.tabContentTransclude); + + //Now our tab is ready to be transcluded: both the tab heading area + //and the tab content area are loaded. Transclude 'em both. + tab.$transcludeFn(tab.$parent, function(contents) { + angular.forEach(contents, function(node) { + if (isTabHeading(node)) { + //Let tabHeadingTransclude know. + tab.headingElement = node; + } else { + elm.append(node); + } + }); }); } }; + function isTabHeading(node) { + return node.tagName && ( + node.hasAttribute('tab-heading') || + node.hasAttribute('data-tab-heading') || + node.tagName.toLowerCase() === 'tab-heading' || + node.tagName.toLowerCase() === 'data-tab-heading' + ); + } +}]) + +.directive('tabsetTitles', ['$http', function($http) { + return { + restrict: 'A', + require: '^tabset', + templateUrl: 'template/tabs/tabset-titles.html', + replace: true, + link: function(scope, elm, attrs, tabsetCtrl) { + if (!scope.$eval(attrs.tabsetTitles)) { + elm.remove(); + } else { + //now that tabs location has been decided, transclude the tab titles in + tabsetCtrl.$transcludeFn(tabsetCtrl.$scope.$parent, function(node) { + elm.append(node); + }); + } + } + }; }]) ; @@ -2443,15 +2749,6 @@ function($parse, $http, $templateCache, $compile) { angular.module('ui.bootstrap.timepicker', []) -.filter('pad', function() { - return function(input) { - if ( angular.isDefined(input) && input.toString().length < 2 ) { - input = '0' + input; - } - return input; - }; -}) - .constant('timepickerConfig', { hourStep: 1, minuteStep: 1, @@ -2461,16 +2758,18 @@ angular.module('ui.bootstrap.timepicker', []) mousewheel: true }) -.directive('timepicker', ['padFilter', '$parse', 'timepickerConfig', function (padFilter, $parse, timepickerConfig) { +.directive('timepicker', ['$parse', '$log', 'timepickerConfig', function ($parse, $log, timepickerConfig) { return { restrict: 'EA', - require:'ngModel', + require:'?^ngModel', replace: true, + scope: {}, templateUrl: 'template/timepicker/timepicker.html', - scope: { - model: '=ngModel' - }, - link: function(scope, element, attrs, ngModelCtrl) { + link: function(scope, element, attrs, ngModel) { + if ( !ngModel ) { + return; // do nothing if no ng-model + } + var selected = new Date(), meridians = timepickerConfig.meridians; var hourStep = timepickerConfig.hourStep; @@ -2491,28 +2790,27 @@ angular.module('ui.bootstrap.timepicker', []) scope.showMeridian = timepickerConfig.showMeridian; if (attrs.showMeridian) { scope.$parent.$watch($parse(attrs.showMeridian), function(value) { - scope.showMeridian = !! value; + scope.showMeridian = !!value; - if ( ! scope.model ) { - // Reset - var dt = new Date( selected ); - var hours = getScopeHours(); - if (angular.isDefined( hours )) { - dt.setHours( hours ); + if ( ngModel.$error.time ) { + // Evaluate from template + var hours = getHoursFromTemplate(), minutes = getMinutesFromTemplate(); + if (angular.isDefined( hours ) && angular.isDefined( minutes )) { + selected.setHours( hours ); + refresh(); } - scope.model = new Date( dt ); } else { - refreshTemplate(); + updateTemplate(); } }); } // Get scope.hours in 24H mode if valid - function getScopeHours ( ) { + function getHoursFromTemplate ( ) { var hours = parseInt( scope.hours, 10 ); var valid = ( scope.showMeridian ) ? (hours > 0 && hours < 13) : (hours >= 0 && hours < 24); if ( !valid ) { - return; + return undefined; } if ( scope.showMeridian ) { @@ -2526,9 +2824,17 @@ angular.module('ui.bootstrap.timepicker', []) return hours; } + function getMinutesFromTemplate() { + var minutes = parseInt(scope.minutes, 10); + return ( minutes >= 0 && minutes < 60 ) ? minutes : undefined; + } + + function pad( value ) { + return ( angular.isDefined(value) && value.toString().length < 2 ) ? '0' + value : value; + } + // Input elements - var inputs = element.find('input'); - var hoursInputEl = inputs.eq(0), minutesInputEl = inputs.eq(1); + var inputs = element.find('input'), hoursInputEl = inputs.eq(0), minutesInputEl = inputs.eq(1); // Respond on mousewheel spin var mousewheel = (angular.isDefined(attrs.mousewheel)) ? scope.$eval(attrs.mousewheel) : timepickerConfig.mousewheel; @@ -2538,64 +2844,70 @@ angular.module('ui.bootstrap.timepicker', []) if (e.originalEvent) { e = e.originalEvent; } - return (e.detail || e.wheelDelta > 0); + //pick correct delta variable depending on event + var delta = (e.wheelDelta) ? e.wheelDelta : -e.deltaY; + return (e.detail || delta > 0); }; - hoursInputEl.bind('mousewheel', function(e) { + hoursInputEl.bind('mousewheel wheel', function(e) { scope.$apply( (isScrollingUp(e)) ? scope.incrementHours() : scope.decrementHours() ); e.preventDefault(); }); - minutesInputEl.bind('mousewheel', function(e) { + minutesInputEl.bind('mousewheel wheel', function(e) { scope.$apply( (isScrollingUp(e)) ? scope.incrementMinutes() : scope.decrementMinutes() ); e.preventDefault(); }); } - var keyboardChange = false; scope.readonlyInput = (angular.isDefined(attrs.readonlyInput)) ? scope.$eval(attrs.readonlyInput) : timepickerConfig.readonlyInput; if ( ! scope.readonlyInput ) { + + var invalidate = function(invalidHours, invalidMinutes) { + ngModel.$setViewValue( null ); + ngModel.$setValidity('time', false); + if (angular.isDefined(invalidHours)) { + scope.invalidHours = invalidHours; + } + if (angular.isDefined(invalidMinutes)) { + scope.invalidMinutes = invalidMinutes; + } + }; + scope.updateHours = function() { - var hours = getScopeHours(); + var hours = getHoursFromTemplate(); if ( angular.isDefined(hours) ) { - keyboardChange = 'h'; - if ( scope.model === null ) { - scope.model = new Date( selected ); - } - scope.model.setHours( hours ); + selected.setHours( hours ); + refresh( 'h' ); } else { - scope.model = null; - scope.validHours = false; + invalidate(true); } }; hoursInputEl.bind('blur', function(e) { - if ( scope.validHours && scope.hours < 10) { + if ( !scope.validHours && scope.hours < 10) { scope.$apply( function() { - scope.hours = padFilter( scope.hours ); + scope.hours = pad( scope.hours ); }); } }); scope.updateMinutes = function() { - var minutes = parseInt(scope.minutes, 10); - if ( minutes >= 0 && minutes < 60 ) { - keyboardChange = 'm'; - if ( scope.model === null ) { - scope.model = new Date( selected ); - } - scope.model.setMinutes( minutes ); + var minutes = getMinutesFromTemplate(); + + if ( angular.isDefined(minutes) ) { + selected.setMinutes( minutes ); + refresh( 'm' ); } else { - scope.model = null; - scope.validMinutes = false; + invalidate(undefined, true); } }; minutesInputEl.bind('blur', function(e) { - if ( scope.validMinutes && scope.minutes < 10 ) { + if ( !scope.invalidMinutes && scope.minutes < 10 ) { scope.$apply( function() { - scope.minutes = padFilter( scope.minutes ); + scope.minutes = pad( scope.minutes ); }); } }); @@ -2604,40 +2916,49 @@ angular.module('ui.bootstrap.timepicker', []) scope.updateMinutes = angular.noop; } - scope.$watch( function getModelTimestamp() { - return +scope.model; - }, function( timestamp ) { - if ( !isNaN( timestamp ) && timestamp > 0 ) { - selected = new Date( timestamp ); - refreshTemplate(); - } - }); + ngModel.$render = function() { + var date = ngModel.$modelValue ? new Date( ngModel.$modelValue ) : null; + + if ( isNaN(date) ) { + ngModel.$setValidity('time', false); + $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.'); + } else { + if ( date ) { + selected = date; + } + makeValid(); + updateTemplate(); + } + }; + + // Call internally when we know that model is valid. + function refresh( keyboardChange ) { + makeValid(); + ngModel.$setViewValue( new Date(selected) ); + updateTemplate( keyboardChange ); + } + + function makeValid() { + ngModel.$setValidity('time', true); + scope.invalidHours = false; + scope.invalidMinutes = false; + } + + function updateTemplate( keyboardChange ) { + var hours = selected.getHours(), minutes = selected.getMinutes(); - function refreshTemplate() { - var hours = selected.getHours(); if ( scope.showMeridian ) { - // Convert 24 to 12 hour system - hours = ( hours === 0 || hours === 12 ) ? 12 : hours % 12; + hours = ( hours === 0 || hours === 12 ) ? 12 : hours % 12; // Convert 24 to 12 hour system } - scope.hours = ( keyboardChange === 'h' ) ? hours : padFilter(hours); - scope.validHours = true; - - var minutes = selected.getMinutes(); - scope.minutes = ( keyboardChange === 'm' ) ? minutes : padFilter(minutes); - scope.validMinutes = true; - - scope.meridian = ( scope.showMeridian ) ? (( selected.getHours() < 12 ) ? meridians[0] : meridians[1]) : ''; - - keyboardChange = false; + scope.hours = keyboardChange === 'h' ? hours : pad(hours); + scope.minutes = keyboardChange === 'm' ? minutes : pad(minutes); + scope.meridian = selected.getHours() < 12 ? meridians[0] : meridians[1]; } function addMinutes( minutes ) { var dt = new Date( selected.getTime() + minutes * 60000 ); - if ( dt.getDate() !== selected.getDate()) { - dt.setDate( dt.getDate() - 1 ); - } - selected.setTime( dt.getTime() ); - scope.model = new Date( selected ); + selected.setHours( dt.getHours(), dt.getMinutes() ); + refresh(); } scope.incrementHours = function() { @@ -2658,7 +2979,8 @@ angular.module('ui.bootstrap.timepicker', []) } }; }]); -angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position']) + +angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap.bindHtml']) /** * A helper service that can parse typeahead's syntax (string provided by users) @@ -2689,7 +3011,8 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position']) }; }]) - .directive('typeahead', ['$compile', '$parse', '$q', '$timeout', '$document', '$position', 'typeaheadParser', function ($compile, $parse, $q, $timeout, $document, $position, typeaheadParser) { + .directive('typeahead', ['$compile', '$parse', '$q', '$timeout', '$document', '$position', 'typeaheadParser', + function ($compile, $parse, $q, $timeout, $document, $position, typeaheadParser) { var HOT_KEYS = [9, 13, 27, 38, 40]; @@ -2697,7 +3020,7 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position']) require:'ngModel', link:function (originalScope, element, attrs, modelCtrl) { - var selected; + //SUPPORTED ATTRIBUTES (OPTIONS) //minimal no of characters that needs to be entered before typeahead kicks-in var minSearch = originalScope.$eval(attrs.typeaheadMinLength) || 1; @@ -2705,16 +3028,26 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position']) //minimal wait time after last character typed before typehead kicks-in var waitTime = originalScope.$eval(attrs.typeaheadWaitMs) || 0; - //expressions used by typeahead - var parserResult = typeaheadParser.parse(attrs.typeahead); - //should it restrict model values to the ones selected from the popup only? var isEditable = originalScope.$eval(attrs.typeaheadEditable) !== false; + //binding to a variable that indicates if matches are being retrieved asynchronously var isLoadingSetter = $parse(attrs.typeaheadLoading).assign || angular.noop; + //a callback executed when a match is selected var onSelectCallback = $parse(attrs.typeaheadOnSelect); + var inputFormatter = attrs.typeaheadInputFormatter ? $parse(attrs.typeaheadInputFormatter) : undefined; + + //INTERNAL VARIABLES + + //model setter executed upon match selection + var $setModelValue = $parse(attrs.ngModel).assign; + + //expressions used by typeahead + var parserResult = typeaheadParser.parse(attrs.typeahead); + + //pop-up element used to display matches var popUpEl = angular.element(''); popUpEl.attr({ @@ -2724,6 +3057,10 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position']) query: 'query', position: 'position' }); + //custom item template + if (angular.isDefined(attrs.typeaheadTemplateUrl)) { + popUpEl.attr('template-url', attrs.typeaheadTemplateUrl); + } //create a child scope for the typeahead directive so we are not polluting original scope //with typeahead-specific data (matches, query etc.) @@ -2783,55 +3120,77 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position']) //we need to propagate user's query so we can higlight matches scope.query = undefined; + //Declare the timeout promise var outside the function scope so that stacked calls can be cancelled later + var timeoutPromise; + //plug into $parsers pipeline to open a typeahead on view changes initiated from DOM //$parsers kick-in on all the changes coming from the view as well as manually triggered by $setViewValue - modelCtrl.$parsers.push(function (inputValue) { - - var timeoutId; + modelCtrl.$parsers.unshift(function (inputValue) { resetMatches(); - if (selected) { - return inputValue; - } else { - if (inputValue && inputValue.length >= minSearch) { - if (waitTime > 0) { - if (timeoutId) { - $timeout.cancel(timeoutId);//cancel previous timeout - } - timeoutId = $timeout(function () { - getMatchesAsync(inputValue); - }, waitTime); - } else { - getMatchesAsync(inputValue); + if (inputValue && inputValue.length >= minSearch) { + if (waitTime > 0) { + if (timeoutPromise) { + $timeout.cancel(timeoutPromise);//cancel previous timeout } + timeoutPromise = $timeout(function () { + getMatchesAsync(inputValue); + }, waitTime); + } else { + getMatchesAsync(inputValue); } } - return isEditable ? inputValue : undefined; + if (isEditable) { + return inputValue; + } else { + modelCtrl.$setValidity('editable', false); + return undefined; + } }); - modelCtrl.$render = function () { + modelCtrl.$formatters.push(function (modelValue) { + + var candidateViewValue, emptyViewValue; var locals = {}; - locals[parserResult.itemName] = selected || modelCtrl.$viewValue; - element.val(parserResult.viewMapper(scope, locals) || modelCtrl.$viewValue); - selected = undefined; - }; + + if (inputFormatter) { + + locals['$model'] = modelValue; + return inputFormatter(originalScope, locals); + + } else { + + //it might happen that we don't have enough info to properly render input value + //we need to check for this situation and simply return model value if we can't apply custom formatting + locals[parserResult.itemName] = modelValue; + candidateViewValue = parserResult.viewMapper(originalScope, locals); + locals[parserResult.itemName] = undefined; + emptyViewValue = parserResult.viewMapper(originalScope, locals); + + return candidateViewValue!== emptyViewValue ? candidateViewValue : modelValue; + } + }); scope.select = function (activeIdx) { //called from within the $digest() cycle var locals = {}; var model, item; - locals[parserResult.itemName] = item = selected = scope.matches[activeIdx].model; - model = parserResult.modelMapper(scope, locals); - modelCtrl.$setViewValue(model); - modelCtrl.$render(); - onSelectCallback(scope, { + locals[parserResult.itemName] = item = scope.matches[activeIdx].model; + model = parserResult.modelMapper(originalScope, locals); + $setModelValue(originalScope, model); + modelCtrl.$setValidity('editable', true); + + onSelectCallback(originalScope, { $item: item, $model: model, - $label: parserResult.viewMapper(scope, locals) + $label: parserResult.viewMapper(originalScope, locals) }); + resetMatches(); + + //return focus to the input element if a mach was selected via a mouse click event element[0].focus(); }; @@ -2866,9 +3225,18 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position']) } }); - $document.bind('click', function(){ - resetMatches(); - scope.$digest(); + // Keep reference to click handler to unbind it. + var dismissClickHandler = function (evt) { + if (element[0] !== evt.target) { + resetMatches(); + scope.$digest(); + } + }; + + $document.bind('click', dismissClickHandler); + + originalScope.$on('$destroy', function(){ + $document.unbind('click', dismissClickHandler); }); element.after($compile(popUpEl)(scope)); @@ -2888,9 +3256,11 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position']) select:'&' }, replace:true, - templateUrl:'template/typeahead/typeahead.html', + templateUrl:'template/typeahead/typeahead-popup.html', link:function (scope, element, attrs) { + scope.templateUrl = attrs.templateUrl; + scope.isOpen = function () { return scope.matches.length > 0; }; @@ -2910,6 +3280,23 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position']) }; }) + .directive('typeaheadMatch', ['$http', '$templateCache', '$compile', '$parse', function ($http, $templateCache, $compile, $parse) { + return { + restrict:'E', + scope:{ + index:'=', + match:'=', + query:'=' + }, + link:function (scope, element, attrs) { + var tplUrl = $parse(attrs.templateUrl)(scope.$parent) || 'template/typeahead/typeahead-match.html'; + $http.get(tplUrl, {cache: $templateCache}).success(function(tplContent){ + element.replaceWith($compile(tplContent.trim())(scope)); + }); + } + }; + }]) + .filter('typeaheadHighlight', function() { function escapeRegexp(queryToEscape) { @@ -2917,10 +3304,9 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position']) } return function(matchItem, query) { - return query ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '$&') : query; + return query ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '$&') : matchItem; }; }); - angular.module("template/accordion/accordion-group.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/accordion/accordion-group.html", "
    \n" + @@ -2971,12 +3357,12 @@ angular.module("template/carousel/slide.html", []).run(["$templateCache", functi angular.module("template/datepicker/datepicker.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/datepicker/datepicker.html", - "\n" + + "
    \n" + " \n" + " \n" + - " \n" + - " \n" + - " \n" + + " \n" + + " \n" + + " \n" + " \n" + " 0\">\n" + " \n" + @@ -2987,7 +3373,7 @@ angular.module("template/datepicker/datepicker.html", []).run(["$templateCache", " \n" + " \n" + " \n" + " \n" + " \n" + @@ -2995,28 +3381,30 @@ angular.module("template/datepicker/datepicker.html", []).run(["$templateCache", ""); }]); -angular.module("template/dialog/message.html", []).run(["$templateCache", function($templateCache) { - $templateCache.put("template/dialog/message.html", - "
    \n" + - "

    {{ title }}

    \n" + - "
    \n" + - "
    \n" + - "

    {{ message }}

    \n" + - "
    \n" + - "
    \n" + - " \n" + - "
    \n" + - ""); +angular.module("template/datepicker/popup.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/datepicker/popup.html", + "
      \n" + + "
    • \n" + + "
    • \n" + + "
    • \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
    • \n" + + "
    "); }]); angular.module("template/modal/backdrop.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/modal/backdrop.html", - "
    "); + "
    "); }]); angular.module("template/modal/window.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/modal/window.html", - "
    "); + "
    "); }]); angular.module("template/pagination/pager.html", []).run(["$templateCache", function($templateCache) { @@ -3082,9 +3470,8 @@ angular.module("template/progressbar/progress.html", []).run(["$templateCache", angular.module("template/rating/rating.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/rating/rating.html", "\n" + - " val}\">\n" + - "\n" + - ""); + " \n" + + ""); }]); angular.module("template/tabs/pane.html", []).run(["$templateCache", function($templateCache) { @@ -3114,19 +3501,26 @@ angular.module("template/tabs/tabs.html", []).run(["$templateCache", function($t ""); }]); +angular.module("template/tabs/tabset-titles.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/tabs/tabset-titles.html", + "
      \n" + + "
    \n" + + ""); +}]); + angular.module("template/tabs/tabset.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/tabs/tabset.html", "\n" + - "
    \n" + - "
      \n" + - "
    \n" + + "
    \n" + + "
    \n" + "
    \n" + "
    \n" + + " tab-content-transclude=\"tab\">\n" + "
    \n" + "
    \n" + + "
    \n" + "
    \n" + ""); }]); @@ -3141,10 +3535,10 @@ angular.module("template/timepicker/timepicker.html", []).run(["$templateCache", "
    \n" + " \n" + " \n" + - " \n" + + " \n" + " \n" + - " \n" + - " \n" + + " \n" + + " \n" + " \n" + " \n" + " \n" + @@ -3155,6 +3549,20 @@ angular.module("template/timepicker/timepicker.html", []).run(["$templateCache", "
    #
    {{ getWeekNumber(row) }}\n" + - " \n" + + " \n" + "
    :
    "); }]); +angular.module("template/typeahead/typeahead-match.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/typeahead/typeahead-match.html", + ""); +}]); + +angular.module("template/typeahead/typeahead-popup.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/typeahead/typeahead-popup.html", + "
      \n" + + "
    • \n" + + " \n" + + "
    • \n" + + "
    "); +}]); + angular.module("template/typeahead/typeahead.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/typeahead/typeahead.html", "
      \n" + diff --git a/ui/vendor/ui-bootstrap-tpls-0.6.0.min.js b/ui/vendor/ui-bootstrap-tpls-0.6.0.min.js new file mode 100755 index 000000000..2ac1a9d4b --- /dev/null +++ b/ui/vendor/ui-bootstrap-tpls-0.6.0.min.js @@ -0,0 +1,2 @@ +angular.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"]),angular.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"]),angular.module("ui.bootstrap.transition",[]).factory("$transition",["$q","$timeout","$rootScope",function(e,t,n){function a(e){for(var t in e)if(void 0!==r.style[t])return e[t]}var i=function(a,r,o){o=o||{};var l=e.defer(),s=i[o.animation?"animationEndEventName":"transitionEndEventName"],c=function(){n.$apply(function(){a.unbind(s,c),l.resolve(a)})};return s&&a.bind(s,c),t(function(){angular.isString(r)?a.addClass(r):angular.isFunction(r)?r(a):angular.isObject(r)&&a.css(r),s||l.resolve(a)}),l.promise.cancel=function(){s&&a.unbind(s,c),l.reject("Transition cancelled")},l.promise},r=document.createElement("trans"),o={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",transition:"transitionend"},l={WebkitTransition:"webkitAnimationEnd",MozTransition:"animationend",OTransition:"oAnimationEnd",transition:"animationend"};return i.transitionEndEventName=a(o),i.animationEndEventName=a(l),i}]),angular.module("ui.bootstrap.collapse",["ui.bootstrap.transition"]).directive("collapse",["$transition",function(e){var t=function(e,t,n){t.removeClass("collapse"),t.css({height:n}),t[0].offsetWidth,t.addClass("collapse")};return{link:function(n,a,i){var r,o=!0;n.$watch(function(){return a[0].scrollHeight},function(){0!==a[0].scrollHeight&&(r||(o?t(n,a,a[0].scrollHeight+"px"):t(n,a,"auto")))}),n.$watch(i.collapse,function(e){e?u():c()});var l,s=function(t){return l&&l.cancel(),l=e(a,t),l.then(function(){l=void 0},function(){l=void 0}),l},c=function(){o?(o=!1,r||t(n,a,"auto")):s({height:a[0].scrollHeight+"px"}).then(function(){r||t(n,a,"auto")}),r=!1},u=function(){r=!0,o?(o=!1,t(n,a,0)):(t(n,a,a[0].scrollHeight+"px"),s({height:"0"}))}}}}]),angular.module("ui.bootstrap.accordion",["ui.bootstrap.collapse"]).constant("accordionConfig",{closeOthers:!0}).controller("AccordionController",["$scope","$attrs","accordionConfig",function(e,t,n){this.groups=[],this.closeOthers=function(a){var i=angular.isDefined(t.closeOthers)?e.$eval(t.closeOthers):n.closeOthers;i&&angular.forEach(this.groups,function(e){e!==a&&(e.isOpen=!1)})},this.addGroup=function(e){var t=this;this.groups.push(e),e.$on("$destroy",function(){t.removeGroup(e)})},this.removeGroup=function(e){var t=this.groups.indexOf(e);-1!==t&&this.groups.splice(this.groups.indexOf(e),1)}}]).directive("accordion",function(){return{restrict:"EA",controller:"AccordionController",transclude:!0,replace:!1,templateUrl:"template/accordion/accordion.html"}}).directive("accordionGroup",["$parse","$transition","$timeout",function(e){return{require:"^accordion",restrict:"EA",transclude:!0,replace:!0,templateUrl:"template/accordion/accordion-group.html",scope:{heading:"@"},controller:["$scope",function(){this.setHeading=function(e){this.heading=e}}],link:function(t,n,a,i){var r,o;i.addGroup(t),t.isOpen=!1,a.isOpen&&(r=e(a.isOpen),o=r.assign,t.$watch(function(){return r(t.$parent)},function(e){t.isOpen=e}),t.isOpen=r?r(t.$parent):!1),t.$watch("isOpen",function(e){e&&i.closeOthers(t),o&&o(t.$parent,e)})}}}]).directive("accordionHeading",function(){return{restrict:"EA",transclude:!0,template:"",replace:!0,require:"^accordionGroup",compile:function(e,t,n){return function(e,t,a,i){i.setHeading(n(e,function(){}))}}}}).directive("accordionTransclude",function(){return{require:"^accordionGroup",link:function(e,t,n,a){e.$watch(function(){return a[n.accordionTransclude]},function(e){e&&(t.html(""),t.append(e))})}}}),angular.module("ui.bootstrap.alert",[]).directive("alert",function(){return{restrict:"EA",templateUrl:"template/alert/alert.html",transclude:!0,replace:!0,scope:{type:"=",close:"&"},link:function(e,t,n){e.closeable="close"in n}}}),angular.module("ui.bootstrap.bindHtml",[]).directive("bindHtmlUnsafe",function(){return function(e,t,n){t.addClass("ng-binding").data("$binding",n.bindHtmlUnsafe),e.$watch(n.bindHtmlUnsafe,function(e){t.html(e||"")})}}),angular.module("ui.bootstrap.buttons",[]).constant("buttonConfig",{activeClass:"active",toggleEvent:"click"}).directive("btnRadio",["buttonConfig",function(e){var t=e.activeClass||"active",n=e.toggleEvent||"click";return{require:"ngModel",link:function(e,a,i,r){r.$render=function(){a.toggleClass(t,angular.equals(r.$modelValue,e.$eval(i.btnRadio)))},a.bind(n,function(){a.hasClass(t)||e.$apply(function(){r.$setViewValue(e.$eval(i.btnRadio)),r.$render()})})}}}]).directive("btnCheckbox",["buttonConfig",function(e){var t=e.activeClass||"active",n=e.toggleEvent||"click";return{require:"ngModel",link:function(e,a,i,r){function o(){var t=e.$eval(i.btnCheckboxTrue);return angular.isDefined(t)?t:!0}function l(){var t=e.$eval(i.btnCheckboxFalse);return angular.isDefined(t)?t:!1}r.$render=function(){a.toggleClass(t,angular.equals(r.$modelValue,o()))},a.bind(n,function(){e.$apply(function(){r.$setViewValue(a.hasClass(t)?l():o()),r.$render()})})}}}]),angular.module("ui.bootstrap.carousel",["ui.bootstrap.transition"]).controller("CarouselController",["$scope","$timeout","$transition","$q",function(e,t,n){function a(){function n(){r?(e.next(),a()):e.pause()}i&&t.cancel(i);var o=+e.interval;!isNaN(o)&&o>=0&&(i=t(n,o))}var i,r,o=this,l=o.slides=[],s=-1;o.currentSlide=null,o.select=function(i,r){function c(){o.currentSlide&&angular.isString(r)&&!e.noTransition&&i.$element?(i.$element.addClass(r),i.$element[0].offsetWidth,angular.forEach(l,function(e){angular.extend(e,{direction:"",entering:!1,leaving:!1,active:!1})}),angular.extend(i,{direction:r,active:!0,entering:!0}),angular.extend(o.currentSlide||{},{direction:r,leaving:!0}),e.$currentTransition=n(i.$element,{}),function(t,n){e.$currentTransition.then(function(){u(t,n)},function(){u(t,n)})}(i,o.currentSlide)):u(i,o.currentSlide),o.currentSlide=i,s=p,a()}function u(t,n){angular.extend(t,{direction:"",active:!0,leaving:!1,entering:!1}),angular.extend(n||{},{direction:"",active:!1,leaving:!1,entering:!1}),e.$currentTransition=null}var p=l.indexOf(i);void 0===r&&(r=p>s?"next":"prev"),i&&i!==o.currentSlide&&(e.$currentTransition?(e.$currentTransition.cancel(),t(c)):c())},o.indexOfSlide=function(e){return l.indexOf(e)},e.next=function(){var t=(s+1)%l.length;return e.$currentTransition?void 0:o.select(l[t],"next")},e.prev=function(){var t=0>s-1?l.length-1:s-1;return e.$currentTransition?void 0:o.select(l[t],"prev")},e.select=function(e){o.select(e)},e.isActive=function(e){return o.currentSlide===e},e.slides=function(){return l},e.$watch("interval",a),e.play=function(){r||(r=!0,a())},e.pause=function(){e.noPause||(r=!1,i&&t.cancel(i))},o.addSlide=function(t,n){t.$element=n,l.push(t),1===l.length||t.active?(o.select(l[l.length-1]),1==l.length&&e.play()):t.active=!1},o.removeSlide=function(e){var t=l.indexOf(e);l.splice(t,1),l.length>0&&e.active?t>=l.length?o.select(l[t-1]):o.select(l[t]):s>t&&s--}}]).directive("carousel",[function(){return{restrict:"EA",transclude:!0,replace:!0,controller:"CarouselController",require:"carousel",templateUrl:"template/carousel/carousel.html",scope:{interval:"=",noTransition:"=",noPause:"="}}}]).directive("slide",["$parse",function(e){return{require:"^carousel",restrict:"EA",transclude:!0,replace:!0,templateUrl:"template/carousel/slide.html",scope:{},link:function(t,n,a,i){if(a.active){var r=e(a.active),o=r.assign,l=t.active=r(t.$parent);t.$watch(function(){var e=r(t.$parent);return e!==t.active&&(e!==l?l=t.active=e:o(t.$parent,e=l=t.active)),e})}i.addSlide(t,n),t.$on("$destroy",function(){i.removeSlide(t)}),t.$watch("active",function(e){e&&i.select(t)})}}}]),angular.module("ui.bootstrap.position",[]).factory("$position",["$document","$window",function(e,t){function n(e,n){return e.currentStyle?e.currentStyle[n]:t.getComputedStyle?t.getComputedStyle(e)[n]:e.style[n]}function a(e){return"static"===(n(e,"position")||"static")}var i=function(t){for(var n=e[0],i=t.offsetParent||n;i&&i!==n&&a(i);)i=i.offsetParent;return i||n};return{position:function(t){var n=this.offset(t),a={top:0,left:0},r=i(t[0]);return r!=e[0]&&(a=this.offset(angular.element(r)),a.top+=r.clientTop-r.scrollTop,a.left+=r.clientLeft-r.scrollLeft),{width:t.prop("offsetWidth"),height:t.prop("offsetHeight"),top:n.top-a.top,left:n.left-a.left}},offset:function(n){var a=n[0].getBoundingClientRect();return{width:n.prop("offsetWidth"),height:n.prop("offsetHeight"),top:a.top+(t.pageYOffset||e[0].body.scrollTop||e[0].documentElement.scrollTop),left:a.left+(t.pageXOffset||e[0].body.scrollLeft||e[0].documentElement.scrollLeft)}}}}]),angular.module("ui.bootstrap.datepicker",["ui.bootstrap.position"]).constant("datepickerConfig",{dayFormat:"dd",monthFormat:"MMMM",yearFormat:"yyyy",dayHeaderFormat:"EEE",dayTitleFormat:"MMMM yyyy",monthTitleFormat:"yyyy",showWeeks:!0,startingDay:0,yearRange:20,minDate:null,maxDate:null}).controller("DatepickerController",["$scope","$attrs","dateFilter","datepickerConfig",function(e,t,n,a){function i(t,n){return angular.isDefined(t)?e.$parent.$eval(t):n}function r(e,t){return new Date(e,t,0).getDate()}function o(e,t){for(var n=Array(t),a=e,i=0;t>i;)n[i++]=new Date(a),a.setDate(a.getDate()+1);return n}function l(e,t,a,i){return{date:e,label:n(e,t),selected:!!a,secondary:!!i}}var s={day:i(t.dayFormat,a.dayFormat),month:i(t.monthFormat,a.monthFormat),year:i(t.yearFormat,a.yearFormat),dayHeader:i(t.dayHeaderFormat,a.dayHeaderFormat),dayTitle:i(t.dayTitleFormat,a.dayTitleFormat),monthTitle:i(t.monthTitleFormat,a.monthTitleFormat)},c=i(t.startingDay,a.startingDay),u=i(t.yearRange,a.yearRange);this.minDate=a.minDate?new Date(a.minDate):null,this.maxDate=a.maxDate?new Date(a.maxDate):null,this.modes=[{name:"day",getVisibleDates:function(e,t){var a=e.getFullYear(),i=e.getMonth(),u=new Date(a,i,1),p=c-u.getDay(),d=p>0?7-p:-p,f=new Date(u),m=0;d>0&&(f.setDate(-d+1),m+=d),m+=r(a,i+1),m+=(7-m%7)%7;for(var g=o(f,m),h=Array(7),v=0;m>v;v++){var b=new Date(g[v]);g[v]=l(b,s.day,t&&t.getDate()===b.getDate()&&t.getMonth()===b.getMonth()&&t.getFullYear()===b.getFullYear(),b.getMonth()!==i)}for(var $=0;7>$;$++)h[$]=n(g[$].date,s.dayHeader);return{objects:g,title:n(e,s.dayTitle),labels:h}},compare:function(e,t){return new Date(e.getFullYear(),e.getMonth(),e.getDate())-new Date(t.getFullYear(),t.getMonth(),t.getDate())},split:7,step:{months:1}},{name:"month",getVisibleDates:function(e,t){for(var a=Array(12),i=e.getFullYear(),r=0;12>r;r++){var o=new Date(i,r,1);a[r]=l(o,s.month,t&&t.getMonth()===r&&t.getFullYear()===i)}return{objects:a,title:n(e,s.monthTitle)}},compare:function(e,t){return new Date(e.getFullYear(),e.getMonth())-new Date(t.getFullYear(),t.getMonth())},split:3,step:{years:1}},{name:"year",getVisibleDates:function(e,t){for(var n=Array(u),a=e.getFullYear(),i=parseInt((a-1)/u,10)*u+1,r=0;u>r;r++){var o=new Date(i+r,0,1);n[r]=l(o,s.year,t&&t.getFullYear()===o.getFullYear())}return{objects:n,title:[n[0].label,n[u-1].label].join(" - ")}},compare:function(e,t){return e.getFullYear()-t.getFullYear()},split:5,step:{years:u}}],this.isDisabled=function(t,n){var a=this.modes[n||0];return this.minDate&&0>a.compare(t,this.minDate)||this.maxDate&&a.compare(t,this.maxDate)>0||e.dateDisabled&&e.dateDisabled({date:t,mode:a.name})}}]).directive("datepicker",["dateFilter","$parse","datepickerConfig","$log",function(e,t,n,a){return{restrict:"EA",replace:!0,templateUrl:"template/datepicker/datepicker.html",scope:{dateDisabled:"&"},require:["datepicker","?^ngModel"],controller:"DatepickerController",link:function(e,i,r,o){function l(){e.showWeekNumbers=0===m&&h}function s(e,t){for(var n=[];e.length>0;)n.push(e.splice(0,t));return n}function c(t){var n=null,i=!0;f.$modelValue&&(n=new Date(f.$modelValue),isNaN(n)?(i=!1,a.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.')):t&&(g=n)),f.$setValidity("date",i);var r=d.modes[m],o=r.getVisibleDates(g,n);angular.forEach(o.objects,function(e){e.disabled=d.isDisabled(e.date,m)}),f.$setValidity("date-disabled",!n||!d.isDisabled(n)),e.rows=s(o.objects,r.split),e.labels=o.labels||[],e.title=o.title}function u(e){m=e,l(),c()}function p(e){var t=new Date(e);t.setDate(t.getDate()+4-(t.getDay()||7));var n=t.getTime();return t.setMonth(0),t.setDate(1),Math.floor(Math.round((n-t)/864e5)/7)+1}var d=o[0],f=o[1];if(f){var m=0,g=new Date,h=n.showWeeks;r.showWeeks?e.$parent.$watch(t(r.showWeeks),function(e){h=!!e,l()}):l(),r.min&&e.$parent.$watch(t(r.min),function(e){d.minDate=e?new Date(e):null,c()}),r.max&&e.$parent.$watch(t(r.max),function(e){d.maxDate=e?new Date(e):null,c()}),f.$render=function(){c(!0)},e.select=function(e){if(0===m){var t=new Date(f.$modelValue);t.setFullYear(e.getFullYear(),e.getMonth(),e.getDate()),f.$setViewValue(t),c(!0)}else g=e,u(m-1)},e.move=function(e){var t=d.modes[m].step;g.setMonth(g.getMonth()+e*(t.months||0)),g.setFullYear(g.getFullYear()+e*(t.years||0)),c()},e.toggleMode=function(){u((m+1)%d.modes.length)},e.getWeekNumber=function(t){return 0===m&&e.showWeekNumbers&&7===t.length?p(t[0].date):null}}}}}]).constant("datepickerPopupConfig",{dateFormat:"yyyy-MM-dd",closeOnDateSelection:!0}).directive("datepickerPopup",["$compile","$parse","$document","$position","dateFilter","datepickerPopupConfig",function(e,t,n,a,i,r){return{restrict:"EA",require:"ngModel",link:function(o,l,s,c){function u(e){$?$(o,!!e):v.isOpen=!!e}function p(e){if(e){if(angular.isDate(e))return c.$setValidity("date",!0),e;if(angular.isString(e)){var t=new Date(e);return isNaN(t)?(c.$setValidity("date",!1),void 0):(c.$setValidity("date",!0),t)}return c.$setValidity("date",!1),void 0}return c.$setValidity("date",!0),null}function d(){v.date=c.$modelValue,m()}function f(e,n,a){e&&(o.$watch(t(e),function(e){v[n]=e}),D.attr(a||n,n))}function m(){v.position=a.position(l),v.position.top=v.position.top+l.prop("offsetHeight")}var g=angular.isDefined(s.closeOnDateSelection)?v.$eval(s.closeOnDateSelection):r.closeOnDateSelection,h=s.datepickerPopup||r.dateFormat,v=o.$new();o.$on("$destroy",function(){v.$destroy()});var b,$;s.isOpen&&(b=t(s.isOpen),$=b.assign,o.$watch(b,function(e){v.isOpen=!!e})),v.isOpen=b?b(o):!1;var y=function(e){v.isOpen&&e.target!==l[0]&&v.$apply(function(){u(!1)})},w=function(){v.$apply(function(){u(!0)})},k=angular.element("");k.attr({"ng-model":"date","ng-change":"dateSelection()"});var D=k.find("datepicker");s.datepickerOptions&&D.attr(angular.extend({},o.$eval(s.datepickerOptions))),c.$parsers.unshift(p),v.dateSelection=function(){c.$setViewValue(v.date),c.$render(),g&&u(!1)},l.bind("input change keyup",function(){v.$apply(function(){d()})}),c.$render=function(){var e=c.$viewValue?i(c.$viewValue,h):"";l.val(e),d()},f(s.min,"min"),f(s.max,"max"),s.showWeeks?f(s.showWeeks,"showWeeks","show-weeks"):(v.showWeeks=!0,D.attr("show-weeks","showWeeks")),s.dateDisabled&&D.attr("date-disabled",s.dateDisabled);var x=!1,T=!1;v.$watch("isOpen",function(e){e?(m(),n.bind("click",y),T&&l.unbind("focus",w),l[0].focus(),x=!0):(x&&n.unbind("click",y),l.bind("focus",w),T=!0),$&&$(o,e)});var C=t(s.ngModel).assign;v.today=function(){C(o,new Date)},v.clear=function(){C(o,null)},l.after(e(k)(v))}}}]).directive("datepickerPopupWrap",[function(){return{restrict:"E",replace:!0,transclude:!0,templateUrl:"template/datepicker/popup.html",link:function(e,t){t.bind("click",function(e){e.preventDefault(),e.stopPropagation()})}}}]),angular.module("ui.bootstrap.dropdownToggle",[]).directive("dropdownToggle",["$document","$location",function(e){var t=null,n=angular.noop;return{restrict:"CA",link:function(a,i){a.$watch("$location.path",function(){n()}),i.parent().bind("click",function(){n()}),i.bind("click",function(a){var r=i===t;a.preventDefault(),a.stopPropagation(),t&&n(),r||(i.parent().addClass("open"),t=i,n=function(a){a&&(a.preventDefault(),a.stopPropagation()),e.unbind("click",n),i.parent().removeClass("open"),n=angular.noop,t=null},e.bind("click",n))})}}}]),angular.module("ui.bootstrap.modal",[]).factory("$$stackedMap",function(){return{createNew:function(){var e=[];return{add:function(t,n){e.push({key:t,value:n})},get:function(t){for(var n=0;e.length>n;n++)if(t==e[n].key)return e[n]},keys:function(){for(var t=[],n=0;e.length>n;n++)t.push(e[n].key);return t},top:function(){return e[e.length-1]},remove:function(t){for(var n=-1,a=0;e.length>a;a++)if(t==e[a].key){n=a;break}return e.splice(n,1)[0]},removeTop:function(){return e.splice(e.length-1,1)[0]},length:function(){return e.length}}}}}).directive("modalBackdrop",["$modalStack","$timeout",function(e,t){return{restrict:"EA",replace:!0,templateUrl:"template/modal/backdrop.html",link:function(n){t(function(){n.animate=!0}),n.close=function(t){var n=e.getTop();n&&n.value.backdrop&&"static"!=n.value.backdrop&&(t.preventDefault(),t.stopPropagation(),e.dismiss(n.key,"backdrop click"))}}}}]).directive("modalWindow",["$timeout",function(e){return{restrict:"EA",scope:{index:"@"},replace:!0,transclude:!0,templateUrl:"template/modal/window.html",link:function(t,n,a){t.windowClass=a.windowClass||"",e(function(){t.animate=!0})}}}]).factory("$modalStack",["$document","$compile","$rootScope","$$stackedMap",function(e,t,n,a){function i(){for(var e=-1,t=u.keys(),n=0;t.length>n;n++)u.get(t[n]).value.backdrop&&(e=n);return e}function r(e){var t=u.get(e).value;u.remove(e),t.modalDomEl.remove(),-1==i()&&(l.remove(),l=void 0),t.modalScope.$destroy()}var o,l,s=n.$new(!0),c=e.find("body").eq(0),u=a.createNew(),p={};return n.$watch(i,function(e){s.index=e}),e.bind("keydown",function(e){var t;27===e.which&&(t=u.top(),t&&t.value.keyboard&&n.$apply(function(){p.dismiss(t.key)}))}),p.open=function(e,n){u.add(e,{deferred:n.deferred,modalScope:n.scope,backdrop:n.backdrop,keyboard:n.keyboard});var a=angular.element("
      ");a.attr("window-class",n.windowClass),a.attr("index",u.length()-1),a.html(n.content);var r=t(a)(n.scope);u.top().value.modalDomEl=r,c.append(r),i()>=0&&!l&&(o=angular.element("
      "),l=t(o)(s),c.append(l))},p.close=function(e,t){var n=u.get(e);n&&(n.value.deferred.resolve(t),r(e))},p.dismiss=function(e,t){var n=u.get(e).value;n&&(n.deferred.reject(t),r(e))},p.getTop=function(){return u.top()},p}]).provider("$modal",function(){var e={options:{backdrop:!0,keyboard:!0},$get:["$injector","$rootScope","$q","$http","$templateCache","$controller","$modalStack",function(t,n,a,i,r,o,l){function s(e){return e.template?a.when(e.template):i.get(e.templateUrl,{cache:r}).then(function(e){return e.data})}function c(e){var n=[];return angular.forEach(e,function(e){(angular.isFunction(e)||angular.isArray(e))&&n.push(a.when(t.invoke(e)))}),n}var u={};return u.open=function(t){var i=a.defer(),r=a.defer(),u={result:i.promise,opened:r.promise,close:function(e){l.close(u,e)},dismiss:function(e){l.dismiss(u,e)}};if(t=angular.extend({},e.options,t),t.resolve=t.resolve||{},!t.template&&!t.templateUrl)throw Error("One of template or templateUrl options is required.");var p=a.all([s(t)].concat(c(t.resolve)));return p.then(function(e){var a=(t.scope||n).$new();a.$close=u.close,a.$dismiss=u.dismiss;var r,s={},c=1;t.controller&&(s.$scope=a,s.$modalInstance=u,angular.forEach(t.resolve,function(t,n){s[n]=e[c++]}),r=o(t.controller,s)),l.open(u,{scope:a,deferred:i,content:e[0],backdrop:t.backdrop,keyboard:t.keyboard,windowClass:t.windowClass})},function(e){i.reject(e)}),p.then(function(){r.resolve(!0)},function(){r.reject(!1)}),u},u}]};return e}),angular.module("ui.bootstrap.pagination",[]).controller("PaginationController",["$scope","$attrs","$parse","$interpolate",function(e,t,n,a){var i=this;this.init=function(a){t.itemsPerPage?e.$parent.$watch(n(t.itemsPerPage),function(t){i.itemsPerPage=parseInt(t,10),e.totalPages=i.calculateTotalPages()}):this.itemsPerPage=a},this.noPrevious=function(){return 1===this.page},this.noNext=function(){return this.page===e.totalPages},this.isActive=function(e){return this.page===e},this.calculateTotalPages=function(){return 1>this.itemsPerPage?1:Math.ceil(e.totalItems/this.itemsPerPage)},this.getAttributeValue=function(t,n,i){return angular.isDefined(t)?i?a(t)(e.$parent):e.$parent.$eval(t):n},this.render=function(){this.page=parseInt(e.page,10)||1,e.pages=this.getPages(this.page,e.totalPages)},e.selectPage=function(t){!i.isActive(t)&&t>0&&e.totalPages>=t&&(e.page=t,e.onSelectPage({page:t}))},e.$watch("totalItems",function(){e.totalPages=i.calculateTotalPages()}),e.$watch("totalPages",function(n){t.numPages&&(e.numPages=n),i.page>n?e.selectPage(n):i.render()}),e.$watch("page",function(){i.render()})}]).constant("paginationConfig",{itemsPerPage:10,boundaryLinks:!1,directionLinks:!0,firstText:"First",previousText:"Previous",nextText:"Next",lastText:"Last",rotate:!0}).directive("pagination",["$parse","paginationConfig",function(e,t){return{restrict:"EA",scope:{page:"=",totalItems:"=",onSelectPage:" &",numPages:"="},controller:"PaginationController",templateUrl:"template/pagination/pagination.html",replace:!0,link:function(n,a,i,r){function o(e,t,n,a){return{number:e,text:t,active:n,disabled:a}}var l,s=r.getAttributeValue(i.boundaryLinks,t.boundaryLinks),c=r.getAttributeValue(i.directionLinks,t.directionLinks),u=r.getAttributeValue(i.firstText,t.firstText,!0),p=r.getAttributeValue(i.previousText,t.previousText,!0),d=r.getAttributeValue(i.nextText,t.nextText,!0),f=r.getAttributeValue(i.lastText,t.lastText,!0),m=r.getAttributeValue(i.rotate,t.rotate);r.init(t.itemsPerPage),i.maxSize&&n.$parent.$watch(e(i.maxSize),function(e){l=parseInt(e,10),r.render()}),r.getPages=function(e,t){var n=[],a=1,i=t,g=angular.isDefined(l)&&t>l;g&&(m?(a=Math.max(e-Math.floor(l/2),1),i=a+l-1,i>t&&(i=t,a=i-l+1)):(a=(Math.ceil(e/l)-1)*l+1,i=Math.min(a+l-1,t)));for(var h=a;i>=h;h++){var v=o(h,h,r.isActive(h),!1);n.push(v)}if(g&&!m){if(a>1){var b=o(a-1,"...",!1,!1);n.unshift(b)}if(t>i){var $=o(i+1,"...",!1,!1);n.push($)}}if(c){var y=o(e-1,p,!1,r.noPrevious());n.unshift(y);var w=o(e+1,d,!1,r.noNext());n.push(w)}if(s){var k=o(1,u,!1,r.noPrevious());n.unshift(k);var D=o(t,f,!1,r.noNext());n.push(D)}return n}}}}]).constant("pagerConfig",{itemsPerPage:10,previousText:"« Previous",nextText:"Next »",align:!0}).directive("pager",["pagerConfig",function(e){return{restrict:"EA",scope:{page:"=",totalItems:"=",onSelectPage:" &",numPages:"="},controller:"PaginationController",templateUrl:"template/pagination/pager.html",replace:!0,link:function(t,n,a,i){function r(e,t,n,a,i){return{number:e,text:t,disabled:n,previous:s&&a,next:s&&i}}var o=i.getAttributeValue(a.previousText,e.previousText,!0),l=i.getAttributeValue(a.nextText,e.nextText,!0),s=i.getAttributeValue(a.align,e.align);i.init(e.itemsPerPage),i.getPages=function(e){return[r(e-1,o,i.noPrevious(),!0,!1),r(e+1,l,i.noNext(),!1,!0)]}}}}]),angular.module("ui.bootstrap.tooltip",["ui.bootstrap.position","ui.bootstrap.bindHtml"]).provider("$tooltip",function(){function e(e){var t=/[A-Z]/g,n="-";return e.replace(t,function(e,t){return(t?n:"")+e.toLowerCase()})}var t={placement:"top",animation:!0,popupDelay:0},n={mouseenter:"mouseleave",click:"click",focus:"blur"},a={};this.options=function(e){angular.extend(a,e)},this.setTriggers=function(e){angular.extend(n,e)},this.$get=["$window","$compile","$timeout","$parse","$document","$position","$interpolate",function(i,r,o,l,s,c,u){return function(i,p,d){function f(e){var t=e||m.trigger||d,a=n[t]||t;return{show:t,hide:a}}var m=angular.extend({},t,a),g=e(i),h=u.startSymbol(),v=u.endSymbol(),b="<"+g+"-popup "+'title="'+h+"tt_title"+v+'" '+'content="'+h+"tt_content"+v+'" '+'placement="'+h+"tt_placement"+v+'" '+'animation="tt_animation()" '+'is-open="tt_isOpen"'+">"+"";return{restrict:"EA",scope:!0,link:function(e,t,n){function a(){e.tt_isOpen?d():u()}function u(){e.tt_popupDelay?$=o(g,e.tt_popupDelay):e.$apply(g)}function d(){e.$apply(function(){h()})}function g(){var n,a,i,r;if(e.tt_content){switch(v&&o.cancel(v),w.css({top:0,left:0,display:"block"}),k?(y=y||s.find("body"),y.append(w)):t.after(w),n=k?c.offset(t):c.position(t),a=w.prop("offsetWidth"),i=w.prop("offsetHeight"),e.tt_placement){case"right":r={top:n.top+n.height/2-i/2,left:n.left+n.width};break;case"bottom":r={top:n.top+n.height,left:n.left+n.width/2-a/2};break;case"left":r={top:n.top+n.height/2-i/2,left:n.left-a};break;default:r={top:n.top-i,left:n.left+n.width/2-a/2}}r.top+="px",r.left+="px",w.css(r),e.tt_isOpen=!0}}function h(){e.tt_isOpen=!1,o.cancel($),angular.isDefined(e.tt_animation)&&e.tt_animation()?v=o(function(){w.remove()},500):w.remove()}var v,$,y,w=r(b)(e),k=angular.isDefined(m.appendToBody)?m.appendToBody:!1,D=f(void 0),x=!1;e.tt_isOpen=!1,n.$observe(i,function(t){e.tt_content=t}),n.$observe(p+"Title",function(t){e.tt_title=t}),n.$observe(p+"Placement",function(t){e.tt_placement=angular.isDefined(t)?t:m.placement}),n.$observe(p+"Animation",function(t){e.tt_animation=angular.isDefined(t)?l(t):function(){return m.animation}}),n.$observe(p+"PopupDelay",function(t){var n=parseInt(t,10);e.tt_popupDelay=isNaN(n)?m.popupDelay:n}),n.$observe(p+"Trigger",function(e){x&&(t.unbind(D.show,u),t.unbind(D.hide,d)),D=f(e),D.show===D.hide?t.bind(D.show,a):(t.bind(D.show,u),t.bind(D.hide,d)),x=!0}),n.$observe(p+"AppendToBody",function(t){k=angular.isDefined(t)?l(t)(e):k}),k&&e.$on("$locationChangeSuccess",function(){e.tt_isOpen&&h()}),e.$on("$destroy",function(){e.tt_isOpen?h():w.remove()})}}}}]}).directive("tooltipPopup",function(){return{restrict:"E",replace:!0,scope:{content:"@",placement:"@",animation:"&",isOpen:"&"},templateUrl:"template/tooltip/tooltip-popup.html"}}).directive("tooltip",["$tooltip",function(e){return e("tooltip","tooltip","mouseenter")}]).directive("tooltipHtmlUnsafePopup",function(){return{restrict:"E",replace:!0,scope:{content:"@",placement:"@",animation:"&",isOpen:"&"},templateUrl:"template/tooltip/tooltip-html-unsafe-popup.html"}}).directive("tooltipHtmlUnsafe",["$tooltip",function(e){return e("tooltipHtmlUnsafe","tooltip","mouseenter")}]),angular.module("ui.bootstrap.popover",["ui.bootstrap.tooltip"]).directive("popoverPopup",function(){return{restrict:"EA",replace:!0,scope:{title:"@",content:"@",placement:"@",animation:"&",isOpen:"&"},templateUrl:"template/popover/popover.html"}}).directive("popover",["$compile","$timeout","$parse","$window","$tooltip",function(e,t,n,a,i){return i("popover","popover","click")}]),angular.module("ui.bootstrap.progressbar",["ui.bootstrap.transition"]).constant("progressConfig",{animate:!0,autoType:!1,stackedTypes:["success","info","warning","danger"]}).controller("ProgressBarController",["$scope","$attrs","progressConfig",function(e,t,n){function a(e){return o[e]}var i=angular.isDefined(t.animate)?e.$eval(t.animate):n.animate,r=angular.isDefined(t.autoType)?e.$eval(t.autoType):n.autoType,o=angular.isDefined(t.stackedTypes)?e.$eval("["+t.stackedTypes+"]"):n.stackedTypes;this.makeBar=function(e,t,n){var o=angular.isObject(e)?e.value:e||0,l=angular.isObject(t)?t.value:t||0,s=angular.isObject(e)&&angular.isDefined(e.type)?e.type:r?a(n||0):null;return{from:l,to:o,type:s,animate:i}},this.addBar=function(t){e.bars.push(t),e.totalPercent+=t.to},this.clearBars=function(){e.bars=[],e.totalPercent=0},this.clearBars()}]).directive("progress",function(){return{restrict:"EA",replace:!0,controller:"ProgressBarController",scope:{value:"=percent",onFull:"&",onEmpty:"&"},templateUrl:"template/progressbar/progress.html",link:function(e,t,n,a){e.$watch("value",function(e,t){if(a.clearBars(),angular.isArray(e))for(var n=0,i=e.length;i>n;n++)a.addBar(a.makeBar(e[n],t[n],n));else a.addBar(a.makeBar(e,t))},!0),e.$watch("totalPercent",function(t){t>=100?e.onFull():0>=t&&e.onEmpty()},!0)}}}).directive("progressbar",["$transition",function(e){return{restrict:"EA",replace:!0,scope:{width:"=",old:"=",type:"=",animate:"="},templateUrl:"template/progressbar/bar.html",link:function(t,n){t.$watch("width",function(a){t.animate?(n.css("width",t.old+"%"),e(n,{width:a+"%"})):n.css("width",a+"%")})}}}]),angular.module("ui.bootstrap.rating",[]).constant("ratingConfig",{max:5,stateOn:null,stateOff:null}).controller("RatingController",["$scope","$attrs","$parse","ratingConfig",function(e,t,n,a){this.maxRange=angular.isDefined(t.max)?e.$parent.$eval(t.max):a.max,this.stateOn=angular.isDefined(t.stateOn)?e.$parent.$eval(t.stateOn):a.stateOn,this.stateOff=angular.isDefined(t.stateOff)?e.$parent.$eval(t.stateOff):a.stateOff,this.createDefaultRange=function(e){for(var t={stateOn:this.stateOn,stateOff:this.stateOff},n=Array(e),a=0;e>a;a++)n[a]=t;return n},this.normalizeRange=function(e){for(var t=0,n=e.length;n>t;t++)e[t].stateOn=e[t].stateOn||this.stateOn,e[t].stateOff=e[t].stateOff||this.stateOff;return e},e.range=angular.isDefined(t.ratingStates)?this.normalizeRange(angular.copy(e.$parent.$eval(t.ratingStates))):this.createDefaultRange(this.maxRange),e.rate=function(t){e.readonly||e.value===t||(e.value=t)},e.enter=function(t){e.readonly||(e.val=t),e.onHover({value:t})},e.reset=function(){e.val=angular.copy(e.value),e.onLeave()},e.$watch("value",function(t){e.val=t}),e.readonly=!1,t.readonly&&e.$parent.$watch(n(t.readonly),function(t){e.readonly=!!t})}]).directive("rating",function(){return{restrict:"EA",scope:{value:"=",onHover:"&",onLeave:"&"},controller:"RatingController",templateUrl:"template/rating/rating.html",replace:!0}}),angular.module("ui.bootstrap.tabs",[]).directive("tabs",function(){return function(){throw 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")}}).controller("TabsetController",["$scope","$element",function(e){var t=this,n=t.tabs=e.tabs=[];t.select=function(e){angular.forEach(n,function(e){e.active=!1}),e.active=!0},t.addTab=function(e){n.push(e),(1===n.length||e.active)&&t.select(e)},t.removeTab=function(e){var a=n.indexOf(e);if(e.active&&n.length>1){var i=a==n.length-1?a-1:a+1;t.select(n[i])}n.splice(a,1)}}]).directive("tabset",function(){return{restrict:"EA",transclude:!0,replace:!0,require:"^tabset",scope:{},controller:"TabsetController",templateUrl:"template/tabs/tabset.html",compile:function(e,t,n){return function(e,t,a,i){e.vertical=angular.isDefined(a.vertical)?e.$parent.$eval(a.vertical):!1,e.type=angular.isDefined(a.type)?e.$parent.$eval(a.type):"tabs",e.direction=angular.isDefined(a.direction)?e.$parent.$eval(a.direction):"top",e.tabsAbove="below"!=e.direction,i.$scope=e,i.$transcludeFn=n}}}}).directive("tab",["$parse","$http","$templateCache","$compile",function(e){return{require:"^tabset",restrict:"EA",replace:!0,templateUrl:"template/tabs/tab.html",transclude:!0,scope:{heading:"@",onSelect:"&select",onDeselect:"&deselect"},controller:function(){},compile:function(t,n,a){return function(t,n,i,r){var o,l; +i.active?(o=e(i.active),l=o.assign,t.$parent.$watch(o,function(e){t.active=!!e}),t.active=o(t.$parent)):l=o=angular.noop,t.$watch("active",function(e){l(t.$parent,e),e?(r.select(t),t.onSelect()):t.onDeselect()}),t.disabled=!1,i.disabled&&t.$parent.$watch(e(i.disabled),function(e){t.disabled=!!e}),t.select=function(){t.disabled||(t.active=!0)},r.addTab(t),t.$on("$destroy",function(){r.removeTab(t)}),t.active&&l(t.$parent,!0),t.$transcludeFn=a}}}}]).directive("tabHeadingTransclude",[function(){return{restrict:"A",require:"^tab",link:function(e,t){e.$watch("headingElement",function(e){e&&(t.html(""),t.append(e))})}}}]).directive("tabContentTransclude",["$compile","$parse",function(){function e(e){return e.tagName&&(e.hasAttribute("tab-heading")||e.hasAttribute("data-tab-heading")||"tab-heading"===e.tagName.toLowerCase()||"data-tab-heading"===e.tagName.toLowerCase())}return{restrict:"A",require:"^tabset",link:function(t,n,a){var i=t.$eval(a.tabContentTransclude);i.$transcludeFn(i.$parent,function(t){angular.forEach(t,function(t){e(t)?i.headingElement=t:n.append(t)})})}}}]).directive("tabsetTitles",["$http",function(){return{restrict:"A",require:"^tabset",templateUrl:"template/tabs/tabset-titles.html",replace:!0,link:function(e,t,n,a){e.$eval(n.tabsetTitles)?a.$transcludeFn(a.$scope.$parent,function(e){t.append(e)}):t.remove()}}}]),angular.module("ui.bootstrap.timepicker",[]).constant("timepickerConfig",{hourStep:1,minuteStep:1,showMeridian:!0,meridians:["AM","PM"],readonlyInput:!1,mousewheel:!0}).directive("timepicker",["$parse","$log","timepickerConfig",function(e,t,n){return{restrict:"EA",require:"?^ngModel",replace:!0,scope:{},templateUrl:"template/timepicker/timepicker.html",link:function(a,i,r,o){function l(){var e=parseInt(a.hours,10),t=a.showMeridian?e>0&&13>e:e>=0&&24>e;return t?(a.showMeridian&&(12===e&&(e=0),a.meridian===g[1]&&(e+=12)),e):void 0}function s(){var e=parseInt(a.minutes,10);return e>=0&&60>e?e:void 0}function c(e){return angular.isDefined(e)&&2>(""+e).length?"0"+e:e}function u(e){p(),o.$setViewValue(new Date(m)),d(e)}function p(){o.$setValidity("time",!0),a.invalidHours=!1,a.invalidMinutes=!1}function d(e){var t=m.getHours(),n=m.getMinutes();a.showMeridian&&(t=0===t||12===t?12:t%12),a.hours="h"===e?t:c(t),a.minutes="m"===e?n:c(n),a.meridian=12>m.getHours()?g[0]:g[1]}function f(e){var t=new Date(m.getTime()+6e4*e);m.setHours(t.getHours(),t.getMinutes()),u()}if(o){var m=new Date,g=n.meridians,h=n.hourStep;r.hourStep&&a.$parent.$watch(e(r.hourStep),function(e){h=parseInt(e,10)});var v=n.minuteStep;r.minuteStep&&a.$parent.$watch(e(r.minuteStep),function(e){v=parseInt(e,10)}),a.showMeridian=n.showMeridian,r.showMeridian&&a.$parent.$watch(e(r.showMeridian),function(e){if(a.showMeridian=!!e,o.$error.time){var t=l(),n=s();angular.isDefined(t)&&angular.isDefined(n)&&(m.setHours(t),u())}else d()});var b=i.find("input"),$=b.eq(0),y=b.eq(1),w=angular.isDefined(r.mousewheel)?a.$eval(r.mousewheel):n.mousewheel;if(w){var k=function(e){e.originalEvent&&(e=e.originalEvent);var t=e.wheelDelta?e.wheelDelta:-e.deltaY;return e.detail||t>0};$.bind("mousewheel wheel",function(e){a.$apply(k(e)?a.incrementHours():a.decrementHours()),e.preventDefault()}),y.bind("mousewheel wheel",function(e){a.$apply(k(e)?a.incrementMinutes():a.decrementMinutes()),e.preventDefault()})}if(a.readonlyInput=angular.isDefined(r.readonlyInput)?a.$eval(r.readonlyInput):n.readonlyInput,a.readonlyInput)a.updateHours=angular.noop,a.updateMinutes=angular.noop;else{var D=function(e,t){o.$setViewValue(null),o.$setValidity("time",!1),angular.isDefined(e)&&(a.invalidHours=e),angular.isDefined(t)&&(a.invalidMinutes=t)};a.updateHours=function(){var e=l();angular.isDefined(e)?(m.setHours(e),u("h")):D(!0)},$.bind("blur",function(){!a.validHours&&10>a.hours&&a.$apply(function(){a.hours=c(a.hours)})}),a.updateMinutes=function(){var e=s();angular.isDefined(e)?(m.setMinutes(e),u("m")):D(void 0,!0)},y.bind("blur",function(){!a.invalidMinutes&&10>a.minutes&&a.$apply(function(){a.minutes=c(a.minutes)})})}o.$render=function(){var e=o.$modelValue?new Date(o.$modelValue):null;isNaN(e)?(o.$setValidity("time",!1),t.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.')):(e&&(m=e),p(),d())},a.incrementHours=function(){f(60*h)},a.decrementHours=function(){f(60*-h)},a.incrementMinutes=function(){f(v)},a.decrementMinutes=function(){f(-v)},a.toggleMeridian=function(){f(720*(12>m.getHours()?1:-1))}}}}}]),angular.module("ui.bootstrap.typeahead",["ui.bootstrap.position","ui.bootstrap.bindHtml"]).factory("typeaheadParser",["$parse",function(e){var t=/^\s*(.*?)(?:\s+as\s+(.*?))?\s+for\s+(?:([\$\w][\$\w\d]*))\s+in\s+(.*)$/;return{parse:function(n){var a=n.match(t);if(!a)throw Error("Expected typeahead specification in form of '_modelValue_ (as _label_)? for _item_ in _collection_' but got '"+n+"'.");return{itemName:a[3],source:e(a[4]),viewMapper:e(a[2]||a[1]),modelMapper:e(a[1])}}}}]).directive("typeahead",["$compile","$parse","$q","$timeout","$document","$position","typeaheadParser",function(e,t,n,a,i,r,o){var l=[9,13,27,38,40];return{require:"ngModel",link:function(s,c,u,p){var d=s.$eval(u.typeaheadMinLength)||1,f=s.$eval(u.typeaheadWaitMs)||0,m=s.$eval(u.typeaheadEditable)!==!1,g=t(u.typeaheadLoading).assign||angular.noop,h=t(u.typeaheadOnSelect),v=u.typeaheadInputFormatter?t(u.typeaheadInputFormatter):void 0,b=t(u.ngModel).assign,$=o.parse(u.typeahead),y=angular.element("");y.attr({matches:"matches",active:"activeIdx",select:"select(activeIdx)",query:"query",position:"position"}),angular.isDefined(u.typeaheadTemplateUrl)&&y.attr("template-url",u.typeaheadTemplateUrl);var w=s.$new();s.$on("$destroy",function(){w.$destroy()});var k=function(){w.matches=[],w.activeIdx=-1},D=function(e){var t={$viewValue:e};g(s,!0),n.when($.source(w,t)).then(function(n){if(e===p.$viewValue){if(n.length>0){w.activeIdx=0,w.matches.length=0;for(var a=0;n.length>a;a++)t[$.itemName]=n[a],w.matches.push({label:$.viewMapper(w,t),model:n[a]});w.query=e,w.position=r.position(c),w.position.top=w.position.top+c.prop("offsetHeight")}else k();g(s,!1)}},function(){k(),g(s,!1)})};k(),w.query=void 0;var x;p.$parsers.unshift(function(e){return k(),e&&e.length>=d&&(f>0?(x&&a.cancel(x),x=a(function(){D(e)},f)):D(e)),m?e:(p.$setValidity("editable",!1),void 0)}),p.$formatters.push(function(e){var t,n,a={};return v?(a.$model=e,v(s,a)):(a[$.itemName]=e,t=$.viewMapper(s,a),a[$.itemName]=void 0,n=$.viewMapper(s,a),t!==n?t:e)}),w.select=function(e){var t,n,a={};a[$.itemName]=n=w.matches[e].model,t=$.modelMapper(s,a),b(s,t),p.$setValidity("editable",!0),h(s,{$item:n,$model:t,$label:$.viewMapper(s,a)}),k(),c[0].focus()},c.bind("keydown",function(e){0!==w.matches.length&&-1!==l.indexOf(e.which)&&(e.preventDefault(),40===e.which?(w.activeIdx=(w.activeIdx+1)%w.matches.length,w.$digest()):38===e.which?(w.activeIdx=(w.activeIdx?w.activeIdx:w.matches.length)-1,w.$digest()):13===e.which||9===e.which?w.$apply(function(){w.select(w.activeIdx)}):27===e.which&&(e.stopPropagation(),k(),w.$digest()))});var T=function(e){c[0]!==e.target&&(k(),w.$digest())};i.bind("click",T),s.$on("$destroy",function(){i.unbind("click",T)}),c.after(e(y)(w))}}}]).directive("typeaheadPopup",function(){return{restrict:"E",scope:{matches:"=",query:"=",active:"=",position:"=",select:"&"},replace:!0,templateUrl:"template/typeahead/typeahead-popup.html",link:function(e,t,n){e.templateUrl=n.templateUrl,e.isOpen=function(){return e.matches.length>0},e.isActive=function(t){return e.active==t},e.selectActive=function(t){e.active=t},e.selectMatch=function(t){e.select({activeIdx:t})}}}}).directive("typeaheadMatch",["$http","$templateCache","$compile","$parse",function(e,t,n,a){return{restrict:"E",scope:{index:"=",match:"=",query:"="},link:function(i,r,o){var l=a(o.templateUrl)(i.$parent)||"template/typeahead/typeahead-match.html";e.get(l,{cache:t}).success(function(e){r.replaceWith(n(e.trim())(i))})}}}]).filter("typeaheadHighlight",function(){function e(e){return e.replace(/([.?*+^$[\]\\(){}|-])/g,"\\$1")}return function(t,n){return n?t.replace(RegExp(e(n),"gi"),"$&"):t}}),angular.module("template/accordion/accordion-group.html",[]).run(["$templateCache",function(e){e.put("template/accordion/accordion-group.html",'
      \n \n
      \n
      \n
      ')}]),angular.module("template/accordion/accordion.html",[]).run(["$templateCache",function(e){e.put("template/accordion/accordion.html",'
      ')}]),angular.module("template/alert/alert.html",[]).run(["$templateCache",function(e){e.put("template/alert/alert.html","
      \n \n
      \n
      \n")}]),angular.module("template/carousel/carousel.html",[]).run(["$templateCache",function(e){e.put("template/carousel/carousel.html",'\n')}]),angular.module("template/carousel/slide.html",[]).run(["$templateCache",function(e){e.put("template/carousel/slide.html","
      \n")}]),angular.module("template/datepicker/datepicker.html",[]).run(["$templateCache",function(e){e.put("template/datepicker/datepicker.html",'\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
      #{{label}}
      {{ getWeekNumber(row) }}\n \n
      \n')}]),angular.module("template/datepicker/popup.html",[]).run(["$templateCache",function(e){e.put("template/datepicker/popup.html",'')}]),angular.module("template/modal/backdrop.html",[]).run(["$templateCache",function(e){e.put("template/modal/backdrop.html",'')}]),angular.module("template/modal/window.html",[]).run(["$templateCache",function(e){e.put("template/modal/window.html",'')}]),angular.module("template/pagination/pager.html",[]).run(["$templateCache",function(e){e.put("template/pagination/pager.html",'
      \n \n
      \n')}]),angular.module("template/pagination/pagination.html",[]).run(["$templateCache",function(e){e.put("template/pagination/pagination.html",'\n')}]),angular.module("template/tooltip/tooltip-html-unsafe-popup.html",[]).run(["$templateCache",function(e){e.put("template/tooltip/tooltip-html-unsafe-popup.html",'
      \n
      \n
      \n
      \n')}]),angular.module("template/tooltip/tooltip-popup.html",[]).run(["$templateCache",function(e){e.put("template/tooltip/tooltip-popup.html",'
      \n
      \n
      \n
      \n')}]),angular.module("template/popover/popover.html",[]).run(["$templateCache",function(e){e.put("template/popover/popover.html",'
      \n
      \n\n
      \n

      \n
      \n
      \n
      \n')}]),angular.module("template/progressbar/bar.html",[]).run(["$templateCache",function(e){e.put("template/progressbar/bar.html",'
      ')}]),angular.module("template/progressbar/progress.html",[]).run(["$templateCache",function(e){e.put("template/progressbar/progress.html",'
      ')}]),angular.module("template/rating/rating.html",[]).run(["$templateCache",function(e){e.put("template/rating/rating.html",'\n \n')}]),angular.module("template/tabs/pane.html",[]).run(["$templateCache",function(e){e.put("template/tabs/pane.html",'
      \n')}]),angular.module("template/tabs/tab.html",[]).run(["$templateCache",function(e){e.put("template/tabs/tab.html",'
    • \n {{heading}}\n
    • \n')}]),angular.module("template/tabs/tabs.html",[]).run(["$templateCache",function(e){e.put("template/tabs/tabs.html",'
      \n \n
      \n
      \n')}]),angular.module("template/tabs/tabset-titles.html",[]).run(["$templateCache",function(e){e.put("template/tabs/tabset-titles.html","
        \n
      \n")}]),angular.module("template/tabs/tabset.html",[]).run(["$templateCache",function(e){e.put("template/tabs/tabset.html",'\n
      \n
      \n
      \n
      \n
      \n
      \n
      \n
      \n')}]),angular.module("template/timepicker/timepicker.html",[]).run(["$templateCache",function(e){e.put("template/timepicker/timepicker.html",'\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
       
      :
       
      ')}]),angular.module("template/typeahead/typeahead-match.html",[]).run(["$templateCache",function(e){e.put("template/typeahead/typeahead-match.html",'')}]),angular.module("template/typeahead/typeahead-popup.html",[]).run(["$templateCache",function(e){e.put("template/typeahead/typeahead-popup.html",'')}]),angular.module("template/typeahead/typeahead.html",[]).run(["$templateCache",function(e){e.put("template/typeahead/typeahead.html",'')}]); \ No newline at end of file