angular-ui-bootstrap-rails 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }]);