-
8 Jan 2008 3:34 AM #1
extension datepicker-range (day/week/month)
extension datepicker-range (day/week/month)
Hi,
Here is a datepicker with support for selecting a single day, week or month.
Its an extension of the datepicker but now you can set a selection mode ('day', 'week', 'month').
Hope it is useful for someoneCode:Ext.namespace('Ext.ux'); Date.prototype.getFirstDateOfWeek = function(){ var value=this.clearTime(); var semana=this.getWeekOfYear(); while(semana == value.getWeekOfYear()) value=value.add(Date.DAY,-1); value=value.add(Date.DAY,1); return value; } Ext.ux.DatePickerRange = Ext.extend(Ext.DatePicker, { selectionMode:'month', setSelectionMode:function(mode){ this.selectionMode=mode; this.setValue(this.value); }, getSelectionMode:function(){ return this.selectionMode(); }, //private update : function(date){ var vd = this.activeDate; this.activeDate = date; if(vd && this.el){ var t = date.getTime(); if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){ this.cells.removeClass("x-date-selected"); this.cells.each(function(c){ if(this.isSelected( c.dom.firstChild.dateValue )){ c.addClass("x-date-selected"); } },this); return; } } var days = date.getDaysInMonth(); var firstOfMonth = date.getFirstDateOfMonth(); var startingPos = firstOfMonth.getDay()-this.startDay; if(startingPos <= this.startDay){ startingPos += 7; } var pm = date.add("mo", -1); var prevStart = pm.getDaysInMonth()-startingPos; var cells = this.cells.elements; var textEls = this.textNodes; days += startingPos; var day = 86400000; var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime(); var today = new Date().clearTime().getTime(); var sel = date.clearTime().getTime(); var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY; var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY; var ddMatch = this.disabledDatesRE; var ddText = this.disabledDatesText; var ddays = this.disabledDays ? this.disabledDays.join("") : false; var ddaysText = this.disabledDaysText; var format = this.format; var setCellClass = function(cal, cell){ cell.title = ""; var t = d.getTime(); cell.firstChild.dateValue = t; if(t == today){ cell.className += " x-date-today"; cell.title = cal.todayText; } if(cal.isSelected(cell.firstChild.dateValue)){ cell.className += " x-date-selected"; } if(t < min) { cell.className = " x-date-disabled"; cell.title = cal.minText; return; } if(t > max) { cell.className = " x-date-disabled"; cell.title = cal.maxText; return; } if(ddays){ if(ddays.indexOf(d.getDay()) != -1){ cell.title = ddaysText; cell.className = " x-date-disabled"; } } if(ddMatch && format){ var fvalue = d.dateFormat(format); if(ddMatch.test(fvalue)){ cell.title = ddText.replace("%0", fvalue); cell.className = " x-date-disabled"; } } }; var i = 0; for(; i < startingPos; i++) { textEls[i].innerHTML = (++prevStart); d.setDate(d.getDate()+1); cells[i].className = "x-date-prevday"; setCellClass(this, cells[i]); } for(; i < days; i++){ intDay = i - startingPos + 1; textEls[i].innerHTML = (intDay); d.setDate(d.getDate()+1); cells[i].className = "x-date-active"; setCellClass(this, cells[i]); } var extraDays = 0; for(; i < 42; i++) { textEls[i].innerHTML = (++extraDays); d.setDate(d.getDate()+1); cells[i].className = "x-date-nextday"; setCellClass(this, cells[i]); } this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear()); if(!this.internalRender){ var main = this.el.dom.firstChild; var w = main.offsetWidth; this.el.setWidth(w + this.el.getBorderWidth("lr")); Ext.fly(main).setWidth(w); this.internalRender = true; if(Ext.isOpera && !this.secondPass){ main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px"; this.secondPass = true; this.update.defer(10, this, [date]); } } }, isSelected:function(date){ date=new Date(date); if(this.selectionMode=='day') return date.clearTime()==this.value.clearTime(); if(this.selectionMode=='month') return date.getFirstDateOfMonth().clearTime().getTime ()==this.value.getFirstDateOfMonth().clearTime().getTime (); if(this.selectionMode=='week'){ return date.getFirstDateOfWeek().clearTime().getTime ()==this.value.getFirstDateOfWeek().clearTime().getTime (); } throw 'Illegal selection mode'; } }); Ext.reg('datepickerrange', Ext.ux.DatePickerRange);
Last edited by cocorossello; 8 Jan 2008 at 7:01 AM. Reason: A little bit nicer code
-
9 Jan 2008 2:14 AM #2
Nice, thank you !
-
15 Jan 2008 4:49 AM #3
Thanx for this extension. I use it in a calendar application. I found a small bug:
When in selectionMode == 'day' the chosen day isn't selected. Fixed when you change this line of code:
into this one:Code:return date.clearTime() == this.value.clearTime();
Code:return date.clearTime().getTime() == this.value.clearTime().getTime();
-
15 Jan 2008 10:52 AM #4
Thx esteven, i forgot that one.
I am doing a calendar application too :P
-
16 Jan 2008 7:10 AM #5
I extended your extension: When you hold the shiftkey you can select more days or weeks. In my project it wasn't necessary to select more than one month, but it is easy to add this functionality.
There is an public var "amount" which is set. When you select 1 day or week the amount is 1. If you select 2 days or weeks the amount is 2 etc. Simple
Also the fireEvent sends this extra amount parameter.
Here's the code:
Any comments are welcomeCode:Ext.namespace('Ext.ux'); Date.prototype.getFirstDateOfWeek = function(){ var value = this.clone(); var dayOfWeek = this.getDay(); dayOfWeek = (dayOfWeek + 6) % 7; value.setDate(value.getDate() - dayOfWeek); return value; } Ext.ux.DatePickerRange = Ext.extend(Ext.DatePicker, { selectionMode:'month', amount: 1, setSelectionMode:function(mode){ this.selectionMode=mode; this.setValue(this.value); }, getSelectionMode:function(){ return this.selectionMode(); }, // private handleDateClick : function(e, t){ e.stopEvent(); if(t.dateValue && !Ext.fly(t.parentNode).hasClass("x-date-disabled")){ if (Ext.EventObject.shiftKey) { if (t.dateValue && t.dateValue >= this.activeDate) { var d = new Date(t.dateValue); var DAY = 86400000; if(this.selectionMode=='day') { this.amount = ((d.getTime() - this.activeDate.getTime()) / DAY) + 1; //if(this.selectionMode=='month') // this.amount = 1; } else if(this.selectionMode=='week'){ var days = d.getFirstDateOfWeek().getTime() - this.activeDate.getFirstDateOfWeek().getTime() + DAY; this.amount = Math.ceil(days / (DAY * 7)); } this.setValue(new Date(this.value)); } } else { this.amount = 1; this.setValue(new Date(t.dateValue)); } this.fireEvent("select", this, this.value, this.amount); } }, //private update : function(date){ var vd = this.activeDate; this.activeDate = date; if(vd && this.el){ var t = date.getTime(); if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){ this.cells.removeClass("x-date-selected"); this.cells.each(function(c){ if(this.isSelected( c.dom.firstChild.dateValue )){ c.addClass("x-date-selected"); } },this); return; } } var days = date.getDaysInMonth(); var firstOfMonth = date.getFirstDateOfMonth(); var startingPos = firstOfMonth.getDay()-this.startDay; if(startingPos <= this.startDay){ startingPos += 7; } var pm = date.add("mo", -1); var prevStart = pm.getDaysInMonth()-startingPos; var cells = this.cells.elements; var textEls = this.textNodes; days += startingPos; var day = 86400000; var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime(); var today = new Date().clearTime().getTime(); var sel = date.clearTime().getTime(); var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY; var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY; var ddMatch = this.disabledDatesRE; var ddText = this.disabledDatesText; var ddays = this.disabledDays ? this.disabledDays.join("") : false; var ddaysText = this.disabledDaysText; var format = this.format; var setCellClass = function(cal, cell){ cell.title = ""; var t = d.getTime(); cell.firstChild.dateValue = t; if(t == today){ cell.className += " x-date-today"; cell.title = cal.todayText; } if(cal.isSelected(cell.firstChild.dateValue)){ cell.className += " x-date-selected"; } if(t < min) { cell.className = " x-date-disabled"; cell.title = cal.minText; return; } if(t > max) { cell.className = " x-date-disabled"; cell.title = cal.maxText; return; } if(ddays){ if(ddays.indexOf(d.getDay()) != -1){ cell.title = ddaysText; cell.className = " x-date-disabled"; } } if(ddMatch && format){ var fvalue = d.dateFormat(format); if(ddMatch.test(fvalue)){ cell.title = ddText.replace("%0", fvalue); cell.className = " x-date-disabled"; } } }; var i = 0; for(; i < startingPos; i++) { textEls[i].innerHTML = (++prevStart); d.setDate(d.getDate()+1); cells[i].className = "x-date-prevday"; setCellClass(this, cells[i]); } for(; i < days; i++){ intDay = i - startingPos + 1; textEls[i].innerHTML = (intDay); d.setDate(d.getDate()+1); cells[i].className = "x-date-active"; setCellClass(this, cells[i]); } var extraDays = 0; for(; i < 42; i++) { textEls[i].innerHTML = (++extraDays); d.setDate(d.getDate()+1); cells[i].className = "x-date-nextday"; setCellClass(this, cells[i]); } this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear()); if(!this.internalRender){ var main = this.el.dom.firstChild; var w = main.offsetWidth; this.el.setWidth(w + this.el.getBorderWidth("lr")); Ext.fly(main).setWidth(w); this.internalRender = true; if(Ext.isOpera && !this.secondPass){ main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px"; this.secondPass = true; this.update.defer(10, this, [date]); } } }, isSelected:function(date){ // date to test date=new Date(date).clearTime(); // activeDate ad = new Date(this.value).clearTime(); var DAY = 86400000; if(this.selectionMode=='day') { date = date.getTime() for (var i=0; i<this.amount;++i) { if (date == ad.add(Date.DAY,i).getTime()) return true; } return false; } if(this.selectionMode=='month') return date.getFirstDateOfMonth().getTime() == this.value.getFirstDateOfMonth().getTime(); if(this.selectionMode=='week'){ var refTime = date.getFirstDateOfWeek().getTime(); var ad = ad.getFirstDateOfWeek(); if (refTime == ad.getTime()) return true; for (var i=1; i<this.amount;++i) { ad.setDate(ad.getDate() + 7); if (refTime == ad.getTime()) return true; } return false; } throw 'Illegal selection mode'; } }); Ext.reg('datepickerrange', Ext.ux.DatePickerRange);
Last edited by stevenvegt; 18 Jan 2008 at 5:17 AM. Reason: less elegant, but much faster code
-
17 Jan 2008 6:45 PM #6
Excellent!
Excellent!
Excellent work guys!
Just one question (and I really hope that it isnt an obvious answer that I missed), how do I programatically select a date range?
Hopefully Im not the only one needing to do that..
-
18 Jan 2008 12:11 AM #7
Just set the value. If it's a week or month selection, it will tear your value to the beginning of the week/month,
Code:mydatepicker.setSelectionMode('week'); mydatepicker.setValue(new Date());
-
18 Jan 2008 12:31 AM #8
-
18 Jan 2008 2:14 AM #9
Use steven's version, he already did that
I guess you'll have to make do some modifications for your application
-
18 Jan 2008 5:15 AM #10
You can do this by setting the amount to 7 and set the date value of the picker to the 3rd.
For instance:
Code:picker.amount = 7; picker.setValue(new Date())
I optimized the getFirstDateOfWeek method, it was a bit slow.
Code:Date.prototype.getFirstDateOfWeek = function(){ var value = this.clone(); var dayOfWeek = this.getDay(); dayOfWeek = (dayOfWeek + 6) % 7; value.setDate(value.getDate() - dayOfWeek); return value; }


Reply With Quote