Calendar.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. define("dijit/Calendar", [
  2. "dojo/_base/array", // array.map
  3. "dojo/date",
  4. "dojo/date/locale",
  5. "dojo/_base/declare", // declare
  6. "dojo/dom-attr", // domAttr.get
  7. "dojo/dom-class", // domClass.add domClass.contains domClass.remove domClass.toggle
  8. "dojo/_base/event", // event.stop
  9. "dojo/_base/kernel", // kernel.deprecated
  10. "dojo/keys", // keys
  11. "dojo/_base/lang", // lang.hitch
  12. "dojo/_base/sniff", // has("ie")
  13. "./CalendarLite",
  14. "./_Widget",
  15. "./_CssStateMixin",
  16. "./_TemplatedMixin",
  17. "./form/DropDownButton",
  18. "./hccss" // not used directly, but sets CSS class on <body>
  19. ], function(array, date, local, declare, domAttr, domClass, event, kernel, keys, lang, has,
  20. CalendarLite, _Widget, _CssStateMixin, _TemplatedMixin, DropDownButton){
  21. /*=====
  22. var CalendarLite = dijit.CalendarLite;
  23. var _CssStateMixin = dijit._CssStateMixin;
  24. var _Widget = dijit._Widget;
  25. var _TemplatedMixin = dijit._TemplatedMixin;
  26. var DropDownButton = dijit.form.DropDownButton;
  27. =====*/
  28. // module:
  29. // dijit/Calendar
  30. // summary:
  31. // A simple GUI for choosing a date in the context of a monthly calendar.
  32. var Calendar = declare("dijit.Calendar",
  33. [CalendarLite, _Widget, _CssStateMixin], // _Widget for deprecated methods like setAttribute()
  34. {
  35. // summary:
  36. // A simple GUI for choosing a date in the context of a monthly calendar.
  37. //
  38. // description:
  39. // See CalendarLite for general description. Calendar extends CalendarLite, adding:
  40. // - month drop down list
  41. // - keyboard navigation
  42. // - CSS classes for hover/mousepress on date, month, and year nodes
  43. // - support of deprecated methods (will be removed in 2.0)
  44. // Set node classes for various mouse events, see dijit._CssStateMixin for more details
  45. cssStateNodes: {
  46. "decrementMonth": "dijitCalendarArrow",
  47. "incrementMonth": "dijitCalendarArrow",
  48. "previousYearLabelNode": "dijitCalendarPreviousYear",
  49. "nextYearLabelNode": "dijitCalendarNextYear"
  50. },
  51. setValue: function(/*Date*/ value){
  52. // summary:
  53. // Deprecated. Use set('value', ...) instead.
  54. // tags:
  55. // deprecated
  56. kernel.deprecated("dijit.Calendar:setValue() is deprecated. Use set('value', ...) instead.", "", "2.0");
  57. this.set('value', value);
  58. },
  59. _createMonthWidget: function(){
  60. // summary:
  61. // Creates the drop down button that displays the current month and lets user pick a new one
  62. return new Calendar._MonthDropDownButton({
  63. id: this.id + "_mddb",
  64. tabIndex: -1,
  65. onMonthSelect: lang.hitch(this, "_onMonthSelect"),
  66. lang: this.lang,
  67. dateLocaleModule: this.dateLocaleModule
  68. }, this.monthNode);
  69. },
  70. buildRendering: function(){
  71. this.inherited(arguments);
  72. // Events specific to Calendar, not used in CalendarLite
  73. this.connect(this.domNode, "onkeydown", "_onKeyDown");
  74. this.connect(this.dateRowsNode, "onmouseover", "_onDayMouseOver");
  75. this.connect(this.dateRowsNode, "onmouseout", "_onDayMouseOut");
  76. this.connect(this.dateRowsNode, "onmousedown", "_onDayMouseDown");
  77. this.connect(this.dateRowsNode, "onmouseup", "_onDayMouseUp");
  78. },
  79. _onMonthSelect: function(/*Number*/ newMonth){
  80. // summary:
  81. // Handler for when user selects a month from the drop down list
  82. // tags:
  83. // protected
  84. // move to selected month, bounding by the number of days in the month
  85. // (ex: dec 31 --> jan 28, not jan 31)
  86. this._setCurrentFocusAttr(this.dateFuncObj.add(this.currentFocus, "month",
  87. newMonth - this.currentFocus.getMonth()));
  88. },
  89. _onDayMouseOver: function(/*Event*/ evt){
  90. // summary:
  91. // Handler for mouse over events on days, sets hovered style
  92. // tags:
  93. // protected
  94. // event can occur on <td> or the <span> inside the td,
  95. // set node to the <td>.
  96. var node =
  97. domClass.contains(evt.target, "dijitCalendarDateLabel") ?
  98. evt.target.parentNode :
  99. evt.target;
  100. if(node && (
  101. (node.dijitDateValue && !domClass.contains(node, "dijitCalendarDisabledDate"))
  102. || node == this.previousYearLabelNode || node == this.nextYearLabelNode
  103. )){
  104. domClass.add(node, "dijitCalendarHoveredDate");
  105. this._currentNode = node;
  106. }
  107. },
  108. _onDayMouseOut: function(/*Event*/ evt){
  109. // summary:
  110. // Handler for mouse out events on days, clears hovered style
  111. // tags:
  112. // protected
  113. if(!this._currentNode){ return; }
  114. // if mouse out occurs moving from <td> to <span> inside <td>, ignore it
  115. if(evt.relatedTarget && evt.relatedTarget.parentNode == this._currentNode){ return; }
  116. var cls = "dijitCalendarHoveredDate";
  117. if(domClass.contains(this._currentNode, "dijitCalendarActiveDate")){
  118. cls += " dijitCalendarActiveDate";
  119. }
  120. domClass.remove(this._currentNode, cls);
  121. this._currentNode = null;
  122. },
  123. _onDayMouseDown: function(/*Event*/ evt){
  124. var node = evt.target.parentNode;
  125. if(node && node.dijitDateValue && !domClass.contains(node, "dijitCalendarDisabledDate")){
  126. domClass.add(node, "dijitCalendarActiveDate");
  127. this._currentNode = node;
  128. }
  129. },
  130. _onDayMouseUp: function(/*Event*/ evt){
  131. var node = evt.target.parentNode;
  132. if(node && node.dijitDateValue){
  133. domClass.remove(node, "dijitCalendarActiveDate");
  134. }
  135. },
  136. handleKey: function(/*Event*/ evt){
  137. // summary:
  138. // Provides keyboard navigation of calendar.
  139. // description:
  140. // Called from _onKeyDown() to handle keypress on a stand alone Calendar,
  141. // and also from `dijit.form._DateTimeTextBox` to pass a keydown event
  142. // from the `dijit.form.DateTextBox` to be handled in this widget
  143. // returns:
  144. // False if the key was recognized as a navigation key,
  145. // to indicate that the event was handled by Calendar and shouldn't be propagated
  146. // tags:
  147. // protected
  148. var increment = -1,
  149. interval,
  150. newValue = this.currentFocus;
  151. switch(evt.keyCode){
  152. case keys.RIGHT_ARROW:
  153. increment = 1;
  154. //fallthrough...
  155. case keys.LEFT_ARROW:
  156. interval = "day";
  157. if(!this.isLeftToRight()){ increment *= -1; }
  158. break;
  159. case keys.DOWN_ARROW:
  160. increment = 1;
  161. //fallthrough...
  162. case keys.UP_ARROW:
  163. interval = "week";
  164. break;
  165. case keys.PAGE_DOWN:
  166. increment = 1;
  167. //fallthrough...
  168. case keys.PAGE_UP:
  169. interval = evt.ctrlKey || evt.altKey ? "year" : "month";
  170. break;
  171. case keys.END:
  172. // go to the next month
  173. newValue = this.dateFuncObj.add(newValue, "month", 1);
  174. // subtract a day from the result when we're done
  175. interval = "day";
  176. //fallthrough...
  177. case keys.HOME:
  178. newValue = new this.dateClassObj(newValue);
  179. newValue.setDate(1);
  180. break;
  181. case keys.ENTER:
  182. case keys.SPACE:
  183. this.set("value", this.currentFocus);
  184. break;
  185. default:
  186. return true;
  187. }
  188. if(interval){
  189. newValue = this.dateFuncObj.add(newValue, interval, increment);
  190. }
  191. this._setCurrentFocusAttr(newValue);
  192. return false;
  193. },
  194. _onKeyDown: function(/*Event*/ evt){
  195. // summary:
  196. // For handling keypress events on a stand alone calendar
  197. if(!this.handleKey(evt)){
  198. event.stop(evt);
  199. }
  200. },
  201. onValueSelected: function(/*Date*/ /*===== date =====*/){
  202. // summary:
  203. // Deprecated. Notification that a date cell was selected. It may be the same as the previous value.
  204. // description:
  205. // Formerly used by `dijit.form._DateTimeTextBox` (and thus `dijit.form.DateTextBox`)
  206. // to get notification when the user has clicked a date. Now onExecute() (above) is used.
  207. // tags:
  208. // protected
  209. },
  210. onChange: function(value){
  211. this.onValueSelected(value); // remove in 2.0
  212. },
  213. getClassForDate: function(/*===== dateObject, locale =====*/){
  214. // summary:
  215. // May be overridden to return CSS classes to associate with the date entry for the given dateObject,
  216. // for example to indicate a holiday in specified locale.
  217. // dateObject: Date
  218. // locale: String?
  219. // tags:
  220. // extension
  221. /*=====
  222. return ""; // String
  223. =====*/
  224. }
  225. });
  226. Calendar._MonthDropDownButton = declare("dijit.Calendar._MonthDropDownButton", DropDownButton, {
  227. // summary:
  228. // DropDownButton for the current month. Displays name of current month
  229. // and a list of month names in the drop down
  230. onMonthSelect: function(){ },
  231. postCreate: function(){
  232. this.inherited(arguments);
  233. this.dropDown = new Calendar._MonthDropDown({
  234. id: this.id + "_mdd", //do not change this id because it is referenced in the template
  235. onChange: this.onMonthSelect
  236. });
  237. },
  238. _setMonthAttr: function(month){
  239. // summary:
  240. // Set the current month to display as a label
  241. var monthNames = this.dateLocaleModule.getNames('months', 'wide', 'standAlone', this.lang, month);
  242. this.dropDown.set("months", monthNames);
  243. // Set name of current month and also fill in spacer element with all the month names
  244. // (invisible) so that the maximum width will affect layout. But not on IE6 because then
  245. // the center <TH> overlaps the right <TH> (due to a browser bug).
  246. this.containerNode.innerHTML =
  247. (has("ie") == 6 ? "" : "<div class='dijitSpacer'>" + this.dropDown.domNode.innerHTML + "</div>") +
  248. "<div class='dijitCalendarMonthLabel dijitCalendarCurrentMonthLabel'>" + monthNames[month.getMonth()] + "</div>";
  249. }
  250. });
  251. Calendar._MonthDropDown = declare("dijit.Calendar._MonthDropDown", [_Widget, _TemplatedMixin], {
  252. // summary:
  253. // The list-of-months drop down from the MonthDropDownButton
  254. // months: String[]
  255. // List of names of months, possibly w/some undefined entries for Hebrew leap months
  256. // (ex: ["January", "February", undefined, "April", ...])
  257. months: [],
  258. templateString: "<div class='dijitCalendarMonthMenu dijitMenu' " +
  259. "data-dojo-attach-event='onclick:_onClick,onmouseover:_onMenuHover,onmouseout:_onMenuHover'></div>",
  260. _setMonthsAttr: function(/*String[]*/ months){
  261. this.domNode.innerHTML = array.map(months, function(month, idx){
  262. return month ? "<div class='dijitCalendarMonthLabel' month='" + idx +"'>" + month + "</div>" : "";
  263. }).join("");
  264. },
  265. _onClick: function(/*Event*/ evt){
  266. this.onChange(domAttr.get(evt.target, "month"));
  267. },
  268. onChange: function(/*Number*/ /*===== month =====*/){
  269. // summary:
  270. // Callback when month is selected from drop down
  271. },
  272. _onMenuHover: function(evt){
  273. domClass.toggle(evt.target, "dijitCalendarMonthLabelHover", evt.type == "mouseover");
  274. }
  275. });
  276. return Calendar;
  277. });