corey.gilmore
4 Jan 2007, 9:11 AM
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.
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);
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.
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);