You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
391 lines
11 KiB
391 lines
11 KiB
define([ |
|
"dijit/_WidgetBase", |
|
"dijit/_TemplatedMixin", |
|
"dijit/_Container", |
|
"dijit/_WidgetsInTemplateMixin", |
|
"dijit/typematic", |
|
"dojo/_base/declare", |
|
"dojo/date", |
|
"dojo/date/stamp", |
|
"dojo/date/locale", |
|
"dojo/dom-style", |
|
"dojo/dom-class", |
|
"dojo/_base/fx", |
|
"dojo/on", |
|
"dojo/_base/array", |
|
"dojo/_base/lang", |
|
"dojo/text!./Calendar/Calendar.html" |
|
], function(_WidgetBase, _TemplatedMixin, _Container, _WidgetsInTemplateMixin, dijitTypematic, |
|
declare, dojoDate, stamp, dojoDateLocale, domStyle, domClass, fx, on, array, lang, template){ |
|
return declare("dojox.widget._CalendarBase", [_WidgetBase, _TemplatedMixin, _Container, _WidgetsInTemplateMixin], { |
|
// summary: |
|
// The Root class for all _Calendar extensions |
|
|
|
// templateString: String |
|
// The template to be used to construct the widget. |
|
templateString: template, |
|
|
|
// _views: Array |
|
// The list of mixin views available on this calendar. |
|
_views: null, |
|
|
|
// useFx: Boolean |
|
// Specifies if visual effects should be applied to the widget. |
|
// The default behavior of the widget does not contain any effects. |
|
// The dojox.widget.CalendarFx package is needed for these. |
|
useFx: true, |
|
|
|
// value: Date |
|
// The currently selected Date |
|
value: new Date(), |
|
|
|
constraints: null, |
|
|
|
// footerFormat: String |
|
// The date format of the date displayed in the footer. Can be |
|
// 'short', 'medium', and 'long' |
|
footerFormat: "medium", |
|
|
|
constructor: function(){ |
|
this._views = []; |
|
this.value = new Date(); |
|
}, |
|
|
|
_setConstraintsAttr: function(constraints){ |
|
// summary: |
|
// Sets minimum and maximum constraints |
|
var c = this.constraints = constraints; |
|
if(c){ |
|
if(typeof c.min == "string"){ |
|
c.min = stamp.fromISOString(c.min); |
|
} |
|
if(typeof c.max == "string"){ |
|
c.max = stamp.fromISOString(c.max); |
|
} |
|
} |
|
}, |
|
|
|
postMixInProperties: function () { |
|
this.inherited(arguments); |
|
this.value = this.parseInitialValue(this.value); |
|
}, |
|
|
|
parseInitialValue: function(value){ |
|
if (!value || value === -1){ |
|
return new Date(); |
|
}else if(value.getFullYear){ |
|
return value; |
|
}else if (!isNaN(value)) { |
|
if (typeof this.value == "string") { |
|
value = parseInt(value); |
|
} |
|
value = this._makeDate(value); |
|
} |
|
return value; |
|
}, |
|
|
|
_makeDate: function(value){ |
|
return value;//new Date(value); |
|
}, |
|
|
|
postCreate: function(){ |
|
// summary: |
|
// Instantiates the mixin views |
|
|
|
this.displayMonth = new Date(this.get('value')); |
|
|
|
if(this._isInvalidDate(this.displayMonth)){ |
|
this.displayMonth = new Date(); |
|
} |
|
|
|
var mixin = { |
|
parent: this, |
|
_getValueAttr: lang.hitch(this, function(){return new Date(this._internalValue || this.value);}), |
|
_getDisplayMonthAttr: lang.hitch(this, function(){return new Date(this.displayMonth);}), |
|
_getConstraintsAttr: lang.hitch(this, function(){return this.constraints;}), |
|
getLang: lang.hitch(this, function(){return this.lang;}), |
|
isDisabledDate: lang.hitch(this, this.isDisabledDate), |
|
getClassForDate: lang.hitch(this, this.getClassForDate), |
|
addFx: this.useFx ? lang.hitch(this, this.addFx) : function(){} |
|
}; |
|
|
|
//Add the mixed in views. |
|
array.forEach(this._views, function(widgetType){ |
|
var widget = new widgetType(mixin).placeAt(this); |
|
|
|
var header = widget.getHeader(); |
|
if(header){ |
|
//place the views's header node in the header of the main widget |
|
this.header.appendChild(header); |
|
|
|
//hide the header node of the widget |
|
domStyle.set(header, "display", "none"); |
|
} |
|
//Hide all views |
|
domStyle.set(widget.domNode, "visibility", "hidden"); |
|
|
|
//Listen for the values in a view to be selected |
|
widget.on("valueSelected", lang.hitch(this, "_onDateSelected")); |
|
widget.set("value", this.get('value')); |
|
}, this); |
|
|
|
if(this._views.length < 2){ |
|
domStyle.set(this.header, "cursor", "auto"); |
|
} |
|
|
|
this.inherited(arguments); |
|
|
|
// Cache the list of children widgets. |
|
this._children = this.getChildren(); |
|
|
|
this._currentChild = 0; |
|
|
|
//Populate the footer with today's date. |
|
var today = new Date(); |
|
|
|
this.footer.innerHTML = "Today: " + |
|
dojoDateLocale.format(today, { |
|
formatLength:this.footerFormat, |
|
selector:'date', |
|
locale:this.lang}); |
|
|
|
on(this.footer, "click", lang.hitch(this, "goToToday")); |
|
|
|
var first = this._children[0]; |
|
|
|
domStyle.set(first.domNode, "top", "0px"); |
|
domStyle.set(first.domNode, "visibility", "visible"); |
|
|
|
var header = first.getHeader(); |
|
if(header){ |
|
domStyle.set(first.getHeader(), "display", ""); |
|
} |
|
|
|
domClass.toggle(this.container, "no-header", !first.useHeader); |
|
|
|
first.onDisplay(); |
|
|
|
var _this = this; |
|
|
|
var typematic = function(nodeProp, dateProp, adj){ |
|
dijitTypematic.addMouseListener(_this[nodeProp], _this, function(count){ |
|
if(count >= 0){ _this._adjustDisplay(dateProp, adj);} |
|
}, 0.8, 500); |
|
}; |
|
typematic("incrementMonth", "month", 1); |
|
typematic("decrementMonth", "month", -1); |
|
this._updateTitleStyle(); |
|
}, |
|
|
|
addFx: function(query, fromNode){ |
|
// Stub function than can be overridden to add effects. |
|
}, |
|
|
|
_isInvalidDate: function(/*Date*/ value){ |
|
// summary: |
|
// Runs various tests on the value, checking for invalid conditions |
|
// tags: |
|
// private |
|
return !value || isNaN(value) || typeof value != "object" || value.toString() == this._invalidDate; |
|
}, |
|
|
|
_setValueAttr: function(/*Date*/ value){ |
|
// summary: |
|
// Set the current date and update the UI. If the date is disabled, the selection will |
|
// not change, but the display will change to the corresponding month. |
|
if(!value){ |
|
value = new Date(); |
|
} |
|
if(!value["getFullYear"]){ |
|
value = stamp.fromISOString(value + ""); |
|
} |
|
if(this._isInvalidDate(value)){ |
|
return false; |
|
} |
|
if(!this.value || dojoDate.compare(value, this.value)){ |
|
value = new Date(value); |
|
this.displayMonth = new Date(value); |
|
this._internalValue = value; |
|
if(!this.isDisabledDate(value, this.lang) && this._currentChild === 0){ |
|
this.value = value; |
|
this.onChange(value); |
|
} |
|
if (this._children && this._children.length > 0) { |
|
this._children[this._currentChild].set("value", this.value); |
|
} |
|
return true; |
|
} |
|
this.onExecute(); |
|
return false; |
|
}, |
|
|
|
isDisabledDate: function(/*Date*/date, /*String?*/locale){ |
|
// summary: |
|
// May be overridden to disable certain dates in the calendar e.g. `isDisabledDate=dojo.date.locale.isWeekend` |
|
var c = this.constraints; |
|
var compare = dojoDate.compare; |
|
return c && (c.min && (compare(c.min, date, "date") > 0) || |
|
(c.max && compare(c.max, date, "date") < 0)); |
|
}, |
|
|
|
onValueSelected: function(/*Date*/date){ |
|
// summary: |
|
// A date cell was selected. It may be the same as the previous value. |
|
}, |
|
|
|
_onDateSelected: function(date, formattedValue, force){ |
|
this.displayMonth = date; |
|
|
|
this.set("value", date); |
|
//Only change the selected value if it was chosen from the |
|
//first child. |
|
if(!this._transitionVert(-1)){ |
|
if(!formattedValue && formattedValue !== 0){ |
|
formattedValue = this.get('value'); |
|
} |
|
this.onValueSelected(formattedValue); |
|
} |
|
|
|
}, |
|
|
|
onChange: function(/*Date*/date){ |
|
// summary: |
|
// Called only when the selected date has changed |
|
}, |
|
|
|
onHeaderClick: function(e){ |
|
// summary: |
|
// Transitions to the next view. |
|
this._transitionVert(1); |
|
}, |
|
|
|
goToToday: function(){ |
|
this.set("value", new Date()); |
|
this.onValueSelected(this.get('value')); |
|
}, |
|
|
|
_transitionVert: function(/*Number*/direction){ |
|
// summary: |
|
// Animates the views to show one and hide another, in a |
|
// vertical direction. |
|
// If 'direction' is 1, then the views slide upwards. |
|
// If 'direction' is -1, the views slide downwards. |
|
var curWidget = this._children[this._currentChild]; |
|
var nextWidget = this._children[this._currentChild + direction]; |
|
if(!nextWidget){return false;} |
|
|
|
domStyle.set(nextWidget.domNode, "visibility", "visible"); |
|
|
|
var height = domStyle.get(this.containerNode, "height"); |
|
nextWidget.set("value", this.displayMonth); |
|
|
|
if(curWidget.header){ |
|
domStyle.set(curWidget.header, "display", "none"); |
|
} |
|
if(nextWidget.header){ |
|
domStyle.set(nextWidget.header, "display", ""); |
|
} |
|
domStyle.set(nextWidget.domNode, "top", (height * -1) + "px"); |
|
domStyle.set(nextWidget.domNode, "visibility", "visible"); |
|
|
|
this._currentChild += direction; |
|
|
|
var height1 = height * direction; |
|
var height2 = 0; |
|
domStyle.set(nextWidget.domNode, "top", (height1 * -1) + "px"); |
|
|
|
// summary: |
|
// Slides two nodes vertically. |
|
var anim1 = fx.animateProperty({ |
|
node: curWidget.domNode, |
|
properties: {top: height1}, |
|
onEnd: function(){ |
|
domStyle.set(curWidget.domNode, "visibility", "hidden"); |
|
} |
|
}); |
|
var anim2 = fx.animateProperty({ |
|
node: nextWidget.domNode, |
|
properties: {top: height2}, |
|
onEnd: function(){ |
|
nextWidget.onDisplay(); |
|
} |
|
}); |
|
|
|
domClass.toggle(this.container, "no-header", !nextWidget.useHeader); |
|
|
|
anim1.play(); |
|
anim2.play(); |
|
curWidget.onBeforeUnDisplay(); |
|
nextWidget.onBeforeDisplay(); |
|
|
|
this._updateTitleStyle(); |
|
return true; |
|
}, |
|
|
|
_updateTitleStyle: function(){ |
|
domClass.toggle(this.header, "navToPanel", this._currentChild < this._children.length -1); |
|
}, |
|
|
|
_slideTable: function(/*String*/widget, /*Number*/direction, /*Function*/callback){ |
|
// summary: |
|
// Animates the horizontal sliding of a table. |
|
var table = widget.domNode; |
|
|
|
//Clone the existing table |
|
var newTable = table.cloneNode(true); |
|
var left = domStyle.get(table, "width"); |
|
|
|
table.parentNode.appendChild(newTable); |
|
|
|
//Place the existing node either to the left or the right of the new node, |
|
//depending on which direction it is to slide. |
|
domStyle.set(table, "left", (left * direction) + "px"); |
|
|
|
//Call the function that generally populates the new cloned node with new data. |
|
//It may also attach event listeners. |
|
callback(); |
|
|
|
//Animate the two nodes. |
|
var anim1 = fx.animateProperty({node: newTable, properties:{left: left * direction * -1}, duration: 500, onEnd: function(){ |
|
newTable.parentNode.removeChild(newTable); |
|
}}); |
|
var anim2 = fx.animateProperty({node: table, properties:{left: 0}, duration: 500}); |
|
|
|
anim1.play(); |
|
anim2.play(); |
|
}, |
|
|
|
_addView: function(view){ |
|
//Insert the view at the start of the array. |
|
this._views.push(view); |
|
}, |
|
|
|
getClassForDate: function(/*Date*/dateObject, /*String?*/locale){ |
|
// summary: |
|
// May be overridden to return CSS classes to associate with the date entry for the given dateObject, |
|
// for example to indicate a holiday in specified locale. |
|
|
|
/*===== |
|
return ""; // String |
|
=====*/ |
|
}, |
|
|
|
_adjustDisplay: function(/*String*/part, /*int*/amount, noSlide){ |
|
// summary: |
|
// This function overrides the base function defined in dijit/Calendar. |
|
// It changes the displayed years, months and days depending on the inputs. |
|
var child = this._children[this._currentChild]; |
|
|
|
var month = this.displayMonth = child.adjustDate(this.displayMonth, amount); |
|
|
|
this._slideTable(child, amount, function(){ |
|
child.set("value", month); |
|
}); |
|
}, |
|
|
|
onExecute:function(){ |
|
// summary: |
|
// Stub for child classes to override. |
|
} |
|
}); |
|
});
|
|
|