/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.widget.DatePicker");
dojo.require("dojo.date.common");
dojo.require("dojo.date.format");
dojo.require("dojo.date.serialize");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.event.*");
dojo.require("dojo.dom");
dojo.require("dojo.html.style");
dojo.widget.defineWidget(
"dojo.widget.DatePicker",
dojo.widget.HtmlWidget,
{
/*
summary:
Base class for a stand-alone DatePicker widget
which makes it easy to select a date, or switch by month and/or year.
description:
A stand-alone DatePicker widget that makes it
easy to select a date, or increment by week, month, and/or year.
It is designed to be used on its own, or inside of other widgets to
(see dojo.widget.DropdownDatePicker) or other similar combination widgets.
Dates attributes passed in the `RFC 3339` format:
http://www.faqs.org/rfcs/rfc3339.html (2005-06-30T08:05:00-07:00)
so that they are serializable and locale-independent.
usage:
var datePicker = dojo.widget.createWidget("DatePicker", {},
dojo.byId("datePickerNode"));
*/
//start attributes
// value: String|Date
// form value property if =='today' will be today's date
value: "",
// name: String
// name of the form element
name: "",
// displayWeeks: Integer
// total weeks to display default
displayWeeks: 6,
// adjustWeeks: Boolean
// if true, weekly size of calendar changes to acomodate the month if false, 42 day format is used
adjustWeeks: false,
// startDate: String|Date
// first available date in the calendar set
startDate: "1492-10-12",
// endDate: String|Date
// last available date in the calendar set
endDate: "2941-10-12",
// weekStartsOn: Integer
// adjusts the first day of the week 0==Sunday..6==Saturday
weekStartsOn: "",
// storedDate: String
// deprecated use value instead
storedDate: "",
// staticDisplay: Boolean
// disable all incremental controls, must pick a date in the current display
staticDisplay: false,
// dayWidth: String
// how to render the names of the days in the header. see dojo.date.getDayNames
dayWidth: 'narrow',
classNames: {
// summary:
// stores a list of class names that may be overriden
// TODO: this is not good; can't be adjusted via markup, etc. since it's an array
previous: "previousMonth",
disabledPrevious: "previousMonthDisabled",
current: "currentMonth",
disabledCurrent: "currentMonthDisabled",
next: "nextMonth",
disabledNext: "nextMonthDisabled",
currentDate: "currentDate",
selectedDate: "selectedItem"
},
templatePath: dojo.uri.dojoUri("src/widget/templates/DatePicker.html"),
templateCssPath: dojo.uri.dojoUri("src/widget/templates/DatePicker.css"),
postMixInProperties: function(){
// summary: see dojo.widget.DomWidget
dojo.widget.DatePicker.superclass.postMixInProperties.apply(this, arguments);
if(this.storedDate){
dojo.deprecated("dojo.widget.DatePicker", "use 'value' instead of 'storedDate'", "0.5");
this.value=this.storedDate;
}
this.startDate = dojo.date.fromRfc3339(this.startDate);
this.endDate = dojo.date.fromRfc3339(this.endDate);
this.startDate.setHours(0,0,0,0); //adjust startDate to be exactly midnight
this.endDate.setHours(24,0,0,-1); //adjusting endDate to be a fraction of a second before midnight
if(!this.weekStartsOn){
this.weekStartsOn=dojo.date.getFirstDayOfWeek(this.lang);
}
this.today = new Date();
this.today.setHours(0,0,0,0);
if(typeof(this.value)=='string'&&this.value.toLowerCase()=='today'){
this.value = new Date();
}else if(this.value && (typeof this.value=="string") && (this.value.split("-").length > 2)) {
this.value = dojo.date.fromRfc3339(this.value);
this.value.setHours(0,0,0,0);
}
},
fillInTemplate: function(args, frag) {
// summary: see dojo.widget.DomWidget
dojo.widget.DatePicker.superclass.fillInTemplate.apply(this, arguments);
// Copy style info from input node to output node
var source = this.getFragNodeRef(frag);
dojo.html.copyStyle(this.domNode, source);
this.weekTemplate = dojo.dom.removeNode(this.calendarWeekTemplate);
this._preInitUI(this.value ? this.value : this.today, false, true); //init UI with date selected ONLY if user supplies one
// Insert localized day names in the template
var dayLabels = dojo.lang.unnest(dojo.date.getNames('days', this.dayWidth, 'standAlone', this.lang)); //if we dont use unnest, we risk modifying the dayLabels array inside of dojo.date and screwing up other calendars on the page
if(this.weekStartsOn > 0){
//adjust dayLabels for different first day of week. ie: Monday or Thursday instead of Sunday
for(var i=0;ithis.endDate){
dateObj = new Date((dateObj days){
this._preInitUI(this.startDate,true,false);
nextDate = new Date(this.firstDay);
}
this.curMonth = new Date(nextDate);
this.curMonth.setDate(nextDate.getDate()+6);
this.curMonth.setDate(1);
var curClass = (nextDate.getMonth() == this.curMonth.getMonth())?'current':'previous';
}
if(initUI){
this._initUI(days);
}
},
_initUI: function(days) {
dojo.dom.removeChildren(this.calendarDatesContainerNode);
for(var i=0;ithis.endDate){
incWeek = incMonth = incYear = false;
}
if(decMonth && add(d,DAY,-1)this.endDate){
incMonth = incYear = false;
}
if(decYear && add(d2,YEAR,-1)this.endDate){
incYear = false;
}
}
function enableControl(node, enabled){
dojo.html.setVisibility(node, enabled ? '' : 'hidden');
}
enableControl(this.decreaseWeekNode,decWeek);
enableControl(this.increaseWeekNode,incWeek);
enableControl(this.decreaseMonthNode,decMonth);
enableControl(this.increaseMonthNode,incMonth);
enableControl(this.previousYearLabelNode,decYear);
enableControl(this.nextYearLabelNode,incYear);
},
_incrementWeek: function(evt) {
var d = new Date(this.firstDay);
switch(evt.target) {
case this.increaseWeekNode.getElementsByTagName("img").item(0):
case this.increaseWeekNode:
var tmpDate = dojo.date.add(d, dojo.date.dateParts.WEEK, 1);
if(tmpDate < this.endDate){
d = dojo.date.add(d, dojo.date.dateParts.WEEK, 1);
}
break;
case this.decreaseWeekNode.getElementsByTagName("img").item(0):
case this.decreaseWeekNode:
if(d >= this.startDate){
d = dojo.date.add(d, dojo.date.dateParts.WEEK, -1);
}
break;
}
this._preInitUI(d,true,true);
},
_incrementMonth: function(evt) {
var d = new Date(this.curMonth);
var tmpDate = new Date(this.firstDay);
switch(evt.currentTarget) {
case this.increaseMonthNode.getElementsByTagName("img").item(0):
case this.increaseMonthNode:
tmpDate = dojo.date.add(tmpDate, dojo.date.dateParts.DAY, this.displayWeeks*7);
if(tmpDate < this.endDate){
d = dojo.date.add(d, dojo.date.dateParts.MONTH, 1);
}else{
var revertToEndDate = true;
}
break;
case this.decreaseMonthNode.getElementsByTagName("img").item(0):
case this.decreaseMonthNode:
if(tmpDate > this.startDate){
d = dojo.date.add(d, dojo.date.dateParts.MONTH, -1);
}else{
var revertToStartDate = true;
}
break;
}
if(revertToStartDate){
d = new Date(this.startDate);
}else if(revertToEndDate){
d = new Date(this.endDate);
}
this._preInitUI(d,false,true);
},
_incrementYear: function(evt) {
var year = this.curMonth.getFullYear();
var tmpDate = new Date(this.firstDay);
switch(evt.target) {
case this.nextYearLabelNode:
tmpDate = dojo.date.add(tmpDate, dojo.date.dateParts.YEAR, 1);
if(tmpDatethis.startDate){
year--;
}else{
var revertToStartDate = true;
}
break;
}
var d;
if(revertToStartDate){
d = new Date(this.startDate);
}else if(revertToEndDate){
d = new Date(this.endDate);
}else{
d = new Date(year, this.curMonth.getMonth(), 1);
}
this._preInitUI(d,false,true);
},
onIncrementWeek: function(/*Event*/evt) {
// summary: handler for increment week event
evt.stopPropagation();
if(!this.staticDisplay){
this._incrementWeek(evt);
}
},
onIncrementWeekPressed: function(event) {
// DOJO accessibility for Alfresco WCM: ALF-11956
if(null != event){
event.stopPropagation();
if((13 == event.keyCode) || (32 == event.keyCode) || ((null != event.charCode) && (32 == event.charCode))){
this.onIncrementWeek(event);
}
}
},
onIncrementMonth: function(/*Event*/evt) {
// summary: handler for increment month event
evt.stopPropagation();
if(!this.staticDisplay){
this._incrementMonth(evt);
}
},
onIncrementMonthPressed: function(event) {
// DOJO accessibility for Alfresco WCM: ALF-11956
if(null != event){
event.stopPropagation();
if((13 == event.keyCode) || (32 == event.keyCode) || ((null != event.charCode) && (32 == event.charCode))){
this.onIncrementMonth(event);
}
}
},
onIncrementYear: function(/*Event*/evt) {
// summary: handler for increment year event
evt.stopPropagation();
if(!this.staticDisplay){
this._incrementYear(evt);
}
},
onIncrementYearPressed: function(event) {
// DOJO accessibility for Alfresco WCM: ALF-11956
if(null != event){
event.stopPropagation();
if((13 == event.keyCode) || (32 == event.keyCode) || ((null != event.charCode) && (32 == event.charCode))){
this.onIncrementYear(event);
}
}
},
_setMonthLabel: function(monthIndex) {
this.monthLabelNode.innerHTML = dojo.date.getNames('months', 'wide', 'standAlone', this.lang)[monthIndex];
},
_setYearLabels: function(year) {
var y = year - 1;
var that = this;
function f(n){
that[n+"YearLabelNode"].innerHTML =
dojo.date.format(new Date(y++, 0), {formatLength:'yearOnly', locale:that.lang});
}
f("previous");
f("current");
f("next");
},
_getDateClassName: function(date, monthState) {
var currentClassName = this.classNames[monthState];
//we use Number comparisons because 2 dateObjects never seem to equal each other otherwise
if ((!this.selectedIsUsed && this.value) && (Number(date) == Number(this.value))) {
currentClassName = this.classNames.selectedDate + " " + currentClassName;
this.selectedIsUsed = true;
}
if((!this.currentIsUsed) && (Number(date) == Number(this.today))) {
currentClassName = currentClassName + " " + this.classNames.currentDate;
this.currentIsUsed = true;
}
return currentClassName;
},
onClick: function(/*Event*/evt) {
//summary: the click event handler
dojo.event.browser.stopEvent(evt);
},
_handleUiClick: function(/*Event*/evt) {
// DOJO accessibility for Alfresco WCM: ALF-11956
var selectedDate = this._getSelectDayMonthAndYear(evt);
if(null == selectedDate){
return;
}
this.clickedNode = evt.target;
this.setDate(new Date(selectedDate.year, selectedDate.month, evt.target.innerHTML));
},
_getSelectDayMonthAndYear: function(evt) {
// DOJO accessibility for Alfresco WCM: ALF-11956
var eventTarget = evt.target;
if(eventTarget.nodeType != dojo.dom.ELEMENT_NODE){eventTarget = eventTarget.parentNode;}
if(null != evt.preventDefault){
dojo.event.browser.stopEvent(evt);
}
this.selectedIsUsed = this.todayIsUsed = false;
var month = this.curMonth.getMonth();
var year = this.curMonth.getFullYear();
if(dojo.html.hasClass(eventTarget, this.classNames["disabledPrevious"])||dojo.html.hasClass(eventTarget, this.classNames["disabledCurrent"])||dojo.html.hasClass(eventTarget, this.classNames["disabledNext"])){
return null; //this date is disabled... ignore it
}else if (dojo.html.hasClass(eventTarget, this.classNames["next"])) {
month = ++month % 12;
if(month===0){++year;}
} else if (dojo.html.hasClass(eventTarget, this.classNames["previous"])) {
month = --month % 12;
if(month==11){--year;}
}
return {"day": eventTarget.innerHTML, "month": month, "year": year};
},
_handleUiPress: function(event) {
// DOJO accessibility for Alfresco WCM: ALF-11956
if(null != event){
event.stopPropagation();
if((13 == event.keyCode) || (32 == event.keyCode) || ((null != event.charCode) && (32 == event.charCode))){
this._handleUiClick(event);
}
}
},
onValueChanged: function(/*Date*/date) {
//summary: the set date event handler
},
_isDisabledDate: function(dateObj){
if(dateObjthis.endDate){
return true;
}
return this.isDisabledDate(dateObj, this.lang);
},
isDisabledDate: function(/*Date*/dateObj, /*String?*/locale){
// summary:
// May be overridden to disable certain dates in the calendar e.g. isDisabledDate=dojo.date.isWeekend
return false; // Boolean
},
_initFirstDay: function(/*Date*/dateObj, /*Boolean*/adj){
//adj: false for first day of month, true for first day of week adjusted by startOfWeek
var d = new Date(dateObj);
if(!adj){d.setDate(1);}
d.setDate(d.getDate()-this._getAdjustedDay(d,this.weekStartsOn));
d.setHours(0,0,0,0);
return d; // Date
},
_getAdjustedDay: function(/*Date*/dateObj){
//summary: used to adjust date.getDay() values to the new values based on the current first day of the week value
var days = [0,1,2,3,4,5,6];
if(this.weekStartsOn>0){
for(var i=0;i