angular-ui-bootstrap-rails 0.13.3 → 0.13.4
Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 157585fd25062ce26b115bc7bf8f4ba28daae01f
|
4
|
+
data.tar.gz: 0917b5bc46d3c0a9aff497eee7686316b22a4565
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2262d699dd426b1cc8ce6f75cc9ea68c102f7bc9d2ba6f21809370f7f1922144c91884a6a37ea20297ad61095829482122410e96dd2358927ce1410cbf7fd647
|
7
|
+
data.tar.gz: c3bc1958dfb2c1f455b6ca9f9d87e11ebf67f51466e72b6e6d825a526c303869f23bdd77bbd037ac31a52332ea5178ad55c755242ba179fe361b9de5b59324c5
|
@@ -2,17 +2,16 @@
|
|
2
2
|
* angular-ui-bootstrap
|
3
3
|
* http://angular-ui.github.io/bootstrap/
|
4
4
|
|
5
|
-
* Version: 0.13.
|
5
|
+
* Version: 0.13.4 - 2015-09-03
|
6
6
|
* License: MIT
|
7
7
|
*/
|
8
8
|
angular.module("ui.bootstrap", ["ui.bootstrap.tpls", "ui.bootstrap.collapse","ui.bootstrap.accordion","ui.bootstrap.alert","ui.bootstrap.bindHtml","ui.bootstrap.buttons","ui.bootstrap.carousel","ui.bootstrap.dateparser","ui.bootstrap.position","ui.bootstrap.datepicker","ui.bootstrap.dropdown","ui.bootstrap.modal","ui.bootstrap.pagination","ui.bootstrap.tooltip","ui.bootstrap.popover","ui.bootstrap.progressbar","ui.bootstrap.rating","ui.bootstrap.tabs","ui.bootstrap.timepicker","ui.bootstrap.transition","ui.bootstrap.typeahead"]);
|
9
9
|
angular.module("ui.bootstrap.tpls", ["template/accordion/accordion-group.html","template/accordion/accordion.html","template/alert/alert.html","template/carousel/carousel.html","template/carousel/slide.html","template/datepicker/datepicker.html","template/datepicker/day.html","template/datepicker/month.html","template/datepicker/popup.html","template/datepicker/year.html","template/modal/backdrop.html","template/modal/window.html","template/pagination/pager.html","template/pagination/pagination.html","template/tooltip/tooltip-html-popup.html","template/tooltip/tooltip-html-unsafe-popup.html","template/tooltip/tooltip-popup.html","template/tooltip/tooltip-template-popup.html","template/popover/popover-html.html","template/popover/popover-template.html","template/popover/popover.html","template/progressbar/bar.html","template/progressbar/progress.html","template/progressbar/progressbar.html","template/rating/rating.html","template/tabs/tab.html","template/tabs/tabset.html","template/timepicker/timepicker.html","template/typeahead/typeahead-match.html","template/typeahead/typeahead-popup.html"]);
|
10
10
|
angular.module('ui.bootstrap.collapse', [])
|
11
11
|
|
12
|
-
.directive('collapse', ['$animate', function
|
13
|
-
|
12
|
+
.directive('collapse', ['$animate', function($animate) {
|
14
13
|
return {
|
15
|
-
link: function
|
14
|
+
link: function(scope, element, attrs) {
|
16
15
|
function expand() {
|
17
16
|
element.removeClass('collapse')
|
18
17
|
.addClass('collapsing')
|
@@ -30,7 +29,7 @@ angular.module('ui.bootstrap.collapse', [])
|
|
30
29
|
}
|
31
30
|
|
32
31
|
function collapse() {
|
33
|
-
if(!
|
32
|
+
if (!element.hasClass('collapse') && !element.hasClass('in')) {
|
34
33
|
return collapseDone();
|
35
34
|
}
|
36
35
|
|
@@ -57,7 +56,7 @@ angular.module('ui.bootstrap.collapse', [])
|
|
57
56
|
element.addClass('collapse');
|
58
57
|
}
|
59
58
|
|
60
|
-
scope.$watch(attrs.collapse, function
|
59
|
+
scope.$watch(attrs.collapse, function(shouldCollapse) {
|
61
60
|
if (shouldCollapse) {
|
62
61
|
collapse();
|
63
62
|
} else {
|
@@ -74,17 +73,17 @@ angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
|
|
74
73
|
closeOthers: true
|
75
74
|
})
|
76
75
|
|
77
|
-
.controller('AccordionController', ['$scope', '$attrs', 'accordionConfig', function
|
78
|
-
|
76
|
+
.controller('AccordionController', ['$scope', '$attrs', 'accordionConfig', function($scope, $attrs, accordionConfig) {
|
79
77
|
// This array keeps track of the accordion groups
|
80
78
|
this.groups = [];
|
81
79
|
|
82
80
|
// Ensure that all the groups in this accordion are closed, unless close-others explicitly says not to
|
83
81
|
this.closeOthers = function(openGroup) {
|
84
|
-
var closeOthers = angular.isDefined($attrs.closeOthers) ?
|
85
|
-
|
86
|
-
|
87
|
-
|
82
|
+
var closeOthers = angular.isDefined($attrs.closeOthers) ?
|
83
|
+
$scope.$eval($attrs.closeOthers) : accordionConfig.closeOthers;
|
84
|
+
if (closeOthers) {
|
85
|
+
angular.forEach(this.groups, function(group) {
|
86
|
+
if (group !== openGroup) {
|
88
87
|
group.isOpen = false;
|
89
88
|
}
|
90
89
|
});
|
@@ -96,7 +95,7 @@ angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
|
|
96
95
|
var that = this;
|
97
96
|
this.groups.push(groupScope);
|
98
97
|
|
99
|
-
groupScope.$on('$destroy', function
|
98
|
+
groupScope.$on('$destroy', function(event) {
|
100
99
|
that.removeGroup(groupScope);
|
101
100
|
});
|
102
101
|
};
|
@@ -104,7 +103,7 @@ angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
|
|
104
103
|
// This is called from the accordion-group directive when to remove itself
|
105
104
|
this.removeGroup = function(group) {
|
106
105
|
var index = this.groups.indexOf(group);
|
107
|
-
if (
|
106
|
+
if (index !== -1) {
|
108
107
|
this.groups.splice(index, 1);
|
109
108
|
}
|
110
109
|
};
|
@@ -113,7 +112,7 @@ angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
|
|
113
112
|
|
114
113
|
// The accordion directive simply sets up the directive controller
|
115
114
|
// and adds an accordion CSS class to itself element.
|
116
|
-
.directive('accordion', function
|
115
|
+
.directive('accordion', function() {
|
117
116
|
return {
|
118
117
|
restrict: 'EA',
|
119
118
|
controller: 'AccordionController',
|
@@ -129,9 +128,9 @@ angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
|
|
129
128
|
// The accordion-group directive indicates a block of html that will expand and collapse in an accordion
|
130
129
|
.directive('accordionGroup', function() {
|
131
130
|
return {
|
132
|
-
require:'^accordion', // We need this directive to be inside an accordion
|
133
|
-
restrict:'EA',
|
134
|
-
transclude:true, // It transcludes the contents of the directive into the template
|
131
|
+
require: '^accordion', // We need this directive to be inside an accordion
|
132
|
+
restrict: 'EA',
|
133
|
+
transclude: true, // It transcludes the contents of the directive into the template
|
135
134
|
replace: true, // The element containing the directive will be replaced with the template
|
136
135
|
templateUrl: function(element, attrs) {
|
137
136
|
return attrs.templateUrl || 'template/accordion/accordion-group.html';
|
@@ -149,15 +148,20 @@ angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
|
|
149
148
|
link: function(scope, element, attrs, accordionCtrl) {
|
150
149
|
accordionCtrl.addGroup(scope);
|
151
150
|
|
151
|
+
scope.openClass = attrs.openClass || 'panel-open';
|
152
|
+
scope.panelClass = attrs.panelClass;
|
152
153
|
scope.$watch('isOpen', function(value) {
|
153
|
-
|
154
|
+
element.toggleClass(scope.openClass, value);
|
155
|
+
if (value) {
|
154
156
|
accordionCtrl.closeOthers(scope);
|
155
157
|
}
|
156
158
|
});
|
157
159
|
|
158
|
-
scope.toggleOpen = function() {
|
159
|
-
if (
|
160
|
-
|
160
|
+
scope.toggleOpen = function($event) {
|
161
|
+
if (!scope.isDisabled) {
|
162
|
+
if (!$event || $event.which === 32) {
|
163
|
+
scope.isOpen = !scope.isOpen;
|
164
|
+
}
|
161
165
|
}
|
162
166
|
};
|
163
167
|
}
|
@@ -195,7 +199,7 @@ angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
|
|
195
199
|
require: '^accordionGroup',
|
196
200
|
link: function(scope, element, attr, controller) {
|
197
201
|
scope.$watch(function() { return controller[attr.accordionTransclude]; }, function(heading) {
|
198
|
-
if (
|
202
|
+
if (heading) {
|
199
203
|
element.find('span').html('');
|
200
204
|
element.find('span').append(heading);
|
201
205
|
}
|
@@ -208,14 +212,13 @@ angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
|
|
208
212
|
|
209
213
|
angular.module('ui.bootstrap.alert', [])
|
210
214
|
|
211
|
-
.controller('AlertController', ['$scope', '$attrs', function
|
215
|
+
.controller('AlertController', ['$scope', '$attrs', function($scope, $attrs) {
|
212
216
|
$scope.closeable = !!$attrs.close;
|
213
217
|
this.close = $scope.close;
|
214
218
|
}])
|
215
219
|
|
216
|
-
.directive('alert', function
|
220
|
+
.directive('alert', function() {
|
217
221
|
return {
|
218
|
-
restrict: 'EA',
|
219
222
|
controller: 'AlertController',
|
220
223
|
controllerAs: 'alert',
|
221
224
|
templateUrl: function(element, attrs) {
|
@@ -234,7 +237,7 @@ angular.module('ui.bootstrap.alert', [])
|
|
234
237
|
return {
|
235
238
|
require: 'alert',
|
236
239
|
link: function(scope, element, attrs, alertCtrl) {
|
237
|
-
$timeout(function(){
|
240
|
+
$timeout(function() {
|
238
241
|
alertCtrl.close();
|
239
242
|
}, parseInt(attrs.dismissOnTimeout, 10));
|
240
243
|
}
|
@@ -268,21 +271,23 @@ angular.module('ui.bootstrap.buttons', [])
|
|
268
271
|
this.toggleEvent = buttonConfig.toggleEvent || 'click';
|
269
272
|
}])
|
270
273
|
|
271
|
-
.directive('btnRadio', function
|
274
|
+
.directive('btnRadio', function() {
|
272
275
|
return {
|
273
276
|
require: ['btnRadio', 'ngModel'],
|
274
277
|
controller: 'ButtonsController',
|
275
278
|
controllerAs: 'buttons',
|
276
|
-
link: function
|
279
|
+
link: function(scope, element, attrs, ctrls) {
|
277
280
|
var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1];
|
278
281
|
|
282
|
+
element.find('input').css({display: 'none'});
|
283
|
+
|
279
284
|
//model -> UI
|
280
|
-
ngModelCtrl.$render = function
|
285
|
+
ngModelCtrl.$render = function() {
|
281
286
|
element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.btnRadio)));
|
282
287
|
};
|
283
288
|
|
284
289
|
//ui->model
|
285
|
-
element.bind(buttonsCtrl.toggleEvent, function
|
290
|
+
element.bind(buttonsCtrl.toggleEvent, function() {
|
286
291
|
if (attrs.disabled) {
|
287
292
|
return;
|
288
293
|
}
|
@@ -290,7 +295,7 @@ angular.module('ui.bootstrap.buttons', [])
|
|
290
295
|
var isActive = element.hasClass(buttonsCtrl.activeClass);
|
291
296
|
|
292
297
|
if (!isActive || angular.isDefined(attrs.uncheckable)) {
|
293
|
-
scope.$apply(function
|
298
|
+
scope.$apply(function() {
|
294
299
|
ngModelCtrl.$setViewValue(isActive ? null : scope.$eval(attrs.btnRadio));
|
295
300
|
ngModelCtrl.$render();
|
296
301
|
});
|
@@ -300,14 +305,16 @@ angular.module('ui.bootstrap.buttons', [])
|
|
300
305
|
};
|
301
306
|
})
|
302
307
|
|
303
|
-
.directive('btnCheckbox', function
|
308
|
+
.directive('btnCheckbox', ['$document', function($document) {
|
304
309
|
return {
|
305
310
|
require: ['btnCheckbox', 'ngModel'],
|
306
311
|
controller: 'ButtonsController',
|
307
312
|
controllerAs: 'button',
|
308
|
-
link: function
|
313
|
+
link: function(scope, element, attrs, ctrls) {
|
309
314
|
var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1];
|
310
315
|
|
316
|
+
element.find('input').css({display: 'none'});
|
317
|
+
|
311
318
|
function getTrueValue() {
|
312
319
|
return getCheckboxValue(attrs.btnCheckboxTrue, true);
|
313
320
|
}
|
@@ -322,24 +329,36 @@ angular.module('ui.bootstrap.buttons', [])
|
|
322
329
|
}
|
323
330
|
|
324
331
|
//model -> UI
|
325
|
-
ngModelCtrl.$render = function
|
332
|
+
ngModelCtrl.$render = function() {
|
326
333
|
element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, getTrueValue()));
|
327
334
|
};
|
328
335
|
|
329
336
|
//ui->model
|
330
|
-
element.bind(buttonsCtrl.toggleEvent, function
|
337
|
+
element.bind(buttonsCtrl.toggleEvent, function() {
|
331
338
|
if (attrs.disabled) {
|
332
339
|
return;
|
333
340
|
}
|
334
341
|
|
335
|
-
scope.$apply(function
|
342
|
+
scope.$apply(function() {
|
343
|
+
ngModelCtrl.$setViewValue(element.hasClass(buttonsCtrl.activeClass) ? getFalseValue() : getTrueValue());
|
344
|
+
ngModelCtrl.$render();
|
345
|
+
});
|
346
|
+
});
|
347
|
+
|
348
|
+
//accessibility
|
349
|
+
element.on('keypress', function(e) {
|
350
|
+
if (attrs.disabled || e.which !== 32 || $document[0].activeElement !== element[0]) {
|
351
|
+
return;
|
352
|
+
}
|
353
|
+
|
354
|
+
scope.$apply(function() {
|
336
355
|
ngModelCtrl.$setViewValue(element.hasClass(buttonsCtrl.activeClass) ? getFalseValue() : getTrueValue());
|
337
356
|
ngModelCtrl.$render();
|
338
357
|
});
|
339
358
|
});
|
340
359
|
}
|
341
360
|
};
|
342
|
-
});
|
361
|
+
}]);
|
343
362
|
|
344
363
|
/**
|
345
364
|
* @ngdoc overview
|
@@ -535,7 +554,7 @@ angular.module('ui.bootstrap.carousel', [])
|
|
535
554
|
} else if (currentIndex > index) {
|
536
555
|
currentIndex--;
|
537
556
|
}
|
538
|
-
|
557
|
+
|
539
558
|
//clean the currentSlide when no more slide
|
540
559
|
if (slides.length === 0) {
|
541
560
|
self.currentSlide = null;
|
@@ -659,6 +678,7 @@ function CarouselDemoCtrl($scope) {
|
|
659
678
|
},
|
660
679
|
scope: {
|
661
680
|
active: '=?',
|
681
|
+
actual: '=?',
|
662
682
|
index: '=?'
|
663
683
|
},
|
664
684
|
link: function (scope, element, attrs, carouselCtrl) {
|
@@ -823,6 +843,10 @@ angular.module('ui.bootstrap.dateparser', [])
|
|
823
843
|
regex: '1?[0-9]|2[0-3]',
|
824
844
|
apply: function(value) { this.hours = +value; }
|
825
845
|
},
|
846
|
+
'h': {
|
847
|
+
regex: '[0-9]|1[0-2]',
|
848
|
+
apply: function(value) { this.hours = +value; }
|
849
|
+
},
|
826
850
|
'mm': {
|
827
851
|
regex: '[0-5][0-9]',
|
828
852
|
apply: function(value) { this.minutes = +value; }
|
@@ -885,14 +909,14 @@ angular.module('ui.bootstrap.dateparser', [])
|
|
885
909
|
}
|
886
910
|
|
887
911
|
this.parse = function(input, format, baseDate) {
|
888
|
-
if (
|
912
|
+
if (!angular.isString(input) || !format) {
|
889
913
|
return input;
|
890
914
|
}
|
891
915
|
|
892
916
|
format = $locale.DATETIME_FORMATS[format] || format;
|
893
917
|
format = format.replace(SPECIAL_CHARACTERS_REGEXP, '\\$&');
|
894
918
|
|
895
|
-
if (
|
919
|
+
if (!this.parsers[format]) {
|
896
920
|
this.parsers[format] = createParser(format);
|
897
921
|
}
|
898
922
|
|
@@ -901,7 +925,7 @@ angular.module('ui.bootstrap.dateparser', [])
|
|
901
925
|
map = parser.map,
|
902
926
|
results = input.match(regex);
|
903
927
|
|
904
|
-
if (
|
928
|
+
if (results && results.length) {
|
905
929
|
var fields, dt;
|
906
930
|
if (angular.isDate(baseDate) && !isNaN(baseDate.getTime())) {
|
907
931
|
fields = {
|
@@ -920,15 +944,16 @@ angular.module('ui.bootstrap.dateparser', [])
|
|
920
944
|
fields = { year: 1900, month: 0, date: 1, hours: 0, minutes: 0, seconds: 0, milliseconds: 0 };
|
921
945
|
}
|
922
946
|
|
923
|
-
for(
|
947
|
+
for (var i = 1, n = results.length; i < n; i++) {
|
924
948
|
var mapper = map[i-1];
|
925
|
-
if (
|
949
|
+
if (mapper.apply) {
|
926
950
|
mapper.apply.call(fields, results[i]);
|
927
951
|
}
|
928
952
|
}
|
929
953
|
|
930
|
-
if (
|
931
|
-
dt = new Date(fields.year, fields.month, fields.date,
|
954
|
+
if (isValid(fields.year, fields.month, fields.date)) {
|
955
|
+
dt = new Date(fields.year, fields.month, fields.date,
|
956
|
+
fields.hours, fields.minutes, fields.seconds,
|
932
957
|
fields.milliseconds || 0);
|
933
958
|
}
|
934
959
|
|
@@ -943,12 +968,12 @@ angular.module('ui.bootstrap.dateparser', [])
|
|
943
968
|
return false;
|
944
969
|
}
|
945
970
|
|
946
|
-
if (
|
947
|
-
|
971
|
+
if (month === 1 && date > 28) {
|
972
|
+
return date === 29 && ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0);
|
948
973
|
}
|
949
974
|
|
950
|
-
if (
|
951
|
-
|
975
|
+
if (month === 3 || month === 5 || month === 8 || month === 10) {
|
976
|
+
return date < 31;
|
952
977
|
}
|
953
978
|
|
954
979
|
return true;
|
@@ -963,8 +988,7 @@ angular.module('ui.bootstrap.position', [])
|
|
963
988
|
* relation to other, existing elements (this is the case for tooltips, popovers,
|
964
989
|
* typeahead suggestions etc.).
|
965
990
|
*/
|
966
|
-
.factory('$position', ['$document', '$window', function
|
967
|
-
|
991
|
+
.factory('$position', ['$document', '$window', function($document, $window) {
|
968
992
|
function getStyle(el, cssprop) {
|
969
993
|
if (el.currentStyle) { //IE
|
970
994
|
return el.currentStyle[cssprop];
|
@@ -987,7 +1011,7 @@ angular.module('ui.bootstrap.position', [])
|
|
987
1011
|
* returns the closest, non-statically positioned parentOffset of a given element
|
988
1012
|
* @param element
|
989
1013
|
*/
|
990
|
-
var parentOffsetEl = function
|
1014
|
+
var parentOffsetEl = function(element) {
|
991
1015
|
var docDomEl = $document[0];
|
992
1016
|
var offsetParent = element.offsetParent || docDomEl;
|
993
1017
|
while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent) ) {
|
@@ -1001,7 +1025,7 @@ angular.module('ui.bootstrap.position', [])
|
|
1001
1025
|
* Provides read-only equivalent of jQuery's position function:
|
1002
1026
|
* http://api.jquery.com/position/
|
1003
1027
|
*/
|
1004
|
-
position: function
|
1028
|
+
position: function(element) {
|
1005
1029
|
var elBCR = this.offset(element);
|
1006
1030
|
var offsetParentBCR = { top: 0, left: 0 };
|
1007
1031
|
var offsetParentEl = parentOffsetEl(element[0]);
|
@@ -1024,7 +1048,7 @@ angular.module('ui.bootstrap.position', [])
|
|
1024
1048
|
* Provides read-only equivalent of jQuery's offset function:
|
1025
1049
|
* http://api.jquery.com/offset/
|
1026
1050
|
*/
|
1027
|
-
offset: function
|
1051
|
+
offset: function(element) {
|
1028
1052
|
var boundingClientRect = element[0].getBoundingClientRect();
|
1029
1053
|
return {
|
1030
1054
|
width: boundingClientRect.width || element.prop('offsetWidth'),
|
@@ -1037,8 +1061,7 @@ angular.module('ui.bootstrap.position', [])
|
|
1037
1061
|
/**
|
1038
1062
|
* Provides coordinates for the targetEl in relation to hostEl
|
1039
1063
|
*/
|
1040
|
-
positionElements: function
|
1041
|
-
|
1064
|
+
positionElements: function(hostEl, targetEl, positionStr, appendToBody) {
|
1042
1065
|
var positionStrParts = positionStr.split('-');
|
1043
1066
|
var pos0 = positionStrParts[0], pos1 = positionStrParts[1] || 'center';
|
1044
1067
|
|
@@ -1053,25 +1076,25 @@ angular.module('ui.bootstrap.position', [])
|
|
1053
1076
|
targetElHeight = targetEl.prop('offsetHeight');
|
1054
1077
|
|
1055
1078
|
var shiftWidth = {
|
1056
|
-
center: function
|
1079
|
+
center: function() {
|
1057
1080
|
return hostElPos.left + hostElPos.width / 2 - targetElWidth / 2;
|
1058
1081
|
},
|
1059
|
-
left: function
|
1082
|
+
left: function() {
|
1060
1083
|
return hostElPos.left;
|
1061
1084
|
},
|
1062
|
-
right: function
|
1085
|
+
right: function() {
|
1063
1086
|
return hostElPos.left + hostElPos.width;
|
1064
1087
|
}
|
1065
1088
|
};
|
1066
1089
|
|
1067
1090
|
var shiftHeight = {
|
1068
|
-
center: function
|
1091
|
+
center: function() {
|
1069
1092
|
return hostElPos.top + hostElPos.height / 2 - targetElHeight / 2;
|
1070
1093
|
},
|
1071
|
-
top: function
|
1094
|
+
top: function() {
|
1072
1095
|
return hostElPos.top;
|
1073
1096
|
},
|
1074
|
-
bottom: function
|
1097
|
+
bottom: function() {
|
1075
1098
|
return hostElPos.top + hostElPos.height;
|
1076
1099
|
}
|
1077
1100
|
};
|
@@ -1139,13 +1162,13 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
|
|
1139
1162
|
|
1140
1163
|
// Configuration attributes
|
1141
1164
|
angular.forEach(['formatDay', 'formatMonth', 'formatYear', 'formatDayHeader', 'formatDayTitle', 'formatMonthTitle',
|
1142
|
-
'showWeeks', 'startingDay', 'yearRange', 'shortcutPropagation'], function(
|
1165
|
+
'showWeeks', 'startingDay', 'yearRange', 'shortcutPropagation'], function(key, index) {
|
1143
1166
|
self[key] = angular.isDefined($attrs[key]) ? (index < 6 ? $interpolate($attrs[key])($scope.$parent) : $scope.$parent.$eval($attrs[key])) : datepickerConfig[key];
|
1144
1167
|
});
|
1145
1168
|
|
1146
1169
|
// Watchable date attributes
|
1147
|
-
angular.forEach(['minDate', 'maxDate'], function(
|
1148
|
-
if (
|
1170
|
+
angular.forEach(['minDate', 'maxDate'], function(key) {
|
1171
|
+
if ($attrs[key]) {
|
1149
1172
|
$scope.$parent.$watch($parse($attrs[key]), function(value) {
|
1150
1173
|
self[key] = value ? new Date(value) : null;
|
1151
1174
|
self.refreshView();
|
@@ -1155,12 +1178,12 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
|
|
1155
1178
|
}
|
1156
1179
|
});
|
1157
1180
|
|
1158
|
-
angular.forEach(['minMode', 'maxMode'], function(
|
1159
|
-
if (
|
1181
|
+
angular.forEach(['minMode', 'maxMode'], function(key) {
|
1182
|
+
if ($attrs[key]) {
|
1160
1183
|
$scope.$parent.$watch($parse($attrs[key]), function(value) {
|
1161
1184
|
self[key] = angular.isDefined(value) ? value : $attrs[key];
|
1162
1185
|
$scope[key] = self[key];
|
1163
|
-
if ((key == 'minMode' && self.modes.indexOf(
|
1186
|
+
if ((key == 'minMode' && self.modes.indexOf($scope.datepickerMode) < self.modes.indexOf(self[key])) || (key == 'maxMode' && self.modes.indexOf($scope.datepickerMode) > self.modes.indexOf(self[key]))) {
|
1164
1187
|
$scope.datepickerMode = self[key];
|
1165
1188
|
}
|
1166
1189
|
});
|
@@ -1173,16 +1196,16 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
|
|
1173
1196
|
$scope.datepickerMode = $scope.datepickerMode || datepickerConfig.datepickerMode;
|
1174
1197
|
$scope.uniqueId = 'datepicker-' + $scope.$id + '-' + Math.floor(Math.random() * 10000);
|
1175
1198
|
|
1176
|
-
if(angular.isDefined($attrs.initDate)) {
|
1199
|
+
if (angular.isDefined($attrs.initDate)) {
|
1177
1200
|
this.activeDate = $scope.$parent.$eval($attrs.initDate) || new Date();
|
1178
|
-
$scope.$parent.$watch($attrs.initDate, function(initDate){
|
1179
|
-
if(initDate && (ngModelCtrl.$isEmpty(ngModelCtrl.$modelValue) || ngModelCtrl.$invalid)){
|
1201
|
+
$scope.$parent.$watch($attrs.initDate, function(initDate) {
|
1202
|
+
if (initDate && (ngModelCtrl.$isEmpty(ngModelCtrl.$modelValue) || ngModelCtrl.$invalid)) {
|
1180
1203
|
self.activeDate = initDate;
|
1181
1204
|
self.refreshView();
|
1182
1205
|
}
|
1183
1206
|
});
|
1184
1207
|
} else {
|
1185
|
-
this.activeDate =
|
1208
|
+
this.activeDate = new Date();
|
1186
1209
|
}
|
1187
1210
|
|
1188
1211
|
$scope.isActive = function(dateObject) {
|
@@ -1193,7 +1216,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
|
|
1193
1216
|
return false;
|
1194
1217
|
};
|
1195
1218
|
|
1196
|
-
this.init = function(
|
1219
|
+
this.init = function(ngModelCtrl_) {
|
1197
1220
|
ngModelCtrl = ngModelCtrl_;
|
1198
1221
|
|
1199
1222
|
ngModelCtrl.$render = function() {
|
@@ -1202,13 +1225,13 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
|
|
1202
1225
|
};
|
1203
1226
|
|
1204
1227
|
this.render = function() {
|
1205
|
-
if (
|
1206
|
-
var date = new Date(
|
1228
|
+
if (ngModelCtrl.$viewValue) {
|
1229
|
+
var date = new Date(ngModelCtrl.$viewValue),
|
1207
1230
|
isValid = !isNaN(date);
|
1208
1231
|
|
1209
|
-
if (
|
1232
|
+
if (isValid) {
|
1210
1233
|
this.activeDate = date;
|
1211
|
-
} else if (
|
1234
|
+
} else if (!$datepickerSuppressError) {
|
1212
1235
|
$log.error('Datepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.');
|
1213
1236
|
}
|
1214
1237
|
}
|
@@ -1216,7 +1239,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
|
|
1216
1239
|
};
|
1217
1240
|
|
1218
1241
|
this.refreshView = function() {
|
1219
|
-
if (
|
1242
|
+
if (this.element) {
|
1220
1243
|
this._refreshView();
|
1221
1244
|
|
1222
1245
|
var date = ngModelCtrl.$viewValue ? new Date(ngModelCtrl.$viewValue) : null;
|
@@ -1236,11 +1259,11 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
|
|
1236
1259
|
};
|
1237
1260
|
};
|
1238
1261
|
|
1239
|
-
this.isDisabled = function(
|
1262
|
+
this.isDisabled = function(date) {
|
1240
1263
|
return ((this.minDate && this.compare(date, this.minDate) < 0) || (this.maxDate && this.compare(date, this.maxDate) > 0) || ($attrs.dateDisabled && $scope.dateDisabled({date: date, mode: $scope.datepickerMode})));
|
1241
1264
|
};
|
1242
1265
|
|
1243
|
-
this.customClass = function(
|
1266
|
+
this.customClass = function(date) {
|
1244
1267
|
return $scope.customClass({date: date, mode: $scope.datepickerMode});
|
1245
1268
|
};
|
1246
1269
|
|
@@ -1264,37 +1287,37 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
|
|
1264
1287
|
date.setHours(hours === 23 ? hours + 2 : 0);
|
1265
1288
|
};
|
1266
1289
|
|
1267
|
-
$scope.select = function(
|
1268
|
-
if (
|
1269
|
-
var dt = ngModelCtrl.$viewValue ? new Date(
|
1270
|
-
dt.setFullYear(
|
1271
|
-
ngModelCtrl.$setViewValue(
|
1290
|
+
$scope.select = function(date) {
|
1291
|
+
if ($scope.datepickerMode === self.minMode) {
|
1292
|
+
var dt = ngModelCtrl.$viewValue ? new Date(ngModelCtrl.$viewValue) : new Date(0, 0, 0, 0, 0, 0, 0);
|
1293
|
+
dt.setFullYear(date.getFullYear(), date.getMonth(), date.getDate());
|
1294
|
+
ngModelCtrl.$setViewValue(dt);
|
1272
1295
|
ngModelCtrl.$render();
|
1273
1296
|
} else {
|
1274
1297
|
self.activeDate = date;
|
1275
|
-
$scope.datepickerMode = self.modes[
|
1298
|
+
$scope.datepickerMode = self.modes[self.modes.indexOf($scope.datepickerMode) - 1];
|
1276
1299
|
}
|
1277
1300
|
};
|
1278
1301
|
|
1279
|
-
$scope.move = function(
|
1302
|
+
$scope.move = function(direction) {
|
1280
1303
|
var year = self.activeDate.getFullYear() + direction * (self.step.years || 0),
|
1281
1304
|
month = self.activeDate.getMonth() + direction * (self.step.months || 0);
|
1282
1305
|
self.activeDate.setFullYear(year, month, 1);
|
1283
1306
|
self.refreshView();
|
1284
1307
|
};
|
1285
1308
|
|
1286
|
-
$scope.toggleMode = function(
|
1309
|
+
$scope.toggleMode = function(direction) {
|
1287
1310
|
direction = direction || 1;
|
1288
1311
|
|
1289
1312
|
if (($scope.datepickerMode === self.maxMode && direction === 1) || ($scope.datepickerMode === self.minMode && direction === -1)) {
|
1290
1313
|
return;
|
1291
1314
|
}
|
1292
1315
|
|
1293
|
-
$scope.datepickerMode = self.modes[
|
1316
|
+
$scope.datepickerMode = self.modes[self.modes.indexOf($scope.datepickerMode) + direction];
|
1294
1317
|
};
|
1295
1318
|
|
1296
1319
|
// Key event mapper
|
1297
|
-
$scope.keys = { 13:'enter', 32:'space', 33:'pageup', 34:'pagedown', 35:'end', 36:'home', 37:'left', 38:'up', 39:'right', 40:'down' };
|
1320
|
+
$scope.keys = { 13: 'enter', 32: 'space', 33: 'pageup', 34: 'pagedown', 35: 'end', 36: 'home', 37: 'left', 38: 'up', 39: 'right', 40: 'down' };
|
1298
1321
|
|
1299
1322
|
var focusElement = function() {
|
1300
1323
|
self.element[0].focus();
|
@@ -1303,20 +1326,20 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
|
|
1303
1326
|
// Listen for focus requests from popup directive
|
1304
1327
|
$scope.$on('datepicker.focus', focusElement);
|
1305
1328
|
|
1306
|
-
$scope.keydown = function(
|
1329
|
+
$scope.keydown = function(evt) {
|
1307
1330
|
var key = $scope.keys[evt.which];
|
1308
1331
|
|
1309
|
-
if (
|
1332
|
+
if (!key || evt.shiftKey || evt.altKey) {
|
1310
1333
|
return;
|
1311
1334
|
}
|
1312
1335
|
|
1313
1336
|
evt.preventDefault();
|
1314
|
-
if(!self.shortcutPropagation){
|
1315
|
-
|
1337
|
+
if (!self.shortcutPropagation) {
|
1338
|
+
evt.stopPropagation();
|
1316
1339
|
}
|
1317
1340
|
|
1318
1341
|
if (key === 'enter' || key === 'space') {
|
1319
|
-
if (
|
1342
|
+
if (self.isDisabled(self.activeDate)) {
|
1320
1343
|
return; // do nothing
|
1321
1344
|
}
|
1322
1345
|
$scope.select(self.activeDate);
|
@@ -1331,7 +1354,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
|
|
1331
1354
|
};
|
1332
1355
|
}])
|
1333
1356
|
|
1334
|
-
.directive(
|
1357
|
+
.directive('datepicker', function() {
|
1335
1358
|
return {
|
1336
1359
|
restrict: 'EA',
|
1337
1360
|
replace: true,
|
@@ -1355,7 +1378,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
|
|
1355
1378
|
};
|
1356
1379
|
})
|
1357
1380
|
|
1358
|
-
.directive('daypicker', ['dateFilter', function
|
1381
|
+
.directive('daypicker', ['dateFilter', function(dateFilter) {
|
1359
1382
|
return {
|
1360
1383
|
restrict: 'EA',
|
1361
1384
|
replace: true,
|
@@ -1368,17 +1391,17 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
|
|
1368
1391
|
ctrl.element = element;
|
1369
1392
|
|
1370
1393
|
var DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
1371
|
-
function getDaysInMonth(
|
1394
|
+
function getDaysInMonth(year, month) {
|
1372
1395
|
return ((month === 1) && (year % 4 === 0) && ((year % 100 !== 0) || (year % 400 === 0))) ? 29 : DAYS_IN_MONTH[month];
|
1373
1396
|
}
|
1374
1397
|
|
1375
1398
|
function getDates(startDate, n) {
|
1376
1399
|
var dates = new Array(n), current = new Date(startDate), i = 0, date;
|
1377
|
-
while (
|
1400
|
+
while (i < n) {
|
1378
1401
|
date = new Date(current);
|
1379
1402
|
ctrl.fixTimeZone(date);
|
1380
1403
|
dates[i++] = date;
|
1381
|
-
current.setDate(
|
1404
|
+
current.setDate(current.getDate() + 1);
|
1382
1405
|
}
|
1383
1406
|
return dates;
|
1384
1407
|
}
|
@@ -1391,8 +1414,8 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
|
|
1391
1414
|
numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : - difference,
|
1392
1415
|
firstDate = new Date(firstDayOfMonth);
|
1393
1416
|
|
1394
|
-
if (
|
1395
|
-
firstDate.setDate(
|
1417
|
+
if (numDisplayedFromPreviousMonth > 0) {
|
1418
|
+
firstDate.setDate(-numDisplayedFromPreviousMonth + 1);
|
1396
1419
|
}
|
1397
1420
|
|
1398
1421
|
// 42 is the number of days on a six-month calendar
|
@@ -1415,19 +1438,19 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
|
|
1415
1438
|
scope.title = dateFilter(ctrl.activeDate, ctrl.formatDayTitle);
|
1416
1439
|
scope.rows = ctrl.split(days, 7);
|
1417
1440
|
|
1418
|
-
if (
|
1441
|
+
if (scope.showWeeks) {
|
1419
1442
|
scope.weekNumbers = [];
|
1420
1443
|
var thursdayIndex = (4 + 7 - ctrl.startingDay) % 7,
|
1421
1444
|
numWeeks = scope.rows.length;
|
1422
1445
|
for (var curWeek = 0; curWeek < numWeeks; curWeek++) {
|
1423
1446
|
scope.weekNumbers.push(
|
1424
|
-
getISO8601WeekNumber(
|
1447
|
+
getISO8601WeekNumber(scope.rows[curWeek][thursdayIndex].date));
|
1425
1448
|
}
|
1426
1449
|
}
|
1427
1450
|
};
|
1428
1451
|
|
1429
1452
|
ctrl.compare = function(date1, date2) {
|
1430
|
-
return (new Date(
|
1453
|
+
return (new Date(date1.getFullYear(), date1.getMonth(), date1.getDate()) - new Date(date2.getFullYear(), date2.getMonth(), date2.getDate()));
|
1431
1454
|
};
|
1432
1455
|
|
1433
1456
|
function getISO8601WeekNumber(date) {
|
@@ -1439,7 +1462,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
|
|
1439
1462
|
return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
|
1440
1463
|
}
|
1441
1464
|
|
1442
|
-
ctrl.handleKeyDown = function(
|
1465
|
+
ctrl.handleKeyDown = function(key, evt) {
|
1443
1466
|
var date = ctrl.activeDate.getDate();
|
1444
1467
|
|
1445
1468
|
if (key === 'left') {
|
@@ -1467,7 +1490,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
|
|
1467
1490
|
};
|
1468
1491
|
}])
|
1469
1492
|
|
1470
|
-
.directive('monthpicker', ['dateFilter', function
|
1493
|
+
.directive('monthpicker', ['dateFilter', function(dateFilter) {
|
1471
1494
|
return {
|
1472
1495
|
restrict: 'EA',
|
1473
1496
|
replace: true,
|
@@ -1482,7 +1505,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
|
|
1482
1505
|
year = ctrl.activeDate.getFullYear(),
|
1483
1506
|
date;
|
1484
1507
|
|
1485
|
-
for (
|
1508
|
+
for (var i = 0; i < 12; i++) {
|
1486
1509
|
date = new Date(year, i, 1);
|
1487
1510
|
ctrl.fixTimeZone(date);
|
1488
1511
|
months[i] = angular.extend(ctrl.createDateObject(date, ctrl.formatMonth), {
|
@@ -1495,10 +1518,10 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
|
|
1495
1518
|
};
|
1496
1519
|
|
1497
1520
|
ctrl.compare = function(date1, date2) {
|
1498
|
-
return new Date(
|
1521
|
+
return new Date(date1.getFullYear(), date1.getMonth()) - new Date(date2.getFullYear(), date2.getMonth());
|
1499
1522
|
};
|
1500
1523
|
|
1501
|
-
ctrl.handleKeyDown = function(
|
1524
|
+
ctrl.handleKeyDown = function(key, evt) {
|
1502
1525
|
var date = ctrl.activeDate.getMonth();
|
1503
1526
|
|
1504
1527
|
if (key === 'left') {
|
@@ -1525,7 +1548,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
|
|
1525
1548
|
};
|
1526
1549
|
}])
|
1527
1550
|
|
1528
|
-
.directive('yearpicker', ['dateFilter', function
|
1551
|
+
.directive('yearpicker', ['dateFilter', function(dateFilter) {
|
1529
1552
|
return {
|
1530
1553
|
restrict: 'EA',
|
1531
1554
|
replace: true,
|
@@ -1544,7 +1567,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
|
|
1544
1567
|
ctrl._refreshView = function() {
|
1545
1568
|
var years = new Array(range), date;
|
1546
1569
|
|
1547
|
-
for (
|
1570
|
+
for (var i = 0, start = getStartingYear(ctrl.activeDate.getFullYear()); i < range; i++) {
|
1548
1571
|
date = new Date(start + i, 0, 1);
|
1549
1572
|
ctrl.fixTimeZone(date);
|
1550
1573
|
years[i] = angular.extend(ctrl.createDateObject(date, ctrl.formatYear), {
|
@@ -1560,7 +1583,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
|
|
1560
1583
|
return date1.getFullYear() - date2.getFullYear();
|
1561
1584
|
};
|
1562
1585
|
|
1563
|
-
ctrl.handleKeyDown = function(
|
1586
|
+
ctrl.handleKeyDown = function(key, evt) {
|
1564
1587
|
var date = ctrl.activeDate.getFullYear();
|
1565
1588
|
|
1566
1589
|
if (key === 'left') {
|
@@ -1574,9 +1597,9 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
|
|
1574
1597
|
} else if (key === 'pageup' || key === 'pagedown') {
|
1575
1598
|
date += (key === 'pageup' ? - 1 : 1) * ctrl.step.years;
|
1576
1599
|
} else if (key === 'home') {
|
1577
|
-
date = getStartingYear(
|
1600
|
+
date = getStartingYear(ctrl.activeDate.getFullYear());
|
1578
1601
|
} else if (key === 'end') {
|
1579
|
-
date = getStartingYear(
|
1602
|
+
date = getStartingYear(ctrl.activeDate.getFullYear()) + range - 1;
|
1580
1603
|
}
|
1581
1604
|
ctrl.activeDate.setFullYear(date);
|
1582
1605
|
};
|
@@ -1605,7 +1628,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
|
|
1605
1628
|
})
|
1606
1629
|
|
1607
1630
|
.directive('datepickerPopup', ['$compile', '$parse', '$document', '$rootScope', '$position', 'dateFilter', 'dateParser', 'datepickerPopupConfig', '$timeout',
|
1608
|
-
function
|
1631
|
+
function($compile, $parse, $document, $rootScope, $position, dateFilter, dateParser, datepickerPopupConfig, $timeout) {
|
1609
1632
|
return {
|
1610
1633
|
restrict: 'EA',
|
1611
1634
|
require: 'ngModel',
|
@@ -1623,14 +1646,28 @@ function ($compile, $parse, $document, $rootScope, $position, dateFilter, datePa
|
|
1623
1646
|
appendToBody = angular.isDefined(attrs.datepickerAppendToBody) ? scope.$parent.$eval(attrs.datepickerAppendToBody) : datepickerPopupConfig.appendToBody,
|
1624
1647
|
onOpenFocus = angular.isDefined(attrs.onOpenFocus) ? scope.$parent.$eval(attrs.onOpenFocus) : datepickerPopupConfig.onOpenFocus,
|
1625
1648
|
datepickerPopupTemplateUrl = angular.isDefined(attrs.datepickerPopupTemplateUrl) ? attrs.datepickerPopupTemplateUrl : datepickerPopupConfig.datepickerPopupTemplateUrl,
|
1626
|
-
datepickerTemplateUrl = angular.isDefined(attrs.datepickerTemplateUrl) ? attrs.datepickerTemplateUrl : datepickerPopupConfig.datepickerTemplateUrl
|
1649
|
+
datepickerTemplateUrl = angular.isDefined(attrs.datepickerTemplateUrl) ? attrs.datepickerTemplateUrl : datepickerPopupConfig.datepickerTemplateUrl,
|
1650
|
+
cache = {};
|
1627
1651
|
|
1628
1652
|
scope.showButtonBar = angular.isDefined(attrs.showButtonBar) ? scope.$parent.$eval(attrs.showButtonBar) : datepickerPopupConfig.showButtonBar;
|
1629
1653
|
|
1630
|
-
scope.getText = function(
|
1654
|
+
scope.getText = function(key) {
|
1631
1655
|
return scope[key + 'Text'] || datepickerPopupConfig[key + 'Text'];
|
1632
1656
|
};
|
1633
1657
|
|
1658
|
+
scope.isDisabled = function(date) {
|
1659
|
+
if (date === 'today') {
|
1660
|
+
date = new Date();
|
1661
|
+
}
|
1662
|
+
|
1663
|
+
return ((scope.watchData.minDate && scope.compare(date, cache.minDate) < 0) ||
|
1664
|
+
(scope.watchData.maxDate && scope.compare(date, cache.maxDate) > 0));
|
1665
|
+
};
|
1666
|
+
|
1667
|
+
scope.compare = function(date1, date2) {
|
1668
|
+
return (new Date(date1.getFullYear(), date1.getMonth(), date1.getDate()) - new Date(date2.getFullYear(), date2.getMonth(), date2.getDate()));
|
1669
|
+
};
|
1670
|
+
|
1634
1671
|
var isHtml5DateInput = false;
|
1635
1672
|
if (datepickerPopupConfig.html5Types[attrs.type]) {
|
1636
1673
|
dateFormat = datepickerPopupConfig.html5Types[attrs.type];
|
@@ -1668,7 +1705,7 @@ function ($compile, $parse, $document, $rootScope, $position, dateFilter, datePa
|
|
1668
1705
|
'template-url': datepickerPopupTemplateUrl
|
1669
1706
|
});
|
1670
1707
|
|
1671
|
-
function cameltoDash(
|
1708
|
+
function cameltoDash(string) {
|
1672
1709
|
return string.replace(/([A-Z])/g, function($1) { return '-' + $1.toLowerCase(); });
|
1673
1710
|
}
|
1674
1711
|
|
@@ -1677,38 +1714,41 @@ function ($compile, $parse, $document, $rootScope, $position, dateFilter, datePa
|
|
1677
1714
|
datepickerEl.attr('template-url', datepickerTemplateUrl);
|
1678
1715
|
|
1679
1716
|
if (isHtml5DateInput) {
|
1680
|
-
if (attrs.type
|
1717
|
+
if (attrs.type === 'month') {
|
1681
1718
|
datepickerEl.attr('datepicker-mode', '"month"');
|
1682
1719
|
datepickerEl.attr('min-mode', 'month');
|
1683
1720
|
}
|
1684
1721
|
}
|
1685
1722
|
|
1686
|
-
if (
|
1723
|
+
if (attrs.datepickerOptions) {
|
1687
1724
|
var options = scope.$parent.$eval(attrs.datepickerOptions);
|
1688
|
-
if(options && options.initDate) {
|
1725
|
+
if (options && options.initDate) {
|
1689
1726
|
scope.initDate = options.initDate;
|
1690
|
-
datepickerEl.attr(
|
1727
|
+
datepickerEl.attr('init-date', 'initDate');
|
1691
1728
|
delete options.initDate;
|
1692
1729
|
}
|
1693
|
-
angular.forEach(options, function(
|
1730
|
+
angular.forEach(options, function(value, option) {
|
1694
1731
|
datepickerEl.attr( cameltoDash(option), value );
|
1695
1732
|
});
|
1696
1733
|
}
|
1697
1734
|
|
1698
1735
|
scope.watchData = {};
|
1699
|
-
angular.forEach(['minMode', 'maxMode', 'minDate', 'maxDate', 'datepickerMode', 'initDate', 'shortcutPropagation'], function(
|
1700
|
-
if (
|
1736
|
+
angular.forEach(['minMode', 'maxMode', 'minDate', 'maxDate', 'datepickerMode', 'initDate', 'shortcutPropagation'], function(key) {
|
1737
|
+
if (attrs[key]) {
|
1701
1738
|
var getAttribute = $parse(attrs[key]);
|
1702
|
-
scope.$parent.$watch(getAttribute, function(value){
|
1739
|
+
scope.$parent.$watch(getAttribute, function(value) {
|
1703
1740
|
scope.watchData[key] = value;
|
1741
|
+
if (key === 'minDate' || key === 'maxDate') {
|
1742
|
+
cache[key] = new Date(value);
|
1743
|
+
}
|
1704
1744
|
});
|
1705
1745
|
datepickerEl.attr(cameltoDash(key), 'watchData.' + key);
|
1706
1746
|
|
1707
1747
|
// Propagate changes from datepicker to outside
|
1708
|
-
if (
|
1748
|
+
if (key === 'datepickerMode') {
|
1709
1749
|
var setAttribute = getAttribute.assign;
|
1710
1750
|
scope.$watch('watchData.' + key, function(value, oldvalue) {
|
1711
|
-
if (
|
1751
|
+
if (angular.isFunction(setAttribute) && value !== oldvalue) {
|
1712
1752
|
setAttribute(scope.$parent, value);
|
1713
1753
|
}
|
1714
1754
|
});
|
@@ -1723,7 +1763,7 @@ function ($compile, $parse, $document, $rootScope, $position, dateFilter, datePa
|
|
1723
1763
|
datepickerEl.attr('show-weeks', attrs.showWeeks);
|
1724
1764
|
}
|
1725
1765
|
|
1726
|
-
if (attrs.customClass){
|
1766
|
+
if (attrs.customClass) {
|
1727
1767
|
datepickerEl.attr('custom-class', 'customClass({ date: date, mode: mode })');
|
1728
1768
|
}
|
1729
1769
|
|
@@ -1776,13 +1816,12 @@ function ($compile, $parse, $document, $rootScope, $position, dateFilter, datePa
|
|
1776
1816
|
ngModel.$$parserName = 'date';
|
1777
1817
|
ngModel.$validators.date = validator;
|
1778
1818
|
ngModel.$parsers.unshift(parseDate);
|
1779
|
-
ngModel.$formatters.push(function
|
1819
|
+
ngModel.$formatters.push(function(value) {
|
1780
1820
|
scope.date = value;
|
1781
1821
|
return ngModel.$isEmpty(value) ? value : dateFilter(value, dateFormat);
|
1782
1822
|
});
|
1783
|
-
}
|
1784
|
-
|
1785
|
-
ngModel.$formatters.push(function (value) {
|
1823
|
+
} else {
|
1824
|
+
ngModel.$formatters.push(function(value) {
|
1786
1825
|
scope.date = value;
|
1787
1826
|
return value;
|
1788
1827
|
});
|
@@ -1797,19 +1836,19 @@ function ($compile, $parse, $document, $rootScope, $position, dateFilter, datePa
|
|
1797
1836
|
element.val(date);
|
1798
1837
|
ngModel.$setViewValue(date);
|
1799
1838
|
|
1800
|
-
if (
|
1839
|
+
if (closeOnDateSelection) {
|
1801
1840
|
scope.isOpen = false;
|
1802
1841
|
element[0].focus();
|
1803
1842
|
}
|
1804
1843
|
};
|
1805
1844
|
|
1806
1845
|
// Detect changes in the view from the text box
|
1807
|
-
ngModel.$viewChangeListeners.push(function
|
1846
|
+
ngModel.$viewChangeListeners.push(function() {
|
1808
1847
|
scope.date = dateParser.parse(ngModel.$viewValue, dateFormat, scope.date);
|
1809
1848
|
});
|
1810
1849
|
|
1811
1850
|
var documentClickBind = function(event) {
|
1812
|
-
if (scope.isOpen && !element[0].contains(event.target)) {
|
1851
|
+
if (scope.isOpen && !(element[0].contains(event.target) || popupEl[0].contains(event.target))) {
|
1813
1852
|
scope.$apply(function() {
|
1814
1853
|
scope.isOpen = false;
|
1815
1854
|
});
|
@@ -1857,7 +1896,7 @@ function ($compile, $parse, $document, $rootScope, $position, dateFilter, datePa
|
|
1857
1896
|
}
|
1858
1897
|
});
|
1859
1898
|
|
1860
|
-
scope.select = function(
|
1899
|
+
scope.select = function(date) {
|
1861
1900
|
if (date === 'today') {
|
1862
1901
|
var today = new Date();
|
1863
1902
|
if (angular.isDate(scope.date)) {
|
@@ -1867,7 +1906,7 @@ function ($compile, $parse, $document, $rootScope, $position, dateFilter, datePa
|
|
1867
1906
|
date = new Date(today.setHours(0, 0, 0, 0));
|
1868
1907
|
}
|
1869
1908
|
}
|
1870
|
-
scope.dateSelection(
|
1909
|
+
scope.dateSelection(date);
|
1871
1910
|
};
|
1872
1911
|
|
1873
1912
|
scope.close = function() {
|
@@ -1879,7 +1918,7 @@ function ($compile, $parse, $document, $rootScope, $position, dateFilter, datePa
|
|
1879
1918
|
// Prevent jQuery cache memory leak (template is now redundant after linking)
|
1880
1919
|
popupEl.remove();
|
1881
1920
|
|
1882
|
-
if (
|
1921
|
+
if (appendToBody) {
|
1883
1922
|
$document.find('body').append($popup);
|
1884
1923
|
} else {
|
1885
1924
|
element.after($popup);
|
@@ -1922,36 +1961,36 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
|
|
1922
1961
|
.service('dropdownService', ['$document', '$rootScope', function($document, $rootScope) {
|
1923
1962
|
var openScope = null;
|
1924
1963
|
|
1925
|
-
this.open = function(
|
1926
|
-
if (
|
1964
|
+
this.open = function(dropdownScope) {
|
1965
|
+
if (!openScope) {
|
1927
1966
|
$document.bind('click', closeDropdown);
|
1928
1967
|
$document.bind('keydown', keybindFilter);
|
1929
1968
|
}
|
1930
1969
|
|
1931
|
-
if (
|
1970
|
+
if (openScope && openScope !== dropdownScope) {
|
1932
1971
|
openScope.isOpen = false;
|
1933
1972
|
}
|
1934
1973
|
|
1935
1974
|
openScope = dropdownScope;
|
1936
1975
|
};
|
1937
1976
|
|
1938
|
-
this.close = function(
|
1939
|
-
if (
|
1977
|
+
this.close = function(dropdownScope) {
|
1978
|
+
if (openScope === dropdownScope) {
|
1940
1979
|
openScope = null;
|
1941
1980
|
$document.unbind('click', closeDropdown);
|
1942
1981
|
$document.unbind('keydown', keybindFilter);
|
1943
1982
|
}
|
1944
1983
|
};
|
1945
1984
|
|
1946
|
-
var closeDropdown = function(
|
1985
|
+
var closeDropdown = function(evt) {
|
1947
1986
|
// This method may still be called during the same mouse event that
|
1948
1987
|
// unbound this event handler. So check openScope before proceeding.
|
1949
1988
|
if (!openScope) { return; }
|
1950
1989
|
|
1951
|
-
if(
|
1990
|
+
if (evt && openScope.getAutoClose() === 'disabled') { return ; }
|
1952
1991
|
|
1953
1992
|
var toggleElement = openScope.getToggleElement();
|
1954
|
-
if (
|
1993
|
+
if (evt && toggleElement && toggleElement[0].contains(evt.target)) {
|
1955
1994
|
return;
|
1956
1995
|
}
|
1957
1996
|
|
@@ -1968,12 +2007,11 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
|
|
1968
2007
|
}
|
1969
2008
|
};
|
1970
2009
|
|
1971
|
-
var keybindFilter = function(
|
1972
|
-
if (
|
2010
|
+
var keybindFilter = function(evt) {
|
2011
|
+
if (evt.which === 27) {
|
1973
2012
|
openScope.focusToggleElement();
|
1974
2013
|
closeDropdown();
|
1975
|
-
}
|
1976
|
-
else if ( openScope.isKeynavEnabled() && /(38|40)/.test(evt.which) && openScope.isOpen ) {
|
2014
|
+
} else if (openScope.isKeynavEnabled() && /(38|40)/.test(evt.which) && openScope.isOpen) {
|
1977
2015
|
evt.preventDefault();
|
1978
2016
|
evt.stopPropagation();
|
1979
2017
|
openScope.focusDropdownEntry(evt.which);
|
@@ -1984,19 +2022,20 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
|
|
1984
2022
|
.controller('DropdownController', ['$scope', '$attrs', '$parse', 'dropdownConfig', 'dropdownService', '$animate', '$position', '$document', '$compile', '$templateRequest', function($scope, $attrs, $parse, dropdownConfig, dropdownService, $animate, $position, $document, $compile, $templateRequest) {
|
1985
2023
|
var self = this,
|
1986
2024
|
scope = $scope.$new(), // create a child scope so we are not polluting original one
|
1987
|
-
|
2025
|
+
templateScope,
|
1988
2026
|
openClass = dropdownConfig.openClass,
|
1989
2027
|
getIsOpen,
|
1990
2028
|
setIsOpen = angular.noop,
|
1991
2029
|
toggleInvoker = $attrs.onToggle ? $parse($attrs.onToggle) : angular.noop,
|
1992
2030
|
appendToBody = false,
|
1993
|
-
keynavEnabled =false,
|
1994
|
-
selectedOption = null
|
2031
|
+
keynavEnabled = false,
|
2032
|
+
selectedOption = null,
|
2033
|
+
body = $document.find('body');
|
1995
2034
|
|
1996
|
-
this.init = function(
|
2035
|
+
this.init = function(element) {
|
1997
2036
|
self.$element = element;
|
1998
2037
|
|
1999
|
-
if (
|
2038
|
+
if ($attrs.isOpen) {
|
2000
2039
|
getIsOpen = $parse($attrs.isOpen);
|
2001
2040
|
setIsOpen = getIsOpen.assign;
|
2002
2041
|
|
@@ -2008,15 +2047,16 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
|
|
2008
2047
|
appendToBody = angular.isDefined($attrs.dropdownAppendToBody);
|
2009
2048
|
keynavEnabled = angular.isDefined($attrs.keyboardNav);
|
2010
2049
|
|
2011
|
-
if (
|
2012
|
-
|
2050
|
+
if (appendToBody && self.dropdownMenu) {
|
2051
|
+
body.append(self.dropdownMenu);
|
2052
|
+
body.addClass('dropdown');
|
2013
2053
|
element.on('$destroy', function handleDestroyEvent() {
|
2014
2054
|
self.dropdownMenu.remove();
|
2015
2055
|
});
|
2016
2056
|
}
|
2017
2057
|
};
|
2018
2058
|
|
2019
|
-
this.toggle = function(
|
2059
|
+
this.toggle = function(open) {
|
2020
2060
|
return scope.isOpen = arguments.length ? !!open : !scope.isOpen;
|
2021
2061
|
};
|
2022
2062
|
|
@@ -2048,7 +2088,7 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
|
|
2048
2088
|
|
2049
2089
|
switch (keyCode) {
|
2050
2090
|
case (40): {
|
2051
|
-
if (
|
2091
|
+
if (!angular.isNumber(self.selectedOption)) {
|
2052
2092
|
self.selectedOption = 0;
|
2053
2093
|
} else {
|
2054
2094
|
self.selectedOption = (self.selectedOption === elems.length -1 ?
|
@@ -2058,12 +2098,11 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
|
|
2058
2098
|
break;
|
2059
2099
|
}
|
2060
2100
|
case (38): {
|
2061
|
-
if (
|
2062
|
-
|
2101
|
+
if (!angular.isNumber(self.selectedOption)) {
|
2102
|
+
self.selectedOption = elems.length - 1;
|
2063
2103
|
} else {
|
2064
|
-
self.selectedOption =
|
2065
|
-
0 :
|
2066
|
-
self.selectedOption - 1);
|
2104
|
+
self.selectedOption = self.selectedOption === 0 ?
|
2105
|
+
0 : self.selectedOption - 1;
|
2067
2106
|
}
|
2068
2107
|
break;
|
2069
2108
|
}
|
@@ -2076,38 +2115,40 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
|
|
2076
2115
|
};
|
2077
2116
|
|
2078
2117
|
scope.focusToggleElement = function() {
|
2079
|
-
if (
|
2118
|
+
if (self.toggleElement) {
|
2080
2119
|
self.toggleElement[0].focus();
|
2081
2120
|
}
|
2082
2121
|
};
|
2083
2122
|
|
2084
|
-
scope.$watch('isOpen', function(
|
2123
|
+
scope.$watch('isOpen', function(isOpen, wasOpen) {
|
2085
2124
|
if (appendToBody && self.dropdownMenu) {
|
2086
|
-
|
2087
|
-
|
2088
|
-
|
2089
|
-
|
2090
|
-
|
2125
|
+
var pos = $position.positionElements(self.$element, self.dropdownMenu, 'bottom-left', true);
|
2126
|
+
var css = {
|
2127
|
+
top: pos.top + 'px',
|
2128
|
+
display: isOpen ? 'block' : 'none'
|
2129
|
+
};
|
2091
2130
|
|
2092
|
-
|
2093
|
-
|
2094
|
-
|
2095
|
-
|
2096
|
-
|
2097
|
-
|
2098
|
-
|
2099
|
-
|
2131
|
+
var rightalign = self.dropdownMenu.hasClass('dropdown-menu-right');
|
2132
|
+
if (!rightalign) {
|
2133
|
+
css.left = pos.left + 'px';
|
2134
|
+
css.right = 'auto';
|
2135
|
+
} else {
|
2136
|
+
css.left = 'auto';
|
2137
|
+
css.right = (window.innerWidth - (pos.left + self.$element.prop('offsetWidth'))) + 'px';
|
2138
|
+
}
|
2100
2139
|
|
2101
|
-
|
2140
|
+
self.dropdownMenu.css(css);
|
2102
2141
|
}
|
2103
2142
|
|
2104
|
-
|
2105
|
-
|
2106
|
-
|
2107
|
-
|
2143
|
+
var openContainer = appendToBody ? body : self.$element;
|
2144
|
+
|
2145
|
+
$animate[isOpen ? 'addClass' : 'removeClass'](openContainer, openClass).then(function() {
|
2146
|
+
if (angular.isDefined(isOpen) && isOpen !== wasOpen) {
|
2147
|
+
toggleInvoker($scope, { open: !!isOpen });
|
2148
|
+
}
|
2108
2149
|
});
|
2109
2150
|
|
2110
|
-
if (
|
2151
|
+
if (isOpen) {
|
2111
2152
|
if (self.dropdownMenuTemplateUrl) {
|
2112
2153
|
$templateRequest(self.dropdownMenuTemplateUrl).then(function(tplContent) {
|
2113
2154
|
templateScope = scope.$new();
|
@@ -2120,7 +2161,7 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
|
|
2120
2161
|
}
|
2121
2162
|
|
2122
2163
|
scope.focusToggleElement();
|
2123
|
-
dropdownService.open(
|
2164
|
+
dropdownService.open(scope);
|
2124
2165
|
} else {
|
2125
2166
|
if (self.dropdownMenuTemplateUrl) {
|
2126
2167
|
if (templateScope) {
|
@@ -2131,7 +2172,7 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
|
|
2131
2172
|
self.dropdownMenu = newEl;
|
2132
2173
|
}
|
2133
2174
|
|
2134
|
-
dropdownService.close(
|
2175
|
+
dropdownService.close(scope);
|
2135
2176
|
self.selectedOption = null;
|
2136
2177
|
}
|
2137
2178
|
|
@@ -2146,9 +2187,10 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
|
|
2146
2187
|
}
|
2147
2188
|
});
|
2148
2189
|
|
2149
|
-
$scope.$on('$destroy', function() {
|
2190
|
+
var offDestroy = $scope.$on('$destroy', function() {
|
2150
2191
|
scope.$destroy();
|
2151
2192
|
});
|
2193
|
+
scope.$on('$destroy', offDestroy);
|
2152
2194
|
}])
|
2153
2195
|
|
2154
2196
|
.directive('dropdown', function() {
|
@@ -2187,9 +2229,7 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
|
|
2187
2229
|
link: function (scope, element, attrs, dropdownCtrl) {
|
2188
2230
|
|
2189
2231
|
element.bind('keydown', function(e) {
|
2190
|
-
|
2191
2232
|
if ([38, 40].indexOf(e.which) !== -1) {
|
2192
|
-
|
2193
2233
|
e.preventDefault();
|
2194
2234
|
e.stopPropagation();
|
2195
2235
|
|
@@ -2197,24 +2237,28 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
|
|
2197
2237
|
|
2198
2238
|
switch (e.which) {
|
2199
2239
|
case (40): { // Down
|
2200
|
-
if (
|
2240
|
+
if (!angular.isNumber(dropdownCtrl.selectedOption)) {
|
2201
2241
|
dropdownCtrl.selectedOption = 0;
|
2202
2242
|
} else {
|
2203
|
-
dropdownCtrl.selectedOption =
|
2243
|
+
dropdownCtrl.selectedOption = dropdownCtrl.selectedOption === elems.length -1 ?
|
2244
|
+
dropdownCtrl.selectedOption : dropdownCtrl.selectedOption + 1;
|
2204
2245
|
}
|
2205
|
-
|
2246
|
+
break;
|
2206
2247
|
}
|
2207
|
-
break;
|
2208
2248
|
case (38): { // Up
|
2209
|
-
|
2249
|
+
if (!angular.isNumber(dropdownCtrl.selectedOption)) {
|
2250
|
+
dropdownCtrl.selectedOption = elems.length - 1;
|
2251
|
+
} else {
|
2252
|
+
dropdownCtrl.selectedOption = dropdownCtrl.selectedOption === 0 ?
|
2253
|
+
0 : dropdownCtrl.selectedOption - 1;
|
2254
|
+
}
|
2255
|
+
break;
|
2210
2256
|
}
|
2211
|
-
break;
|
2212
2257
|
}
|
2213
2258
|
elems[dropdownCtrl.selectedOption].focus();
|
2214
2259
|
}
|
2215
2260
|
});
|
2216
2261
|
}
|
2217
|
-
|
2218
2262
|
};
|
2219
2263
|
})
|
2220
2264
|
|
@@ -2222,7 +2266,7 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
|
|
2222
2266
|
return {
|
2223
2267
|
require: '?^dropdown',
|
2224
2268
|
link: function(scope, element, attrs, dropdownCtrl) {
|
2225
|
-
if (
|
2269
|
+
if (!dropdownCtrl) {
|
2226
2270
|
return;
|
2227
2271
|
}
|
2228
2272
|
|
@@ -2233,7 +2277,7 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
|
|
2233
2277
|
var toggleDropdown = function(event) {
|
2234
2278
|
event.preventDefault();
|
2235
2279
|
|
2236
|
-
if (
|
2280
|
+
if (!element.hasClass('disabled') && !attrs.disabled) {
|
2237
2281
|
scope.$apply(function() {
|
2238
2282
|
dropdownCtrl.toggle();
|
2239
2283
|
});
|
@@ -2261,19 +2305,19 @@ angular.module('ui.bootstrap.modal', [])
|
|
2261
2305
|
* A helper, internal data structure that acts as a map but also allows getting / removing
|
2262
2306
|
* elements in the LIFO order
|
2263
2307
|
*/
|
2264
|
-
.factory('$$stackedMap', function
|
2308
|
+
.factory('$$stackedMap', function() {
|
2265
2309
|
return {
|
2266
|
-
createNew: function
|
2310
|
+
createNew: function() {
|
2267
2311
|
var stack = [];
|
2268
2312
|
|
2269
2313
|
return {
|
2270
|
-
add: function
|
2314
|
+
add: function(key, value) {
|
2271
2315
|
stack.push({
|
2272
2316
|
key: key,
|
2273
2317
|
value: value
|
2274
2318
|
});
|
2275
2319
|
},
|
2276
|
-
get: function
|
2320
|
+
get: function(key) {
|
2277
2321
|
for (var i = 0; i < stack.length; i++) {
|
2278
2322
|
if (key == stack[i].key) {
|
2279
2323
|
return stack[i];
|
@@ -2287,10 +2331,10 @@ angular.module('ui.bootstrap.modal', [])
|
|
2287
2331
|
}
|
2288
2332
|
return keys;
|
2289
2333
|
},
|
2290
|
-
top: function
|
2334
|
+
top: function() {
|
2291
2335
|
return stack[stack.length - 1];
|
2292
2336
|
},
|
2293
|
-
remove: function
|
2337
|
+
remove: function(key) {
|
2294
2338
|
var idx = -1;
|
2295
2339
|
for (var i = 0; i < stack.length; i++) {
|
2296
2340
|
if (key == stack[i].key) {
|
@@ -2300,10 +2344,10 @@ angular.module('ui.bootstrap.modal', [])
|
|
2300
2344
|
}
|
2301
2345
|
return stack.splice(idx, 1)[0];
|
2302
2346
|
},
|
2303
|
-
removeTop: function
|
2347
|
+
removeTop: function() {
|
2304
2348
|
return stack.splice(stack.length - 1, 1)[0];
|
2305
2349
|
},
|
2306
|
-
length: function
|
2350
|
+
length: function() {
|
2307
2351
|
return stack.length;
|
2308
2352
|
}
|
2309
2353
|
};
|
@@ -2311,12 +2355,67 @@ angular.module('ui.bootstrap.modal', [])
|
|
2311
2355
|
};
|
2312
2356
|
})
|
2313
2357
|
|
2358
|
+
/**
|
2359
|
+
* A helper, internal data structure that stores all references attached to key
|
2360
|
+
*/
|
2361
|
+
.factory('$$multiMap', function() {
|
2362
|
+
return {
|
2363
|
+
createNew: function() {
|
2364
|
+
var map = {};
|
2365
|
+
|
2366
|
+
return {
|
2367
|
+
entries: function() {
|
2368
|
+
return Object.keys(map).map(function(key) {
|
2369
|
+
return {
|
2370
|
+
key: key,
|
2371
|
+
value: map[key]
|
2372
|
+
};
|
2373
|
+
});
|
2374
|
+
},
|
2375
|
+
get: function(key) {
|
2376
|
+
return map[key];
|
2377
|
+
},
|
2378
|
+
hasKey: function(key) {
|
2379
|
+
return !!map[key];
|
2380
|
+
},
|
2381
|
+
keys: function() {
|
2382
|
+
return Object.keys(map);
|
2383
|
+
},
|
2384
|
+
put: function(key, value) {
|
2385
|
+
if (!map[key]) {
|
2386
|
+
map[key] = [];
|
2387
|
+
}
|
2388
|
+
|
2389
|
+
map[key].push(value);
|
2390
|
+
},
|
2391
|
+
remove: function(key, value) {
|
2392
|
+
var values = map[key];
|
2393
|
+
|
2394
|
+
if (!values) {
|
2395
|
+
return;
|
2396
|
+
}
|
2397
|
+
|
2398
|
+
var idx = values.indexOf(value);
|
2399
|
+
|
2400
|
+
if (idx !== -1) {
|
2401
|
+
values.splice(idx, 1);
|
2402
|
+
}
|
2403
|
+
|
2404
|
+
if (!values.length) {
|
2405
|
+
delete map[key];
|
2406
|
+
}
|
2407
|
+
}
|
2408
|
+
};
|
2409
|
+
}
|
2410
|
+
};
|
2411
|
+
})
|
2412
|
+
|
2314
2413
|
/**
|
2315
2414
|
* A helper directive for the $modal service. It creates a backdrop element.
|
2316
2415
|
*/
|
2317
2416
|
.directive('modalBackdrop', [
|
2318
2417
|
'$animate', '$injector', '$modalStack',
|
2319
|
-
function
|
2418
|
+
function($animate , $injector, $modalStack) {
|
2320
2419
|
var $animateCss = null;
|
2321
2420
|
|
2322
2421
|
if ($injector.has('$animateCss')) {
|
@@ -2327,7 +2426,7 @@ angular.module('ui.bootstrap.modal', [])
|
|
2327
2426
|
restrict: 'EA',
|
2328
2427
|
replace: true,
|
2329
2428
|
templateUrl: 'template/modal/backdrop.html',
|
2330
|
-
compile: function
|
2429
|
+
compile: function(tElement, tAttrs) {
|
2331
2430
|
tElement.addClass(tAttrs.backdropClass);
|
2332
2431
|
return linkFn;
|
2333
2432
|
}
|
@@ -2343,7 +2442,7 @@ angular.module('ui.bootstrap.modal', [])
|
|
2343
2442
|
$animate.addClass(element, attrs.modalInClass);
|
2344
2443
|
}
|
2345
2444
|
|
2346
|
-
scope.$on($modalStack.NOW_CLOSING_EVENT, function
|
2445
|
+
scope.$on($modalStack.NOW_CLOSING_EVENT, function(e, setIsAsync) {
|
2347
2446
|
var done = setIsAsync();
|
2348
2447
|
if ($animateCss) {
|
2349
2448
|
$animateCss(element, {
|
@@ -2359,7 +2458,7 @@ angular.module('ui.bootstrap.modal', [])
|
|
2359
2458
|
|
2360
2459
|
.directive('modalWindow', [
|
2361
2460
|
'$modalStack', '$q', '$animate', '$injector',
|
2362
|
-
function
|
2461
|
+
function($modalStack , $q , $animate, $injector) {
|
2363
2462
|
var $animateCss = null;
|
2364
2463
|
|
2365
2464
|
if ($injector.has('$animateCss')) {
|
@@ -2376,13 +2475,13 @@ angular.module('ui.bootstrap.modal', [])
|
|
2376
2475
|
templateUrl: function(tElement, tAttrs) {
|
2377
2476
|
return tAttrs.templateUrl || 'template/modal/window.html';
|
2378
2477
|
},
|
2379
|
-
link: function
|
2478
|
+
link: function(scope, element, attrs) {
|
2380
2479
|
element.addClass(attrs.windowClass || '');
|
2381
2480
|
scope.size = attrs.size;
|
2382
2481
|
|
2383
|
-
scope.close = function
|
2482
|
+
scope.close = function(evt) {
|
2384
2483
|
var modal = $modalStack.getTop();
|
2385
|
-
if (modal && modal.value.backdrop && modal.value.backdrop
|
2484
|
+
if (modal && modal.value.backdrop && modal.value.backdrop !== 'static' && (evt.target === evt.currentTarget)) {
|
2386
2485
|
evt.preventDefault();
|
2387
2486
|
evt.stopPropagation();
|
2388
2487
|
$modalStack.dismiss(modal.key, 'backdrop click');
|
@@ -2398,23 +2497,25 @@ angular.module('ui.bootstrap.modal', [])
|
|
2398
2497
|
var modalRenderDeferObj = $q.defer();
|
2399
2498
|
// Observe function will be called on next digest cycle after compilation, ensuring that the DOM is ready.
|
2400
2499
|
// In order to use this way of finding whether DOM is ready, we need to observe a scope property used in modal's template.
|
2401
|
-
attrs.$observe('modalRender', function
|
2500
|
+
attrs.$observe('modalRender', function(value) {
|
2402
2501
|
if (value == 'true') {
|
2403
2502
|
modalRenderDeferObj.resolve();
|
2404
2503
|
}
|
2405
2504
|
});
|
2406
2505
|
|
2407
|
-
modalRenderDeferObj.promise.then(function
|
2506
|
+
modalRenderDeferObj.promise.then(function() {
|
2507
|
+
var animationPromise = null;
|
2508
|
+
|
2408
2509
|
if (attrs.modalInClass) {
|
2409
2510
|
if ($animateCss) {
|
2410
|
-
$animateCss(element, {
|
2511
|
+
animationPromise = $animateCss(element, {
|
2411
2512
|
addClass: attrs.modalInClass
|
2412
2513
|
}).start();
|
2413
2514
|
} else {
|
2414
|
-
$animate.addClass(element, attrs.modalInClass);
|
2515
|
+
animationPromise = $animate.addClass(element, attrs.modalInClass);
|
2415
2516
|
}
|
2416
2517
|
|
2417
|
-
scope.$on($modalStack.NOW_CLOSING_EVENT, function
|
2518
|
+
scope.$on($modalStack.NOW_CLOSING_EVENT, function(e, setIsAsync) {
|
2418
2519
|
var done = setIsAsync();
|
2419
2520
|
if ($animateCss) {
|
2420
2521
|
$animateCss(element, {
|
@@ -2426,20 +2527,23 @@ angular.module('ui.bootstrap.modal', [])
|
|
2426
2527
|
});
|
2427
2528
|
}
|
2428
2529
|
|
2429
|
-
|
2430
|
-
|
2431
|
-
|
2432
|
-
|
2433
|
-
|
2434
|
-
|
2435
|
-
|
2436
|
-
|
2437
|
-
|
2438
|
-
|
2439
|
-
|
2440
|
-
|
2441
|
-
|
2442
|
-
|
2530
|
+
|
2531
|
+
$q.when(animationPromise).then(function() {
|
2532
|
+
var inputsWithAutofocus = element[0].querySelectorAll('[autofocus]');
|
2533
|
+
/**
|
2534
|
+
* Auto-focusing of a freshly-opened modal element causes any child elements
|
2535
|
+
* with the autofocus attribute to lose focus. This is an issue on touch
|
2536
|
+
* based devices which will show and then hide the onscreen keyboard.
|
2537
|
+
* Attempts to refocus the autofocus element via JavaScript will not reopen
|
2538
|
+
* the onscreen keyboard. Fixed by updated the focusing logic to only autofocus
|
2539
|
+
* the modal element if the modal does not contain an autofocus element.
|
2540
|
+
*/
|
2541
|
+
if (inputsWithAutofocus.length) {
|
2542
|
+
inputsWithAutofocus[0].focus();
|
2543
|
+
} else {
|
2544
|
+
element[0].focus();
|
2545
|
+
}
|
2546
|
+
});
|
2443
2547
|
|
2444
2548
|
// Notify {@link $modalStack} that modal is rendered.
|
2445
2549
|
var modal = $modalStack.getTop();
|
@@ -2454,7 +2558,7 @@ angular.module('ui.bootstrap.modal', [])
|
|
2454
2558
|
.directive('modalAnimationClass', [
|
2455
2559
|
function () {
|
2456
2560
|
return {
|
2457
|
-
compile: function
|
2561
|
+
compile: function(tElement, tAttrs) {
|
2458
2562
|
if (tAttrs.modalAnimation) {
|
2459
2563
|
tElement.addClass(tAttrs.modalAnimationClass);
|
2460
2564
|
}
|
@@ -2462,7 +2566,7 @@ angular.module('ui.bootstrap.modal', [])
|
|
2462
2566
|
};
|
2463
2567
|
}])
|
2464
2568
|
|
2465
|
-
.directive('modalTransclude', function
|
2569
|
+
.directive('modalTransclude', function() {
|
2466
2570
|
return {
|
2467
2571
|
link: function($scope, $element, $attrs, controller, $transclude) {
|
2468
2572
|
$transclude($scope.$parent, function(clone) {
|
@@ -2477,10 +2581,12 @@ angular.module('ui.bootstrap.modal', [])
|
|
2477
2581
|
'$animate', '$timeout', '$document', '$compile', '$rootScope',
|
2478
2582
|
'$q',
|
2479
2583
|
'$injector',
|
2584
|
+
'$$multiMap',
|
2480
2585
|
'$$stackedMap',
|
2481
|
-
function
|
2586
|
+
function($animate , $timeout , $document , $compile , $rootScope ,
|
2482
2587
|
$q,
|
2483
2588
|
$injector,
|
2589
|
+
$$multiMap,
|
2484
2590
|
$$stackedMap) {
|
2485
2591
|
var $animateCss = null;
|
2486
2592
|
|
@@ -2492,6 +2598,7 @@ angular.module('ui.bootstrap.modal', [])
|
|
2492
2598
|
|
2493
2599
|
var backdropDomEl, backdropScope;
|
2494
2600
|
var openedWindows = $$stackedMap.createNew();
|
2601
|
+
var openedClasses = $$multiMap.createNew();
|
2495
2602
|
var $modalStack = {
|
2496
2603
|
NOW_CLOSING_EVENT: 'modal.stack.now-closing'
|
2497
2604
|
};
|
@@ -2521,7 +2628,6 @@ angular.module('ui.bootstrap.modal', [])
|
|
2521
2628
|
});
|
2522
2629
|
|
2523
2630
|
function removeModalWindow(modalInstance, elementToReceiveFocus) {
|
2524
|
-
|
2525
2631
|
var body = $document.find('body').eq(0);
|
2526
2632
|
var modalWindow = openedWindows.get(modalInstance).value;
|
2527
2633
|
|
@@ -2529,7 +2635,9 @@ angular.module('ui.bootstrap.modal', [])
|
|
2529
2635
|
openedWindows.remove(modalInstance);
|
2530
2636
|
|
2531
2637
|
removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, function() {
|
2532
|
-
|
2638
|
+
var modalBodyClass = modalWindow.openedClass || OPENED_MODAL_CLASS;
|
2639
|
+
openedClasses.remove(modalBodyClass, modalInstance);
|
2640
|
+
body.toggleClass(modalBodyClass, openedClasses.hasKey(modalBodyClass));
|
2533
2641
|
});
|
2534
2642
|
checkRemoveBackdrop();
|
2535
2643
|
|
@@ -2545,7 +2653,7 @@ angular.module('ui.bootstrap.modal', [])
|
|
2545
2653
|
//remove backdrop if no longer needed
|
2546
2654
|
if (backdropDomEl && backdropIndex() == -1) {
|
2547
2655
|
var backdropScopeRef = backdropScope;
|
2548
|
-
removeAfterAnimate(backdropDomEl, backdropScope, function
|
2656
|
+
removeAfterAnimate(backdropDomEl, backdropScope, function() {
|
2549
2657
|
backdropScopeRef = null;
|
2550
2658
|
});
|
2551
2659
|
backdropDomEl = undefined;
|
@@ -2556,7 +2664,7 @@ angular.module('ui.bootstrap.modal', [])
|
|
2556
2664
|
function removeAfterAnimate(domEl, scope, done) {
|
2557
2665
|
var asyncDeferred;
|
2558
2666
|
var asyncPromise = null;
|
2559
|
-
var setIsAsync = function
|
2667
|
+
var setIsAsync = function() {
|
2560
2668
|
if (!asyncDeferred) {
|
2561
2669
|
asyncDeferred = $q.defer();
|
2562
2670
|
asyncPromise = asyncDeferred.promise;
|
@@ -2595,7 +2703,7 @@ angular.module('ui.bootstrap.modal', [])
|
|
2595
2703
|
}
|
2596
2704
|
}
|
2597
2705
|
|
2598
|
-
$document.bind('keydown', function
|
2706
|
+
$document.bind('keydown', function(evt) {
|
2599
2707
|
if (evt.isDefaultPrevented()) {
|
2600
2708
|
return evt;
|
2601
2709
|
}
|
@@ -2605,7 +2713,7 @@ angular.module('ui.bootstrap.modal', [])
|
|
2605
2713
|
switch (evt.which){
|
2606
2714
|
case 27: {
|
2607
2715
|
evt.preventDefault();
|
2608
|
-
$rootScope.$apply(function
|
2716
|
+
$rootScope.$apply(function() {
|
2609
2717
|
$modalStack.dismiss(modal.key, 'escape key press');
|
2610
2718
|
});
|
2611
2719
|
break;
|
@@ -2633,9 +2741,9 @@ angular.module('ui.bootstrap.modal', [])
|
|
2633
2741
|
}
|
2634
2742
|
});
|
2635
2743
|
|
2636
|
-
$modalStack.open = function
|
2637
|
-
|
2638
|
-
|
2744
|
+
$modalStack.open = function(modalInstance, modal) {
|
2745
|
+
var modalOpener = $document[0].activeElement,
|
2746
|
+
modalBodyClass = modal.openedClass || OPENED_MODAL_CLASS;
|
2639
2747
|
|
2640
2748
|
openedWindows.add(modalInstance, {
|
2641
2749
|
deferred: modal.deferred,
|
@@ -2646,6 +2754,8 @@ angular.module('ui.bootstrap.modal', [])
|
|
2646
2754
|
openedClass: modal.openedClass
|
2647
2755
|
});
|
2648
2756
|
|
2757
|
+
openedClasses.put(modalBodyClass, modalInstance);
|
2758
|
+
|
2649
2759
|
var body = $document.find('body').eq(0),
|
2650
2760
|
currBackdropIndex = backdropIndex();
|
2651
2761
|
|
@@ -2677,7 +2787,8 @@ angular.module('ui.bootstrap.modal', [])
|
|
2677
2787
|
openedWindows.top().value.modalDomEl = modalDomEl;
|
2678
2788
|
openedWindows.top().value.modalOpener = modalOpener;
|
2679
2789
|
body.append(modalDomEl);
|
2680
|
-
body.addClass(
|
2790
|
+
body.addClass(modalBodyClass);
|
2791
|
+
|
2681
2792
|
$modalStack.clearFocusListCache();
|
2682
2793
|
};
|
2683
2794
|
|
@@ -2685,7 +2796,7 @@ angular.module('ui.bootstrap.modal', [])
|
|
2685
2796
|
return !modalWindow.value.modalScope.$broadcast('modal.closing', resultOrReason, closing).defaultPrevented;
|
2686
2797
|
}
|
2687
2798
|
|
2688
|
-
$modalStack.close = function
|
2799
|
+
$modalStack.close = function(modalInstance, result) {
|
2689
2800
|
var modalWindow = openedWindows.get(modalInstance);
|
2690
2801
|
if (modalWindow && broadcastClosing(modalWindow, result, true)) {
|
2691
2802
|
modalWindow.value.modalScope.$$uibDestructionScheduled = true;
|
@@ -2696,7 +2807,7 @@ angular.module('ui.bootstrap.modal', [])
|
|
2696
2807
|
return !modalWindow;
|
2697
2808
|
};
|
2698
2809
|
|
2699
|
-
$modalStack.dismiss = function
|
2810
|
+
$modalStack.dismiss = function(modalInstance, reason) {
|
2700
2811
|
var modalWindow = openedWindows.get(modalInstance);
|
2701
2812
|
if (modalWindow && broadcastClosing(modalWindow, reason, false)) {
|
2702
2813
|
modalWindow.value.modalScope.$$uibDestructionScheduled = true;
|
@@ -2707,18 +2818,18 @@ angular.module('ui.bootstrap.modal', [])
|
|
2707
2818
|
return !modalWindow;
|
2708
2819
|
};
|
2709
2820
|
|
2710
|
-
$modalStack.dismissAll = function
|
2821
|
+
$modalStack.dismissAll = function(reason) {
|
2711
2822
|
var topModal = this.getTop();
|
2712
2823
|
while (topModal && this.dismiss(topModal.key, reason)) {
|
2713
2824
|
topModal = this.getTop();
|
2714
2825
|
}
|
2715
2826
|
};
|
2716
2827
|
|
2717
|
-
$modalStack.getTop = function
|
2828
|
+
$modalStack.getTop = function() {
|
2718
2829
|
return openedWindows.top();
|
2719
2830
|
};
|
2720
2831
|
|
2721
|
-
$modalStack.modalRendered = function
|
2832
|
+
$modalStack.modalRendered = function(modalInstance) {
|
2722
2833
|
var modalWindow = openedWindows.get(modalInstance);
|
2723
2834
|
if (modalWindow) {
|
2724
2835
|
modalWindow.value.renderDeferred.resolve();
|
@@ -2773,8 +2884,7 @@ angular.module('ui.bootstrap.modal', [])
|
|
2773
2884
|
return $modalStack;
|
2774
2885
|
}])
|
2775
2886
|
|
2776
|
-
.provider('$modal', function
|
2777
|
-
|
2887
|
+
.provider('$modal', function() {
|
2778
2888
|
var $modalProvider = {
|
2779
2889
|
options: {
|
2780
2890
|
animation: true,
|
@@ -2783,7 +2893,6 @@ angular.module('ui.bootstrap.modal', [])
|
|
2783
2893
|
},
|
2784
2894
|
$get: ['$injector', '$rootScope', '$q', '$templateRequest', '$controller', '$modalStack',
|
2785
2895
|
function ($injector, $rootScope, $q, $templateRequest, $controller, $modalStack) {
|
2786
|
-
|
2787
2896
|
var $modal = {};
|
2788
2897
|
|
2789
2898
|
function getTemplatePromise(options) {
|
@@ -2793,16 +2902,23 @@ angular.module('ui.bootstrap.modal', [])
|
|
2793
2902
|
|
2794
2903
|
function getResolvePromises(resolves) {
|
2795
2904
|
var promisesArr = [];
|
2796
|
-
angular.forEach(resolves, function
|
2905
|
+
angular.forEach(resolves, function(value) {
|
2797
2906
|
if (angular.isFunction(value) || angular.isArray(value)) {
|
2798
2907
|
promisesArr.push($q.when($injector.invoke(value)));
|
2799
2908
|
} else if (angular.isString(value)) {
|
2800
2909
|
promisesArr.push($q.when($injector.get(value)));
|
2910
|
+
} else {
|
2911
|
+
promisesArr.push($q.when(value));
|
2801
2912
|
}
|
2802
2913
|
});
|
2803
2914
|
return promisesArr;
|
2804
2915
|
}
|
2805
2916
|
|
2917
|
+
var promiseChain = null;
|
2918
|
+
$modal.getPromiseChain = function() {
|
2919
|
+
return promiseChain;
|
2920
|
+
};
|
2921
|
+
|
2806
2922
|
$modal.open = function (modalOptions) {
|
2807
2923
|
|
2808
2924
|
var modalResultDeferred = $q.defer();
|
@@ -2834,63 +2950,70 @@ angular.module('ui.bootstrap.modal', [])
|
|
2834
2950
|
var templateAndResolvePromise =
|
2835
2951
|
$q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve)));
|
2836
2952
|
|
2953
|
+
// Wait for the resolution of the existing promise chain.
|
2954
|
+
// Then switch to our own combined promise dependency (regardless of how the previous modal fared).
|
2955
|
+
// Then add to $modalStack and resolve opened.
|
2956
|
+
// Finally clean up the chain variable if no subsequent modal has overwritten it.
|
2957
|
+
var samePromise;
|
2958
|
+
samePromise = promiseChain = $q.all([promiseChain])
|
2959
|
+
.then(function() { return templateAndResolvePromise; }, function() { return templateAndResolvePromise; })
|
2960
|
+
.then(function resolveSuccess(tplAndVars) {
|
2961
|
+
|
2962
|
+
var modalScope = (modalOptions.scope || $rootScope).$new();
|
2963
|
+
modalScope.$close = modalInstance.close;
|
2964
|
+
modalScope.$dismiss = modalInstance.dismiss;
|
2965
|
+
|
2966
|
+
modalScope.$on('$destroy', function() {
|
2967
|
+
if (!modalScope.$$uibDestructionScheduled) {
|
2968
|
+
modalScope.$dismiss('$uibUnscheduledDestruction');
|
2969
|
+
}
|
2970
|
+
});
|
2837
2971
|
|
2838
|
-
|
2839
|
-
|
2840
|
-
var modalScope = (modalOptions.scope || $rootScope).$new();
|
2841
|
-
modalScope.$close = modalInstance.close;
|
2842
|
-
modalScope.$dismiss = modalInstance.dismiss;
|
2843
|
-
|
2844
|
-
modalScope.$on('$destroy', function() {
|
2845
|
-
if (!modalScope.$$uibDestructionScheduled) {
|
2846
|
-
modalScope.$dismiss('$uibUnscheduledDestruction');
|
2847
|
-
}
|
2848
|
-
});
|
2972
|
+
var ctrlInstance, ctrlLocals = {};
|
2973
|
+
var resolveIter = 1;
|
2849
2974
|
|
2850
|
-
|
2851
|
-
|
2975
|
+
//controllers
|
2976
|
+
if (modalOptions.controller) {
|
2977
|
+
ctrlLocals.$scope = modalScope;
|
2978
|
+
ctrlLocals.$modalInstance = modalInstance;
|
2979
|
+
angular.forEach(modalOptions.resolve, function(value, key) {
|
2980
|
+
ctrlLocals[key] = tplAndVars[resolveIter++];
|
2981
|
+
});
|
2852
2982
|
|
2853
|
-
|
2854
|
-
|
2855
|
-
|
2856
|
-
|
2857
|
-
|
2858
|
-
ctrlLocals[key] = tplAndVars[resolveIter++];
|
2859
|
-
});
|
2983
|
+
ctrlInstance = $controller(modalOptions.controller, ctrlLocals);
|
2984
|
+
if (modalOptions.controllerAs) {
|
2985
|
+
if (modalOptions.bindToController) {
|
2986
|
+
angular.extend(ctrlInstance, modalScope);
|
2987
|
+
}
|
2860
2988
|
|
2861
|
-
|
2862
|
-
if (modalOptions.controllerAs) {
|
2863
|
-
if (modalOptions.bindToController) {
|
2864
|
-
angular.extend(ctrlInstance, modalScope);
|
2989
|
+
modalScope[modalOptions.controllerAs] = ctrlInstance;
|
2865
2990
|
}
|
2866
|
-
|
2867
|
-
modalScope[modalOptions.controllerAs] = ctrlInstance;
|
2868
2991
|
}
|
2869
|
-
}
|
2870
2992
|
|
2871
|
-
|
2872
|
-
|
2873
|
-
|
2874
|
-
|
2875
|
-
|
2876
|
-
|
2877
|
-
|
2878
|
-
|
2879
|
-
|
2880
|
-
|
2881
|
-
|
2882
|
-
|
2883
|
-
|
2884
|
-
|
2993
|
+
$modalStack.open(modalInstance, {
|
2994
|
+
scope: modalScope,
|
2995
|
+
deferred: modalResultDeferred,
|
2996
|
+
renderDeferred: modalRenderDeferred,
|
2997
|
+
content: tplAndVars[0],
|
2998
|
+
animation: modalOptions.animation,
|
2999
|
+
backdrop: modalOptions.backdrop,
|
3000
|
+
keyboard: modalOptions.keyboard,
|
3001
|
+
backdropClass: modalOptions.backdropClass,
|
3002
|
+
windowClass: modalOptions.windowClass,
|
3003
|
+
windowTemplateUrl: modalOptions.windowTemplateUrl,
|
3004
|
+
size: modalOptions.size,
|
3005
|
+
openedClass: modalOptions.openedClass
|
3006
|
+
});
|
3007
|
+
modalOpenedDeferred.resolve(true);
|
2885
3008
|
|
2886
3009
|
}, function resolveError(reason) {
|
2887
|
-
modalResultDeferred.reject(reason);
|
2888
|
-
});
|
2889
|
-
|
2890
|
-
templateAndResolvePromise.then(function () {
|
2891
|
-
modalOpenedDeferred.resolve(true);
|
2892
|
-
}, function (reason) {
|
2893
3010
|
modalOpenedDeferred.reject(reason);
|
3011
|
+
modalResultDeferred.reject(reason);
|
3012
|
+
})
|
3013
|
+
.finally(function() {
|
3014
|
+
if (promiseChain === samePromise) {
|
3015
|
+
promiseChain = null;
|
3016
|
+
}
|
2894
3017
|
});
|
2895
3018
|
|
2896
3019
|
return modalInstance;
|
@@ -2904,7 +3027,7 @@ angular.module('ui.bootstrap.modal', [])
|
|
2904
3027
|
});
|
2905
3028
|
|
2906
3029
|
angular.module('ui.bootstrap.pagination', [])
|
2907
|
-
.controller('PaginationController', ['$scope', '$attrs', '$parse', function
|
3030
|
+
.controller('PaginationController', ['$scope', '$attrs', '$parse', function($scope, $attrs, $parse) {
|
2908
3031
|
var self = this,
|
2909
3032
|
ngModelCtrl = { $setViewValue: angular.noop }, // nullModelCtrl
|
2910
3033
|
setNumPages = $attrs.numPages ? $parse($attrs.numPages).assign : angular.noop;
|
@@ -2965,12 +3088,14 @@ angular.module('ui.bootstrap.pagination', [])
|
|
2965
3088
|
}
|
2966
3089
|
};
|
2967
3090
|
|
2968
|
-
$scope.getText = function(
|
3091
|
+
$scope.getText = function(key) {
|
2969
3092
|
return $scope[key + 'Text'] || self.config[key + 'Text'];
|
2970
3093
|
};
|
3094
|
+
|
2971
3095
|
$scope.noPrevious = function() {
|
2972
3096
|
return $scope.page === 1;
|
2973
3097
|
};
|
3098
|
+
|
2974
3099
|
$scope.noNext = function() {
|
2975
3100
|
return $scope.page === $scope.totalPages;
|
2976
3101
|
};
|
@@ -3041,11 +3166,11 @@ angular.module('ui.bootstrap.pagination', [])
|
|
3041
3166
|
|
3042
3167
|
// Default page limits
|
3043
3168
|
var startPage = 1, endPage = totalPages;
|
3044
|
-
var isMaxSized =
|
3169
|
+
var isMaxSized = angular.isDefined(maxSize) && maxSize < totalPages;
|
3045
3170
|
|
3046
3171
|
// recompute if maxSize
|
3047
|
-
if (
|
3048
|
-
if (
|
3172
|
+
if (isMaxSized) {
|
3173
|
+
if (rotate) {
|
3049
3174
|
// Current page is displayed in the middle of the visible ones
|
3050
3175
|
startPage = Math.max(currentPage - Math.floor(maxSize/2), 1);
|
3051
3176
|
endPage = startPage + maxSize - 1;
|
@@ -3071,13 +3196,13 @@ angular.module('ui.bootstrap.pagination', [])
|
|
3071
3196
|
}
|
3072
3197
|
|
3073
3198
|
// Add links to move between page sets
|
3074
|
-
if (
|
3075
|
-
if (
|
3199
|
+
if (isMaxSized && ! rotate) {
|
3200
|
+
if (startPage > 1) {
|
3076
3201
|
var previousPageSet = makePage(startPage - 1, '...', false);
|
3077
3202
|
pages.unshift(previousPageSet);
|
3078
3203
|
}
|
3079
3204
|
|
3080
|
-
if (
|
3205
|
+
if (endPage < totalPages) {
|
3081
3206
|
var nextPageSet = makePage(endPage + 1, '...', false);
|
3082
3207
|
pages.push(nextPageSet);
|
3083
3208
|
}
|
@@ -3110,11 +3235,15 @@ angular.module('ui.bootstrap.pagination', [])
|
|
3110
3235
|
scope: {
|
3111
3236
|
totalItems: '=',
|
3112
3237
|
previousText: '@',
|
3113
|
-
nextText: '@'
|
3238
|
+
nextText: '@',
|
3239
|
+
ngDisabled: '='
|
3114
3240
|
},
|
3115
3241
|
require: ['pager', '?ngModel'],
|
3116
3242
|
controller: 'PaginationController',
|
3117
|
-
|
3243
|
+
controllerAs: 'pagination',
|
3244
|
+
templateUrl: function(element, attrs) {
|
3245
|
+
return attrs.templateUrl || 'template/pagination/pager.html';
|
3246
|
+
},
|
3118
3247
|
replace: true,
|
3119
3248
|
link: function(scope, element, attrs, ctrls) {
|
3120
3249
|
var paginationCtrl = ctrls[0], ngModelCtrl = ctrls[1];
|
@@ -3134,13 +3263,13 @@ angular.module('ui.bootstrap.pagination', [])
|
|
3134
3263
|
* function, placement as a function, inside, support for more triggers than
|
3135
3264
|
* just mouse enter/leave, html tooltips, and selector delegation.
|
3136
3265
|
*/
|
3137
|
-
angular.module(
|
3266
|
+
angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.bindHtml'])
|
3138
3267
|
|
3139
3268
|
/**
|
3140
3269
|
* The $tooltip service creates tooltip- and popover-like directives as well as
|
3141
3270
|
* houses global options for them.
|
3142
3271
|
*/
|
3143
|
-
.provider(
|
3272
|
+
.provider('$tooltip', function() {
|
3144
3273
|
// The default options tooltip and popover.
|
3145
3274
|
var defaultOptions = {
|
3146
3275
|
placement: 'top',
|
@@ -3153,7 +3282,8 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
3153
3282
|
var triggerMap = {
|
3154
3283
|
'mouseenter': 'mouseleave',
|
3155
3284
|
'click': 'click',
|
3156
|
-
'focus': 'blur'
|
3285
|
+
'focus': 'blur',
|
3286
|
+
'none': ''
|
3157
3287
|
};
|
3158
3288
|
|
3159
3289
|
// The options specified to the provider globally.
|
@@ -3168,23 +3298,23 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
3168
3298
|
* $tooltipProvider.options( { placement: 'left' } );
|
3169
3299
|
* });
|
3170
3300
|
*/
|
3171
|
-
|
3172
|
-
|
3173
|
-
|
3301
|
+
this.options = function(value) {
|
3302
|
+
angular.extend(globalOptions, value);
|
3303
|
+
};
|
3174
3304
|
|
3175
3305
|
/**
|
3176
3306
|
* This allows you to extend the set of trigger mappings available. E.g.:
|
3177
3307
|
*
|
3178
3308
|
* $tooltipProvider.setTriggers( 'openTrigger': 'closeTrigger' );
|
3179
3309
|
*/
|
3180
|
-
this.setTriggers = function setTriggers
|
3181
|
-
angular.extend(
|
3310
|
+
this.setTriggers = function setTriggers(triggers) {
|
3311
|
+
angular.extend(triggerMap, triggers);
|
3182
3312
|
};
|
3183
3313
|
|
3184
3314
|
/**
|
3185
3315
|
* This is a helper function for translating camel-case to snake-case.
|
3186
3316
|
*/
|
3187
|
-
function snake_case(name){
|
3317
|
+
function snake_case(name) {
|
3188
3318
|
var regexp = /[A-Z]/g;
|
3189
3319
|
var separator = '-';
|
3190
3320
|
return name.replace(regexp, function(letter, pos) {
|
@@ -3196,9 +3326,9 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
3196
3326
|
* Returns the actual instance of the $tooltip service.
|
3197
3327
|
* TODO support multiple triggers
|
3198
3328
|
*/
|
3199
|
-
this.$get = [
|
3200
|
-
return function $tooltip
|
3201
|
-
options = angular.extend(
|
3329
|
+
this.$get = ['$window', '$compile', '$timeout', '$document', '$position', '$interpolate', '$rootScope', '$parse', function($window, $compile, $timeout, $document, $position, $interpolate, $rootScope, $parse) {
|
3330
|
+
return function $tooltip(type, prefix, defaultTriggerShow, options) {
|
3331
|
+
options = angular.extend({}, defaultOptions, globalOptions, options);
|
3202
3332
|
|
3203
3333
|
/**
|
3204
3334
|
* Returns an object of show and hide triggers.
|
@@ -3214,7 +3344,7 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
3214
3344
|
* undefined; otherwise, it uses the `triggerMap` value of the show
|
3215
3345
|
* trigger; else it will just use the show trigger.
|
3216
3346
|
*/
|
3217
|
-
function getTriggers
|
3347
|
+
function getTriggers(trigger) {
|
3218
3348
|
var show = (trigger || options.trigger || defaultTriggerShow).split(' ');
|
3219
3349
|
var hide = show.map(function(trigger) {
|
3220
3350
|
return triggerMap[trigger] || trigger;
|
@@ -3225,7 +3355,7 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
3225
3355
|
};
|
3226
3356
|
}
|
3227
3357
|
|
3228
|
-
var directiveName = snake_case(
|
3358
|
+
var directiveName = snake_case(type);
|
3229
3359
|
|
3230
3360
|
var startSym = $interpolate.startSymbol();
|
3231
3361
|
var endSym = $interpolate.endSymbol();
|
@@ -3245,33 +3375,45 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
3245
3375
|
|
3246
3376
|
return {
|
3247
3377
|
restrict: 'EA',
|
3248
|
-
compile: function
|
3378
|
+
compile: function(tElem, tAttrs) {
|
3249
3379
|
var tooltipLinker = $compile( template );
|
3250
3380
|
|
3251
|
-
return function link
|
3381
|
+
return function link(scope, element, attrs, tooltipCtrl) {
|
3252
3382
|
var tooltip;
|
3253
3383
|
var tooltipLinkedScope;
|
3254
3384
|
var transitionTimeout;
|
3255
3385
|
var popupTimeout;
|
3256
|
-
var
|
3257
|
-
var
|
3258
|
-
var
|
3386
|
+
var positionTimeout;
|
3387
|
+
var appendToBody = angular.isDefined(options.appendToBody) ? options.appendToBody : false;
|
3388
|
+
var triggers = getTriggers(undefined);
|
3389
|
+
var hasEnableExp = angular.isDefined(attrs[prefix + 'Enable']);
|
3259
3390
|
var ttScope = scope.$new(true);
|
3260
3391
|
var repositionScheduled = false;
|
3392
|
+
var isOpenExp = angular.isDefined(attrs[prefix + 'IsOpen']) ? $parse(attrs[prefix + 'IsOpen']) : false;
|
3261
3393
|
|
3262
|
-
var positionTooltip = function
|
3394
|
+
var positionTooltip = function() {
|
3263
3395
|
if (!tooltip) { return; }
|
3264
3396
|
|
3265
|
-
|
3266
|
-
|
3267
|
-
|
3397
|
+
if (!positionTimeout) {
|
3398
|
+
positionTimeout = $timeout(function() {
|
3399
|
+
// Reset the positioning and box size for correct width and height values.
|
3400
|
+
tooltip.css({ top: 0, left: 0, width: 'auto', height: 'auto' });
|
3268
3401
|
|
3269
|
-
|
3270
|
-
|
3271
|
-
|
3402
|
+
var ttBox = $position.position(tooltip);
|
3403
|
+
var ttCss = $position.positionElements(element, tooltip, ttScope.placement, appendToBody);
|
3404
|
+
ttCss.top += 'px';
|
3405
|
+
ttCss.left += 'px';
|
3406
|
+
|
3407
|
+
ttCss.width = ttBox.width + 'px';
|
3408
|
+
ttCss.height = ttBox.height + 'px';
|
3409
|
+
|
3410
|
+
// Now set the calculated positioning and size.
|
3411
|
+
tooltip.css(ttCss);
|
3272
3412
|
|
3273
|
-
|
3274
|
-
|
3413
|
+
positionTimeout = null;
|
3414
|
+
|
3415
|
+
}, 0, false);
|
3416
|
+
}
|
3275
3417
|
};
|
3276
3418
|
|
3277
3419
|
// Set up the correct scope to allow transclusion later
|
@@ -3281,8 +3423,8 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
3281
3423
|
// TODO add ability to start tooltip opened
|
3282
3424
|
ttScope.isOpen = false;
|
3283
3425
|
|
3284
|
-
function toggleTooltipBind
|
3285
|
-
if (
|
3426
|
+
function toggleTooltipBind() {
|
3427
|
+
if (!ttScope.isOpen) {
|
3286
3428
|
showTooltipBind();
|
3287
3429
|
} else {
|
3288
3430
|
hideTooltipBind();
|
@@ -3291,21 +3433,20 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
3291
3433
|
|
3292
3434
|
// Show the tooltip with delay if specified, otherwise show it immediately
|
3293
3435
|
function showTooltipBind() {
|
3294
|
-
if(hasEnableExp && !scope.$eval(attrs[prefix+'Enable'])) {
|
3436
|
+
if (hasEnableExp && !scope.$eval(attrs[prefix + 'Enable'])) {
|
3295
3437
|
return;
|
3296
3438
|
}
|
3297
3439
|
|
3298
3440
|
prepareTooltip();
|
3299
3441
|
|
3300
|
-
if (
|
3442
|
+
if (ttScope.popupDelay) {
|
3301
3443
|
// Do nothing if the tooltip was already scheduled to pop-up.
|
3302
3444
|
// This happens if show is triggered multiple times before any hide is triggered.
|
3303
3445
|
if (!popupTimeout) {
|
3304
|
-
popupTimeout = $timeout(
|
3305
|
-
popupTimeout.then(function(reposition){reposition();});
|
3446
|
+
popupTimeout = $timeout(show, ttScope.popupDelay, false);
|
3306
3447
|
}
|
3307
3448
|
} else {
|
3308
|
-
show()
|
3449
|
+
show();
|
3309
3450
|
}
|
3310
3451
|
}
|
3311
3452
|
|
@@ -3318,50 +3459,56 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
3318
3459
|
|
3319
3460
|
// Show the tooltip popup element.
|
3320
3461
|
function show() {
|
3321
|
-
|
3322
3462
|
popupTimeout = null;
|
3323
3463
|
|
3324
3464
|
// If there is a pending remove transition, we must cancel it, lest the
|
3325
3465
|
// tooltip be mysteriously removed.
|
3326
|
-
if (
|
3327
|
-
$timeout.cancel(
|
3466
|
+
if (transitionTimeout) {
|
3467
|
+
$timeout.cancel(transitionTimeout);
|
3328
3468
|
transitionTimeout = null;
|
3329
3469
|
}
|
3330
3470
|
|
3331
3471
|
// Don't show empty tooltips.
|
3332
|
-
if (
|
3472
|
+
if (!(options.useContentExp ? ttScope.contentExp() : ttScope.content)) {
|
3333
3473
|
return angular.noop;
|
3334
3474
|
}
|
3335
3475
|
|
3336
3476
|
createTooltip();
|
3337
3477
|
|
3338
|
-
// Set the initial positioning.
|
3339
|
-
tooltip.css({ top: 0, left: 0, display: 'block' });
|
3340
|
-
|
3341
|
-
positionTooltip();
|
3342
|
-
|
3343
3478
|
// And show the tooltip.
|
3344
3479
|
ttScope.isOpen = true;
|
3345
|
-
|
3480
|
+
if (isOpenExp) {
|
3481
|
+
isOpenExp.assign(ttScope.origScope, ttScope.isOpen);
|
3482
|
+
}
|
3483
|
+
|
3484
|
+
if (!$rootScope.$$phase) {
|
3485
|
+
ttScope.$apply(); // digest required as $apply is not called
|
3486
|
+
}
|
3346
3487
|
|
3347
|
-
|
3348
|
-
|
3349
|
-
|
3488
|
+
tooltip.css({ display: 'block' });
|
3489
|
+
|
3490
|
+
positionTooltip();
|
3350
3491
|
}
|
3351
3492
|
|
3352
3493
|
// Hide the tooltip popup element.
|
3353
3494
|
function hide() {
|
3354
3495
|
// First things first: we don't show it anymore.
|
3355
3496
|
ttScope.isOpen = false;
|
3497
|
+
if (isOpenExp) {
|
3498
|
+
isOpenExp.assign(ttScope.origScope, ttScope.isOpen);
|
3499
|
+
}
|
3356
3500
|
|
3357
3501
|
//if tooltip is going to be shown after delay, we must cancel this
|
3358
|
-
$timeout.cancel(
|
3502
|
+
$timeout.cancel(popupTimeout);
|
3359
3503
|
popupTimeout = null;
|
3360
3504
|
|
3505
|
+
$timeout.cancel(positionTimeout);
|
3506
|
+
positionTimeout = null;
|
3507
|
+
|
3361
3508
|
// And now we remove it from the DOM. However, if we have animation, we
|
3362
3509
|
// need to wait for it to expire beforehand.
|
3363
3510
|
// FIXME: this is a placeholder for a port of the transitions library.
|
3364
|
-
if (
|
3511
|
+
if (ttScope.animation) {
|
3365
3512
|
if (!transitionTimeout) {
|
3366
3513
|
transitionTimeout = $timeout(removeTooltip, 500);
|
3367
3514
|
}
|
@@ -3376,16 +3523,16 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
3376
3523
|
removeTooltip();
|
3377
3524
|
}
|
3378
3525
|
tooltipLinkedScope = ttScope.$new();
|
3379
|
-
tooltip = tooltipLinker(tooltipLinkedScope, function
|
3380
|
-
if (
|
3381
|
-
$document.find(
|
3526
|
+
tooltip = tooltipLinker(tooltipLinkedScope, function(tooltip) {
|
3527
|
+
if (appendToBody) {
|
3528
|
+
$document.find('body').append(tooltip);
|
3382
3529
|
} else {
|
3383
|
-
element.after(
|
3530
|
+
element.after(tooltip);
|
3384
3531
|
}
|
3385
3532
|
});
|
3386
3533
|
|
3387
3534
|
if (options.useContentExp) {
|
3388
|
-
tooltipLinkedScope.$watch('contentExp()', function
|
3535
|
+
tooltipLinkedScope.$watch('contentExp()', function(val) {
|
3389
3536
|
if (!val && ttScope.isOpen) {
|
3390
3537
|
hide();
|
3391
3538
|
}
|
@@ -3396,7 +3543,9 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
3396
3543
|
repositionScheduled = true;
|
3397
3544
|
tooltipLinkedScope.$$postDigest(function() {
|
3398
3545
|
repositionScheduled = false;
|
3399
|
-
|
3546
|
+
if (ttScope.isOpen) {
|
3547
|
+
positionTooltip();
|
3548
|
+
}
|
3400
3549
|
});
|
3401
3550
|
}
|
3402
3551
|
});
|
@@ -3422,7 +3571,7 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
3422
3571
|
prepPopupDelay();
|
3423
3572
|
}
|
3424
3573
|
|
3425
|
-
ttScope.contentExp = function
|
3574
|
+
ttScope.contentExp = function() {
|
3426
3575
|
return scope.$eval(attrs[type]);
|
3427
3576
|
};
|
3428
3577
|
|
@@ -3430,57 +3579,64 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
3430
3579
|
* Observe the relevant attributes.
|
3431
3580
|
*/
|
3432
3581
|
if (!options.useContentExp) {
|
3433
|
-
attrs.$observe(
|
3582
|
+
attrs.$observe(type, function(val) {
|
3434
3583
|
ttScope.content = val;
|
3435
3584
|
|
3436
3585
|
if (!val && ttScope.isOpen) {
|
3437
3586
|
hide();
|
3438
3587
|
} else {
|
3439
|
-
|
3588
|
+
positionTooltip();
|
3440
3589
|
}
|
3441
3590
|
});
|
3442
3591
|
}
|
3443
3592
|
|
3444
|
-
attrs.$observe(
|
3593
|
+
attrs.$observe('disabled', function(val) {
|
3445
3594
|
if (popupTimeout && val) {
|
3446
3595
|
$timeout.cancel(popupTimeout);
|
3596
|
+
popupTimeout = null;
|
3447
3597
|
}
|
3448
3598
|
|
3449
|
-
if (val && ttScope.isOpen
|
3599
|
+
if (val && ttScope.isOpen) {
|
3450
3600
|
hide();
|
3451
3601
|
}
|
3452
3602
|
});
|
3453
3603
|
|
3454
|
-
attrs.$observe(
|
3604
|
+
attrs.$observe(prefix + 'Title', function(val) {
|
3455
3605
|
ttScope.title = val;
|
3456
|
-
|
3606
|
+
positionTooltip();
|
3457
3607
|
});
|
3458
3608
|
|
3459
|
-
attrs.$observe(
|
3609
|
+
attrs.$observe(prefix + 'Placement', function() {
|
3460
3610
|
if (ttScope.isOpen) {
|
3461
|
-
|
3462
|
-
|
3463
|
-
show()();
|
3464
|
-
}, 0, false);
|
3611
|
+
prepPlacement();
|
3612
|
+
positionTooltip();
|
3465
3613
|
}
|
3466
3614
|
});
|
3467
3615
|
|
3616
|
+
if (isOpenExp) {
|
3617
|
+
scope.$watch(isOpenExp, function(val) {
|
3618
|
+
if (val !== ttScope.isOpen) {
|
3619
|
+
toggleTooltipBind();
|
3620
|
+
}
|
3621
|
+
});
|
3622
|
+
}
|
3623
|
+
|
3468
3624
|
function prepPopupClass() {
|
3469
3625
|
ttScope.popupClass = attrs[prefix + 'Class'];
|
3470
3626
|
}
|
3471
3627
|
|
3472
3628
|
function prepPlacement() {
|
3473
|
-
var val = attrs[
|
3474
|
-
ttScope.placement = angular.isDefined(
|
3629
|
+
var val = attrs[prefix + 'Placement'];
|
3630
|
+
ttScope.placement = angular.isDefined(val) ? val : options.placement;
|
3475
3631
|
}
|
3476
3632
|
|
3477
3633
|
function prepPopupDelay() {
|
3478
|
-
var val = attrs[
|
3479
|
-
var delay = parseInt(
|
3480
|
-
ttScope.popupDelay = !
|
3634
|
+
var val = attrs[prefix + 'PopupDelay'];
|
3635
|
+
var delay = parseInt(val, 10);
|
3636
|
+
ttScope.popupDelay = !isNaN(delay) ? delay : options.popupDelay;
|
3481
3637
|
}
|
3482
3638
|
|
3483
|
-
var unregisterTriggers = function
|
3639
|
+
var unregisterTriggers = function() {
|
3484
3640
|
triggers.show.forEach(function(trigger) {
|
3485
3641
|
element.unbind(trigger, showTooltipBind);
|
3486
3642
|
});
|
@@ -3490,19 +3646,22 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
3490
3646
|
};
|
3491
3647
|
|
3492
3648
|
function prepTriggers() {
|
3493
|
-
var val = attrs[
|
3649
|
+
var val = attrs[prefix + 'Trigger'];
|
3494
3650
|
unregisterTriggers();
|
3495
3651
|
|
3496
|
-
triggers = getTriggers(
|
3652
|
+
triggers = getTriggers(val);
|
3497
3653
|
|
3498
|
-
triggers.show
|
3499
|
-
|
3500
|
-
|
3501
|
-
|
3502
|
-
|
3503
|
-
|
3504
|
-
|
3505
|
-
|
3654
|
+
if (triggers.show !== 'none') {
|
3655
|
+
triggers.show.forEach(function(trigger, idx) {
|
3656
|
+
// Using raw addEventListener due to jqLite/jQuery bug - #4060
|
3657
|
+
if (trigger === triggers.hide[idx]) {
|
3658
|
+
element[0].addEventListener(trigger, toggleTooltipBind);
|
3659
|
+
} else if (trigger) {
|
3660
|
+
element[0].addEventListener(trigger, showTooltipBind);
|
3661
|
+
element[0].addEventListener(triggers.hide[idx], hideTooltipBind);
|
3662
|
+
}
|
3663
|
+
});
|
3664
|
+
}
|
3506
3665
|
}
|
3507
3666
|
prepTriggers();
|
3508
3667
|
|
@@ -3515,18 +3674,19 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
3515
3674
|
// if a tooltip is attached to <body> we need to remove it on
|
3516
3675
|
// location change as its parent scope will probably not be destroyed
|
3517
3676
|
// by the change.
|
3518
|
-
if (
|
3519
|
-
scope.$on('$locationChangeSuccess', function closeTooltipOnLocationChangeSuccess
|
3520
|
-
|
3521
|
-
|
3522
|
-
|
3523
|
-
|
3677
|
+
if (appendToBody) {
|
3678
|
+
scope.$on('$locationChangeSuccess', function closeTooltipOnLocationChangeSuccess() {
|
3679
|
+
if (ttScope.isOpen) {
|
3680
|
+
hide();
|
3681
|
+
}
|
3682
|
+
});
|
3524
3683
|
}
|
3525
3684
|
|
3526
3685
|
// Make sure tooltip is destroyed and removed.
|
3527
3686
|
scope.$on('$destroy', function onDestroyTooltip() {
|
3528
|
-
$timeout.cancel(
|
3529
|
-
$timeout.cancel(
|
3687
|
+
$timeout.cancel(transitionTimeout);
|
3688
|
+
$timeout.cancel(popupTimeout);
|
3689
|
+
$timeout.cancel(positionTimeout);
|
3530
3690
|
unregisterTriggers();
|
3531
3691
|
removeTooltip();
|
3532
3692
|
ttScope = null;
|
@@ -3539,11 +3699,11 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
3539
3699
|
})
|
3540
3700
|
|
3541
3701
|
// This is mostly ngInclude code but with a custom scope
|
3542
|
-
.directive(
|
3702
|
+
.directive('tooltipTemplateTransclude', [
|
3543
3703
|
'$animate', '$sce', '$compile', '$templateRequest',
|
3544
3704
|
function ($animate , $sce , $compile , $templateRequest) {
|
3545
3705
|
return {
|
3546
|
-
link: function
|
3706
|
+
link: function(scope, elem, attrs) {
|
3547
3707
|
var origScope = scope.$eval(attrs.tooltipTemplateTranscludeScope);
|
3548
3708
|
|
3549
3709
|
var changeCounter = 0,
|
@@ -3569,7 +3729,7 @@ function ($animate , $sce , $compile , $templateRequest) {
|
|
3569
3729
|
}
|
3570
3730
|
};
|
3571
3731
|
|
3572
|
-
scope.$watch($sce.parseAsResourceUrl(attrs.tooltipTemplateTransclude), function
|
3732
|
+
scope.$watch($sce.parseAsResourceUrl(attrs.tooltipTemplateTransclude), function(src) {
|
3573
3733
|
var thisChangeId = ++changeCounter;
|
3574
3734
|
|
3575
3735
|
if (src) {
|
@@ -3611,10 +3771,10 @@ function ($animate , $sce , $compile , $templateRequest) {
|
|
3611
3771
|
* They must not be animated as they're expected to be present on the tooltip on
|
3612
3772
|
* initialization.
|
3613
3773
|
*/
|
3614
|
-
.directive('tooltipClasses', function
|
3774
|
+
.directive('tooltipClasses', function() {
|
3615
3775
|
return {
|
3616
3776
|
restrict: 'A',
|
3617
|
-
link: function
|
3777
|
+
link: function(scope, element, attrs) {
|
3618
3778
|
if (scope.placement) {
|
3619
3779
|
element.addClass(scope.placement);
|
3620
3780
|
}
|
@@ -3628,7 +3788,7 @@ function ($animate , $sce , $compile , $templateRequest) {
|
|
3628
3788
|
};
|
3629
3789
|
})
|
3630
3790
|
|
3631
|
-
.directive(
|
3791
|
+
.directive('tooltipPopup', function() {
|
3632
3792
|
return {
|
3633
3793
|
restrict: 'EA',
|
3634
3794
|
replace: true,
|
@@ -3637,11 +3797,11 @@ function ($animate , $sce , $compile , $templateRequest) {
|
|
3637
3797
|
};
|
3638
3798
|
})
|
3639
3799
|
|
3640
|
-
.directive(
|
3641
|
-
return $tooltip(
|
3800
|
+
.directive('tooltip', [ '$tooltip', function($tooltip) {
|
3801
|
+
return $tooltip('tooltip', 'tooltip', 'mouseenter');
|
3642
3802
|
}])
|
3643
3803
|
|
3644
|
-
.directive(
|
3804
|
+
.directive('tooltipTemplatePopup', function() {
|
3645
3805
|
return {
|
3646
3806
|
restrict: 'EA',
|
3647
3807
|
replace: true,
|
@@ -3651,13 +3811,13 @@ function ($animate , $sce , $compile , $templateRequest) {
|
|
3651
3811
|
};
|
3652
3812
|
})
|
3653
3813
|
|
3654
|
-
.directive(
|
3814
|
+
.directive('tooltipTemplate', ['$tooltip', function($tooltip) {
|
3655
3815
|
return $tooltip('tooltipTemplate', 'tooltip', 'mouseenter', {
|
3656
3816
|
useContentExp: true
|
3657
3817
|
});
|
3658
3818
|
}])
|
3659
3819
|
|
3660
|
-
.directive(
|
3820
|
+
.directive('tooltipHtmlPopup', function() {
|
3661
3821
|
return {
|
3662
3822
|
restrict: 'EA',
|
3663
3823
|
replace: true,
|
@@ -3666,7 +3826,7 @@ function ($animate , $sce , $compile , $templateRequest) {
|
|
3666
3826
|
};
|
3667
3827
|
})
|
3668
3828
|
|
3669
|
-
.directive(
|
3829
|
+
.directive('tooltipHtml', ['$tooltip', function($tooltip) {
|
3670
3830
|
return $tooltip('tooltipHtml', 'tooltip', 'mouseenter', {
|
3671
3831
|
useContentExp: true
|
3672
3832
|
});
|
@@ -3675,7 +3835,7 @@ function ($animate , $sce , $compile , $templateRequest) {
|
|
3675
3835
|
/*
|
3676
3836
|
Deprecated
|
3677
3837
|
*/
|
3678
|
-
.directive(
|
3838
|
+
.directive('tooltipHtmlUnsafePopup', function() {
|
3679
3839
|
return {
|
3680
3840
|
restrict: 'EA',
|
3681
3841
|
replace: true,
|
@@ -3685,13 +3845,13 @@ Deprecated
|
|
3685
3845
|
})
|
3686
3846
|
|
3687
3847
|
.value('tooltipHtmlUnsafeSuppressDeprecated', false)
|
3688
|
-
.directive(
|
3848
|
+
.directive('tooltipHtmlUnsafe', [
|
3689
3849
|
'$tooltip', 'tooltipHtmlUnsafeSuppressDeprecated', '$log',
|
3690
|
-
function
|
3850
|
+
function($tooltip , tooltipHtmlUnsafeSuppressDeprecated , $log) {
|
3691
3851
|
if (!tooltipHtmlUnsafeSuppressDeprecated) {
|
3692
3852
|
$log.warn('tooltip-html-unsafe is now deprecated. Use tooltip-html or tooltip-template instead.');
|
3693
3853
|
}
|
3694
|
-
return $tooltip(
|
3854
|
+
return $tooltip('tooltipHtmlUnsafe', 'tooltip', 'mouseenter');
|
3695
3855
|
}]);
|
3696
3856
|
|
3697
3857
|
/**
|
@@ -3699,9 +3859,9 @@ function ( $tooltip , tooltipHtmlUnsafeSuppressDeprecated , $log) {
|
|
3699
3859
|
* function, placement as a function, inside, support for more triggers than
|
3700
3860
|
* just mouse enter/leave, and selector delegatation.
|
3701
3861
|
*/
|
3702
|
-
angular.module( 'ui.bootstrap.popover', [
|
3862
|
+
angular.module( 'ui.bootstrap.popover', ['ui.bootstrap.tooltip'])
|
3703
3863
|
|
3704
|
-
.directive(
|
3864
|
+
.directive('popoverTemplatePopup', function() {
|
3705
3865
|
return {
|
3706
3866
|
restrict: 'EA',
|
3707
3867
|
replace: true,
|
@@ -3711,13 +3871,13 @@ angular.module( 'ui.bootstrap.popover', [ 'ui.bootstrap.tooltip' ] )
|
|
3711
3871
|
};
|
3712
3872
|
})
|
3713
3873
|
|
3714
|
-
.directive(
|
3715
|
-
return $tooltip(
|
3874
|
+
.directive('popoverTemplate', ['$tooltip', function($tooltip) {
|
3875
|
+
return $tooltip('popoverTemplate', 'popover', 'click', {
|
3716
3876
|
useContentExp: true
|
3717
|
-
}
|
3877
|
+
});
|
3718
3878
|
}])
|
3719
3879
|
|
3720
|
-
.directive(
|
3880
|
+
.directive('popoverHtmlPopup', function() {
|
3721
3881
|
return {
|
3722
3882
|
restrict: 'EA',
|
3723
3883
|
replace: true,
|
@@ -3726,13 +3886,13 @@ angular.module( 'ui.bootstrap.popover', [ 'ui.bootstrap.tooltip' ] )
|
|
3726
3886
|
};
|
3727
3887
|
})
|
3728
3888
|
|
3729
|
-
.directive(
|
3889
|
+
.directive('popoverHtml', ['$tooltip', function($tooltip) {
|
3730
3890
|
return $tooltip( 'popoverHtml', 'popover', 'click', {
|
3731
3891
|
useContentExp: true
|
3732
3892
|
});
|
3733
3893
|
}])
|
3734
3894
|
|
3735
|
-
.directive(
|
3895
|
+
.directive('popoverPopup', function() {
|
3736
3896
|
return {
|
3737
3897
|
restrict: 'EA',
|
3738
3898
|
replace: true,
|
@@ -3741,7 +3901,7 @@ angular.module( 'ui.bootstrap.popover', [ 'ui.bootstrap.tooltip' ] )
|
|
3741
3901
|
};
|
3742
3902
|
})
|
3743
3903
|
|
3744
|
-
.directive(
|
3904
|
+
.directive('popover', ['$tooltip', function($tooltip) {
|
3745
3905
|
return $tooltip( 'popover', 'popover', 'click' );
|
3746
3906
|
}]);
|
3747
3907
|
|
@@ -3752,104 +3912,144 @@ angular.module('ui.bootstrap.progressbar', [])
|
|
3752
3912
|
max: 100
|
3753
3913
|
})
|
3754
3914
|
|
3755
|
-
.
|
3756
|
-
var self = this,
|
3757
|
-
animate = angular.isDefined($attrs.animate) ? $scope.$parent.$eval($attrs.animate) : progressConfig.animate;
|
3915
|
+
.value('$progressSuppressWarning', false)
|
3758
3916
|
|
3759
|
-
|
3760
|
-
|
3917
|
+
.controller('ProgressController', ['$scope', '$attrs', 'progressConfig', function($scope, $attrs, progressConfig) {
|
3918
|
+
var self = this,
|
3919
|
+
animate = angular.isDefined($attrs.animate) ? $scope.$parent.$eval($attrs.animate) : progressConfig.animate;
|
3761
3920
|
|
3762
|
-
|
3763
|
-
|
3764
|
-
element.css({'transition': 'none'});
|
3765
|
-
}
|
3921
|
+
this.bars = [];
|
3922
|
+
$scope.max = angular.isDefined($scope.max) ? $scope.max : progressConfig.max;
|
3766
3923
|
|
3767
|
-
|
3924
|
+
this.addBar = function(bar, element) {
|
3925
|
+
if (!animate) {
|
3926
|
+
element.css({'transition': 'none'});
|
3927
|
+
}
|
3768
3928
|
|
3769
|
-
|
3929
|
+
this.bars.push(bar);
|
3770
3930
|
|
3771
|
-
|
3772
|
-
bar.recalculatePercentage();
|
3773
|
-
});
|
3931
|
+
bar.max = $scope.max;
|
3774
3932
|
|
3775
|
-
|
3776
|
-
|
3933
|
+
bar.$watch('value', function(value) {
|
3934
|
+
bar.recalculatePercentage();
|
3935
|
+
});
|
3777
3936
|
|
3778
|
-
|
3779
|
-
|
3780
|
-
totalPercentage += bar.percent;
|
3781
|
-
});
|
3937
|
+
bar.recalculatePercentage = function() {
|
3938
|
+
bar.percent = +(100 * bar.value / bar.max).toFixed(2);
|
3782
3939
|
|
3783
|
-
|
3784
|
-
|
3785
|
-
|
3786
|
-
};
|
3940
|
+
var totalPercentage = self.bars.reduce(function(total, bar) {
|
3941
|
+
return total + bar.percent;
|
3942
|
+
}, 0);
|
3787
3943
|
|
3788
|
-
|
3789
|
-
|
3790
|
-
|
3791
|
-
});
|
3944
|
+
if (totalPercentage > 100) {
|
3945
|
+
bar.percent -= totalPercentage - 100;
|
3946
|
+
}
|
3792
3947
|
};
|
3793
3948
|
|
3794
|
-
|
3795
|
-
|
3796
|
-
|
3949
|
+
bar.$on('$destroy', function() {
|
3950
|
+
element = null;
|
3951
|
+
self.removeBar(bar);
|
3952
|
+
});
|
3953
|
+
};
|
3797
3954
|
|
3798
|
-
|
3799
|
-
|
3800
|
-
|
3801
|
-
|
3802
|
-
|
3955
|
+
this.removeBar = function(bar) {
|
3956
|
+
this.bars.splice(this.bars.indexOf(bar), 1);
|
3957
|
+
};
|
3958
|
+
|
3959
|
+
$scope.$watch('max', function(max) {
|
3960
|
+
self.bars.forEach(function(bar) {
|
3961
|
+
bar.max = $scope.max;
|
3962
|
+
bar.recalculatePercentage();
|
3803
3963
|
});
|
3964
|
+
});
|
3804
3965
|
}])
|
3805
3966
|
|
3806
|
-
.directive('
|
3807
|
-
|
3808
|
-
|
3809
|
-
|
3810
|
-
|
3811
|
-
|
3812
|
-
|
3813
|
-
|
3814
|
-
|
3815
|
-
|
3816
|
-
|
3817
|
-
|
3967
|
+
.directive('uibProgress', function() {
|
3968
|
+
return {
|
3969
|
+
restrict: 'EA',
|
3970
|
+
replace: true,
|
3971
|
+
transclude: true,
|
3972
|
+
controller: 'ProgressController',
|
3973
|
+
require: 'uibProgress',
|
3974
|
+
scope: {
|
3975
|
+
max: '=?'
|
3976
|
+
},
|
3977
|
+
templateUrl: 'template/progressbar/progress.html'
|
3978
|
+
};
|
3818
3979
|
})
|
3819
3980
|
|
3820
|
-
.directive('
|
3821
|
-
|
3822
|
-
|
3823
|
-
|
3824
|
-
|
3825
|
-
|
3826
|
-
|
3827
|
-
|
3828
|
-
|
3829
|
-
|
3830
|
-
|
3831
|
-
|
3832
|
-
|
3833
|
-
|
3834
|
-
|
3981
|
+
.directive('progress', ['$log', '$progressSuppressWarning', function($log, $progressSuppressWarning) {
|
3982
|
+
return {
|
3983
|
+
restrict: 'EA',
|
3984
|
+
replace: true,
|
3985
|
+
transclude: true,
|
3986
|
+
controller: 'ProgressController',
|
3987
|
+
require: 'progress',
|
3988
|
+
scope: {
|
3989
|
+
max: '=?'
|
3990
|
+
},
|
3991
|
+
templateUrl: 'template/progressbar/progress.html',
|
3992
|
+
link: function() {
|
3993
|
+
if ($progressSuppressWarning) {
|
3994
|
+
$log.warn('progress is now deprecated. Use uib-progress instead');
|
3995
|
+
}
|
3996
|
+
}
|
3997
|
+
};
|
3998
|
+
}])
|
3999
|
+
|
4000
|
+
.directive('uibBar', function() {
|
4001
|
+
return {
|
4002
|
+
restrict: 'EA',
|
4003
|
+
replace: true,
|
4004
|
+
transclude: true,
|
4005
|
+
require: '^uibProgress',
|
4006
|
+
scope: {
|
4007
|
+
value: '=',
|
4008
|
+
type: '@'
|
4009
|
+
},
|
4010
|
+
templateUrl: 'template/progressbar/bar.html',
|
4011
|
+
link: function(scope, element, attrs, progressCtrl) {
|
4012
|
+
progressCtrl.addBar(scope, element);
|
4013
|
+
}
|
4014
|
+
};
|
3835
4015
|
})
|
3836
4016
|
|
4017
|
+
.directive('bar', ['$log', '$progressSuppressWarning', function($log, $progressSuppressWarning) {
|
4018
|
+
return {
|
4019
|
+
restrict: 'EA',
|
4020
|
+
replace: true,
|
4021
|
+
transclude: true,
|
4022
|
+
require: '^progress',
|
4023
|
+
scope: {
|
4024
|
+
value: '=',
|
4025
|
+
type: '@'
|
4026
|
+
},
|
4027
|
+
templateUrl: 'template/progressbar/bar.html',
|
4028
|
+
link: function(scope, element, attrs, progressCtrl) {
|
4029
|
+
if ($progressSuppressWarning) {
|
4030
|
+
$log.warn('bar is now deprecated. Use uib-bar instead');
|
4031
|
+
}
|
4032
|
+
progressCtrl.addBar(scope, element);
|
4033
|
+
}
|
4034
|
+
};
|
4035
|
+
}])
|
4036
|
+
|
3837
4037
|
.directive('progressbar', function() {
|
3838
|
-
|
3839
|
-
|
3840
|
-
|
3841
|
-
|
3842
|
-
|
3843
|
-
|
3844
|
-
|
3845
|
-
|
3846
|
-
|
3847
|
-
|
3848
|
-
|
3849
|
-
|
3850
|
-
|
3851
|
-
|
3852
|
-
|
4038
|
+
return {
|
4039
|
+
restrict: 'EA',
|
4040
|
+
replace: true,
|
4041
|
+
transclude: true,
|
4042
|
+
controller: 'ProgressController',
|
4043
|
+
scope: {
|
4044
|
+
value: '=',
|
4045
|
+
max: '=?',
|
4046
|
+
type: '@'
|
4047
|
+
},
|
4048
|
+
templateUrl: 'template/progressbar/progressbar.html',
|
4049
|
+
link: function(scope, element, attrs, progressCtrl) {
|
4050
|
+
progressCtrl.addBar(scope, angular.element(element.children()[0]));
|
4051
|
+
}
|
4052
|
+
};
|
3853
4053
|
});
|
3854
4054
|
|
3855
4055
|
angular.module('ui.bootstrap.rating', [])
|
@@ -3877,12 +4077,13 @@ angular.module('ui.bootstrap.rating', [])
|
|
3877
4077
|
|
3878
4078
|
this.stateOn = angular.isDefined($attrs.stateOn) ? $scope.$parent.$eval($attrs.stateOn) : ratingConfig.stateOn;
|
3879
4079
|
this.stateOff = angular.isDefined($attrs.stateOff) ? $scope.$parent.$eval($attrs.stateOff) : ratingConfig.stateOff;
|
3880
|
-
var tmpTitles = angular.isDefined($attrs.titles) ? $scope.$parent.$eval($attrs.titles) : ratingConfig.titles ;
|
4080
|
+
var tmpTitles = angular.isDefined($attrs.titles) ? $scope.$parent.$eval($attrs.titles) : ratingConfig.titles ;
|
3881
4081
|
this.titles = angular.isArray(tmpTitles) && tmpTitles.length > 0 ?
|
3882
4082
|
tmpTitles : ratingConfig.titles;
|
3883
|
-
|
3884
|
-
var ratingStates = angular.isDefined($attrs.ratingStates) ?
|
3885
|
-
|
4083
|
+
|
4084
|
+
var ratingStates = angular.isDefined($attrs.ratingStates) ?
|
4085
|
+
$scope.$parent.$eval($attrs.ratingStates) :
|
4086
|
+
new Array(angular.isDefined($attrs.max) ? $scope.$parent.$eval($attrs.max) : ratingConfig.max);
|
3886
4087
|
$scope.range = this.buildTemplateObjects(ratingStates);
|
3887
4088
|
};
|
3888
4089
|
|
@@ -3892,7 +4093,7 @@ angular.module('ui.bootstrap.rating', [])
|
|
3892
4093
|
}
|
3893
4094
|
return states;
|
3894
4095
|
};
|
3895
|
-
|
4096
|
+
|
3896
4097
|
this.getTitle = function(index) {
|
3897
4098
|
if (index >= this.titles.length) {
|
3898
4099
|
return index + 1;
|
@@ -3900,16 +4101,16 @@ angular.module('ui.bootstrap.rating', [])
|
|
3900
4101
|
return this.titles[index];
|
3901
4102
|
}
|
3902
4103
|
};
|
3903
|
-
|
4104
|
+
|
3904
4105
|
$scope.rate = function(value) {
|
3905
|
-
if (
|
4106
|
+
if (!$scope.readonly && value >= 0 && value <= $scope.range.length) {
|
3906
4107
|
ngModelCtrl.$setViewValue(ngModelCtrl.$viewValue === value ? 0 : value);
|
3907
4108
|
ngModelCtrl.$render();
|
3908
4109
|
}
|
3909
4110
|
};
|
3910
4111
|
|
3911
4112
|
$scope.enter = function(value) {
|
3912
|
-
if (
|
4113
|
+
if (!$scope.readonly) {
|
3913
4114
|
$scope.value = value;
|
3914
4115
|
}
|
3915
4116
|
$scope.onHover({value: value});
|
@@ -3924,7 +4125,7 @@ angular.module('ui.bootstrap.rating', [])
|
|
3924
4125
|
if (/(37|38|39|40)/.test(evt.which)) {
|
3925
4126
|
evt.preventDefault();
|
3926
4127
|
evt.stopPropagation();
|
3927
|
-
$scope.rate(
|
4128
|
+
$scope.rate($scope.value + (evt.which === 38 || evt.which === 39 ? 1 : -1));
|
3928
4129
|
}
|
3929
4130
|
};
|
3930
4131
|
|
@@ -3972,10 +4173,15 @@ angular.module('ui.bootstrap.tabs', [])
|
|
3972
4173
|
if (tab.active && tab !== selectedTab) {
|
3973
4174
|
tab.active = false;
|
3974
4175
|
tab.onDeselect();
|
4176
|
+
selectedTab.selectCalled = false;
|
3975
4177
|
}
|
3976
4178
|
});
|
3977
4179
|
selectedTab.active = true;
|
3978
|
-
|
4180
|
+
// only call select if it has not already been called
|
4181
|
+
if (!selectedTab.selectCalled) {
|
4182
|
+
selectedTab.onSelect();
|
4183
|
+
selectedTab.selectCalled = true;
|
4184
|
+
}
|
3979
4185
|
};
|
3980
4186
|
|
3981
4187
|
ctrl.addTab = function addTab(tab) {
|
@@ -3986,8 +4192,7 @@ angular.module('ui.bootstrap.tabs', [])
|
|
3986
4192
|
tab.active = true;
|
3987
4193
|
} else if (tab.active) {
|
3988
4194
|
ctrl.select(tab);
|
3989
|
-
}
|
3990
|
-
else {
|
4195
|
+
} else {
|
3991
4196
|
tab.active = false;
|
3992
4197
|
}
|
3993
4198
|
};
|
@@ -4161,7 +4366,7 @@ angular.module('ui.bootstrap.tabs', [])
|
|
4161
4366
|
});
|
4162
4367
|
|
4163
4368
|
scope.disabled = false;
|
4164
|
-
if (
|
4369
|
+
if (attrs.disable) {
|
4165
4370
|
scope.$parent.$watch($parse(attrs.disable), function(value) {
|
4166
4371
|
scope.disabled = !! value;
|
4167
4372
|
});
|
@@ -4171,7 +4376,7 @@ angular.module('ui.bootstrap.tabs', [])
|
|
4171
4376
|
// fix(tab): IE9 disabled attr renders grey text on enabled tab #2677
|
4172
4377
|
// This code is duplicated from the lines above to make it easy to remove once
|
4173
4378
|
// the feature has been completely deprecated
|
4174
|
-
if (
|
4379
|
+
if (attrs.disabled) {
|
4175
4380
|
$log.warn('Use of "disabled" attribute has been deprecated, please use "disable"');
|
4176
4381
|
scope.$parent.$watch($parse(attrs.disabled), function(value) {
|
4177
4382
|
scope.disabled = !! value;
|
@@ -4179,7 +4384,7 @@ angular.module('ui.bootstrap.tabs', [])
|
|
4179
4384
|
}
|
4180
4385
|
|
4181
4386
|
scope.select = function() {
|
4182
|
-
if (
|
4387
|
+
if (!scope.disabled) {
|
4183
4388
|
scope.active = true;
|
4184
4389
|
}
|
4185
4390
|
};
|
@@ -4196,7 +4401,7 @@ angular.module('ui.bootstrap.tabs', [])
|
|
4196
4401
|
};
|
4197
4402
|
}])
|
4198
4403
|
|
4199
|
-
.directive('tabHeadingTransclude',
|
4404
|
+
.directive('tabHeadingTransclude', function() {
|
4200
4405
|
return {
|
4201
4406
|
restrict: 'A',
|
4202
4407
|
require: '^tab',
|
@@ -4209,7 +4414,7 @@ angular.module('ui.bootstrap.tabs', [])
|
|
4209
4414
|
});
|
4210
4415
|
}
|
4211
4416
|
};
|
4212
|
-
}
|
4417
|
+
})
|
4213
4418
|
|
4214
4419
|
.directive('tabContentTransclude', function() {
|
4215
4420
|
return {
|
@@ -4232,17 +4437,18 @@ angular.module('ui.bootstrap.tabs', [])
|
|
4232
4437
|
});
|
4233
4438
|
}
|
4234
4439
|
};
|
4440
|
+
|
4235
4441
|
function isTabHeading(node) {
|
4236
|
-
return node.tagName &&
|
4442
|
+
return node.tagName && (
|
4237
4443
|
node.hasAttribute('tab-heading') ||
|
4238
4444
|
node.hasAttribute('data-tab-heading') ||
|
4445
|
+
node.hasAttribute('x-tab-heading') ||
|
4239
4446
|
node.tagName.toLowerCase() === 'tab-heading' ||
|
4240
|
-
node.tagName.toLowerCase() === 'data-tab-heading'
|
4447
|
+
node.tagName.toLowerCase() === 'data-tab-heading' ||
|
4448
|
+
node.tagName.toLowerCase() === 'x-tab-heading'
|
4241
4449
|
);
|
4242
4450
|
}
|
4243
|
-
})
|
4244
|
-
|
4245
|
-
;
|
4451
|
+
});
|
4246
4452
|
|
4247
4453
|
angular.module('ui.bootstrap.timepicker', [])
|
4248
4454
|
|
@@ -4262,29 +4468,29 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
4262
4468
|
ngModelCtrl = { $setViewValue: angular.noop }, // nullModelCtrl
|
4263
4469
|
meridians = angular.isDefined($attrs.meridians) ? $scope.$parent.$eval($attrs.meridians) : timepickerConfig.meridians || $locale.DATETIME_FORMATS.AMPMS;
|
4264
4470
|
|
4265
|
-
this.init = function(
|
4471
|
+
this.init = function(ngModelCtrl_, inputs) {
|
4266
4472
|
ngModelCtrl = ngModelCtrl_;
|
4267
4473
|
ngModelCtrl.$render = this.render;
|
4268
4474
|
|
4269
|
-
ngModelCtrl.$formatters.unshift(function
|
4270
|
-
return modelValue ? new Date(
|
4475
|
+
ngModelCtrl.$formatters.unshift(function(modelValue) {
|
4476
|
+
return modelValue ? new Date(modelValue) : null;
|
4271
4477
|
});
|
4272
4478
|
|
4273
4479
|
var hoursInputEl = inputs.eq(0),
|
4274
4480
|
minutesInputEl = inputs.eq(1);
|
4275
4481
|
|
4276
4482
|
var mousewheel = angular.isDefined($attrs.mousewheel) ? $scope.$parent.$eval($attrs.mousewheel) : timepickerConfig.mousewheel;
|
4277
|
-
if (
|
4278
|
-
this.setupMousewheelEvents(
|
4483
|
+
if (mousewheel) {
|
4484
|
+
this.setupMousewheelEvents(hoursInputEl, minutesInputEl);
|
4279
4485
|
}
|
4280
4486
|
|
4281
4487
|
var arrowkeys = angular.isDefined($attrs.arrowkeys) ? $scope.$parent.$eval($attrs.arrowkeys) : timepickerConfig.arrowkeys;
|
4282
4488
|
if (arrowkeys) {
|
4283
|
-
this.setupArrowkeyEvents(
|
4489
|
+
this.setupArrowkeyEvents(hoursInputEl, minutesInputEl);
|
4284
4490
|
}
|
4285
4491
|
|
4286
4492
|
$scope.readonlyInput = angular.isDefined($attrs.readonlyInput) ? $scope.$parent.$eval($attrs.readonlyInput) : timepickerConfig.readonlyInput;
|
4287
|
-
this.setupInputEvents(
|
4493
|
+
this.setupInputEvents(hoursInputEl, minutesInputEl);
|
4288
4494
|
};
|
4289
4495
|
|
4290
4496
|
var hourStep = timepickerConfig.hourStep;
|
@@ -4320,7 +4526,7 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
4320
4526
|
};
|
4321
4527
|
|
4322
4528
|
$scope.noDecrementHours = function() {
|
4323
|
-
var decrementedSelected = addMinutes(selected, -
|
4529
|
+
var decrementedSelected = addMinutes(selected, -hourStep * 60);
|
4324
4530
|
return decrementedSelected < min ||
|
4325
4531
|
(decrementedSelected > selected && decrementedSelected > max);
|
4326
4532
|
};
|
@@ -4332,7 +4538,7 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
4332
4538
|
};
|
4333
4539
|
|
4334
4540
|
$scope.noDecrementMinutes = function() {
|
4335
|
-
var decrementedSelected = addMinutes(selected, -
|
4541
|
+
var decrementedSelected = addMinutes(selected, -minuteStep);
|
4336
4542
|
return decrementedSelected < min ||
|
4337
4543
|
(decrementedSelected > selected && decrementedSelected > max);
|
4338
4544
|
};
|
@@ -4341,7 +4547,7 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
4341
4547
|
if (selected.getHours() < 13) {
|
4342
4548
|
return addMinutes(selected, 12 * 60) > max;
|
4343
4549
|
} else {
|
4344
|
-
return addMinutes(selected, -
|
4550
|
+
return addMinutes(selected, -12 * 60) < min;
|
4345
4551
|
}
|
4346
4552
|
};
|
4347
4553
|
|
@@ -4351,11 +4557,11 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
4351
4557
|
$scope.$parent.$watch($parse($attrs.showMeridian), function(value) {
|
4352
4558
|
$scope.showMeridian = !!value;
|
4353
4559
|
|
4354
|
-
if (
|
4560
|
+
if (ngModelCtrl.$error.time) {
|
4355
4561
|
// Evaluate from template
|
4356
4562
|
var hours = getHoursFromTemplate(), minutes = getMinutesFromTemplate();
|
4357
|
-
if (angular.isDefined(
|
4358
|
-
selected.setHours(
|
4563
|
+
if (angular.isDefined(hours) && angular.isDefined(minutes)) {
|
4564
|
+
selected.setHours(hours);
|
4359
4565
|
refresh();
|
4360
4566
|
}
|
4361
4567
|
} else {
|
@@ -4365,18 +4571,18 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
4365
4571
|
}
|
4366
4572
|
|
4367
4573
|
// Get $scope.hours in 24H mode if valid
|
4368
|
-
function getHoursFromTemplate
|
4369
|
-
var hours = parseInt(
|
4370
|
-
var valid =
|
4371
|
-
if (
|
4574
|
+
function getHoursFromTemplate() {
|
4575
|
+
var hours = parseInt($scope.hours, 10);
|
4576
|
+
var valid = $scope.showMeridian ? (hours > 0 && hours < 13) : (hours >= 0 && hours < 24);
|
4577
|
+
if (!valid) {
|
4372
4578
|
return undefined;
|
4373
4579
|
}
|
4374
4580
|
|
4375
|
-
if (
|
4376
|
-
if (
|
4581
|
+
if ($scope.showMeridian) {
|
4582
|
+
if (hours === 12) {
|
4377
4583
|
hours = 0;
|
4378
4584
|
}
|
4379
|
-
if (
|
4585
|
+
if ($scope.meridian === meridians[1]) {
|
4380
4586
|
hours = hours + 12;
|
4381
4587
|
}
|
4382
4588
|
}
|
@@ -4385,15 +4591,15 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
4385
4591
|
|
4386
4592
|
function getMinutesFromTemplate() {
|
4387
4593
|
var minutes = parseInt($scope.minutes, 10);
|
4388
|
-
return (
|
4594
|
+
return (minutes >= 0 && minutes < 60) ? minutes : undefined;
|
4389
4595
|
}
|
4390
4596
|
|
4391
|
-
function pad(
|
4392
|
-
return (
|
4597
|
+
function pad(value) {
|
4598
|
+
return (angular.isDefined(value) && value.toString().length < 2) ? '0' + value : value.toString();
|
4393
4599
|
}
|
4394
4600
|
|
4395
4601
|
// Respond on mousewheel spin
|
4396
|
-
this.setupMousewheelEvents = function(
|
4602
|
+
this.setupMousewheelEvents = function(hoursInputEl, minutesInputEl) {
|
4397
4603
|
var isScrollingUp = function(e) {
|
4398
4604
|
if (e.originalEvent) {
|
4399
4605
|
e = e.originalEvent;
|
@@ -4404,26 +4610,25 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
4404
4610
|
};
|
4405
4611
|
|
4406
4612
|
hoursInputEl.bind('mousewheel wheel', function(e) {
|
4407
|
-
$scope.$apply(
|
4613
|
+
$scope.$apply(isScrollingUp(e) ? $scope.incrementHours() : $scope.decrementHours());
|
4408
4614
|
e.preventDefault();
|
4409
4615
|
});
|
4410
4616
|
|
4411
4617
|
minutesInputEl.bind('mousewheel wheel', function(e) {
|
4412
|
-
$scope.$apply(
|
4618
|
+
$scope.$apply(isScrollingUp(e) ? $scope.incrementMinutes() : $scope.decrementMinutes());
|
4413
4619
|
e.preventDefault();
|
4414
4620
|
});
|
4415
4621
|
|
4416
4622
|
};
|
4417
4623
|
|
4418
4624
|
// Respond on up/down arrowkeys
|
4419
|
-
this.setupArrowkeyEvents = function(
|
4625
|
+
this.setupArrowkeyEvents = function(hoursInputEl, minutesInputEl) {
|
4420
4626
|
hoursInputEl.bind('keydown', function(e) {
|
4421
|
-
if (
|
4627
|
+
if (e.which === 38) { // up
|
4422
4628
|
e.preventDefault();
|
4423
4629
|
$scope.incrementHours();
|
4424
4630
|
$scope.$apply();
|
4425
|
-
}
|
4426
|
-
else if ( e.which === 40 ) { // down
|
4631
|
+
} else if (e.which === 40) { // down
|
4427
4632
|
e.preventDefault();
|
4428
4633
|
$scope.decrementHours();
|
4429
4634
|
$scope.$apply();
|
@@ -4431,12 +4636,11 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
4431
4636
|
});
|
4432
4637
|
|
4433
4638
|
minutesInputEl.bind('keydown', function(e) {
|
4434
|
-
if (
|
4639
|
+
if (e.which === 38) { // up
|
4435
4640
|
e.preventDefault();
|
4436
4641
|
$scope.incrementMinutes();
|
4437
4642
|
$scope.$apply();
|
4438
|
-
}
|
4439
|
-
else if ( e.which === 40 ) { // down
|
4643
|
+
} else if (e.which === 40) { // down
|
4440
4644
|
e.preventDefault();
|
4441
4645
|
$scope.decrementMinutes();
|
4442
4646
|
$scope.$apply();
|
@@ -4444,15 +4648,15 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
4444
4648
|
});
|
4445
4649
|
};
|
4446
4650
|
|
4447
|
-
this.setupInputEvents = function(
|
4448
|
-
if (
|
4651
|
+
this.setupInputEvents = function(hoursInputEl, minutesInputEl) {
|
4652
|
+
if ($scope.readonlyInput) {
|
4449
4653
|
$scope.updateHours = angular.noop;
|
4450
4654
|
$scope.updateMinutes = angular.noop;
|
4451
4655
|
return;
|
4452
4656
|
}
|
4453
4657
|
|
4454
4658
|
var invalidate = function(invalidHours, invalidMinutes) {
|
4455
|
-
ngModelCtrl.$setViewValue(
|
4659
|
+
ngModelCtrl.$setViewValue(null);
|
4456
4660
|
ngModelCtrl.$setValidity('time', false);
|
4457
4661
|
if (angular.isDefined(invalidHours)) {
|
4458
4662
|
$scope.invalidHours = invalidHours;
|
@@ -4463,14 +4667,15 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
4463
4667
|
};
|
4464
4668
|
|
4465
4669
|
$scope.updateHours = function() {
|
4466
|
-
var hours = getHoursFromTemplate()
|
4670
|
+
var hours = getHoursFromTemplate(),
|
4671
|
+
minutes = getMinutesFromTemplate();
|
4467
4672
|
|
4468
|
-
if (
|
4469
|
-
selected.setHours(
|
4673
|
+
if (angular.isDefined(hours) && angular.isDefined(minutes)) {
|
4674
|
+
selected.setHours(hours);
|
4470
4675
|
if (selected < min || selected > max) {
|
4471
4676
|
invalidate(true);
|
4472
4677
|
} else {
|
4473
|
-
refresh(
|
4678
|
+
refresh('h');
|
4474
4679
|
}
|
4475
4680
|
} else {
|
4476
4681
|
invalidate(true);
|
@@ -4478,22 +4683,23 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
4478
4683
|
};
|
4479
4684
|
|
4480
4685
|
hoursInputEl.bind('blur', function(e) {
|
4481
|
-
if (
|
4482
|
-
$scope.$apply(
|
4483
|
-
$scope.hours = pad(
|
4686
|
+
if (!$scope.invalidHours && $scope.hours < 10) {
|
4687
|
+
$scope.$apply(function() {
|
4688
|
+
$scope.hours = pad($scope.hours);
|
4484
4689
|
});
|
4485
4690
|
}
|
4486
4691
|
});
|
4487
4692
|
|
4488
4693
|
$scope.updateMinutes = function() {
|
4489
|
-
var minutes = getMinutesFromTemplate()
|
4694
|
+
var minutes = getMinutesFromTemplate(),
|
4695
|
+
hours = getHoursFromTemplate();
|
4490
4696
|
|
4491
|
-
if (
|
4492
|
-
selected.setMinutes(
|
4697
|
+
if (angular.isDefined(minutes) && angular.isDefined(hours)) {
|
4698
|
+
selected.setMinutes(minutes);
|
4493
4699
|
if (selected < min || selected > max) {
|
4494
4700
|
invalidate(undefined, true);
|
4495
4701
|
} else {
|
4496
|
-
refresh(
|
4702
|
+
refresh('m');
|
4497
4703
|
}
|
4498
4704
|
} else {
|
4499
4705
|
invalidate(undefined, true);
|
@@ -4501,9 +4707,9 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
4501
4707
|
};
|
4502
4708
|
|
4503
4709
|
minutesInputEl.bind('blur', function(e) {
|
4504
|
-
if (
|
4505
|
-
$scope.$apply(
|
4506
|
-
$scope.minutes = pad(
|
4710
|
+
if (!$scope.invalidMinutes && $scope.minutes < 10) {
|
4711
|
+
$scope.$apply(function() {
|
4712
|
+
$scope.minutes = pad($scope.minutes);
|
4507
4713
|
});
|
4508
4714
|
}
|
4509
4715
|
});
|
@@ -4513,11 +4719,11 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
4513
4719
|
this.render = function() {
|
4514
4720
|
var date = ngModelCtrl.$viewValue;
|
4515
4721
|
|
4516
|
-
if (
|
4722
|
+
if (isNaN(date)) {
|
4517
4723
|
ngModelCtrl.$setValidity('time', false);
|
4518
4724
|
$log.error('Timepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.');
|
4519
4725
|
} else {
|
4520
|
-
if (
|
4726
|
+
if (date) {
|
4521
4727
|
selected = date;
|
4522
4728
|
}
|
4523
4729
|
|
@@ -4533,10 +4739,10 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
4533
4739
|
};
|
4534
4740
|
|
4535
4741
|
// Call internally when we know that model is valid.
|
4536
|
-
function refresh(
|
4742
|
+
function refresh(keyboardChange) {
|
4537
4743
|
makeValid();
|
4538
|
-
ngModelCtrl.$setViewValue(
|
4539
|
-
updateTemplate(
|
4744
|
+
ngModelCtrl.$setViewValue(new Date(selected));
|
4745
|
+
updateTemplate(keyboardChange);
|
4540
4746
|
}
|
4541
4747
|
|
4542
4748
|
function makeValid() {
|
@@ -4545,11 +4751,11 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
4545
4751
|
$scope.invalidMinutes = false;
|
4546
4752
|
}
|
4547
4753
|
|
4548
|
-
function updateTemplate(
|
4754
|
+
function updateTemplate(keyboardChange) {
|
4549
4755
|
var hours = selected.getHours(), minutes = selected.getMinutes();
|
4550
4756
|
|
4551
|
-
if (
|
4552
|
-
hours = (
|
4757
|
+
if ($scope.showMeridian) {
|
4758
|
+
hours = (hours === 0 || hours === 12) ? 12 : hours % 12; // Convert 24 to 12 hour system
|
4553
4759
|
}
|
4554
4760
|
|
4555
4761
|
$scope.hours = keyboardChange === 'h' ? hours : pad(hours);
|
@@ -4559,15 +4765,15 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
4559
4765
|
$scope.meridian = selected.getHours() < 12 ? meridians[0] : meridians[1];
|
4560
4766
|
}
|
4561
4767
|
|
4562
|
-
function addMinutes(date,
|
4768
|
+
function addMinutes(date, minutes) {
|
4563
4769
|
var dt = new Date(date.getTime() + minutes * 60000);
|
4564
4770
|
var newDate = new Date(date);
|
4565
4771
|
newDate.setHours(dt.getHours(), dt.getMinutes());
|
4566
4772
|
return newDate;
|
4567
4773
|
}
|
4568
4774
|
|
4569
|
-
function addMinutesToSelected(
|
4570
|
-
selected = addMinutes(
|
4775
|
+
function addMinutesToSelected(minutes) {
|
4776
|
+
selected = addMinutes(selected, minutes);
|
4571
4777
|
refresh();
|
4572
4778
|
}
|
4573
4779
|
|
@@ -4579,21 +4785,25 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
4579
4785
|
addMinutesToSelected(hourStep * 60);
|
4580
4786
|
}
|
4581
4787
|
};
|
4788
|
+
|
4582
4789
|
$scope.decrementHours = function() {
|
4583
4790
|
if (!$scope.noDecrementHours()) {
|
4584
4791
|
addMinutesToSelected(-hourStep * 60);
|
4585
4792
|
}
|
4586
4793
|
};
|
4794
|
+
|
4587
4795
|
$scope.incrementMinutes = function() {
|
4588
4796
|
if (!$scope.noIncrementMinutes()) {
|
4589
4797
|
addMinutesToSelected(minuteStep);
|
4590
4798
|
}
|
4591
4799
|
};
|
4800
|
+
|
4592
4801
|
$scope.decrementMinutes = function() {
|
4593
4802
|
if (!$scope.noDecrementMinutes()) {
|
4594
4803
|
addMinutesToSelected(-minuteStep);
|
4595
4804
|
}
|
4596
4805
|
};
|
4806
|
+
|
4597
4807
|
$scope.toggleMeridian = function() {
|
4598
4808
|
if (!$scope.noToggleMeridian()) {
|
4599
4809
|
addMinutesToSelected(12 * 60 * (selected.getHours() < 12 ? 1 : -1));
|
@@ -4601,19 +4811,22 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
4601
4811
|
};
|
4602
4812
|
}])
|
4603
4813
|
|
4604
|
-
.directive('timepicker', function
|
4814
|
+
.directive('timepicker', function() {
|
4605
4815
|
return {
|
4606
4816
|
restrict: 'EA',
|
4607
4817
|
require: ['timepicker', '?^ngModel'],
|
4608
4818
|
controller:'TimepickerController',
|
4819
|
+
controllerAs: 'timepicker',
|
4609
4820
|
replace: true,
|
4610
4821
|
scope: {},
|
4611
|
-
templateUrl:
|
4822
|
+
templateUrl: function(element, attrs) {
|
4823
|
+
return attrs.templateUrl || 'template/timepicker/timepicker.html';
|
4824
|
+
},
|
4612
4825
|
link: function(scope, element, attrs, ctrls) {
|
4613
4826
|
var timepickerCtrl = ctrls[0], ngModelCtrl = ctrls[1];
|
4614
4827
|
|
4615
|
-
if (
|
4616
|
-
timepickerCtrl.init(
|
4828
|
+
if (ngModelCtrl) {
|
4829
|
+
timepickerCtrl.init(ngModelCtrl, element.find('input'));
|
4617
4830
|
}
|
4618
4831
|
}
|
4619
4832
|
};
|
@@ -4709,20 +4922,19 @@ function($q , $timeout , $rootScope , $log , $transitionSuppressDeprecated)
|
|
4709
4922
|
return $transition;
|
4710
4923
|
}]);
|
4711
4924
|
|
4712
|
-
angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'
|
4925
|
+
angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
|
4713
4926
|
|
4714
4927
|
/**
|
4715
4928
|
* A helper service that can parse typeahead's syntax (string provided by users)
|
4716
4929
|
* Extracted to a separate service for ease of unit testing
|
4717
4930
|
*/
|
4718
|
-
.factory('typeaheadParser', ['$parse', function
|
4931
|
+
.factory('typeaheadParser', ['$parse', function($parse) {
|
4719
4932
|
|
4720
4933
|
// 00000111000000000000022200000000000000003333333333333330000000000044000
|
4721
4934
|
var TYPEAHEAD_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w\d]*))\s+in\s+([\s\S]+?)$/;
|
4722
4935
|
|
4723
4936
|
return {
|
4724
|
-
parse:function
|
4725
|
-
|
4937
|
+
parse: function(input) {
|
4726
4938
|
var match = input.match(TYPEAHEAD_REGEXP);
|
4727
4939
|
if (!match) {
|
4728
4940
|
throw new Error(
|
@@ -4741,461 +4953,469 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
|
|
4741
4953
|
}])
|
4742
4954
|
|
4743
4955
|
.directive('typeahead', ['$compile', '$parse', '$q', '$timeout', '$document', '$window', '$rootScope', '$position', 'typeaheadParser',
|
4744
|
-
|
4745
|
-
|
4746
|
-
|
4747
|
-
var eventDebounceTime = 200;
|
4956
|
+
function($compile, $parse, $q, $timeout, $document, $window, $rootScope, $position, typeaheadParser) {
|
4957
|
+
var HOT_KEYS = [9, 13, 27, 38, 40];
|
4958
|
+
var eventDebounceTime = 200;
|
4748
4959
|
|
4749
|
-
|
4750
|
-
|
4751
|
-
|
4752
|
-
|
4753
|
-
|
4754
|
-
|
4755
|
-
|
4756
|
-
|
4757
|
-
|
4758
|
-
minLength
|
4759
|
-
|
4760
|
-
|
4761
|
-
//minimal wait time after last character typed before typeahead kicks-in
|
4762
|
-
var waitTime = originalScope.$eval(attrs.typeaheadWaitMs) || 0;
|
4960
|
+
return {
|
4961
|
+
require: ['ngModel', '^?ngModelOptions'],
|
4962
|
+
link: function(originalScope, element, attrs, ctrls) {
|
4963
|
+
var modelCtrl = ctrls[0];
|
4964
|
+
var ngModelOptions = ctrls[1];
|
4965
|
+
//SUPPORTED ATTRIBUTES (OPTIONS)
|
4966
|
+
|
4967
|
+
//minimal no of characters that needs to be entered before typeahead kicks-in
|
4968
|
+
var minLength = originalScope.$eval(attrs.typeaheadMinLength);
|
4969
|
+
if (!minLength && minLength !== 0) {
|
4970
|
+
minLength = 1;
|
4971
|
+
}
|
4763
4972
|
|
4764
|
-
|
4765
|
-
|
4973
|
+
//minimal wait time after last character typed before typeahead kicks-in
|
4974
|
+
var waitTime = originalScope.$eval(attrs.typeaheadWaitMs) || 0;
|
4766
4975
|
|
4767
|
-
|
4768
|
-
|
4976
|
+
//should it restrict model values to the ones selected from the popup only?
|
4977
|
+
var isEditable = originalScope.$eval(attrs.typeaheadEditable) !== false;
|
4769
4978
|
|
4770
|
-
|
4771
|
-
|
4979
|
+
//binding to a variable that indicates if matches are being retrieved asynchronously
|
4980
|
+
var isLoadingSetter = $parse(attrs.typeaheadLoading).assign || angular.noop;
|
4772
4981
|
|
4773
|
-
|
4774
|
-
|
4982
|
+
//a callback executed when a match is selected
|
4983
|
+
var onSelectCallback = $parse(attrs.typeaheadOnSelect);
|
4775
4984
|
|
4776
|
-
|
4777
|
-
|
4985
|
+
//should it select highlighted popup value when losing focus?
|
4986
|
+
var isSelectOnBlur = angular.isDefined(attrs.typeaheadSelectOnBlur) ? originalScope.$eval(attrs.typeaheadSelectOnBlur) : false;
|
4778
4987
|
|
4779
|
-
|
4988
|
+
//binding to a variable that indicates if there were no results after the query is completed
|
4989
|
+
var isNoResultsSetter = $parse(attrs.typeaheadNoResults).assign || angular.noop;
|
4780
4990
|
|
4781
|
-
|
4991
|
+
var inputFormatter = attrs.typeaheadInputFormatter ? $parse(attrs.typeaheadInputFormatter) : undefined;
|
4782
4992
|
|
4783
|
-
|
4993
|
+
var appendToBody = attrs.typeaheadAppendToBody ? originalScope.$eval(attrs.typeaheadAppendToBody) : false;
|
4784
4994
|
|
4785
|
-
|
4786
|
-
var selectOnExact = attrs.typeaheadSelectOnExact ? originalScope.$eval(attrs.typeaheadSelectOnExact) : false;
|
4995
|
+
var focusFirst = originalScope.$eval(attrs.typeaheadFocusFirst) !== false;
|
4787
4996
|
|
4788
|
-
|
4997
|
+
//If input matches an item of the list exactly, select it automatically
|
4998
|
+
var selectOnExact = attrs.typeaheadSelectOnExact ? originalScope.$eval(attrs.typeaheadSelectOnExact) : false;
|
4789
4999
|
|
4790
|
-
|
4791
|
-
var $setModelValue = $parse(attrs.ngModel).assign;
|
5000
|
+
//INTERNAL VARIABLES
|
4792
5001
|
|
4793
|
-
|
4794
|
-
|
5002
|
+
//model setter executed upon match selection
|
5003
|
+
var parsedModel = $parse(attrs.ngModel);
|
5004
|
+
var invokeModelSetter = $parse(attrs.ngModel + '($$$p)');
|
5005
|
+
var $setModelValue = function(scope, newValue) {
|
5006
|
+
if (angular.isFunction(parsedModel(originalScope)) &&
|
5007
|
+
ngModelOptions && ngModelOptions.$options && ngModelOptions.$options.getterSetter) {
|
5008
|
+
return invokeModelSetter(scope, {$$$p: newValue});
|
5009
|
+
} else {
|
5010
|
+
return parsedModel.assign(scope, newValue);
|
5011
|
+
}
|
5012
|
+
};
|
4795
5013
|
|
4796
|
-
|
5014
|
+
//expressions used by typeahead
|
5015
|
+
var parserResult = typeaheadParser.parse(attrs.typeahead);
|
4797
5016
|
|
4798
|
-
|
4799
|
-
//mousedown & mouseup events
|
4800
|
-
//Issue #3699
|
4801
|
-
var selected;
|
5017
|
+
var hasFocus;
|
4802
5018
|
|
4803
|
-
|
4804
|
-
|
4805
|
-
|
4806
|
-
|
4807
|
-
scope.$destroy();
|
4808
|
-
});
|
5019
|
+
//Used to avoid bug in iOS webview where iOS keyboard does not fire
|
5020
|
+
//mousedown & mouseup events
|
5021
|
+
//Issue #3699
|
5022
|
+
var selected;
|
4809
5023
|
|
4810
|
-
|
4811
|
-
|
4812
|
-
|
4813
|
-
|
4814
|
-
|
4815
|
-
|
4816
|
-
|
5024
|
+
//create a child scope for the typeahead directive so we are not polluting original scope
|
5025
|
+
//with typeahead-specific data (matches, query etc.)
|
5026
|
+
var scope = originalScope.$new();
|
5027
|
+
var offDestroy = originalScope.$on('$destroy', function() {
|
5028
|
+
scope.$destroy();
|
5029
|
+
});
|
5030
|
+
scope.$on('$destroy', offDestroy);
|
5031
|
+
|
5032
|
+
// WAI-ARIA
|
5033
|
+
var popupId = 'typeahead-' + scope.$id + '-' + Math.floor(Math.random() * 10000);
|
5034
|
+
element.attr({
|
5035
|
+
'aria-autocomplete': 'list',
|
5036
|
+
'aria-expanded': false,
|
5037
|
+
'aria-owns': popupId
|
5038
|
+
});
|
4817
5039
|
|
4818
|
-
|
4819
|
-
|
4820
|
-
|
4821
|
-
|
4822
|
-
|
4823
|
-
|
4824
|
-
|
4825
|
-
|
4826
|
-
|
4827
|
-
|
4828
|
-
|
4829
|
-
|
4830
|
-
|
4831
|
-
|
4832
|
-
|
5040
|
+
//pop-up element used to display matches
|
5041
|
+
var popUpEl = angular.element('<div typeahead-popup></div>');
|
5042
|
+
popUpEl.attr({
|
5043
|
+
id: popupId,
|
5044
|
+
matches: 'matches',
|
5045
|
+
active: 'activeIdx',
|
5046
|
+
select: 'select(activeIdx)',
|
5047
|
+
'move-in-progress': 'moveInProgress',
|
5048
|
+
query: 'query',
|
5049
|
+
position: 'position'
|
5050
|
+
});
|
5051
|
+
//custom item template
|
5052
|
+
if (angular.isDefined(attrs.typeaheadTemplateUrl)) {
|
5053
|
+
popUpEl.attr('template-url', attrs.typeaheadTemplateUrl);
|
5054
|
+
}
|
4833
5055
|
|
4834
|
-
|
4835
|
-
|
4836
|
-
|
4837
|
-
element.attr('aria-expanded', false);
|
4838
|
-
};
|
5056
|
+
if (angular.isDefined(attrs.typeaheadPopupTemplateUrl)) {
|
5057
|
+
popUpEl.attr('popup-template-url', attrs.typeaheadPopupTemplateUrl);
|
5058
|
+
}
|
4839
5059
|
|
4840
|
-
|
4841
|
-
|
4842
|
-
|
5060
|
+
var resetMatches = function() {
|
5061
|
+
scope.matches = [];
|
5062
|
+
scope.activeIdx = -1;
|
5063
|
+
element.attr('aria-expanded', false);
|
5064
|
+
};
|
4843
5065
|
|
4844
|
-
|
4845
|
-
|
4846
|
-
|
4847
|
-
if (index < 0) {
|
4848
|
-
element.removeAttr('aria-activedescendant');
|
4849
|
-
} else {
|
4850
|
-
element.attr('aria-activedescendant', getMatchId(index));
|
4851
|
-
}
|
4852
|
-
});
|
5066
|
+
var getMatchId = function(index) {
|
5067
|
+
return popupId + '-option-' + index;
|
5068
|
+
};
|
4853
5069
|
|
4854
|
-
|
5070
|
+
// Indicate that the specified match is the active (pre-selected) item in the list owned by this typeahead.
|
5071
|
+
// This attribute is added or removed automatically when the `activeIdx` changes.
|
5072
|
+
scope.$watch('activeIdx', function(index) {
|
5073
|
+
if (index < 0) {
|
5074
|
+
element.removeAttr('aria-activedescendant');
|
5075
|
+
} else {
|
5076
|
+
element.attr('aria-activedescendant', getMatchId(index));
|
5077
|
+
}
|
5078
|
+
});
|
4855
5079
|
|
4856
|
-
|
4857
|
-
|
4858
|
-
|
5080
|
+
var inputIsExactMatch = function(inputValue, index) {
|
5081
|
+
if (scope.matches.length > index && inputValue) {
|
5082
|
+
return inputValue.toUpperCase() === scope.matches[index].label.toUpperCase();
|
5083
|
+
}
|
4859
5084
|
|
4860
|
-
|
4861
|
-
|
5085
|
+
return false;
|
5086
|
+
};
|
4862
5087
|
|
4863
|
-
|
4864
|
-
|
4865
|
-
|
4866
|
-
|
4867
|
-
|
4868
|
-
|
4869
|
-
|
4870
|
-
|
4871
|
-
|
4872
|
-
|
4873
|
-
|
4874
|
-
|
4875
|
-
|
4876
|
-
|
4877
|
-
|
4878
|
-
|
4879
|
-
|
4880
|
-
|
4881
|
-
|
4882
|
-
|
4883
|
-
|
4884
|
-
|
4885
|
-
|
4886
|
-
|
4887
|
-
});
|
4888
|
-
}
|
5088
|
+
var getMatchesAsync = function(inputValue) {
|
5089
|
+
var locals = {$viewValue: inputValue};
|
5090
|
+
isLoadingSetter(originalScope, true);
|
5091
|
+
isNoResultsSetter(originalScope, false);
|
5092
|
+
$q.when(parserResult.source(originalScope, locals)).then(function(matches) {
|
5093
|
+
//it might happen that several async queries were in progress if a user were typing fast
|
5094
|
+
//but we are interested only in responses that correspond to the current view value
|
5095
|
+
var onCurrentRequest = (inputValue === modelCtrl.$viewValue);
|
5096
|
+
if (onCurrentRequest && hasFocus) {
|
5097
|
+
if (matches && matches.length > 0) {
|
5098
|
+
|
5099
|
+
scope.activeIdx = focusFirst ? 0 : -1;
|
5100
|
+
isNoResultsSetter(originalScope, false);
|
5101
|
+
scope.matches.length = 0;
|
5102
|
+
|
5103
|
+
//transform labels
|
5104
|
+
for (var i = 0; i < matches.length; i++) {
|
5105
|
+
locals[parserResult.itemName] = matches[i];
|
5106
|
+
scope.matches.push({
|
5107
|
+
id: getMatchId(i),
|
5108
|
+
label: parserResult.viewMapper(scope, locals),
|
5109
|
+
model: matches[i]
|
5110
|
+
});
|
5111
|
+
}
|
4889
5112
|
|
4890
|
-
|
4891
|
-
|
4892
|
-
|
4893
|
-
|
4894
|
-
|
5113
|
+
scope.query = inputValue;
|
5114
|
+
//position pop-up with matches - we need to re-calculate its position each time we are opening a window
|
5115
|
+
//with matches as a pop-up might be absolute-positioned and position of an input might have changed on a page
|
5116
|
+
//due to other elements being rendered
|
5117
|
+
recalculatePosition();
|
4895
5118
|
|
4896
|
-
|
5119
|
+
element.attr('aria-expanded', true);
|
4897
5120
|
|
4898
|
-
|
4899
|
-
|
4900
|
-
|
5121
|
+
//Select the single remaining option if user input matches
|
5122
|
+
if (selectOnExact && scope.matches.length === 1 && inputIsExactMatch(inputValue, 0)) {
|
5123
|
+
scope.select(0);
|
5124
|
+
}
|
5125
|
+
} else {
|
5126
|
+
resetMatches();
|
5127
|
+
isNoResultsSetter(originalScope, true);
|
4901
5128
|
}
|
4902
|
-
} else {
|
4903
|
-
resetMatches();
|
4904
|
-
isNoResultsSetter(originalScope, true);
|
4905
5129
|
}
|
4906
|
-
|
4907
|
-
|
5130
|
+
if (onCurrentRequest) {
|
5131
|
+
isLoadingSetter(originalScope, false);
|
5132
|
+
}
|
5133
|
+
}, function() {
|
5134
|
+
resetMatches();
|
4908
5135
|
isLoadingSetter(originalScope, false);
|
4909
|
-
|
4910
|
-
|
4911
|
-
|
4912
|
-
isLoadingSetter(originalScope, false);
|
4913
|
-
isNoResultsSetter(originalScope, true);
|
4914
|
-
});
|
4915
|
-
};
|
4916
|
-
|
4917
|
-
// bind events only if appendToBody params exist - performance feature
|
4918
|
-
if (appendToBody) {
|
4919
|
-
angular.element($window).bind('resize', fireRecalculating);
|
4920
|
-
$document.find('body').bind('scroll', fireRecalculating);
|
4921
|
-
}
|
5136
|
+
isNoResultsSetter(originalScope, true);
|
5137
|
+
});
|
5138
|
+
};
|
4922
5139
|
|
4923
|
-
|
4924
|
-
|
5140
|
+
// bind events only if appendToBody params exist - performance feature
|
5141
|
+
if (appendToBody) {
|
5142
|
+
angular.element($window).bind('resize', fireRecalculating);
|
5143
|
+
$document.find('body').bind('scroll', fireRecalculating);
|
5144
|
+
}
|
4925
5145
|
|
4926
|
-
|
4927
|
-
|
5146
|
+
// Declare the timeout promise var outside the function scope so that stacked calls can be cancelled later
|
5147
|
+
var timeoutEventPromise;
|
4928
5148
|
|
4929
|
-
|
4930
|
-
|
4931
|
-
scope.moveInProgress = true;
|
4932
|
-
scope.$digest();
|
4933
|
-
}
|
5149
|
+
// Default progress type
|
5150
|
+
scope.moveInProgress = false;
|
4934
5151
|
|
4935
|
-
|
4936
|
-
|
4937
|
-
|
4938
|
-
|
5152
|
+
function fireRecalculating() {
|
5153
|
+
if (!scope.moveInProgress) {
|
5154
|
+
scope.moveInProgress = true;
|
5155
|
+
scope.$digest();
|
5156
|
+
}
|
4939
5157
|
|
4940
|
-
|
4941
|
-
|
4942
|
-
|
4943
|
-
if (scope.matches.length) {
|
4944
|
-
recalculatePosition();
|
5158
|
+
// Cancel previous timeout
|
5159
|
+
if (timeoutEventPromise) {
|
5160
|
+
$timeout.cancel(timeoutEventPromise);
|
4945
5161
|
}
|
4946
5162
|
|
4947
|
-
|
4948
|
-
|
4949
|
-
|
4950
|
-
|
5163
|
+
// Debounced executing recalculate after events fired
|
5164
|
+
timeoutEventPromise = $timeout(function() {
|
5165
|
+
// if popup is visible
|
5166
|
+
if (scope.matches.length) {
|
5167
|
+
recalculatePosition();
|
5168
|
+
}
|
4951
5169
|
|
4952
|
-
|
4953
|
-
|
4954
|
-
|
4955
|
-
|
4956
|
-
scope.position.top += element.prop('offsetHeight');
|
4957
|
-
}
|
5170
|
+
scope.moveInProgress = false;
|
5171
|
+
scope.$digest();
|
5172
|
+
}, eventDebounceTime);
|
5173
|
+
}
|
4958
5174
|
|
4959
|
-
|
5175
|
+
// recalculate actual position and set new values to scope
|
5176
|
+
// after digest loop is popup in right position
|
5177
|
+
function recalculatePosition() {
|
5178
|
+
scope.position = appendToBody ? $position.offset(element) : $position.position(element);
|
5179
|
+
scope.position.top += element.prop('offsetHeight');
|
5180
|
+
}
|
4960
5181
|
|
4961
|
-
|
4962
|
-
scope.query = undefined;
|
5182
|
+
resetMatches();
|
4963
5183
|
|
4964
|
-
|
4965
|
-
|
5184
|
+
//we need to propagate user's query so we can higlight matches
|
5185
|
+
scope.query = undefined;
|
4966
5186
|
|
4967
|
-
|
4968
|
-
timeoutPromise
|
4969
|
-
getMatchesAsync(inputValue);
|
4970
|
-
}, waitTime);
|
4971
|
-
};
|
5187
|
+
//Declare the timeout promise var outside the function scope so that stacked calls can be cancelled later
|
5188
|
+
var timeoutPromise;
|
4972
5189
|
|
4973
|
-
|
4974
|
-
|
4975
|
-
|
4976
|
-
|
4977
|
-
|
5190
|
+
var scheduleSearchWithTimeout = function(inputValue) {
|
5191
|
+
timeoutPromise = $timeout(function() {
|
5192
|
+
getMatchesAsync(inputValue);
|
5193
|
+
}, waitTime);
|
5194
|
+
};
|
4978
5195
|
|
4979
|
-
|
4980
|
-
|
4981
|
-
|
5196
|
+
var cancelPreviousTimeout = function() {
|
5197
|
+
if (timeoutPromise) {
|
5198
|
+
$timeout.cancel(timeoutPromise);
|
5199
|
+
}
|
5200
|
+
};
|
4982
5201
|
|
4983
|
-
|
5202
|
+
//plug into $parsers pipeline to open a typeahead on view changes initiated from DOM
|
5203
|
+
//$parsers kick-in on all the changes coming from the view as well as manually triggered by $setViewValue
|
5204
|
+
modelCtrl.$parsers.unshift(function(inputValue) {
|
5205
|
+
hasFocus = true;
|
4984
5206
|
|
4985
|
-
|
4986
|
-
|
4987
|
-
|
4988
|
-
|
5207
|
+
if (minLength === 0 || inputValue && inputValue.length >= minLength) {
|
5208
|
+
if (waitTime > 0) {
|
5209
|
+
cancelPreviousTimeout();
|
5210
|
+
scheduleSearchWithTimeout(inputValue);
|
5211
|
+
} else {
|
5212
|
+
getMatchesAsync(inputValue);
|
5213
|
+
}
|
4989
5214
|
} else {
|
4990
|
-
|
5215
|
+
isLoadingSetter(originalScope, false);
|
5216
|
+
cancelPreviousTimeout();
|
5217
|
+
resetMatches();
|
4991
5218
|
}
|
4992
|
-
} else {
|
4993
|
-
isLoadingSetter(originalScope, false);
|
4994
|
-
cancelPreviousTimeout();
|
4995
|
-
resetMatches();
|
4996
|
-
}
|
4997
5219
|
|
4998
|
-
|
4999
|
-
|
5000
|
-
} else {
|
5001
|
-
if (!inputValue) {
|
5002
|
-
// Reset in case user had typed something previously.
|
5003
|
-
modelCtrl.$setValidity('editable', true);
|
5004
|
-
return null;
|
5220
|
+
if (isEditable) {
|
5221
|
+
return inputValue;
|
5005
5222
|
} else {
|
5006
|
-
|
5007
|
-
|
5223
|
+
if (!inputValue) {
|
5224
|
+
// Reset in case user had typed something previously.
|
5225
|
+
modelCtrl.$setValidity('editable', true);
|
5226
|
+
return null;
|
5227
|
+
} else {
|
5228
|
+
modelCtrl.$setValidity('editable', false);
|
5229
|
+
return undefined;
|
5230
|
+
}
|
5008
5231
|
}
|
5009
|
-
}
|
5010
|
-
});
|
5011
|
-
|
5012
|
-
modelCtrl.$formatters.push(function (modelValue) {
|
5232
|
+
});
|
5013
5233
|
|
5014
|
-
|
5015
|
-
|
5234
|
+
modelCtrl.$formatters.push(function(modelValue) {
|
5235
|
+
var candidateViewValue, emptyViewValue;
|
5236
|
+
var locals = {};
|
5016
5237
|
|
5017
|
-
|
5018
|
-
|
5019
|
-
|
5020
|
-
|
5021
|
-
|
5022
|
-
|
5023
|
-
|
5024
|
-
if (inputFormatter) {
|
5238
|
+
// The validity may be set to false via $parsers (see above) if
|
5239
|
+
// the model is restricted to selected values. If the model
|
5240
|
+
// is set manually it is considered to be valid.
|
5241
|
+
if (!isEditable) {
|
5242
|
+
modelCtrl.$setValidity('editable', true);
|
5243
|
+
}
|
5025
5244
|
|
5026
|
-
|
5027
|
-
|
5245
|
+
if (inputFormatter) {
|
5246
|
+
locals.$model = modelValue;
|
5247
|
+
return inputFormatter(originalScope, locals);
|
5248
|
+
} else {
|
5249
|
+
//it might happen that we don't have enough info to properly render input value
|
5250
|
+
//we need to check for this situation and simply return model value if we can't apply custom formatting
|
5251
|
+
locals[parserResult.itemName] = modelValue;
|
5252
|
+
candidateViewValue = parserResult.viewMapper(originalScope, locals);
|
5253
|
+
locals[parserResult.itemName] = undefined;
|
5254
|
+
emptyViewValue = parserResult.viewMapper(originalScope, locals);
|
5255
|
+
|
5256
|
+
return candidateViewValue!== emptyViewValue ? candidateViewValue : modelValue;
|
5257
|
+
}
|
5258
|
+
});
|
5028
5259
|
|
5029
|
-
|
5260
|
+
scope.select = function(activeIdx) {
|
5261
|
+
//called from within the $digest() cycle
|
5262
|
+
var locals = {};
|
5263
|
+
var model, item;
|
5030
5264
|
|
5031
|
-
|
5032
|
-
|
5033
|
-
|
5034
|
-
|
5035
|
-
|
5036
|
-
|
5265
|
+
selected = true;
|
5266
|
+
locals[parserResult.itemName] = item = scope.matches[activeIdx].model;
|
5267
|
+
model = parserResult.modelMapper(originalScope, locals);
|
5268
|
+
$setModelValue(originalScope, model);
|
5269
|
+
modelCtrl.$setValidity('editable', true);
|
5270
|
+
modelCtrl.$setValidity('parse', true);
|
5037
5271
|
|
5038
|
-
|
5039
|
-
|
5040
|
-
|
5272
|
+
onSelectCallback(originalScope, {
|
5273
|
+
$item: item,
|
5274
|
+
$model: model,
|
5275
|
+
$label: parserResult.viewMapper(originalScope, locals)
|
5276
|
+
});
|
5041
5277
|
|
5042
|
-
|
5043
|
-
//called from within the $digest() cycle
|
5044
|
-
var locals = {};
|
5045
|
-
var model, item;
|
5046
|
-
|
5047
|
-
selected = true;
|
5048
|
-
locals[parserResult.itemName] = item = scope.matches[activeIdx].model;
|
5049
|
-
model = parserResult.modelMapper(originalScope, locals);
|
5050
|
-
$setModelValue(originalScope, model);
|
5051
|
-
modelCtrl.$setValidity('editable', true);
|
5052
|
-
modelCtrl.$setValidity('parse', true);
|
5053
|
-
|
5054
|
-
onSelectCallback(originalScope, {
|
5055
|
-
$item: item,
|
5056
|
-
$model: model,
|
5057
|
-
$label: parserResult.viewMapper(originalScope, locals)
|
5058
|
-
});
|
5278
|
+
resetMatches();
|
5059
5279
|
|
5060
|
-
|
5280
|
+
//return focus to the input element if a match was selected via a mouse click event
|
5281
|
+
// use timeout to avoid $rootScope:inprog error
|
5282
|
+
if (scope.$eval(attrs.typeaheadFocusOnSelect) !== false) {
|
5283
|
+
$timeout(function() { element[0].focus(); }, 0, false);
|
5284
|
+
}
|
5285
|
+
};
|
5061
5286
|
|
5062
|
-
//
|
5063
|
-
|
5064
|
-
|
5065
|
-
|
5287
|
+
//bind keyboard events: arrows up(38) / down(40), enter(13) and tab(9), esc(27)
|
5288
|
+
element.bind('keydown', function(evt) {
|
5289
|
+
//typeahead is open and an "interesting" key was pressed
|
5290
|
+
if (scope.matches.length === 0 || HOT_KEYS.indexOf(evt.which) === -1) {
|
5291
|
+
return;
|
5292
|
+
}
|
5066
5293
|
|
5067
|
-
|
5068
|
-
|
5294
|
+
// if there's nothing selected (i.e. focusFirst) and enter or tab is hit, clear the results
|
5295
|
+
if (scope.activeIdx === -1 && (evt.which === 9 || evt.which === 13)) {
|
5296
|
+
resetMatches();
|
5297
|
+
scope.$digest();
|
5298
|
+
return;
|
5299
|
+
}
|
5069
5300
|
|
5070
|
-
|
5071
|
-
if (scope.matches.length === 0 || HOT_KEYS.indexOf(evt.which) === -1) {
|
5072
|
-
return;
|
5073
|
-
}
|
5301
|
+
evt.preventDefault();
|
5074
5302
|
|
5075
|
-
|
5076
|
-
|
5077
|
-
|
5078
|
-
scope.$digest();
|
5079
|
-
return;
|
5080
|
-
}
|
5303
|
+
if (evt.which === 40) {
|
5304
|
+
scope.activeIdx = (scope.activeIdx + 1) % scope.matches.length;
|
5305
|
+
scope.$digest();
|
5081
5306
|
|
5082
|
-
|
5307
|
+
} else if (evt.which === 38) {
|
5308
|
+
scope.activeIdx = (scope.activeIdx > 0 ? scope.activeIdx : scope.matches.length) - 1;
|
5309
|
+
scope.$digest();
|
5083
5310
|
|
5084
|
-
|
5085
|
-
|
5086
|
-
|
5311
|
+
} else if (evt.which === 13 || evt.which === 9) {
|
5312
|
+
scope.$apply(function () {
|
5313
|
+
scope.select(scope.activeIdx);
|
5314
|
+
});
|
5087
5315
|
|
5088
|
-
|
5089
|
-
|
5090
|
-
scope.$digest();
|
5316
|
+
} else if (evt.which === 27) {
|
5317
|
+
evt.stopPropagation();
|
5091
5318
|
|
5092
|
-
|
5093
|
-
|
5094
|
-
|
5095
|
-
|
5319
|
+
resetMatches();
|
5320
|
+
scope.$digest();
|
5321
|
+
}
|
5322
|
+
});
|
5096
5323
|
|
5097
|
-
|
5098
|
-
|
5324
|
+
element.bind('blur', function() {
|
5325
|
+
if (isSelectOnBlur && scope.matches.length && scope.activeIdx !== -1 && !selected) {
|
5326
|
+
selected = true;
|
5327
|
+
scope.$apply(function() {
|
5328
|
+
scope.select(scope.activeIdx);
|
5329
|
+
});
|
5330
|
+
}
|
5331
|
+
hasFocus = false;
|
5332
|
+
selected = false;
|
5333
|
+
});
|
5099
5334
|
|
5100
|
-
|
5101
|
-
|
5102
|
-
|
5103
|
-
|
5335
|
+
// Keep reference to click handler to unbind it.
|
5336
|
+
var dismissClickHandler = function(evt) {
|
5337
|
+
// Issue #3973
|
5338
|
+
// Firefox treats right click as a click on document
|
5339
|
+
if (element[0] !== evt.target && evt.which !== 3 && scope.matches.length !== 0) {
|
5340
|
+
resetMatches();
|
5341
|
+
if (!$rootScope.$$phase) {
|
5342
|
+
scope.$digest();
|
5343
|
+
}
|
5344
|
+
}
|
5345
|
+
};
|
5104
5346
|
|
5105
|
-
|
5106
|
-
if (isSelectOnBlur && scope.matches.length && scope.activeIdx !== -1 && !selected) {
|
5107
|
-
selected = true;
|
5108
|
-
scope.$apply(function () {
|
5109
|
-
scope.select(scope.activeIdx);
|
5110
|
-
});
|
5111
|
-
}
|
5112
|
-
hasFocus = false;
|
5113
|
-
selected = false;
|
5114
|
-
});
|
5347
|
+
$document.bind('click', dismissClickHandler);
|
5115
5348
|
|
5116
|
-
|
5117
|
-
|
5118
|
-
|
5119
|
-
|
5120
|
-
if (element[0] !== evt.target && evt.which !== 3 && scope.matches.length !== 0) {
|
5121
|
-
resetMatches();
|
5122
|
-
if (!$rootScope.$$phase) {
|
5123
|
-
scope.$digest();
|
5349
|
+
originalScope.$on('$destroy', function() {
|
5350
|
+
$document.unbind('click', dismissClickHandler);
|
5351
|
+
if (appendToBody) {
|
5352
|
+
$popup.remove();
|
5124
5353
|
}
|
5125
|
-
|
5126
|
-
|
5354
|
+
// Prevent jQuery cache memory leak
|
5355
|
+
popUpEl.remove();
|
5356
|
+
});
|
5127
5357
|
|
5128
|
-
|
5358
|
+
var $popup = $compile(popUpEl)(scope);
|
5129
5359
|
|
5130
|
-
originalScope.$on('$destroy', function(){
|
5131
|
-
$document.unbind('click', dismissClickHandler);
|
5132
5360
|
if (appendToBody) {
|
5133
|
-
$
|
5361
|
+
$document.find('body').append($popup);
|
5362
|
+
} else {
|
5363
|
+
element.after($popup);
|
5134
5364
|
}
|
5135
|
-
// Prevent jQuery cache memory leak
|
5136
|
-
popUpEl.remove();
|
5137
|
-
});
|
5138
|
-
|
5139
|
-
var $popup = $compile(popUpEl)(scope);
|
5140
|
-
|
5141
|
-
if (appendToBody) {
|
5142
|
-
$document.find('body').append($popup);
|
5143
|
-
} else {
|
5144
|
-
element.after($popup);
|
5145
5365
|
}
|
5146
|
-
}
|
5147
|
-
};
|
5366
|
+
};
|
5148
5367
|
|
5149
|
-
}])
|
5368
|
+
}])
|
5150
5369
|
|
5151
|
-
.directive('typeaheadPopup', function
|
5370
|
+
.directive('typeaheadPopup', function() {
|
5152
5371
|
return {
|
5153
|
-
restrict:'EA',
|
5154
|
-
scope:{
|
5155
|
-
matches:'=',
|
5156
|
-
query:'=',
|
5157
|
-
active:'=',
|
5158
|
-
position:'&',
|
5159
|
-
moveInProgress:'=',
|
5160
|
-
select:'&'
|
5372
|
+
restrict: 'EA',
|
5373
|
+
scope: {
|
5374
|
+
matches: '=',
|
5375
|
+
query: '=',
|
5376
|
+
active: '=',
|
5377
|
+
position: '&',
|
5378
|
+
moveInProgress: '=',
|
5379
|
+
select: '&'
|
5161
5380
|
},
|
5162
|
-
replace:true,
|
5163
|
-
templateUrl:
|
5164
|
-
|
5165
|
-
|
5381
|
+
replace: true,
|
5382
|
+
templateUrl: function(element, attrs) {
|
5383
|
+
return attrs.popupTemplateUrl || 'template/typeahead/typeahead-popup.html';
|
5384
|
+
},
|
5385
|
+
link: function(scope, element, attrs) {
|
5166
5386
|
scope.templateUrl = attrs.templateUrl;
|
5167
5387
|
|
5168
|
-
scope.isOpen = function
|
5388
|
+
scope.isOpen = function() {
|
5169
5389
|
return scope.matches.length > 0;
|
5170
5390
|
};
|
5171
5391
|
|
5172
|
-
scope.isActive = function
|
5392
|
+
scope.isActive = function(matchIdx) {
|
5173
5393
|
return scope.active == matchIdx;
|
5174
5394
|
};
|
5175
5395
|
|
5176
|
-
scope.selectActive = function
|
5396
|
+
scope.selectActive = function(matchIdx) {
|
5177
5397
|
scope.active = matchIdx;
|
5178
5398
|
};
|
5179
5399
|
|
5180
|
-
scope.selectMatch = function
|
5400
|
+
scope.selectMatch = function(activeIdx) {
|
5181
5401
|
scope.select({activeIdx:activeIdx});
|
5182
5402
|
};
|
5183
5403
|
}
|
5184
5404
|
};
|
5185
5405
|
})
|
5186
5406
|
|
5187
|
-
.directive('typeaheadMatch', ['$templateRequest', '$compile', '$parse', function
|
5407
|
+
.directive('typeaheadMatch', ['$templateRequest', '$compile', '$parse', function($templateRequest, $compile, $parse) {
|
5188
5408
|
return {
|
5189
|
-
restrict:'EA',
|
5190
|
-
scope:{
|
5191
|
-
index:'=',
|
5192
|
-
match:'=',
|
5193
|
-
query:'='
|
5409
|
+
restrict: 'EA',
|
5410
|
+
scope: {
|
5411
|
+
index: '=',
|
5412
|
+
match: '=',
|
5413
|
+
query: '='
|
5194
5414
|
},
|
5195
|
-
link:function
|
5415
|
+
link:function(scope, element, attrs) {
|
5196
5416
|
var tplUrl = $parse(attrs.templateUrl)(scope.$parent) || 'template/typeahead/typeahead-match.html';
|
5197
5417
|
$templateRequest(tplUrl).then(function(tplContent) {
|
5198
|
-
$compile(tplContent.trim())(scope, function(clonedElement){
|
5418
|
+
$compile(tplContent.trim())(scope, function(clonedElement) {
|
5199
5419
|
element.replaceWith(clonedElement);
|
5200
5420
|
});
|
5201
5421
|
});
|
@@ -5203,27 +5423,42 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
|
|
5203
5423
|
};
|
5204
5424
|
}])
|
5205
5425
|
|
5206
|
-
.filter('typeaheadHighlight', function() {
|
5426
|
+
.filter('typeaheadHighlight', ['$sce', '$injector', '$log', function($sce, $injector, $log) {
|
5427
|
+
var isSanitizePresent;
|
5428
|
+
isSanitizePresent = $injector.has('$sanitize');
|
5207
5429
|
|
5208
5430
|
function escapeRegexp(queryToEscape) {
|
5431
|
+
// Regex: capture the whole query string and replace it with the string that will be used to match
|
5432
|
+
// the results, for example if the capture is "a" the result will be \a
|
5209
5433
|
return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
|
5210
5434
|
}
|
5211
5435
|
|
5436
|
+
function containsHtml(matchItem) {
|
5437
|
+
return /<.*>/g.test(matchItem);
|
5438
|
+
}
|
5439
|
+
|
5212
5440
|
return function(matchItem, query) {
|
5213
|
-
|
5441
|
+
if (!isSanitizePresent && containsHtml(matchItem)) {
|
5442
|
+
$log.warn('Unsafe use of typeahead please use ngSanitize'); // Warn the user about the danger
|
5443
|
+
}
|
5444
|
+
matchItem = query? ('' + matchItem).replace(new RegExp(escapeRegexp(query), 'gi'), '<strong>$&</strong>') : matchItem; // Replaces the capture string with a the same string inside of a "strong" tag
|
5445
|
+
if (!isSanitizePresent) {
|
5446
|
+
matchItem = $sce.trustAsHtml(matchItem); // If $sanitize is not present we pack the string in a $sce object for the ng-bind-html directive
|
5447
|
+
}
|
5448
|
+
return matchItem;
|
5214
5449
|
};
|
5215
|
-
});
|
5450
|
+
}]);
|
5216
5451
|
|
5217
5452
|
angular.module("template/accordion/accordion-group.html", []).run(["$templateCache", function($templateCache) {
|
5218
5453
|
$templateCache.put("template/accordion/accordion-group.html",
|
5219
|
-
"<div class=\"panel
|
5220
|
-
" <div class=\"panel-heading\">\n" +
|
5454
|
+
"<div class=\"panel {{panelClass || 'panel-default'}}\">\n" +
|
5455
|
+
" <div class=\"panel-heading\" ng-keypress=\"toggleOpen($event)\">\n" +
|
5221
5456
|
" <h4 class=\"panel-title\">\n" +
|
5222
5457
|
" <a href tabindex=\"0\" class=\"accordion-toggle\" ng-click=\"toggleOpen()\" accordion-transclude=\"heading\"><span ng-class=\"{'text-muted': isDisabled}\">{{heading}}</span></a>\n" +
|
5223
5458
|
" </h4>\n" +
|
5224
5459
|
" </div>\n" +
|
5225
5460
|
" <div class=\"panel-collapse collapse\" collapse=\"!isOpen\">\n" +
|
5226
|
-
"
|
5461
|
+
" <div class=\"panel-body\" ng-transclude></div>\n" +
|
5227
5462
|
" </div>\n" +
|
5228
5463
|
"</div>\n" +
|
5229
5464
|
"");
|
@@ -5326,14 +5561,14 @@ angular.module("template/datepicker/month.html", []).run(["$templateCache", func
|
|
5326
5561
|
angular.module("template/datepicker/popup.html", []).run(["$templateCache", function($templateCache) {
|
5327
5562
|
$templateCache.put("template/datepicker/popup.html",
|
5328
5563
|
"<ul class=\"dropdown-menu\" ng-if=\"isOpen\" style=\"display: block\" ng-style=\"{top: position.top+'px', left: position.left+'px'}\" ng-keydown=\"keydown($event)\" ng-click=\"$event.stopPropagation()\">\n" +
|
5329
|
-
"
|
5330
|
-
"
|
5331
|
-
"
|
5332
|
-
"
|
5333
|
-
"
|
5334
|
-
"
|
5335
|
-
"
|
5336
|
-
"
|
5564
|
+
" <li ng-transclude></li>\n" +
|
5565
|
+
" <li ng-if=\"showButtonBar\" style=\"padding:10px 9px 2px\">\n" +
|
5566
|
+
" <span class=\"btn-group pull-left\">\n" +
|
5567
|
+
" <button type=\"button\" class=\"btn btn-sm btn-info\" ng-click=\"select('today')\" ng-disabled=\"isDisabled('today')\">{{ getText('current') }}</button>\n" +
|
5568
|
+
" <button type=\"button\" class=\"btn btn-sm btn-danger\" ng-click=\"select(null)\">{{ getText('clear') }}</button>\n" +
|
5569
|
+
" </span>\n" +
|
5570
|
+
" <button type=\"button\" class=\"btn btn-sm btn-success pull-right\" ng-click=\"close()\">{{ getText('close') }}</button>\n" +
|
5571
|
+
" </li>\n" +
|
5337
5572
|
"</ul>\n" +
|
5338
5573
|
"");
|
5339
5574
|
}]);
|
@@ -5374,7 +5609,7 @@ angular.module("template/modal/window.html", []).run(["$templateCache", function
|
|
5374
5609
|
"<div modal-render=\"{{$isRendered}}\" tabindex=\"-1\" role=\"dialog\" class=\"modal\"\n" +
|
5375
5610
|
" modal-animation-class=\"fade\"\n" +
|
5376
5611
|
" modal-in-class=\"in\"\n" +
|
5377
|
-
"
|
5612
|
+
" ng-style=\"{'z-index': 1050 + index*10, display: 'block'}\" ng-click=\"close($event)\">\n" +
|
5378
5613
|
" <div class=\"modal-dialog\" ng-class=\"size ? 'modal-' + size : ''\"><div class=\"modal-content\" modal-transclude></div></div>\n" +
|
5379
5614
|
"</div>\n" +
|
5380
5615
|
"");
|
@@ -5383,9 +5618,10 @@ angular.module("template/modal/window.html", []).run(["$templateCache", function
|
|
5383
5618
|
angular.module("template/pagination/pager.html", []).run(["$templateCache", function($templateCache) {
|
5384
5619
|
$templateCache.put("template/pagination/pager.html",
|
5385
5620
|
"<ul class=\"pager\">\n" +
|
5386
|
-
" <li ng-class=\"{disabled: noPrevious(), previous: align}\"><a href ng-click=\"selectPage(page - 1, $event)\">{{::getText('previous')}}</a></li>\n" +
|
5387
|
-
" <li ng-class=\"{disabled: noNext(), next: align}\"><a href ng-click=\"selectPage(page + 1, $event)\">{{::getText('next')}}</a></li>\n" +
|
5388
|
-
"</ul
|
5621
|
+
" <li ng-class=\"{disabled: noPrevious()||ngDisabled, previous: align}\"><a href ng-click=\"selectPage(page - 1, $event)\">{{::getText('previous')}}</a></li>\n" +
|
5622
|
+
" <li ng-class=\"{disabled: noNext()||ngDisabled, next: align}\"><a href ng-click=\"selectPage(page + 1, $event)\">{{::getText('next')}}</a></li>\n" +
|
5623
|
+
"</ul>\n" +
|
5624
|
+
"");
|
5389
5625
|
}]);
|
5390
5626
|
|
5391
5627
|
angular.module("template/pagination/pagination.html", []).run(["$templateCache", function($templateCache) {
|
@@ -5584,7 +5820,7 @@ angular.module("template/timepicker/timepicker.html", []).run(["$templateCache",
|
|
5584
5820
|
|
5585
5821
|
angular.module("template/typeahead/typeahead-match.html", []).run(["$templateCache", function($templateCache) {
|
5586
5822
|
$templateCache.put("template/typeahead/typeahead-match.html",
|
5587
|
-
"<a href tabindex=\"-1\" bind-html
|
5823
|
+
"<a href tabindex=\"-1\" ng-bind-html=\"match.label | typeaheadHighlight:query\"></a>\n" +
|
5588
5824
|
"");
|
5589
5825
|
}]);
|
5590
5826
|
|
@@ -5597,4 +5833,4 @@ angular.module("template/typeahead/typeahead-popup.html", []).run(["$templateCac
|
|
5597
5833
|
"</ul>\n" +
|
5598
5834
|
"");
|
5599
5835
|
}]);
|
5600
|
-
!angular.$$csp() && angular.element(document).find('head').prepend('<style type="text/css">.ng-animate.item:not(.left):not(.right){-webkit-transition:0s ease-in-out left;transition:0s ease-in-out left}</style>');
|
5836
|
+
!angular.$$csp() && angular.element(document).find('head').prepend('<style type="text/css">.ng-animate.item:not(.left):not(.right){-webkit-transition:0s ease-in-out left;transition:0s ease-in-out left}</style>');
|