1 | dojo.provide("dojox.widget.Calendar"); |
---|
2 | dojo.experimental("dojox.widget.Calendar"); |
---|
3 | |
---|
4 | dojo.require("dijit._Widget"); |
---|
5 | dojo.require("dijit._Templated"); |
---|
6 | dojo.require("dijit._Container"); |
---|
7 | dojo.require("dijit.typematic"); |
---|
8 | |
---|
9 | dojo.require("dojo.date"); |
---|
10 | dojo.require("dojo.date.locale"); |
---|
11 | |
---|
12 | dojo.declare("dojox.widget._CalendarBase", [dijit._Widget, dijit._Templated, dijit._Container], { |
---|
13 | // summary: |
---|
14 | // The Root class for all _Calendar extensions |
---|
15 | |
---|
16 | // templateString: String |
---|
17 | // The template to be used to construct the widget. |
---|
18 | templateString: dojo.cache("dojox.widget","Calendar/Calendar.html"), |
---|
19 | |
---|
20 | // _views: Array |
---|
21 | // The list of mixin views available on this calendar. |
---|
22 | _views: null, |
---|
23 | |
---|
24 | // useFx: Boolean |
---|
25 | // Specifies if visual effects should be applied to the widget. |
---|
26 | // The default behavior of the widget does not contain any effects. |
---|
27 | // The dojox.widget.CalendarFx package is needed for these. |
---|
28 | useFx: true, |
---|
29 | |
---|
30 | // widgetsInTemplate: Boolean |
---|
31 | // This widget is a container of other widgets, so this is true. |
---|
32 | widgetsInTemplate: true, |
---|
33 | |
---|
34 | // value: Date |
---|
35 | // The currently selected Date |
---|
36 | value: new Date(), |
---|
37 | |
---|
38 | constraints: null, |
---|
39 | |
---|
40 | // footerFormat: String |
---|
41 | // The date format of the date displayed in the footer. Can be |
---|
42 | // 'short', 'medium', and 'long' |
---|
43 | footerFormat: "medium", |
---|
44 | |
---|
45 | constructor: function(){ |
---|
46 | this._views = []; |
---|
47 | this.value = new Date(); |
---|
48 | }, |
---|
49 | |
---|
50 | postMixInProperties: function(){ |
---|
51 | var c = this.constraints; |
---|
52 | if(c){ |
---|
53 | var fromISO = dojo.date.stamp.fromISOString; |
---|
54 | if(typeof c.min == "string"){ |
---|
55 | c.min = fromISO(c.min); |
---|
56 | } |
---|
57 | if(typeof c.max == "string"){ |
---|
58 | c.max = fromISO(c.max); |
---|
59 | } |
---|
60 | } |
---|
61 | this.value = this.parseInitialValue(this.value); |
---|
62 | }, |
---|
63 | |
---|
64 | parseInitialValue: function(value){ |
---|
65 | if (!value || value === -1){ |
---|
66 | return new Date(); |
---|
67 | }else if(value.getFullYear){ |
---|
68 | return value; |
---|
69 | }else if (!isNaN(value)) { |
---|
70 | if (typeof this.value == "string") { |
---|
71 | value = parseInt(value); |
---|
72 | } |
---|
73 | value = this._makeDate(value); |
---|
74 | } |
---|
75 | return value; |
---|
76 | }, |
---|
77 | |
---|
78 | _makeDate: function(value){ |
---|
79 | return value;//new Date(value); |
---|
80 | }, |
---|
81 | |
---|
82 | postCreate: function(){ |
---|
83 | // summary: |
---|
84 | // Instantiates the mixin views |
---|
85 | |
---|
86 | this.displayMonth = new Date(this.get('value')); |
---|
87 | |
---|
88 | if(this._isInvalidDate(this.displayMonth)){ |
---|
89 | this.displayMonth = new Date(); |
---|
90 | } |
---|
91 | |
---|
92 | var mixin = { |
---|
93 | parent: this, |
---|
94 | _getValueAttr: dojo.hitch(this, function(){return new Date(this._internalValue || this.value);}), |
---|
95 | _getDisplayMonthAttr: dojo.hitch(this, function(){return new Date(this.displayMonth);}), |
---|
96 | _getConstraintsAttr: dojo.hitch(this, function(){return this.constraints;}), |
---|
97 | getLang: dojo.hitch(this, function(){return this.lang;}), |
---|
98 | isDisabledDate: dojo.hitch(this, this.isDisabledDate), |
---|
99 | getClassForDate: dojo.hitch(this, this.getClassForDate), |
---|
100 | addFx: this.useFx ? dojo.hitch(this, this.addFx) : function(){} |
---|
101 | }; |
---|
102 | |
---|
103 | //Add the mixed in views. |
---|
104 | dojo.forEach(this._views, function(widgetType){ |
---|
105 | var widget = new widgetType(mixin, dojo.create('div')); |
---|
106 | this.addChild(widget); |
---|
107 | |
---|
108 | var header = widget.getHeader(); |
---|
109 | if(header){ |
---|
110 | //place the views's header node in the header of the main widget |
---|
111 | this.header.appendChild(header); |
---|
112 | |
---|
113 | //hide the header node of the widget |
---|
114 | dojo.style(header, "display", "none"); |
---|
115 | } |
---|
116 | //Hide all views |
---|
117 | dojo.style(widget.domNode, "visibility", "hidden"); |
---|
118 | |
---|
119 | //Listen for the values in a view to be selected |
---|
120 | dojo.connect(widget, "onValueSelected", this, "_onDateSelected"); |
---|
121 | widget.set("value", this.get('value')); |
---|
122 | }, this); |
---|
123 | |
---|
124 | if(this._views.length < 2){ |
---|
125 | dojo.style(this.header, "cursor", "auto"); |
---|
126 | } |
---|
127 | |
---|
128 | this.inherited(arguments); |
---|
129 | |
---|
130 | // Cache the list of children widgets. |
---|
131 | this._children = this.getChildren(); |
---|
132 | |
---|
133 | this._currentChild = 0; |
---|
134 | |
---|
135 | //Populate the footer with today's date. |
---|
136 | var today = new Date(); |
---|
137 | |
---|
138 | this.footer.innerHTML = "Today: " |
---|
139 | + dojo.date.locale.format(today, { |
---|
140 | formatLength:this.footerFormat, |
---|
141 | selector:'date', |
---|
142 | locale:this.lang}); |
---|
143 | |
---|
144 | dojo.connect(this.footer, "onclick", this, "goToToday"); |
---|
145 | |
---|
146 | var first = this._children[0]; |
---|
147 | |
---|
148 | dojo.style(first.domNode, "top", "0px"); |
---|
149 | dojo.style(first.domNode, "visibility", "visible"); |
---|
150 | |
---|
151 | var header = first.getHeader(); |
---|
152 | if(header){ |
---|
153 | dojo.style(first.getHeader(), "display", ""); |
---|
154 | } |
---|
155 | |
---|
156 | dojo[first.useHeader ? "removeClass" : "addClass"](this.container, "no-header"); |
---|
157 | |
---|
158 | first.onDisplay(); |
---|
159 | |
---|
160 | var _this = this; |
---|
161 | |
---|
162 | var typematic = function(nodeProp, dateProp, adj){ |
---|
163 | dijit.typematic.addMouseListener(_this[nodeProp], _this, function(count){ |
---|
164 | if(count >= 0){ _this._adjustDisplay(dateProp, adj);} |
---|
165 | }, 0.8, 500); |
---|
166 | }; |
---|
167 | typematic("incrementMonth", "month", 1); |
---|
168 | typematic("decrementMonth", "month", -1); |
---|
169 | this._updateTitleStyle(); |
---|
170 | }, |
---|
171 | |
---|
172 | addFx: function(query, fromNode){ |
---|
173 | // Stub function than can be overridden to add effects. |
---|
174 | }, |
---|
175 | |
---|
176 | _isInvalidDate: function(/*Date*/ value){ |
---|
177 | // summary: |
---|
178 | // Runs various tests on the value, checking for invalid conditions |
---|
179 | // tags: |
---|
180 | // private |
---|
181 | return !value || isNaN(value) || typeof value != "object" || value.toString() == this._invalidDate; |
---|
182 | }, |
---|
183 | |
---|
184 | _setValueAttr: function(/*Date*/ value){ |
---|
185 | // summary: |
---|
186 | // Set the current date and update the UI. If the date is disabled, the selection will |
---|
187 | // not change, but the display will change to the corresponding month. |
---|
188 | if(!value){ |
---|
189 | value = new Date(); |
---|
190 | } |
---|
191 | if(!value["getFullYear"]){ |
---|
192 | value = dojo.date.stamp.fromISOString(value + ""); |
---|
193 | } |
---|
194 | if(this._isInvalidDate(value)){ |
---|
195 | return false; |
---|
196 | } |
---|
197 | if(!this.value || dojo.date.compare(value, this.value)){ |
---|
198 | value = new Date(value); |
---|
199 | this.displayMonth = new Date(value); |
---|
200 | this._internalValue = value; |
---|
201 | if(!this.isDisabledDate(value, this.lang) && this._currentChild == 0){ |
---|
202 | this.value = value; |
---|
203 | this.onChange(value); |
---|
204 | } |
---|
205 | if (this._children && this._children.length > 0) { |
---|
206 | this._children[this._currentChild].set("value", this.value); |
---|
207 | } |
---|
208 | return true; |
---|
209 | } |
---|
210 | return false; |
---|
211 | }, |
---|
212 | |
---|
213 | isDisabledDate: function(/*Date*/date, /*String?*/locale){ |
---|
214 | // summary: |
---|
215 | // May be overridden to disable certain dates in the calendar e.g. `isDisabledDate=dojo.date.locale.isWeekend` |
---|
216 | var c = this.constraints; |
---|
217 | var compare = dojo.date.compare; |
---|
218 | return c && (c.min && (compare(c.min, date, "date") > 0) || |
---|
219 | (c.max && compare(c.max, date, "date") < 0)); |
---|
220 | }, |
---|
221 | |
---|
222 | onValueSelected: function(/*Date*/date){ |
---|
223 | // summary: |
---|
224 | // A date cell was selected. It may be the same as the previous value. |
---|
225 | }, |
---|
226 | |
---|
227 | _onDateSelected: function(date, formattedValue, force){ |
---|
228 | this.displayMonth = date; |
---|
229 | |
---|
230 | this.set("value", date) |
---|
231 | //Only change the selected value if it was chosen from the |
---|
232 | //first child. |
---|
233 | if(!this._transitionVert(-1)){ |
---|
234 | if(!formattedValue && formattedValue !== 0){ |
---|
235 | formattedValue = this.get('value'); |
---|
236 | } |
---|
237 | this.onValueSelected(formattedValue); |
---|
238 | } |
---|
239 | |
---|
240 | }, |
---|
241 | |
---|
242 | onChange: function(/*Date*/date){ |
---|
243 | // summary: |
---|
244 | // Called only when the selected date has changed |
---|
245 | }, |
---|
246 | |
---|
247 | onHeaderClick: function(e){ |
---|
248 | // summary: |
---|
249 | // Transitions to the next view. |
---|
250 | this._transitionVert(1); |
---|
251 | }, |
---|
252 | |
---|
253 | goToToday: function(){ |
---|
254 | this.set("value", new Date()); |
---|
255 | this.onValueSelected(this.get('value')); |
---|
256 | }, |
---|
257 | |
---|
258 | _transitionVert: function(/*Number*/direction){ |
---|
259 | // summary: |
---|
260 | // Animates the views to show one and hide another, in a |
---|
261 | // vertical direction. |
---|
262 | // If 'direction' is 1, then the views slide upwards. |
---|
263 | // If 'direction' is -1, the views slide downwards. |
---|
264 | var curWidget = this._children[this._currentChild]; |
---|
265 | var nextWidget = this._children[this._currentChild + direction]; |
---|
266 | if(!nextWidget){return false;} |
---|
267 | |
---|
268 | dojo.style(nextWidget.domNode, "visibility", "visible"); |
---|
269 | |
---|
270 | var height = dojo.style(this.containerNode, "height"); |
---|
271 | nextWidget.set("value", this.displayMonth); |
---|
272 | |
---|
273 | if(curWidget.header){ |
---|
274 | dojo.style(curWidget.header, "display", "none"); |
---|
275 | } |
---|
276 | if(nextWidget.header){ |
---|
277 | dojo.style(nextWidget.header, "display", ""); |
---|
278 | } |
---|
279 | dojo.style(nextWidget.domNode, "top", (height * -1) + "px"); |
---|
280 | dojo.style(nextWidget.domNode, "visibility", "visible"); |
---|
281 | |
---|
282 | this._currentChild += direction; |
---|
283 | |
---|
284 | var height1 = height * direction; |
---|
285 | var height2 = 0; |
---|
286 | dojo.style(nextWidget.domNode, "top", (height1 * -1) + "px"); |
---|
287 | |
---|
288 | // summary: Slides two nodes vertically. |
---|
289 | var anim1 = dojo.animateProperty({ |
---|
290 | node: curWidget.domNode, |
---|
291 | properties: {top: height1}, |
---|
292 | onEnd: function(){ |
---|
293 | dojo.style(curWidget.domNode, "visibility", "hidden"); |
---|
294 | } |
---|
295 | }); |
---|
296 | var anim2 = dojo.animateProperty({ |
---|
297 | node: nextWidget.domNode, |
---|
298 | properties: {top: height2}, |
---|
299 | onEnd: function(){ |
---|
300 | nextWidget.onDisplay(); |
---|
301 | } |
---|
302 | }); |
---|
303 | |
---|
304 | dojo[nextWidget.useHeader ? "removeClass" : "addClass"](this.container, "no-header"); |
---|
305 | |
---|
306 | anim1.play(); |
---|
307 | anim2.play(); |
---|
308 | curWidget.onBeforeUnDisplay() |
---|
309 | nextWidget.onBeforeDisplay(); |
---|
310 | |
---|
311 | this._updateTitleStyle(); |
---|
312 | return true; |
---|
313 | }, |
---|
314 | |
---|
315 | _updateTitleStyle: function(){ |
---|
316 | dojo[this._currentChild < this._children.length -1 ? "addClass" : "removeClass"](this.header, "navToPanel"); |
---|
317 | }, |
---|
318 | |
---|
319 | _slideTable: function(/*String*/widget, /*Number*/direction, /*Function*/callback){ |
---|
320 | // summary: |
---|
321 | // Animates the horizontal sliding of a table. |
---|
322 | var table = widget.domNode; |
---|
323 | |
---|
324 | //Clone the existing table |
---|
325 | var newTable = table.cloneNode(true); |
---|
326 | var left = dojo.style(table, "width"); |
---|
327 | |
---|
328 | table.parentNode.appendChild(newTable); |
---|
329 | |
---|
330 | //Place the existing node either to the left or the right of the new node, |
---|
331 | //depending on which direction it is to slide. |
---|
332 | dojo.style(table, "left", (left * direction) + "px"); |
---|
333 | |
---|
334 | //Call the function that generally populates the new cloned node with new data. |
---|
335 | //It may also attach event listeners. |
---|
336 | callback(); |
---|
337 | |
---|
338 | //Animate the two nodes. |
---|
339 | var anim1 = dojo.animateProperty({node: newTable, properties:{left: left * direction * -1}, duration: 500, onEnd: function(){ |
---|
340 | newTable.parentNode.removeChild(newTable); |
---|
341 | }}); |
---|
342 | var anim2 = dojo.animateProperty({node: table, properties:{left: 0}, duration: 500}); |
---|
343 | |
---|
344 | anim1.play(); |
---|
345 | anim2.play(); |
---|
346 | }, |
---|
347 | |
---|
348 | _addView: function(view){ |
---|
349 | //Insert the view at the start of the array. |
---|
350 | this._views.push(view); |
---|
351 | }, |
---|
352 | |
---|
353 | getClassForDate: function(/*Date*/dateObject, /*String?*/locale){ |
---|
354 | // summary: |
---|
355 | // May be overridden to return CSS classes to associate with the date entry for the given dateObject, |
---|
356 | // for example to indicate a holiday in specified locale. |
---|
357 | |
---|
358 | /*===== |
---|
359 | return ""; // String |
---|
360 | =====*/ |
---|
361 | }, |
---|
362 | |
---|
363 | _adjustDisplay: function(/*String*/part, /*int*/amount, noSlide){ |
---|
364 | // summary: |
---|
365 | // This function overrides the base function defined in dijit.Calendar. |
---|
366 | // It changes the displayed years, months and days depending on the inputs. |
---|
367 | var child = this._children[this._currentChild]; |
---|
368 | |
---|
369 | var month = this.displayMonth = child.adjustDate(this.displayMonth, amount); |
---|
370 | |
---|
371 | this._slideTable(child, amount, function(){ |
---|
372 | child.set("value", month); |
---|
373 | }); |
---|
374 | } |
---|
375 | }); |
---|
376 | |
---|
377 | dojo.declare("dojox.widget._CalendarView", dijit._Widget, { |
---|
378 | // summary: |
---|
379 | // Base implementation for all view mixins. |
---|
380 | // All calendar views should extend this widget. |
---|
381 | headerClass: "", |
---|
382 | |
---|
383 | useHeader: true, |
---|
384 | |
---|
385 | cloneClass: function(clazz, n, before){ |
---|
386 | // summary: |
---|
387 | // Clones all nodes with the class 'clazz' in a widget |
---|
388 | var template = dojo.query(clazz, this.domNode)[0]; |
---|
389 | var i; |
---|
390 | if(!before){ |
---|
391 | for(i = 0; i < n; i++){ |
---|
392 | template.parentNode.appendChild(template.cloneNode(true)); |
---|
393 | } |
---|
394 | }else{ |
---|
395 | var bNode = dojo.query(clazz, this.domNode)[0]; |
---|
396 | for(i = 0; i < n; i++){ |
---|
397 | template.parentNode.insertBefore(template.cloneNode(true), bNode); |
---|
398 | } |
---|
399 | } |
---|
400 | }, |
---|
401 | |
---|
402 | _setText: function(node, text){ |
---|
403 | // summary: |
---|
404 | // Sets the text inside a node |
---|
405 | if(node.innerHTML != text){ |
---|
406 | dojo.empty(node); |
---|
407 | node.appendChild(dojo.doc.createTextNode(text)); |
---|
408 | } |
---|
409 | }, |
---|
410 | |
---|
411 | getHeader: function(){ |
---|
412 | // summary: |
---|
413 | // Returns the header node of a view. If none exists, |
---|
414 | // an empty DIV is created and returned. |
---|
415 | return this.header || (this.header = this.header = dojo.create("span", { "class":this.headerClass })); |
---|
416 | }, |
---|
417 | |
---|
418 | onValueSelected: function(date){ |
---|
419 | //Stub function called when a date is selected |
---|
420 | }, |
---|
421 | |
---|
422 | adjustDate: function(date, amount){ |
---|
423 | // summary: |
---|
424 | // Adds or subtracts values from a date. |
---|
425 | // The unit, e.g. "day", "month" or "year", is |
---|
426 | // specified in the "datePart" property of the |
---|
427 | // calendar view mixin. |
---|
428 | return dojo.date.add(date, this.datePart, amount); |
---|
429 | }, |
---|
430 | |
---|
431 | onDisplay: function(){ |
---|
432 | // summary: |
---|
433 | // Stub function that can be used to tell a view when it is shown. |
---|
434 | }, |
---|
435 | |
---|
436 | onBeforeDisplay: function(){ |
---|
437 | // summary: |
---|
438 | // Stub function that can be used to tell a view it is about to be shown. |
---|
439 | }, |
---|
440 | |
---|
441 | onBeforeUnDisplay: function(){ |
---|
442 | // summary: |
---|
443 | // Stub function that can be used to tell |
---|
444 | // a view when it is no longer shown. |
---|
445 | } |
---|
446 | }); |
---|
447 | |
---|
448 | dojo.declare("dojox.widget._CalendarDay", null, { |
---|
449 | // summary: |
---|
450 | // Mixin for the dojox.widget.Calendar which provides |
---|
451 | // the standard day-view. A single month is shown at a time. |
---|
452 | parent: null, |
---|
453 | |
---|
454 | constructor: function(){ |
---|
455 | this._addView(dojox.widget._CalendarDayView); |
---|
456 | } |
---|
457 | }); |
---|
458 | |
---|
459 | dojo.declare("dojox.widget._CalendarDayView", [dojox.widget._CalendarView, dijit._Templated], { |
---|
460 | // summary: View class for the dojox.widget.Calendar. |
---|
461 | // Adds a view showing every day of a single month to the calendar. |
---|
462 | // This should not be mixed in directly with dojox.widget._CalendarBase. |
---|
463 | // Instead, use dojox.widget._CalendarDay |
---|
464 | |
---|
465 | // templateString: String |
---|
466 | // The template to be used to construct the widget. |
---|
467 | templateString: dojo.cache("dojox.widget","Calendar/CalendarDay.html"), |
---|
468 | |
---|
469 | // datePart: String |
---|
470 | // Specifies how much to increment the displayed date when the user |
---|
471 | // clicks the array button to increment of decrement the view. |
---|
472 | datePart: "month", |
---|
473 | |
---|
474 | // dayWidth: String |
---|
475 | // Specifies the type of day name to display. "narrow" causes just one letter to be shown. |
---|
476 | dayWidth: "narrow", |
---|
477 | |
---|
478 | postCreate: function(){ |
---|
479 | // summary: |
---|
480 | // Constructs the calendar view. |
---|
481 | this.cloneClass(".dijitCalendarDayLabelTemplate", 6); |
---|
482 | this.cloneClass(".dijitCalendarDateTemplate", 6); |
---|
483 | |
---|
484 | // now make 6 week rows |
---|
485 | this.cloneClass(".dijitCalendarWeekTemplate", 5); |
---|
486 | |
---|
487 | // insert localized day names in the header |
---|
488 | var dayNames = dojo.date.locale.getNames('days', this.dayWidth, 'standAlone', this.getLang()); |
---|
489 | var dayOffset = dojo.cldr.supplemental.getFirstDayOfWeek(this.getLang()); |
---|
490 | |
---|
491 | // Set the text of the day labels. |
---|
492 | dojo.query(".dijitCalendarDayLabel", this.domNode).forEach(function(label, i){ |
---|
493 | this._setText(label, dayNames[(i + dayOffset) % 7]); |
---|
494 | }, this); |
---|
495 | }, |
---|
496 | |
---|
497 | onDisplay: function(){ |
---|
498 | if(!this._addedFx){ |
---|
499 | // Add visual effects to the view, if any has been specified. |
---|
500 | this._addedFx = true; |
---|
501 | this.addFx(".dijitCalendarDateTemplate div", this.domNode); |
---|
502 | } |
---|
503 | }, |
---|
504 | |
---|
505 | _onDayClick: function(e){ |
---|
506 | // summary: |
---|
507 | // Executed when a day value is clicked. |
---|
508 | |
---|
509 | // If the user somehow clicked the TR, rather than a |
---|
510 | // cell, ignore it. |
---|
511 | if(typeof(e.target._date) == "undefined"){return;} |
---|
512 | |
---|
513 | var date = new Date(this.get("displayMonth")); |
---|
514 | |
---|
515 | var p = e.target.parentNode; |
---|
516 | var c = "dijitCalendar"; |
---|
517 | var d = dojo.hasClass(p, c + "PreviousMonth") ? -1 : |
---|
518 | (dojo.hasClass(p, c + "NextMonth") ? 1 : 0); |
---|
519 | if(d){date = dojo.date.add(date, "month", d)} |
---|
520 | date.setDate(e.target._date); |
---|
521 | |
---|
522 | // If the day is disabled, ignore it |
---|
523 | if(this.isDisabledDate(date)){ |
---|
524 | dojo.stopEvent(e); |
---|
525 | return; |
---|
526 | } |
---|
527 | this.parent._onDateSelected(date); |
---|
528 | }, |
---|
529 | |
---|
530 | _setValueAttr: function(value){ |
---|
531 | //Change the day values |
---|
532 | this._populateDays(); |
---|
533 | }, |
---|
534 | |
---|
535 | _populateDays: function(){ |
---|
536 | // summary: |
---|
537 | // Fills the days of the current month. |
---|
538 | |
---|
539 | var currentDate = new Date(this.get("displayMonth")); |
---|
540 | currentDate.setDate(1); |
---|
541 | var firstDay = currentDate.getDay(); |
---|
542 | var daysInMonth = dojo.date.getDaysInMonth(currentDate); |
---|
543 | var daysInPreviousMonth = dojo.date.getDaysInMonth(dojo.date.add(currentDate, "month", -1)); |
---|
544 | var today = new Date(); |
---|
545 | var selected = this.get('value'); |
---|
546 | |
---|
547 | var dayOffset = dojo.cldr.supplemental.getFirstDayOfWeek(this.getLang()); |
---|
548 | if(dayOffset > firstDay){ dayOffset -= 7; } |
---|
549 | |
---|
550 | var compareDate = dojo.date.compare; |
---|
551 | var templateCls = ".dijitCalendarDateTemplate"; |
---|
552 | var selectedCls = "dijitCalendarSelectedDate"; |
---|
553 | |
---|
554 | var oldDate = this._lastDate; |
---|
555 | var redrawRequired = oldDate == null |
---|
556 | || oldDate.getMonth() != currentDate.getMonth() |
---|
557 | || oldDate.getFullYear() != currentDate.getFullYear(); |
---|
558 | this._lastDate = currentDate; |
---|
559 | |
---|
560 | // If still showing the same month, it's much faster to not redraw, |
---|
561 | // and just change the selected date. |
---|
562 | if(!redrawRequired){ |
---|
563 | dojo.query(templateCls, this.domNode) |
---|
564 | .removeClass(selectedCls) |
---|
565 | .filter(function(node){ |
---|
566 | return node.className.indexOf("dijitCalendarCurrent") > -1 |
---|
567 | && node._date == selected.getDate(); |
---|
568 | }) |
---|
569 | .addClass(selectedCls); |
---|
570 | return; |
---|
571 | } |
---|
572 | |
---|
573 | // Iterate through dates in the calendar and fill in date numbers and style info |
---|
574 | dojo.query(templateCls, this.domNode).forEach(function(template, i){ |
---|
575 | i += dayOffset; |
---|
576 | var date = new Date(currentDate); |
---|
577 | var number, clazz = "dijitCalendar", adj = 0; |
---|
578 | |
---|
579 | if(i < firstDay){ |
---|
580 | number = daysInPreviousMonth - firstDay + i + 1; |
---|
581 | adj = -1; |
---|
582 | clazz += "Previous"; |
---|
583 | }else if(i >= (firstDay + daysInMonth)){ |
---|
584 | number = i - firstDay - daysInMonth + 1; |
---|
585 | adj = 1; |
---|
586 | clazz += "Next"; |
---|
587 | }else{ |
---|
588 | number = i - firstDay + 1; |
---|
589 | clazz += "Current"; |
---|
590 | } |
---|
591 | |
---|
592 | if(adj){ |
---|
593 | date = dojo.date.add(date, "month", adj); |
---|
594 | } |
---|
595 | date.setDate(number); |
---|
596 | |
---|
597 | if(!compareDate(date, today, "date")){ |
---|
598 | clazz = "dijitCalendarCurrentDate " + clazz; |
---|
599 | } |
---|
600 | |
---|
601 | if(!compareDate(date, selected, "date") |
---|
602 | && !compareDate(date, selected, "month") |
---|
603 | && !compareDate(date, selected, "year") ){ |
---|
604 | clazz = selectedCls + " " + clazz; |
---|
605 | } |
---|
606 | |
---|
607 | if(this.isDisabledDate(date, this.getLang())){ |
---|
608 | clazz = " dijitCalendarDisabledDate " + clazz; |
---|
609 | } |
---|
610 | |
---|
611 | var clazz2 = this.getClassForDate(date, this.getLang()); |
---|
612 | if(clazz2){ |
---|
613 | clazz = clazz2 + " " + clazz; |
---|
614 | } |
---|
615 | |
---|
616 | template.className = clazz + "Month dijitCalendarDateTemplate"; |
---|
617 | template.dijitDateValue = date.valueOf(); |
---|
618 | var label = dojo.query(".dijitCalendarDateLabel", template)[0]; |
---|
619 | |
---|
620 | this._setText(label, date.getDate()); |
---|
621 | |
---|
622 | label._date = label.parentNode._date = date.getDate(); |
---|
623 | }, this); |
---|
624 | |
---|
625 | // Fill in localized month name |
---|
626 | var monthNames = dojo.date.locale.getNames('months', 'wide', 'standAlone', this.getLang()); |
---|
627 | this._setText(this.monthLabelNode, monthNames[currentDate.getMonth()]); |
---|
628 | this._setText(this.yearLabelNode, currentDate.getFullYear()); |
---|
629 | } |
---|
630 | }); |
---|
631 | |
---|
632 | |
---|
633 | dojo.declare("dojox.widget._CalendarMonthYear", null, { |
---|
634 | // summary: |
---|
635 | // Mixin class for adding a view listing all 12 |
---|
636 | // months of the year to the dojox.widget._CalendarBase |
---|
637 | |
---|
638 | constructor: function(){ |
---|
639 | // summary: |
---|
640 | // Adds a dojox.widget._CalendarMonthView view to the calendar widget. |
---|
641 | this._addView(dojox.widget._CalendarMonthYearView); |
---|
642 | } |
---|
643 | }); |
---|
644 | |
---|
645 | dojo.declare("dojox.widget._CalendarMonthYearView", [dojox.widget._CalendarView, dijit._Templated], { |
---|
646 | // summary: |
---|
647 | // A Calendar view listing the 12 months of the year |
---|
648 | |
---|
649 | // templateString: String |
---|
650 | // The template to be used to construct the widget. |
---|
651 | templateString: dojo.cache("dojox.widget","Calendar/CalendarMonthYear.html"), |
---|
652 | |
---|
653 | // datePart: String |
---|
654 | // Specifies how much to increment the displayed date when the user |
---|
655 | // clicks the array button to increment of decrement the view. |
---|
656 | datePart: "year", |
---|
657 | |
---|
658 | // displayedYears: Number |
---|
659 | // The number of years to display at once. |
---|
660 | displayedYears: 10, |
---|
661 | |
---|
662 | useHeader: false, |
---|
663 | |
---|
664 | postCreate: function(){ |
---|
665 | this.cloneClass(".dojoxCal-MY-G-Template", 5, ".dojoxCal-MY-btns"); |
---|
666 | this.monthContainer = this.yearContainer = this.myContainer; |
---|
667 | |
---|
668 | var yClass = "dojoxCalendarYearLabel"; |
---|
669 | var dClass = "dojoxCalendarDecrease"; |
---|
670 | var iClass = "dojoxCalendarIncrease"; |
---|
671 | |
---|
672 | dojo.query("." + yClass, this.myContainer).forEach(function(node, idx){ |
---|
673 | var clazz = iClass; |
---|
674 | switch(idx){ |
---|
675 | case 0: |
---|
676 | clazz = dClass; |
---|
677 | case 1: |
---|
678 | dojo.removeClass(node, yClass); |
---|
679 | dojo.addClass(node, clazz); |
---|
680 | break; |
---|
681 | } |
---|
682 | }); |
---|
683 | // Get the year increment and decrement buttons. |
---|
684 | this._decBtn = dojo.query('.' + dClass, this.myContainer)[0]; |
---|
685 | this._incBtn = dojo.query('.' + iClass, this.myContainer)[0]; |
---|
686 | |
---|
687 | dojo.query(".dojoxCal-MY-M-Template", this.domNode) |
---|
688 | .filter(function(item){ |
---|
689 | return item.cellIndex == 1; |
---|
690 | }) |
---|
691 | .addClass("dojoxCal-MY-M-last"); |
---|
692 | |
---|
693 | dojo.connect(this, "onBeforeDisplay", dojo.hitch(this, function(){ |
---|
694 | this._cachedDate = new Date(this.get("value").getTime()); |
---|
695 | this._populateYears(this._cachedDate.getFullYear()); |
---|
696 | this._populateMonths(); |
---|
697 | this._updateSelectedMonth(); |
---|
698 | this._updateSelectedYear(); |
---|
699 | })); |
---|
700 | |
---|
701 | dojo.connect(this, "_populateYears", dojo.hitch(this, function(){ |
---|
702 | this._updateSelectedYear(); |
---|
703 | })); |
---|
704 | dojo.connect(this, "_populateMonths", dojo.hitch(this, function(){ |
---|
705 | this._updateSelectedMonth(); |
---|
706 | })); |
---|
707 | |
---|
708 | this._cachedDate = this.get("value"); |
---|
709 | |
---|
710 | this._populateYears(); |
---|
711 | this._populateMonths(); |
---|
712 | |
---|
713 | // Add visual effects to the view, if any have been mixed in |
---|
714 | this.addFx(".dojoxCalendarMonthLabel,.dojoxCalendarYearLabel ", this.myContainer); |
---|
715 | }, |
---|
716 | |
---|
717 | _setValueAttr: function(value){ |
---|
718 | if (value && value.getFullYear()) { |
---|
719 | this._populateYears(value.getFullYear()); |
---|
720 | } |
---|
721 | }, |
---|
722 | |
---|
723 | getHeader: function(){ |
---|
724 | return null; |
---|
725 | }, |
---|
726 | |
---|
727 | _getMonthNames: function(format){ |
---|
728 | // summary: |
---|
729 | // Returns localized month names |
---|
730 | this._monthNames = this._monthNames || dojo.date.locale.getNames('months', format, 'standAlone', this.getLang()); |
---|
731 | return this._monthNames; |
---|
732 | }, |
---|
733 | |
---|
734 | _populateMonths: function(){ |
---|
735 | // summary: |
---|
736 | // Populate the month names using the localized values. |
---|
737 | var monthNames = this._getMonthNames('abbr'); |
---|
738 | dojo.query(".dojoxCalendarMonthLabel", this.monthContainer).forEach(dojo.hitch(this, function(node, cnt){ |
---|
739 | this._setText(node, monthNames[cnt]); |
---|
740 | })); |
---|
741 | var constraints = this.get('constraints'); |
---|
742 | |
---|
743 | if(constraints){ |
---|
744 | var date = new Date(); |
---|
745 | date.setFullYear(this._year); |
---|
746 | var min = -1, max = 12; |
---|
747 | if(constraints.min){ |
---|
748 | var minY = constraints.min.getFullYear(); |
---|
749 | if(minY > this._year){ |
---|
750 | min = 12; |
---|
751 | }else if(minY == this._year){ |
---|
752 | min = constraints.min.getMonth(); |
---|
753 | } |
---|
754 | } |
---|
755 | if(constraints.max){ |
---|
756 | var maxY = constraints.max.getFullYear(); |
---|
757 | if(maxY < this._year){ |
---|
758 | max = -1; |
---|
759 | }else if(maxY == this._year){ |
---|
760 | max = constraints.max.getMonth(); |
---|
761 | } |
---|
762 | } |
---|
763 | |
---|
764 | dojo.query(".dojoxCalendarMonthLabel", this.monthContainer) |
---|
765 | .forEach(dojo.hitch(this, function(node, cnt){ |
---|
766 | dojo[(cnt < min || cnt > max) ? "addClass" : "removeClass"] |
---|
767 | (node, 'dijitCalendarDisabledDate'); |
---|
768 | })); |
---|
769 | } |
---|
770 | |
---|
771 | var h = this.getHeader(); |
---|
772 | if(h){ |
---|
773 | this._setText(this.getHeader(), this.get("value").getFullYear()); |
---|
774 | } |
---|
775 | }, |
---|
776 | |
---|
777 | _populateYears: function(year){ |
---|
778 | // summary: |
---|
779 | // Fills the list of years with a range of 12 numbers, with the current year |
---|
780 | // being the 6th number. |
---|
781 | var constraints = this.get('constraints'); |
---|
782 | var dispYear = year || this.get("value").getFullYear(); |
---|
783 | var firstYear = dispYear - Math.floor(this.displayedYears/2); |
---|
784 | var min = constraints && constraints.min ? constraints.min.getFullYear() : firstYear -10000; |
---|
785 | firstYear = Math.max(min, firstYear); |
---|
786 | |
---|
787 | // summary: Writes the years to display to the view |
---|
788 | this._displayedYear = dispYear; |
---|
789 | |
---|
790 | var yearLabels = dojo.query(".dojoxCalendarYearLabel", this.yearContainer); |
---|
791 | |
---|
792 | var max = constraints && constraints.max ? constraints.max.getFullYear() - firstYear : yearLabels.length; |
---|
793 | var disabledClass = 'dijitCalendarDisabledDate'; |
---|
794 | |
---|
795 | yearLabels.forEach(dojo.hitch(this, function(node, cnt){ |
---|
796 | if(cnt <= max){ |
---|
797 | this._setText(node, firstYear + cnt); |
---|
798 | dojo.removeClass(node, disabledClass); |
---|
799 | }else{ |
---|
800 | dojo.addClass(node, disabledClass); |
---|
801 | } |
---|
802 | })); |
---|
803 | |
---|
804 | if(this._incBtn){ |
---|
805 | dojo[max < yearLabels.length ? "addClass" : "removeClass"](this._incBtn, disabledClass); |
---|
806 | } |
---|
807 | if(this._decBtn){ |
---|
808 | dojo[min >= firstYear ? "addClass" : "removeClass"](this._decBtn, disabledClass); |
---|
809 | } |
---|
810 | |
---|
811 | var h = this.getHeader(); |
---|
812 | if(h){ |
---|
813 | this._setText(this.getHeader(), firstYear + " - " + (firstYear + 11)); |
---|
814 | } |
---|
815 | }, |
---|
816 | |
---|
817 | _updateSelectedYear: function(){ |
---|
818 | this._year = String((this._cachedDate || this.get("value")).getFullYear()); |
---|
819 | this._updateSelectedNode(".dojoxCalendarYearLabel", dojo.hitch(this, function(node, idx){ |
---|
820 | return this._year !== null && node.innerHTML == this._year; |
---|
821 | })); |
---|
822 | }, |
---|
823 | |
---|
824 | _updateSelectedMonth: function(){ |
---|
825 | var month = (this._cachedDate || this.get("value")).getMonth(); |
---|
826 | this._month = month; |
---|
827 | this._updateSelectedNode(".dojoxCalendarMonthLabel", function(node, idx){ |
---|
828 | return idx == month; |
---|
829 | }); |
---|
830 | }, |
---|
831 | |
---|
832 | _updateSelectedNode: function(query, filter){ |
---|
833 | var sel = "dijitCalendarSelectedDate"; |
---|
834 | dojo.query(query, this.domNode) |
---|
835 | .forEach(function(node, idx, array){ |
---|
836 | dojo[filter(node, idx, array) ? "addClass" : "removeClass"](node.parentNode, sel); |
---|
837 | }); |
---|
838 | var selMonth = dojo.query('.dojoxCal-MY-M-Template div', this.myContainer) |
---|
839 | .filter(function(node){ |
---|
840 | return dojo.hasClass(node.parentNode, sel); |
---|
841 | })[0]; |
---|
842 | if(!selMonth){return;} |
---|
843 | var disabled = dojo.hasClass(selMonth, 'dijitCalendarDisabledDate'); |
---|
844 | |
---|
845 | dojo[disabled ? 'addClass' : 'removeClass'](this.okBtn, "dijitDisabled"); |
---|
846 | }, |
---|
847 | |
---|
848 | onClick: function(evt){ |
---|
849 | // summary: |
---|
850 | // Handles clicks on month names |
---|
851 | var clazz; |
---|
852 | var _this = this; |
---|
853 | var sel = "dijitCalendarSelectedDate"; |
---|
854 | function hc(c){ |
---|
855 | return dojo.hasClass(evt.target, c); |
---|
856 | } |
---|
857 | |
---|
858 | if(hc('dijitCalendarDisabledDate')){ |
---|
859 | dojo.stopEvent(evt); |
---|
860 | return false; |
---|
861 | } |
---|
862 | |
---|
863 | if(hc("dojoxCalendarMonthLabel")){ |
---|
864 | clazz = "dojoxCal-MY-M-Template"; |
---|
865 | this._month = evt.target.parentNode.cellIndex + (evt.target.parentNode.parentNode.rowIndex * 2); |
---|
866 | this._cachedDate.setMonth(this._month); |
---|
867 | this._updateSelectedMonth(); |
---|
868 | }else if(hc( "dojoxCalendarYearLabel")){ |
---|
869 | clazz = "dojoxCal-MY-Y-Template"; |
---|
870 | this._year = Number(evt.target.innerHTML); |
---|
871 | this._cachedDate.setYear(this._year); |
---|
872 | this._populateMonths(); |
---|
873 | this._updateSelectedYear(); |
---|
874 | }else if(hc("dojoxCalendarDecrease")){ |
---|
875 | this._populateYears(this._displayedYear - 10); |
---|
876 | return true; |
---|
877 | }else if(hc("dojoxCalendarIncrease")){ |
---|
878 | this._populateYears(this._displayedYear + 10); |
---|
879 | return true; |
---|
880 | }else{ |
---|
881 | return true; |
---|
882 | } |
---|
883 | dojo.stopEvent(evt); |
---|
884 | return false; |
---|
885 | }, |
---|
886 | |
---|
887 | onOk: function(evt){ |
---|
888 | dojo.stopEvent(evt); |
---|
889 | if(dojo.hasClass(this.okBtn, "dijitDisabled")){ |
---|
890 | return false; |
---|
891 | } |
---|
892 | this.onValueSelected(this._cachedDate); |
---|
893 | return false; |
---|
894 | }, |
---|
895 | |
---|
896 | onCancel: function(evt){ |
---|
897 | dojo.stopEvent(evt); |
---|
898 | this.onValueSelected(this.get("value")); |
---|
899 | return false; |
---|
900 | } |
---|
901 | }); |
---|
902 | |
---|
903 | dojo.declare("dojox.widget.Calendar2Pane", |
---|
904 | [dojox.widget._CalendarBase, |
---|
905 | dojox.widget._CalendarDay, |
---|
906 | dojox.widget._CalendarMonthYear], { |
---|
907 | // summary: A Calendar withtwo panes, the second one |
---|
908 | // containing both month and year |
---|
909 | } |
---|
910 | ); |
---|
911 | |
---|
912 | dojo.declare("dojox.widget.Calendar", |
---|
913 | [dojox.widget._CalendarBase, |
---|
914 | dojox.widget._CalendarDay, |
---|
915 | dojox.widget._CalendarMonthYear], { |
---|
916 | // summary: The standard Calendar. It includes day and month/year views. |
---|
917 | // No visual effects are included. |
---|
918 | } |
---|
919 | ); |
---|
920 | |
---|
921 | dojo.declare("dojox.widget.DailyCalendar", |
---|
922 | [dojox.widget._CalendarBase, |
---|
923 | dojox.widget._CalendarDay], { |
---|
924 | // summary: A calendar withonly a daily view. |
---|
925 | _makeDate: function(value){ |
---|
926 | var now = new Date(); |
---|
927 | now.setDate(value); |
---|
928 | return now; |
---|
929 | } |
---|
930 | } |
---|
931 | |
---|
932 | ); |
---|
933 | |
---|
934 | dojo.declare("dojox.widget.MonthAndYearlyCalendar", |
---|
935 | [dojox.widget._CalendarBase, |
---|
936 | dojox.widget._CalendarMonthYear], { |
---|
937 | // summary: A calendar withonly a daily view. |
---|
938 | } |
---|
939 | ); |
---|