angular-ui-bootstrap-rails 0.1.1 → 0.2.0
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.
@@ -1,6 +1,6 @@
|
|
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"]);
|
1
|
+
angular.module("ui.bootstrap", ["ui.bootstrap.tpls", "ui.bootstrap.accordion","ui.bootstrap.alert","ui.bootstrap.buttons","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","ui.bootstrap.typeahead"]);
|
2
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"]);
|
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","template/typeahead/typeahead.html"]);
|
4
4
|
|
5
5
|
angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
|
6
6
|
|
@@ -43,11 +43,11 @@ angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
|
|
43
43
|
}
|
44
44
|
};
|
45
45
|
|
46
|
-
}])
|
46
|
+
}])
|
47
47
|
|
48
48
|
// The accordion directive simply sets up the directive controller
|
49
49
|
// and adds an accordion CSS class to itself element.
|
50
|
-
|
50
|
+
.directive('accordion', function () {
|
51
51
|
return {
|
52
52
|
restrict:'EA',
|
53
53
|
controller:'AccordionController',
|
@@ -55,10 +55,10 @@ angular.module('ui.bootstrap.accordion').directive('accordion', function () {
|
|
55
55
|
replace: false,
|
56
56
|
templateUrl: 'template/accordion/accordion.html'
|
57
57
|
};
|
58
|
-
})
|
58
|
+
})
|
59
59
|
|
60
60
|
// The accordion-group directive indicates a block of html that will expand and collapse in an accordion
|
61
|
-
|
61
|
+
.directive('accordionGroup', ['$parse', '$transition', '$timeout', function($parse, $transition, $timeout) {
|
62
62
|
return {
|
63
63
|
require:'^accordion', // We need this directive to be inside an accordion
|
64
64
|
restrict:'EA',
|
@@ -66,6 +66,11 @@ angular.module('ui.bootstrap.accordion').directive('accordionGroup', ['$parse',
|
|
66
66
|
replace: true, // The element containing the directive will be replaced with the template
|
67
67
|
templateUrl:'template/accordion/accordion-group.html',
|
68
68
|
scope:{ heading:'@' }, // Create an isolated scope and interpolate the heading attribute onto this scope
|
69
|
+
controller: ['$scope', function($scope) {
|
70
|
+
this.setHeading = function(element) {
|
71
|
+
this.heading = element;
|
72
|
+
};
|
73
|
+
}],
|
69
74
|
link: function(scope, element, attrs, accordionCtrl) {
|
70
75
|
var getIsOpen, setIsOpen;
|
71
76
|
|
@@ -93,10 +98,51 @@ angular.module('ui.bootstrap.accordion').directive('accordionGroup', ['$parse',
|
|
93
98
|
setIsOpen(scope.$parent, value);
|
94
99
|
}
|
95
100
|
});
|
101
|
+
}
|
102
|
+
};
|
103
|
+
}])
|
96
104
|
|
105
|
+
// Use accordion-heading below an accordion-group to provide a heading containing HTML
|
106
|
+
// <accordion-group>
|
107
|
+
// <accordion-heading>Heading containing HTML - <img src="..."></accordion-heading>
|
108
|
+
// </accordion-group>
|
109
|
+
.directive('accordionHeading', function() {
|
110
|
+
return {
|
111
|
+
restrict: 'E',
|
112
|
+
transclude: true, // Grab the contents to be used as the heading
|
113
|
+
template: '', // In effect remove this element!
|
114
|
+
replace: true,
|
115
|
+
require: '^accordionGroup',
|
116
|
+
compile: function(element, attr, transclude) {
|
117
|
+
return function link(scope, element, attr, accordionGroupCtrl) {
|
118
|
+
// Pass the heading to the accordion-group controller
|
119
|
+
// so that it can be transcluded into the right place in the template
|
120
|
+
// [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat]
|
121
|
+
accordionGroupCtrl.setHeading(transclude(scope, function() {}));
|
122
|
+
};
|
97
123
|
}
|
98
124
|
};
|
99
|
-
}
|
125
|
+
})
|
126
|
+
|
127
|
+
// Use in the accordion-group template to indicate where you want the heading to be transcluded
|
128
|
+
// You must provide the property on the accordion-group controller that will hold the transcluded element
|
129
|
+
// <div class="accordion-group">
|
130
|
+
// <div class="accordion-heading" ><a ... accordion-transclude="heading">...</a></div>
|
131
|
+
// ...
|
132
|
+
// </div>
|
133
|
+
.directive('accordionTransclude', function() {
|
134
|
+
return {
|
135
|
+
require: '^accordionGroup',
|
136
|
+
link: function(scope, element, attr, controller) {
|
137
|
+
scope.$watch(function() { return controller[attr.accordionTransclude]; }, function(heading) {
|
138
|
+
if ( heading ) {
|
139
|
+
element.html('');
|
140
|
+
element.append(heading);
|
141
|
+
}
|
142
|
+
});
|
143
|
+
}
|
144
|
+
};
|
145
|
+
});
|
100
146
|
|
101
147
|
angular.module("ui.bootstrap.alert", []).directive('alert', function () {
|
102
148
|
return {
|
@@ -110,11 +156,87 @@ angular.module("ui.bootstrap.alert", []).directive('alert', function () {
|
|
110
156
|
}
|
111
157
|
};
|
112
158
|
});
|
159
|
+
angular.module('ui.bootstrap.buttons', [])
|
160
|
+
|
161
|
+
.constant('buttonConfig', {
|
162
|
+
activeClass:'active',
|
163
|
+
toggleEvent:'click'
|
164
|
+
})
|
165
|
+
|
166
|
+
.directive('btnRadio', ['buttonConfig', function (buttonConfig) {
|
167
|
+
var activeClass = buttonConfig.activeClass || 'active';
|
168
|
+
var toggleEvent = buttonConfig.toggleEvent || 'click';
|
169
|
+
|
170
|
+
return {
|
171
|
+
|
172
|
+
require:'ngModel',
|
173
|
+
link:function (scope, element, attrs, ngModelCtrl) {
|
174
|
+
|
175
|
+
var value = scope.$eval(attrs.btnRadio);
|
176
|
+
|
177
|
+
//model -> UI
|
178
|
+
scope.$watch(function () {
|
179
|
+
return ngModelCtrl.$modelValue;
|
180
|
+
}, function (modelValue) {
|
181
|
+
if (angular.equals(modelValue, value)){
|
182
|
+
element.addClass(activeClass);
|
183
|
+
} else {
|
184
|
+
element.removeClass(activeClass);
|
185
|
+
}
|
186
|
+
});
|
187
|
+
|
188
|
+
//ui->model
|
189
|
+
element.bind(toggleEvent, function () {
|
190
|
+
if (!element.hasClass(activeClass)) {
|
191
|
+
scope.$apply(function () {
|
192
|
+
ngModelCtrl.$setViewValue(value);
|
193
|
+
});
|
194
|
+
}
|
195
|
+
});
|
196
|
+
}
|
197
|
+
};
|
198
|
+
}])
|
199
|
+
|
200
|
+
.directive('btnCheckbox', ['buttonConfig', function (buttonConfig) {
|
201
|
+
|
202
|
+
var activeClass = buttonConfig.activeClass || 'active';
|
203
|
+
var toggleEvent = buttonConfig.toggleEvent || 'click';
|
204
|
+
|
205
|
+
return {
|
206
|
+
require:'ngModel',
|
207
|
+
link:function (scope, element, attrs, ngModelCtrl) {
|
208
|
+
|
209
|
+
var trueValue = scope.$eval(attrs.btnCheckboxTrue);
|
210
|
+
var falseValue = scope.$eval(attrs.btnCheckboxFalse);
|
211
|
+
|
212
|
+
trueValue = angular.isDefined(trueValue) ? trueValue : true;
|
213
|
+
falseValue = angular.isDefined(falseValue) ? falseValue : false;
|
214
|
+
|
215
|
+
//model -> UI
|
216
|
+
scope.$watch(function () {
|
217
|
+
return ngModelCtrl.$modelValue;
|
218
|
+
}, function (modelValue) {
|
219
|
+
if (angular.equals(modelValue, trueValue)) {
|
220
|
+
element.addClass(activeClass);
|
221
|
+
} else {
|
222
|
+
element.removeClass(activeClass);
|
223
|
+
}
|
224
|
+
});
|
225
|
+
|
226
|
+
//ui->model
|
227
|
+
element.bind(toggleEvent, function () {
|
228
|
+
scope.$apply(function () {
|
229
|
+
ngModelCtrl.$setViewValue(element.hasClass(activeClass) ? falseValue : trueValue);
|
230
|
+
});
|
231
|
+
});
|
232
|
+
}
|
233
|
+
};
|
234
|
+
}]);
|
113
235
|
/*
|
114
236
|
*
|
115
|
-
*
|
237
|
+
* AngularJS Bootstrap Carousel
|
116
238
|
*
|
117
|
-
*
|
239
|
+
* A pure AngularJS carousel.
|
118
240
|
*
|
119
241
|
* For no interval set the interval to non-number, or milliseconds of desired interval
|
120
242
|
* Template: <carousel interval="none"><slide>{{anything}}</slide></carousel>
|
@@ -197,6 +319,18 @@ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition'])
|
|
197
319
|
return self.select(slides[newIndex], 'prev');
|
198
320
|
};
|
199
321
|
|
322
|
+
$scope.select = function(slide) {
|
323
|
+
self.select(slide);
|
324
|
+
};
|
325
|
+
|
326
|
+
$scope.isActive = function(slide) {
|
327
|
+
return self.currentSlide === slide;
|
328
|
+
};
|
329
|
+
|
330
|
+
$scope.slides = function() {
|
331
|
+
return slides;
|
332
|
+
};
|
333
|
+
|
200
334
|
$scope.$watch('interval', restartTimer);
|
201
335
|
function restartTimer() {
|
202
336
|
if (currentTimeout) {
|
@@ -327,7 +461,11 @@ angular.module('ui.bootstrap.collapse',['ui.bootstrap.transition'])
|
|
327
461
|
//When we have a change of scrollHeight we are setting again the correct height if the group is opened
|
328
462
|
if (element[0].scrollHeight !== 0) {
|
329
463
|
if (!isCollapsed) {
|
330
|
-
|
464
|
+
if (initialAnimSkip) {
|
465
|
+
fixUpHeight(scope, element, element[0].scrollHeight + 'px');
|
466
|
+
} else {
|
467
|
+
fixUpHeight(scope, element, 'auto');
|
468
|
+
}
|
331
469
|
}
|
332
470
|
}
|
333
471
|
});
|
@@ -403,22 +541,25 @@ dialogModule.controller('MessageBoxController', ['$scope', 'dialog', 'model', fu
|
|
403
541
|
dialogModule.provider("$dialog", function(){
|
404
542
|
|
405
543
|
// The default options for all dialogs.
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
544
|
+
var defaults = {
|
545
|
+
backdrop: true,
|
546
|
+
dialogClass: 'modal',
|
547
|
+
backdropClass: 'modal-backdrop',
|
410
548
|
transitionClass: 'fade',
|
411
549
|
triggerClass: 'in',
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
550
|
+
dialogOpenClass: 'modal-open',
|
551
|
+
resolve:{},
|
552
|
+
backdropFade: false,
|
553
|
+
dialogFade:false,
|
554
|
+
keyboard: true, // close with esc key
|
555
|
+
backdropClick: true // only in conjunction with backdrop=true
|
417
556
|
/* other options: template, templateUrl, controller */
|
418
557
|
};
|
419
558
|
|
420
559
|
var globalOptions = {};
|
421
560
|
|
561
|
+
var activeBackdrops = {value : 0};
|
562
|
+
|
422
563
|
// The `options({})` allows global configuration of all dialogs in the application.
|
423
564
|
//
|
424
565
|
// var app = angular.module('App', ['ui.bootstrap.dialog'], function($dialogProvider){
|
@@ -430,8 +571,8 @@ dialogModule.provider("$dialog", function(){
|
|
430
571
|
};
|
431
572
|
|
432
573
|
// 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) {
|
574
|
+
this.$get = ["$http", "$document", "$compile", "$rootScope", "$controller", "$templateCache", "$q", "$transition", "$injector",
|
575
|
+
function ($http, $document, $compile, $rootScope, $controller, $templateCache, $q, $transition, $injector) {
|
435
576
|
|
436
577
|
var body = $document.find('body');
|
437
578
|
|
@@ -443,9 +584,9 @@ dialogModule.provider("$dialog", function(){
|
|
443
584
|
|
444
585
|
// The `Dialog` class represents a modal dialog. The dialog class can be invoked by providing an options object
|
445
586
|
// containing at lest template or templateUrl and controller:
|
446
|
-
//
|
587
|
+
//
|
447
588
|
// var d = new Dialog({templateUrl: 'foo.html', controller: 'BarController'});
|
448
|
-
//
|
589
|
+
//
|
449
590
|
// Dialogs can also be created using templateUrl and controller as distinct arguments:
|
450
591
|
//
|
451
592
|
// var d = new Dialog('path/to/dialog.html', MyDialogController);
|
@@ -459,8 +600,8 @@ dialogModule.provider("$dialog", function(){
|
|
459
600
|
this.backdropEl.removeClass(options.triggerClass);
|
460
601
|
}
|
461
602
|
|
462
|
-
this.modalEl = createElement(options.
|
463
|
-
if(options.
|
603
|
+
this.modalEl = createElement(options.dialogClass);
|
604
|
+
if(options.dialogFade){
|
464
605
|
this.modalEl.addClass(options.transitionClass);
|
465
606
|
this.modalEl.removeClass(options.triggerClass);
|
466
607
|
}
|
@@ -496,13 +637,13 @@ dialogModule.provider("$dialog", function(){
|
|
496
637
|
if(controller){
|
497
638
|
options.controller = controller;
|
498
639
|
}
|
499
|
-
|
640
|
+
|
500
641
|
if(!(options.template || options.templateUrl)) {
|
501
642
|
throw new Error('Dialog.open expected template or templateUrl, neither found. Use options or open method to specify them.');
|
502
643
|
}
|
503
644
|
|
504
645
|
this._loadResolves().then(function(locals) {
|
505
|
-
var $scope = locals.$scope = self.$scope = $rootScope.$new();
|
646
|
+
var $scope = locals.$scope = self.$scope = locals.$scope ? locals.$scope : $rootScope.$new();
|
506
647
|
|
507
648
|
self.modalEl.html(locals.$template);
|
508
649
|
|
@@ -511,12 +652,13 @@ dialogModule.provider("$dialog", function(){
|
|
511
652
|
self.modalEl.contents().data('ngControllerController', ctrl);
|
512
653
|
}
|
513
654
|
|
514
|
-
$compile(self.modalEl
|
655
|
+
$compile(self.modalEl)($scope);
|
515
656
|
self._addElementsToDom();
|
657
|
+
body.addClass(self.options.dialogOpenClass);
|
516
658
|
|
517
659
|
// trigger tranisitions
|
518
660
|
setTimeout(function(){
|
519
|
-
if(self.options.
|
661
|
+
if(self.options.dialogFade){ self.modalEl.addClass(self.options.triggerClass); }
|
520
662
|
if(self.options.backdropFade){ self.backdropEl.addClass(self.options.triggerClass); }
|
521
663
|
});
|
522
664
|
|
@@ -532,6 +674,7 @@ dialogModule.provider("$dialog", function(){
|
|
532
674
|
var self = this;
|
533
675
|
var fadingElements = this._getFadingElements();
|
534
676
|
|
677
|
+
body.removeClass(self.options.dialogOpenClass);
|
535
678
|
if(fadingElements.length > 0){
|
536
679
|
for (var i = fadingElements.length - 1; i >= 0; i--) {
|
537
680
|
$transition(fadingElements[i], removeTriggerClass).then(onCloseComplete);
|
@@ -554,7 +697,7 @@ dialogModule.provider("$dialog", function(){
|
|
554
697
|
|
555
698
|
Dialog.prototype._getFadingElements = function(){
|
556
699
|
var elements = [];
|
557
|
-
if(this.options.
|
700
|
+
if(this.options.dialogFade){
|
558
701
|
elements.push(this.modalEl);
|
559
702
|
}
|
560
703
|
if(this.options.backdropFade){
|
@@ -583,13 +726,26 @@ dialogModule.provider("$dialog", function(){
|
|
583
726
|
|
584
727
|
Dialog.prototype._addElementsToDom = function(){
|
585
728
|
body.append(this.modalEl);
|
586
|
-
|
729
|
+
|
730
|
+
if(this.options.backdrop) {
|
731
|
+
if (activeBackdrops.value === 0) {
|
732
|
+
body.append(this.backdropEl);
|
733
|
+
}
|
734
|
+
activeBackdrops.value++;
|
735
|
+
}
|
736
|
+
|
587
737
|
this._open = true;
|
588
738
|
};
|
589
739
|
|
590
740
|
Dialog.prototype._removeElementsFromDom = function(){
|
591
741
|
this.modalEl.remove();
|
592
|
-
|
742
|
+
|
743
|
+
if(this.options.backdrop) {
|
744
|
+
activeBackdrops.value--;
|
745
|
+
if (activeBackdrops.value === 0) {
|
746
|
+
this.backdropEl.remove();
|
747
|
+
}
|
748
|
+
}
|
593
749
|
this._open = false;
|
594
750
|
};
|
595
751
|
|
@@ -606,7 +762,7 @@ dialogModule.provider("$dialog", function(){
|
|
606
762
|
|
607
763
|
angular.forEach(this.options.resolve || [], function(value, key) {
|
608
764
|
keys.push(key);
|
609
|
-
values.push(value);
|
765
|
+
values.push(angular.isString(value) ? $injector.get(value) : $injector.invoke(value));
|
610
766
|
});
|
611
767
|
|
612
768
|
keys.push('$template');
|
@@ -638,11 +794,15 @@ dialogModule.provider("$dialog", function(){
|
|
638
794
|
// * `label`: the label of the button
|
639
795
|
// * `cssClass`: additional css class(es) to apply to the button for styling
|
640
796
|
messageBox: function(title, message, buttons){
|
641
|
-
return new Dialog({templateUrl: 'template/dialog/message.html', controller: 'MessageBoxController', resolve:
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
797
|
+
return new Dialog({templateUrl: 'template/dialog/message.html', controller: 'MessageBoxController', resolve:
|
798
|
+
{model: function() {
|
799
|
+
return {
|
800
|
+
title: title,
|
801
|
+
message: message,
|
802
|
+
buttons: buttons
|
803
|
+
};
|
804
|
+
}
|
805
|
+
}});
|
646
806
|
}
|
647
807
|
};
|
648
808
|
}];
|
@@ -709,100 +869,97 @@ angular.module('ui.bootstrap.dropdownToggle', []).directive('dropdownToggle',
|
|
709
869
|
};
|
710
870
|
}]);
|
711
871
|
|
712
|
-
angular.module('ui.bootstrap.modal', [
|
872
|
+
angular.module('ui.bootstrap.modal', ['ui.bootstrap.dialog'])
|
873
|
+
.directive('modal', ['$parse', '$dialog', function($parse, $dialog) {
|
713
874
|
var backdropEl;
|
714
875
|
var body = angular.element(document.getElementsByTagName('body')[0]);
|
715
|
-
var defaultOpts = {
|
716
|
-
backdrop: true,
|
717
|
-
escape: true
|
718
|
-
};
|
719
876
|
return {
|
720
877
|
restrict: 'EA',
|
878
|
+
terminal: true,
|
721
879
|
link: function(scope, elm, attrs) {
|
722
|
-
var opts = angular.extend(
|
880
|
+
var opts = angular.extend({}, scope.$eval(attrs.uiOptions || attrs.bsOptions || attrs.options));
|
723
881
|
var shownExpr = attrs.modal || attrs.show;
|
724
882
|
var setClosed;
|
725
883
|
|
884
|
+
// Create a dialog with the template as the contents of the directive
|
885
|
+
// Add the current scope as the resolve in order to make the directive scope as a dialog controller scope
|
886
|
+
opts = angular.extend(opts, {
|
887
|
+
template: elm.html(),
|
888
|
+
resolve: { $scope: function() { return scope; } }
|
889
|
+
});
|
890
|
+
var dialog = $dialog.dialog(opts);
|
891
|
+
|
892
|
+
elm.remove();
|
893
|
+
|
726
894
|
if (attrs.close) {
|
727
895
|
setClosed = function() {
|
728
|
-
|
896
|
+
$parse(attrs.close)(scope);
|
729
897
|
};
|
730
898
|
} else {
|
731
|
-
setClosed = function() {
|
732
|
-
|
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);
|
899
|
+
setClosed = function() {
|
900
|
+
if (angular.isFunction($parse(shownExpr).assign)) {
|
901
|
+
$parse(shownExpr).assign(scope, false);
|
773
902
|
}
|
774
|
-
}
|
775
|
-
elm.css('display', 'block').addClass('in');
|
776
|
-
body.addClass('modal-open');
|
903
|
+
};
|
777
904
|
}
|
778
905
|
|
779
906
|
scope.$watch(shownExpr, function(isShown, oldShown) {
|
780
907
|
if (isShown) {
|
781
|
-
open()
|
908
|
+
dialog.open().then(function(){
|
909
|
+
setClosed();
|
910
|
+
});
|
782
911
|
} else {
|
783
|
-
|
912
|
+
//Make sure it is not opened
|
913
|
+
if (dialog.isOpen()){
|
914
|
+
dialog.close();
|
915
|
+
}
|
784
916
|
}
|
785
917
|
});
|
786
918
|
}
|
787
919
|
};
|
788
|
-
}]);
|
789
|
-
|
920
|
+
}]);
|
790
921
|
angular.module('ui.bootstrap.pagination', [])
|
791
922
|
|
792
|
-
.
|
923
|
+
.constant('paginationConfig', {
|
924
|
+
boundaryLinks: false,
|
925
|
+
directionLinks: true,
|
926
|
+
firstText: 'First',
|
927
|
+
previousText: 'Previous',
|
928
|
+
nextText: 'Next',
|
929
|
+
lastText: 'Last'
|
930
|
+
})
|
931
|
+
|
932
|
+
.directive('pagination', ['paginationConfig', function(paginationConfig) {
|
793
933
|
return {
|
794
934
|
restrict: 'EA',
|
795
935
|
scope: {
|
796
936
|
numPages: '=',
|
797
937
|
currentPage: '=',
|
798
938
|
maxSize: '=',
|
799
|
-
onSelectPage: '&'
|
800
|
-
nextText: '@',
|
801
|
-
previousText: '@'
|
939
|
+
onSelectPage: '&'
|
802
940
|
},
|
803
941
|
templateUrl: 'template/pagination/pagination.html',
|
804
942
|
replace: true,
|
805
|
-
link: function(scope) {
|
943
|
+
link: function(scope, element, attrs) {
|
944
|
+
|
945
|
+
// Setup configuration parameters
|
946
|
+
var boundaryLinks = angular.isDefined(attrs.boundaryLinks) ? scope.$eval(attrs.boundaryLinks) : paginationConfig.boundaryLinks;
|
947
|
+
var directionLinks = angular.isDefined(attrs.directionLinks) ? scope.$eval(attrs.directionLinks) : paginationConfig.directionLinks;
|
948
|
+
var firstText = angular.isDefined(attrs.firstText) ? attrs.firstText : paginationConfig.firstText;
|
949
|
+
var previousText = angular.isDefined(attrs.previousText) ? attrs.previousText : paginationConfig.previousText;
|
950
|
+
var nextText = angular.isDefined(attrs.nextText) ? attrs.nextText : paginationConfig.nextText;
|
951
|
+
var lastText = angular.isDefined(attrs.lastText) ? attrs.lastText : paginationConfig.lastText;
|
952
|
+
|
953
|
+
// Create page object used in template
|
954
|
+
function makePage(number, text, isActive, isDisabled) {
|
955
|
+
return {
|
956
|
+
number: number,
|
957
|
+
text: text,
|
958
|
+
active: isActive,
|
959
|
+
disabled: isDisabled
|
960
|
+
};
|
961
|
+
}
|
962
|
+
|
806
963
|
scope.$watch('numPages + currentPage + maxSize', function() {
|
807
964
|
scope.pages = [];
|
808
965
|
|
@@ -818,9 +975,31 @@ angular.module('ui.bootstrap.pagination', [])
|
|
818
975
|
startPage = startPage - ((startPage + maxSize - 1) - scope.numPages );
|
819
976
|
}
|
820
977
|
|
821
|
-
|
822
|
-
|
978
|
+
// Add page number links
|
979
|
+
for (var number = startPage, max = startPage + maxSize; number < max; number++) {
|
980
|
+
var page = makePage(number, number, scope.isActive(number), false);
|
981
|
+
scope.pages.push(page);
|
982
|
+
}
|
983
|
+
|
984
|
+
// Add previous & next links
|
985
|
+
if (directionLinks) {
|
986
|
+
var previousPage = makePage(scope.currentPage - 1, previousText, false, scope.noPrevious());
|
987
|
+
scope.pages.unshift(previousPage);
|
988
|
+
|
989
|
+
var nextPage = makePage(scope.currentPage + 1, nextText, false, scope.noNext());
|
990
|
+
scope.pages.push(nextPage);
|
991
|
+
}
|
992
|
+
|
993
|
+
// Add first & last links
|
994
|
+
if (boundaryLinks) {
|
995
|
+
var firstPage = makePage(1, firstText, false, scope.noPrevious());
|
996
|
+
scope.pages.unshift(firstPage);
|
997
|
+
|
998
|
+
var lastPage = makePage(scope.numPages, lastText, false, scope.noNext());
|
999
|
+
scope.pages.push(lastPage);
|
823
1000
|
}
|
1001
|
+
|
1002
|
+
|
824
1003
|
if ( scope.currentPage > scope.numPages ) {
|
825
1004
|
scope.selectPage(scope.numPages);
|
826
1005
|
}
|
@@ -836,25 +1015,14 @@ angular.module('ui.bootstrap.pagination', [])
|
|
836
1015
|
};
|
837
1016
|
|
838
1017
|
scope.selectPage = function(page) {
|
839
|
-
if ( ! scope.isActive(page) ) {
|
1018
|
+
if ( ! scope.isActive(page) && page > 0 && page <= scope.numPages) {
|
840
1019
|
scope.currentPage = page;
|
841
1020
|
scope.onSelectPage({ page: page });
|
842
1021
|
}
|
843
1022
|
};
|
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
1023
|
}
|
856
1024
|
};
|
857
|
-
});
|
1025
|
+
}]);
|
858
1026
|
/**
|
859
1027
|
* The following features are still outstanding: popup delay, animation as a
|
860
1028
|
* function, placement as a function, inside, support for more triggers than
|
@@ -869,7 +1037,7 @@ angular.module( 'ui.bootstrap.popover', [] )
|
|
869
1037
|
templateUrl: 'template/popover/popover.html'
|
870
1038
|
};
|
871
1039
|
})
|
872
|
-
.directive( 'popover', [ '$compile', '$timeout', '$parse', function ( $compile, $timeout, $parse ) {
|
1040
|
+
.directive( 'popover', [ '$compile', '$timeout', '$parse', '$window', function ( $compile, $timeout, $parse, $window ) {
|
873
1041
|
|
874
1042
|
var template =
|
875
1043
|
'<popover-popup '+
|
@@ -909,15 +1077,15 @@ angular.module( 'ui.bootstrap.popover', [] )
|
|
909
1077
|
|
910
1078
|
// Calculate the current position and size of the directive element.
|
911
1079
|
function getPosition() {
|
1080
|
+
var boundingClientRect = element[0].getBoundingClientRect();
|
912
1081
|
return {
|
913
1082
|
width: element.prop( 'offsetWidth' ),
|
914
1083
|
height: element.prop( 'offsetHeight' ),
|
915
|
-
top:
|
916
|
-
left:
|
1084
|
+
top: boundingClientRect.top + $window.pageYOffset,
|
1085
|
+
left: boundingClientRect.left + $window.pageXOffset
|
917
1086
|
};
|
918
1087
|
}
|
919
|
-
|
920
|
-
// Show the popover popup element.
|
1088
|
+
|
921
1089
|
function show() {
|
922
1090
|
var position,
|
923
1091
|
ttWidth,
|
@@ -1100,7 +1268,7 @@ angular.module( 'ui.bootstrap.tooltip', [] )
|
|
1100
1268
|
templateUrl: 'template/tooltip/tooltip-popup.html'
|
1101
1269
|
};
|
1102
1270
|
})
|
1103
|
-
.directive( 'tooltip', [ '$compile', '$timeout', '$parse', function ( $compile, $timeout, $parse ) {
|
1271
|
+
.directive( 'tooltip', [ '$compile', '$timeout', '$parse', '$window', function ( $compile, $timeout, $parse, $window) {
|
1104
1272
|
|
1105
1273
|
var template =
|
1106
1274
|
'<tooltip-popup '+
|
@@ -1135,11 +1303,12 @@ angular.module( 'ui.bootstrap.tooltip', [] )
|
|
1135
1303
|
|
1136
1304
|
// Calculate the current position and size of the directive element.
|
1137
1305
|
function getPosition() {
|
1306
|
+
var boundingClientRect = element[0].getBoundingClientRect();
|
1138
1307
|
return {
|
1139
1308
|
width: element.prop( 'offsetWidth' ),
|
1140
1309
|
height: element.prop( 'offsetHeight' ),
|
1141
|
-
top:
|
1142
|
-
left:
|
1310
|
+
top: boundingClientRect.top + $window.pageYOffset,
|
1311
|
+
left: boundingClientRect.left + $window.pageXOffset
|
1143
1312
|
};
|
1144
1313
|
}
|
1145
1314
|
|
@@ -1149,7 +1318,12 @@ angular.module( 'ui.bootstrap.tooltip', [] )
|
|
1149
1318
|
ttWidth,
|
1150
1319
|
ttHeight,
|
1151
1320
|
ttPosition;
|
1152
|
-
|
1321
|
+
|
1322
|
+
//don't show empty tooltips
|
1323
|
+
if (!scope.tt_tooltip) {
|
1324
|
+
return;
|
1325
|
+
}
|
1326
|
+
|
1153
1327
|
// If there is a pending remove transition, we must cancel it, lest the
|
1154
1328
|
// toolip be mysteriously removed.
|
1155
1329
|
if ( transitionTimeout ) {
|
@@ -1165,7 +1339,7 @@ angular.module( 'ui.bootstrap.tooltip', [] )
|
|
1165
1339
|
|
1166
1340
|
// Get the position of the directive element.
|
1167
1341
|
position = getPosition();
|
1168
|
-
|
1342
|
+
|
1169
1343
|
// Get the height and width of the tooltip so we can center it.
|
1170
1344
|
ttWidth = tooltip.prop( 'offsetWidth' );
|
1171
1345
|
ttHeight = tooltip.prop( 'offsetHeight' );
|
@@ -1319,10 +1493,212 @@ angular.module('ui.bootstrap.transition', [])
|
|
1319
1493
|
return $transition;
|
1320
1494
|
}]);
|
1321
1495
|
|
1496
|
+
angular.module('ui.bootstrap.typeahead', [])
|
1497
|
+
|
1498
|
+
/**
|
1499
|
+
* A helper service that can parse typeahead's syntax (string provided by users)
|
1500
|
+
* Extracted to a separate service for ease of unit testing
|
1501
|
+
*/
|
1502
|
+
.factory('typeaheadParser', ['$parse', function ($parse) {
|
1503
|
+
|
1504
|
+
// 00000111000000000000022200000000000000003333333333333330000000000044000
|
1505
|
+
var TYPEAHEAD_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?\s+for\s+(?:([\$\w][\$\w\d]*))\s+in\s+(.*)$/;
|
1506
|
+
|
1507
|
+
return {
|
1508
|
+
parse:function (input) {
|
1509
|
+
|
1510
|
+
var match = input.match(TYPEAHEAD_REGEXP), modelMapper, viewMapper, source;
|
1511
|
+
if (!match) {
|
1512
|
+
throw new Error(
|
1513
|
+
"Expected typeahead specification in form of '_modelValue_ (as _label_)? for _item_ in _collection_'" +
|
1514
|
+
" but got '" + input + "'.");
|
1515
|
+
}
|
1516
|
+
|
1517
|
+
return {
|
1518
|
+
itemName:match[3],
|
1519
|
+
source:$parse(match[4]),
|
1520
|
+
viewMapper:$parse(match[2] || match[1]),
|
1521
|
+
modelMapper:$parse(match[1])
|
1522
|
+
};
|
1523
|
+
}
|
1524
|
+
};
|
1525
|
+
}])
|
1526
|
+
|
1527
|
+
//options - min length
|
1528
|
+
.directive('typeahead', ['$compile', '$q', 'typeaheadParser', function ($compile, $q, typeaheadParser) {
|
1529
|
+
|
1530
|
+
var HOT_KEYS = [9, 13, 27, 38, 40];
|
1531
|
+
|
1532
|
+
return {
|
1533
|
+
require:'ngModel',
|
1534
|
+
link:function (originalScope, element, attrs, modelCtrl) {
|
1535
|
+
|
1536
|
+
var selected = modelCtrl.$modelValue;
|
1537
|
+
|
1538
|
+
//minimal no of characters that needs to be entered before typeahead kicks-in
|
1539
|
+
var minSearch = originalScope.$eval(attrs.typeaheadMinLength) || 1;
|
1540
|
+
|
1541
|
+
//expressions used by typeahead
|
1542
|
+
var parserResult = typeaheadParser.parse(attrs.typeahead);
|
1543
|
+
|
1544
|
+
//create a child scope for the typeahead directive so we are not polluting original scope
|
1545
|
+
//with typeahead-specific data (matches, query etc.)
|
1546
|
+
var scope = originalScope.$new();
|
1547
|
+
originalScope.$on('$destroy', function(){
|
1548
|
+
scope.$destroy();
|
1549
|
+
});
|
1550
|
+
|
1551
|
+
var resetMatches = function() {
|
1552
|
+
scope.matches = [];
|
1553
|
+
scope.activeIdx = -1;
|
1554
|
+
};
|
1555
|
+
|
1556
|
+
var getMatchesAsync = function(inputValue) {
|
1557
|
+
|
1558
|
+
var locals = {$viewValue: inputValue};
|
1559
|
+
$q.when(parserResult.source(scope, locals)).then(function(matches) {
|
1560
|
+
|
1561
|
+
//it might happen that several async queries were in progress if a user were typing fast
|
1562
|
+
//but we are interested only in responses that correspond to the current view value
|
1563
|
+
if (inputValue === modelCtrl.$viewValue) {
|
1564
|
+
if (matches.length > 0) {
|
1565
|
+
|
1566
|
+
scope.activeIdx = 0;
|
1567
|
+
scope.matches.length = 0;
|
1568
|
+
|
1569
|
+
//transform labels
|
1570
|
+
for(var i=0; i<matches.length; i++) {
|
1571
|
+
locals[parserResult.itemName] = matches[i];
|
1572
|
+
scope.matches.push({
|
1573
|
+
label: parserResult.viewMapper(scope, locals),
|
1574
|
+
model: matches[i]
|
1575
|
+
});
|
1576
|
+
}
|
1577
|
+
|
1578
|
+
scope.query = inputValue;
|
1579
|
+
|
1580
|
+
} else {
|
1581
|
+
resetMatches();
|
1582
|
+
}
|
1583
|
+
}
|
1584
|
+
}, resetMatches);
|
1585
|
+
};
|
1586
|
+
|
1587
|
+
resetMatches();
|
1588
|
+
|
1589
|
+
//we need to propagate user's query so we can higlight matches
|
1590
|
+
scope.query = undefined;
|
1591
|
+
|
1592
|
+
//plug into $parsers pipeline to open a typeahead on view changes initiated from DOM
|
1593
|
+
//$parsers kick-in on all the changes coming from the vview as well as manually triggered by $setViewValue
|
1594
|
+
modelCtrl.$parsers.push(function (inputValue) {
|
1595
|
+
|
1596
|
+
resetMatches();
|
1597
|
+
if (selected) {
|
1598
|
+
return inputValue;
|
1599
|
+
} else {
|
1600
|
+
if (inputValue && inputValue.length >= minSearch) {
|
1601
|
+
getMatchesAsync(inputValue);
|
1602
|
+
}
|
1603
|
+
}
|
1604
|
+
|
1605
|
+
return undefined;
|
1606
|
+
});
|
1607
|
+
|
1608
|
+
modelCtrl.$render = function () {
|
1609
|
+
var locals = {};
|
1610
|
+
locals[parserResult.itemName] = selected;
|
1611
|
+
element.val(parserResult.viewMapper(scope, locals) || modelCtrl.$viewValue);
|
1612
|
+
selected = undefined;
|
1613
|
+
};
|
1614
|
+
|
1615
|
+
scope.select = function (activeIdx) {
|
1616
|
+
//called from within the $digest() cycle
|
1617
|
+
var locals = {};
|
1618
|
+
locals[parserResult.itemName] = selected = scope.matches[activeIdx].model;
|
1619
|
+
|
1620
|
+
modelCtrl.$setViewValue(parserResult.modelMapper(scope, locals));
|
1621
|
+
modelCtrl.$render();
|
1622
|
+
};
|
1623
|
+
|
1624
|
+
//bind keyboard events: arrows up(38) / down(40), enter(13) and tab(9), esc(9)
|
1625
|
+
element.bind('keydown', function (evt) {
|
1626
|
+
|
1627
|
+
//typeahead is open and an "interesting" key was pressed
|
1628
|
+
if (scope.matches.length === 0 || HOT_KEYS.indexOf(evt.which) === -1) {
|
1629
|
+
return;
|
1630
|
+
}
|
1631
|
+
|
1632
|
+
evt.preventDefault();
|
1633
|
+
|
1634
|
+
if (evt.which === 40) {
|
1635
|
+
scope.activeIdx = (scope.activeIdx + 1) % scope.matches.length;
|
1636
|
+
scope.$digest();
|
1637
|
+
|
1638
|
+
} else if (evt.which === 38) {
|
1639
|
+
scope.activeIdx = (scope.activeIdx ? scope.activeIdx : scope.matches.length) - 1;
|
1640
|
+
scope.$digest();
|
1641
|
+
|
1642
|
+
} else if (evt.which === 13 || evt.which === 9) {
|
1643
|
+
scope.$apply(function () {
|
1644
|
+
scope.select(scope.activeIdx);
|
1645
|
+
});
|
1646
|
+
|
1647
|
+
} else if (evt.which === 27) {
|
1648
|
+
scope.matches = [];
|
1649
|
+
scope.$digest();
|
1650
|
+
}
|
1651
|
+
});
|
1652
|
+
|
1653
|
+
var tplElCompiled = $compile("<typeahead-popup matches='matches' active='activeIdx' select='select(activeIdx)' "+
|
1654
|
+
"query='query'></typeahead-popup>")(scope);
|
1655
|
+
element.after(tplElCompiled);
|
1656
|
+
}
|
1657
|
+
};
|
1658
|
+
|
1659
|
+
}])
|
1660
|
+
|
1661
|
+
.directive('typeaheadPopup', function () {
|
1662
|
+
return {
|
1663
|
+
restrict:'E',
|
1664
|
+
scope:{
|
1665
|
+
matches:'=',
|
1666
|
+
query:'=',
|
1667
|
+
active:'=',
|
1668
|
+
select:'&'
|
1669
|
+
},
|
1670
|
+
replace:true,
|
1671
|
+
templateUrl:'template/typeahead/typeahead.html',
|
1672
|
+
link:function (scope, element, attrs) {
|
1673
|
+
|
1674
|
+
scope.isOpen = function () {
|
1675
|
+
return scope.matches.length > 0;
|
1676
|
+
};
|
1677
|
+
|
1678
|
+
scope.isActive = function (matchIdx) {
|
1679
|
+
return scope.active == matchIdx;
|
1680
|
+
};
|
1681
|
+
|
1682
|
+
scope.selectActive = function (matchIdx) {
|
1683
|
+
scope.active = matchIdx;
|
1684
|
+
};
|
1685
|
+
|
1686
|
+
scope.selectMatch = function (activeIdx) {
|
1687
|
+
scope.select({activeIdx:activeIdx});
|
1688
|
+
};
|
1689
|
+
}
|
1690
|
+
};
|
1691
|
+
})
|
1692
|
+
|
1693
|
+
.filter('typeaheadHighlight', function() {
|
1694
|
+
return function(matchItem, query) {
|
1695
|
+
return (query) ? matchItem.replace(new RegExp(query, 'gi'), '<strong>$&</strong>') : query;
|
1696
|
+
};
|
1697
|
+
});
|
1322
1698
|
angular.module("template/accordion/accordion-group.html", []).run(["$templateCache", function($templateCache){
|
1323
1699
|
$templateCache.put("template/accordion/accordion-group.html",
|
1324
1700
|
"<div class=\"accordion-group\">" +
|
1325
|
-
" <div class=\"accordion-heading\" ><a class=\"accordion-toggle\" ng-click=\"isOpen = !isOpen\">{{heading}}</a></div>" +
|
1701
|
+
" <div class=\"accordion-heading\" ><a class=\"accordion-toggle\" ng-click=\"isOpen = !isOpen\" accordion-transclude=\"heading\">{{heading}}</a></div>" +
|
1326
1702
|
" <div class=\"accordion-body\" collapse=\"!isOpen\">" +
|
1327
1703
|
" <div class=\"accordion-inner\" ng-transclude></div> </div>" +
|
1328
1704
|
"</div>");
|
@@ -1344,6 +1720,9 @@ angular.module("template/alert/alert.html", []).run(["$templateCache", function(
|
|
1344
1720
|
angular.module("template/carousel/carousel.html", []).run(["$templateCache", function($templateCache){
|
1345
1721
|
$templateCache.put("template/carousel/carousel.html",
|
1346
1722
|
"<div ng-mouseenter=\"pause()\" ng-mouseleave=\"play()\" class=\"carousel\">" +
|
1723
|
+
" <ol class=\"carousel-indicators\">" +
|
1724
|
+
" <li ng-repeat=\"slide in slides()\" ng-class=\"{active: isActive(slide)}\" ng-click=\"select(slide)\"></li>" +
|
1725
|
+
" </ol>" +
|
1347
1726
|
" <div class=\"carousel-inner\" ng-transclude></div>" +
|
1348
1727
|
" <a ng-click=\"prev()\" class=\"carousel-control left\">‹</a>" +
|
1349
1728
|
" <a ng-click=\"next()\" class=\"carousel-control right\">›</a>" +
|
@@ -1380,9 +1759,7 @@ angular.module("template/dialog/message.html", []).run(["$templateCache", functi
|
|
1380
1759
|
angular.module("template/pagination/pagination.html", []).run(["$templateCache", function($templateCache){
|
1381
1760
|
$templateCache.put("template/pagination/pagination.html",
|
1382
1761
|
"<div class=\"pagination\"><ul>" +
|
1383
|
-
" <li ng-class=\"{disabled:
|
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>" +
|
1762
|
+
" <li ng-repeat=\"page in pages\" ng-class=\"{active: page.active, disabled: page.disabled}\"><a ng-click=\"selectPage(page.number)\">{{page.text}}</a></li>" +
|
1386
1763
|
" </ul>" +
|
1387
1764
|
"</div>" +
|
1388
1765
|
"");
|
@@ -1428,3 +1805,14 @@ angular.module("template/tooltip/tooltip-popup.html", []).run(["$templateCache",
|
|
1428
1805
|
"</div>" +
|
1429
1806
|
"");
|
1430
1807
|
}]);
|
1808
|
+
|
1809
|
+
angular.module("template/typeahead/typeahead.html", []).run(["$templateCache", function($templateCache){
|
1810
|
+
$templateCache.put("template/typeahead/typeahead.html",
|
1811
|
+
"<div class=\"dropdown clearfix\" ng-class=\"{open: isOpen()}\">" +
|
1812
|
+
" <ul class=\"typeahead dropdown-menu\">" +
|
1813
|
+
" <li ng-repeat=\"match in matches\" ng-class=\"{active: isActive($index) }\" ng-mouseenter=\"selectActive($index)\">" +
|
1814
|
+
" <a tabindex=\"-1\" ng-click=\"selectMatch($index)\" ng-bind-html-unsafe=\"match.label | typeaheadHighlight:query\"></a>" +
|
1815
|
+
" </li>" +
|
1816
|
+
" </ul>" +
|
1817
|
+
"</div>");
|
1818
|
+
}]);
|