Upgrade to ExtJS 3.0.3 - Released 10/11/2009
[extjs.git] / docs / source / DatePicker.html
1 <html>
2 <head>
3   <title>The source code</title>
4     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
5     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
6 </head>
7 <body  onload="prettyPrint();">
8     <pre class="prettyprint lang-js">/*!
9  * Ext JS Library 3.0.3
10  * Copyright(c) 2006-2009 Ext JS, LLC
11  * licensing@extjs.com
12  * http://www.extjs.com/license
13  */
14 <div id="cls-Ext.DatePicker"></div>/**\r
15  * @class Ext.DatePicker\r
16  * @extends Ext.Component\r
17  * Simple date picker class.\r
18  * @constructor\r
19  * Create a new DatePicker\r
20  * @param {Object} config The config object\r
21  * @xtype datepicker\r
22  */\r
23 Ext.DatePicker = Ext.extend(Ext.BoxComponent, {\r
24     <div id="cfg-Ext.DatePicker-todayText"></div>/**\r
25      * @cfg {String} todayText\r
26      * The text to display on the button that selects the current date (defaults to <tt>'Today'</tt>)\r
27      */\r
28     todayText : 'Today',\r
29     <div id="cfg-Ext.DatePicker-okText"></div>/**\r
30      * @cfg {String} okText\r
31      * The text to display on the ok button (defaults to <tt>'&#160;OK&#160;'</tt> to give the user extra clicking room)\r
32      */\r
33     okText : '&#160;OK&#160;',\r
34     <div id="cfg-Ext.DatePicker-cancelText"></div>/**\r
35      * @cfg {String} cancelText\r
36      * The text to display on the cancel button (defaults to <tt>'Cancel'</tt>)\r
37      */\r
38     cancelText : 'Cancel',\r
39     <div id="cfg-Ext.DatePicker-handler"></div>/**\r
40      * @cfg {Function} handler\r
41      * Optional. A function that will handle the select event of this picker.\r
42      * The handler is passed the following parameters:<div class="mdetail-params"><ul>\r
43      * <li><code>picker</code> : DatePicker<div class="sub-desc">The Ext.DatePicker.</div></li>\r
44      * <li><code>date</code> : Date<div class="sub-desc">The selected date.</div></li>\r
45      * </ul></div>\r
46      */\r
47     <div id="cfg-Ext.DatePicker-scope"></div>/**\r
48      * @cfg {Object} scope\r
49      * The scope (<tt><b>this</b></tt> reference) in which the <code>{@link #handler}</code>\r
50      * function will be called.  Defaults to this DatePicker instance.\r
51      */ \r
52     <div id="cfg-Ext.DatePicker-todayTip"></div>/**\r
53      * @cfg {String} todayTip\r
54      * The tooltip to display for the button that selects the current date (defaults to <tt>'{current date} (Spacebar)'</tt>)\r
55      */\r
56     todayTip : '{0} (Spacebar)',\r
57     <div id="cfg-Ext.DatePicker-minText"></div>/**\r
58      * @cfg {String} minText\r
59      * The error text to display if the minDate validation fails (defaults to <tt>'This date is before the minimum date'</tt>)\r
60      */\r
61     minText : 'This date is before the minimum date',\r
62     <div id="cfg-Ext.DatePicker-maxText"></div>/**\r
63      * @cfg {String} maxText\r
64      * The error text to display if the maxDate validation fails (defaults to <tt>'This date is after the maximum date'</tt>)\r
65      */\r
66     maxText : 'This date is after the maximum date',\r
67     <div id="cfg-Ext.DatePicker-format"></div>/**\r
68      * @cfg {String} format\r
69      * The default date format string which can be overriden for localization support.  The format must be\r
70      * valid according to {@link Date#parseDate} (defaults to <tt>'m/d/y'</tt>).\r
71      */\r
72     format : 'm/d/y',\r
73     <div id="cfg-Ext.DatePicker-disabledDaysText"></div>/**\r
74      * @cfg {String} disabledDaysText\r
75      * The tooltip to display when the date falls on a disabled day (defaults to <tt>'Disabled'</tt>)\r
76      */\r
77     disabledDaysText : 'Disabled',\r
78     <div id="cfg-Ext.DatePicker-disabledDatesText"></div>/**\r
79      * @cfg {String} disabledDatesText\r
80      * The tooltip text to display when the date falls on a disabled date (defaults to <tt>'Disabled'</tt>)\r
81      */\r
82     disabledDatesText : 'Disabled',\r
83     <div id="cfg-Ext.DatePicker-monthNames"></div>/**\r
84      * @cfg {Array} monthNames\r
85      * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)\r
86      */\r
87     monthNames : Date.monthNames,\r
88     <div id="cfg-Ext.DatePicker-dayNames"></div>/**\r
89      * @cfg {Array} dayNames\r
90      * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)\r
91      */\r
92     dayNames : Date.dayNames,\r
93     <div id="cfg-Ext.DatePicker-nextText"></div>/**\r
94      * @cfg {String} nextText\r
95      * The next month navigation button tooltip (defaults to <tt>'Next Month (Control+Right)'</tt>)\r
96      */\r
97     nextText : 'Next Month (Control+Right)',\r
98     <div id="cfg-Ext.DatePicker-prevText"></div>/**\r
99      * @cfg {String} prevText\r
100      * The previous month navigation button tooltip (defaults to <tt>'Previous Month (Control+Left)'</tt>)\r
101      */\r
102     prevText : 'Previous Month (Control+Left)',\r
103     <div id="cfg-Ext.DatePicker-monthYearText"></div>/**\r
104      * @cfg {String} monthYearText\r
105      * The header month selector tooltip (defaults to <tt>'Choose a month (Control+Up/Down to move years)'</tt>)\r
106      */\r
107     monthYearText : 'Choose a month (Control+Up/Down to move years)',\r
108     <div id="cfg-Ext.DatePicker-startDay"></div>/**\r
109      * @cfg {Number} startDay\r
110      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)\r
111      */\r
112     startDay : 0,\r
113     <div id="cfg-Ext.DatePicker-showToday"></div>/**\r
114      * @cfg {Boolean} showToday\r
115      * False to hide the footer area containing the Today button and disable the keyboard handler for spacebar\r
116      * that selects the current date (defaults to <tt>true</tt>).\r
117      */\r
118     showToday : true,\r
119     <div id="cfg-Ext.DatePicker-minDate"></div>/**\r
120      * @cfg {Date} minDate\r
121      * Minimum allowable date (JavaScript date object, defaults to null)\r
122      */\r
123     <div id="cfg-Ext.DatePicker-maxDate"></div>/**\r
124      * @cfg {Date} maxDate\r
125      * Maximum allowable date (JavaScript date object, defaults to null)\r
126      */\r
127     <div id="cfg-Ext.DatePicker-disabledDays"></div>/**\r
128      * @cfg {Array} disabledDays\r
129      * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).\r
130      */\r
131     <div id="cfg-Ext.DatePicker-disabledDatesRE"></div>/**\r
132      * @cfg {RegExp} disabledDatesRE\r
133      * JavaScript regular expression used to disable a pattern of dates (defaults to null).  The {@link #disabledDates}\r
134      * config will generate this regex internally, but if you specify disabledDatesRE it will take precedence over the\r
135      * disabledDates value.\r
136      */\r
137     <div id="cfg-Ext.DatePicker-disabledDates"></div>/**\r
138      * @cfg {Array} disabledDates\r
139      * An array of 'dates' to disable, as strings. These strings will be used to build a dynamic regular\r
140      * expression so they are very powerful. Some examples:\r
141      * <ul>\r
142      * <li>['03/08/2003', '09/16/2003'] would disable those exact dates</li>\r
143      * <li>['03/08', '09/16'] would disable those days for every year</li>\r
144      * <li>['^03/08'] would only match the beginning (useful if you are using short years)</li>\r
145      * <li>['03/../2006'] would disable every day in March 2006</li>\r
146      * <li>['^03'] would disable every day in every March</li>\r
147      * </ul>\r
148      * Note that the format of the dates included in the array should exactly match the {@link #format} config.\r
149      * In order to support regular expressions, if you are using a date format that has '.' in it, you will have to\r
150      * escape the dot when restricting dates. For example: ['03\\.08\\.03'].\r
151      */\r
152 \r
153     // private\r
154     initComponent : function(){\r
155         Ext.DatePicker.superclass.initComponent.call(this);\r
156 \r
157         this.value = this.value ?\r
158                  this.value.clearTime(true) : new Date().clearTime();\r
159 \r
160         this.addEvents(\r
161             <div id="event-Ext.DatePicker-select"></div>/**\r
162              * @event select\r
163              * Fires when a date is selected\r
164              * @param {DatePicker} this\r
165              * @param {Date} date The selected date\r
166              */\r
167             'select'\r
168         );\r
169 \r
170         if(this.handler){\r
171             this.on('select', this.handler,  this.scope || this);\r
172         }\r
173 \r
174         this.initDisabledDays();\r
175     },\r
176 \r
177     // private\r
178     initDisabledDays : function(){\r
179         if(!this.disabledDatesRE && this.disabledDates){\r
180             var dd = this.disabledDates,\r
181                 len = dd.length - 1,\r
182                 re = '(?:';\r
183                 \r
184             Ext.each(dd, function(d, i){\r
185                 re += Ext.isDate(d) ? '^' + Ext.escapeRe(d.dateFormat(this.format)) + '$' : dd[i];\r
186                 if(i != len){\r
187                     re += '|';\r
188                 }\r
189             }, this);\r
190             this.disabledDatesRE = new RegExp(re + ')');\r
191         }\r
192     },\r
193 \r
194     <div id="method-Ext.DatePicker-setDisabledDates"></div>/**\r
195      * Replaces any existing disabled dates with new values and refreshes the DatePicker.\r
196      * @param {Array/RegExp} disabledDates An array of date strings (see the {@link #disabledDates} config\r
197      * for details on supported values), or a JavaScript regular expression used to disable a pattern of dates.\r
198      */\r
199     setDisabledDates : function(dd){\r
200         if(Ext.isArray(dd)){\r
201             this.disabledDates = dd;\r
202             this.disabledDatesRE = null;\r
203         }else{\r
204             this.disabledDatesRE = dd;\r
205         }\r
206         this.initDisabledDays();\r
207         this.update(this.value, true);\r
208     },\r
209 \r
210     <div id="method-Ext.DatePicker-setDisabledDays"></div>/**\r
211      * Replaces any existing disabled days (by index, 0-6) with new values and refreshes the DatePicker.\r
212      * @param {Array} disabledDays An array of disabled day indexes. See the {@link #disabledDays} config\r
213      * for details on supported values.\r
214      */\r
215     setDisabledDays : function(dd){\r
216         this.disabledDays = dd;\r
217         this.update(this.value, true);\r
218     },\r
219 \r
220     <div id="method-Ext.DatePicker-setMinDate"></div>/**\r
221      * Replaces any existing {@link #minDate} with the new value and refreshes the DatePicker.\r
222      * @param {Date} value The minimum date that can be selected\r
223      */\r
224     setMinDate : function(dt){\r
225         this.minDate = dt;\r
226         this.update(this.value, true);\r
227     },\r
228 \r
229     <div id="method-Ext.DatePicker-setMaxDate"></div>/**\r
230      * Replaces any existing {@link #maxDate} with the new value and refreshes the DatePicker.\r
231      * @param {Date} value The maximum date that can be selected\r
232      */\r
233     setMaxDate : function(dt){\r
234         this.maxDate = dt;\r
235         this.update(this.value, true);\r
236     },\r
237 \r
238     <div id="method-Ext.DatePicker-setValue"></div>/**\r
239      * Sets the value of the date field\r
240      * @param {Date} value The date to set\r
241      */\r
242     setValue : function(value){\r
243         this.value = value.clearTime(true);\r
244         this.update(this.value);\r
245     },\r
246 \r
247     <div id="method-Ext.DatePicker-getValue"></div>/**\r
248      * Gets the current selected value of the date field\r
249      * @return {Date} The selected date\r
250      */\r
251     getValue : function(){\r
252         return this.value;\r
253     },\r
254 \r
255     // private\r
256     focus : function(){\r
257         this.update(this.activeDate);\r
258     },\r
259     \r
260     // private\r
261     onEnable: function(initial){\r
262         Ext.DatePicker.superclass.onEnable.call(this);    \r
263         this.doDisabled(false);\r
264         this.update(initial ? this.value : this.activeDate);\r
265         if(Ext.isIE){\r
266             this.el.repaint();\r
267         }\r
268         \r
269     },\r
270     \r
271     // private\r
272     onDisable : function(){\r
273         Ext.DatePicker.superclass.onDisable.call(this);   \r
274         this.doDisabled(true);\r
275         if(Ext.isIE && !Ext.isIE8){\r
276             /* Really strange problem in IE6/7, when disabled, have to explicitly\r
277              * repaint each of the nodes to get them to display correctly, simply\r
278              * calling repaint on the main element doesn't appear to be enough.\r
279              */\r
280              Ext.each([].concat(this.textNodes, this.el.query('th span')), function(el){\r
281                  Ext.fly(el).repaint();\r
282              });\r
283         }\r
284     },\r
285     \r
286     // private\r
287     doDisabled : function(disabled){\r
288         this.keyNav.setDisabled(disabled);\r
289         this.prevRepeater.setDisabled(disabled);\r
290         this.nextRepeater.setDisabled(disabled);\r
291         if(this.showToday){\r
292             this.todayKeyListener.setDisabled(disabled);\r
293             this.todayBtn.setDisabled(disabled);\r
294         }\r
295     },\r
296 \r
297     // private\r
298     onRender : function(container, position){\r
299         var m = [\r
300              '<table cellspacing="0">',\r
301                 '<tr><td class="x-date-left"><a href="#" title="', this.prevText ,'">&#160;</a></td><td class="x-date-middle" align="center"></td><td class="x-date-right"><a href="#" title="', this.nextText ,'">&#160;</a></td></tr>',\r
302                 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'],\r
303                 dn = this.dayNames,\r
304                 i;\r
305         for(i = 0; i < 7; i++){\r
306             var d = this.startDay+i;\r
307             if(d > 6){\r
308                 d = d-7;\r
309             }\r
310             m.push('<th><span>', dn[d].substr(0,1), '</span></th>');\r
311         }\r
312         m[m.length] = '</tr></thead><tbody><tr>';\r
313         for(i = 0; i < 42; i++) {\r
314             if(i % 7 === 0 && i !== 0){\r
315                 m[m.length] = '</tr><tr>';\r
316             }\r
317             m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';\r
318         }\r
319         m.push('</tr></tbody></table></td></tr>',\r
320                 this.showToday ? '<tr><td colspan="3" class="x-date-bottom" align="center"></td></tr>' : '',\r
321                 '</table><div class="x-date-mp"></div>');\r
322 \r
323         var el = document.createElement('div');\r
324         el.className = 'x-date-picker';\r
325         el.innerHTML = m.join('');\r
326 \r
327         container.dom.insertBefore(el, position);\r
328 \r
329         this.el = Ext.get(el);\r
330         this.eventEl = Ext.get(el.firstChild);\r
331 \r
332         this.prevRepeater = new Ext.util.ClickRepeater(this.el.child('td.x-date-left a'), {\r
333             handler: this.showPrevMonth,\r
334             scope: this,\r
335             preventDefault:true,\r
336             stopDefault:true\r
337         });\r
338 \r
339         this.nextRepeater = new Ext.util.ClickRepeater(this.el.child('td.x-date-right a'), {\r
340             handler: this.showNextMonth,\r
341             scope: this,\r
342             preventDefault:true,\r
343             stopDefault:true\r
344         });\r
345 \r
346         this.monthPicker = this.el.down('div.x-date-mp');\r
347         this.monthPicker.enableDisplayMode('block');\r
348 \r
349         this.keyNav = new Ext.KeyNav(this.eventEl, {\r
350             'left' : function(e){\r
351                 if(e.ctrlKey){\r
352                     this.showPrevMonth();\r
353                 }else{\r
354                     this.update(this.activeDate.add('d', -1));    \r
355                 }\r
356             },\r
357 \r
358             'right' : function(e){\r
359                 if(e.ctrlKey){\r
360                     this.showNextMonth();\r
361                 }else{\r
362                     this.update(this.activeDate.add('d', 1));    \r
363                 }\r
364             },\r
365 \r
366             'up' : function(e){\r
367                 if(e.ctrlKey){\r
368                     this.showNextYear();\r
369                 }else{\r
370                     this.update(this.activeDate.add('d', -7));\r
371                 }\r
372             },\r
373 \r
374             'down' : function(e){\r
375                 if(e.ctrlKey){\r
376                     this.showPrevYear();\r
377                 }else{\r
378                     this.update(this.activeDate.add('d', 7));\r
379                 }\r
380             },\r
381 \r
382             'pageUp' : function(e){\r
383                 this.showNextMonth();\r
384             },\r
385 \r
386             'pageDown' : function(e){\r
387                 this.showPrevMonth();\r
388             },\r
389 \r
390             'enter' : function(e){\r
391                 e.stopPropagation();\r
392                 return true;\r
393             },\r
394 \r
395             scope : this\r
396         });\r
397 \r
398         this.el.unselectable();\r
399 \r
400         this.cells = this.el.select('table.x-date-inner tbody td');\r
401         this.textNodes = this.el.query('table.x-date-inner tbody span');\r
402 \r
403         this.mbtn = new Ext.Button({\r
404             text: '&#160;',\r
405             tooltip: this.monthYearText,\r
406             renderTo: this.el.child('td.x-date-middle', true)\r
407         });\r
408         this.mbtn.el.child('em').addClass('x-btn-arrow');\r
409 \r
410         if(this.showToday){\r
411             this.todayKeyListener = this.eventEl.addKeyListener(Ext.EventObject.SPACE, this.selectToday,  this);\r
412             var today = (new Date()).dateFormat(this.format);\r
413             this.todayBtn = new Ext.Button({\r
414                 renderTo: this.el.child('td.x-date-bottom', true),\r
415                 text: String.format(this.todayText, today),\r
416                 tooltip: String.format(this.todayTip, today),\r
417                 handler: this.selectToday,\r
418                 scope: this\r
419             });\r
420         }\r
421         this.mon(this.eventEl, 'mousewheel', this.handleMouseWheel, this);\r
422         this.mon(this.eventEl, 'click', this.handleDateClick,  this, {delegate: 'a.x-date-date'});\r
423         this.mon(this.mbtn, 'click', this.showMonthPicker, this);\r
424         this.onEnable(true);\r
425     },\r
426 \r
427     // private\r
428     createMonthPicker : function(){\r
429         if(!this.monthPicker.dom.firstChild){\r
430             var buf = ['<table border="0" cellspacing="0">'];\r
431             for(var i = 0; i < 6; i++){\r
432                 buf.push(\r
433                     '<tr><td class="x-date-mp-month"><a href="#">', Date.getShortMonthName(i), '</a></td>',\r
434                     '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', Date.getShortMonthName(i + 6), '</a></td>',\r
435                     i === 0 ?\r
436                     '<td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-prev"></a></td><td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-next"></a></td></tr>' :\r
437                     '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'\r
438                 );\r
439             }\r
440             buf.push(\r
441                 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',\r
442                     this.okText,\r
443                     '</button><button type="button" class="x-date-mp-cancel">',\r
444                     this.cancelText,\r
445                     '</button></td></tr>',\r
446                 '</table>'\r
447             );\r
448             this.monthPicker.update(buf.join(''));\r
449 \r
450             this.mon(this.monthPicker, 'click', this.onMonthClick, this);\r
451             this.mon(this.monthPicker, 'dblclick', this.onMonthDblClick, this);\r
452 \r
453             this.mpMonths = this.monthPicker.select('td.x-date-mp-month');\r
454             this.mpYears = this.monthPicker.select('td.x-date-mp-year');\r
455 \r
456             this.mpMonths.each(function(m, a, i){\r
457                 i += 1;\r
458                 if((i%2) === 0){\r
459                     m.dom.xmonth = 5 + Math.round(i * 0.5);\r
460                 }else{\r
461                     m.dom.xmonth = Math.round((i-1) * 0.5);\r
462                 }\r
463             });\r
464         }\r
465     },\r
466 \r
467     // private\r
468     showMonthPicker : function(){\r
469         if(!this.disabled){\r
470             this.createMonthPicker();\r
471             var size = this.el.getSize();\r
472             this.monthPicker.setSize(size);\r
473             this.monthPicker.child('table').setSize(size);\r
474 \r
475             this.mpSelMonth = (this.activeDate || this.value).getMonth();\r
476             this.updateMPMonth(this.mpSelMonth);\r
477             this.mpSelYear = (this.activeDate || this.value).getFullYear();\r
478             this.updateMPYear(this.mpSelYear);\r
479 \r
480             this.monthPicker.slideIn('t', {duration:0.2});\r
481         }\r
482     },\r
483 \r
484     // private\r
485     updateMPYear : function(y){\r
486         this.mpyear = y;\r
487         var ys = this.mpYears.elements;\r
488         for(var i = 1; i <= 10; i++){\r
489             var td = ys[i-1], y2;\r
490             if((i%2) === 0){\r
491                 y2 = y + Math.round(i * 0.5);\r
492                 td.firstChild.innerHTML = y2;\r
493                 td.xyear = y2;\r
494             }else{\r
495                 y2 = y - (5-Math.round(i * 0.5));\r
496                 td.firstChild.innerHTML = y2;\r
497                 td.xyear = y2;\r
498             }\r
499             this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');\r
500         }\r
501     },\r
502 \r
503     // private\r
504     updateMPMonth : function(sm){\r
505         this.mpMonths.each(function(m, a, i){\r
506             m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');\r
507         });\r
508     },\r
509 \r
510     // private\r
511     selectMPMonth : function(m){\r
512 \r
513     },\r
514 \r
515     // private\r
516     onMonthClick : function(e, t){\r
517         e.stopEvent();\r
518         var el = new Ext.Element(t), pn;\r
519         if(el.is('button.x-date-mp-cancel')){\r
520             this.hideMonthPicker();\r
521         }\r
522         else if(el.is('button.x-date-mp-ok')){\r
523             var d = new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate());\r
524             if(d.getMonth() != this.mpSelMonth){\r
525                 // 'fix' the JS rolling date conversion if needed\r
526                 d = new Date(this.mpSelYear, this.mpSelMonth, 1).getLastDateOfMonth();\r
527             }\r
528             this.update(d);\r
529             this.hideMonthPicker();\r
530         }\r
531         else if((pn = el.up('td.x-date-mp-month', 2))){\r
532             this.mpMonths.removeClass('x-date-mp-sel');\r
533             pn.addClass('x-date-mp-sel');\r
534             this.mpSelMonth = pn.dom.xmonth;\r
535         }\r
536         else if((pn = el.up('td.x-date-mp-year', 2))){\r
537             this.mpYears.removeClass('x-date-mp-sel');\r
538             pn.addClass('x-date-mp-sel');\r
539             this.mpSelYear = pn.dom.xyear;\r
540         }\r
541         else if(el.is('a.x-date-mp-prev')){\r
542             this.updateMPYear(this.mpyear-10);\r
543         }\r
544         else if(el.is('a.x-date-mp-next')){\r
545             this.updateMPYear(this.mpyear+10);\r
546         }\r
547     },\r
548 \r
549     // private\r
550     onMonthDblClick : function(e, t){\r
551         e.stopEvent();\r
552         var el = new Ext.Element(t), pn;\r
553         if((pn = el.up('td.x-date-mp-month', 2))){\r
554             this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));\r
555             this.hideMonthPicker();\r
556         }\r
557         else if((pn = el.up('td.x-date-mp-year', 2))){\r
558             this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));\r
559             this.hideMonthPicker();\r
560         }\r
561     },\r
562 \r
563     // private\r
564     hideMonthPicker : function(disableAnim){\r
565         if(this.monthPicker){\r
566             if(disableAnim === true){\r
567                 this.monthPicker.hide();\r
568             }else{\r
569                 this.monthPicker.slideOut('t', {duration:0.2});\r
570             }\r
571         }\r
572     },\r
573 \r
574     // private\r
575     showPrevMonth : function(e){\r
576         this.update(this.activeDate.add('mo', -1));\r
577     },\r
578 \r
579     // private\r
580     showNextMonth : function(e){\r
581         this.update(this.activeDate.add('mo', 1));\r
582     },\r
583 \r
584     // private\r
585     showPrevYear : function(){\r
586         this.update(this.activeDate.add('y', -1));\r
587     },\r
588 \r
589     // private\r
590     showNextYear : function(){\r
591         this.update(this.activeDate.add('y', 1));\r
592     },\r
593 \r
594     // private\r
595     handleMouseWheel : function(e){\r
596         e.stopEvent();\r
597         if(!this.disabled){\r
598             var delta = e.getWheelDelta();\r
599             if(delta > 0){\r
600                 this.showPrevMonth();\r
601             } else if(delta < 0){\r
602                 this.showNextMonth();\r
603             }\r
604         }\r
605     },\r
606 \r
607     // private\r
608     handleDateClick : function(e, t){\r
609         e.stopEvent();\r
610         if(!this.disabled && t.dateValue && !Ext.fly(t.parentNode).hasClass('x-date-disabled')){\r
611             this.setValue(new Date(t.dateValue));\r
612             this.fireEvent('select', this, this.value);\r
613         }\r
614     },\r
615 \r
616     // private\r
617     selectToday : function(){\r
618         if(this.todayBtn && !this.todayBtn.disabled){\r
619             this.setValue(new Date().clearTime());\r
620             this.fireEvent('select', this, this.value);\r
621         }\r
622     },\r
623 \r
624     // private\r
625     update : function(date, forceRefresh){\r
626         if(this.rendered){\r
627                 var vd = this.activeDate, vis = this.isVisible();\r
628                 this.activeDate = date;\r
629                 if(!forceRefresh && vd && this.el){\r
630                     var t = date.getTime();\r
631                     if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){\r
632                         this.cells.removeClass('x-date-selected');\r
633                         this.cells.each(function(c){\r
634                            if(c.dom.firstChild.dateValue == t){\r
635                                c.addClass('x-date-selected');\r
636                                if(vis){\r
637                                    Ext.fly(c.dom.firstChild).focus(50);\r
638                                }\r
639                                return false;\r
640                            }\r
641                         });\r
642                         return;\r
643                     }\r
644                 }\r
645                 var days = date.getDaysInMonth(),\r
646                     firstOfMonth = date.getFirstDateOfMonth(),\r
647                     startingPos = firstOfMonth.getDay()-this.startDay;\r
648         \r
649                 if(startingPos < 0){\r
650                     startingPos += 7;\r
651                 }\r
652                 days += startingPos;\r
653         \r
654                 var pm = date.add('mo', -1),\r
655                     prevStart = pm.getDaysInMonth()-startingPos,\r
656                     cells = this.cells.elements,\r
657                     textEls = this.textNodes,\r
658                     // convert everything to numbers so it's fast\r
659                     day = 86400000,\r
660                     d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime(),\r
661                     today = new Date().clearTime().getTime(),\r
662                     sel = date.clearTime(true).getTime(),\r
663                     min = this.minDate ? this.minDate.clearTime(true) : Number.NEGATIVE_INFINITY,\r
664                     max = this.maxDate ? this.maxDate.clearTime(true) : Number.POSITIVE_INFINITY,\r
665                     ddMatch = this.disabledDatesRE,\r
666                     ddText = this.disabledDatesText,\r
667                     ddays = this.disabledDays ? this.disabledDays.join('') : false,\r
668                     ddaysText = this.disabledDaysText,\r
669                     format = this.format;\r
670         \r
671                 if(this.showToday){\r
672                     var td = new Date().clearTime(),\r
673                         disable = (td < min || td > max ||\r
674                         (ddMatch && format && ddMatch.test(td.dateFormat(format))) ||\r
675                         (ddays && ddays.indexOf(td.getDay()) != -1));\r
676         \r
677                     if(!this.disabled){\r
678                         this.todayBtn.setDisabled(disable);\r
679                         this.todayKeyListener[disable ? 'disable' : 'enable']();\r
680                     }\r
681                 }\r
682         \r
683                 var setCellClass = function(cal, cell){\r
684                     cell.title = '';\r
685                     var t = d.getTime();\r
686                     cell.firstChild.dateValue = t;\r
687                     if(t == today){\r
688                         cell.className += ' x-date-today';\r
689                         cell.title = cal.todayText;\r
690                     }\r
691                     if(t == sel){\r
692                         cell.className += ' x-date-selected';\r
693                         if(vis){\r
694                             Ext.fly(cell.firstChild).focus(50);\r
695                         }\r
696                     }\r
697                     // disabling\r
698                     if(t < min) {\r
699                         cell.className = ' x-date-disabled';\r
700                         cell.title = cal.minText;\r
701                         return;\r
702                     }\r
703                     if(t > max) {\r
704                         cell.className = ' x-date-disabled';\r
705                         cell.title = cal.maxText;\r
706                         return;\r
707                     }\r
708                     if(ddays){\r
709                         if(ddays.indexOf(d.getDay()) != -1){\r
710                             cell.title = ddaysText;\r
711                             cell.className = ' x-date-disabled';\r
712                         }\r
713                     }\r
714                     if(ddMatch && format){\r
715                         var fvalue = d.dateFormat(format);\r
716                         if(ddMatch.test(fvalue)){\r
717                             cell.title = ddText.replace('%0', fvalue);\r
718                             cell.className = ' x-date-disabled';\r
719                         }\r
720                     }\r
721                 };\r
722         \r
723                 var i = 0;\r
724                 for(; i < startingPos; i++) {\r
725                     textEls[i].innerHTML = (++prevStart);\r
726                     d.setDate(d.getDate()+1);\r
727                     cells[i].className = 'x-date-prevday';\r
728                     setCellClass(this, cells[i]);\r
729                 }\r
730                 for(; i < days; i++){\r
731                     var intDay = i - startingPos + 1;\r
732                     textEls[i].innerHTML = (intDay);\r
733                     d.setDate(d.getDate()+1);\r
734                     cells[i].className = 'x-date-active';\r
735                     setCellClass(this, cells[i]);\r
736                 }\r
737                 var extraDays = 0;\r
738                 for(; i < 42; i++) {\r
739                      textEls[i].innerHTML = (++extraDays);\r
740                      d.setDate(d.getDate()+1);\r
741                      cells[i].className = 'x-date-nextday';\r
742                      setCellClass(this, cells[i]);\r
743                 }\r
744         \r
745                 this.mbtn.setText(this.monthNames[date.getMonth()] + ' ' + date.getFullYear());\r
746         \r
747                 if(!this.internalRender){\r
748                     var main = this.el.dom.firstChild,\r
749                         w = main.offsetWidth;\r
750                     this.el.setWidth(w + this.el.getBorderWidth('lr'));\r
751                     Ext.fly(main).setWidth(w);\r
752                     this.internalRender = true;\r
753                     // opera does not respect the auto grow header center column\r
754                     // then, after it gets a width opera refuses to recalculate\r
755                     // without a second pass\r
756                     if(Ext.isOpera && !this.secondPass){\r
757                         main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + 'px';\r
758                         this.secondPass = true;\r
759                         this.update.defer(10, this, [date]);\r
760                     }\r
761                 }\r
762         }\r
763     },\r
764 \r
765     // private\r
766     beforeDestroy : function() {\r
767         if(this.rendered){\r
768             this.keyNav.disable();\r
769             this.keyNav = null;\r
770             Ext.destroy(\r
771                 this.leftClickRpt,\r
772                 this.rightClickRpt,\r
773                 this.monthPicker,\r
774                 this.eventEl,\r
775                 this.mbtn,\r
776                 this.todayBtn\r
777             );\r
778         }\r
779     }\r
780 \r
781     <div id="cfg-Ext.DatePicker-autoEl"></div>/**\r
782      * @cfg {String} autoEl @hide\r
783      */\r
784 });\r
785 \r
786 Ext.reg('datepicker', Ext.DatePicker);\r
787 </pre>
788 </body>
789 </html>