1. #1

    Default DatePicker.js (misc)

    DatePicker.js (misc)


    Some bugs, some features. This is more just a FYI for anyone looking to implement it (I've got an example posted at http://www.yui-ext.com/forum/viewtopic.php?p=6327).

    I'm hoping to submit a revised version of DatePicker.js in two weeks when I've had a chance to sit down and work on it.

    Right now the DatePicker constructer accepts a parentElement, but doesen't actually use it. Since it's a pop-up this isn't a big deal, but if you want to use it as an inline calendar (not a pop-up) this won't work. Also constrainXY wasn't working properly if you were positioning the calendar relative to a link at the bottom of a long scrolled page, where it would be offscreen.

    Purely for reference here is the code I use in my apps to instantiate a pop-up calendar, and optionally an inline calendar. It's really hacky, hence my desire to sit down and contribute a solution

    This is based on the 0.33 release, there are minor changes to the DatePicker code in 0.40, mostly CSS related.
    Code:
    var CalObj = function(opts) {
    	this.textfield = null;
    	this.datepicker = null; // YAHOO.ext.DatePicker object
    	this.calID = YAHOO.util.Dom.generateId(0, 'dpobj-dp-');
    	this.showDatePicker = null;
    
    	this.onSelectEvent = new YAHOO.util.CustomEvent("onSelect", this);
    
    	this.onSelectEvent.subscribe(this.setTextfield);
    
    	this.config = {
    		textfield: null, // id/HTML Element
    		showPickerOnFocus: false, // show the picker when the textfield is focused
    		outputDateFmt: 'm/d/Y',
    		showPicker: null,
    		parent:false,
    		inlinePicker:false,
    		twoDigitYearCutoff: 1980 // null to ignore, otherwise dates before this have 100 years added to them (1904 becomes 2004).
    	};
    
    	// initialize our config
    	if( typeof opts != 'undefined' ) {
    		for( var c in this.config) {
    			if( typeof opts[c] != "undefined" ) {
    				this.config[c] = opts[c];
    			}
    		}
    	}
    
    }
    CalObj.prototype.init = function() {
    	if( this.config.showPicker ) {
    		this.showDatePicker = getEl(this.config.showPicker);
    		// add our click handler to show the link
    		this.showDatePicker.on('click', this.show, this, true);
    	}
    	if( this.config.textfield ) {
    		this.textfield = getEl(this.config.textfield);
    		if( this.config.showPickerOnFocus ) {
    			this.textfield.set({autocomplete:'off'}); // work around firefox errors
    			this.textfield.on('focus', this.show, this, true);
    		}
    	}
    	if( this.config.inlinePicker ) {
    		var _this = this; // scope our callback appropriately
    		this.datepicker = new YAHOO.ext.InlineDatePicker(this.calID, this.config.parent, function() { _this.onSelectEventFire(_this); } );
    	} else {
    		this.datepicker = new YAHOO.ext.DatePicker(this.calID, this.config.parent);
    	}
    }
    CalObj.prototype.getSelectedDate = function() {
    	return this.datepicker.getSelectedDate();
    }
    CalObj.prototype.show = function() {
    	var selectedDate = new Date();
    	var _this = this; // scope our callback appropriately
    	var r = { left:0, bottom:0 };
    
    	if( this.textfield && this.config.showPickerOnFocus ) {
    		r = this.textfield.getRegion();
    	} else if( this.showDatePicker ) {
    		r = this.showDatePicker.getRegion();
    	}
    
    	if( this.textfield && this.textfield.dom.value != '' ) {
    		selectedDate = Date.parse(this.textfield.dom.value);
    		if( isNaN(selectedDate) ) {
    			selectedDate = new Date();
    		} else {
    			selectedDate = new Date(selectedDate);
    			if( this.config.twoDigitYearCutoff && selectedDate.getFullYear() <= this.config.twoDigitYearCutoff ) {
    				selectedDate.setFullYear(selectedDate.getFullYear()+100);
    			}
    		}
    	}
    		this.datepicker.show(r.left, r.bottom, selectedDate, function() { _this.onSelectEventFire(_this); } );
    }
    CalObj.prototype.onSelectEventFire = function() {
    	this.onSelectEvent.fire();
    }
    
    CalObj.prototype.setTextfield = function() {
    	var selDate = this.getSelectedDate();
    	if( this.textfield ) {
    		this.textfield.dom.value = selDate.dateFormat(this.config.outputDateFmt);
    	}
    }
    
    YAHOO.ext.DatePicker.prototype.constrainXY = function(x, y) {
    	var w = YAHOO.util.Dom.getViewportWidth();
    	var h = YAHOO.util.Dom.getViewportHeight();
    	var size = this.element.getSize();
    	var mx = x;
    	var my = y;
    	if( size.width + x > w ) {
    		mx = w - size.width;
    	}
    	if( size.height + y > h ) {
    		my = y - size.height;
    	}
    	return [ mx, my ];
    }
    
    // override the base picker to show it inline
    YAHOO.ext.InlineDatePicker = function(id, parentElement, callback){
      this.id = id;
      this.selectedDate = new Date();
      this.visibleDate = new Date();
      this.element = null;
      this.shadow = null;
      this.callback = callback;
      this.buildControl(parentElement);
      this.refresh();
    };
    YAHOO.ext.InlineDatePicker.prototype.buildControl = function(parentElement){
    	var c = document.createElement('div');
      parentElement = $(parentElement);
      parentElement.appendChild(c);
      var html = '<div class="ypopcal" id="'+this.id+'" style="-moz-outline:none;">' +
      '<table class="ypopcal-head" border=0 cellpadding=0 cellspacing=0><tbody><tr><td class="ypopcal-arrow"><div class="prev-month"> </div></td><td class="ypopcal-month"> </td><td class="ypopcal-arrow"><div class="next-month"> </div></td></tr></tbody></table>' +
      '<center><div class="ypopcal-inner">';
      html += "<table border=0 cellpadding=2 cellspacing=0 class=\"ypopcal-table\"><thead><tr class=\"ypopcal-daynames\">";
      var names = this.dayNames;
      for(var i = 0; i < names.length; i++){
          html += '<td>' + names[i].substr(0, 1) + '</td>';
      }
      html+= "</tr></thead><tbody><tr>";
      for(var i = 0; i < 42; i++) {
          if(i % 7 == 0 && i != 0){
              html += '</tr><tr>';
          }
          html += "<td></td>";
      }
      html += "</tr></tbody></table>";
      html += '</div><button class="ypopcal-today" style="margin-top:2px;">'+this.todayText+'</button></center></div>';
      c.innerHTML = html;
      this.element = getEl(c.childNodes[0], true);
      parentElement.appendChild(this.element.dom);
      parentElement.removeChild(c);
      this.element.on("selectstart", function(){return false;});
      var tbody = this.element.dom.getElementsByTagName('tbody')[1];
      this.cells = tbody.getElementsByTagName('td');
      this.calHead = this.element.getChildrenByClassName('ypopcal-month', 'td')[0];
      this.element.mon('mousedown', this.handleClick, this, true);
    };
    YAHOO.ext.InlineDatePicker.prototype.refresh = function(){
      var d = this.visibleDate;
      this.buildInnerCal(d);
      this.calHead.update(this.monthNames[d.getMonth()] + ' ' + d.getFullYear());
    }
    YAHOO.ext.InlineDatePicker.prototype.show = function(x, y, value, callback) {
    	this.selectedDate = value;
      this.visibleDate = value;
      this.callback = callback;
      this.refresh();
    }
    YAHOO.ext.InlineDatePicker.prototype.hide = function() { }
    
    YAHOO.augment(YAHOO.ext.InlineDatePicker, YAHOO.ext.DatePicker);

  2. #2
    Sencha User jack.slocum's Avatar
    Join Date
    Mar 2007
    Location
    Tampa, FL
    Posts
    6,955
    Vote Rating
    16
    jack.slocum will become famous soon enough

      0  

    Default


    The whole control needs a refactor. It was written almost 8 years ago with some updates here and there. The refactor is coming soon, it will be part of the forms lib.

  3. #3

    Default


    Quote Originally Posted by jacksloc
    The whole control needs a refactor. It was written almost 8 years ago with some updates here and there. The refactor is coming soon, it will be part of the forms lib.
    Sounds like an excuse to wait to me

  4. #4
    Ext User hcristea's Avatar
    Join Date
    Mar 2007
    Posts
    31
    Vote Rating
    0
    hcristea is on a distinguished road

      0  

    Default


    The way the datepicker is constructed causes a bug when you try to localize the calendar.
    The method buildControl of the DatePicker is called in the constructor and uses the dayNames from the default (Date.dayNames).

    Changing the property dayNames of the DatePicker object after it is initialized doesnt affect the dayNames from the calendar header. they remain always the same (S, M, T, W, T, F, S ie. .substr(0, 1) from the default english days).

    Currently without modifying the code in yui-ext.js you cannot set the dayNames for the Calendar. Please have this in mind when you do the refactor.

  5. #5
    Sencha User jack.slocum's Avatar
    Join Date
    Mar 2007
    Location
    Tampa, FL
    Posts
    6,955
    Vote Rating
    16
    jack.slocum will become famous soon enough

      0  

    Default


    To localize, you would modify them on the prototype, before the DP is used:

    Ext.DatePicker.prototype.dayNames = ['Lunes', .... 'Sabado'];

  6. #6
    Ext User
    Join Date
    Mar 2007
    Posts
    13
    Vote Rating
    0
    ter is on a distinguished road

      0  

    Default


    But if week begins not with sunday?

  7. #7
    Ext User hcristea's Avatar
    Join Date
    Mar 2007
    Posts
    31
    Vote Rating
    0
    hcristea is on a distinguished road

      0  

    Default


    Quote Originally Posted by jacksloc
    To localize, you would modify them on the prototype, before the DP is used:

    Ext.DatePicker.prototype.dayNames = ['Lunes', .... 'Sabado'];
    Hi Jack,

    yes, i tried that but it doesn't affect the days initials in the "Calendar". when the calendar is build i remember that you take the first letter from the day names. that constructor is called before my line that modify the prototype.

    (sorry i don't have the code handy to look and tell you specifically why i think its a bug this. I'll come back with a post later).

    changing the prototype of the monthNames works. maybe changing the prototype of the dayNames will localize the data in a "verbose" format but it doesn't affect the INITIALS of the days in the calendar.

    forgot to say that this behaviour is happening on 0.33 version

  8. #8
    Ext User hcristea's Avatar
    Join Date
    Mar 2007
    Posts
    31
    Vote Rating
    0
    hcristea is on a distinguished road

      0  

    Default


    Quote Originally Posted by jacksloc
    To localize, you would modify them on the prototype, before the DP is used:

    Ext.DatePicker.prototype.dayNames = ['Lunes', .... 'Sabado'];

    hi jack,

    you are right, i got to modify the prototype on the DP BEFORE is used. This works and this is what i'm currently doing. But i think it shouldn't work like this.

    i've got the code now and i got more specific information.
    I'll explain this "bug" with some code examples.

    I implemented a very basic DateTimeEditor which has a input field type=text and on focus will show the DatePicker.
    So the code looks like this: (i will show only the specific lines)
    Code:
    YAHOO.cw.DateTimeEditor = function(el, config){
    	....
    	this.cal = null;
    	....
    };
    
    YAHOO.cw.DateTimeEditor.prototype = {
    	init : function(){ ... }, 
        
    	initEvents: function(){ ... },
    
    	.....,
        
    	showCalendar : function(){
    		if(this.cal == null){
    			YAHOO.ext.DatePicker.prototype.dayNames = this.dayNames;
    			this.cal = new YAHOO.ext.DatePicker(YAHOO.util.Dom.generateId());
    		}
    		this.cal.monthNames = this.monthNames;
    		//this.cal.dayNames = this.dayNames;
    
    		.... 
    		var r = this.element.getRegion();
    		this.cal.show(r.left, r.bottom, this.getValue() || new Date(), this.setValue.createDelegate(this));
    	},
    	
    	.....	    
    };
    
    YAHOO.cw.DateTimeEditor.prototype.monthNames = ["Januar", .... "Dezember"];
    YAHOO.cw.DateTimeEditor.prototype.dayNames = ["Sonntag", ...., "Samstag"];

    To localize the dayNames i use YAHOO.ext.DatePicker.prototype.dayNames = this.dayNames; before i instantiate the DP.
    However i can localize the monthNames after i have an instance of DP and before calling the this.cal.show() method.

    When the show() method is called the method refresh() is called before the actual calendar is displayed. the refresh() method is updating the calHeader with the proper month name which is localized when do this.cal.monthNames = this.monthNames; in my code above.

    I'm saying that also to localize the dayNames to be done with this.cal.dayNames = this.dayNames; which now has no effect on the actual calendar.

    maybe the DP.refresh() method should do more like updating also the day Initials in the DP control and also the Today text.

    what do you think?

Similar Threads

  1. Help with DatePicker
    By alex1er in forum Ext 1.x: Help & Discussion
    Replies: 12
    Last Post: 2 Apr 2008, 7:14 AM
  2. DatePicker example
    By corey.gilmore in forum Community Discussion
    Replies: 19
    Last Post: 15 Nov 2007, 10:31 PM
  3. Inputs to DatePicker
    By alindsay55661 in forum Ext 2.x: Help & Discussion
    Replies: 11
    Last Post: 3 Mar 2007, 4:23 PM
  4. [1.0a2 Rev 6] DatePicker bugs
    By Arikon in forum Ext 2.x: Help & Discussion
    Replies: 6
    Last Post: 2 Mar 2007, 9:00 AM

Thread Participants: 3