]>
Commit | Line | Data |
---|---|---|
2f01fe57 | 1 | /* |
81bea17a | 2 | Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. |
2f01fe57 AD |
3 | Available via Academic Free License >= 2.1 OR the modified BSD license. |
4 | see: http://dojotoolkit.org/license for details | |
5 | */ | |
6 | ||
7 | ||
81bea17a AD |
8 | if(!dojo._hasResource["dijit.Calendar"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
9 | dojo._hasResource["dijit.Calendar"] = true; | |
2f01fe57 AD |
10 | dojo.provide("dijit.Calendar"); |
11 | dojo.require("dojo.cldr.supplemental"); | |
12 | dojo.require("dojo.date"); | |
13 | dojo.require("dojo.date.locale"); | |
14 | dojo.require("dijit._Widget"); | |
15 | dojo.require("dijit._Templated"); | |
16 | dojo.require("dijit._CssStateMixin"); | |
81bea17a AD |
17 | dojo.require("dijit.form.DropDownButton"); |
18 | ||
19 | ||
20 | dojo.declare( | |
21 | "dijit.Calendar", | |
22 | [dijit._Widget, dijit._Templated, dijit._CssStateMixin], | |
23 | { | |
24 | // summary: | |
25 | // A simple GUI for choosing a date in the context of a monthly calendar. | |
26 | // | |
27 | // description: | |
28 | // A simple GUI for choosing a date in the context of a monthly calendar. | |
29 | // This widget can't be used in a form because it doesn't serialize the date to an | |
30 | // `<input>` field. For a form element, use dijit.form.DateTextBox instead. | |
31 | // | |
32 | // Note that the parser takes all dates attributes passed in the | |
33 | // [RFC 3339 format](http://www.faqs.org/rfcs/rfc3339.html), e.g. `2005-06-30T08:05:00-07:00` | |
34 | // so that they are serializable and locale-independent. | |
35 | // | |
36 | // example: | |
37 | // | var calendar = new dijit.Calendar({}, dojo.byId("calendarNode")); | |
38 | // | |
39 | // example: | |
40 | // | <div dojoType="dijit.Calendar"></div> | |
41 | ||
42 | templateString: dojo.cache("dijit", "templates/Calendar.html", "<table cellspacing=\"0\" cellpadding=\"0\" class=\"dijitCalendarContainer\" role=\"grid\" dojoAttachEvent=\"onkeypress: _onKeyPress\" aria-labelledby=\"${id}_year\">\n\t<thead>\n\t\t<tr class=\"dijitReset dijitCalendarMonthContainer\" valign=\"top\">\n\t\t\t<th class='dijitReset dijitCalendarArrow' dojoAttachPoint=\"decrementMonth\">\n\t\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitCalendarIncrementControl dijitCalendarDecrease\" role=\"presentation\"/>\n\t\t\t\t<span dojoAttachPoint=\"decreaseArrowNode\" class=\"dijitA11ySideArrow\">-</span>\n\t\t\t</th>\n\t\t\t<th class='dijitReset' colspan=\"5\">\n\t\t\t\t<div dojoType=\"dijit.form.DropDownButton\" dojoAttachPoint=\"monthDropDownButton\"\n\t\t\t\t\tid=\"${id}_mddb\" tabIndex=\"-1\">\n\t\t\t\t</div>\n\t\t\t</th>\n\t\t\t<th class='dijitReset dijitCalendarArrow' dojoAttachPoint=\"incrementMonth\">\n\t\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitCalendarIncrementControl dijitCalendarIncrease\" role=\"presentation\"/>\n\t\t\t\t<span dojoAttachPoint=\"increaseArrowNode\" class=\"dijitA11ySideArrow\">+</span>\n\t\t\t</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<th class=\"dijitReset dijitCalendarDayLabelTemplate\" role=\"columnheader\"><span class=\"dijitCalendarDayLabel\"></span></th>\n\t\t</tr>\n\t</thead>\n\t<tbody dojoAttachEvent=\"onclick: _onDayClick, onmouseover: _onDayMouseOver, onmouseout: _onDayMouseOut, onmousedown: _onDayMouseDown, onmouseup: _onDayMouseUp\" class=\"dijitReset dijitCalendarBodyContainer\">\n\t\t<tr class=\"dijitReset dijitCalendarWeekTemplate\" role=\"row\">\n\t\t\t<td class=\"dijitReset dijitCalendarDateTemplate\" role=\"gridcell\"><span class=\"dijitCalendarDateLabel\"></span></td>\n\t\t</tr>\n\t</tbody>\n\t<tfoot class=\"dijitReset dijitCalendarYearContainer\">\n\t\t<tr>\n\t\t\t<td class='dijitReset' valign=\"top\" colspan=\"7\">\n\t\t\t\t<h3 class=\"dijitCalendarYearLabel\">\n\t\t\t\t\t<span dojoAttachPoint=\"previousYearLabelNode\" class=\"dijitInline dijitCalendarPreviousYear\"></span>\n\t\t\t\t\t<span dojoAttachPoint=\"currentYearLabelNode\" class=\"dijitInline dijitCalendarSelectedYear\" id=\"${id}_year\"></span>\n\t\t\t\t\t<span dojoAttachPoint=\"nextYearLabelNode\" class=\"dijitInline dijitCalendarNextYear\"></span>\n\t\t\t\t</h3>\n\t\t\t</td>\n\t\t</tr>\n\t</tfoot>\n</table>\n"), | |
43 | widgetsInTemplate: true, | |
44 | ||
45 | // value: Date | |
46 | // The currently selected Date, initially set to invalid date to indicate no selection. | |
47 | value: new Date(""), | |
48 | // TODO: for 2.0 make this a string (ISO format) rather than a Date | |
49 | ||
50 | // datePackage: String | |
51 | // JavaScript namespace to find Calendar routines. Uses Gregorian Calendar routines | |
52 | // at dojo.date by default. | |
53 | datePackage: "dojo.date", | |
54 | ||
55 | // dayWidth: String | |
56 | // How to represent the days of the week in the calendar header. See dojo.date.locale | |
57 | dayWidth: "narrow", | |
58 | ||
59 | // tabIndex: Integer | |
60 | // Order fields are traversed when user hits the tab key | |
61 | tabIndex: "0", | |
62 | ||
63 | // currentFocus: Date | |
64 | // Date object containing the currently focused date, or the date which would be focused | |
65 | // if the calendar itself was focused. Also indicates which year and month to display, | |
66 | // i.e. the current "page" the calendar is on. | |
67 | currentFocus: new Date(), | |
68 | ||
69 | baseClass:"dijitCalendar", | |
70 | ||
71 | // Set node classes for various mouse events, see dijit._CssStateMixin for more details | |
72 | cssStateNodes: { | |
73 | "decrementMonth": "dijitCalendarArrow", | |
74 | "incrementMonth": "dijitCalendarArrow", | |
75 | "previousYearLabelNode": "dijitCalendarPreviousYear", | |
76 | "nextYearLabelNode": "dijitCalendarNextYear" | |
77 | }, | |
78 | ||
79 | _isValidDate: function(/*Date*/ value){ | |
80 | // summary: | |
81 | // Runs various tests on the value, checking that it's a valid date, rather | |
82 | // than blank or NaN. | |
83 | // tags: | |
84 | // private | |
85 | return value && !isNaN(value) && typeof value == "object" && | |
86 | value.toString() != this.constructor.prototype.value.toString(); | |
87 | }, | |
88 | ||
89 | setValue: function(/*Date*/ value){ | |
90 | // summary: | |
91 | // Deprecated. Use set('value', ...) instead. | |
92 | // tags: | |
93 | // deprecated | |
94 | dojo.deprecated("dijit.Calendar:setValue() is deprecated. Use set('value', ...) instead.", "", "2.0"); | |
95 | this.set('value', value); | |
96 | }, | |
97 | ||
98 | _getValueAttr: function(){ | |
99 | // summary: | |
100 | // Support get('value') | |
101 | ||
102 | // this.value is set to 1AM, but return midnight, local time for back-compat | |
103 | var value = new this.dateClassObj(this.value); | |
104 | value.setHours(0, 0, 0, 0); | |
105 | ||
106 | // If daylight savings pushes midnight to the previous date, fix the Date | |
107 | // object to point at 1am so it will represent the correct day. See #9366 | |
108 | if(value.getDate() < this.value.getDate()){ | |
109 | value = this.dateFuncObj.add(value, "hour", 1); | |
110 | } | |
111 | return value; | |
112 | }, | |
113 | ||
114 | _setValueAttr: function(/*Date|Number*/ value, /*Boolean*/ priorityChange){ | |
115 | // summary: | |
116 | // Support set("value", ...) | |
117 | // description: | |
118 | // Set the current date and update the UI. If the date is disabled, the value will | |
119 | // not change, but the display will change to the corresponding month. | |
120 | // value: | |
121 | // Either a Date or the number of seconds since 1970. | |
122 | // tags: | |
123 | // protected | |
124 | if(value){ | |
125 | // convert from Number to Date, or make copy of Date object so that setHours() call below | |
126 | // doesn't affect original value | |
127 | value = new this.dateClassObj(value); | |
128 | } | |
129 | if(this._isValidDate(value)){ | |
130 | if(!this._isValidDate(this.value) || this.dateFuncObj.compare(value, this.value)){ | |
131 | value.setHours(1, 0, 0, 0); // round to nearest day (1am to avoid issues when DST shift occurs at midnight, see #8521, #9366) | |
132 | ||
133 | if(!this.isDisabledDate(value, this.lang)){ | |
134 | this._set("value", value); | |
135 | ||
136 | // Set focus cell to the new value. Arguably this should only happen when there isn't a current | |
137 | // focus point. This will also repopulate the grid, showing the new selected value (and possibly | |
138 | // new month/year). | |
139 | this.set("currentFocus", value); | |
140 | ||
141 | if(priorityChange || typeof priorityChange == "undefined"){ | |
142 | this.onChange(this.get('value')); | |
143 | this.onValueSelected(this.get('value')); // remove in 2.0 | |
144 | } | |
145 | } | |
146 | } | |
147 | }else{ | |
148 | // clear value, and repopulate grid (to deselect the previously selected day) without changing currentFocus | |
149 | this._set("value", null); | |
150 | this.set("currentFocus", this.currentFocus); | |
151 | } | |
152 | }, | |
153 | ||
154 | _setText: function(node, text){ | |
155 | // summary: | |
156 | // This just sets the content of node to the specified text. | |
157 | // Can't do "node.innerHTML=text" because of an IE bug w/tables, see #3434. | |
158 | // tags: | |
159 | // private | |
160 | while(node.firstChild){ | |
161 | node.removeChild(node.firstChild); | |
162 | } | |
163 | node.appendChild(dojo.doc.createTextNode(text)); | |
164 | }, | |
165 | ||
166 | _populateGrid: function(){ | |
167 | // summary: | |
168 | // Fills in the calendar grid with each day (1-31) | |
169 | // tags: | |
170 | // private | |
171 | ||
172 | var month = new this.dateClassObj(this.currentFocus); | |
173 | month.setDate(1); | |
174 | ||
175 | var firstDay = month.getDay(), | |
176 | daysInMonth = this.dateFuncObj.getDaysInMonth(month), | |
177 | daysInPreviousMonth = this.dateFuncObj.getDaysInMonth(this.dateFuncObj.add(month, "month", -1)), | |
178 | today = new this.dateClassObj(), | |
179 | dayOffset = dojo.cldr.supplemental.getFirstDayOfWeek(this.lang); | |
180 | if(dayOffset > firstDay){ dayOffset -= 7; } | |
181 | ||
182 | // Iterate through dates in the calendar and fill in date numbers and style info | |
183 | dojo.query(".dijitCalendarDateTemplate", this.domNode).forEach(function(template, i){ | |
184 | i += dayOffset; | |
185 | var date = new this.dateClassObj(month), | |
186 | number, clazz = "dijitCalendar", adj = 0; | |
187 | ||
188 | if(i < firstDay){ | |
189 | number = daysInPreviousMonth - firstDay + i + 1; | |
190 | adj = -1; | |
191 | clazz += "Previous"; | |
192 | }else if(i >= (firstDay + daysInMonth)){ | |
193 | number = i - firstDay - daysInMonth + 1; | |
194 | adj = 1; | |
195 | clazz += "Next"; | |
196 | }else{ | |
197 | number = i - firstDay + 1; | |
198 | clazz += "Current"; | |
199 | } | |
200 | ||
201 | if(adj){ | |
202 | date = this.dateFuncObj.add(date, "month", adj); | |
203 | } | |
204 | date.setDate(number); | |
205 | ||
206 | if(!this.dateFuncObj.compare(date, today, "date")){ | |
207 | clazz = "dijitCalendarCurrentDate " + clazz; | |
208 | } | |
209 | ||
210 | if(this._isSelectedDate(date, this.lang)){ | |
211 | clazz = "dijitCalendarSelectedDate " + clazz; | |
212 | } | |
213 | ||
214 | if(this.isDisabledDate(date, this.lang)){ | |
215 | clazz = "dijitCalendarDisabledDate " + clazz; | |
216 | } | |
217 | ||
218 | var clazz2 = this.getClassForDate(date, this.lang); | |
219 | if(clazz2){ | |
220 | clazz = clazz2 + " " + clazz; | |
221 | } | |
222 | ||
223 | template.className = clazz + "Month dijitCalendarDateTemplate"; | |
224 | template.dijitDateValue = date.valueOf(); // original code | |
225 | dojo.attr(template, "dijitDateValue", date.valueOf()); // so I can dojo.query() it | |
226 | var label = dojo.query(".dijitCalendarDateLabel", template)[0], | |
227 | text = date.getDateLocalized ? date.getDateLocalized(this.lang) : date.getDate(); | |
228 | this._setText(label, text); | |
229 | }, this); | |
230 | ||
231 | // Repopulate month drop down list based on current year. | |
232 | // Need to do this to hide leap months in Hebrew calendar. | |
233 | var monthNames = this.dateLocaleModule.getNames('months', 'wide', 'standAlone', this.lang, month); | |
234 | this.monthDropDownButton.dropDown.set("months", monthNames); | |
235 | ||
236 | // Set name of current month and also fill in spacer element with all the month names | |
237 | // (invisible) so that the maximum width will affect layout. But not on IE6 because then | |
238 | // the center <TH> overlaps the right <TH> (due to a browser bug). | |
239 | this.monthDropDownButton.containerNode.innerHTML = | |
240 | (dojo.isIE == 6 ? "" : "<div class='dijitSpacer'>" + this.monthDropDownButton.dropDown.domNode.innerHTML + "</div>") + | |
241 | "<div class='dijitCalendarMonthLabel dijitCalendarCurrentMonthLabel'>" + monthNames[month.getMonth()] + "</div>"; | |
242 | ||
243 | // Fill in localized prev/current/next years | |
244 | var y = month.getFullYear() - 1; | |
245 | var d = new this.dateClassObj(); | |
246 | dojo.forEach(["previous", "current", "next"], function(name){ | |
247 | d.setFullYear(y++); | |
248 | this._setText(this[name+"YearLabelNode"], | |
249 | this.dateLocaleModule.format(d, {selector:'year', locale:this.lang})); | |
250 | }, this); | |
251 | }, | |
252 | ||
253 | goToToday: function(){ | |
254 | // summary: | |
255 | // Sets calendar's value to today's date | |
256 | this.set('value', new this.dateClassObj()); | |
257 | }, | |
258 | ||
259 | constructor: function(/*Object*/args){ | |
260 | var dateClass = (args.datePackage && (args.datePackage != "dojo.date"))? args.datePackage + ".Date" : "Date"; | |
261 | this.dateClassObj = dojo.getObject(dateClass, false); | |
262 | this.datePackage = args.datePackage || this.datePackage; | |
263 | this.dateFuncObj = dojo.getObject(this.datePackage, false); | |
264 | this.dateLocaleModule = dojo.getObject(this.datePackage + ".locale", false); | |
265 | }, | |
266 | ||
267 | postMixInProperties: function(){ | |
268 | // Parser.instantiate sometimes passes in NaN for IE. Use default value in prototype instead. | |
269 | // TODO: remove this for 2.0 (thanks to #11511) | |
270 | if(isNaN(this.value)){ delete this.value; } | |
271 | ||
272 | this.inherited(arguments); | |
273 | }, | |
274 | ||
275 | buildRendering: function(){ | |
276 | this.inherited(arguments); | |
277 | dojo.setSelectable(this.domNode, false); | |
278 | ||
279 | var cloneClass = dojo.hitch(this, function(clazz, n){ | |
280 | var template = dojo.query(clazz, this.domNode)[0]; | |
281 | for(var i=0; i<n; i++){ | |
282 | template.parentNode.appendChild(template.cloneNode(true)); | |
283 | } | |
284 | }); | |
285 | ||
286 | // clone the day label and calendar day templates 6 times to make 7 columns | |
287 | cloneClass(".dijitCalendarDayLabelTemplate", 6); | |
288 | cloneClass(".dijitCalendarDateTemplate", 6); | |
289 | ||
290 | // now make 6 week rows | |
291 | cloneClass(".dijitCalendarWeekTemplate", 5); | |
292 | ||
293 | // insert localized day names in the header | |
294 | var dayNames = this.dateLocaleModule.getNames('days', this.dayWidth, 'standAlone', this.lang); | |
295 | var dayOffset = dojo.cldr.supplemental.getFirstDayOfWeek(this.lang); | |
296 | dojo.query(".dijitCalendarDayLabel", this.domNode).forEach(function(label, i){ | |
297 | this._setText(label, dayNames[(i + dayOffset) % 7]); | |
298 | }, this); | |
299 | ||
300 | var dateObj = new this.dateClassObj(this.currentFocus); | |
301 | ||
302 | this.monthDropDownButton.dropDown = new dijit.Calendar._MonthDropDown({ | |
303 | id: this.id + "_mdd", | |
304 | onChange: dojo.hitch(this, "_onMonthSelect") | |
305 | }); | |
306 | ||
307 | this.set('currentFocus', dateObj, false); // draw the grid to the month specified by currentFocus | |
308 | ||
309 | // Set up repeating mouse behavior for increment/decrement of months/years | |
310 | var _this = this; | |
311 | var typematic = function(nodeProp, dateProp, adj){ | |
312 | _this._connects.push( | |
313 | dijit.typematic.addMouseListener(_this[nodeProp], _this, function(count){ | |
314 | if(count >= 0){ _this._adjustDisplay(dateProp, adj); } | |
315 | }, 0.8, 500) | |
316 | ); | |
317 | }; | |
318 | typematic("incrementMonth", "month", 1); | |
319 | typematic("decrementMonth", "month", -1); | |
320 | typematic("nextYearLabelNode", "year", 1); | |
321 | typematic("previousYearLabelNode", "year", -1); | |
322 | }, | |
323 | ||
324 | _adjustDisplay: function(/*String*/ part, /*int*/ amount){ | |
325 | // summary: | |
326 | // Moves calendar forwards or backwards by months or years | |
327 | // part: | |
328 | // "month" or "year" | |
329 | // amount: | |
330 | // Number of months or years | |
331 | // tags: | |
332 | // private | |
333 | this._setCurrentFocusAttr(this.dateFuncObj.add(this.currentFocus, part, amount)); | |
334 | }, | |
335 | ||
336 | _setCurrentFocusAttr: function(/*Date*/ date, /*Boolean*/ forceFocus){ | |
337 | // summary: | |
338 | // If the calendar currently has focus, then focuses specified date, | |
339 | // changing the currently displayed month/year if necessary. | |
340 | // If the calendar doesn't have focus, updates currently | |
341 | // displayed month/year, and sets the cell that will get focus. | |
342 | // forceFocus: | |
343 | // If true, will focus() the cell even if calendar itself doesn't have focus | |
344 | ||
345 | var oldFocus = this.currentFocus, | |
346 | oldCell = oldFocus ? dojo.query("[dijitDateValue=" + oldFocus.valueOf() + "]", this.domNode)[0] : null; | |
347 | ||
348 | // round specified value to nearest day (1am to avoid issues when DST shift occurs at midnight, see #8521, #9366) | |
349 | date = new this.dateClassObj(date); | |
350 | date.setHours(1, 0, 0, 0); | |
351 | ||
352 | this._set("currentFocus", date); | |
353 | ||
354 | // TODO: only re-populate grid when month/year has changed | |
355 | this._populateGrid(); | |
356 | ||
357 | // set tabIndex=0 on new cell, and focus it (but only if Calendar itself is focused) | |
358 | var newCell = dojo.query("[dijitDateValue=" + date.valueOf() + "]", this.domNode)[0]; | |
359 | newCell.setAttribute("tabIndex", this.tabIndex); | |
360 | if(this._focused || forceFocus){ | |
361 | newCell.focus(); | |
362 | } | |
363 | ||
364 | // set tabIndex=-1 on old focusable cell | |
365 | if(oldCell && oldCell != newCell){ | |
366 | if(dojo.isWebKit){ // see #11064 about webkit bug | |
367 | oldCell.setAttribute("tabIndex", "-1"); | |
368 | }else{ | |
369 | oldCell.removeAttribute("tabIndex"); | |
370 | } | |
371 | } | |
372 | }, | |
373 | ||
374 | focus: function(){ | |
375 | // summary: | |
376 | // Focus the calendar by focusing one of the calendar cells | |
377 | this._setCurrentFocusAttr(this.currentFocus, true); | |
378 | }, | |
379 | ||
380 | _onMonthSelect: function(/*Number*/ newMonth){ | |
381 | // summary: | |
382 | // Handler for when user selects a month from the drop down list | |
383 | // tags: | |
384 | // protected | |
385 | ||
386 | // move to selected month, bounding by the number of days in the month | |
387 | // (ex: dec 31 --> jan 28, not jan 31) | |
388 | this.currentFocus = this.dateFuncObj.add(this.currentFocus, "month", | |
389 | newMonth - this.currentFocus.getMonth()); | |
390 | this._populateGrid(); | |
391 | }, | |
392 | ||
393 | _onDayClick: function(/*Event*/ evt){ | |
394 | // summary: | |
395 | // Handler for day clicks, selects the date if appropriate | |
396 | // tags: | |
397 | // protected | |
398 | dojo.stopEvent(evt); | |
399 | for(var node = evt.target; node && !node.dijitDateValue; node = node.parentNode); | |
400 | if(node && !dojo.hasClass(node, "dijitCalendarDisabledDate")){ | |
401 | this.set('value', node.dijitDateValue); | |
402 | } | |
403 | }, | |
404 | ||
405 | _onDayMouseOver: function(/*Event*/ evt){ | |
406 | // summary: | |
407 | // Handler for mouse over events on days, sets hovered style | |
408 | // tags: | |
409 | // protected | |
410 | ||
411 | // event can occur on <td> or the <span> inside the td, | |
412 | // set node to the <td>. | |
413 | var node = | |
414 | dojo.hasClass(evt.target, "dijitCalendarDateLabel") ? | |
415 | evt.target.parentNode : | |
416 | evt.target; | |
417 | ||
418 | if(node && (node.dijitDateValue || node == this.previousYearLabelNode || node == this.nextYearLabelNode) ){ | |
419 | dojo.addClass(node, "dijitCalendarHoveredDate"); | |
420 | this._currentNode = node; | |
421 | } | |
422 | }, | |
423 | ||
424 | _onDayMouseOut: function(/*Event*/ evt){ | |
425 | // summary: | |
426 | // Handler for mouse out events on days, clears hovered style | |
427 | // tags: | |
428 | // protected | |
429 | ||
430 | if(!this._currentNode){ return; } | |
431 | ||
432 | // if mouse out occurs moving from <td> to <span> inside <td>, ignore it | |
433 | if(evt.relatedTarget && evt.relatedTarget.parentNode == this._currentNode){ return; } | |
434 | var cls = "dijitCalendarHoveredDate"; | |
435 | if(dojo.hasClass(this._currentNode, "dijitCalendarActiveDate")) { | |
436 | cls += " dijitCalendarActiveDate"; | |
437 | } | |
438 | dojo.removeClass(this._currentNode, cls); | |
439 | this._currentNode = null; | |
440 | }, | |
441 | ||
442 | _onDayMouseDown: function(/*Event*/ evt){ | |
443 | var node = evt.target.parentNode; | |
444 | if(node && node.dijitDateValue){ | |
445 | dojo.addClass(node, "dijitCalendarActiveDate"); | |
446 | this._currentNode = node; | |
447 | } | |
448 | }, | |
449 | ||
450 | _onDayMouseUp: function(/*Event*/ evt){ | |
451 | var node = evt.target.parentNode; | |
452 | if(node && node.dijitDateValue){ | |
453 | dojo.removeClass(node, "dijitCalendarActiveDate"); | |
454 | } | |
455 | }, | |
456 | ||
457 | //TODO: use typematic | |
458 | handleKey: function(/*Event*/ evt){ | |
459 | // summary: | |
460 | // Provides keyboard navigation of calendar. | |
461 | // description: | |
462 | // Called from _onKeyPress() to handle keypress on a stand alone Calendar, | |
463 | // and also from `dijit.form._DateTimeTextBox` to pass a keypress event | |
464 | // from the `dijit.form.DateTextBox` to be handled in this widget | |
465 | // returns: | |
466 | // False if the key was recognized as a navigation key, | |
467 | // to indicate that the event was handled by Calendar and shouldn't be propogated | |
468 | // tags: | |
469 | // protected | |
470 | var dk = dojo.keys, | |
471 | increment = -1, | |
472 | interval, | |
473 | newValue = this.currentFocus; | |
474 | switch(evt.keyCode){ | |
475 | case dk.RIGHT_ARROW: | |
476 | increment = 1; | |
477 | //fallthrough... | |
478 | case dk.LEFT_ARROW: | |
479 | interval = "day"; | |
480 | if(!this.isLeftToRight()){ increment *= -1; } | |
481 | break; | |
482 | case dk.DOWN_ARROW: | |
483 | increment = 1; | |
484 | //fallthrough... | |
485 | case dk.UP_ARROW: | |
486 | interval = "week"; | |
487 | break; | |
488 | case dk.PAGE_DOWN: | |
489 | increment = 1; | |
490 | //fallthrough... | |
491 | case dk.PAGE_UP: | |
492 | interval = evt.ctrlKey || evt.altKey ? "year" : "month"; | |
493 | break; | |
494 | case dk.END: | |
495 | // go to the next month | |
496 | newValue = this.dateFuncObj.add(newValue, "month", 1); | |
497 | // subtract a day from the result when we're done | |
498 | interval = "day"; | |
499 | //fallthrough... | |
500 | case dk.HOME: | |
501 | newValue = new this.dateClassObj(newValue); | |
502 | newValue.setDate(1); | |
503 | break; | |
504 | case dk.ENTER: | |
505 | case dk.SPACE: | |
506 | this.set("value", this.currentFocus); | |
507 | break; | |
508 | default: | |
509 | return true; | |
510 | } | |
511 | ||
512 | if(interval){ | |
513 | newValue = this.dateFuncObj.add(newValue, interval, increment); | |
514 | } | |
515 | ||
516 | this._setCurrentFocusAttr(newValue); | |
517 | ||
518 | return false; | |
519 | }, | |
520 | ||
521 | _onKeyPress: function(/*Event*/ evt){ | |
522 | // summary: | |
523 | // For handling keypress events on a stand alone calendar | |
524 | if(!this.handleKey(evt)){ | |
525 | dojo.stopEvent(evt); | |
526 | } | |
527 | }, | |
528 | ||
529 | onValueSelected: function(/*Date*/ date){ | |
530 | // summary: | |
531 | // Notification that a date cell was selected. It may be the same as the previous value. | |
532 | // description: | |
533 | // Formerly used by `dijit.form._DateTimeTextBox` (and thus `dijit.form.DateTextBox`) | |
534 | // to get notification when the user has clicked a date. Now onExecute() (above) is used. | |
535 | // tags: | |
536 | // protected | |
537 | }, | |
538 | ||
539 | onChange: function(/*Date*/ date){ | |
540 | // summary: | |
541 | // Called only when the selected date has changed | |
542 | }, | |
543 | ||
544 | _isSelectedDate: function(/*Date*/ dateObject, /*String?*/ locale){ | |
545 | // summary: | |
546 | // Extension point so developers can subclass Calendar to | |
547 | // support multiple (concurrently) selected dates | |
548 | // tags: | |
549 | // protected extension | |
550 | return this._isValidDate(this.value) && !this.dateFuncObj.compare(dateObject, this.value, "date") | |
551 | }, | |
552 | ||
553 | isDisabledDate: function(/*Date*/ dateObject, /*String?*/ locale){ | |
554 | // summary: | |
555 | // May be overridden to disable certain dates in the calendar e.g. `isDisabledDate=dojo.date.locale.isWeekend` | |
556 | // tags: | |
557 | // extension | |
558 | /*===== | |
559 | return false; // Boolean | |
560 | =====*/ | |
561 | }, | |
562 | ||
563 | getClassForDate: function(/*Date*/ dateObject, /*String?*/ locale){ | |
564 | // summary: | |
565 | // May be overridden to return CSS classes to associate with the date entry for the given dateObject, | |
566 | // for example to indicate a holiday in specified locale. | |
567 | // tags: | |
568 | // extension | |
569 | ||
570 | /*===== | |
571 | return ""; // String | |
572 | =====*/ | |
573 | } | |
574 | } | |
575 | ); | |
576 | ||
577 | dojo.declare("dijit.Calendar._MonthDropDown", [dijit._Widget, dijit._Templated], { | |
578 | // summary: | |
579 | // The month drop down | |
580 | ||
581 | // months: String[] | |
582 | // List of names of months, possibly w/some undefined entries for Hebrew leap months | |
583 | // (ex: ["January", "February", undefined, "April", ...]) | |
584 | months: [], | |
585 | ||
586 | templateString: "<div class='dijitCalendarMonthMenu dijitMenu' " + | |
587 | "dojoAttachEvent='onclick:_onClick,onmouseover:_onMenuHover,onmouseout:_onMenuHover'></div>", | |
588 | ||
589 | _setMonthsAttr: function(/*String[]*/ months){ | |
590 | this.domNode.innerHTML = dojo.map(months, function(month, idx){ | |
591 | return month ? "<div class='dijitCalendarMonthLabel' month='" + idx +"'>" + month + "</div>" : ""; | |
592 | }).join(""); | |
593 | }, | |
594 | ||
595 | _onClick: function(/*Event*/ evt){ | |
596 | this.onChange(dojo.attr(evt.target, "month")); | |
597 | }, | |
598 | ||
599 | onChange: function(/*Number*/ month){ | |
600 | // summary: | |
601 | // Callback when month is selected from drop down | |
602 | }, | |
603 | ||
604 | _onMenuHover: function(evt){ | |
605 | dojo.toggleClass(evt.target, "dijitCalendarMonthLabelHover", evt.type == "mouseover"); | |
606 | } | |
2f01fe57 | 607 | }); |
81bea17a | 608 | |
2f01fe57 | 609 | } |