angular-ui-bootstrap-rails 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,10 +2,10 @@
|
|
2
2
|
* angular-ui-bootstrap
|
3
3
|
* http://angular-ui.github.io/bootstrap/
|
4
4
|
|
5
|
-
* Version: 0.
|
5
|
+
* Version: 0.11.0 - 2014-05-01
|
6
6
|
* License: MIT
|
7
7
|
*/
|
8
|
-
angular.module("ui.bootstrap", ["ui.bootstrap.transition","ui.bootstrap.collapse","ui.bootstrap.accordion","ui.bootstrap.alert","ui.bootstrap.bindHtml","ui.bootstrap.buttons","ui.bootstrap.carousel","ui.bootstrap.position","ui.bootstrap.datepicker","ui.bootstrap.
|
8
|
+
angular.module("ui.bootstrap", ["ui.bootstrap.transition","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.typeahead"]);
|
9
9
|
angular.module('ui.bootstrap.transition', [])
|
10
10
|
|
11
11
|
/**
|
@@ -22,7 +22,7 @@ angular.module('ui.bootstrap.transition', [])
|
|
22
22
|
var $transition = function(element, trigger, options) {
|
23
23
|
options = options || {};
|
24
24
|
var deferred = $q.defer();
|
25
|
-
var endEventName = $transition[options.animation ?
|
25
|
+
var endEventName = $transition[options.animation ? 'animationEndEventName' : 'transitionEndEventName'];
|
26
26
|
|
27
27
|
var transitionEndHandler = function(event) {
|
28
28
|
$rootScope.$apply(function() {
|
@@ -91,7 +91,7 @@ angular.module('ui.bootstrap.transition', [])
|
|
91
91
|
|
92
92
|
angular.module('ui.bootstrap.collapse', ['ui.bootstrap.transition'])
|
93
93
|
|
94
|
-
.directive('collapse', ['$transition', function ($transition
|
94
|
+
.directive('collapse', ['$transition', function ($transition) {
|
95
95
|
|
96
96
|
return {
|
97
97
|
link: function (scope, element, attrs) {
|
@@ -187,7 +187,7 @@ angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
|
|
187
187
|
});
|
188
188
|
}
|
189
189
|
};
|
190
|
-
|
190
|
+
|
191
191
|
// This is called from the accordion-group directive to add itself to the accordion
|
192
192
|
this.addGroup = function(groupScope) {
|
193
193
|
var that = this;
|
@@ -202,7 +202,7 @@ angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
|
|
202
202
|
this.removeGroup = function(group) {
|
203
203
|
var index = this.groups.indexOf(group);
|
204
204
|
if ( index !== -1 ) {
|
205
|
-
this.groups.splice(
|
205
|
+
this.groups.splice(index, 1);
|
206
206
|
}
|
207
207
|
};
|
208
208
|
|
@@ -221,46 +221,40 @@ angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
|
|
221
221
|
})
|
222
222
|
|
223
223
|
// The accordion-group directive indicates a block of html that will expand and collapse in an accordion
|
224
|
-
.directive('accordionGroup',
|
224
|
+
.directive('accordionGroup', function() {
|
225
225
|
return {
|
226
226
|
require:'^accordion', // We need this directive to be inside an accordion
|
227
227
|
restrict:'EA',
|
228
228
|
transclude:true, // It transcludes the contents of the directive into the template
|
229
229
|
replace: true, // The element containing the directive will be replaced with the template
|
230
230
|
templateUrl:'template/accordion/accordion-group.html',
|
231
|
-
scope:{
|
231
|
+
scope: {
|
232
|
+
heading: '@', // Interpolate the heading attribute onto this scope
|
233
|
+
isOpen: '=?',
|
234
|
+
isDisabled: '=?'
|
235
|
+
},
|
232
236
|
controller: function() {
|
233
237
|
this.setHeading = function(element) {
|
234
238
|
this.heading = element;
|
235
239
|
};
|
236
240
|
},
|
237
241
|
link: function(scope, element, attrs, accordionCtrl) {
|
238
|
-
var getIsOpen, setIsOpen;
|
239
|
-
|
240
242
|
accordionCtrl.addGroup(scope);
|
241
243
|
|
242
|
-
scope.isOpen = false;
|
243
|
-
|
244
|
-
if ( attrs.isOpen ) {
|
245
|
-
getIsOpen = $parse(attrs.isOpen);
|
246
|
-
setIsOpen = getIsOpen.assign;
|
247
|
-
|
248
|
-
scope.$parent.$watch(getIsOpen, function(value) {
|
249
|
-
scope.isOpen = !!value;
|
250
|
-
});
|
251
|
-
}
|
252
|
-
|
253
244
|
scope.$watch('isOpen', function(value) {
|
254
245
|
if ( value ) {
|
255
246
|
accordionCtrl.closeOthers(scope);
|
256
247
|
}
|
257
|
-
if ( setIsOpen ) {
|
258
|
-
setIsOpen(scope.$parent, value);
|
259
|
-
}
|
260
248
|
});
|
249
|
+
|
250
|
+
scope.toggleOpen = function() {
|
251
|
+
if ( !scope.isDisabled ) {
|
252
|
+
scope.isOpen = !scope.isOpen;
|
253
|
+
}
|
254
|
+
};
|
261
255
|
}
|
262
256
|
};
|
263
|
-
}
|
257
|
+
})
|
264
258
|
|
265
259
|
// Use accordion-heading below an accordion-group to provide a heading containing HTML
|
266
260
|
// <accordion-group>
|
@@ -273,13 +267,11 @@ angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
|
|
273
267
|
template: '', // In effect remove this element!
|
274
268
|
replace: true,
|
275
269
|
require: '^accordionGroup',
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
accordionGroupCtrl.setHeading(transclude(scope, function() {}));
|
282
|
-
};
|
270
|
+
link: function(scope, element, attr, accordionGroupCtrl, transclude) {
|
271
|
+
// Pass the heading to the accordion-group controller
|
272
|
+
// so that it can be transcluded into the right place in the template
|
273
|
+
// [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat]
|
274
|
+
accordionGroupCtrl.setHeading(transclude(scope, function() {}));
|
283
275
|
}
|
284
276
|
};
|
285
277
|
})
|
@@ -304,7 +296,7 @@ angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
|
|
304
296
|
};
|
305
297
|
});
|
306
298
|
|
307
|
-
angular.module(
|
299
|
+
angular.module('ui.bootstrap.alert', [])
|
308
300
|
|
309
301
|
.controller('AlertController', ['$scope', '$attrs', function ($scope, $attrs) {
|
310
302
|
$scope.closeable = 'close' in $attrs;
|
@@ -318,7 +310,7 @@ angular.module("ui.bootstrap.alert", [])
|
|
318
310
|
transclude:true,
|
319
311
|
replace:true,
|
320
312
|
scope: {
|
321
|
-
type: '
|
313
|
+
type: '@',
|
322
314
|
close: '&'
|
323
315
|
}
|
324
316
|
};
|
@@ -360,9 +352,11 @@ angular.module('ui.bootstrap.buttons', [])
|
|
360
352
|
|
361
353
|
//ui->model
|
362
354
|
element.bind(buttonsCtrl.toggleEvent, function () {
|
363
|
-
|
355
|
+
var isActive = element.hasClass(buttonsCtrl.activeClass);
|
356
|
+
|
357
|
+
if (!isActive || angular.isDefined(attrs.uncheckable)) {
|
364
358
|
scope.$apply(function () {
|
365
|
-
ngModelCtrl.$setViewValue(scope.$eval(attrs.btnRadio));
|
359
|
+
ngModelCtrl.$setViewValue(isActive ? null : scope.$eval(attrs.btnRadio));
|
366
360
|
ngModelCtrl.$render();
|
367
361
|
});
|
368
362
|
}
|
@@ -385,7 +379,7 @@ angular.module('ui.bootstrap.buttons', [])
|
|
385
379
|
function getFalseValue() {
|
386
380
|
return getCheckboxValue(attrs.btnCheckboxFalse, false);
|
387
381
|
}
|
388
|
-
|
382
|
+
|
389
383
|
function getCheckboxValue(attributeValue, defaultValue) {
|
390
384
|
var val = scope.$eval(attributeValue);
|
391
385
|
return angular.isDefined(val) ? val : defaultValue;
|
@@ -416,20 +410,20 @@ angular.module('ui.bootstrap.buttons', [])
|
|
416
410
|
*
|
417
411
|
*/
|
418
412
|
angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition'])
|
419
|
-
.controller('CarouselController', ['$scope', '$timeout', '$transition',
|
413
|
+
.controller('CarouselController', ['$scope', '$timeout', '$transition', function ($scope, $timeout, $transition) {
|
420
414
|
var self = this,
|
421
|
-
slides = self.slides = [],
|
415
|
+
slides = self.slides = $scope.slides = [],
|
422
416
|
currentIndex = -1,
|
423
417
|
currentTimeout, isPlaying;
|
424
418
|
self.currentSlide = null;
|
425
419
|
|
426
420
|
var destroyed = false;
|
427
421
|
/* direction: "prev" or "next" */
|
428
|
-
self.select = function(nextSlide, direction) {
|
422
|
+
self.select = $scope.select = function(nextSlide, direction) {
|
429
423
|
var nextIndex = slides.indexOf(nextSlide);
|
430
424
|
//Decide direction if it's not given
|
431
425
|
if (direction === undefined) {
|
432
|
-
direction = nextIndex > currentIndex ?
|
426
|
+
direction = nextIndex > currentIndex ? 'next' : 'prev';
|
433
427
|
}
|
434
428
|
if (nextSlide && nextSlide !== self.currentSlide) {
|
435
429
|
if ($scope.$currentTransition) {
|
@@ -505,18 +499,10 @@ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition'])
|
|
505
499
|
}
|
506
500
|
};
|
507
501
|
|
508
|
-
$scope.select = function(slide) {
|
509
|
-
self.select(slide);
|
510
|
-
};
|
511
|
-
|
512
502
|
$scope.isActive = function(slide) {
|
513
503
|
return self.currentSlide === slide;
|
514
504
|
};
|
515
505
|
|
516
|
-
$scope.slides = function() {
|
517
|
-
return slides;
|
518
|
-
};
|
519
|
-
|
520
506
|
$scope.$watch('interval', restartTimer);
|
521
507
|
$scope.$on('$destroy', resetTimer);
|
522
508
|
|
@@ -665,36 +651,13 @@ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition'])
|
|
665
651
|
</div>
|
666
652
|
</slide>
|
667
653
|
</carousel>
|
668
|
-
<
|
669
|
-
|
670
|
-
<ul>
|
671
|
-
<li ng-repeat="slide in slides">
|
672
|
-
<button class="btn btn-mini" ng-class="{'btn-info': !slide.active, 'btn-success': slide.active}" ng-disabled="slide.active" ng-click="slide.active = true">select</button>
|
673
|
-
{{$index}}: {{slide.text}}
|
674
|
-
</li>
|
675
|
-
</ul>
|
676
|
-
<a class="btn" ng-click="addSlide()">Add Slide</a>
|
677
|
-
</div>
|
678
|
-
<div class="span6">
|
679
|
-
Interval, in milliseconds: <input type="number" ng-model="myInterval">
|
680
|
-
<br />Enter a negative number to stop the interval.
|
681
|
-
</div>
|
682
|
-
</div>
|
654
|
+
Interval, in milliseconds: <input type="number" ng-model="myInterval">
|
655
|
+
<br />Enter a negative number to stop the interval.
|
683
656
|
</div>
|
684
657
|
</file>
|
685
658
|
<file name="script.js">
|
686
659
|
function CarouselDemoCtrl($scope) {
|
687
660
|
$scope.myInterval = 5000;
|
688
|
-
var slides = $scope.slides = [];
|
689
|
-
$scope.addSlide = function() {
|
690
|
-
var newWidth = 200 + ((slides.length + (25 * slides.length)) % 150);
|
691
|
-
slides.push({
|
692
|
-
image: 'http://placekitten.com/' + newWidth + '/200',
|
693
|
-
text: ['More','Extra','Lots of','Surplus'][slides.length % 4] + ' '
|
694
|
-
['Cats', 'Kittys', 'Felines', 'Cutes'][slides.length % 4]
|
695
|
-
});
|
696
|
-
};
|
697
|
-
for (var i=0; i<4; i++) $scope.addSlide();
|
698
661
|
}
|
699
662
|
</file>
|
700
663
|
<file name="demo.css">
|
@@ -706,7 +669,7 @@ function CarouselDemoCtrl($scope) {
|
|
706
669
|
</example>
|
707
670
|
*/
|
708
671
|
|
709
|
-
.directive('slide',
|
672
|
+
.directive('slide', function() {
|
710
673
|
return {
|
711
674
|
require: '^carousel',
|
712
675
|
restrict: 'EA',
|
@@ -714,30 +677,9 @@ function CarouselDemoCtrl($scope) {
|
|
714
677
|
replace: true,
|
715
678
|
templateUrl: 'template/carousel/slide.html',
|
716
679
|
scope: {
|
680
|
+
active: '=?'
|
717
681
|
},
|
718
682
|
link: function (scope, element, attrs, carouselCtrl) {
|
719
|
-
//Set up optional 'active' = binding
|
720
|
-
if (attrs.active) {
|
721
|
-
var getActive = $parse(attrs.active);
|
722
|
-
var setActive = getActive.assign;
|
723
|
-
var lastValue = scope.active = getActive(scope.$parent);
|
724
|
-
scope.$watch(function parentActiveWatch() {
|
725
|
-
var parentActive = getActive(scope.$parent);
|
726
|
-
|
727
|
-
if (parentActive !== scope.active) {
|
728
|
-
// we are out of sync and need to copy
|
729
|
-
if (parentActive !== lastValue) {
|
730
|
-
// parent changed and it has precedence
|
731
|
-
lastValue = scope.active = parentActive;
|
732
|
-
} else {
|
733
|
-
// if the parent can be assigned then do so
|
734
|
-
setActive(scope.$parent, parentActive = lastValue = scope.active);
|
735
|
-
}
|
736
|
-
}
|
737
|
-
return parentActive;
|
738
|
-
});
|
739
|
-
}
|
740
|
-
|
741
683
|
carouselCtrl.addSlide(scope, element);
|
742
684
|
//when the scope is destroyed then remove the slide from the current slides array
|
743
685
|
scope.$on('$destroy', function() {
|
@@ -751,6 +693,133 @@ function CarouselDemoCtrl($scope) {
|
|
751
693
|
});
|
752
694
|
}
|
753
695
|
};
|
696
|
+
});
|
697
|
+
|
698
|
+
angular.module('ui.bootstrap.dateparser', [])
|
699
|
+
|
700
|
+
.service('dateParser', ['$locale', 'orderByFilter', function($locale, orderByFilter) {
|
701
|
+
|
702
|
+
this.parsers = {};
|
703
|
+
|
704
|
+
var formatCodeToRegex = {
|
705
|
+
'yyyy': {
|
706
|
+
regex: '\\d{4}',
|
707
|
+
apply: function(value) { this.year = +value; }
|
708
|
+
},
|
709
|
+
'yy': {
|
710
|
+
regex: '\\d{2}',
|
711
|
+
apply: function(value) { this.year = +value + 2000; }
|
712
|
+
},
|
713
|
+
'y': {
|
714
|
+
regex: '\\d{1,4}',
|
715
|
+
apply: function(value) { this.year = +value; }
|
716
|
+
},
|
717
|
+
'MMMM': {
|
718
|
+
regex: $locale.DATETIME_FORMATS.MONTH.join('|'),
|
719
|
+
apply: function(value) { this.month = $locale.DATETIME_FORMATS.MONTH.indexOf(value); }
|
720
|
+
},
|
721
|
+
'MMM': {
|
722
|
+
regex: $locale.DATETIME_FORMATS.SHORTMONTH.join('|'),
|
723
|
+
apply: function(value) { this.month = $locale.DATETIME_FORMATS.SHORTMONTH.indexOf(value); }
|
724
|
+
},
|
725
|
+
'MM': {
|
726
|
+
regex: '0[1-9]|1[0-2]',
|
727
|
+
apply: function(value) { this.month = value - 1; }
|
728
|
+
},
|
729
|
+
'M': {
|
730
|
+
regex: '[1-9]|1[0-2]',
|
731
|
+
apply: function(value) { this.month = value - 1; }
|
732
|
+
},
|
733
|
+
'dd': {
|
734
|
+
regex: '[0-2][0-9]{1}|3[0-1]{1}',
|
735
|
+
apply: function(value) { this.date = +value; }
|
736
|
+
},
|
737
|
+
'd': {
|
738
|
+
regex: '[1-2]?[0-9]{1}|3[0-1]{1}',
|
739
|
+
apply: function(value) { this.date = +value; }
|
740
|
+
},
|
741
|
+
'EEEE': {
|
742
|
+
regex: $locale.DATETIME_FORMATS.DAY.join('|')
|
743
|
+
},
|
744
|
+
'EEE': {
|
745
|
+
regex: $locale.DATETIME_FORMATS.SHORTDAY.join('|')
|
746
|
+
}
|
747
|
+
};
|
748
|
+
|
749
|
+
this.createParser = function(format) {
|
750
|
+
var map = [], regex = format.split('');
|
751
|
+
|
752
|
+
angular.forEach(formatCodeToRegex, function(data, code) {
|
753
|
+
var index = format.indexOf(code);
|
754
|
+
|
755
|
+
if (index > -1) {
|
756
|
+
format = format.split('');
|
757
|
+
|
758
|
+
regex[index] = '(' + data.regex + ')';
|
759
|
+
format[index] = '$'; // Custom symbol to define consumed part of format
|
760
|
+
for (var i = index + 1, n = index + code.length; i < n; i++) {
|
761
|
+
regex[i] = '';
|
762
|
+
format[i] = '$';
|
763
|
+
}
|
764
|
+
format = format.join('');
|
765
|
+
|
766
|
+
map.push({ index: index, apply: data.apply });
|
767
|
+
}
|
768
|
+
});
|
769
|
+
|
770
|
+
return {
|
771
|
+
regex: new RegExp('^' + regex.join('') + '$'),
|
772
|
+
map: orderByFilter(map, 'index')
|
773
|
+
};
|
774
|
+
};
|
775
|
+
|
776
|
+
this.parse = function(input, format) {
|
777
|
+
if ( !angular.isString(input) ) {
|
778
|
+
return input;
|
779
|
+
}
|
780
|
+
|
781
|
+
format = $locale.DATETIME_FORMATS[format] || format;
|
782
|
+
|
783
|
+
if ( !this.parsers[format] ) {
|
784
|
+
this.parsers[format] = this.createParser(format);
|
785
|
+
}
|
786
|
+
|
787
|
+
var parser = this.parsers[format],
|
788
|
+
regex = parser.regex,
|
789
|
+
map = parser.map,
|
790
|
+
results = input.match(regex);
|
791
|
+
|
792
|
+
if ( results && results.length ) {
|
793
|
+
var fields = { year: 1900, month: 0, date: 1, hours: 0 }, dt;
|
794
|
+
|
795
|
+
for( var i = 1, n = results.length; i < n; i++ ) {
|
796
|
+
var mapper = map[i-1];
|
797
|
+
if ( mapper.apply ) {
|
798
|
+
mapper.apply.call(fields, results[i]);
|
799
|
+
}
|
800
|
+
}
|
801
|
+
|
802
|
+
if ( isValid(fields.year, fields.month, fields.date) ) {
|
803
|
+
dt = new Date( fields.year, fields.month, fields.date, fields.hours);
|
804
|
+
}
|
805
|
+
|
806
|
+
return dt;
|
807
|
+
}
|
808
|
+
};
|
809
|
+
|
810
|
+
// Check if date is valid for specific month (and year for February).
|
811
|
+
// Month: 0 = Jan, 1 = Feb, etc
|
812
|
+
function isValid(year, month, date) {
|
813
|
+
if ( month === 1 && date > 28) {
|
814
|
+
return date === 29 && ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0);
|
815
|
+
}
|
816
|
+
|
817
|
+
if ( month === 3 || month === 5 || month === 8 || month === 10) {
|
818
|
+
return date < 31;
|
819
|
+
}
|
820
|
+
|
821
|
+
return true;
|
822
|
+
}
|
754
823
|
}]);
|
755
824
|
|
756
825
|
angular.module('ui.bootstrap.position', [])
|
@@ -778,7 +847,7 @@ angular.module('ui.bootstrap.position', [])
|
|
778
847
|
* @param element - raw DOM element
|
779
848
|
*/
|
780
849
|
function isStaticPositioned(element) {
|
781
|
-
return (getStyle(element,
|
850
|
+
return (getStyle(element, 'position') || 'static' ) === 'static';
|
782
851
|
}
|
783
852
|
|
784
853
|
/**
|
@@ -827,22 +896,97 @@ angular.module('ui.bootstrap.position', [])
|
|
827
896
|
return {
|
828
897
|
width: boundingClientRect.width || element.prop('offsetWidth'),
|
829
898
|
height: boundingClientRect.height || element.prop('offsetHeight'),
|
830
|
-
top: boundingClientRect.top + ($window.pageYOffset || $document[0].
|
831
|
-
left: boundingClientRect.left + ($window.pageXOffset || $document[0].
|
899
|
+
top: boundingClientRect.top + ($window.pageYOffset || $document[0].documentElement.scrollTop),
|
900
|
+
left: boundingClientRect.left + ($window.pageXOffset || $document[0].documentElement.scrollLeft)
|
901
|
+
};
|
902
|
+
},
|
903
|
+
|
904
|
+
/**
|
905
|
+
* Provides coordinates for the targetEl in relation to hostEl
|
906
|
+
*/
|
907
|
+
positionElements: function (hostEl, targetEl, positionStr, appendToBody) {
|
908
|
+
|
909
|
+
var positionStrParts = positionStr.split('-');
|
910
|
+
var pos0 = positionStrParts[0], pos1 = positionStrParts[1] || 'center';
|
911
|
+
|
912
|
+
var hostElPos,
|
913
|
+
targetElWidth,
|
914
|
+
targetElHeight,
|
915
|
+
targetElPos;
|
916
|
+
|
917
|
+
hostElPos = appendToBody ? this.offset(hostEl) : this.position(hostEl);
|
918
|
+
|
919
|
+
targetElWidth = targetEl.prop('offsetWidth');
|
920
|
+
targetElHeight = targetEl.prop('offsetHeight');
|
921
|
+
|
922
|
+
var shiftWidth = {
|
923
|
+
center: function () {
|
924
|
+
return hostElPos.left + hostElPos.width / 2 - targetElWidth / 2;
|
925
|
+
},
|
926
|
+
left: function () {
|
927
|
+
return hostElPos.left;
|
928
|
+
},
|
929
|
+
right: function () {
|
930
|
+
return hostElPos.left + hostElPos.width;
|
931
|
+
}
|
932
|
+
};
|
933
|
+
|
934
|
+
var shiftHeight = {
|
935
|
+
center: function () {
|
936
|
+
return hostElPos.top + hostElPos.height / 2 - targetElHeight / 2;
|
937
|
+
},
|
938
|
+
top: function () {
|
939
|
+
return hostElPos.top;
|
940
|
+
},
|
941
|
+
bottom: function () {
|
942
|
+
return hostElPos.top + hostElPos.height;
|
943
|
+
}
|
832
944
|
};
|
945
|
+
|
946
|
+
switch (pos0) {
|
947
|
+
case 'right':
|
948
|
+
targetElPos = {
|
949
|
+
top: shiftHeight[pos1](),
|
950
|
+
left: shiftWidth[pos0]()
|
951
|
+
};
|
952
|
+
break;
|
953
|
+
case 'left':
|
954
|
+
targetElPos = {
|
955
|
+
top: shiftHeight[pos1](),
|
956
|
+
left: hostElPos.left - targetElWidth
|
957
|
+
};
|
958
|
+
break;
|
959
|
+
case 'bottom':
|
960
|
+
targetElPos = {
|
961
|
+
top: shiftHeight[pos0](),
|
962
|
+
left: shiftWidth[pos1]()
|
963
|
+
};
|
964
|
+
break;
|
965
|
+
default:
|
966
|
+
targetElPos = {
|
967
|
+
top: hostElPos.top - targetElHeight,
|
968
|
+
left: shiftWidth[pos1]()
|
969
|
+
};
|
970
|
+
break;
|
971
|
+
}
|
972
|
+
|
973
|
+
return targetElPos;
|
833
974
|
}
|
834
975
|
};
|
835
976
|
}]);
|
836
977
|
|
837
|
-
angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.position'])
|
978
|
+
angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootstrap.position'])
|
838
979
|
|
839
980
|
.constant('datepickerConfig', {
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
981
|
+
formatDay: 'dd',
|
982
|
+
formatMonth: 'MMMM',
|
983
|
+
formatYear: 'yyyy',
|
984
|
+
formatDayHeader: 'EEE',
|
985
|
+
formatDayTitle: 'MMMM yyyy',
|
986
|
+
formatMonthTitle: 'yyyy',
|
987
|
+
datepickerMode: 'day',
|
988
|
+
minMode: 'day',
|
989
|
+
maxMode: 'year',
|
846
990
|
showWeeks: true,
|
847
991
|
startingDay: 0,
|
848
992
|
yearRange: 20,
|
@@ -850,229 +994,256 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.position'])
|
|
850
994
|
maxDate: null
|
851
995
|
})
|
852
996
|
|
853
|
-
.controller('DatepickerController', ['$scope', '$attrs', 'dateFilter', 'datepickerConfig', function($scope, $attrs, dateFilter,
|
854
|
-
var
|
855
|
-
|
856
|
-
month: getValue($attrs.monthFormat, dtConfig.monthFormat),
|
857
|
-
year: getValue($attrs.yearFormat, dtConfig.yearFormat),
|
858
|
-
dayHeader: getValue($attrs.dayHeaderFormat, dtConfig.dayHeaderFormat),
|
859
|
-
dayTitle: getValue($attrs.dayTitleFormat, dtConfig.dayTitleFormat),
|
860
|
-
monthTitle: getValue($attrs.monthTitleFormat, dtConfig.monthTitleFormat)
|
861
|
-
},
|
862
|
-
startingDay = getValue($attrs.startingDay, dtConfig.startingDay),
|
863
|
-
yearRange = getValue($attrs.yearRange, dtConfig.yearRange);
|
864
|
-
|
865
|
-
this.minDate = dtConfig.minDate ? new Date(dtConfig.minDate) : null;
|
866
|
-
this.maxDate = dtConfig.maxDate ? new Date(dtConfig.maxDate) : null;
|
867
|
-
|
868
|
-
function getValue(value, defaultValue) {
|
869
|
-
return angular.isDefined(value) ? $scope.$parent.$eval(value) : defaultValue;
|
870
|
-
}
|
997
|
+
.controller('DatepickerController', ['$scope', '$attrs', '$parse', '$interpolate', '$timeout', '$log', 'dateFilter', 'datepickerConfig', function($scope, $attrs, $parse, $interpolate, $timeout, $log, dateFilter, datepickerConfig) {
|
998
|
+
var self = this,
|
999
|
+
ngModelCtrl = { $setViewValue: angular.noop }; // nullModelCtrl;
|
871
1000
|
|
872
|
-
|
873
|
-
|
874
|
-
|
1001
|
+
// Modes chain
|
1002
|
+
this.modes = ['day', 'month', 'year'];
|
1003
|
+
|
1004
|
+
// Configuration attributes
|
1005
|
+
angular.forEach(['formatDay', 'formatMonth', 'formatYear', 'formatDayHeader', 'formatDayTitle', 'formatMonthTitle',
|
1006
|
+
'minMode', 'maxMode', 'showWeeks', 'startingDay', 'yearRange'], function( key, index ) {
|
1007
|
+
self[key] = angular.isDefined($attrs[key]) ? (index < 8 ? $interpolate($attrs[key])($scope.$parent) : $scope.$parent.$eval($attrs[key])) : datepickerConfig[key];
|
1008
|
+
});
|
875
1009
|
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
1010
|
+
// Watchable attributes
|
1011
|
+
angular.forEach(['minDate', 'maxDate'], function( key ) {
|
1012
|
+
if ( $attrs[key] ) {
|
1013
|
+
$scope.$parent.$watch($parse($attrs[key]), function(value) {
|
1014
|
+
self[key] = value ? new Date(value) : null;
|
1015
|
+
self.refreshView();
|
1016
|
+
});
|
1017
|
+
} else {
|
1018
|
+
self[key] = datepickerConfig[key] ? new Date(datepickerConfig[key]) : null;
|
882
1019
|
}
|
883
|
-
|
884
|
-
}
|
1020
|
+
});
|
885
1021
|
|
886
|
-
|
887
|
-
|
888
|
-
|
1022
|
+
$scope.datepickerMode = $scope.datepickerMode || datepickerConfig.datepickerMode;
|
1023
|
+
$scope.uniqueId = 'datepicker-' + $scope.$id + '-' + Math.floor(Math.random() * 10000);
|
1024
|
+
this.activeDate = angular.isDefined($attrs.initDate) ? $scope.$parent.$eval($attrs.initDate) : new Date();
|
889
1025
|
|
890
|
-
|
891
|
-
{
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
firstDate = new Date(firstDayOfMonth), numDates = 0;
|
1026
|
+
$scope.isActive = function(dateObject) {
|
1027
|
+
if (self.compare(dateObject.date, self.activeDate) === 0) {
|
1028
|
+
$scope.activeDateId = dateObject.uid;
|
1029
|
+
return true;
|
1030
|
+
}
|
1031
|
+
return false;
|
1032
|
+
};
|
898
1033
|
|
899
|
-
|
900
|
-
|
901
|
-
numDates += numDisplayedFromPreviousMonth; // Previous
|
902
|
-
}
|
903
|
-
numDates += getDaysInMonth(year, month + 1); // Current
|
904
|
-
numDates += (7 - numDates % 7) % 7; // Next
|
1034
|
+
this.init = function( ngModelCtrl_ ) {
|
1035
|
+
ngModelCtrl = ngModelCtrl_;
|
905
1036
|
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
}
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
{
|
923
|
-
name: 'month',
|
924
|
-
getVisibleDates: function(date, selected) {
|
925
|
-
var months = new Array(12), year = date.getFullYear();
|
926
|
-
for ( var i = 0; i < 12; i++ ) {
|
927
|
-
var dt = new Date(year, i, 1);
|
928
|
-
months[i] = makeDate(dt, format.month, (selected && selected.getMonth() === i && selected.getFullYear() === year));
|
929
|
-
}
|
930
|
-
return { objects: months, title: dateFilter(date, format.monthTitle) };
|
931
|
-
},
|
932
|
-
compare: function(date1, date2) {
|
933
|
-
return new Date( date1.getFullYear(), date1.getMonth() ) - new Date( date2.getFullYear(), date2.getMonth() );
|
934
|
-
},
|
935
|
-
split: 3,
|
936
|
-
step: { years: 1 }
|
937
|
-
},
|
938
|
-
{
|
939
|
-
name: 'year',
|
940
|
-
getVisibleDates: function(date, selected) {
|
941
|
-
var years = new Array(yearRange), year = date.getFullYear(), startYear = parseInt((year - 1) / yearRange, 10) * yearRange + 1;
|
942
|
-
for ( var i = 0; i < yearRange; i++ ) {
|
943
|
-
var dt = new Date(startYear + i, 0, 1);
|
944
|
-
years[i] = makeDate(dt, format.year, (selected && selected.getFullYear() === dt.getFullYear()));
|
945
|
-
}
|
946
|
-
return { objects: years, title: [years[0].label, years[yearRange - 1].label].join(' - ') };
|
947
|
-
},
|
948
|
-
compare: function(date1, date2) {
|
949
|
-
return date1.getFullYear() - date2.getFullYear();
|
950
|
-
},
|
951
|
-
split: 5,
|
952
|
-
step: { years: yearRange }
|
1037
|
+
ngModelCtrl.$render = function() {
|
1038
|
+
self.render();
|
1039
|
+
};
|
1040
|
+
};
|
1041
|
+
|
1042
|
+
this.render = function() {
|
1043
|
+
if ( ngModelCtrl.$modelValue ) {
|
1044
|
+
var date = new Date( ngModelCtrl.$modelValue ),
|
1045
|
+
isValid = !isNaN(date);
|
1046
|
+
|
1047
|
+
if ( isValid ) {
|
1048
|
+
this.activeDate = date;
|
1049
|
+
} else {
|
1050
|
+
$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.');
|
1051
|
+
}
|
1052
|
+
ngModelCtrl.$setValidity('date', isValid);
|
953
1053
|
}
|
954
|
-
|
1054
|
+
this.refreshView();
|
1055
|
+
};
|
1056
|
+
|
1057
|
+
this.refreshView = function() {
|
1058
|
+
if ( this.element ) {
|
1059
|
+
this._refreshView();
|
955
1060
|
|
956
|
-
|
957
|
-
|
958
|
-
|
1061
|
+
var date = ngModelCtrl.$modelValue ? new Date(ngModelCtrl.$modelValue) : null;
|
1062
|
+
ngModelCtrl.$setValidity('date-disabled', !date || (this.element && !this.isDisabled(date)));
|
1063
|
+
}
|
1064
|
+
};
|
1065
|
+
|
1066
|
+
this.createDateObject = function(date, format) {
|
1067
|
+
var model = ngModelCtrl.$modelValue ? new Date(ngModelCtrl.$modelValue) : null;
|
1068
|
+
return {
|
1069
|
+
date: date,
|
1070
|
+
label: dateFilter(date, format),
|
1071
|
+
selected: model && this.compare(date, model) === 0,
|
1072
|
+
disabled: this.isDisabled(date),
|
1073
|
+
current: this.compare(date, new Date()) === 0
|
1074
|
+
};
|
1075
|
+
};
|
1076
|
+
|
1077
|
+
this.isDisabled = function( date ) {
|
1078
|
+
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})));
|
1079
|
+
};
|
1080
|
+
|
1081
|
+
// Split array into smaller arrays
|
1082
|
+
this.split = function(arr, size) {
|
1083
|
+
var arrays = [];
|
1084
|
+
while (arr.length > 0) {
|
1085
|
+
arrays.push(arr.splice(0, size));
|
1086
|
+
}
|
1087
|
+
return arrays;
|
1088
|
+
};
|
1089
|
+
|
1090
|
+
$scope.select = function( date ) {
|
1091
|
+
if ( $scope.datepickerMode === self.minMode ) {
|
1092
|
+
var dt = ngModelCtrl.$modelValue ? new Date( ngModelCtrl.$modelValue ) : new Date(0, 0, 0, 0, 0, 0, 0);
|
1093
|
+
dt.setFullYear( date.getFullYear(), date.getMonth(), date.getDate() );
|
1094
|
+
ngModelCtrl.$setViewValue( dt );
|
1095
|
+
ngModelCtrl.$render();
|
1096
|
+
} else {
|
1097
|
+
self.activeDate = date;
|
1098
|
+
$scope.datepickerMode = self.modes[ self.modes.indexOf( $scope.datepickerMode ) - 1 ];
|
1099
|
+
}
|
1100
|
+
};
|
1101
|
+
|
1102
|
+
$scope.move = function( direction ) {
|
1103
|
+
var year = self.activeDate.getFullYear() + direction * (self.step.years || 0),
|
1104
|
+
month = self.activeDate.getMonth() + direction * (self.step.months || 0);
|
1105
|
+
self.activeDate.setFullYear(year, month, 1);
|
1106
|
+
self.refreshView();
|
1107
|
+
};
|
1108
|
+
|
1109
|
+
$scope.toggleMode = function( direction ) {
|
1110
|
+
direction = direction || 1;
|
1111
|
+
|
1112
|
+
if (($scope.datepickerMode === self.maxMode && direction === 1) || ($scope.datepickerMode === self.minMode && direction === -1)) {
|
1113
|
+
return;
|
1114
|
+
}
|
1115
|
+
|
1116
|
+
$scope.datepickerMode = self.modes[ self.modes.indexOf( $scope.datepickerMode ) + direction ];
|
1117
|
+
};
|
1118
|
+
|
1119
|
+
// Key event mapper
|
1120
|
+
$scope.keys = { 13:'enter', 32:'space', 33:'pageup', 34:'pagedown', 35:'end', 36:'home', 37:'left', 38:'up', 39:'right', 40:'down' };
|
1121
|
+
|
1122
|
+
var focusElement = function() {
|
1123
|
+
$timeout(function() {
|
1124
|
+
self.element[0].focus();
|
1125
|
+
}, 0 , false);
|
1126
|
+
};
|
1127
|
+
|
1128
|
+
// Listen for focus requests from popup directive
|
1129
|
+
$scope.$on('datepicker.focus', focusElement);
|
1130
|
+
|
1131
|
+
$scope.keydown = function( evt ) {
|
1132
|
+
var key = $scope.keys[evt.which];
|
1133
|
+
|
1134
|
+
if ( !key || evt.shiftKey || evt.altKey ) {
|
1135
|
+
return;
|
1136
|
+
}
|
1137
|
+
|
1138
|
+
evt.preventDefault();
|
1139
|
+
evt.stopPropagation();
|
1140
|
+
|
1141
|
+
if (key === 'enter' || key === 'space') {
|
1142
|
+
if ( self.isDisabled(self.activeDate)) {
|
1143
|
+
return; // do nothing
|
1144
|
+
}
|
1145
|
+
$scope.select(self.activeDate);
|
1146
|
+
focusElement();
|
1147
|
+
} else if (evt.ctrlKey && (key === 'up' || key === 'down')) {
|
1148
|
+
$scope.toggleMode(key === 'up' ? 1 : -1);
|
1149
|
+
focusElement();
|
1150
|
+
} else {
|
1151
|
+
self.handleKeyDown(key, evt);
|
1152
|
+
self.refreshView();
|
1153
|
+
}
|
959
1154
|
};
|
960
1155
|
}])
|
961
1156
|
|
962
|
-
.directive( 'datepicker',
|
1157
|
+
.directive( 'datepicker', function () {
|
963
1158
|
return {
|
964
1159
|
restrict: 'EA',
|
965
1160
|
replace: true,
|
966
1161
|
templateUrl: 'template/datepicker/datepicker.html',
|
967
1162
|
scope: {
|
1163
|
+
datepickerMode: '=?',
|
968
1164
|
dateDisabled: '&'
|
969
1165
|
},
|
970
1166
|
require: ['datepicker', '?^ngModel'],
|
971
1167
|
controller: 'DatepickerController',
|
972
1168
|
link: function(scope, element, attrs, ctrls) {
|
973
|
-
var datepickerCtrl = ctrls[0],
|
1169
|
+
var datepickerCtrl = ctrls[0], ngModelCtrl = ctrls[1];
|
974
1170
|
|
975
|
-
if (
|
976
|
-
|
1171
|
+
if ( ngModelCtrl ) {
|
1172
|
+
datepickerCtrl.init( ngModelCtrl );
|
977
1173
|
}
|
1174
|
+
}
|
1175
|
+
};
|
1176
|
+
})
|
978
1177
|
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
} else {
|
988
|
-
updateShowWeekNumbers();
|
989
|
-
}
|
1178
|
+
.directive('daypicker', ['dateFilter', function (dateFilter) {
|
1179
|
+
return {
|
1180
|
+
restrict: 'EA',
|
1181
|
+
replace: true,
|
1182
|
+
templateUrl: 'template/datepicker/day.html',
|
1183
|
+
require: '^datepicker',
|
1184
|
+
link: function(scope, element, attrs, ctrl) {
|
1185
|
+
scope.showWeeks = ctrl.showWeeks;
|
990
1186
|
|
991
|
-
|
992
|
-
|
993
|
-
datepickerCtrl.minDate = value ? new Date(value) : null;
|
994
|
-
refill();
|
995
|
-
});
|
996
|
-
}
|
997
|
-
if (attrs.max) {
|
998
|
-
scope.$parent.$watch($parse(attrs.max), function(value) {
|
999
|
-
datepickerCtrl.maxDate = value ? new Date(value) : null;
|
1000
|
-
refill();
|
1001
|
-
});
|
1002
|
-
}
|
1187
|
+
ctrl.step = { months: 1 };
|
1188
|
+
ctrl.element = element;
|
1003
1189
|
|
1004
|
-
|
1005
|
-
|
1190
|
+
var DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
1191
|
+
function getDaysInMonth( year, month ) {
|
1192
|
+
return ((month === 1) && (year % 4 === 0) && ((year % 100 !== 0) || (year % 400 === 0))) ? 29 : DAYS_IN_MONTH[month];
|
1006
1193
|
}
|
1007
1194
|
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
while (
|
1012
|
-
|
1195
|
+
function getDates(startDate, n) {
|
1196
|
+
var dates = new Array(n), current = new Date(startDate), i = 0;
|
1197
|
+
current.setHours(12); // Prevent repeated dates because of timezone bug
|
1198
|
+
while ( i < n ) {
|
1199
|
+
dates[i++] = new Date(current);
|
1200
|
+
current.setDate( current.getDate() + 1 );
|
1013
1201
|
}
|
1014
|
-
return
|
1202
|
+
return dates;
|
1015
1203
|
}
|
1016
1204
|
|
1017
|
-
function
|
1018
|
-
var
|
1205
|
+
ctrl._refreshView = function() {
|
1206
|
+
var year = ctrl.activeDate.getFullYear(),
|
1207
|
+
month = ctrl.activeDate.getMonth(),
|
1208
|
+
firstDayOfMonth = new Date(year, month, 1),
|
1209
|
+
difference = ctrl.startingDay - firstDayOfMonth.getDay(),
|
1210
|
+
numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : - difference,
|
1211
|
+
firstDate = new Date(firstDayOfMonth);
|
1019
1212
|
|
1020
|
-
if (
|
1021
|
-
|
1022
|
-
|
1023
|
-
if ( isNaN(date) ) {
|
1024
|
-
valid = false;
|
1025
|
-
$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.');
|
1026
|
-
} else if ( updateSelected ) {
|
1027
|
-
selected = date;
|
1028
|
-
}
|
1213
|
+
if ( numDisplayedFromPreviousMonth > 0 ) {
|
1214
|
+
firstDate.setDate( - numDisplayedFromPreviousMonth + 1 );
|
1029
1215
|
}
|
1030
|
-
ngModel.$setValidity('date', valid);
|
1031
|
-
|
1032
|
-
var currentMode = datepickerCtrl.modes[mode], data = currentMode.getVisibleDates(selected, date);
|
1033
|
-
angular.forEach(data.objects, function(obj) {
|
1034
|
-
obj.disabled = datepickerCtrl.isDisabled(obj.date, mode);
|
1035
|
-
});
|
1036
|
-
|
1037
|
-
ngModel.$setValidity('date-disabled', (!date || !datepickerCtrl.isDisabled(date)));
|
1038
1216
|
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1217
|
+
// 42 is the number of days on a six-month calendar
|
1218
|
+
var days = getDates(firstDate, 42);
|
1219
|
+
for (var i = 0; i < 42; i ++) {
|
1220
|
+
days[i] = angular.extend(ctrl.createDateObject(days[i], ctrl.formatDay), {
|
1221
|
+
secondary: days[i].getMonth() !== month,
|
1222
|
+
uid: scope.uniqueId + '-' + i
|
1223
|
+
});
|
1224
|
+
}
|
1043
1225
|
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1226
|
+
scope.labels = new Array(7);
|
1227
|
+
for (var j = 0; j < 7; j++) {
|
1228
|
+
scope.labels[j] = {
|
1229
|
+
abbr: dateFilter(days[j].date, ctrl.formatDayHeader),
|
1230
|
+
full: dateFilter(days[j].date, 'EEEE')
|
1231
|
+
};
|
1232
|
+
}
|
1049
1233
|
|
1050
|
-
|
1051
|
-
|
1052
|
-
};
|
1234
|
+
scope.title = dateFilter(ctrl.activeDate, ctrl.formatDayTitle);
|
1235
|
+
scope.rows = ctrl.split(days, 7);
|
1053
1236
|
|
1054
|
-
|
1055
|
-
|
1056
|
-
var
|
1057
|
-
|
1058
|
-
|
1059
|
-
refill( true );
|
1060
|
-
} else {
|
1061
|
-
selected = date;
|
1062
|
-
setMode( mode - 1 );
|
1237
|
+
if ( scope.showWeeks ) {
|
1238
|
+
scope.weekNumbers = [];
|
1239
|
+
var weekNumber = getISO8601WeekNumber( scope.rows[0][0].date ),
|
1240
|
+
numWeeks = scope.rows.length;
|
1241
|
+
while( scope.weekNumbers.push(weekNumber++) < numWeeks ) {}
|
1063
1242
|
}
|
1064
1243
|
};
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
selected.setFullYear( selected.getFullYear() + direction * (step.years || 0) );
|
1069
|
-
refill();
|
1070
|
-
};
|
1071
|
-
scope.toggleMode = function() {
|
1072
|
-
setMode( (mode + 1) % datepickerCtrl.modes.length );
|
1073
|
-
};
|
1074
|
-
scope.getWeekNumber = function(row) {
|
1075
|
-
return ( mode === 0 && scope.showWeekNumbers && row.length === 7 ) ? getISO8601WeekNumber(row[0].date) : null;
|
1244
|
+
|
1245
|
+
ctrl.compare = function(date1, date2) {
|
1246
|
+
return (new Date( date1.getFullYear(), date1.getMonth(), date1.getDate() ) - new Date( date2.getFullYear(), date2.getMonth(), date2.getDate() ) );
|
1076
1247
|
};
|
1077
1248
|
|
1078
1249
|
function getISO8601WeekNumber(date) {
|
@@ -1083,14 +1254,152 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.position'])
|
|
1083
1254
|
checkDate.setDate(1);
|
1084
1255
|
return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
|
1085
1256
|
}
|
1257
|
+
|
1258
|
+
ctrl.handleKeyDown = function( key, evt ) {
|
1259
|
+
var date = ctrl.activeDate.getDate();
|
1260
|
+
|
1261
|
+
if (key === 'left') {
|
1262
|
+
date = date - 1; // up
|
1263
|
+
} else if (key === 'up') {
|
1264
|
+
date = date - 7; // down
|
1265
|
+
} else if (key === 'right') {
|
1266
|
+
date = date + 1; // down
|
1267
|
+
} else if (key === 'down') {
|
1268
|
+
date = date + 7;
|
1269
|
+
} else if (key === 'pageup' || key === 'pagedown') {
|
1270
|
+
var month = ctrl.activeDate.getMonth() + (key === 'pageup' ? - 1 : 1);
|
1271
|
+
ctrl.activeDate.setMonth(month, 1);
|
1272
|
+
date = Math.min(getDaysInMonth(ctrl.activeDate.getFullYear(), ctrl.activeDate.getMonth()), date);
|
1273
|
+
} else if (key === 'home') {
|
1274
|
+
date = 1;
|
1275
|
+
} else if (key === 'end') {
|
1276
|
+
date = getDaysInMonth(ctrl.activeDate.getFullYear(), ctrl.activeDate.getMonth());
|
1277
|
+
}
|
1278
|
+
ctrl.activeDate.setDate(date);
|
1279
|
+
};
|
1280
|
+
|
1281
|
+
ctrl.refreshView();
|
1282
|
+
}
|
1283
|
+
};
|
1284
|
+
}])
|
1285
|
+
|
1286
|
+
.directive('monthpicker', ['dateFilter', function (dateFilter) {
|
1287
|
+
return {
|
1288
|
+
restrict: 'EA',
|
1289
|
+
replace: true,
|
1290
|
+
templateUrl: 'template/datepicker/month.html',
|
1291
|
+
require: '^datepicker',
|
1292
|
+
link: function(scope, element, attrs, ctrl) {
|
1293
|
+
ctrl.step = { years: 1 };
|
1294
|
+
ctrl.element = element;
|
1295
|
+
|
1296
|
+
ctrl._refreshView = function() {
|
1297
|
+
var months = new Array(12),
|
1298
|
+
year = ctrl.activeDate.getFullYear();
|
1299
|
+
|
1300
|
+
for ( var i = 0; i < 12; i++ ) {
|
1301
|
+
months[i] = angular.extend(ctrl.createDateObject(new Date(year, i, 1), ctrl.formatMonth), {
|
1302
|
+
uid: scope.uniqueId + '-' + i
|
1303
|
+
});
|
1304
|
+
}
|
1305
|
+
|
1306
|
+
scope.title = dateFilter(ctrl.activeDate, ctrl.formatMonthTitle);
|
1307
|
+
scope.rows = ctrl.split(months, 3);
|
1308
|
+
};
|
1309
|
+
|
1310
|
+
ctrl.compare = function(date1, date2) {
|
1311
|
+
return new Date( date1.getFullYear(), date1.getMonth() ) - new Date( date2.getFullYear(), date2.getMonth() );
|
1312
|
+
};
|
1313
|
+
|
1314
|
+
ctrl.handleKeyDown = function( key, evt ) {
|
1315
|
+
var date = ctrl.activeDate.getMonth();
|
1316
|
+
|
1317
|
+
if (key === 'left') {
|
1318
|
+
date = date - 1; // up
|
1319
|
+
} else if (key === 'up') {
|
1320
|
+
date = date - 3; // down
|
1321
|
+
} else if (key === 'right') {
|
1322
|
+
date = date + 1; // down
|
1323
|
+
} else if (key === 'down') {
|
1324
|
+
date = date + 3;
|
1325
|
+
} else if (key === 'pageup' || key === 'pagedown') {
|
1326
|
+
var year = ctrl.activeDate.getFullYear() + (key === 'pageup' ? - 1 : 1);
|
1327
|
+
ctrl.activeDate.setFullYear(year);
|
1328
|
+
} else if (key === 'home') {
|
1329
|
+
date = 0;
|
1330
|
+
} else if (key === 'end') {
|
1331
|
+
date = 11;
|
1332
|
+
}
|
1333
|
+
ctrl.activeDate.setMonth(date);
|
1334
|
+
};
|
1335
|
+
|
1336
|
+
ctrl.refreshView();
|
1337
|
+
}
|
1338
|
+
};
|
1339
|
+
}])
|
1340
|
+
|
1341
|
+
.directive('yearpicker', ['dateFilter', function (dateFilter) {
|
1342
|
+
return {
|
1343
|
+
restrict: 'EA',
|
1344
|
+
replace: true,
|
1345
|
+
templateUrl: 'template/datepicker/year.html',
|
1346
|
+
require: '^datepicker',
|
1347
|
+
link: function(scope, element, attrs, ctrl) {
|
1348
|
+
var range = ctrl.yearRange;
|
1349
|
+
|
1350
|
+
ctrl.step = { years: range };
|
1351
|
+
ctrl.element = element;
|
1352
|
+
|
1353
|
+
function getStartingYear( year ) {
|
1354
|
+
return parseInt((year - 1) / range, 10) * range + 1;
|
1355
|
+
}
|
1356
|
+
|
1357
|
+
ctrl._refreshView = function() {
|
1358
|
+
var years = new Array(range);
|
1359
|
+
|
1360
|
+
for ( var i = 0, start = getStartingYear(ctrl.activeDate.getFullYear()); i < range; i++ ) {
|
1361
|
+
years[i] = angular.extend(ctrl.createDateObject(new Date(start + i, 0, 1), ctrl.formatYear), {
|
1362
|
+
uid: scope.uniqueId + '-' + i
|
1363
|
+
});
|
1364
|
+
}
|
1365
|
+
|
1366
|
+
scope.title = [years[0].label, years[range - 1].label].join(' - ');
|
1367
|
+
scope.rows = ctrl.split(years, 5);
|
1368
|
+
};
|
1369
|
+
|
1370
|
+
ctrl.compare = function(date1, date2) {
|
1371
|
+
return date1.getFullYear() - date2.getFullYear();
|
1372
|
+
};
|
1373
|
+
|
1374
|
+
ctrl.handleKeyDown = function( key, evt ) {
|
1375
|
+
var date = ctrl.activeDate.getFullYear();
|
1376
|
+
|
1377
|
+
if (key === 'left') {
|
1378
|
+
date = date - 1; // up
|
1379
|
+
} else if (key === 'up') {
|
1380
|
+
date = date - 5; // down
|
1381
|
+
} else if (key === 'right') {
|
1382
|
+
date = date + 1; // down
|
1383
|
+
} else if (key === 'down') {
|
1384
|
+
date = date + 5;
|
1385
|
+
} else if (key === 'pageup' || key === 'pagedown') {
|
1386
|
+
date += (key === 'pageup' ? - 1 : 1) * ctrl.step.years;
|
1387
|
+
} else if (key === 'home') {
|
1388
|
+
date = getStartingYear( ctrl.activeDate.getFullYear() );
|
1389
|
+
} else if (key === 'end') {
|
1390
|
+
date = getStartingYear( ctrl.activeDate.getFullYear() ) + range - 1;
|
1391
|
+
}
|
1392
|
+
ctrl.activeDate.setFullYear(date);
|
1393
|
+
};
|
1394
|
+
|
1395
|
+
ctrl.refreshView();
|
1086
1396
|
}
|
1087
1397
|
};
|
1088
1398
|
}])
|
1089
1399
|
|
1090
1400
|
.constant('datepickerPopupConfig', {
|
1091
|
-
|
1401
|
+
datepickerPopup: 'yyyy-MM-dd',
|
1092
1402
|
currentText: 'Today',
|
1093
|
-
toggleWeeksText: 'Weeks',
|
1094
1403
|
clearText: 'Clear',
|
1095
1404
|
closeText: 'Done',
|
1096
1405
|
closeOnDateSelection: true,
|
@@ -1098,98 +1407,74 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.position'])
|
|
1098
1407
|
showButtonBar: true
|
1099
1408
|
})
|
1100
1409
|
|
1101
|
-
.directive('datepickerPopup', ['$compile', '$parse', '$document', '$position', 'dateFilter', '
|
1102
|
-
function ($compile, $parse, $document, $position, dateFilter,
|
1410
|
+
.directive('datepickerPopup', ['$compile', '$parse', '$document', '$position', 'dateFilter', 'dateParser', 'datepickerPopupConfig',
|
1411
|
+
function ($compile, $parse, $document, $position, dateFilter, dateParser, datepickerPopupConfig) {
|
1103
1412
|
return {
|
1104
1413
|
restrict: 'EA',
|
1105
1414
|
require: 'ngModel',
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1415
|
+
scope: {
|
1416
|
+
isOpen: '=?',
|
1417
|
+
currentText: '@',
|
1418
|
+
clearText: '@',
|
1419
|
+
closeText: '@',
|
1420
|
+
dateDisabled: '&'
|
1421
|
+
},
|
1422
|
+
link: function(scope, element, attrs, ngModel) {
|
1423
|
+
var dateFormat,
|
1424
|
+
closeOnDateSelection = angular.isDefined(attrs.closeOnDateSelection) ? scope.$parent.$eval(attrs.closeOnDateSelection) : datepickerPopupConfig.closeOnDateSelection,
|
1425
|
+
appendToBody = angular.isDefined(attrs.datepickerAppendToBody) ? scope.$parent.$eval(attrs.datepickerAppendToBody) : datepickerPopupConfig.appendToBody;
|
1111
1426
|
|
1112
|
-
attrs.$
|
1113
|
-
dateFormat = value || datepickerPopupConfig.dateFormat;
|
1114
|
-
ngModel.$render();
|
1115
|
-
});
|
1427
|
+
scope.showButtonBar = angular.isDefined(attrs.showButtonBar) ? scope.$parent.$eval(attrs.showButtonBar) : datepickerPopupConfig.showButtonBar;
|
1116
1428
|
|
1117
|
-
scope.
|
1429
|
+
scope.getText = function( key ) {
|
1430
|
+
return scope[key + 'Text'] || datepickerPopupConfig[key + 'Text'];
|
1431
|
+
};
|
1118
1432
|
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
1433
|
+
attrs.$observe('datepickerPopup', function(value) {
|
1434
|
+
dateFormat = value || datepickerPopupConfig.datepickerPopup;
|
1435
|
+
ngModel.$render();
|
1122
1436
|
});
|
1123
1437
|
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1129
|
-
});
|
1130
|
-
attrs.$observe('clearText', function(text) {
|
1131
|
-
scope.clearText = angular.isDefined(text) ? text : datepickerPopupConfig.clearText;
|
1132
|
-
});
|
1133
|
-
attrs.$observe('closeText', function(text) {
|
1134
|
-
scope.closeText = angular.isDefined(text) ? text : datepickerPopupConfig.closeText;
|
1438
|
+
// popup element used to display calendar
|
1439
|
+
var popupEl = angular.element('<div datepicker-popup-wrap><div datepicker></div></div>');
|
1440
|
+
popupEl.attr({
|
1441
|
+
'ng-model': 'date',
|
1442
|
+
'ng-change': 'dateSelection()'
|
1135
1443
|
});
|
1136
1444
|
|
1137
|
-
|
1138
|
-
|
1139
|
-
getIsOpen = $parse(attrs.isOpen);
|
1140
|
-
setIsOpen = getIsOpen.assign;
|
1141
|
-
|
1142
|
-
originalScope.$watch(getIsOpen, function updateOpen(value) {
|
1143
|
-
scope.isOpen = !! value;
|
1144
|
-
});
|
1445
|
+
function cameltoDash( string ){
|
1446
|
+
return string.replace(/([A-Z])/g, function($1) { return '-' + $1.toLowerCase(); });
|
1145
1447
|
}
|
1146
|
-
scope.isOpen = getIsOpen ? getIsOpen(originalScope) : false; // Initial state
|
1147
1448
|
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1153
|
-
}
|
1449
|
+
// datepicker element
|
1450
|
+
var datepickerEl = angular.element(popupEl.children()[0]);
|
1451
|
+
if ( attrs.datepickerOptions ) {
|
1452
|
+
angular.forEach(scope.$parent.$eval(attrs.datepickerOptions), function( value, option ) {
|
1453
|
+
datepickerEl.attr( cameltoDash(option), value );
|
1454
|
+
});
|
1154
1455
|
}
|
1155
1456
|
|
1156
|
-
|
1157
|
-
if (
|
1158
|
-
scope.$
|
1159
|
-
|
1457
|
+
angular.forEach(['minDate', 'maxDate'], function( key ) {
|
1458
|
+
if ( attrs[key] ) {
|
1459
|
+
scope.$parent.$watch($parse(attrs[key]), function(value){
|
1460
|
+
scope[key] = value;
|
1160
1461
|
});
|
1462
|
+
datepickerEl.attr(cameltoDash(key), key);
|
1161
1463
|
}
|
1162
|
-
};
|
1163
|
-
|
1164
|
-
var elementFocusBind = function() {
|
1165
|
-
scope.$apply(function() {
|
1166
|
-
setOpen( true );
|
1167
|
-
});
|
1168
|
-
};
|
1169
|
-
|
1170
|
-
// popup element used to display calendar
|
1171
|
-
var popupEl = angular.element('<div datepicker-popup-wrap><div datepicker></div></div>');
|
1172
|
-
popupEl.attr({
|
1173
|
-
'ng-model': 'date',
|
1174
|
-
'ng-change': 'dateSelection()'
|
1175
1464
|
});
|
1176
|
-
|
1177
|
-
|
1178
|
-
if (attrs.datepickerOptions) {
|
1179
|
-
datepickerOptions = originalScope.$eval(attrs.datepickerOptions);
|
1180
|
-
datepickerEl.attr(angular.extend({}, datepickerOptions));
|
1465
|
+
if (attrs.dateDisabled) {
|
1466
|
+
datepickerEl.attr('date-disabled', 'dateDisabled({ date: date, mode: mode })');
|
1181
1467
|
}
|
1182
1468
|
|
1183
|
-
// TODO: reverse from dateFilter string to Date object
|
1184
1469
|
function parseDate(viewValue) {
|
1185
1470
|
if (!viewValue) {
|
1186
1471
|
ngModel.$setValidity('date', true);
|
1187
1472
|
return null;
|
1188
|
-
} else if (angular.isDate(viewValue)) {
|
1473
|
+
} else if (angular.isDate(viewValue) && !isNaN(viewValue)) {
|
1189
1474
|
ngModel.$setValidity('date', true);
|
1190
1475
|
return viewValue;
|
1191
1476
|
} else if (angular.isString(viewValue)) {
|
1192
|
-
var date = new Date(viewValue);
|
1477
|
+
var date = dateParser.parse(viewValue, dateFormat) || new Date(viewValue);
|
1193
1478
|
if (isNaN(date)) {
|
1194
1479
|
ngModel.$setValidity('date', false);
|
1195
1480
|
return undefined;
|
@@ -1212,8 +1497,9 @@ function ($compile, $parse, $document, $position, dateFilter, datepickerPopupCon
|
|
1212
1497
|
ngModel.$setViewValue(scope.date);
|
1213
1498
|
ngModel.$render();
|
1214
1499
|
|
1215
|
-
if (closeOnDateSelection) {
|
1216
|
-
|
1500
|
+
if ( closeOnDateSelection ) {
|
1501
|
+
scope.isOpen = false;
|
1502
|
+
element[0].focus();
|
1217
1503
|
}
|
1218
1504
|
};
|
1219
1505
|
|
@@ -1227,62 +1513,60 @@ function ($compile, $parse, $document, $position, dateFilter, datepickerPopupCon
|
|
1227
1513
|
ngModel.$render = function() {
|
1228
1514
|
var date = ngModel.$viewValue ? dateFilter(ngModel.$viewValue, dateFormat) : '';
|
1229
1515
|
element.val(date);
|
1230
|
-
scope.date = ngModel.$modelValue;
|
1516
|
+
scope.date = parseDate( ngModel.$modelValue );
|
1231
1517
|
};
|
1232
1518
|
|
1233
|
-
|
1234
|
-
if (
|
1235
|
-
|
1236
|
-
scope
|
1519
|
+
var documentClickBind = function(event) {
|
1520
|
+
if (scope.isOpen && event.target !== element[0]) {
|
1521
|
+
scope.$apply(function() {
|
1522
|
+
scope.isOpen = false;
|
1237
1523
|
});
|
1238
|
-
datepickerEl.attr(datepickerAttribute || scopeProperty, scopeProperty);
|
1239
1524
|
}
|
1240
|
-
}
|
1241
|
-
addWatchableAttribute(attrs.min, 'min');
|
1242
|
-
addWatchableAttribute(attrs.max, 'max');
|
1243
|
-
if (attrs.showWeeks) {
|
1244
|
-
addWatchableAttribute(attrs.showWeeks, 'showWeeks', 'show-weeks');
|
1245
|
-
} else {
|
1246
|
-
scope.showWeeks = 'show-weeks' in datepickerOptions ? datepickerOptions['show-weeks'] : datepickerConfig.showWeeks;
|
1247
|
-
datepickerEl.attr('show-weeks', 'showWeeks');
|
1248
|
-
}
|
1249
|
-
if (attrs.dateDisabled) {
|
1250
|
-
datepickerEl.attr('date-disabled', attrs.dateDisabled);
|
1251
|
-
}
|
1525
|
+
};
|
1252
1526
|
|
1253
|
-
function
|
1254
|
-
scope.
|
1255
|
-
|
1256
|
-
|
1527
|
+
var keydown = function(evt, noApply) {
|
1528
|
+
scope.keydown(evt);
|
1529
|
+
};
|
1530
|
+
element.bind('keydown', keydown);
|
1531
|
+
|
1532
|
+
scope.keydown = function(evt) {
|
1533
|
+
if (evt.which === 27) {
|
1534
|
+
evt.preventDefault();
|
1535
|
+
evt.stopPropagation();
|
1536
|
+
scope.close();
|
1537
|
+
} else if (evt.which === 40 && !scope.isOpen) {
|
1538
|
+
scope.isOpen = true;
|
1539
|
+
}
|
1540
|
+
};
|
1257
1541
|
|
1258
|
-
var documentBindingInitialized = false, elementFocusInitialized = false;
|
1259
1542
|
scope.$watch('isOpen', function(value) {
|
1260
1543
|
if (value) {
|
1261
|
-
|
1544
|
+
scope.$broadcast('datepicker.focus');
|
1545
|
+
scope.position = appendToBody ? $position.offset(element) : $position.position(element);
|
1546
|
+
scope.position.top = scope.position.top + element.prop('offsetHeight');
|
1547
|
+
|
1262
1548
|
$document.bind('click', documentClickBind);
|
1263
|
-
if(elementFocusInitialized) {
|
1264
|
-
element.unbind('focus', elementFocusBind);
|
1265
|
-
}
|
1266
|
-
element[0].focus();
|
1267
|
-
documentBindingInitialized = true;
|
1268
1549
|
} else {
|
1269
|
-
|
1270
|
-
$document.unbind('click', documentClickBind);
|
1271
|
-
}
|
1272
|
-
element.bind('focus', elementFocusBind);
|
1273
|
-
elementFocusInitialized = true;
|
1274
|
-
}
|
1275
|
-
|
1276
|
-
if ( setIsOpen ) {
|
1277
|
-
setIsOpen(originalScope, value);
|
1550
|
+
$document.unbind('click', documentClickBind);
|
1278
1551
|
}
|
1279
1552
|
});
|
1280
1553
|
|
1281
|
-
scope.
|
1282
|
-
|
1554
|
+
scope.select = function( date ) {
|
1555
|
+
if (date === 'today') {
|
1556
|
+
var today = new Date();
|
1557
|
+
if (angular.isDate(ngModel.$modelValue)) {
|
1558
|
+
date = new Date(ngModel.$modelValue);
|
1559
|
+
date.setFullYear(today.getFullYear(), today.getMonth(), today.getDate());
|
1560
|
+
} else {
|
1561
|
+
date = new Date(today.setHours(0, 0, 0, 0));
|
1562
|
+
}
|
1563
|
+
}
|
1564
|
+
scope.dateSelection( date );
|
1283
1565
|
};
|
1284
|
-
|
1285
|
-
|
1566
|
+
|
1567
|
+
scope.close = function() {
|
1568
|
+
scope.isOpen = false;
|
1569
|
+
element[0].focus();
|
1286
1570
|
};
|
1287
1571
|
|
1288
1572
|
var $popup = $compile(popupEl)(scope);
|
@@ -1291,6 +1575,12 @@ function ($compile, $parse, $document, $position, dateFilter, datepickerPopupCon
|
|
1291
1575
|
} else {
|
1292
1576
|
element.after($popup);
|
1293
1577
|
}
|
1578
|
+
|
1579
|
+
scope.$on('$destroy', function() {
|
1580
|
+
$popup.remove();
|
1581
|
+
element.unbind('keydown', keydown);
|
1582
|
+
$document.unbind('click', documentClickBind);
|
1583
|
+
});
|
1294
1584
|
}
|
1295
1585
|
};
|
1296
1586
|
}])
|
@@ -1310,58 +1600,160 @@ function ($compile, $parse, $document, $position, dateFilter, datepickerPopupCon
|
|
1310
1600
|
};
|
1311
1601
|
});
|
1312
1602
|
|
1313
|
-
|
1314
|
-
|
1315
|
-
|
1316
|
-
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1603
|
+
angular.module('ui.bootstrap.dropdown', [])
|
1604
|
+
|
1605
|
+
.constant('dropdownConfig', {
|
1606
|
+
openClass: 'open'
|
1607
|
+
})
|
1608
|
+
|
1609
|
+
.service('dropdownService', ['$document', function($document) {
|
1610
|
+
var openScope = null;
|
1611
|
+
|
1612
|
+
this.open = function( dropdownScope ) {
|
1613
|
+
if ( !openScope ) {
|
1614
|
+
$document.bind('click', closeDropdown);
|
1615
|
+
$document.bind('keydown', escapeKeyBind);
|
1616
|
+
}
|
1617
|
+
|
1618
|
+
if ( openScope && openScope !== dropdownScope ) {
|
1619
|
+
openScope.isOpen = false;
|
1620
|
+
}
|
1621
|
+
|
1622
|
+
openScope = dropdownScope;
|
1623
|
+
};
|
1624
|
+
|
1625
|
+
this.close = function( dropdownScope ) {
|
1626
|
+
if ( openScope === dropdownScope ) {
|
1627
|
+
openScope = null;
|
1628
|
+
$document.unbind('click', closeDropdown);
|
1629
|
+
$document.unbind('keydown', escapeKeyBind);
|
1630
|
+
}
|
1631
|
+
};
|
1632
|
+
|
1633
|
+
var closeDropdown = function( evt ) {
|
1634
|
+
if (evt && evt.isDefaultPrevented()) {
|
1635
|
+
return;
|
1636
|
+
}
|
1637
|
+
|
1638
|
+
openScope.$apply(function() {
|
1639
|
+
openScope.isOpen = false;
|
1640
|
+
});
|
1641
|
+
};
|
1642
|
+
|
1643
|
+
var escapeKeyBind = function( evt ) {
|
1644
|
+
if ( evt.which === 27 ) {
|
1645
|
+
openScope.focusToggleElement();
|
1646
|
+
closeDropdown();
|
1647
|
+
}
|
1648
|
+
};
|
1649
|
+
}])
|
1650
|
+
|
1651
|
+
.controller('DropdownController', ['$scope', '$attrs', '$parse', 'dropdownConfig', 'dropdownService', '$animate', function($scope, $attrs, $parse, dropdownConfig, dropdownService, $animate) {
|
1652
|
+
var self = this,
|
1653
|
+
scope = $scope.$new(), // create a child scope so we are not polluting original one
|
1654
|
+
openClass = dropdownConfig.openClass,
|
1655
|
+
getIsOpen,
|
1656
|
+
setIsOpen = angular.noop,
|
1657
|
+
toggleInvoker = $attrs.onToggle ? $parse($attrs.onToggle) : angular.noop;
|
1658
|
+
|
1659
|
+
this.init = function( element ) {
|
1660
|
+
self.$element = element;
|
1661
|
+
|
1662
|
+
if ( $attrs.isOpen ) {
|
1663
|
+
getIsOpen = $parse($attrs.isOpen);
|
1664
|
+
setIsOpen = getIsOpen.assign;
|
1665
|
+
|
1666
|
+
$scope.$watch(getIsOpen, function(value) {
|
1667
|
+
scope.isOpen = !!value;
|
1668
|
+
});
|
1669
|
+
}
|
1670
|
+
};
|
1671
|
+
|
1672
|
+
this.toggle = function( open ) {
|
1673
|
+
return scope.isOpen = arguments.length ? !!open : !scope.isOpen;
|
1674
|
+
};
|
1675
|
+
|
1676
|
+
// Allow other directives to watch status
|
1677
|
+
this.isOpen = function() {
|
1678
|
+
return scope.isOpen;
|
1679
|
+
};
|
1680
|
+
|
1681
|
+
scope.focusToggleElement = function() {
|
1682
|
+
if ( self.toggleElement ) {
|
1683
|
+
self.toggleElement[0].focus();
|
1684
|
+
}
|
1685
|
+
};
|
1686
|
+
|
1687
|
+
scope.$watch('isOpen', function( isOpen, wasOpen ) {
|
1688
|
+
$animate[isOpen ? 'addClass' : 'removeClass'](self.$element, openClass);
|
1689
|
+
|
1690
|
+
if ( isOpen ) {
|
1691
|
+
scope.focusToggleElement();
|
1692
|
+
dropdownService.open( scope );
|
1693
|
+
} else {
|
1694
|
+
dropdownService.close( scope );
|
1695
|
+
}
|
1696
|
+
|
1697
|
+
setIsOpen($scope, isOpen);
|
1698
|
+
if (angular.isDefined(isOpen) && isOpen !== wasOpen) {
|
1699
|
+
toggleInvoker($scope, { open: !!isOpen });
|
1700
|
+
}
|
1701
|
+
});
|
1702
|
+
|
1703
|
+
$scope.$on('$locationChangeSuccess', function() {
|
1704
|
+
scope.isOpen = false;
|
1705
|
+
});
|
1706
|
+
|
1707
|
+
$scope.$on('$destroy', function() {
|
1708
|
+
scope.$destroy();
|
1709
|
+
});
|
1710
|
+
}])
|
1711
|
+
|
1712
|
+
.directive('dropdown', function() {
|
1713
|
+
return {
|
1714
|
+
restrict: 'CA',
|
1715
|
+
controller: 'DropdownController',
|
1716
|
+
link: function(scope, element, attrs, dropdownCtrl) {
|
1717
|
+
dropdownCtrl.init( element );
|
1718
|
+
}
|
1719
|
+
};
|
1720
|
+
})
|
1326
1721
|
|
1327
|
-
|
1328
|
-
var openElement = null,
|
1329
|
-
closeMenu = angular.noop;
|
1722
|
+
.directive('dropdownToggle', function() {
|
1330
1723
|
return {
|
1331
1724
|
restrict: 'CA',
|
1332
|
-
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
1725
|
+
require: '?^dropdown',
|
1726
|
+
link: function(scope, element, attrs, dropdownCtrl) {
|
1727
|
+
if ( !dropdownCtrl ) {
|
1728
|
+
return;
|
1729
|
+
}
|
1336
1730
|
|
1337
|
-
|
1731
|
+
dropdownCtrl.toggleElement = element;
|
1338
1732
|
|
1733
|
+
var toggleDropdown = function(event) {
|
1339
1734
|
event.preventDefault();
|
1340
|
-
event.stopPropagation();
|
1341
1735
|
|
1342
|
-
if (
|
1343
|
-
|
1736
|
+
if ( !element.hasClass('disabled') && !attrs.disabled ) {
|
1737
|
+
scope.$apply(function() {
|
1738
|
+
dropdownCtrl.toggle();
|
1739
|
+
});
|
1344
1740
|
}
|
1741
|
+
};
|
1345
1742
|
|
1346
|
-
|
1347
|
-
|
1348
|
-
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
closeMenu = angular.noop;
|
1357
|
-
openElement = null;
|
1358
|
-
};
|
1359
|
-
$document.bind('click', closeMenu);
|
1360
|
-
}
|
1743
|
+
element.bind('click', toggleDropdown);
|
1744
|
+
|
1745
|
+
// WAI-ARIA
|
1746
|
+
element.attr({ 'aria-haspopup': true, 'aria-expanded': false });
|
1747
|
+
scope.$watch(dropdownCtrl.isOpen, function( isOpen ) {
|
1748
|
+
element.attr('aria-expanded', !!isOpen);
|
1749
|
+
});
|
1750
|
+
|
1751
|
+
scope.$on('$destroy', function() {
|
1752
|
+
element.unbind('click', toggleDropdown);
|
1361
1753
|
});
|
1362
1754
|
}
|
1363
1755
|
};
|
1364
|
-
}
|
1756
|
+
});
|
1365
1757
|
|
1366
1758
|
angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition'])
|
1367
1759
|
|
@@ -1448,9 +1840,12 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition'])
|
|
1448
1840
|
},
|
1449
1841
|
replace: true,
|
1450
1842
|
transclude: true,
|
1451
|
-
templateUrl:
|
1843
|
+
templateUrl: function(tElement, tAttrs) {
|
1844
|
+
return tAttrs.templateUrl || 'template/modal/window.html';
|
1845
|
+
},
|
1452
1846
|
link: function (scope, element, attrs) {
|
1453
|
-
|
1847
|
+
element.addClass(attrs.windowClass || '');
|
1848
|
+
scope.size = attrs.size;
|
1454
1849
|
|
1455
1850
|
$timeout(function () {
|
1456
1851
|
// trigger CSS transitions
|
@@ -1506,8 +1901,11 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition'])
|
|
1506
1901
|
openedWindows.remove(modalInstance);
|
1507
1902
|
|
1508
1903
|
//remove window DOM element
|
1509
|
-
removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, 300,
|
1510
|
-
|
1904
|
+
removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, 300, function() {
|
1905
|
+
modalWindow.modalScope.$destroy();
|
1906
|
+
body.toggleClass(OPENED_MODAL_CLASS, openedWindows.length() > 0);
|
1907
|
+
checkRemoveBackdrop();
|
1908
|
+
});
|
1511
1909
|
}
|
1512
1910
|
|
1513
1911
|
function checkRemoveBackdrop() {
|
@@ -1561,8 +1959,9 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition'])
|
|
1561
1959
|
if (evt.which === 27) {
|
1562
1960
|
modal = openedWindows.top();
|
1563
1961
|
if (modal && modal.value.keyboard) {
|
1962
|
+
evt.preventDefault();
|
1564
1963
|
$rootScope.$apply(function () {
|
1565
|
-
$modalStack.dismiss(modal.key);
|
1964
|
+
$modalStack.dismiss(modal.key, 'escape key press');
|
1566
1965
|
});
|
1567
1966
|
}
|
1568
1967
|
}
|
@@ -1586,12 +1985,15 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition'])
|
|
1586
1985
|
backdropDomEl = $compile('<div modal-backdrop></div>')(backdropScope);
|
1587
1986
|
body.append(backdropDomEl);
|
1588
1987
|
}
|
1589
|
-
|
1988
|
+
|
1590
1989
|
var angularDomEl = angular.element('<div modal-window></div>');
|
1591
|
-
angularDomEl.attr(
|
1592
|
-
|
1593
|
-
|
1594
|
-
|
1990
|
+
angularDomEl.attr({
|
1991
|
+
'template-url': modal.windowTemplateUrl,
|
1992
|
+
'window-class': modal.windowClass,
|
1993
|
+
'size': modal.size,
|
1994
|
+
'index': openedWindows.length() - 1,
|
1995
|
+
'animate': 'animate'
|
1996
|
+
}).html(modal.content);
|
1595
1997
|
|
1596
1998
|
var modalDomEl = $compile(angularDomEl)(modal.scope);
|
1597
1999
|
openedWindows.top().value.modalDomEl = modalDomEl;
|
@@ -1715,7 +2117,9 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition'])
|
|
1715
2117
|
content: tplAndVars[0],
|
1716
2118
|
backdrop: modalOptions.backdrop,
|
1717
2119
|
keyboard: modalOptions.keyboard,
|
1718
|
-
windowClass: modalOptions.windowClass
|
2120
|
+
windowClass: modalOptions.windowClass,
|
2121
|
+
windowTemplateUrl: modalOptions.windowTemplateUrl,
|
2122
|
+
size: modalOptions.size
|
1719
2123
|
});
|
1720
2124
|
|
1721
2125
|
}, function resolveError(reason) {
|
@@ -1740,58 +2144,54 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition'])
|
|
1740
2144
|
|
1741
2145
|
angular.module('ui.bootstrap.pagination', [])
|
1742
2146
|
|
1743
|
-
.controller('PaginationController', ['$scope', '$attrs', '$parse',
|
2147
|
+
.controller('PaginationController', ['$scope', '$attrs', '$parse', function ($scope, $attrs, $parse) {
|
1744
2148
|
var self = this,
|
2149
|
+
ngModelCtrl = { $setViewValue: angular.noop }, // nullModelCtrl
|
1745
2150
|
setNumPages = $attrs.numPages ? $parse($attrs.numPages).assign : angular.noop;
|
1746
2151
|
|
1747
|
-
this.init = function(
|
2152
|
+
this.init = function(ngModelCtrl_, config) {
|
2153
|
+
ngModelCtrl = ngModelCtrl_;
|
2154
|
+
this.config = config;
|
2155
|
+
|
2156
|
+
ngModelCtrl.$render = function() {
|
2157
|
+
self.render();
|
2158
|
+
};
|
2159
|
+
|
1748
2160
|
if ($attrs.itemsPerPage) {
|
1749
2161
|
$scope.$parent.$watch($parse($attrs.itemsPerPage), function(value) {
|
1750
2162
|
self.itemsPerPage = parseInt(value, 10);
|
1751
2163
|
$scope.totalPages = self.calculateTotalPages();
|
1752
2164
|
});
|
1753
2165
|
} else {
|
1754
|
-
this.itemsPerPage =
|
2166
|
+
this.itemsPerPage = config.itemsPerPage;
|
1755
2167
|
}
|
1756
2168
|
};
|
1757
2169
|
|
1758
|
-
this.noPrevious = function() {
|
1759
|
-
return this.page === 1;
|
1760
|
-
};
|
1761
|
-
this.noNext = function() {
|
1762
|
-
return this.page === $scope.totalPages;
|
1763
|
-
};
|
1764
|
-
|
1765
|
-
this.isActive = function(page) {
|
1766
|
-
return this.page === page;
|
1767
|
-
};
|
1768
|
-
|
1769
2170
|
this.calculateTotalPages = function() {
|
1770
2171
|
var totalPages = this.itemsPerPage < 1 ? 1 : Math.ceil($scope.totalItems / this.itemsPerPage);
|
1771
2172
|
return Math.max(totalPages || 0, 1);
|
1772
2173
|
};
|
1773
2174
|
|
1774
|
-
this.getAttributeValue = function(attribute, defaultValue, interpolate) {
|
1775
|
-
return angular.isDefined(attribute) ? (interpolate ? $interpolate(attribute)($scope.$parent) : $scope.$parent.$eval(attribute)) : defaultValue;
|
1776
|
-
};
|
1777
|
-
|
1778
2175
|
this.render = function() {
|
1779
|
-
|
1780
|
-
if (this.page > 0 && this.page <= $scope.totalPages) {
|
1781
|
-
$scope.pages = this.getPages(this.page, $scope.totalPages);
|
1782
|
-
}
|
2176
|
+
$scope.page = parseInt(ngModelCtrl.$viewValue, 10) || 1;
|
1783
2177
|
};
|
1784
2178
|
|
1785
2179
|
$scope.selectPage = function(page) {
|
1786
|
-
if (
|
1787
|
-
|
1788
|
-
|
2180
|
+
if ( $scope.page !== page && page > 0 && page <= $scope.totalPages) {
|
2181
|
+
ngModelCtrl.$setViewValue(page);
|
2182
|
+
ngModelCtrl.$render();
|
1789
2183
|
}
|
1790
2184
|
};
|
1791
2185
|
|
1792
|
-
$scope
|
1793
|
-
self.
|
1794
|
-
}
|
2186
|
+
$scope.getText = function( key ) {
|
2187
|
+
return $scope[key + 'Text'] || self.config[key + 'Text'];
|
2188
|
+
};
|
2189
|
+
$scope.noPrevious = function() {
|
2190
|
+
return $scope.page === 1;
|
2191
|
+
};
|
2192
|
+
$scope.noNext = function() {
|
2193
|
+
return $scope.page === $scope.totalPages;
|
2194
|
+
};
|
1795
2195
|
|
1796
2196
|
$scope.$watch('totalItems', function() {
|
1797
2197
|
$scope.totalPages = self.calculateTotalPages();
|
@@ -1800,10 +2200,10 @@ angular.module('ui.bootstrap.pagination', [])
|
|
1800
2200
|
$scope.$watch('totalPages', function(value) {
|
1801
2201
|
setNumPages($scope.$parent, value); // Readonly variable
|
1802
2202
|
|
1803
|
-
if (
|
2203
|
+
if ( $scope.page > value ) {
|
1804
2204
|
$scope.selectPage(value);
|
1805
2205
|
} else {
|
1806
|
-
|
2206
|
+
ngModelCtrl.$render();
|
1807
2207
|
}
|
1808
2208
|
});
|
1809
2209
|
}])
|
@@ -1819,30 +2219,34 @@ angular.module('ui.bootstrap.pagination', [])
|
|
1819
2219
|
rotate: true
|
1820
2220
|
})
|
1821
2221
|
|
1822
|
-
.directive('pagination', ['$parse', 'paginationConfig', function($parse,
|
2222
|
+
.directive('pagination', ['$parse', 'paginationConfig', function($parse, paginationConfig) {
|
1823
2223
|
return {
|
1824
2224
|
restrict: 'EA',
|
1825
2225
|
scope: {
|
1826
|
-
page: '=',
|
1827
2226
|
totalItems: '=',
|
1828
|
-
|
2227
|
+
firstText: '@',
|
2228
|
+
previousText: '@',
|
2229
|
+
nextText: '@',
|
2230
|
+
lastText: '@'
|
1829
2231
|
},
|
2232
|
+
require: ['pagination', '?ngModel'],
|
1830
2233
|
controller: 'PaginationController',
|
1831
2234
|
templateUrl: 'template/pagination/pagination.html',
|
1832
2235
|
replace: true,
|
1833
|
-
link: function(scope, element, attrs,
|
2236
|
+
link: function(scope, element, attrs, ctrls) {
|
2237
|
+
var paginationCtrl = ctrls[0], ngModelCtrl = ctrls[1];
|
2238
|
+
|
2239
|
+
if (!ngModelCtrl) {
|
2240
|
+
return; // do nothing if no ng-model
|
2241
|
+
}
|
1834
2242
|
|
1835
2243
|
// Setup configuration parameters
|
1836
|
-
var maxSize,
|
1837
|
-
|
1838
|
-
|
1839
|
-
|
1840
|
-
previousText = paginationCtrl.getAttributeValue(attrs.previousText, config.previousText, true),
|
1841
|
-
nextText = paginationCtrl.getAttributeValue(attrs.nextText, config.nextText, true),
|
1842
|
-
lastText = paginationCtrl.getAttributeValue(attrs.lastText, config.lastText, true),
|
1843
|
-
rotate = paginationCtrl.getAttributeValue(attrs.rotate, config.rotate);
|
2244
|
+
var maxSize = angular.isDefined(attrs.maxSize) ? scope.$parent.$eval(attrs.maxSize) : paginationConfig.maxSize,
|
2245
|
+
rotate = angular.isDefined(attrs.rotate) ? scope.$parent.$eval(attrs.rotate) : paginationConfig.rotate;
|
2246
|
+
scope.boundaryLinks = angular.isDefined(attrs.boundaryLinks) ? scope.$parent.$eval(attrs.boundaryLinks) : paginationConfig.boundaryLinks;
|
2247
|
+
scope.directionLinks = angular.isDefined(attrs.directionLinks) ? scope.$parent.$eval(attrs.directionLinks) : paginationConfig.directionLinks;
|
1844
2248
|
|
1845
|
-
paginationCtrl.init(
|
2249
|
+
paginationCtrl.init(ngModelCtrl, paginationConfig);
|
1846
2250
|
|
1847
2251
|
if (attrs.maxSize) {
|
1848
2252
|
scope.$parent.$watch($parse(attrs.maxSize), function(value) {
|
@@ -1852,16 +2256,15 @@ angular.module('ui.bootstrap.pagination', [])
|
|
1852
2256
|
}
|
1853
2257
|
|
1854
2258
|
// Create page object used in template
|
1855
|
-
function makePage(number, text, isActive
|
2259
|
+
function makePage(number, text, isActive) {
|
1856
2260
|
return {
|
1857
2261
|
number: number,
|
1858
2262
|
text: text,
|
1859
|
-
active: isActive
|
1860
|
-
disabled: isDisabled
|
2263
|
+
active: isActive
|
1861
2264
|
};
|
1862
2265
|
}
|
1863
2266
|
|
1864
|
-
|
2267
|
+
function getPages(currentPage, totalPages) {
|
1865
2268
|
var pages = [];
|
1866
2269
|
|
1867
2270
|
// Default page limits
|
@@ -1891,42 +2294,32 @@ angular.module('ui.bootstrap.pagination', [])
|
|
1891
2294
|
|
1892
2295
|
// Add page number links
|
1893
2296
|
for (var number = startPage; number <= endPage; number++) {
|
1894
|
-
var page = makePage(number, number,
|
2297
|
+
var page = makePage(number, number, number === currentPage);
|
1895
2298
|
pages.push(page);
|
1896
2299
|
}
|
1897
2300
|
|
1898
2301
|
// Add links to move between page sets
|
1899
2302
|
if ( isMaxSized && ! rotate ) {
|
1900
2303
|
if ( startPage > 1 ) {
|
1901
|
-
var previousPageSet = makePage(startPage - 1, '...', false
|
2304
|
+
var previousPageSet = makePage(startPage - 1, '...', false);
|
1902
2305
|
pages.unshift(previousPageSet);
|
1903
2306
|
}
|
1904
2307
|
|
1905
2308
|
if ( endPage < totalPages ) {
|
1906
|
-
var nextPageSet = makePage(endPage + 1, '...', false
|
2309
|
+
var nextPageSet = makePage(endPage + 1, '...', false);
|
1907
2310
|
pages.push(nextPageSet);
|
1908
2311
|
}
|
1909
2312
|
}
|
1910
2313
|
|
1911
|
-
|
1912
|
-
|
1913
|
-
var previousPage = makePage(currentPage - 1, previousText, false, paginationCtrl.noPrevious());
|
1914
|
-
pages.unshift(previousPage);
|
1915
|
-
|
1916
|
-
var nextPage = makePage(currentPage + 1, nextText, false, paginationCtrl.noNext());
|
1917
|
-
pages.push(nextPage);
|
1918
|
-
}
|
1919
|
-
|
1920
|
-
// Add first & last links
|
1921
|
-
if (boundaryLinks) {
|
1922
|
-
var firstPage = makePage(1, firstText, false, paginationCtrl.noPrevious());
|
1923
|
-
pages.unshift(firstPage);
|
2314
|
+
return pages;
|
2315
|
+
}
|
1924
2316
|
|
1925
|
-
|
1926
|
-
|
2317
|
+
var originalRender = paginationCtrl.render;
|
2318
|
+
paginationCtrl.render = function() {
|
2319
|
+
originalRender();
|
2320
|
+
if (scope.page > 0 && scope.page <= scope.totalPages) {
|
2321
|
+
scope.pages = getPages(scope.page, scope.totalPages);
|
1927
2322
|
}
|
1928
|
-
|
1929
|
-
return pages;
|
1930
2323
|
};
|
1931
2324
|
}
|
1932
2325
|
};
|
@@ -1939,43 +2332,27 @@ angular.module('ui.bootstrap.pagination', [])
|
|
1939
2332
|
align: true
|
1940
2333
|
})
|
1941
2334
|
|
1942
|
-
.directive('pager', ['pagerConfig', function(
|
2335
|
+
.directive('pager', ['pagerConfig', function(pagerConfig) {
|
1943
2336
|
return {
|
1944
2337
|
restrict: 'EA',
|
1945
2338
|
scope: {
|
1946
|
-
page: '=',
|
1947
2339
|
totalItems: '=',
|
1948
|
-
|
2340
|
+
previousText: '@',
|
2341
|
+
nextText: '@'
|
1949
2342
|
},
|
2343
|
+
require: ['pager', '?ngModel'],
|
1950
2344
|
controller: 'PaginationController',
|
1951
2345
|
templateUrl: 'template/pagination/pager.html',
|
1952
2346
|
replace: true,
|
1953
|
-
link: function(scope, element, attrs,
|
1954
|
-
|
1955
|
-
// Setup configuration parameters
|
1956
|
-
var previousText = paginationCtrl.getAttributeValue(attrs.previousText, config.previousText, true),
|
1957
|
-
nextText = paginationCtrl.getAttributeValue(attrs.nextText, config.nextText, true),
|
1958
|
-
align = paginationCtrl.getAttributeValue(attrs.align, config.align);
|
1959
|
-
|
1960
|
-
paginationCtrl.init(config.itemsPerPage);
|
2347
|
+
link: function(scope, element, attrs, ctrls) {
|
2348
|
+
var paginationCtrl = ctrls[0], ngModelCtrl = ctrls[1];
|
1961
2349
|
|
1962
|
-
|
1963
|
-
|
1964
|
-
return {
|
1965
|
-
number: number,
|
1966
|
-
text: text,
|
1967
|
-
disabled: isDisabled,
|
1968
|
-
previous: ( align && isPrevious ),
|
1969
|
-
next: ( align && isNext )
|
1970
|
-
};
|
2350
|
+
if (!ngModelCtrl) {
|
2351
|
+
return; // do nothing if no ng-model
|
1971
2352
|
}
|
1972
2353
|
|
1973
|
-
|
1974
|
-
|
1975
|
-
makePage(currentPage - 1, previousText, paginationCtrl.noPrevious(), true, false),
|
1976
|
-
makePage(currentPage + 1, nextText, paginationCtrl.noNext(), false, true)
|
1977
|
-
];
|
1978
|
-
};
|
2354
|
+
scope.align = angular.isDefined(attrs.align) ? scope.$parent.$eval(attrs.align) : pagerConfig.align;
|
2355
|
+
paginationCtrl.init(ngModelCtrl, pagerConfig);
|
1979
2356
|
}
|
1980
2357
|
};
|
1981
2358
|
}]);
|
@@ -2008,7 +2385,7 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
2008
2385
|
|
2009
2386
|
// The options specified to the provider globally.
|
2010
2387
|
var globalOptions = {};
|
2011
|
-
|
2388
|
+
|
2012
2389
|
/**
|
2013
2390
|
* `options({})` allows global configuration of all tooltips in the
|
2014
2391
|
* application.
|
@@ -2077,7 +2454,7 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
2077
2454
|
|
2078
2455
|
var startSym = $interpolate.startSymbol();
|
2079
2456
|
var endSym = $interpolate.endSymbol();
|
2080
|
-
var template =
|
2457
|
+
var template =
|
2081
2458
|
'<div '+ directiveName +'-popup '+
|
2082
2459
|
'title="'+startSym+'tt_title'+endSym+'" '+
|
2083
2460
|
'content="'+startSym+'tt_content'+endSym+'" '+
|
@@ -2099,56 +2476,16 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
2099
2476
|
var popupTimeout;
|
2100
2477
|
var appendToBody = angular.isDefined( options.appendToBody ) ? options.appendToBody : false;
|
2101
2478
|
var triggers = getTriggers( undefined );
|
2102
|
-
var hasRegisteredTriggers = false;
|
2103
2479
|
var hasEnableExp = angular.isDefined(attrs[prefix+'Enable']);
|
2104
2480
|
|
2105
|
-
var positionTooltip = function (){
|
2106
|
-
var position,
|
2107
|
-
ttWidth,
|
2108
|
-
ttHeight,
|
2109
|
-
ttPosition;
|
2110
|
-
// Get the position of the directive element.
|
2111
|
-
position = appendToBody ? $position.offset( element ) : $position.position( element );
|
2112
|
-
|
2113
|
-
// Get the height and width of the tooltip so we can center it.
|
2114
|
-
ttWidth = tooltip.prop( 'offsetWidth' );
|
2115
|
-
ttHeight = tooltip.prop( 'offsetHeight' );
|
2116
|
-
|
2117
|
-
// Calculate the tooltip's top and left coordinates to center it with
|
2118
|
-
// this directive.
|
2119
|
-
switch ( scope.tt_placement ) {
|
2120
|
-
case 'right':
|
2121
|
-
ttPosition = {
|
2122
|
-
top: position.top + position.height / 2 - ttHeight / 2,
|
2123
|
-
left: position.left + position.width
|
2124
|
-
};
|
2125
|
-
break;
|
2126
|
-
case 'bottom':
|
2127
|
-
ttPosition = {
|
2128
|
-
top: position.top + position.height,
|
2129
|
-
left: position.left + position.width / 2 - ttWidth / 2
|
2130
|
-
};
|
2131
|
-
break;
|
2132
|
-
case 'left':
|
2133
|
-
ttPosition = {
|
2134
|
-
top: position.top + position.height / 2 - ttHeight / 2,
|
2135
|
-
left: position.left - ttWidth
|
2136
|
-
};
|
2137
|
-
break;
|
2138
|
-
default:
|
2139
|
-
ttPosition = {
|
2140
|
-
top: position.top - ttHeight,
|
2141
|
-
left: position.left + position.width / 2 - ttWidth / 2
|
2142
|
-
};
|
2143
|
-
break;
|
2144
|
-
}
|
2481
|
+
var positionTooltip = function () {
|
2145
2482
|
|
2483
|
+
var ttPosition = $position.positionElements(element, tooltip, scope.tt_placement, appendToBody);
|
2146
2484
|
ttPosition.top += 'px';
|
2147
2485
|
ttPosition.left += 'px';
|
2148
2486
|
|
2149
2487
|
// Now set the calculated positioning.
|
2150
2488
|
tooltip.css( ttPosition );
|
2151
|
-
|
2152
2489
|
};
|
2153
2490
|
|
2154
2491
|
// By default, the tooltip is not open.
|
@@ -2169,8 +2506,12 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
2169
2506
|
return;
|
2170
2507
|
}
|
2171
2508
|
if ( scope.tt_popupDelay ) {
|
2172
|
-
|
2173
|
-
|
2509
|
+
// Do nothing if the tooltip was already scheduled to pop-up.
|
2510
|
+
// This happens if show is triggered multiple times before any hide is triggered.
|
2511
|
+
if (!popupTimeout) {
|
2512
|
+
popupTimeout = $timeout( show, scope.tt_popupDelay, false );
|
2513
|
+
popupTimeout.then(function(reposition){reposition();});
|
2514
|
+
}
|
2174
2515
|
} else {
|
2175
2516
|
show()();
|
2176
2517
|
}
|
@@ -2185,6 +2526,14 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
2185
2526
|
// Show the tooltip popup element.
|
2186
2527
|
function show() {
|
2187
2528
|
|
2529
|
+
popupTimeout = null;
|
2530
|
+
|
2531
|
+
// If there is a pending remove transition, we must cancel it, lest the
|
2532
|
+
// tooltip be mysteriously removed.
|
2533
|
+
if ( transitionTimeout ) {
|
2534
|
+
$timeout.cancel( transitionTimeout );
|
2535
|
+
transitionTimeout = null;
|
2536
|
+
}
|
2188
2537
|
|
2189
2538
|
// Don't show empty tooltips.
|
2190
2539
|
if ( ! scope.tt_content ) {
|
@@ -2193,12 +2542,6 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
2193
2542
|
|
2194
2543
|
createTooltip();
|
2195
2544
|
|
2196
|
-
// If there is a pending remove transition, we must cancel it, lest the
|
2197
|
-
// tooltip be mysteriously removed.
|
2198
|
-
if ( transitionTimeout ) {
|
2199
|
-
$timeout.cancel( transitionTimeout );
|
2200
|
-
}
|
2201
|
-
|
2202
2545
|
// Set the initial positioning.
|
2203
2546
|
tooltip.css({ top: 0, left: 0, display: 'block' });
|
2204
2547
|
|
@@ -2228,12 +2571,15 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
2228
2571
|
|
2229
2572
|
//if tooltip is going to be shown after delay, we must cancel this
|
2230
2573
|
$timeout.cancel( popupTimeout );
|
2574
|
+
popupTimeout = null;
|
2231
2575
|
|
2232
2576
|
// And now we remove it from the DOM. However, if we have animation, we
|
2233
2577
|
// need to wait for it to expire beforehand.
|
2234
2578
|
// FIXME: this is a placeholder for a port of the transitions library.
|
2235
2579
|
if ( scope.tt_animation ) {
|
2236
|
-
|
2580
|
+
if (!transitionTimeout) {
|
2581
|
+
transitionTimeout = $timeout(removeTooltip, 500);
|
2582
|
+
}
|
2237
2583
|
} else {
|
2238
2584
|
removeTooltip();
|
2239
2585
|
}
|
@@ -2251,6 +2597,7 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
2251
2597
|
}
|
2252
2598
|
|
2253
2599
|
function removeTooltip() {
|
2600
|
+
transitionTimeout = null;
|
2254
2601
|
if (tooltip) {
|
2255
2602
|
tooltip.remove();
|
2256
2603
|
tooltip = null;
|
@@ -2281,11 +2628,9 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
2281
2628
|
scope.tt_popupDelay = ! isNaN(delay) ? delay : options.popupDelay;
|
2282
2629
|
});
|
2283
2630
|
|
2284
|
-
var unregisterTriggers = function() {
|
2285
|
-
|
2286
|
-
|
2287
|
-
element.unbind( triggers.hide, hideTooltipBind );
|
2288
|
-
}
|
2631
|
+
var unregisterTriggers = function () {
|
2632
|
+
element.unbind(triggers.show, showTooltipBind);
|
2633
|
+
element.unbind(triggers.hide, hideTooltipBind);
|
2289
2634
|
};
|
2290
2635
|
|
2291
2636
|
attrs.$observe( prefix+'Trigger', function ( val ) {
|
@@ -2299,8 +2644,6 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
|
|
2299
2644
|
element.bind( triggers.show, showTooltipBind );
|
2300
2645
|
element.bind( triggers.hide, hideTooltipBind );
|
2301
2646
|
}
|
2302
|
-
|
2303
|
-
hasRegisteredTriggers = true;
|
2304
2647
|
});
|
2305
2648
|
|
2306
2649
|
var animation = scope.$eval(attrs[prefix + 'Animation']);
|
@@ -2381,57 +2724,39 @@ angular.module( 'ui.bootstrap.popover', [ 'ui.bootstrap.tooltip' ] )
|
|
2381
2724
|
return $tooltip( 'popover', 'popover', 'click' );
|
2382
2725
|
}]);
|
2383
2726
|
|
2384
|
-
angular.module('ui.bootstrap.progressbar', [
|
2727
|
+
angular.module('ui.bootstrap.progressbar', [])
|
2385
2728
|
|
2386
2729
|
.constant('progressConfig', {
|
2387
2730
|
animate: true,
|
2388
2731
|
max: 100
|
2389
2732
|
})
|
2390
2733
|
|
2391
|
-
.controller('ProgressController', ['$scope', '$attrs', 'progressConfig',
|
2734
|
+
.controller('ProgressController', ['$scope', '$attrs', 'progressConfig', function($scope, $attrs, progressConfig) {
|
2392
2735
|
var self = this,
|
2393
|
-
bars = [],
|
2394
|
-
max = angular.isDefined($attrs.max) ? $scope.$parent.$eval($attrs.max) : progressConfig.max,
|
2395
2736
|
animate = angular.isDefined($attrs.animate) ? $scope.$parent.$eval($attrs.animate) : progressConfig.animate;
|
2396
2737
|
|
2738
|
+
this.bars = [];
|
2739
|
+
$scope.max = angular.isDefined($attrs.max) ? $scope.$parent.$eval($attrs.max) : progressConfig.max;
|
2740
|
+
|
2397
2741
|
this.addBar = function(bar, element) {
|
2398
|
-
|
2399
|
-
|
2400
|
-
oldValue = bars[index].value;
|
2742
|
+
if ( !animate ) {
|
2743
|
+
element.css({'transition': 'none'});
|
2401
2744
|
}
|
2402
|
-
bars.push(bar);
|
2403
2745
|
|
2404
|
-
this.
|
2746
|
+
this.bars.push(bar);
|
2405
2747
|
|
2406
|
-
bar.$watch('value', function(value
|
2407
|
-
|
2408
|
-
self.update(element, value, oldValue);
|
2409
|
-
}
|
2748
|
+
bar.$watch('value', function( value ) {
|
2749
|
+
bar.percent = +(100 * value / $scope.max).toFixed(2);
|
2410
2750
|
});
|
2411
2751
|
|
2412
2752
|
bar.$on('$destroy', function() {
|
2753
|
+
element = null;
|
2413
2754
|
self.removeBar(bar);
|
2414
2755
|
});
|
2415
2756
|
};
|
2416
2757
|
|
2417
|
-
// Update bar element width
|
2418
|
-
this.update = function(element, newValue, oldValue) {
|
2419
|
-
var percent = this.getPercentage(newValue);
|
2420
|
-
|
2421
|
-
if (animate) {
|
2422
|
-
element.css('width', this.getPercentage(oldValue) + '%');
|
2423
|
-
$transition(element, {width: percent + '%'});
|
2424
|
-
} else {
|
2425
|
-
element.css({'transition': 'none', 'width': percent + '%'});
|
2426
|
-
}
|
2427
|
-
};
|
2428
|
-
|
2429
2758
|
this.removeBar = function(bar) {
|
2430
|
-
bars.splice(bars.indexOf(bar), 1);
|
2431
|
-
};
|
2432
|
-
|
2433
|
-
this.getPercentage = function(value) {
|
2434
|
-
return Math.round(100 * value / max);
|
2759
|
+
this.bars.splice(this.bars.indexOf(bar), 1);
|
2435
2760
|
};
|
2436
2761
|
}])
|
2437
2762
|
|
@@ -2443,8 +2768,7 @@ angular.module('ui.bootstrap.progressbar', ['ui.bootstrap.transition'])
|
|
2443
2768
|
controller: 'ProgressController',
|
2444
2769
|
require: 'progress',
|
2445
2770
|
scope: {},
|
2446
|
-
|
2447
|
-
//templateUrl: 'template/progressbar/progress.html' // Works in AngularJS 1.2
|
2771
|
+
templateUrl: 'template/progressbar/progress.html'
|
2448
2772
|
};
|
2449
2773
|
})
|
2450
2774
|
|
@@ -2489,68 +2813,79 @@ angular.module('ui.bootstrap.rating', [])
|
|
2489
2813
|
stateOff: null
|
2490
2814
|
})
|
2491
2815
|
|
2492
|
-
.controller('RatingController', ['$scope', '$attrs', '
|
2816
|
+
.controller('RatingController', ['$scope', '$attrs', 'ratingConfig', function($scope, $attrs, ratingConfig) {
|
2817
|
+
var ngModelCtrl = { $setViewValue: angular.noop };
|
2493
2818
|
|
2494
|
-
this.
|
2495
|
-
|
2496
|
-
|
2819
|
+
this.init = function(ngModelCtrl_) {
|
2820
|
+
ngModelCtrl = ngModelCtrl_;
|
2821
|
+
ngModelCtrl.$render = this.render;
|
2497
2822
|
|
2498
|
-
|
2499
|
-
|
2500
|
-
|
2501
|
-
|
2502
|
-
|
2823
|
+
this.stateOn = angular.isDefined($attrs.stateOn) ? $scope.$parent.$eval($attrs.stateOn) : ratingConfig.stateOn;
|
2824
|
+
this.stateOff = angular.isDefined($attrs.stateOff) ? $scope.$parent.$eval($attrs.stateOff) : ratingConfig.stateOff;
|
2825
|
+
|
2826
|
+
var ratingStates = angular.isDefined($attrs.ratingStates) ? $scope.$parent.$eval($attrs.ratingStates) :
|
2827
|
+
new Array( angular.isDefined($attrs.max) ? $scope.$parent.$eval($attrs.max) : ratingConfig.max );
|
2828
|
+
$scope.range = this.buildTemplateObjects(ratingStates);
|
2829
|
+
};
|
2503
2830
|
|
2831
|
+
this.buildTemplateObjects = function(states) {
|
2504
2832
|
for (var i = 0, n = states.length; i < n; i++) {
|
2505
|
-
states[i] = angular.extend({ index: i },
|
2833
|
+
states[i] = angular.extend({ index: i }, { stateOn: this.stateOn, stateOff: this.stateOff }, states[i]);
|
2506
2834
|
}
|
2507
2835
|
return states;
|
2508
2836
|
};
|
2509
2837
|
|
2510
|
-
// Get objects used in template
|
2511
|
-
$scope.range = angular.isDefined($attrs.ratingStates) ? this.createRateObjects(angular.copy($scope.$parent.$eval($attrs.ratingStates))): this.createRateObjects(new Array(this.maxRange));
|
2512
|
-
|
2513
2838
|
$scope.rate = function(value) {
|
2514
|
-
if (
|
2515
|
-
|
2839
|
+
if ( !$scope.readonly && value >= 0 && value <= $scope.range.length ) {
|
2840
|
+
ngModelCtrl.$setViewValue(value);
|
2841
|
+
ngModelCtrl.$render();
|
2516
2842
|
}
|
2517
2843
|
};
|
2518
2844
|
|
2519
2845
|
$scope.enter = function(value) {
|
2520
|
-
if (
|
2521
|
-
$scope.
|
2846
|
+
if ( !$scope.readonly ) {
|
2847
|
+
$scope.value = value;
|
2522
2848
|
}
|
2523
2849
|
$scope.onHover({value: value});
|
2524
2850
|
};
|
2525
2851
|
|
2526
2852
|
$scope.reset = function() {
|
2527
|
-
$scope.
|
2853
|
+
$scope.value = ngModelCtrl.$viewValue;
|
2528
2854
|
$scope.onLeave();
|
2529
2855
|
};
|
2530
2856
|
|
2531
|
-
$scope
|
2532
|
-
|
2533
|
-
|
2857
|
+
$scope.onKeydown = function(evt) {
|
2858
|
+
if (/(37|38|39|40)/.test(evt.which)) {
|
2859
|
+
evt.preventDefault();
|
2860
|
+
evt.stopPropagation();
|
2861
|
+
$scope.rate( $scope.value + (evt.which === 38 || evt.which === 39 ? 1 : -1) );
|
2862
|
+
}
|
2863
|
+
};
|
2534
2864
|
|
2535
|
-
|
2536
|
-
|
2537
|
-
|
2538
|
-
$scope.readonly = !!value;
|
2539
|
-
});
|
2540
|
-
}
|
2865
|
+
this.render = function() {
|
2866
|
+
$scope.value = ngModelCtrl.$viewValue;
|
2867
|
+
};
|
2541
2868
|
}])
|
2542
2869
|
|
2543
2870
|
.directive('rating', function() {
|
2544
2871
|
return {
|
2545
2872
|
restrict: 'EA',
|
2873
|
+
require: ['rating', 'ngModel'],
|
2546
2874
|
scope: {
|
2547
|
-
|
2875
|
+
readonly: '=?',
|
2548
2876
|
onHover: '&',
|
2549
2877
|
onLeave: '&'
|
2550
2878
|
},
|
2551
2879
|
controller: 'RatingController',
|
2552
2880
|
templateUrl: 'template/rating/rating.html',
|
2553
|
-
replace: true
|
2881
|
+
replace: true,
|
2882
|
+
link: function(scope, element, attrs, ctrls) {
|
2883
|
+
var ratingCtrl = ctrls[0], ngModelCtrl = ctrls[1];
|
2884
|
+
|
2885
|
+
if ( ngModelCtrl ) {
|
2886
|
+
ratingCtrl.init( ngModelCtrl );
|
2887
|
+
}
|
2888
|
+
}
|
2554
2889
|
};
|
2555
2890
|
});
|
2556
2891
|
|
@@ -2568,16 +2903,24 @@ angular.module('ui.bootstrap.tabs', [])
|
|
2568
2903
|
var ctrl = this,
|
2569
2904
|
tabs = ctrl.tabs = $scope.tabs = [];
|
2570
2905
|
|
2571
|
-
ctrl.select = function(
|
2906
|
+
ctrl.select = function(selectedTab) {
|
2572
2907
|
angular.forEach(tabs, function(tab) {
|
2573
|
-
tab.active
|
2908
|
+
if (tab.active && tab !== selectedTab) {
|
2909
|
+
tab.active = false;
|
2910
|
+
tab.onDeselect();
|
2911
|
+
}
|
2574
2912
|
});
|
2575
|
-
|
2913
|
+
selectedTab.active = true;
|
2914
|
+
selectedTab.onSelect();
|
2576
2915
|
};
|
2577
2916
|
|
2578
2917
|
ctrl.addTab = function addTab(tab) {
|
2579
2918
|
tabs.push(tab);
|
2580
|
-
|
2919
|
+
// we can't run the select function on the first tab
|
2920
|
+
// since that would select it twice
|
2921
|
+
if (tabs.length === 1) {
|
2922
|
+
tab.active = true;
|
2923
|
+
} else if (tab.active) {
|
2581
2924
|
ctrl.select(tab);
|
2582
2925
|
}
|
2583
2926
|
};
|
@@ -2629,13 +2972,14 @@ angular.module('ui.bootstrap.tabs', [])
|
|
2629
2972
|
restrict: 'EA',
|
2630
2973
|
transclude: true,
|
2631
2974
|
replace: true,
|
2632
|
-
scope: {
|
2975
|
+
scope: {
|
2976
|
+
type: '@'
|
2977
|
+
},
|
2633
2978
|
controller: 'TabsetController',
|
2634
2979
|
templateUrl: 'template/tabs/tabset.html',
|
2635
2980
|
link: function(scope, element, attrs) {
|
2636
2981
|
scope.vertical = angular.isDefined(attrs.vertical) ? scope.$parent.$eval(attrs.vertical) : false;
|
2637
2982
|
scope.justified = angular.isDefined(attrs.justified) ? scope.$parent.$eval(attrs.justified) : false;
|
2638
|
-
scope.type = angular.isDefined(attrs.type) ? scope.$parent.$eval(attrs.type) : 'tabs';
|
2639
2983
|
}
|
2640
2984
|
};
|
2641
2985
|
})
|
@@ -2728,6 +3072,7 @@ angular.module('ui.bootstrap.tabs', [])
|
|
2728
3072
|
templateUrl: 'template/tabs/tab.html',
|
2729
3073
|
transclude: true,
|
2730
3074
|
scope: {
|
3075
|
+
active: '=?',
|
2731
3076
|
heading: '@',
|
2732
3077
|
onSelect: '&select', //This callback is called in contentHeadingTransclude
|
2733
3078
|
//once it inserts the tab's content into the dom
|
@@ -2738,32 +3083,9 @@ angular.module('ui.bootstrap.tabs', [])
|
|
2738
3083
|
},
|
2739
3084
|
compile: function(elm, attrs, transclude) {
|
2740
3085
|
return function postLink(scope, elm, attrs, tabsetCtrl) {
|
2741
|
-
var getActive, setActive;
|
2742
|
-
if (attrs.active) {
|
2743
|
-
getActive = $parse(attrs.active);
|
2744
|
-
setActive = getActive.assign;
|
2745
|
-
scope.$parent.$watch(getActive, function updateActive(value, oldVal) {
|
2746
|
-
// Avoid re-initializing scope.active as it is already initialized
|
2747
|
-
// below. (watcher is called async during init with value ===
|
2748
|
-
// oldVal)
|
2749
|
-
if (value !== oldVal) {
|
2750
|
-
scope.active = !!value;
|
2751
|
-
}
|
2752
|
-
});
|
2753
|
-
scope.active = getActive(scope.$parent);
|
2754
|
-
} else {
|
2755
|
-
setActive = getActive = angular.noop;
|
2756
|
-
}
|
2757
|
-
|
2758
3086
|
scope.$watch('active', function(active) {
|
2759
|
-
// Note this watcher also initializes and assigns scope.active to the
|
2760
|
-
// attrs.active expression.
|
2761
|
-
setActive(scope.$parent, active);
|
2762
3087
|
if (active) {
|
2763
3088
|
tabsetCtrl.select(scope);
|
2764
|
-
scope.onSelect();
|
2765
|
-
} else {
|
2766
|
-
scope.onDeselect();
|
2767
3089
|
}
|
2768
3090
|
});
|
2769
3091
|
|
@@ -2775,7 +3097,7 @@ angular.module('ui.bootstrap.tabs', [])
|
|
2775
3097
|
}
|
2776
3098
|
|
2777
3099
|
scope.select = function() {
|
2778
|
-
if ( !
|
3100
|
+
if ( !scope.disabled ) {
|
2779
3101
|
scope.active = true;
|
2780
3102
|
}
|
2781
3103
|
};
|
@@ -2785,7 +3107,6 @@ angular.module('ui.bootstrap.tabs', [])
|
|
2785
3107
|
tabsetCtrl.removeTab(scope);
|
2786
3108
|
});
|
2787
3109
|
|
2788
|
-
|
2789
3110
|
//We need to transclude later, once the content container is ready.
|
2790
3111
|
//when this link happens, we're inside a tab heading.
|
2791
3112
|
scope.$transcludeFn = transclude;
|
@@ -2853,228 +3174,249 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
2853
3174
|
mousewheel: true
|
2854
3175
|
})
|
2855
3176
|
|
2856
|
-
.
|
2857
|
-
|
2858
|
-
|
2859
|
-
|
2860
|
-
replace: true,
|
2861
|
-
scope: {},
|
2862
|
-
templateUrl: 'template/timepicker/timepicker.html',
|
2863
|
-
link: function(scope, element, attrs, ngModel) {
|
2864
|
-
if ( !ngModel ) {
|
2865
|
-
return; // do nothing if no ng-model
|
2866
|
-
}
|
3177
|
+
.controller('TimepickerController', ['$scope', '$attrs', '$parse', '$log', '$locale', 'timepickerConfig', function($scope, $attrs, $parse, $log, $locale, timepickerConfig) {
|
3178
|
+
var selected = new Date(),
|
3179
|
+
ngModelCtrl = { $setViewValue: angular.noop }, // nullModelCtrl
|
3180
|
+
meridians = angular.isDefined($attrs.meridians) ? $scope.$parent.$eval($attrs.meridians) : timepickerConfig.meridians || $locale.DATETIME_FORMATS.AMPMS;
|
2867
3181
|
|
2868
|
-
|
2869
|
-
|
3182
|
+
this.init = function( ngModelCtrl_, inputs ) {
|
3183
|
+
ngModelCtrl = ngModelCtrl_;
|
3184
|
+
ngModelCtrl.$render = this.render;
|
2870
3185
|
|
2871
|
-
|
2872
|
-
|
2873
|
-
scope.$parent.$watch($parse(attrs.hourStep), function(value) {
|
2874
|
-
hourStep = parseInt(value, 10);
|
2875
|
-
});
|
2876
|
-
}
|
3186
|
+
var hoursInputEl = inputs.eq(0),
|
3187
|
+
minutesInputEl = inputs.eq(1);
|
2877
3188
|
|
2878
|
-
|
2879
|
-
|
2880
|
-
|
2881
|
-
|
2882
|
-
});
|
2883
|
-
}
|
3189
|
+
var mousewheel = angular.isDefined($attrs.mousewheel) ? $scope.$parent.$eval($attrs.mousewheel) : timepickerConfig.mousewheel;
|
3190
|
+
if ( mousewheel ) {
|
3191
|
+
this.setupMousewheelEvents( hoursInputEl, minutesInputEl );
|
3192
|
+
}
|
2884
3193
|
|
2885
|
-
|
2886
|
-
|
2887
|
-
|
2888
|
-
scope.$parent.$watch($parse(attrs.showMeridian), function(value) {
|
2889
|
-
scope.showMeridian = !!value;
|
2890
|
-
|
2891
|
-
if ( ngModel.$error.time ) {
|
2892
|
-
// Evaluate from template
|
2893
|
-
var hours = getHoursFromTemplate(), minutes = getMinutesFromTemplate();
|
2894
|
-
if (angular.isDefined( hours ) && angular.isDefined( minutes )) {
|
2895
|
-
selected.setHours( hours );
|
2896
|
-
refresh();
|
2897
|
-
}
|
2898
|
-
} else {
|
2899
|
-
updateTemplate();
|
2900
|
-
}
|
2901
|
-
});
|
2902
|
-
}
|
3194
|
+
$scope.readonlyInput = angular.isDefined($attrs.readonlyInput) ? $scope.$parent.$eval($attrs.readonlyInput) : timepickerConfig.readonlyInput;
|
3195
|
+
this.setupInputEvents( hoursInputEl, minutesInputEl );
|
3196
|
+
};
|
2903
3197
|
|
2904
|
-
|
2905
|
-
|
2906
|
-
|
2907
|
-
|
2908
|
-
|
2909
|
-
|
2910
|
-
}
|
3198
|
+
var hourStep = timepickerConfig.hourStep;
|
3199
|
+
if ($attrs.hourStep) {
|
3200
|
+
$scope.$parent.$watch($parse($attrs.hourStep), function(value) {
|
3201
|
+
hourStep = parseInt(value, 10);
|
3202
|
+
});
|
3203
|
+
}
|
2911
3204
|
|
2912
|
-
|
2913
|
-
|
2914
|
-
|
2915
|
-
|
2916
|
-
|
2917
|
-
|
2918
|
-
|
3205
|
+
var minuteStep = timepickerConfig.minuteStep;
|
3206
|
+
if ($attrs.minuteStep) {
|
3207
|
+
$scope.$parent.$watch($parse($attrs.minuteStep), function(value) {
|
3208
|
+
minuteStep = parseInt(value, 10);
|
3209
|
+
});
|
3210
|
+
}
|
3211
|
+
|
3212
|
+
// 12H / 24H mode
|
3213
|
+
$scope.showMeridian = timepickerConfig.showMeridian;
|
3214
|
+
if ($attrs.showMeridian) {
|
3215
|
+
$scope.$parent.$watch($parse($attrs.showMeridian), function(value) {
|
3216
|
+
$scope.showMeridian = !!value;
|
3217
|
+
|
3218
|
+
if ( ngModelCtrl.$error.time ) {
|
3219
|
+
// Evaluate from template
|
3220
|
+
var hours = getHoursFromTemplate(), minutes = getMinutesFromTemplate();
|
3221
|
+
if (angular.isDefined( hours ) && angular.isDefined( minutes )) {
|
3222
|
+
selected.setHours( hours );
|
3223
|
+
refresh();
|
2919
3224
|
}
|
2920
|
-
|
3225
|
+
} else {
|
3226
|
+
updateTemplate();
|
2921
3227
|
}
|
3228
|
+
});
|
3229
|
+
}
|
2922
3230
|
|
2923
|
-
|
2924
|
-
|
2925
|
-
|
2926
|
-
|
3231
|
+
// Get $scope.hours in 24H mode if valid
|
3232
|
+
function getHoursFromTemplate ( ) {
|
3233
|
+
var hours = parseInt( $scope.hours, 10 );
|
3234
|
+
var valid = ( $scope.showMeridian ) ? (hours > 0 && hours < 13) : (hours >= 0 && hours < 24);
|
3235
|
+
if ( !valid ) {
|
3236
|
+
return undefined;
|
3237
|
+
}
|
2927
3238
|
|
2928
|
-
|
2929
|
-
|
3239
|
+
if ( $scope.showMeridian ) {
|
3240
|
+
if ( hours === 12 ) {
|
3241
|
+
hours = 0;
|
3242
|
+
}
|
3243
|
+
if ( $scope.meridian === meridians[1] ) {
|
3244
|
+
hours = hours + 12;
|
2930
3245
|
}
|
3246
|
+
}
|
3247
|
+
return hours;
|
3248
|
+
}
|
2931
3249
|
|
2932
|
-
|
2933
|
-
|
3250
|
+
function getMinutesFromTemplate() {
|
3251
|
+
var minutes = parseInt($scope.minutes, 10);
|
3252
|
+
return ( minutes >= 0 && minutes < 60 ) ? minutes : undefined;
|
3253
|
+
}
|
2934
3254
|
|
2935
|
-
|
2936
|
-
|
2937
|
-
|
3255
|
+
function pad( value ) {
|
3256
|
+
return ( angular.isDefined(value) && value.toString().length < 2 ) ? '0' + value : value;
|
3257
|
+
}
|
2938
3258
|
|
2939
|
-
|
2940
|
-
|
2941
|
-
|
2942
|
-
|
2943
|
-
|
2944
|
-
|
2945
|
-
|
2946
|
-
|
3259
|
+
// Respond on mousewheel spin
|
3260
|
+
this.setupMousewheelEvents = function( hoursInputEl, minutesInputEl ) {
|
3261
|
+
var isScrollingUp = function(e) {
|
3262
|
+
if (e.originalEvent) {
|
3263
|
+
e = e.originalEvent;
|
3264
|
+
}
|
3265
|
+
//pick correct delta variable depending on event
|
3266
|
+
var delta = (e.wheelDelta) ? e.wheelDelta : -e.deltaY;
|
3267
|
+
return (e.detail || delta > 0);
|
3268
|
+
};
|
2947
3269
|
|
2948
|
-
|
2949
|
-
|
2950
|
-
|
2951
|
-
|
3270
|
+
hoursInputEl.bind('mousewheel wheel', function(e) {
|
3271
|
+
$scope.$apply( (isScrollingUp(e)) ? $scope.incrementHours() : $scope.decrementHours() );
|
3272
|
+
e.preventDefault();
|
3273
|
+
});
|
2952
3274
|
|
2953
|
-
|
2954
|
-
|
2955
|
-
|
2956
|
-
|
2957
|
-
|
3275
|
+
minutesInputEl.bind('mousewheel wheel', function(e) {
|
3276
|
+
$scope.$apply( (isScrollingUp(e)) ? $scope.incrementMinutes() : $scope.decrementMinutes() );
|
3277
|
+
e.preventDefault();
|
3278
|
+
});
|
3279
|
+
|
3280
|
+
};
|
2958
3281
|
|
2959
|
-
|
2960
|
-
|
3282
|
+
this.setupInputEvents = function( hoursInputEl, minutesInputEl ) {
|
3283
|
+
if ( $scope.readonlyInput ) {
|
3284
|
+
$scope.updateHours = angular.noop;
|
3285
|
+
$scope.updateMinutes = angular.noop;
|
3286
|
+
return;
|
3287
|
+
}
|
2961
3288
|
|
2962
|
-
|
2963
|
-
|
2964
|
-
|
2965
|
-
|
2966
|
-
|
2967
|
-
|
2968
|
-
|
2969
|
-
|
2970
|
-
|
2971
|
-
|
3289
|
+
var invalidate = function(invalidHours, invalidMinutes) {
|
3290
|
+
ngModelCtrl.$setViewValue( null );
|
3291
|
+
ngModelCtrl.$setValidity('time', false);
|
3292
|
+
if (angular.isDefined(invalidHours)) {
|
3293
|
+
$scope.invalidHours = invalidHours;
|
3294
|
+
}
|
3295
|
+
if (angular.isDefined(invalidMinutes)) {
|
3296
|
+
$scope.invalidMinutes = invalidMinutes;
|
3297
|
+
}
|
3298
|
+
};
|
2972
3299
|
|
2973
|
-
|
2974
|
-
|
3300
|
+
$scope.updateHours = function() {
|
3301
|
+
var hours = getHoursFromTemplate();
|
2975
3302
|
|
2976
|
-
|
2977
|
-
|
2978
|
-
|
2979
|
-
|
2980
|
-
|
2981
|
-
|
2982
|
-
|
3303
|
+
if ( angular.isDefined(hours) ) {
|
3304
|
+
selected.setHours( hours );
|
3305
|
+
refresh( 'h' );
|
3306
|
+
} else {
|
3307
|
+
invalidate(true);
|
3308
|
+
}
|
3309
|
+
};
|
2983
3310
|
|
2984
|
-
|
2985
|
-
|
2986
|
-
|
2987
|
-
|
2988
|
-
});
|
2989
|
-
}
|
3311
|
+
hoursInputEl.bind('blur', function(e) {
|
3312
|
+
if ( !$scope.invalidHours && $scope.hours < 10) {
|
3313
|
+
$scope.$apply( function() {
|
3314
|
+
$scope.hours = pad( $scope.hours );
|
2990
3315
|
});
|
3316
|
+
}
|
3317
|
+
});
|
2991
3318
|
|
2992
|
-
|
2993
|
-
|
3319
|
+
$scope.updateMinutes = function() {
|
3320
|
+
var minutes = getMinutesFromTemplate();
|
2994
3321
|
|
2995
|
-
|
2996
|
-
|
2997
|
-
|
2998
|
-
|
2999
|
-
|
3000
|
-
|
3001
|
-
|
3322
|
+
if ( angular.isDefined(minutes) ) {
|
3323
|
+
selected.setMinutes( minutes );
|
3324
|
+
refresh( 'm' );
|
3325
|
+
} else {
|
3326
|
+
invalidate(undefined, true);
|
3327
|
+
}
|
3328
|
+
};
|
3002
3329
|
|
3003
|
-
|
3004
|
-
|
3005
|
-
|
3006
|
-
|
3007
|
-
});
|
3008
|
-
}
|
3330
|
+
minutesInputEl.bind('blur', function(e) {
|
3331
|
+
if ( !$scope.invalidMinutes && $scope.minutes < 10 ) {
|
3332
|
+
$scope.$apply( function() {
|
3333
|
+
$scope.minutes = pad( $scope.minutes );
|
3009
3334
|
});
|
3010
|
-
} else {
|
3011
|
-
scope.updateHours = angular.noop;
|
3012
|
-
scope.updateMinutes = angular.noop;
|
3013
3335
|
}
|
3336
|
+
});
|
3014
3337
|
|
3015
|
-
|
3016
|
-
var date = ngModel.$modelValue ? new Date( ngModel.$modelValue ) : null;
|
3338
|
+
};
|
3017
3339
|
|
3018
|
-
|
3019
|
-
|
3020
|
-
$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.');
|
3021
|
-
} else {
|
3022
|
-
if ( date ) {
|
3023
|
-
selected = date;
|
3024
|
-
}
|
3025
|
-
makeValid();
|
3026
|
-
updateTemplate();
|
3027
|
-
}
|
3028
|
-
};
|
3340
|
+
this.render = function() {
|
3341
|
+
var date = ngModelCtrl.$modelValue ? new Date( ngModelCtrl.$modelValue ) : null;
|
3029
3342
|
|
3030
|
-
|
3031
|
-
|
3032
|
-
|
3033
|
-
|
3034
|
-
|
3343
|
+
if ( isNaN(date) ) {
|
3344
|
+
ngModelCtrl.$setValidity('time', false);
|
3345
|
+
$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.');
|
3346
|
+
} else {
|
3347
|
+
if ( date ) {
|
3348
|
+
selected = date;
|
3035
3349
|
}
|
3350
|
+
makeValid();
|
3351
|
+
updateTemplate();
|
3352
|
+
}
|
3353
|
+
};
|
3036
3354
|
|
3037
|
-
|
3038
|
-
|
3039
|
-
|
3040
|
-
|
3041
|
-
|
3355
|
+
// Call internally when we know that model is valid.
|
3356
|
+
function refresh( keyboardChange ) {
|
3357
|
+
makeValid();
|
3358
|
+
ngModelCtrl.$setViewValue( new Date(selected) );
|
3359
|
+
updateTemplate( keyboardChange );
|
3360
|
+
}
|
3042
3361
|
|
3043
|
-
|
3044
|
-
|
3362
|
+
function makeValid() {
|
3363
|
+
ngModelCtrl.$setValidity('time', true);
|
3364
|
+
$scope.invalidHours = false;
|
3365
|
+
$scope.invalidMinutes = false;
|
3366
|
+
}
|
3045
3367
|
|
3046
|
-
|
3047
|
-
|
3048
|
-
}
|
3049
|
-
scope.hours = keyboardChange === 'h' ? hours : pad(hours);
|
3050
|
-
scope.minutes = keyboardChange === 'm' ? minutes : pad(minutes);
|
3051
|
-
scope.meridian = selected.getHours() < 12 ? meridians[0] : meridians[1];
|
3052
|
-
}
|
3368
|
+
function updateTemplate( keyboardChange ) {
|
3369
|
+
var hours = selected.getHours(), minutes = selected.getMinutes();
|
3053
3370
|
|
3054
|
-
|
3055
|
-
|
3056
|
-
|
3057
|
-
refresh();
|
3058
|
-
}
|
3371
|
+
if ( $scope.showMeridian ) {
|
3372
|
+
hours = ( hours === 0 || hours === 12 ) ? 12 : hours % 12; // Convert 24 to 12 hour system
|
3373
|
+
}
|
3059
3374
|
|
3060
|
-
|
3061
|
-
|
3062
|
-
|
3063
|
-
|
3064
|
-
|
3065
|
-
|
3066
|
-
|
3067
|
-
|
3068
|
-
|
3069
|
-
|
3070
|
-
|
3071
|
-
|
3072
|
-
|
3073
|
-
|
3074
|
-
|
3375
|
+
$scope.hours = keyboardChange === 'h' ? hours : pad(hours);
|
3376
|
+
$scope.minutes = keyboardChange === 'm' ? minutes : pad(minutes);
|
3377
|
+
$scope.meridian = selected.getHours() < 12 ? meridians[0] : meridians[1];
|
3378
|
+
}
|
3379
|
+
|
3380
|
+
function addMinutes( minutes ) {
|
3381
|
+
var dt = new Date( selected.getTime() + minutes * 60000 );
|
3382
|
+
selected.setHours( dt.getHours(), dt.getMinutes() );
|
3383
|
+
refresh();
|
3384
|
+
}
|
3385
|
+
|
3386
|
+
$scope.incrementHours = function() {
|
3387
|
+
addMinutes( hourStep * 60 );
|
3388
|
+
};
|
3389
|
+
$scope.decrementHours = function() {
|
3390
|
+
addMinutes( - hourStep * 60 );
|
3391
|
+
};
|
3392
|
+
$scope.incrementMinutes = function() {
|
3393
|
+
addMinutes( minuteStep );
|
3394
|
+
};
|
3395
|
+
$scope.decrementMinutes = function() {
|
3396
|
+
addMinutes( - minuteStep );
|
3397
|
+
};
|
3398
|
+
$scope.toggleMeridian = function() {
|
3399
|
+
addMinutes( 12 * 60 * (( selected.getHours() < 12 ) ? 1 : -1) );
|
3400
|
+
};
|
3401
|
+
}])
|
3402
|
+
|
3403
|
+
.directive('timepicker', function () {
|
3404
|
+
return {
|
3405
|
+
restrict: 'EA',
|
3406
|
+
require: ['timepicker', '?^ngModel'],
|
3407
|
+
controller:'TimepickerController',
|
3408
|
+
replace: true,
|
3409
|
+
scope: {},
|
3410
|
+
templateUrl: 'template/timepicker/timepicker.html',
|
3411
|
+
link: function(scope, element, attrs, ctrls) {
|
3412
|
+
var timepickerCtrl = ctrls[0], ngModelCtrl = ctrls[1];
|
3413
|
+
|
3414
|
+
if ( ngModelCtrl ) {
|
3415
|
+
timepickerCtrl.init( ngModelCtrl, element.find('input') );
|
3416
|
+
}
|
3075
3417
|
}
|
3076
3418
|
};
|
3077
|
-
}
|
3419
|
+
});
|
3078
3420
|
|
3079
3421
|
angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap.bindHtml'])
|
3080
3422
|
|
@@ -3090,11 +3432,11 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
|
|
3090
3432
|
return {
|
3091
3433
|
parse:function (input) {
|
3092
3434
|
|
3093
|
-
var match = input.match(TYPEAHEAD_REGEXP)
|
3435
|
+
var match = input.match(TYPEAHEAD_REGEXP);
|
3094
3436
|
if (!match) {
|
3095
3437
|
throw new Error(
|
3096
|
-
|
3097
|
-
|
3438
|
+
'Expected typeahead specification in form of "_modelValue_ (as _label_)? for _item_ in _collection_"' +
|
3439
|
+
' but got "' + input + '".');
|
3098
3440
|
}
|
3099
3441
|
|
3100
3442
|
return {
|
@@ -3135,7 +3477,7 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
|
|
3135
3477
|
|
3136
3478
|
var inputFormatter = attrs.typeaheadInputFormatter ? $parse(attrs.typeaheadInputFormatter) : undefined;
|
3137
3479
|
|
3138
|
-
var appendToBody = attrs.typeaheadAppendToBody ?
|
3480
|
+
var appendToBody = attrs.typeaheadAppendToBody ? originalScope.$eval(attrs.typeaheadAppendToBody) : false;
|
3139
3481
|
|
3140
3482
|
//INTERNAL VARIABLES
|
3141
3483
|
|
@@ -3147,9 +3489,25 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
|
|
3147
3489
|
|
3148
3490
|
var hasFocus;
|
3149
3491
|
|
3492
|
+
//create a child scope for the typeahead directive so we are not polluting original scope
|
3493
|
+
//with typeahead-specific data (matches, query etc.)
|
3494
|
+
var scope = originalScope.$new();
|
3495
|
+
originalScope.$on('$destroy', function(){
|
3496
|
+
scope.$destroy();
|
3497
|
+
});
|
3498
|
+
|
3499
|
+
// WAI-ARIA
|
3500
|
+
var popupId = 'typeahead-' + scope.$id + '-' + Math.floor(Math.random() * 10000);
|
3501
|
+
element.attr({
|
3502
|
+
'aria-autocomplete': 'list',
|
3503
|
+
'aria-expanded': false,
|
3504
|
+
'aria-owns': popupId
|
3505
|
+
});
|
3506
|
+
|
3150
3507
|
//pop-up element used to display matches
|
3151
3508
|
var popUpEl = angular.element('<div typeahead-popup></div>');
|
3152
3509
|
popUpEl.attr({
|
3510
|
+
id: popupId,
|
3153
3511
|
matches: 'matches',
|
3154
3512
|
active: 'activeIdx',
|
3155
3513
|
select: 'select(activeIdx)',
|
@@ -3161,18 +3519,26 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
|
|
3161
3519
|
popUpEl.attr('template-url', attrs.typeaheadTemplateUrl);
|
3162
3520
|
}
|
3163
3521
|
|
3164
|
-
//create a child scope for the typeahead directive so we are not polluting original scope
|
3165
|
-
//with typeahead-specific data (matches, query etc.)
|
3166
|
-
var scope = originalScope.$new();
|
3167
|
-
originalScope.$on('$destroy', function(){
|
3168
|
-
scope.$destroy();
|
3169
|
-
});
|
3170
|
-
|
3171
3522
|
var resetMatches = function() {
|
3172
3523
|
scope.matches = [];
|
3173
3524
|
scope.activeIdx = -1;
|
3525
|
+
element.attr('aria-expanded', false);
|
3526
|
+
};
|
3527
|
+
|
3528
|
+
var getMatchId = function(index) {
|
3529
|
+
return popupId + '-option-' + index;
|
3174
3530
|
};
|
3175
3531
|
|
3532
|
+
// Indicate that the specified match is the active (pre-selected) item in the list owned by this typeahead.
|
3533
|
+
// This attribute is added or removed automatically when the `activeIdx` changes.
|
3534
|
+
scope.$watch('activeIdx', function(index) {
|
3535
|
+
if (index < 0) {
|
3536
|
+
element.removeAttr('aria-activedescendant');
|
3537
|
+
} else {
|
3538
|
+
element.attr('aria-activedescendant', getMatchId(index));
|
3539
|
+
}
|
3540
|
+
});
|
3541
|
+
|
3176
3542
|
var getMatchesAsync = function(inputValue) {
|
3177
3543
|
|
3178
3544
|
var locals = {$viewValue: inputValue};
|
@@ -3181,7 +3547,8 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
|
|
3181
3547
|
|
3182
3548
|
//it might happen that several async queries were in progress if a user were typing fast
|
3183
3549
|
//but we are interested only in responses that correspond to the current view value
|
3184
|
-
|
3550
|
+
var onCurrentRequest = (inputValue === modelCtrl.$viewValue);
|
3551
|
+
if (onCurrentRequest && hasFocus) {
|
3185
3552
|
if (matches.length > 0) {
|
3186
3553
|
|
3187
3554
|
scope.activeIdx = 0;
|
@@ -3191,6 +3558,7 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
|
|
3191
3558
|
for(var i=0; i<matches.length; i++) {
|
3192
3559
|
locals[parserResult.itemName] = matches[i];
|
3193
3560
|
scope.matches.push({
|
3561
|
+
id: getMatchId(i),
|
3194
3562
|
label: parserResult.viewMapper(scope, locals),
|
3195
3563
|
model: matches[i]
|
3196
3564
|
});
|
@@ -3203,9 +3571,12 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
|
|
3203
3571
|
scope.position = appendToBody ? $position.offset(element) : $position.position(element);
|
3204
3572
|
scope.position.top = scope.position.top + element.prop('offsetHeight');
|
3205
3573
|
|
3574
|
+
element.attr('aria-expanded', true);
|
3206
3575
|
} else {
|
3207
3576
|
resetMatches();
|
3208
3577
|
}
|
3578
|
+
}
|
3579
|
+
if (onCurrentRequest) {
|
3209
3580
|
isLoadingSetter(originalScope, false);
|
3210
3581
|
}
|
3211
3582
|
}, function(){
|
@@ -3299,8 +3670,9 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
|
|
3299
3670
|
|
3300
3671
|
resetMatches();
|
3301
3672
|
|
3302
|
-
//return focus to the input element if a
|
3303
|
-
|
3673
|
+
//return focus to the input element if a match was selected via a mouse click event
|
3674
|
+
// use timeout to avoid $rootScope:inprog error
|
3675
|
+
$timeout(function() { element[0].focus(); }, 0, false);
|
3304
3676
|
};
|
3305
3677
|
|
3306
3678
|
//bind keyboard events: arrows up(38) / down(40), enter(13) and tab(9), esc(27)
|
@@ -3418,10 +3790,10 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
|
|
3418
3790
|
.filter('typeaheadHighlight', function() {
|
3419
3791
|
|
3420
3792
|
function escapeRegexp(queryToEscape) {
|
3421
|
-
return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g,
|
3793
|
+
return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
|
3422
3794
|
}
|
3423
3795
|
|
3424
3796
|
return function(matchItem, query) {
|
3425
|
-
return query ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '<strong>$&</strong>') : matchItem;
|
3797
|
+
return query ? ('' + matchItem).replace(new RegExp(escapeRegexp(query), 'gi'), '<strong>$&</strong>') : matchItem;
|
3426
3798
|
};
|
3427
|
-
});
|
3799
|
+
});
|