Skip to content

Commit 87e98c6

Browse files
committed
Merging latest master into pickYear/pickMonth branch to develop tests
2 parents 943e3aa + 80d988f commit 87e98c6

37 files changed

+3923
-73
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
instrumented/
2+
tests/coverage.html

.hgignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
instrumented/
2+
tests/coverage.html

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# Home
22

3-
http://www.eyecon.ro/bootstrap-datepicker/
3+
This is a fork of Stefan Petre's [original code](http://www.eyecon.ro/bootstrap-datepicker/);
4+
thanks go to him for getting this thing started!
5+
6+
Please note that this fork is not used on Stefan's page at this time, nor is it maintained or
7+
contributed to by him (yet?)
48

59
# Example
610

@@ -104,7 +108,7 @@ All options that take a "Date" can handle a `Date` object; a String formatted ac
104108

105109
String. Default: 'mm/dd/yyyy'
106110

107-
The date format, combination of d, dd, m, mm, M, MM, yy, yyy.
111+
The date format, combination of d, dd, m, mm, M, MM, yy, yyyy.
108112

109113
### weekStart
110114

js/bootstrap-datepicker.js

Lines changed: 141 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@
4747
});
4848
} else {
4949
if (this.component){
50+
// For components that are not readonly, allow keyboard nav
51+
this.element.find('input').on({
52+
focus: $.proxy(this.show, this),
53+
blur: $.proxy(this._hide, this),
54+
keyup: $.proxy(this.update, this),
55+
keydown: $.proxy(this.keydown, this)
56+
});
57+
5058
this.component.on('click', $.proxy(this.show, this));
5159
var element = this.element.find('input');
5260
element.on({
@@ -64,7 +72,7 @@
6472
this.autoclose = this.element.data('date-autoclose');
6573
}
6674

67-
switch(options.startView){
75+
switch(options.startView || this.element.data('date-start-view')){
6876
case 2:
6977
case 'decade':
7078
this.viewMode = this.startViewMode = 2;
@@ -155,14 +163,14 @@
155163
},
156164

157165
setValue: function() {
158-
var formated = DPGlobal.formatDate(this.date, this.format, this.language);
166+
var formatted = DPGlobal.formatDate(this.date, this.format, this.language);
159167
if (!this.isInput) {
160168
if (this.component){
161-
this.element.find('input').prop('value', formated);
169+
this.element.find('input').prop('value', formatted);
162170
}
163-
this.element.data('date', formated);
171+
this.element.data('date', formatted);
164172
} else {
165-
this.element.prop('value', formated);
173+
this.element.prop('value', formatted);
166174
}
167175
},
168176

@@ -185,16 +193,20 @@
185193
},
186194

187195
place: function(){
196+
var zIndex = parseInt(this.element.parents().filter(function() {
197+
return $(this).css('z-index') != 'auto';
198+
}).first().css('z-index'))+10;
188199
var offset = this.component ? this.component.offset() : this.element.offset();
189200
this.picker.css({
190201
top: offset.top + this.height,
191-
left: offset.left
202+
left: offset.left,
203+
zIndex: zIndex
192204
});
193205
},
194206

195207
update: function(){
196208
this.date = DPGlobal.parseDate(
197-
this.isInput ? this.element.prop('value') : this.element.data('date'),
209+
this.isInput ? this.element.prop('value') : this.element.data('date') || this.element.find('input').prop('value'),
198210
this.format, this.language
199211
);
200212
if (this.date < this.startDate) {
@@ -240,13 +252,14 @@
240252
this.updateNavArrows();
241253
this.fillMonths();
242254
var prevMonth = new Date(year, month-1, 28,0,0,0,0),
243-
day = DPGlobal.getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth());
255+
day = DPGlobal.getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth()),
256+
prevDate, dstDay = 0, date;
244257
prevMonth.setDate(day);
245258
prevMonth.setDate(day - (prevMonth.getDay() - this.weekStart + 7)%7);
246259
var nextMonth = new Date(prevMonth);
247260
nextMonth.setDate(nextMonth.getDate() + 42);
248261
nextMonth = nextMonth.valueOf();
249-
html = [];
262+
var html = [];
250263
var clsName;
251264
while(prevMonth.valueOf() < nextMonth) {
252265
if (prevMonth.getDay() == this.weekStart) {
@@ -264,11 +277,42 @@
264277
if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate) {
265278
clsName += ' disabled';
266279
}
267-
html.push('<td class="day'+clsName+'">'+prevMonth.getDate() + '</td>');
280+
date = prevMonth.getDate();
281+
if (dstDay == -1) date++;
282+
html.push('<td class="day'+clsName+'">'+date+ '</td>');
268283
if (prevMonth.getDay() == this.weekEnd) {
269284
html.push('</tr>');
270285
}
286+
prevDate = prevMonth.getDate();
271287
prevMonth.setDate(prevMonth.getDate()+1);
288+
if (prevMonth.getHours() != 0) {
289+
// Fix for DST bug: if we are no longer at start of day, a DST jump probably happened
290+
// We either fell back (eg, Jan 1 00:00 -> Jan 1 23:00)
291+
// or jumped forward (eg, Jan 1 00:00 -> Jan 2 01:00)
292+
// Unfortunately, I can think of no way to test this in the unit tests, as it depends
293+
// on the TZ of the client system.
294+
if (!dstDay) {
295+
// We are not currently handling a dst day (next round will deal with it)
296+
if (prevMonth.getDate() == prevDate)
297+
// We must compensate for fall-back
298+
dstDay = -1;
299+
else
300+
// We must compensate for a jump-ahead
301+
dstDay = +1;
302+
}
303+
else {
304+
// The last round was our dst day (hours are still non-zero)
305+
if (dstDay == -1)
306+
// For a fall-back, fast-forward to next midnight
307+
prevMonth.setHours(24);
308+
else
309+
// For a jump-ahead, just reset to 0
310+
prevMonth.setHours(0);
311+
// Reset minutes, as some TZs may be off by portions of an hour
312+
prevMonth.setMinutes(0);
313+
dstDay = 0;
314+
}
315+
}
272316
}
273317
this.picker.find('.datepicker-days tbody').empty().append(html.join(''));
274318
var currentYear = this.date.getFullYear();
@@ -368,6 +412,7 @@
368412
break;
369413
case 'span':
370414
if (!target.is('.disabled')) {
415+
this.viewDate.setDate(1);
371416
if (target.is('.month')) {
372417
var month = target.parent().find('span').index(target);
373418
this.viewDate.setDate(1);
@@ -485,14 +530,19 @@
485530
return this.moveMonth(date, dir*12);
486531
},
487532

533+
dateWithinRange: function(date){
534+
return date >= this.startDate && date <= this.endDate;
535+
},
536+
488537
keydown: function(e){
489538
if (this.picker.is(':not(:visible)')){
490539
if (e.keyCode == 27) // allow escape to hide and re-show picker
491540
this.show();
492541
return;
493542
}
494543
var dateChanged = false,
495-
dir, day, month;
544+
dir, day, month,
545+
newDate, newViewDate;
496546
switch(e.keyCode){
497547
case 27: // escape
498548
this.hide();
@@ -502,37 +552,49 @@
502552
case 39: // right
503553
dir = e.keyCode == 37 ? -1 : 1;
504554
if (e.ctrlKey){
505-
this.date = this.moveYear(this.date, dir);
506-
this.viewDate = this.moveYear(this.viewDate, dir);
555+
newDate = this.moveYear(this.date, dir);
556+
newViewDate = this.moveYear(this.viewDate, dir);
507557
} else if (e.shiftKey){
508-
this.date = this.moveMonth(this.date, dir);
509-
this.viewDate = this.moveMonth(this.viewDate, dir);
558+
newDate = this.moveMonth(this.date, dir);
559+
newViewDate = this.moveMonth(this.viewDate, dir);
510560
} else {
511-
this.date.setDate(this.date.getDate() + dir);
512-
this.viewDate.setDate(this.viewDate.getDate() + dir);
561+
newDate = new Date(this.date);
562+
newDate.setDate(this.date.getDate() + dir);
563+
newViewDate = new Date(this.viewDate);
564+
newViewDate.setDate(this.viewDate.getDate() + dir);
565+
}
566+
if (this.dateWithinRange(newDate)){
567+
this.date = newDate;
568+
this.viewDate = newViewDate;
569+
this.setValue();
570+
this.update();
571+
e.preventDefault();
572+
dateChanged = true;
513573
}
514-
this.setValue();
515-
this.update();
516-
e.preventDefault();
517-
dateChanged = true;
518574
break;
519575
case 38: // up
520576
case 40: // down
521577
dir = e.keyCode == 38 ? -1 : 1;
522578
if (e.ctrlKey){
523-
this.date = this.moveYear(this.date, dir);
524-
this.viewDate = this.moveYear(this.viewDate, dir);
579+
newDate = this.moveYear(this.date, dir);
580+
newViewDate = this.moveYear(this.viewDate, dir);
525581
} else if (e.shiftKey){
526-
this.date = this.moveMonth(this.date, dir);
527-
this.viewDate = this.moveMonth(this.viewDate, dir);
582+
newDate = this.moveMonth(this.date, dir);
583+
newViewDate = this.moveMonth(this.viewDate, dir);
528584
} else {
529-
this.date.setDate(this.date.getDate() + dir * 7);
530-
this.viewDate.setDate(this.viewDate.getDate() + dir * 7);
585+
newDate = new Date(this.date);
586+
newDate.setDate(this.date.getDate() + dir * 7);
587+
newViewDate = new Date(this.viewDate);
588+
newViewDate.setDate(this.viewDate.getDate() + dir * 7);
589+
}
590+
if (this.dateWithinRange(newDate)){
591+
this.date = newDate;
592+
this.viewDate = newViewDate;
593+
this.setValue();
594+
this.update();
595+
e.preventDefault();
596+
dateChanged = true;
531597
}
532-
this.setValue();
533-
this.update();
534-
e.preventDefault();
535-
dateChanged = true;
536598
break;
537599
case 13: // enter
538600
this.hide();
@@ -654,49 +716,58 @@
654716
}
655717
return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
656718
}
657-
var parts = date ? date.match(this.nonpunctuation) : [],
719+
var parts = date && date.match(this.nonpunctuation) || [],
658720
date = new Date(),
659-
val, filtered;
721+
parsed = {},
722+
setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'],
723+
setters_map = {
724+
yyyy: function(d,v){ return d.setFullYear(v); },
725+
yy: function(d,v){ return d.setFullYear(2000+v); },
726+
m: function(d,v){
727+
v -= 1;
728+
while (v<0) v += 12;
729+
v %= 12;
730+
d.setMonth(v);
731+
while (d.getMonth() != v)
732+
d.setDate(d.getDate()-1);
733+
return d;
734+
},
735+
d: function(d,v){ return d.setDate(v); }
736+
},
737+
val, filtered, part;
738+
setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
739+
setters_map['dd'] = setters_map['d'];
660740
date = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
661741
if (parts.length == format.parts.length) {
662742
for (var i=0, cnt = format.parts.length; i < cnt; i++) {
663-
val = parseInt(parts[i], 10)||1;
664-
switch(format.parts[i]) {
665-
case 'MM':
666-
filtered = $(dates[language].months).filter(function(){
667-
var m = this.slice(0, parts[i].length),
668-
p = parts[i].slice(0, m.length);
669-
return m == p;
670-
});
671-
val = $.inArray(filtered[0], dates[language].months) + 1;
672-
break;
673-
case 'M':
674-
filtered = $(dates[language].monthsShort).filter(function(){
675-
var m = this.slice(0, parts[i].length),
676-
p = parts[i].slice(0, m.length);
677-
return m == p;
678-
});
679-
val = $.inArray(filtered[0], dates[language].monthsShort) + 1;
680-
break;
681-
}
682-
switch(format.parts[i]) {
683-
case 'dd':
684-
case 'd':
685-
date.setDate(val);
686-
break;
687-
case 'mm':
688-
case 'm':
689-
case 'MM':
690-
case 'M':
691-
date.setMonth(val - 1);
692-
break;
693-
case 'yy':
694-
date.setFullYear(2000 + val);
695-
break;
696-
case 'yyyy':
697-
date.setFullYear(val);
698-
break;
743+
val = parseInt(parts[i], 10);
744+
part = format.parts[i];
745+
if (isNaN(val)) {
746+
switch(part) {
747+
case 'MM':
748+
filtered = $(dates[language].months).filter(function(){
749+
var m = this.slice(0, parts[i].length),
750+
p = parts[i].slice(0, m.length);
751+
return m == p;
752+
});
753+
val = $.inArray(filtered[0], dates[language].months) + 1;
754+
break;
755+
case 'M':
756+
filtered = $(dates[language].monthsShort).filter(function(){
757+
var m = this.slice(0, parts[i].length),
758+
p = parts[i].slice(0, m.length);
759+
return m == p;
760+
});
761+
val = $.inArray(filtered[0], dates[language].monthsShort) + 1;
762+
break;
763+
}
699764
}
765+
parsed[part] = val;
766+
}
767+
for (var i=0, s; i<setters_order.length; i++){
768+
s = setters_order[i];
769+
if (s in parsed)
770+
setters_map[s](date, parsed[s])
700771
}
701772
}
702773
return date;
@@ -751,4 +822,4 @@
751822
'</div>'+
752823
'</div>';
753824

754-
}( window.jQuery )
825+
}( window.jQuery );

js/locales/bootstrap-datepicker.cs.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* Czech translation for bootstrap-datepicker
3+
* Matěj Koubík <matej@koubik.name>
4+
*/
5+
;(function($){
6+
$.fn.datepicker.dates['cs'] = {
7+
days: ["Neděle", "Pondělí", "Úterý", "Středa", "Čtvrtek", "Pátek", "Sobota", "Neděle"],
8+
daysShort: ["Ne", "Po", "Út", "St", "Čt", "Pá", "So", "Ne"],
9+
daysMin: ["N", "P", "Ú", "St", "Č", "P", "So", "N"],
10+
months: ["Leden", "Únor", "Březen", "Duben", "Květen", "Červen", "Červenec", "Srpen", "Září", "Říjen", "Listopad", "Prosinec"],
11+
monthsShort: ["Led", "Úno", "Bře", "Dub", "Kvě", "Čer", "Čnc", "Srp", "Zář", "Říj", "Lis", "Pro"]
12+
};
13+
}(jQuery));

js/locales/bootstrap-datepicker.fi.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* Finnish translation for bootstrap-datepicker
3+
* Jaakko Salonen <https://github.com/jsalonen>
4+
*/
5+
;(function($){
6+
$.fn.datepicker.dates['fi'] = {
7+
days: ["sunnuntai", "maanantai", "tiistai", "keskiviikko", "torstai", "perjantai", "lauantai", "sunnuntai"],
8+
daysShort: ["sun", "maa", "tii", "kes", "tor", "per", "lau", "sun"],
9+
daysMin: ["su", "ma", "ti", "ke", "to", "pe", "la", "su"],
10+
months: ["tammikuu", "helmikuu", "maaliskuu", "huhtikuu", "toukokuu", "kesäkuu", "heinäkuu", "elokuu", "syyskuu", "lokakuu", "marraskuu", "joulukuu"],
11+
monthsShort: ["tam", "hel", "maa", "huh", "tou", "kes", "hei", "elo", "syy", "lok", "mar", "jou"]
12+
};
13+
}(jQuery));

js/locales/bootstrap-datepicker.id.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* Bahasa translation for bootstrap-datepicker
3+
* Azwar Akbar <azwar.akbar@gmail.com>
4+
*/
5+
;(function($){
6+
$.fn.datepicker.dates['id'] = {
7+
days: ["Minggu", "Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu", "Minggu"],
8+
daysShort: ["Mgu", "Sen", "Sel", "Rab", "Kam", "Jum", "Sab", "Mgu"],
9+
daysMin: ["Mg", "Sn", "Sl", "Ra", "Ka", "Ju", "Sa", "Mg"],
10+
months: ["Januari", "Februari", "Maret", "April", "Mei", "Juni", "Juli", "Agustus", "September", "Oktober", "November", "Desember"],
11+
monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Ags", "Sep", "Okt", "Nov", "Des"]
12+
};
13+
}(jQuery));

0 commit comments

Comments
 (0)