9 * @class Roo.bootstrap.MonthField
10 * @extends Roo.bootstrap.Input
11 * Bootstrap MonthField class
13 * @cfg {String} language default en
16 * Create a new MonthField
17 * @param {Object} config The config object
20 Roo.bootstrap.MonthField = function(config){
21 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
26 * Fires when this field show.
27 * @param {Roo.bootstrap.MonthField} this
28 * @param {Mixed} date The date value
33 * Fires when this field hide.
34 * @param {Roo.bootstrap.MonthField} this
35 * @param {Mixed} date The date value
40 * Fires when select a date.
41 * @param {Roo.bootstrap.MonthField} this
42 * @param {Mixed} date The date value
48 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
52 onRender: function(ct, position)
55 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
57 this.language = this.language || 'en';
58 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
59 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
61 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
62 this.format = this.format || 'F';
63 this.isInline = false;
65 this.component = this.el.select('.add-on', true).first() || false;
66 this.component = (this.component && this.component.length === 0) ? false : this.component;
67 this.hasInput = this.component && this.inputEL().length;
72 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
74 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
76 this.picker().on('mousedown', this.onMousedown, this);
77 this.picker().on('click', this.onClick, this);
79 this.picker().addClass('datepicker-dropdown');
81 this.startViewMode = this.viewMode;
83 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
84 v.setStyle('width', '189px');
100 var d = new Date(this.parseDate(v) ).clearTime();
102 if(isNaN(d.getTime())){
103 this.date = this.viewDate = '';
104 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
108 v = this.formatDate(d);
110 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
112 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
116 this.fireEvent('select', this, this.date);
125 var target = e.getTarget();
127 if(target.nodeName.toLowerCase() === 'i'){
128 target = Roo.get(target).dom.parentNode;
131 var nodeName = target.nodeName;
132 var className = target.className;
133 var html = target.innerHTML;
135 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
138 this.viewDate.setUTCDate(1);
139 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
141 this.setValue(this.formatDate(this.viewDate));
148 return this.pickerEl;
149 // return this.el.select('.datepicker', true).first();
152 fillMonths: function()
155 var months = this.picker().select('>.datepicker-months td', true).first();
157 months.dom.innerHTML = '';
163 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
166 months.createChild(month);
173 this.date = (typeof(this.date) === 'undefined' || ((typeof(this.date) === 'string') && !this.date.length)) ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
175 if (this.date < this.startDate) {
176 this.viewDate = new Date(this.startDate);
177 } else if (this.date > this.endDate) {
178 this.viewDate = new Date(this.endDate);
180 this.viewDate = new Date(this.date);
188 var d = new Date(this.viewDate),
189 year = d.getUTCFullYear(),
190 month = d.getUTCMonth(),
191 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
192 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
193 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
194 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
195 currentDate = this.date && this.date.valueOf(),
196 today = this.UTCToday();
198 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
200 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
202 // this.picker.select('>tfoot th.today').
203 // .text(dates[this.language].today)
204 // .toggle(this.todayBtn !== false);
206 this.updateNavArrows();
209 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
211 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
213 prevMonth.setUTCDate(day);
215 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
217 var nextMonth = new Date(prevMonth);
219 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
221 nextMonth = nextMonth.valueOf();
223 var fillMonths = false;
225 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
227 while(prevMonth.valueOf() < nextMonth) {
230 if (prevMonth.getUTCDay() === this.weekStart) {
232 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
240 if(this.calendarWeeks){
241 // ISO 8601: First week contains first thursday.
242 // ISO also states week starts on Monday, but we can be more abstract here.
244 // Start of current week: based on weekstart/current date
245 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
246 // Thursday of this week
247 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
248 // First Thursday of year, year from thursday
249 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
250 // Calendar week: ms between thursdays, div ms per day, div 7 days
251 calWeek = (th - yth) / 864e5 / 7 + 1;
261 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
263 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
266 if (this.todayHighlight &&
267 prevMonth.getUTCFullYear() == today.getFullYear() &&
268 prevMonth.getUTCMonth() == today.getMonth() &&
269 prevMonth.getUTCDate() == today.getDate()) {
273 if (currentDate && prevMonth.valueOf() === currentDate) {
274 clsName += ' active';
277 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
278 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
279 clsName += ' disabled';
284 cls: 'day ' + clsName,
285 html: prevMonth.getDate()
288 prevMonth.setDate(prevMonth.getDate()+1);
291 var currentYear = this.date && this.date.getUTCFullYear();
292 var currentMonth = this.date && this.date.getUTCMonth();
294 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
296 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
297 v.removeClass('active');
299 if(currentYear === year && k === currentMonth){
300 v.addClass('active');
303 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
304 v.addClass('disabled');
310 year = parseInt(year/10, 10) * 10;
312 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
314 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
317 for (var i = -1; i < 11; i++) {
318 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
320 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
328 showMode: function(dir)
331 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
334 Roo.each(this.picker().select('>div',true).elements, function(v){
335 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
338 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
343 if(this.isInline) return;
345 this.picker().removeClass(['bottom', 'top']);
347 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
349 * place to the top of element!
353 this.picker().addClass('top');
354 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
359 this.picker().addClass('bottom');
361 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
364 parseDate : function(value)
366 if(!value || value instanceof Date){
369 var v = Date.parseDate(value, this.format);
370 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
371 v = Date.parseDate(value, 'Y-m-d');
373 if(!v && this.altFormats){
374 if(!this.altFormatsArray){
375 this.altFormatsArray = this.altFormats.split("|");
377 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
378 v = Date.parseDate(value, this.altFormatsArray[i]);
384 formatDate : function(date, fmt)
386 return (!date || !(date instanceof Date)) ?
387 date : date.dateFormat(fmt || this.format);
392 Roo.bootstrap.DateField.superclass.onFocus.call(this);
398 Roo.bootstrap.DateField.superclass.onBlur.call(this);
400 var d = this.inputEl().getValue();
409 this.picker().show();
413 this.fireEvent('show', this, this.date);
418 if(this.isInline) return;
419 this.picker().hide();
420 this.viewMode = this.startViewMode;
423 this.fireEvent('hide', this, this.date);
427 onMousedown: function(e)
435 Roo.bootstrap.DateField.superclass.keyup.call(this);
441 return this.formatDate(this.date);
446 if (!this.picker().isVisible()){
447 if (e.keyCode == 27) // allow escape to hide and re-show picker
452 var dateChanged = false,
454 newDate, newViewDate;
463 if (!this.keyboardNavigation) break;
464 dir = e.keyCode == 37 ? -1 : 1;
467 newDate = this.moveYear(this.date, dir);
468 newViewDate = this.moveYear(this.viewDate, dir);
469 } else if (e.shiftKey){
470 newDate = this.moveMonth(this.date, dir);
471 newViewDate = this.moveMonth(this.viewDate, dir);
473 newDate = new Date(this.date);
474 newDate.setUTCDate(this.date.getUTCDate() + dir);
475 newViewDate = new Date(this.viewDate);
476 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
478 if (this.dateWithinRange(newDate)){
480 this.viewDate = newViewDate;
481 this.setValue(this.formatDate(this.date));
489 if (!this.keyboardNavigation) break;
490 dir = e.keyCode == 38 ? -1 : 1;
492 newDate = this.moveYear(this.date, dir);
493 newViewDate = this.moveYear(this.viewDate, dir);
494 } else if (e.shiftKey){
495 newDate = this.moveMonth(this.date, dir);
496 newViewDate = this.moveMonth(this.viewDate, dir);
498 newDate = new Date(this.date);
499 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
500 newViewDate = new Date(this.viewDate);
501 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
503 if (this.dateWithinRange(newDate)){
505 this.viewDate = newViewDate;
506 this.setValue(this.formatDate(this.date));
513 this.setValue(this.formatDate(this.date));
518 this.setValue(this.formatDate(this.date));
531 setStartDate: function(startDate)
533 this.startDate = startDate || -Infinity;
534 if (this.startDate !== -Infinity) {
535 this.startDate = this.parseDate(this.startDate);
538 this.updateNavArrows();
541 setEndDate: function(endDate)
543 this.endDate = endDate || Infinity;
544 if (this.endDate !== Infinity) {
545 this.endDate = this.parseDate(this.endDate);
548 this.updateNavArrows();
551 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
553 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
554 if (typeof(this.daysOfWeekDisabled) !== 'object') {
555 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
557 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
558 return parseInt(d, 10);
561 this.updateNavArrows();
564 updateNavArrows: function()
570 var d = new Date(this.viewDate),
571 year = d.getUTCFullYear(),
572 month = d.getUTCMonth();
574 Roo.each(this.picker().select('.prev', true).elements, function(v){
576 switch (this.viewMode) {
579 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
585 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
592 Roo.each(this.picker().select('.next', true).elements, function(v){
594 switch (this.viewMode) {
597 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
603 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
611 moveMonth: function(date, dir)
613 if (!dir) return date;
614 var new_date = new Date(date.valueOf()),
615 day = new_date.getUTCDate(),
616 month = new_date.getUTCMonth(),
619 dir = dir > 0 ? 1 : -1;
622 // If going back one month, make sure month is not current month
623 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
625 return new_date.getUTCMonth() == month;
627 // If going forward one month, make sure month is as expected
628 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
630 return new_date.getUTCMonth() != new_month;
632 new_month = month + dir;
633 new_date.setUTCMonth(new_month);
634 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
635 if (new_month < 0 || new_month > 11)
636 new_month = (new_month + 12) % 12;
638 // For magnitudes >1, move one month at a time...
639 for (var i=0; i<mag; i++)
640 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
641 new_date = this.moveMonth(new_date, dir);
642 // ...then reset the day, keeping it in the new month
643 new_month = new_date.getUTCMonth();
644 new_date.setUTCDate(day);
646 return new_month != new_date.getUTCMonth();
649 // Common date-resetting loop -- if date is beyond end of month, make it
652 new_date.setUTCDate(--day);
653 new_date.setUTCMonth(new_month);
658 moveYear: function(date, dir)
660 return this.moveMonth(date, dir*12);
663 dateWithinRange: function(date)
665 return date >= this.startDate && date <= this.endDate;
671 this.picker().remove();
676 Roo.apply(Roo.bootstrap.DateField, {
687 html: '<i class="fa fa-arrow-left"/>'
697 html: '<i class="fa fa-arrow-right"/>'
739 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
740 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
741 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
742 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
743 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
766 Roo.apply(Roo.bootstrap.DateField, {
770 cls: 'datepicker dropdown-menu roo-dynamic',
774 cls: 'datepicker-days',
778 cls: 'table-condensed',
780 Roo.bootstrap.DateField.head,
784 Roo.bootstrap.DateField.footer
791 cls: 'datepicker-months',
795 cls: 'table-condensed',
797 Roo.bootstrap.DateField.head,
798 Roo.bootstrap.DateField.content,
799 Roo.bootstrap.DateField.footer
806 cls: 'datepicker-years',
810 cls: 'table-condensed',
812 Roo.bootstrap.DateField.head,
813 Roo.bootstrap.DateField.content,
814 Roo.bootstrap.DateField.footer