DatePicker.js
上传用户:shuoshiled
上传日期:2018-01-28
资源大小:10124k
文件大小:27k
源码类别:

中间件编程

开发平台:

JavaScript

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