Skip to content

Commit 52bae16

Browse files
committed
Merge latest master into extensible branch
2 parents 3d6630c + ad7c00e commit 52bae16

13 files changed

+243
-32
lines changed

README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,12 @@ Date. Default: End of time
136136

137137
The latest date that may be selected; all later dates will be disabled.
138138

139+
### daysOfWeekDisabled
140+
141+
String, Array. Default: '', []
142+
143+
Days of the week that should be disabled. Values are 0 (Sunday) to 6 (Saturday). Multiple values should be comma-separated. Example: disable weekends: `'0,6'` or `[0,6]`.
144+
139145
### autoclose
140146

141147
Boolean. Default: false
@@ -172,6 +178,12 @@ String. Default: 'en'
172178

173179
The two-letter code of the language to use for month and day names. These will also be used as the input's value (and subsequently sent to the server in the case of form submissions). Currently ships with English ('en'), German ('de'), Brazilian ('br'), and Spanish ('es') translations, but others can be added (see I18N below). If an unknown language code is given, English will be used.
174180

181+
### forceParse
182+
183+
Boolean. Default: true
184+
185+
Whether or not to force parsing of the input value when the picker is closed. That is, when an invalid date is left in the input field by the user, the picker will forcibly parse that value, and set the input's value to the new, valid date, conforming to the given `format`.
186+
175187
## Markup
176188

177189
Format a component.
@@ -187,6 +199,15 @@ Format a component.
187199

188200
Initializes an datepicker.
189201

202+
### remove
203+
204+
Arguments: None
205+
206+
Remove the datepicker. Removes attached events, internal attached objects, and
207+
added HTML elements.
208+
209+
$('#datepicker').datepicker('remove');
210+
190211
### show
191212

192213
Arguments: None
@@ -241,6 +262,21 @@ Omit endDate (or provide an otherwise falsey value) to unset the limit.
241262
$('#datepicker').datepicker('setEndDate');
242263
$('#datepicker').datepicker('setEndDate', null);
243264

265+
### setDaysOfWeekDisabled
266+
267+
Arguments:
268+
269+
* daysOfWeekDisabled (String|Array)
270+
271+
Sets the days of week that should be disabled.
272+
273+
$('#datepicker').datepicker('setDaysOfWeekDisabled', [0,6]);
274+
275+
Omit daysOfWeekDisabled (or provide an otherwise falsey value) to unset the disabled days.
276+
277+
$('#datepicker').datepicker('setDaysOfWeekDisabled');
278+
$('#datepicker').datepicker('setDaysOfWeekDisabled', null);
279+
244280
## Events
245281

246282
Datepicker class exposes a few events for manipulating the dates.

