angular-ui-bootstrap-rails 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Angular-UI-Bootstrap-Rails RubyGem Copyright (c) 2013 Chris Constantin
2
+
3
+ Angular.JS and related components Copyright (c) 2010-2013 Google Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,19 @@
1
+ # angular-ui-bootstrap-rails
2
+
3
+ angular-ui-bootstrap-rails wraps the [Angular.js UI Bootstrap](http://angular-ui.github.com/bootstrap) library for use in Rails 3.1 and above. Assets will minify automatically during production.
4
+
5
+ ## Usage
6
+
7
+ Add the following to your gemfile:
8
+
9
+ gem 'angular-ui-bootstrap-rails'
10
+
11
+ Add the following directive to your Javascript manifest file (application.js):
12
+
13
+ //= require angular-ui-bootstrap
14
+
15
+ If you would like to use the default bootstrap templates, use the following directive instead
16
+
17
+ //= require angular-ui-bootstrap-tpls
18
+
19
+ Gem based on Angularjs-rails(https://github.com/confuseddesi/angularjs-rails) by Hirav Gandhi
@@ -0,0 +1,10 @@
1
+ require "angular-ui-bootstrap-rails/version"
2
+
3
+ module AngularUI
4
+ module Bootstrap
5
+ module Rails
6
+ class Engine < ::Rails::Engine
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ module AngularUI
2
+ module Bootstrap
3
+ module Rails
4
+ VERSION = "0.1.1"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,1430 @@
1
+ angular.module("ui.bootstrap", ["ui.bootstrap.tpls", "ui.bootstrap.accordion","ui.bootstrap.alert","ui.bootstrap.carousel","ui.bootstrap.collapse","ui.bootstrap.dialog","ui.bootstrap.dropdownToggle","ui.bootstrap.modal","ui.bootstrap.pagination","ui.bootstrap.popover","ui.bootstrap.tabs","ui.bootstrap.tooltip","ui.bootstrap.transition"]);
2
+
3
+ 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/dialog/message.html","template/pagination/pagination.html","template/popover/popover.html","template/tabs/pane.html","template/tabs/tabs.html","template/tooltip/tooltip-popup.html"]);
4
+
5
+ angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
6
+
7
+ .constant('accordionConfig', {
8
+ closeOthers: true
9
+ })
10
+
11
+ .controller('AccordionController', ['$scope', '$attrs', 'accordionConfig', function ($scope, $attrs, accordionConfig) {
12
+
13
+ // This array keeps track of the accordion groups
14
+ this.groups = [];
15
+
16
+ // Ensure that all the groups in this accordion are closed, unless close-others explicitly says not to
17
+ this.closeOthers = function(openGroup) {
18
+ var closeOthers = angular.isDefined($attrs.closeOthers) ? $scope.$eval($attrs.closeOthers) : accordionConfig.closeOthers;
19
+ if ( closeOthers ) {
20
+ angular.forEach(this.groups, function (group) {
21
+ if ( group !== openGroup ) {
22
+ group.isOpen = false;
23
+ }
24
+ });
25
+ }
26
+ };
27
+
28
+ // This is called from the accordion-group directive to add itself to the accordion
29
+ this.addGroup = function(groupScope) {
30
+ var that = this;
31
+ this.groups.push(groupScope);
32
+
33
+ groupScope.$on('$destroy', function (event) {
34
+ that.removeGroup(groupScope);
35
+ });
36
+ };
37
+
38
+ // This is called from the accordion-group directive when to remove itself
39
+ this.removeGroup = function(group) {
40
+ var index = this.groups.indexOf(group);
41
+ if ( index !== -1 ) {
42
+ this.groups.splice(this.groups.indexOf(group), 1);
43
+ }
44
+ };
45
+
46
+ }]);
47
+
48
+ // The accordion directive simply sets up the directive controller
49
+ // and adds an accordion CSS class to itself element.
50
+ angular.module('ui.bootstrap.accordion').directive('accordion', function () {
51
+ return {
52
+ restrict:'EA',
53
+ controller:'AccordionController',
54
+ transclude: true,
55
+ replace: false,
56
+ templateUrl: 'template/accordion/accordion.html'
57
+ };
58
+ });
59
+
60
+ // The accordion-group directive indicates a block of html that will expand and collapse in an accordion
61
+ angular.module('ui.bootstrap.accordion').directive('accordionGroup', ['$parse', '$transition', '$timeout', function($parse, $transition, $timeout) {
62
+ return {
63
+ require:'^accordion', // We need this directive to be inside an accordion
64
+ restrict:'EA',
65
+ transclude:true, // It transcludes the contents of the directive into the template
66
+ replace: true, // The element containing the directive will be replaced with the template
67
+ templateUrl:'template/accordion/accordion-group.html',
68
+ scope:{ heading:'@' }, // Create an isolated scope and interpolate the heading attribute onto this scope
69
+ link: function(scope, element, attrs, accordionCtrl) {
70
+ var getIsOpen, setIsOpen;
71
+
72
+ accordionCtrl.addGroup(scope);
73
+
74
+ scope.isOpen = false;
75
+
76
+ if ( attrs.isOpen ) {
77
+ getIsOpen = $parse(attrs.isOpen);
78
+ setIsOpen = getIsOpen.assign;
79
+
80
+ scope.$watch(
81
+ function watchIsOpen() { return getIsOpen(scope.$parent); },
82
+ function updateOpen(value) { scope.isOpen = value; }
83
+ );
84
+
85
+ scope.isOpen = getIsOpen ? getIsOpen(scope.$parent) : false;
86
+ }
87
+
88
+ scope.$watch('isOpen', function(value) {
89
+ if ( value ) {
90
+ accordionCtrl.closeOthers(scope);
91
+ }
92
+ if ( setIsOpen ) {
93
+ setIsOpen(scope.$parent, value);
94
+ }
95
+ });
96
+
97
+ }
98
+ };
99
+ }]);
100
+
101
+ angular.module("ui.bootstrap.alert", []).directive('alert', function () {
102
+ return {
103
+ restrict:'EA',
104
+ templateUrl:'template/alert/alert.html',
105
+ transclude:true,
106
+ replace:true,
107
+ scope:{
108
+ type:'=',
109
+ close:'&'
110
+ }
111
+ };
112
+ });
113
+ /*
114
+ *
115
+ * Angular Bootstrap Carousel
116
+ *
117
+ * The carousel has all of the function that the original Bootstrap carousel has, except for animations.
118
+ *
119
+ * For no interval set the interval to non-number, or milliseconds of desired interval
120
+ * Template: <carousel interval="none"><slide>{{anything}}</slide></carousel>
121
+ * To change the carousel's active slide set the active attribute to true
122
+ * Template: <carousel interval="none"><slide active="someModel">{{anything}}</slide></carousel>
123
+ */
124
+ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition'])
125
+ .controller('CarouselController', ['$scope', '$timeout', '$transition', '$q', function ($scope, $timeout, $transition, $q) {
126
+ var self = this,
127
+ slides = self.slides = [],
128
+ currentIndex = -1,
129
+ currentTimeout, isPlaying;
130
+ self.currentSlide = null;
131
+
132
+ /* direction: "prev" or "next" */
133
+ self.select = function(nextSlide, direction) {
134
+ var nextIndex = slides.indexOf(nextSlide);
135
+ //Decide direction if it's not given
136
+ if (direction === undefined) {
137
+ direction = nextIndex > currentIndex ? "next" : "prev";
138
+ }
139
+ if (nextSlide && nextSlide !== self.currentSlide) {
140
+ if ($scope.$currentTransition) {
141
+ $scope.$currentTransition.cancel();
142
+ //Timeout so ng-class in template has time to fix classes for finished slide
143
+ $timeout(goNext);
144
+ } else {
145
+ goNext();
146
+ }
147
+ }
148
+ function goNext() {
149
+ //If we have a slide to transition from and we have a transition type and we're allowed, go
150
+ if (self.currentSlide && angular.isString(direction) && !$scope.noTransition && nextSlide.$element) {
151
+ //We shouldn't do class manip in here, but it's the same weird thing bootstrap does. need to fix sometime
152
+ nextSlide.$element.addClass(direction);
153
+ nextSlide.$element[0].offsetWidth = nextSlide.$element[0].offsetWidth; //force reflow
154
+
155
+ //Set all other slides to stop doing their stuff for the new transition
156
+ angular.forEach(slides, function(slide) {
157
+ angular.extend(slide, {direction: '', entering: false, leaving: false, active: false});
158
+ });
159
+ angular.extend(nextSlide, {direction: direction, active: true, entering: true});
160
+ angular.extend(self.currentSlide||{}, {direction: direction, leaving: true});
161
+
162
+ $scope.$currentTransition = $transition(nextSlide.$element, {});
163
+ //We have to create new pointers inside a closure since next & current will change
164
+ (function(next,current) {
165
+ $scope.$currentTransition.then(
166
+ function(){ transitionDone(next, current); },
167
+ function(){ transitionDone(next, current); }
168
+ );
169
+ }(nextSlide, self.currentSlide));
170
+ } else {
171
+ transitionDone(nextSlide, self.currentSlide);
172
+ }
173
+ self.currentSlide = nextSlide;
174
+ currentIndex = nextIndex;
175
+ //every time you change slides, reset the timer
176
+ restartTimer();
177
+ }
178
+ function transitionDone(next, current) {
179
+ angular.extend(next, {direction: '', active: true, leaving: false, entering: false});
180
+ angular.extend(current||{}, {direction: '', active: false, leaving: false, entering: false});
181
+ $scope.$currentTransition = null;
182
+ }
183
+ };
184
+
185
+ /* Allow outside people to call indexOf on slides array */
186
+ self.indexOfSlide = function(slide) {
187
+ return slides.indexOf(slide);
188
+ };
189
+
190
+ $scope.next = function() {
191
+ var newIndex = (currentIndex + 1) % slides.length;
192
+ return self.select(slides[newIndex], 'next');
193
+ };
194
+
195
+ $scope.prev = function() {
196
+ var newIndex = currentIndex - 1 < 0 ? slides.length - 1 : currentIndex - 1;
197
+ return self.select(slides[newIndex], 'prev');
198
+ };
199
+
200
+ $scope.$watch('interval', restartTimer);
201
+ function restartTimer() {
202
+ if (currentTimeout) {
203
+ $timeout.cancel(currentTimeout);
204
+ }
205
+ function go() {
206
+ if (isPlaying) {
207
+ $scope.next();
208
+ restartTimer();
209
+ } else {
210
+ $scope.pause();
211
+ }
212
+ }
213
+ var interval = +$scope.interval;
214
+ if (!isNaN(interval) && interval>=0) {
215
+ currentTimeout = $timeout(go, interval);
216
+ }
217
+ }
218
+ $scope.play = function() {
219
+ if (!isPlaying) {
220
+ isPlaying = true;
221
+ restartTimer();
222
+ }
223
+ };
224
+ $scope.pause = function() {
225
+ isPlaying = false;
226
+ if (currentTimeout) {
227
+ $timeout.cancel(currentTimeout);
228
+ }
229
+ };
230
+
231
+ self.addSlide = function(slide, element) {
232
+ slide.$element = element;
233
+ slides.push(slide);
234
+ //if this is the first slide or the slide is set to active, select it
235
+ if(slides.length === 1 || slide.active) {
236
+ self.select(slides[slides.length-1]);
237
+ if (slides.length == 1) {
238
+ $scope.play();
239
+ }
240
+ } else {
241
+ slide.active = false;
242
+ }
243
+ };
244
+
245
+ self.removeSlide = function(slide) {
246
+ //get the index of the slide inside the carousel
247
+ var index = slides.indexOf(slide);
248
+ slides.splice(index, 1);
249
+ if (slides.length > 0 && slide.active) {
250
+ if (index >= slides.length) {
251
+ self.select(slides[index-1]);
252
+ } else {
253
+ self.select(slides[index]);
254
+ }
255
+ }
256
+ };
257
+ }])
258
+ .directive('carousel', [function() {
259
+ return {
260
+ restrict: 'EA',
261
+ transclude: true,
262
+ replace: true,
263
+ controller: 'CarouselController',
264
+ require: 'carousel',
265
+ templateUrl: 'template/carousel/carousel.html',
266
+ scope: {
267
+ interval: '=',
268
+ noTransition: '='
269
+ }
270
+ };
271
+ }])
272
+ .directive('slide', [function() {
273
+ return {
274
+ require: '^carousel',
275
+ restrict: 'EA',
276
+ transclude: true,
277
+ replace: true,
278
+ templateUrl: 'template/carousel/slide.html',
279
+ scope: {
280
+ active: '='
281
+ },
282
+ link: function (scope, element, attrs, carouselCtrl) {
283
+ carouselCtrl.addSlide(scope, element);
284
+ //when the scope is destroyed then remove the slide from the current slides array
285
+ scope.$on('$destroy', function() {
286
+ carouselCtrl.removeSlide(scope);
287
+ });
288
+
289
+ scope.$watch('active', function(active) {
290
+ if (active) {
291
+ carouselCtrl.select(scope);
292
+ }
293
+ });
294
+ }
295
+ };
296
+ }]);
297
+
298
+ angular.module('ui.bootstrap.collapse',['ui.bootstrap.transition'])
299
+
300
+ // The collapsible directive indicates a block of html that will expand and collapse
301
+ .directive('collapse', ['$transition', function($transition) {
302
+ // CSS transitions don't work with height: auto, so we have to manually change the height to a
303
+ // specific value and then once the animation completes, we can reset the height to auto.
304
+ // Unfortunately if you do this while the CSS transitions are specified (i.e. in the CSS class
305
+ // "collapse") then you trigger a change to height 0 in between.
306
+ // The fix is to remove the "collapse" CSS class while changing the height back to auto - phew!
307
+ var fixUpHeight = function(scope, element, height) {
308
+ // We remove the collapse CSS class to prevent a transition when we change to height: auto
309
+ element.removeClass('collapse');
310
+ element.css({ height: height });
311
+ // It appears that reading offsetWidth makes the browser realise that we have changed the
312
+ // height already :-/
313
+ var x = element[0].offsetWidth;
314
+ element.addClass('collapse');
315
+ };
316
+
317
+ return {
318
+ link: function(scope, element, attrs) {
319
+
320
+ var isCollapsed;
321
+ var initialAnimSkip = true;
322
+ scope.$watch(function (){ return element[0].scrollHeight; }, function (value) {
323
+ //The listener is called when scollHeight changes
324
+ //It actually does on 2 scenarios:
325
+ // 1. Parent is set to display none
326
+ // 2. angular bindings inside are resolved
327
+ //When we have a change of scrollHeight we are setting again the correct height if the group is opened
328
+ if (element[0].scrollHeight !== 0) {
329
+ if (!isCollapsed) {
330
+ fixUpHeight(scope, element, element[0].scrollHeight + 'px');
331
+ }
332
+ }
333
+ });
334
+
335
+ scope.$watch(attrs.collapse, function(value) {
336
+ if (value) {
337
+ collapse();
338
+ } else {
339
+ expand();
340
+ }
341
+ });
342
+
343
+
344
+ var currentTransition;
345
+ var doTransition = function(change) {
346
+ if ( currentTransition ) {
347
+ currentTransition.cancel();
348
+ }
349
+ currentTransition = $transition(element,change);
350
+ currentTransition.then(
351
+ function() { currentTransition = undefined; },
352
+ function() { currentTransition = undefined; }
353
+ );
354
+ return currentTransition;
355
+ };
356
+
357
+ var expand = function() {
358
+ if (initialAnimSkip) {
359
+ initialAnimSkip = false;
360
+ if ( !isCollapsed ) {
361
+ fixUpHeight(scope, element, 'auto');
362
+ }
363
+ } else {
364
+ doTransition({ height : element[0].scrollHeight + 'px' })
365
+ .then(function() {
366
+ // This check ensures that we don't accidentally update the height if the user has closed
367
+ // the group while the animation was still running
368
+ if ( !isCollapsed ) {
369
+ fixUpHeight(scope, element, 'auto');
370
+ }
371
+ });
372
+ }
373
+ isCollapsed = false;
374
+ };
375
+
376
+ var collapse = function() {
377
+ isCollapsed = true;
378
+ if (initialAnimSkip) {
379
+ initialAnimSkip = false;
380
+ fixUpHeight(scope, element, 0);
381
+ } else {
382
+ fixUpHeight(scope, element, element[0].scrollHeight + 'px');
383
+ doTransition({'height':'0'});
384
+ }
385
+ };
386
+ }
387
+ };
388
+ }]);
389
+
390
+ // The `$dialogProvider` can be used to configure global defaults for your
391
+ // `$dialog` service.
392
+ var dialogModule = angular.module('ui.bootstrap.dialog', ['ui.bootstrap.transition']);
393
+
394
+ dialogModule.controller('MessageBoxController', ['$scope', 'dialog', 'model', function($scope, dialog, model){
395
+ $scope.title = model.title;
396
+ $scope.message = model.message;
397
+ $scope.buttons = model.buttons;
398
+ $scope.close = function(res){
399
+ dialog.close(res);
400
+ };
401
+ }]);
402
+
403
+ dialogModule.provider("$dialog", function(){
404
+
405
+ // The default options for all dialogs.
406
+ var defaults = {
407
+ backdrop: true,
408
+ modalClass: 'modal',
409
+ backdropClass: 'modal-backdrop',
410
+ transitionClass: 'fade',
411
+ triggerClass: 'in',
412
+ resolve:{},
413
+ backdropFade: false,
414
+ modalFade:false,
415
+ keyboard: true, // close with esc key
416
+ backdropClick: true // only in conjunction with backdrop=true
417
+ /* other options: template, templateUrl, controller */
418
+ };
419
+
420
+ var globalOptions = {};
421
+
422
+ // The `options({})` allows global configuration of all dialogs in the application.
423
+ //
424
+ // var app = angular.module('App', ['ui.bootstrap.dialog'], function($dialogProvider){
425
+ // // don't close dialog when backdrop is clicked by default
426
+ // $dialogProvider.options({backdropClick: false});
427
+ // });
428
+ this.options = function(value){
429
+ globalOptions = value;
430
+ };
431
+
432
+ // Returns the actual `$dialog` service that is injected in controllers
433
+ this.$get = ["$http", "$document", "$compile", "$rootScope", "$controller", "$templateCache", "$q", "$transition",
434
+ function ($http, $document, $compile, $rootScope, $controller, $templateCache, $q, $transition) {
435
+
436
+ var body = $document.find('body');
437
+
438
+ function createElement(clazz) {
439
+ var el = angular.element("<div>");
440
+ el.addClass(clazz);
441
+ return el;
442
+ }
443
+
444
+ // The `Dialog` class represents a modal dialog. The dialog class can be invoked by providing an options object
445
+ // containing at lest template or templateUrl and controller:
446
+ //
447
+ // var d = new Dialog({templateUrl: 'foo.html', controller: 'BarController'});
448
+ //
449
+ // Dialogs can also be created using templateUrl and controller as distinct arguments:
450
+ //
451
+ // var d = new Dialog('path/to/dialog.html', MyDialogController);
452
+ function Dialog(opts) {
453
+
454
+ var self = this, options = this.options = angular.extend({}, defaults, globalOptions, opts);
455
+
456
+ this.backdropEl = createElement(options.backdropClass);
457
+ if(options.backdropFade){
458
+ this.backdropEl.addClass(options.transitionClass);
459
+ this.backdropEl.removeClass(options.triggerClass);
460
+ }
461
+
462
+ this.modalEl = createElement(options.modalClass);
463
+ if(options.modalFade){
464
+ this.modalEl.addClass(options.transitionClass);
465
+ this.modalEl.removeClass(options.triggerClass);
466
+ }
467
+
468
+ this.handledEscapeKey = function(e) {
469
+ if (e.which === 27) {
470
+ self.close();
471
+ e.preventDefault();
472
+ self.$scope.$apply();
473
+ }
474
+ };
475
+
476
+ this.handleBackDropClick = function(e) {
477
+ self.close();
478
+ e.preventDefault();
479
+ self.$scope.$apply();
480
+ };
481
+ }
482
+
483
+ // The `isOpen()` method returns wether the dialog is currently visible.
484
+ Dialog.prototype.isOpen = function(){
485
+ return this._open;
486
+ };
487
+
488
+ // The `open(templateUrl, controller)` method opens the dialog.
489
+ // Use the `templateUrl` and `controller` arguments if specifying them at dialog creation time is not desired.
490
+ Dialog.prototype.open = function(templateUrl, controller){
491
+ var self = this, options = this.options;
492
+
493
+ if(templateUrl){
494
+ options.templateUrl = templateUrl;
495
+ }
496
+ if(controller){
497
+ options.controller = controller;
498
+ }
499
+
500
+ if(!(options.template || options.templateUrl)) {
501
+ throw new Error('Dialog.open expected template or templateUrl, neither found. Use options or open method to specify them.');
502
+ }
503
+
504
+ this._loadResolves().then(function(locals) {
505
+ var $scope = locals.$scope = self.$scope = $rootScope.$new();
506
+
507
+ self.modalEl.html(locals.$template);
508
+
509
+ if (self.options.controller) {
510
+ var ctrl = $controller(self.options.controller, locals);
511
+ self.modalEl.contents().data('ngControllerController', ctrl);
512
+ }
513
+
514
+ $compile(self.modalEl.contents())($scope);
515
+ self._addElementsToDom();
516
+
517
+ // trigger tranisitions
518
+ setTimeout(function(){
519
+ if(self.options.modalFade){ self.modalEl.addClass(self.options.triggerClass); }
520
+ if(self.options.backdropFade){ self.backdropEl.addClass(self.options.triggerClass); }
521
+ });
522
+
523
+ self._bindEvents();
524
+ });
525
+
526
+ this.deferred = $q.defer();
527
+ return this.deferred.promise;
528
+ };
529
+
530
+ // closes the dialog and resolves the promise returned by the `open` method with the specified result.
531
+ Dialog.prototype.close = function(result){
532
+ var self = this;
533
+ var fadingElements = this._getFadingElements();
534
+
535
+ if(fadingElements.length > 0){
536
+ for (var i = fadingElements.length - 1; i >= 0; i--) {
537
+ $transition(fadingElements[i], removeTriggerClass).then(onCloseComplete);
538
+ }
539
+ return;
540
+ }
541
+
542
+ this._onCloseComplete(result);
543
+
544
+ function removeTriggerClass(el){
545
+ el.removeClass(self.options.triggerClass);
546
+ }
547
+
548
+ function onCloseComplete(){
549
+ if(self._open){
550
+ self._onCloseComplete(result);
551
+ }
552
+ }
553
+ };
554
+
555
+ Dialog.prototype._getFadingElements = function(){
556
+ var elements = [];
557
+ if(this.options.modalFade){
558
+ elements.push(this.modalEl);
559
+ }
560
+ if(this.options.backdropFade){
561
+ elements.push(this.backdropEl);
562
+ }
563
+
564
+ return elements;
565
+ };
566
+
567
+ Dialog.prototype._bindEvents = function() {
568
+ if(this.options.keyboard){ body.bind('keydown', this.handledEscapeKey); }
569
+ if(this.options.backdrop && this.options.backdropClick){ this.backdropEl.bind('click', this.handleBackDropClick); }
570
+ };
571
+
572
+ Dialog.prototype._unbindEvents = function() {
573
+ if(this.options.keyboard){ body.unbind('keydown', this.handledEscapeKey); }
574
+ if(this.options.backdrop && this.options.backdropClick){ this.backdropEl.unbind('click', this.handleBackDropClick); }
575
+ };
576
+
577
+ Dialog.prototype._onCloseComplete = function(result) {
578
+ this._removeElementsFromDom();
579
+ this._unbindEvents();
580
+
581
+ this.deferred.resolve(result);
582
+ };
583
+
584
+ Dialog.prototype._addElementsToDom = function(){
585
+ body.append(this.modalEl);
586
+ if(this.options.backdrop) { body.append(this.backdropEl); }
587
+ this._open = true;
588
+ };
589
+
590
+ Dialog.prototype._removeElementsFromDom = function(){
591
+ this.modalEl.remove();
592
+ if(this.options.backdrop) { this.backdropEl.remove(); }
593
+ this._open = false;
594
+ };
595
+
596
+ // Loads all `options.resolve` members to be used as locals for the controller associated with the dialog.
597
+ Dialog.prototype._loadResolves = function(){
598
+ var values = [], keys = [], templatePromise, self = this;
599
+
600
+ if (this.options.template) {
601
+ templatePromise = $q.when(this.options.template);
602
+ } else if (this.options.templateUrl) {
603
+ templatePromise = $http.get(this.options.templateUrl, {cache:$templateCache})
604
+ .then(function(response) { return response.data; });
605
+ }
606
+
607
+ angular.forEach(this.options.resolve || [], function(value, key) {
608
+ keys.push(key);
609
+ values.push(value);
610
+ });
611
+
612
+ keys.push('$template');
613
+ values.push(templatePromise);
614
+
615
+ return $q.all(values).then(function(values) {
616
+ var locals = {};
617
+ angular.forEach(values, function(value, index) {
618
+ locals[keys[index]] = value;
619
+ });
620
+ locals.dialog = self;
621
+ return locals;
622
+ });
623
+ };
624
+
625
+ // The actual `$dialog` service that is injected in controllers.
626
+ return {
627
+ // Creates a new `Dialog` with the specified options.
628
+ dialog: function(opts){
629
+ return new Dialog(opts);
630
+ },
631
+ // creates a new `Dialog` tied to the default message box template and controller.
632
+ //
633
+ // Arguments `title` and `message` are rendered in the modal header and body sections respectively.
634
+ // The `buttons` array holds an object with the following members for each button to include in the
635
+ // modal footer section:
636
+ //
637
+ // * `result`: the result to pass to the `close` method of the dialog when the button is clicked
638
+ // * `label`: the label of the button
639
+ // * `cssClass`: additional css class(es) to apply to the button for styling
640
+ messageBox: function(title, message, buttons){
641
+ return new Dialog({templateUrl: 'template/dialog/message.html', controller: 'MessageBoxController', resolve: {model: {
642
+ title: title,
643
+ message: message,
644
+ buttons: buttons
645
+ }}});
646
+ }
647
+ };
648
+ }];
649
+ });
650
+
651
+ /*
652
+ * dropdownToggle - Provides dropdown menu functionality in place of bootstrap js
653
+ * @restrict class or attribute
654
+ * @example:
655
+ <li class="dropdown">
656
+ <a class="dropdown-toggle">My Dropdown Menu</a>
657
+ <ul class="dropdown-menu">
658
+ <li ng-repeat="choice in dropChoices">
659
+ <a ng-href="{{choice.href}}">{{choice.text}}</a>
660
+ </li>
661
+ </ul>
662
+ </li>
663
+ */
664
+
665
+ angular.module('ui.bootstrap.dropdownToggle', []).directive('dropdownToggle',
666
+ ['$document', '$location', '$window', function ($document, $location, $window) {
667
+ var openElement = null, close;
668
+ return {
669
+ restrict: 'CA',
670
+ link: function(scope, element, attrs) {
671
+ scope.$watch(function dropdownTogglePathWatch(){return $location.path();}, function dropdownTogglePathWatchAction() {
672
+ if (close) { close(); }
673
+ });
674
+
675
+ element.parent().bind('click', function(event) {
676
+ if (close) { close(); }
677
+ });
678
+
679
+ element.bind('click', function(event) {
680
+ event.preventDefault();
681
+ event.stopPropagation();
682
+
683
+ var iWasOpen = false;
684
+
685
+ if (openElement) {
686
+ iWasOpen = openElement === element;
687
+ close();
688
+ }
689
+
690
+ if (!iWasOpen){
691
+ element.parent().addClass('open');
692
+ openElement = element;
693
+
694
+ close = function (event) {
695
+ if (event) {
696
+ event.preventDefault();
697
+ event.stopPropagation();
698
+ }
699
+ $document.unbind('click', close);
700
+ element.parent().removeClass('open');
701
+ close = null;
702
+ openElement = null;
703
+ };
704
+
705
+ $document.bind('click', close);
706
+ }
707
+ });
708
+ }
709
+ };
710
+ }]);
711
+
712
+ angular.module('ui.bootstrap.modal', []).directive('modal', ['$parse',function($parse) {
713
+ var backdropEl;
714
+ var body = angular.element(document.getElementsByTagName('body')[0]);
715
+ var defaultOpts = {
716
+ backdrop: true,
717
+ escape: true
718
+ };
719
+ return {
720
+ restrict: 'EA',
721
+ link: function(scope, elm, attrs) {
722
+ var opts = angular.extend(defaultOpts, scope.$eval(attrs.uiOptions || attrs.bsOptions || attrs.options));
723
+ var shownExpr = attrs.modal || attrs.show;
724
+ var setClosed;
725
+
726
+ if (attrs.close) {
727
+ setClosed = function() {
728
+ scope.$apply(attrs.close);
729
+ };
730
+ } else {
731
+ setClosed = function() {
732
+ scope.$apply(function() {
733
+ $parse(shownExpr).assign(scope, false);
734
+ });
735
+ };
736
+ }
737
+ elm.addClass('modal');
738
+
739
+ if (opts.backdrop && !backdropEl) {
740
+ backdropEl = angular.element('<div class="modal-backdrop"></div>');
741
+ backdropEl.css('display','none');
742
+ body.append(backdropEl);
743
+ }
744
+
745
+ function setShown(shown) {
746
+ scope.$apply(function() {
747
+ model.assign(scope, shown);
748
+ });
749
+ }
750
+
751
+ function escapeClose(evt) {
752
+ if (evt.which === 27) { setClosed(); }
753
+ }
754
+ function clickClose() {
755
+ setClosed();
756
+ }
757
+
758
+ function close() {
759
+ if (opts.escape) { body.unbind('keyup', escapeClose); }
760
+ if (opts.backdrop) {
761
+ backdropEl.css('display', 'none').removeClass('in');
762
+ backdropEl.unbind('click', clickClose);
763
+ }
764
+ elm.css('display', 'none').removeClass('in');
765
+ body.removeClass('modal-open');
766
+ }
767
+ function open() {
768
+ if (opts.escape) { body.bind('keyup', escapeClose); }
769
+ if (opts.backdrop) {
770
+ backdropEl.css('display', 'block').addClass('in');
771
+ if(opts.backdrop != "static") {
772
+ backdropEl.bind('click', clickClose);
773
+ }
774
+ }
775
+ elm.css('display', 'block').addClass('in');
776
+ body.addClass('modal-open');
777
+ }
778
+
779
+ scope.$watch(shownExpr, function(isShown, oldShown) {
780
+ if (isShown) {
781
+ open();
782
+ } else {
783
+ close();
784
+ }
785
+ });
786
+ }
787
+ };
788
+ }]);
789
+
790
+ angular.module('ui.bootstrap.pagination', [])
791
+
792
+ .directive('pagination', function() {
793
+ return {
794
+ restrict: 'EA',
795
+ scope: {
796
+ numPages: '=',
797
+ currentPage: '=',
798
+ maxSize: '=',
799
+ onSelectPage: '&',
800
+ nextText: '@',
801
+ previousText: '@'
802
+ },
803
+ templateUrl: 'template/pagination/pagination.html',
804
+ replace: true,
805
+ link: function(scope) {
806
+ scope.$watch('numPages + currentPage + maxSize', function() {
807
+ scope.pages = [];
808
+
809
+ //set the default maxSize to numPages
810
+ var maxSize = ( scope.maxSize && scope.maxSize < scope.numPages ) ? scope.maxSize : scope.numPages;
811
+ var startPage = scope.currentPage - Math.floor(maxSize/2);
812
+
813
+ //adjust the startPage within boundary
814
+ if(startPage < 1) {
815
+ startPage = 1;
816
+ }
817
+ if ((startPage + maxSize - 1) > scope.numPages) {
818
+ startPage = startPage - ((startPage + maxSize - 1) - scope.numPages );
819
+ }
820
+
821
+ for(var i=0; i < maxSize && i < scope.numPages ;i++) {
822
+ scope.pages.push(startPage + i);
823
+ }
824
+ if ( scope.currentPage > scope.numPages ) {
825
+ scope.selectPage(scope.numPages);
826
+ }
827
+ });
828
+ scope.noPrevious = function() {
829
+ return scope.currentPage === 1;
830
+ };
831
+ scope.noNext = function() {
832
+ return scope.currentPage === scope.numPages;
833
+ };
834
+ scope.isActive = function(page) {
835
+ return scope.currentPage === page;
836
+ };
837
+
838
+ scope.selectPage = function(page) {
839
+ if ( ! scope.isActive(page) ) {
840
+ scope.currentPage = page;
841
+ scope.onSelectPage({ page: page });
842
+ }
843
+ };
844
+
845
+ scope.selectPrevious = function() {
846
+ if ( !scope.noPrevious() ) {
847
+ scope.selectPage(scope.currentPage-1);
848
+ }
849
+ };
850
+ scope.selectNext = function() {
851
+ if ( !scope.noNext() ) {
852
+ scope.selectPage(scope.currentPage+1);
853
+ }
854
+ };
855
+ }
856
+ };
857
+ });
858
+ /**
859
+ * The following features are still outstanding: popup delay, animation as a
860
+ * function, placement as a function, inside, support for more triggers than
861
+ * just mouse enter/leave, html popovers, and selector delegatation.
862
+ */
863
+ angular.module( 'ui.bootstrap.popover', [] )
864
+ .directive( 'popoverPopup', function () {
865
+ return {
866
+ restrict: 'EA',
867
+ replace: true,
868
+ scope: { popoverTitle: '@', popoverContent: '@', placement: '@', animation: '&', isOpen: '&' },
869
+ templateUrl: 'template/popover/popover.html'
870
+ };
871
+ })
872
+ .directive( 'popover', [ '$compile', '$timeout', '$parse', function ( $compile, $timeout, $parse ) {
873
+
874
+ var template =
875
+ '<popover-popup '+
876
+ 'popover-title="{{tt_title}}" '+
877
+ 'popover-content="{{tt_popover}}" '+
878
+ 'placement="{{tt_placement}}" '+
879
+ 'animation="tt_animation()" '+
880
+ 'is-open="tt_isOpen"'+
881
+ '>'+
882
+ '</popover-popup>';
883
+
884
+ return {
885
+ scope: true,
886
+ link: function ( scope, element, attr ) {
887
+ var popover = $compile( template )( scope ),
888
+ transitionTimeout;
889
+
890
+ attr.$observe( 'popover', function ( val ) {
891
+ scope.tt_popover = val;
892
+ });
893
+
894
+ attr.$observe( 'popoverTitle', function ( val ) {
895
+ scope.tt_title = val;
896
+ });
897
+
898
+ attr.$observe( 'popoverPlacement', function ( val ) {
899
+ // If no placement was provided, default to 'top'.
900
+ scope.tt_placement = val || 'top';
901
+ });
902
+
903
+ attr.$observe( 'popoverAnimation', function ( val ) {
904
+ scope.tt_animation = $parse( val );
905
+ });
906
+
907
+ // By default, the popover is not open.
908
+ scope.tt_isOpen = false;
909
+
910
+ // Calculate the current position and size of the directive element.
911
+ function getPosition() {
912
+ return {
913
+ width: element.prop( 'offsetWidth' ),
914
+ height: element.prop( 'offsetHeight' ),
915
+ top: element.prop( 'offsetTop' ),
916
+ left: element.prop( 'offsetLeft' )
917
+ };
918
+ }
919
+
920
+ // Show the popover popup element.
921
+ function show() {
922
+ var position,
923
+ ttWidth,
924
+ ttHeight,
925
+ ttPosition;
926
+
927
+ // If there is a pending remove transition, we must cancel it, lest the
928
+ // toolip be mysteriously removed.
929
+ if ( transitionTimeout ) {
930
+ $timeout.cancel( transitionTimeout );
931
+ }
932
+
933
+ // Set the initial positioning.
934
+ popover.css({ top: 0, left: 0, display: 'block' });
935
+
936
+ // Now we add it to the DOM because need some info about it. But it's not
937
+ // visible yet anyway.
938
+ element.after( popover );
939
+
940
+ // Get the position of the directive element.
941
+ position = getPosition();
942
+
943
+ // Get the height and width of the popover so we can center it.
944
+ ttWidth = popover.prop( 'offsetWidth' );
945
+ ttHeight = popover.prop( 'offsetHeight' );
946
+
947
+ // Calculate the popover's top and left coordinates to center it with
948
+ // this directive.
949
+ switch ( scope.tt_placement ) {
950
+ case 'right':
951
+ ttPosition = {
952
+ top: (position.top + position.height / 2 - ttHeight / 2) + 'px',
953
+ left: (position.left + position.width) + 'px'
954
+ };
955
+ break;
956
+ case 'bottom':
957
+ ttPosition = {
958
+ top: (position.top + position.height) + 'px',
959
+ left: (position.left + position.width / 2 - ttWidth / 2) + 'px'
960
+ };
961
+ break;
962
+ case 'left':
963
+ ttPosition = {
964
+ top: (position.top + position.height / 2 - ttHeight / 2) + 'px',
965
+ left: (position.left - ttWidth) + 'px'
966
+ };
967
+ break;
968
+ default:
969
+ ttPosition = {
970
+ top: (position.top - ttHeight) + 'px',
971
+ left: (position.left + position.width / 2 - ttWidth / 2) + 'px'
972
+ };
973
+ break;
974
+ }
975
+
976
+ // Now set the calculated positioning.
977
+ popover.css( ttPosition );
978
+
979
+ // And show the popover.
980
+ scope.tt_isOpen = true;
981
+ }
982
+
983
+ // Hide the popover popup element.
984
+ function hide() {
985
+ // First things first: we don't show it anymore.
986
+ //popover.removeClass( 'in' );
987
+ scope.tt_isOpen = false;
988
+
989
+ // And now we remove it from the DOM. However, if we have animation, we
990
+ // need to wait for it to expire beforehand.
991
+ // FIXME: this is a placeholder for a port of the transitions library.
992
+ if ( angular.isDefined( scope.tt_animation ) && scope.tt_animation() ) {
993
+ transitionTimeout = $timeout( function () { popover.remove(); }, 500 );
994
+ } else {
995
+ popover.remove();
996
+ }
997
+ }
998
+
999
+ // Register the event listeners.
1000
+ element.bind( 'click', function() {
1001
+ if(scope.tt_isOpen){
1002
+ scope.$apply( hide );
1003
+ } else {
1004
+ scope.$apply( show );
1005
+ }
1006
+
1007
+ });
1008
+ }
1009
+ };
1010
+ }]);
1011
+
1012
+
1013
+ angular.module('ui.bootstrap.tabs', [])
1014
+ .controller('TabsController', ['$scope', '$element', function($scope, $element) {
1015
+ var panes = $scope.panes = [];
1016
+
1017
+ this.select = $scope.select = function selectPane(pane) {
1018
+ angular.forEach(panes, function(pane) {
1019
+ pane.selected = false;
1020
+ });
1021
+ pane.selected = true;
1022
+ };
1023
+
1024
+ this.addPane = function addPane(pane) {
1025
+ if (!panes.length) {
1026
+ $scope.select(pane);
1027
+ }
1028
+ panes.push(pane);
1029
+ };
1030
+
1031
+ this.removePane = function removePane(pane) {
1032
+ var index = panes.indexOf(pane);
1033
+ panes.splice(index, 1);
1034
+ //Select a new pane if removed pane was selected
1035
+ if (pane.selected && panes.length > 0) {
1036
+ $scope.select(panes[index < panes.length ? index : index-1]);
1037
+ }
1038
+ };
1039
+ }])
1040
+ .directive('tabs', function() {
1041
+ return {
1042
+ restrict: 'EA',
1043
+ transclude: true,
1044
+ scope: {},
1045
+ controller: 'TabsController',
1046
+ templateUrl: 'template/tabs/tabs.html',
1047
+ replace: true
1048
+ };
1049
+ })
1050
+ .directive('pane', ['$parse', function($parse) {
1051
+ return {
1052
+ require: '^tabs',
1053
+ restrict: 'EA',
1054
+ transclude: true,
1055
+ scope:{
1056
+ heading:'@'
1057
+ },
1058
+ link: function(scope, element, attrs, tabsCtrl) {
1059
+ var getSelected, setSelected;
1060
+ scope.selected = false;
1061
+ if (attrs.active) {
1062
+ getSelected = $parse(attrs.active);
1063
+ setSelected = getSelected.assign;
1064
+ scope.$watch(
1065
+ function watchSelected() {return getSelected(scope.$parent);},
1066
+ function updateSelected(value) {scope.selected = value;}
1067
+ );
1068
+ scope.selected = getSelected ? getSelected(scope.$parent) : false;
1069
+ }
1070
+ scope.$watch('selected', function(selected) {
1071
+ if(selected) {
1072
+ tabsCtrl.select(scope);
1073
+ }
1074
+ if(setSelected) {
1075
+ setSelected(scope.$parent, selected);
1076
+ }
1077
+ });
1078
+
1079
+ tabsCtrl.addPane(scope);
1080
+ scope.$on('$destroy', function() {
1081
+ tabsCtrl.removePane(scope);
1082
+ });
1083
+ },
1084
+ templateUrl: 'template/tabs/pane.html',
1085
+ replace: true
1086
+ };
1087
+ }]);
1088
+
1089
+ /**
1090
+ * The following features are still outstanding: popup delay, animation as a
1091
+ * function, placement as a function, inside, support for more triggers than
1092
+ * just mouse enter/leave, html tooltips, and selector delegatation.
1093
+ */
1094
+ angular.module( 'ui.bootstrap.tooltip', [] )
1095
+ .directive( 'tooltipPopup', function () {
1096
+ return {
1097
+ restrict: 'EA',
1098
+ replace: true,
1099
+ scope: { tooltipTitle: '@', placement: '@', animation: '&', isOpen: '&' },
1100
+ templateUrl: 'template/tooltip/tooltip-popup.html'
1101
+ };
1102
+ })
1103
+ .directive( 'tooltip', [ '$compile', '$timeout', '$parse', function ( $compile, $timeout, $parse ) {
1104
+
1105
+ var template =
1106
+ '<tooltip-popup '+
1107
+ 'tooltip-title="{{tt_tooltip}}" '+
1108
+ 'placement="{{tt_placement}}" '+
1109
+ 'animation="tt_animation()" '+
1110
+ 'is-open="tt_isOpen"'+
1111
+ '>'+
1112
+ '</tooltip-popup>';
1113
+
1114
+ return {
1115
+ scope: true,
1116
+ link: function ( scope, element, attr ) {
1117
+ var tooltip = $compile( template )( scope ),
1118
+ transitionTimeout;
1119
+
1120
+ attr.$observe( 'tooltip', function ( val ) {
1121
+ scope.tt_tooltip = val;
1122
+ });
1123
+
1124
+ attr.$observe( 'tooltipPlacement', function ( val ) {
1125
+ // If no placement was provided, default to 'top'.
1126
+ scope.tt_placement = val || 'top';
1127
+ });
1128
+
1129
+ attr.$observe( 'tooltipAnimation', function ( val ) {
1130
+ scope.tt_animation = $parse( val );
1131
+ });
1132
+
1133
+ // By default, the tooltip is not open.
1134
+ scope.tt_isOpen = false;
1135
+
1136
+ // Calculate the current position and size of the directive element.
1137
+ function getPosition() {
1138
+ return {
1139
+ width: element.prop( 'offsetWidth' ),
1140
+ height: element.prop( 'offsetHeight' ),
1141
+ top: element.prop( 'offsetTop' ),
1142
+ left: element.prop( 'offsetLeft' )
1143
+ };
1144
+ }
1145
+
1146
+ // Show the tooltip popup element.
1147
+ function show() {
1148
+ var position,
1149
+ ttWidth,
1150
+ ttHeight,
1151
+ ttPosition;
1152
+
1153
+ // If there is a pending remove transition, we must cancel it, lest the
1154
+ // toolip be mysteriously removed.
1155
+ if ( transitionTimeout ) {
1156
+ $timeout.cancel( transitionTimeout );
1157
+ }
1158
+
1159
+ // Set the initial positioning.
1160
+ tooltip.css({ top: 0, left: 0, display: 'block' });
1161
+
1162
+ // Now we add it to the DOM because need some info about it. But it's not
1163
+ // visible yet anyway.
1164
+ element.after( tooltip );
1165
+
1166
+ // Get the position of the directive element.
1167
+ position = getPosition();
1168
+
1169
+ // Get the height and width of the tooltip so we can center it.
1170
+ ttWidth = tooltip.prop( 'offsetWidth' );
1171
+ ttHeight = tooltip.prop( 'offsetHeight' );
1172
+
1173
+ // Calculate the tooltip's top and left coordinates to center it with
1174
+ // this directive.
1175
+ switch ( scope.tt_placement ) {
1176
+ case 'right':
1177
+ ttPosition = {
1178
+ top: (position.top + position.height / 2 - ttHeight / 2) + 'px',
1179
+ left: (position.left + position.width) + 'px'
1180
+ };
1181
+ break;
1182
+ case 'bottom':
1183
+ ttPosition = {
1184
+ top: (position.top + position.height) + 'px',
1185
+ left: (position.left + position.width / 2 - ttWidth / 2) + 'px'
1186
+ };
1187
+ break;
1188
+ case 'left':
1189
+ ttPosition = {
1190
+ top: (position.top + position.height / 2 - ttHeight / 2) + 'px',
1191
+ left: (position.left - ttWidth) + 'px'
1192
+ };
1193
+ break;
1194
+ default:
1195
+ ttPosition = {
1196
+ top: (position.top - ttHeight) + 'px',
1197
+ left: (position.left + position.width / 2 - ttWidth / 2) + 'px'
1198
+ };
1199
+ break;
1200
+ }
1201
+
1202
+ // Now set the calculated positioning.
1203
+ tooltip.css( ttPosition );
1204
+
1205
+ // And show the tooltip.
1206
+ scope.tt_isOpen = true;
1207
+ }
1208
+
1209
+ // Hide the tooltip popup element.
1210
+ function hide() {
1211
+ // First things first: we don't show it anymore.
1212
+ //tooltip.removeClass( 'in' );
1213
+ scope.tt_isOpen = false;
1214
+
1215
+ // And now we remove it from the DOM. However, if we have animation, we
1216
+ // need to wait for it to expire beforehand.
1217
+ // FIXME: this is a placeholder for a port of the transitions library.
1218
+ if ( angular.isDefined( scope.tt_animation ) && scope.tt_animation() ) {
1219
+ transitionTimeout = $timeout( function () { tooltip.remove(); }, 500 );
1220
+ } else {
1221
+ tooltip.remove();
1222
+ }
1223
+ }
1224
+
1225
+ // Register the event listeners.
1226
+ element.bind( 'mouseenter', function() {
1227
+ scope.$apply( show );
1228
+ });
1229
+ element.bind( 'mouseleave', function() {
1230
+ scope.$apply( hide );
1231
+ });
1232
+ }
1233
+ };
1234
+ }]);
1235
+
1236
+
1237
+ angular.module('ui.bootstrap.transition', [])
1238
+
1239
+ /**
1240
+ * $transition service provides a consistent interface to trigger CSS 3 transitions and to be informed when they complete.
1241
+ * @param {DOMElement} element The DOMElement that will be animated.
1242
+ * @param {string|object|function} trigger The thing that will cause the transition to start:
1243
+ * - As a string, it represents the css class to be added to the element.
1244
+ * - As an object, it represents a hash of style attributes to be applied to the element.
1245
+ * - As a function, it represents a function to be called that will cause the transition to occur.
1246
+ * @return {Promise} A promise that is resolved when the transition finishes.
1247
+ */
1248
+ .factory('$transition', ['$q', '$timeout', '$rootScope', function($q, $timeout, $rootScope) {
1249
+
1250
+ var $transition = function(element, trigger, options) {
1251
+ options = options || {};
1252
+ var deferred = $q.defer();
1253
+ var endEventName = $transition[options.animation ? "animationEndEventName" : "transitionEndEventName"];
1254
+
1255
+ var transitionEndHandler = function(event) {
1256
+ $rootScope.$apply(function() {
1257
+ element.unbind(endEventName, transitionEndHandler);
1258
+ deferred.resolve(element);
1259
+ });
1260
+ };
1261
+
1262
+ if (endEventName) {
1263
+ element.bind(endEventName, transitionEndHandler);
1264
+ }
1265
+
1266
+ // Wrap in a timeout to allow the browser time to update the DOM before the transition is to occur
1267
+ $timeout(function() {
1268
+ if ( angular.isString(trigger) ) {
1269
+ element.addClass(trigger);
1270
+ } else if ( angular.isFunction(trigger) ) {
1271
+ trigger(element);
1272
+ } else if ( angular.isObject(trigger) ) {
1273
+ element.css(trigger);
1274
+ }
1275
+ //If browser does not support transitions, instantly resolve
1276
+ if ( !endEventName ) {
1277
+ deferred.resolve(element);
1278
+ }
1279
+ });
1280
+
1281
+ // Add our custom cancel function to the promise that is returned
1282
+ // We can call this if we are about to run a new transition, which we know will prevent this transition from ending,
1283
+ // i.e. it will therefore never raise a transitionEnd event for that transition
1284
+ deferred.promise.cancel = function() {
1285
+ if ( endEventName ) {
1286
+ element.unbind(endEventName, transitionEndHandler);
1287
+ }
1288
+ deferred.reject('Transition cancelled');
1289
+ };
1290
+
1291
+ return deferred.promise;
1292
+ };
1293
+
1294
+ // Work out the name of the transitionEnd event
1295
+ var transElement = document.createElement('trans');
1296
+ var transitionEndEventNames = {
1297
+ 'WebkitTransition': 'webkitTransitionEnd',
1298
+ 'MozTransition': 'transitionend',
1299
+ 'OTransition': 'oTransitionEnd',
1300
+ 'msTransition': 'MSTransitionEnd',
1301
+ 'transition': 'transitionend'
1302
+ };
1303
+ var animationEndEventNames = {
1304
+ 'WebkitTransition': 'webkitAnimationEnd',
1305
+ 'MozTransition': 'animationend',
1306
+ 'OTransition': 'oAnimationEnd',
1307
+ 'msTransition': 'MSAnimationEnd',
1308
+ 'transition': 'animationend'
1309
+ };
1310
+ function findEndEventName(endEventNames) {
1311
+ for (var name in endEventNames){
1312
+ if (transElement.style[name] !== undefined) {
1313
+ return endEventNames[name];
1314
+ }
1315
+ }
1316
+ }
1317
+ $transition.transitionEndEventName = findEndEventName(transitionEndEventNames);
1318
+ $transition.animationEndEventName = findEndEventName(animationEndEventNames);
1319
+ return $transition;
1320
+ }]);
1321
+
1322
+ angular.module("template/accordion/accordion-group.html", []).run(["$templateCache", function($templateCache){
1323
+ $templateCache.put("template/accordion/accordion-group.html",
1324
+ "<div class=\"accordion-group\">" +
1325
+ " <div class=\"accordion-heading\" ><a class=\"accordion-toggle\" ng-click=\"isOpen = !isOpen\">{{heading}}</a></div>" +
1326
+ " <div class=\"accordion-body\" collapse=\"!isOpen\">" +
1327
+ " <div class=\"accordion-inner\" ng-transclude></div> </div>" +
1328
+ "</div>");
1329
+ }]);
1330
+
1331
+ angular.module("template/accordion/accordion.html", []).run(["$templateCache", function($templateCache){
1332
+ $templateCache.put("template/accordion/accordion.html",
1333
+ "<div class=\"accordion\" ng-transclude></div>");
1334
+ }]);
1335
+
1336
+ angular.module("template/alert/alert.html", []).run(["$templateCache", function($templateCache){
1337
+ $templateCache.put("template/alert/alert.html",
1338
+ "<div class='alert' ng-class='type && \"alert-\" + type'>" +
1339
+ " <button type='button' class='close' ng-click='close()'>&times;</button>" +
1340
+ " <div ng-transclude></div>" +
1341
+ "</div>");
1342
+ }]);
1343
+
1344
+ angular.module("template/carousel/carousel.html", []).run(["$templateCache", function($templateCache){
1345
+ $templateCache.put("template/carousel/carousel.html",
1346
+ "<div ng-mouseenter=\"pause()\" ng-mouseleave=\"play()\" class=\"carousel\">" +
1347
+ " <div class=\"carousel-inner\" ng-transclude></div>" +
1348
+ " <a ng-click=\"prev()\" class=\"carousel-control left\">&lsaquo;</a>" +
1349
+ " <a ng-click=\"next()\" class=\"carousel-control right\">&rsaquo;</a>" +
1350
+ "</div>" +
1351
+ "");
1352
+ }]);
1353
+
1354
+ angular.module("template/carousel/slide.html", []).run(["$templateCache", function($templateCache){
1355
+ $templateCache.put("template/carousel/slide.html",
1356
+ "<div ng-class=\"{" +
1357
+ " 'active': leaving || (active && !entering)," +
1358
+ " 'prev': (next || active) && direction=='prev'," +
1359
+ " 'next': (next || active) && direction=='next'," +
1360
+ " 'right': direction=='prev'," +
1361
+ " 'left': direction=='next'" +
1362
+ " }\" class=\"item\" ng-transclude></div>" +
1363
+ "");
1364
+ }]);
1365
+
1366
+ angular.module("template/dialog/message.html", []).run(["$templateCache", function($templateCache){
1367
+ $templateCache.put("template/dialog/message.html",
1368
+ "<div class=\"modal-header\">" +
1369
+ " <h1>{{ title }}</h1>" +
1370
+ "</div>" +
1371
+ "<div class=\"modal-body\">" +
1372
+ " <p>{{ message }}</p>" +
1373
+ "</div>" +
1374
+ "<div class=\"modal-footer\">" +
1375
+ " <button ng-repeat=\"btn in buttons\" ng-click=\"close(btn.result)\" class=btn ng-class=\"btn.cssClass\">{{ btn.label }}</button>" +
1376
+ "</div>" +
1377
+ "");
1378
+ }]);
1379
+
1380
+ angular.module("template/pagination/pagination.html", []).run(["$templateCache", function($templateCache){
1381
+ $templateCache.put("template/pagination/pagination.html",
1382
+ "<div class=\"pagination\"><ul>" +
1383
+ " <li ng-class=\"{disabled: noPrevious()}\"><a ng-click=\"selectPrevious()\">{{previousText || 'Previous'}}</a></li>" +
1384
+ " <li ng-repeat=\"page in pages\" ng-class=\"{active: isActive(page)}\"><a ng-click=\"selectPage(page)\">{{page}}</a></li>" +
1385
+ " <li ng-class=\"{disabled: noNext()}\"><a ng-click=\"selectNext()\">{{nextText || 'Next'}}</a></li>" +
1386
+ " </ul>" +
1387
+ "</div>" +
1388
+ "");
1389
+ }]);
1390
+
1391
+ angular.module("template/popover/popover.html", []).run(["$templateCache", function($templateCache){
1392
+ $templateCache.put("template/popover/popover.html",
1393
+ "<div class=\"popover {{placement}}\" ng-class=\"{ in: isOpen(), fade: animation() }\">" +
1394
+ " <div class=\"arrow\"></div>" +
1395
+ "" +
1396
+ " <div class=\"popover-inner\">" +
1397
+ " <h3 class=\"popover-title\" ng-bind=\"popoverTitle\" ng-show=\"popoverTitle\"></h3>" +
1398
+ " <div class=\"popover-content\" ng-bind=\"popoverContent\"></div>" +
1399
+ " </div>" +
1400
+ "</div>" +
1401
+ "");
1402
+ }]);
1403
+
1404
+ angular.module("template/tabs/pane.html", []).run(["$templateCache", function($templateCache){
1405
+ $templateCache.put("template/tabs/pane.html",
1406
+ "<div class=\"tab-pane\" ng-class=\"{active: selected}\" ng-show=\"selected\" ng-transclude></div>" +
1407
+ "");
1408
+ }]);
1409
+
1410
+ angular.module("template/tabs/tabs.html", []).run(["$templateCache", function($templateCache){
1411
+ $templateCache.put("template/tabs/tabs.html",
1412
+ "<div class=\"tabbable\">" +
1413
+ " <ul class=\"nav nav-tabs\">" +
1414
+ " <li ng-repeat=\"pane in panes\" ng-class=\"{active:pane.selected}\">" +
1415
+ " <a href=\"\" ng-click=\"select(pane)\">{{pane.heading}}</a>" +
1416
+ " </li>" +
1417
+ " </ul>" +
1418
+ " <div class=\"tab-content\" ng-transclude></div>" +
1419
+ "</div>" +
1420
+ "");
1421
+ }]);
1422
+
1423
+ angular.module("template/tooltip/tooltip-popup.html", []).run(["$templateCache", function($templateCache){
1424
+ $templateCache.put("template/tooltip/tooltip-popup.html",
1425
+ "<div class=\"tooltip {{placement}}\" ng-class=\"{ in: isOpen(), fade: animation() }\">" +
1426
+ " <div class=\"tooltip-arrow\"></div>" +
1427
+ " <div class=\"tooltip-inner\" ng-bind=\"tooltipTitle\"></div>" +
1428
+ "</div>" +
1429
+ "");
1430
+ }]);