]> git.wh0rd.org - tt-rss.git/blame - lib/dijit/CalendarLite.js.uncompressed.js
modify dojo rebuild script to remove uncompressed files
[tt-rss.git] / lib / dijit / CalendarLite.js.uncompressed.js
CommitLineData
f0cfe83e
AD
1require({cache:{
2'url:dijit/templates/Calendar.html':"<table cellspacing=\"0\" cellpadding=\"0\" class=\"dijitCalendarContainer\" role=\"grid\" aria-labelledby=\"${id}_mddb ${id}_year\">\n\t<thead>\n\t\t<tr class=\"dijitReset dijitCalendarMonthContainer\" valign=\"top\">\n\t\t\t<th class='dijitReset dijitCalendarArrow' data-dojo-attach-point=\"decrementMonth\">\n\t\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitCalendarIncrementControl dijitCalendarDecrease\" role=\"presentation\"/>\n\t\t\t\t<span data-dojo-attach-point=\"decreaseArrowNode\" class=\"dijitA11ySideArrow\">-</span>\n\t\t\t</th>\n\t\t\t<th class='dijitReset' colspan=\"5\">\n\t\t\t\t<div data-dojo-attach-point=\"monthNode\">\n\t\t\t\t</div>\n\t\t\t</th>\n\t\t\t<th class='dijitReset dijitCalendarArrow' data-dojo-attach-point=\"incrementMonth\">\n\t\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitCalendarIncrementControl dijitCalendarIncrease\" role=\"presentation\"/>\n\t\t\t\t<span data-dojo-attach-point=\"increaseArrowNode\" class=\"dijitA11ySideArrow\">+</span>\n\t\t\t</th>\n\t\t</tr>\n\t\t<tr role=\"row\">\n\t\t\t${!dayCellsHtml}\n\t\t</tr>\n\t</thead>\n\t<tbody data-dojo-attach-point=\"dateRowsNode\" data-dojo-attach-event=\"onclick: _onDayClick\" class=\"dijitReset dijitCalendarBodyContainer\">\n\t\t\t${!dateRowsHtml}\n\t</tbody>\n\t<tfoot class=\"dijitReset dijitCalendarYearContainer\">\n\t\t<tr>\n\t\t\t<td class='dijitReset' valign=\"top\" colspan=\"7\" role=\"presentation\">\n\t\t\t\t<div class=\"dijitCalendarYearLabel\">\n\t\t\t\t\t<span data-dojo-attach-point=\"previousYearLabelNode\" class=\"dijitInline dijitCalendarPreviousYear\" role=\"button\"></span>\n\t\t\t\t\t<span data-dojo-attach-point=\"currentYearLabelNode\" class=\"dijitInline dijitCalendarSelectedYear\" role=\"button\" id=\"${id}_year\"></span>\n\t\t\t\t\t<span data-dojo-attach-point=\"nextYearLabelNode\" class=\"dijitInline dijitCalendarNextYear\" role=\"button\"></span>\n\t\t\t\t</div>\n\t\t\t</td>\n\t\t</tr>\n\t</tfoot>\n</table>\n"}});
3define("dijit/CalendarLite", [
4 "dojo/_base/array", // array.forEach array.map
5 "dojo/_base/declare", // declare
6 "dojo/cldr/supplemental", // cldrSupplemental.getFirstDayOfWeek
7 "dojo/date", // date
8 "dojo/date/locale",
9 "dojo/date/stamp", // stamp.fromISOString
10 "dojo/dom", // dom.setSelectable
11 "dojo/dom-class", // domClass.contains
12 "dojo/_base/event", // event.stop
13 "dojo/_base/lang", // lang.getObject, lang.hitch
14 "dojo/sniff", // has("ie") has("webkit")
15 "dojo/string", // string.substitute
16 "./_WidgetBase",
17 "./_TemplatedMixin",
18 "dojo/text!./templates/Calendar.html",
19 "./hccss" // not used directly, but sets CSS class on <body>
20], function(array, declare, cldrSupplemental, date, locale, stamp, dom, domClass, event, lang, has, string,
21 _WidgetBase, _TemplatedMixin, template){
22
23
24 // module:
25 // dijit/CalendarLite
26
27 var CalendarLite = declare("dijit.CalendarLite", [_WidgetBase, _TemplatedMixin], {
28 // summary:
29 // Lightweight version of Calendar widget aimed towards mobile use
30 //
31 // description:
32 // A simple GUI for choosing a date in the context of a monthly calendar.
33 // This widget can't be used in a form because it doesn't serialize the date to an
34 // `<input>` field. For a form element, use dijit/form/DateTextBox instead.
35 //
36 // Note that the parser takes all dates attributes passed in the
37 // [RFC 3339 format](http://www.faqs.org/rfcs/rfc3339.html), e.g. `2005-06-30T08:05:00-07:00`
38 // so that they are serializable and locale-independent.
39 //
40 // Also note that this widget isn't keyboard accessible; use dijit.Calendar for that
41 // example:
42 // | var calendar = new dijit.CalendarLite({}, dojo.byId("calendarNode"));
43 //
44 // example:
45 // | <div data-dojo-type="dijit/CalendarLite"></div>
46
47 // Template for main calendar
48 templateString: template,
49
50 // Template for cell for a day of the week (ex: M)
51 dowTemplateString: '<th class="dijitReset dijitCalendarDayLabelTemplate" role="columnheader"><span class="dijitCalendarDayLabel">${d}</span></th>',
52
53 // Templates for a single date (ex: 13), and for a row for a week (ex: 20 21 22 23 24 25 26)
54 dateTemplateString: '<td class="dijitReset" role="gridcell" data-dojo-attach-point="dateCells"><span class="dijitCalendarDateLabel" data-dojo-attach-point="dateLabels"></span></td>',
55 weekTemplateString: '<tr class="dijitReset dijitCalendarWeekTemplate" role="row">${d}${d}${d}${d}${d}${d}${d}</tr>',
56
57 // value: Date
58 // The currently selected Date, initially set to invalid date to indicate no selection.
59 value: new Date(""),
60 // TODO: for 2.0 make this a string (ISO format) rather than a Date
61
62 // datePackage: String
63 // JavaScript namespace to find calendar routines. If unspecified, uses Gregorian calendar routines
64 // at dojo/date and dojo/date/locale.
65 datePackage: "",
66 // TODO: for 2.0, replace datePackage with dateModule and dateLocalModule attributes specifying MIDs,
67 // or alternately just get rid of this completely and tell user to use module ID remapping
68 // via require
69
70 // dayWidth: String
71 // How to represent the days of the week in the calendar header. See locale
72 dayWidth: "narrow",
73
74 // tabIndex: String
75 // Order fields are traversed when user hits the tab key
76 tabIndex: "0",
77
78 // currentFocus: Date
79 // Date object containing the currently focused date, or the date which would be focused
80 // if the calendar itself was focused. Also indicates which year and month to display,
81 // i.e. the current "page" the calendar is on.
82 currentFocus: new Date(),
83
84 baseClass:"dijitCalendar",
85
86 _isValidDate: function(/*Date*/ value){
87 // summary:
88 // Runs various tests on the value, checking that it's a valid date, rather
89 // than blank or NaN.
90 // tags:
91 // private
92 return value && !isNaN(value) && typeof value == "object" &&
93 value.toString() != this.constructor.prototype.value.toString();
94 },
95
96 _getValueAttr: function(){
97 // summary:
98 // Support get('value')
99
100 // this.value is set to 1AM, but return midnight, local time for back-compat
101 if(this.value && !isNaN(this.value)){
102 var value = new this.dateClassObj(this.value);
103 value.setHours(0, 0, 0, 0);
104
105 // If daylight savings pushes midnight to the previous date, fix the Date
106 // object to point at 1am so it will represent the correct day. See #9366
107 if(value.getDate() < this.value.getDate()){
108 value = this.dateModule.add(value, "hour", 1);
109 }
110 return value;
111 }else{
112 return null;
113 }
114 },
115
116 _setValueAttr: function(/*Date|Number*/ value, /*Boolean*/ priorityChange){
117 // summary:
118 // Support set("value", ...)
119 // description:
120 // Set the current date and update the UI. If the date is disabled, the value will
121 // not change, but the display will change to the corresponding month.
122 // value:
123 // Either a Date or the number of seconds since 1970.
124 // tags:
125 // protected
126 if(typeof value == "string"){
127 value = stamp.fromISOString(value);
128 }
129 value = this._patchDate(value);
130
131 if(this._isValidDate(value) && !this.isDisabledDate(value, this.lang)){
132 this._set("value", value);
133
134 // Set focus cell to the new value. Arguably this should only happen when there isn't a current
135 // focus point. This will also repopulate the grid to new month/year if necessary.
136 this.set("currentFocus", value);
137
138 // Mark the selected date
139 this._markSelectedDates([value]);
140
141 if(this._created && (priorityChange || typeof priorityChange == "undefined")){
142 this.onChange(this.get('value'));
143 }
144 }else{
145 // clear value, and mark all dates as unselected
146 this._set("value", null);
147 this._markSelectedDates([]);
148 }
149 },
150
151 _patchDate: function(/*Date|Number*/ value){
152 // summary:
153 // Convert Number into Date, or copy Date object. Then, round to nearest day,
154 // setting to 1am to avoid issues when DST shift occurs at midnight, see #8521, #9366)
155 if(value){
156 value = new this.dateClassObj(value);
157 value.setHours(1, 0, 0, 0);
158 }
159 return value;
160 },
161
162 _setText: function(node, text){
163 // summary:
164 // This just sets the content of node to the specified text.
165 // Can't do "node.innerHTML=text" because of an IE bug w/tables, see #3434.
166 // tags:
167 // private
168 while(node.firstChild){
169 node.removeChild(node.firstChild);
170 }
171 node.appendChild(node.ownerDocument.createTextNode(text));
172 },
173
174 _populateGrid: function(){
175 // summary:
176 // Fills in the calendar grid with each day (1-31).
177 // Call this on creation, when moving to a new month.
178 // tags:
179 // private
180
181 var month = new this.dateClassObj(this.currentFocus);
182 month.setDate(1);
183
184 var firstDay = month.getDay(),
185 daysInMonth = this.dateModule.getDaysInMonth(month),
186 daysInPreviousMonth = this.dateModule.getDaysInMonth(this.dateModule.add(month, "month", -1)),
187 today = new this.dateClassObj(),
188 dayOffset = cldrSupplemental.getFirstDayOfWeek(this.lang);
189 if(dayOffset > firstDay){ dayOffset -= 7; }
190
191 // Mapping from date (as specified by number returned from Date.valueOf()) to corresponding <td>
192 this._date2cell = {};
193
194 // Iterate through dates in the calendar and fill in date numbers and style info
195 array.forEach(this.dateCells, function(template, idx){
196 var i = idx + dayOffset;
197 var date = new this.dateClassObj(month),
198 number, clazz = "dijitCalendar", adj = 0;
199
200 if(i < firstDay){
201 number = daysInPreviousMonth - firstDay + i + 1;
202 adj = -1;
203 clazz += "Previous";
204 }else if(i >= (firstDay + daysInMonth)){
205 number = i - firstDay - daysInMonth + 1;
206 adj = 1;
207 clazz += "Next";
208 }else{
209 number = i - firstDay + 1;
210 clazz += "Current";
211 }
212
213 if(adj){
214 date = this.dateModule.add(date, "month", adj);
215 }
216 date.setDate(number);
217
218 if(!this.dateModule.compare(date, today, "date")){
219 clazz = "dijitCalendarCurrentDate " + clazz;
220 }
221
222 if(this.isDisabledDate(date, this.lang)){
223 clazz = "dijitCalendarDisabledDate " + clazz;
224 template.setAttribute("aria-disabled", "true");
225 }else{
226 clazz = "dijitCalendarEnabledDate " + clazz;
227 template.removeAttribute("aria-disabled");
228 template.setAttribute("aria-selected", "false");
229 }
230
231 var clazz2 = this.getClassForDate(date, this.lang);
232 if(clazz2){
233 clazz = clazz2 + " " + clazz;
234 }
235
236 template.className = clazz + "Month dijitCalendarDateTemplate";
237
238 // Each cell has an associated integer value representing it's date
239 var dateVal = date.valueOf();
240 this._date2cell[dateVal] = template;
241 template.dijitDateValue = dateVal;
242
243 // Set Date string (ex: "13").
244 this._setText(this.dateLabels[idx], date.getDateLocalized ? date.getDateLocalized(this.lang) : date.getDate());
245 }, this);
246 },
247
248 _populateControls: function(){
249 // summary:
250 // Fill in localized month, and prev/current/next years
251 // tags:
252 // protected
253
254 var month = new this.dateClassObj(this.currentFocus);
255 month.setDate(1);
256
257 // set name of this month
258 this.monthWidget.set("month", month);
259
260 var y = month.getFullYear() - 1;
261 var d = new this.dateClassObj();
262 array.forEach(["previous", "current", "next"], function(name){
263 d.setFullYear(y++);
264 this._setText(this[name+"YearLabelNode"],
265 this.dateLocaleModule.format(d, {selector:'year', locale:this.lang}));
266 }, this);
267 },
268
269 goToToday: function(){
270 // summary:
271 // Sets calendar's value to today's date
272 this.set('value', new this.dateClassObj());
273 },
274
275 constructor: function(params /*===== , srcNodeRef =====*/){
276 // summary:
277 // Create the widget.
278 // params: Object|null
279 // Hash of initialization parameters for widget, including scalar values (like title, duration etc.)
280 // and functions, typically callbacks like onClick.
281 // The hash can contain any of the widget's properties, excluding read-only properties.
282 // srcNodeRef: DOMNode|String?
283 // If a srcNodeRef (DOM node) is specified, replace srcNodeRef with my generated DOM tree
284
285 this.dateModule = params.datePackage ? lang.getObject(params.datePackage, false) : date;
286 this.dateClassObj = this.dateModule.Date || Date;
287 this.dateLocaleModule = params.datePackage ? lang.getObject(params.datePackage+".locale", false) : locale;
288 },
289
290 _createMonthWidget: function(){
291 // summary:
292 // Creates the drop down button that displays the current month and lets user pick a new one
293
294 return CalendarLite._MonthWidget({
295 id: this.id + "_mw",
296 lang: this.lang,
297 dateLocaleModule: this.dateLocaleModule
298 }, this.monthNode);
299 },
300
301 buildRendering: function(){
302 // Markup for days of the week (referenced from template)
303 var d = this.dowTemplateString,
304 dayNames = this.dateLocaleModule.getNames('days', this.dayWidth, 'standAlone', this.lang),
305 dayOffset = cldrSupplemental.getFirstDayOfWeek(this.lang);
306 this.dayCellsHtml = string.substitute([d,d,d,d,d,d,d].join(""), {d: ""}, function(){
307 return dayNames[dayOffset++ % 7];
308 });
309
310 // Markup for dates of the month (referenced from template), but without numbers filled in
311 var r = string.substitute(this.weekTemplateString, {d: this.dateTemplateString});
312 this.dateRowsHtml = [r,r,r,r,r,r].join("");
313
314 // Instantiate from template.
315 // dateCells and dateLabels arrays filled when _Templated parses my template.
316 this.dateCells = [];
317 this.dateLabels = [];
318 this.inherited(arguments);
319
320 dom.setSelectable(this.domNode, false);
321
322 var dateObj = new this.dateClassObj(this.currentFocus);
323
324 this.monthWidget = this._createMonthWidget();
325
326 this.set('currentFocus', dateObj, false); // draw the grid to the month specified by currentFocus
327 },
328
329 postCreate: function(){
330 this.inherited(arguments);
331 this._connectControls();
332 },
333
334 _connectControls: function(){
335 // summary:
336 // Set up connects for increment/decrement of months/years
337 // tags:
338 // protected
339
340 var connect = lang.hitch(this, function(nodeProp, part, amount){
341 this.connect(this[nodeProp], "onclick", function(){
342 this._setCurrentFocusAttr(this.dateModule.add(this.currentFocus, part, amount));
343 });
344 });
345
346 connect("incrementMonth", "month", 1);
347 connect("decrementMonth", "month", -1);
348 connect("nextYearLabelNode", "year", 1);
349 connect("previousYearLabelNode", "year", -1);
350 },
351
352 _setCurrentFocusAttr: function(/*Date*/ date, /*Boolean*/ forceFocus){
353 // summary:
354 // If the calendar currently has focus, then focuses specified date,
355 // changing the currently displayed month/year if necessary.
356 // If the calendar doesn't have focus, updates currently
357 // displayed month/year, and sets the cell that will get focus
358 // when Calendar is focused.
359 // forceFocus:
360 // If true, will focus() the cell even if calendar itself doesn't have focus
361
362 var oldFocus = this.currentFocus,
363 oldCell = this._getNodeByDate(oldFocus);
364 date = this._patchDate(date);
365
366 this._set("currentFocus", date);
367
368 // If the focus is on a different month than the current calendar month, switch the displayed month.
369 // Also will populate the grid initially, on Calendar creation.
370 if(!this._date2cell || this.dateModule.difference(oldFocus, date, "month") != 0){
371 this._populateGrid();
372 this._populateControls();
373 this._markSelectedDates([this.value]);
374 }
375
376 // set tabIndex=0 on new cell, and focus it (but only if Calendar itself is focused)
377 var newCell = this._getNodeByDate(date);
378 newCell.setAttribute("tabIndex", this.tabIndex);
379 if(this.focused || forceFocus){
380 newCell.focus();
381 }
382
383 // set tabIndex=-1 on old focusable cell
384 if(oldCell && oldCell != newCell){
385 if(has("webkit")){ // see #11064 about webkit bug
386 oldCell.setAttribute("tabIndex", "-1");
387 }else{
388 oldCell.removeAttribute("tabIndex");
389 }
390 }
391 },
392
393 focus: function(){
394 // summary:
395 // Focus the calendar by focusing one of the calendar cells
396 this._setCurrentFocusAttr(this.currentFocus, true);
397 },
398
399 _onDayClick: function(/*Event*/ evt){
400 // summary:
401 // Handler for day clicks, selects the date if appropriate
402 // tags:
403 // protected
404 event.stop(evt);
405 for(var node = evt.target; node && !node.dijitDateValue; node = node.parentNode);
406 if(node && !domClass.contains(node, "dijitCalendarDisabledDate")){
407 this.set('value', node.dijitDateValue);
408 }
409 },
410
411 _getNodeByDate : function(/*Date*/ value){
412 // summary:
413 // Returns the cell corresponding to the date, or null if the date is not within the currently
414 // displayed month.
415 value = this._patchDate(value);
416 return value && this._date2cell ? this._date2cell[value.valueOf()] : null;
417 },
418
419 _markSelectedDates: function(/*Date[]*/ dates){
420 // summary:
421 // Marks the specified cells as selected, and clears cells previously marked as selected.
422 // For CalendarLite at most one cell is selected at any point, but this allows an array
423 // for easy subclassing.
424
425 // Function to mark a cell as selected or unselected
426 function mark(/*Boolean*/ selected, /*DomNode*/ cell){
427 domClass.toggle(cell, "dijitCalendarSelectedDate", selected);
428 cell.setAttribute("aria-selected", selected ? "true" : "false");
429 }
430
431 // Clear previously selected cells.
432 array.forEach(this._selectedCells || [], lang.partial(mark, false));
433
434 // Mark newly selected cells. Ignore dates outside the currently displayed month.
435 this._selectedCells = array.filter(array.map(dates, this._getNodeByDate, this), function(n){ return n;});
436 array.forEach(this._selectedCells, lang.partial(mark, true));
437 },
438
439 onChange: function(/*Date*/ /*===== date =====*/){
440 // summary:
441 // Called only when the selected date has changed
442 },
443
444 isDisabledDate: function(/*===== dateObject, locale =====*/){
445 // summary:
446 // May be overridden to disable certain dates in the calendar e.g. `isDisabledDate=dojo.date.locale.isWeekend`
447 // dateObject: Date
448 // locale: String?
449 // tags:
450 // extension
451/*=====
452 return false; // Boolean
453=====*/
454 },
455
456 getClassForDate: function(/*===== dateObject, locale =====*/){
457 // summary:
458 // May be overridden to return CSS classes to associate with the date entry for the given dateObject,
459 // for example to indicate a holiday in specified locale.
460 // dateObject: Date
461 // locale: String?
462 // tags:
463 // extension
464
465/*=====
466 return ""; // String
467=====*/
468 }
469 });
470
471 CalendarLite._MonthWidget = declare("dijit.CalendarLite._MonthWidget", _WidgetBase, {
472 // summary:
473 // Displays name of current month padded to the width of the month
474 // w/the longest name, so that changing months doesn't change width.
475 //
476 // Create as:
477 // | new Calendar._MonthWidget({
478 // | lang: ...,
479 // | dateLocaleModule: ...
480 // | })
481
482 _setMonthAttr: function(month){
483 // summary:
484 // Set the current month to display as a label
485 var monthNames = this.dateLocaleModule.getNames('months', 'wide', 'standAlone', this.lang, month),
486 spacer =
487 (has("ie") == 6 ? "" : "<div class='dijitSpacer'>" +
488 array.map(monthNames, function(s){ return "<div>" + s + "</div>"; }).join("") + "</div>");
489
490 // Set name of current month and also fill in spacer element with all the month names
491 // (invisible) so that the maximum width will affect layout. But not on IE6 because then
492 // the center <TH> overlaps the right <TH> (due to a browser bug).
493 this.domNode.innerHTML =
494 spacer +
495 "<div class='dijitCalendarMonthLabel dijitCalendarCurrentMonthLabel'>" +
496 monthNames[month.getMonth()] + "</div>";
497 }
498 });
499
500 return CalendarLite;
501});