js/backends/bootstrap-datepicker.default.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383
val, filtered, part;
8484
setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
8585
setters_map['dd'] = setters_map['d'];
86-
date = UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), 0, 0, 0);
86+
date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
8787
if (parts.length == format.parts.length) {
8888
for (var i=0, cnt = format.parts.length; i < cnt; i++) {
8989
val = parseInt(parts[i], 10);

js/bootstrap-datepicker.js

Lines changed: 103 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -48,25 +48,13 @@
4848
if(this.component && this.component.length === 0)
4949
this.component = false;
5050

51-
if (this.isInput) {
52-
this.element.on({
53-
focus: $.proxy(this.show, this),
54-
keyup: $.proxy(this.update, this),
55-
keydown: $.proxy(this.keydown, this)
56-
});
57-
} else {
58-
if (this.component && this.hasInput){
59-
// For components that are not readonly, allow keyboard nav
60-
this.element.find('input').on({
61-
focus: $.proxy(this.show, this),
62-
keyup: $.proxy(this.update, this),
63-
keydown: $.proxy(this.keydown, this)
64-
});
51+
this._attachEvents();
6552

66-
this.component.on('click', $.proxy(this.show, this));
67-
} else {
68-
this.element.on('click', $.proxy(this.show, this));
69-
}
53+
this.forceParse = true;
54+
if ('forceParse' in options) {
55+
this.forceParse = options.forceParse;
56+
} else if ('dateForceParse' in this.element.data()) {
57+
this.forceParse = this.element.data('date-force-parse');
7058
}
7159

7260
$(document).on('mousedown', function (e) {
@@ -113,8 +101,10 @@
113101
this.weekEnd = ((this.weekStart + 6) % 7);
114102
this.startDate = -Infinity;
115103
this.endDate = Infinity;
104+
this.daysOfWeekDisabled = [];
116105
this.setStartDate(options.startDate||this.element.data('date-startdate'));
117106
this.setEndDate(options.endDate||this.element.data('date-enddate'));
107+
this.setDaysOfWeekDisabled(options.daysOfWeekDisabled||this.element.data('date-days-of-week-disabled'));
118108
this.fillDow();
119109
this.fillMonths();
120110
this.update();
@@ -124,6 +114,53 @@
124114
Datepicker.prototype = {
125115
constructor: Datepicker,
126116

117+
_events: [],
118+
_attachEvents: function(){
119+
this._detachEvents();
120+
if (this.isInput) {
121+
this._events = [
122+
[this.element, {
123+
focus: $.proxy(this.show, this),
124+
keyup: $.proxy(this.update, this),
125+
keydown: $.proxy(this.keydown, this)
126+
}]
127+
];
128+
}
129+
else if (this.component && this.hasInput){
130+
this._events = [
131+
// For components that are not readonly, allow keyboard nav
132+
[this.element.find('input'), {
133+
focus: $.proxy(this.show, this),
134+
keyup: $.proxy(this.update, this),
135+
keydown: $.proxy(this.keydown, this)
136+
}],
137+
[this.component, {
138+
click: $.proxy(this.show, this)
139+
}]
140+
];
141+
}
142+
else {
143+
this._events = [
144+
[this.element, {
145+
click: $.proxy(this.show, this)
146+
}]
147+
];
148+
}
149+
for (var i=0, el, ev; i<this._events.length; i++){
150+
el = this._events[i][0];
151+
ev = this._events[i][1];
152+
el.on(ev);
153+
}
154+
},
155+
_detachEvents: function(){
156+
for (var i=0, el, ev; i<this._events.length; i++){
157+
el = this._events[i][0];
158+
ev = this._events[i][1];
159+
el.off(ev);
160+
}
161+
this._events = [];
162+
},
163+
127164
show: function(e) {
128165
this.picker.show();
129166
this.height = this.component ? this.component.outerHeight() : this.element.outerHeight();
@@ -148,14 +185,45 @@
148185
if (!this.isInput) {
149186
$(document).off('mousedown', this.hide);
150187
}
151-
if (e && e.currentTarget.value)
188+
189+
if (
190+
this.forceParse &&
191+
(
192+
this.isInput && this.element.val() ||
193+
this.hasInput && this.element.find('input').val()
194+
)
195+
)
152196
this.setValue();
153197
this.element.trigger({
154198
type: 'hide',
155199
date: this.date
156200
});
157201
},
158202

203+
remove: function() {
204+
this._detachEvents();
205+
this.picker.remove();
206+
delete this.element.data().datepicker;
207+
},
208+
209+
getDate: function() {
210+
var d = this.getUTCDate();
211+
return new Date(d.getTime() + (d.getTimezoneOffset()*60000))
212+
},
213+
214+
getUTCDate: function() {
215+
return this.date;
216+
},
217+
218+
setDate: function(d) {
219+
this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
220+
},
221+
222+
setUTCDate: function(d) {
223+
this.date = d;
224+
this.setValue();
225+
},
226+
159227
setValue: function() {
160228
var formatted = DPGlobal.formatDate(this.date, this.format, this.language);
161229
if (!this.isInput) {
@@ -186,6 +254,18 @@
186254
this.updateNavArrows();
187255
},
188256

257+
setDaysOfWeekDisabled: function(daysOfWeekDisabled){
258+
this.daysOfWeekDisabled = daysOfWeekDisabled||[];
259+
if (!$.isArray(this.daysOfWeekDisabled)) {
260+
this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
261+
}
262+
this.daysOfWeekDisabled = $.map(this.daysOfWeekDisabled, function (d) {
263+
return parseInt(d, 10);
264+
});
265+
this.update();
266+
this.updateNavArrows();
267+
},
268+
189269
place: function(){
190270
var zIndex = parseInt(this.element.parents().filter(function() {
191271
return $(this).css('z-index') != 'auto';
@@ -248,7 +328,7 @@
248328
.text(DPGlobal.getMonths(this.language)[month]+' '+year);
249329
this.picker.find('tfoot th.today')
250330
.text(dates[this.language].today)
251-
.toggle(this.todayBtn);
331+
.toggle(this.todayBtn !== false);
252332
this.updateNavArrows();
253333
this.fillMonths();
254334
var prevMonth = UTCDate(year, month-1, 28,0,0,0,0),
@@ -280,7 +360,8 @@
280360
if (prevMonth.valueOf() == currentDate) {
281361
clsName += ' active';
282362
}
283-
if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate) {
363+
if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
364+
$.inArray(prevMonth.getUTCDay(), this.daysOfWeekDisabled) !== -1) {
284365
clsName += ' disabled';
285366
}
286367
html.push('<td class="day'+clsName+'">'+prevMonth.getUTCDate() + '</td>');
@@ -646,6 +727,7 @@
646727

647728
var headTemplate =
648729
'<thead>'+
730+
649731
'<tr>'+
650732
'<th class="prev"><i class="icon-arrow-left"/></th>'+
651733
'<th colspan="5" class="switch"></th>'+

js/locales/bootstrap-datepicker.bg.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* Bulgarian translation for bootstrap-datepicker
3+
* Apostol Apostolov <apostol.s.apostolov@gmail.com>
4+
*/
5+
;(function($){
6+
$.fn.datepicker.dates['bg'] = {
7+
days: ["Неделя", "Понеделник", "Вторник", "Сряда", "Четвъртък", "Петък", "Събота", "Неделя"],
8+
daysShort: ["Нед", "Пон", "Вто", "Сря", "Чет", "Пет", "Съб", "Нед"],
9+
daysMin: ["Н", "П", "В", "С", "Ч", "П", "С", "Н"],
10+
months: ["Януари", "Февруари", "Март", "Април", "Май", "Юни", "Юли", "Август", "Септември", "Октомври", "Ноември", "Декември"],
11+
monthsShort: ["Ян", "Фев", "Мар", "Апр", "Май", "Юни", "Юли", "Авг", "Сеп", "Окт", "Ное", "Дек"],
12+
today: "днес"
13+
};
14+
}(jQuery));

js/locales/bootstrap-datepicker.kr.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@
88
daysShort: ["일", "월", "화", "수", "목", "금", "토", "일"],
99
daysMin: ["일", "월", "화", "수", "목", "금", "토", "일"],
1010
months: ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"],
11-
monthsShort: ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"],
11+
monthsShort: ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"]
1212
};
1313
}(jQuery));

js/locales/bootstrap-datepicker.ms.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
daysShort: ["Aha", "Isn", "Sel", "Rab", "Kha", "Jum", "Sab", "Aha"],
99
daysMin: ["Ah", "Is", "Se", "Ra", "Kh", "Ju", "Sa", "Ah"],
1010
months: ["Januari", "Februari", "Mac", "April", "Mei", "Jun", "Julai", "Ogos", "September", "Oktober", "November", "Disember"],
11-
monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Ogo", "Sep", "Okt", "Nov", "Dis"]
11+
monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Ogo", "Sep", "Okt", "Nov", "Dis"],
1212
today: "Hari Ini"
1313
};
1414
}(jQuery));

js/locales/bootstrap-datepicker.ro.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**
2+
* Romanian translation for bootstrap-datepicker
3+
* Cristian Vasile <cristi.mie@gmail.com>
4+
*/
5+
;(function($){
6+
$.fn.datepicker.dates['ro'] = {
7+
days: ["Duminică", "Luni", "Marţi", "Miercuri", "Joi", "Vineri", "Sâmbătă", "Duminică"],
8+
daysShort: ["Dum", "Lun", "Mar", "Mie", "Joi", "Vin", "Sâm", "Dum"],
9+
daysMin: ["Du", "Lu", "Ma", "Mi", "Jo", "Vi", "Sâ", "Du"],
10+
months: ["Ianuarie", "Februarie", "Martie", "Aprilie", "Mai", "Iunie", "Iulie", "August", "Septembrie", "Octombrie", "Noiembrie", "Decembrie"],
11+
monthsShort: ["Ian", "Feb", "Mar", "Apr", "Mai", "Iun", "Iul", "Aug", "Sep", "Oct", "Nov", "Dec"],
12+
today: "Astăzi",
13+
weekStart: 1
14+
};
15+
}(jQuery));

js/locales/bootstrap-datepicker.sk.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* Slovak translation for bootstrap-datepicker
3+
* Marek Lichtner <marek@licht.sk>
4+
*/
5+
;(function($){
6+
$.fn.datepicker.dates["sk"] = {
7+
days: ["Nedeľa", "Pondelok", "Utorok", "Streda", "Štvrtok", "Piatok", "Sobota", "Nedeľa"],
8+
daysShort: ["Ne", "Po", "Ut", "St", "Št", "Pi", "So", "Ne"],
9+
daysMin: ["Ne", "Po", "Ut", "St", "Št", "Pi", "So", "Ne"],
10+
months: ["Január", "Február", "Marec", "Apríl", "Máj", "Jún", "Júl", "August", "September", "Október", "November", "December"],
11+
monthsShort: ["Jan", "Feb", "Mar", "Apr", "Máj", "Jún", "Júl", "Aug", "Sep", "Okt", "Nov", "Dec"],
12+
today: "Dnes"
13+
};
14+
}(jQuery));

js/locales/bootstrap-datepicker.sl.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* Slovene translation for bootstrap-datepicker
3+
* Gregor Rudolf <gregor.rudolf@gmail.com>
4+
*/
5+
;(function($){
6+
$.fn.datepicker.dates['sl'] = {
7+
days: ["Nedelja", "Ponedeljek", "Torek", "Sreda", "Četrtek", "Petek", "Sobota", "Nedelja"],
8+
daysShort: ["Ned", "Pon", "Tor", "Sre", "Čet", "Pet", "Sob", "Ned"],
9+
daysMin: ["Ne", "Po", "To", "Sr", "Če", "Pe", "So", "Ne"],
10+
months: ["Januar", "Februar", "Marec", "April", "Maj", "Junij", "Julij", "Avgust", "September", "Oktober", "November", "December"],
11+
monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Avg", "Sep", "Okt", "Nov", "Dec"],
12+
today: "Danes"
13+
};
14+
}(jQuery));

tests/suites/formats.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,3 +193,18 @@ test('Regression: End-of-month bug', patch_date(function(Date){
193193
.datepicker('setValue');
194194
equal(this.input.val(), '29-02-2012');
195195
}));
196+
197+
test('Invalid formats are force-parsed into a valid date on tab', patch_date(function(Date){
198+
Date.now = UTCDate(2012, 4, 31);
199+
this.input
200+
.val('44-44-4444')
201+
.datepicker({format: 'yyyy-MM-dd'})
202+
.focus();
203+
204+
this.input.trigger({
205+
type: 'keydown',
206+
keyCode: 9
207+
});
208+
209+
equal(this.input.val(), '56-September-30');
210+
}));

tests/suites/keyboard_navigation/all.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ test('TAB hides picker', function(){
1616
var target;
1717

1818
ok(this.picker.is(':visible'), 'Picker is visible');
19-
19+
2020
this.input.trigger({
2121
type: 'keydown',
2222
keyCode: 9

tests/suites/mouse_navigation/all.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,21 @@ module('Mouse Navigation (All)', {
1313
});
1414

1515
test('Clicking datepicker does not hide datepicker', function(){
16-
ok(this.picker.is(':visible'), 'Picker is visible');
16+
ok(this.picker.is(':visible'), 'Picker is visible');
1717
this.picker.trigger('mousedown');
1818
ok(this.picker.is(':visible'), 'Picker is still visible');
1919
});
2020

21-
test('Clicking outside datepicker hides datepicker', function(){
21+
test('Clicking outside datepicker hides datepicker', function(){
2222
var $otherelement = $('<div />');
23-
$('body').append($otherelement);
23+
$('body').append($otherelement);
2424

25-
ok(this.picker.is(':visible'), 'Picker is visible');
26-
this.input.trigger('click');
27-
ok(this.picker.is(':visible'), 'Picker is still visible');
25+
ok(this.picker.is(':visible'), 'Picker is visible');
26+
this.input.trigger('click');
27+
ok(this.picker.is(':visible'), 'Picker is still visible');
2828

2929
$otherelement.trigger('mousedown');
3030
ok(this.picker.is(':not(:visible)'), 'Picker is hidden');
3131

3232
$otherelement.remove();
33-
});
33+
});

0 commit comments

Comments
 (0)