1 | define([ |
---|
2 | "dojo/_base/declare", |
---|
3 | "dojo/_base/lang", |
---|
4 | "dojo/_base/array", |
---|
5 | "dojo/_base/window", |
---|
6 | "dojo/_base/event", |
---|
7 | "dojo/_base/html", |
---|
8 | "dojo/sniff", |
---|
9 | "dojo/query", |
---|
10 | "dojo/dom", |
---|
11 | "dojo/dom-style", |
---|
12 | "dojo/dom-class", |
---|
13 | "dojo/dom-construct", |
---|
14 | "dojo/dom-geometry", |
---|
15 | "dojo/on", |
---|
16 | "dojo/date", |
---|
17 | "dojo/date/locale", |
---|
18 | "dojo/when", |
---|
19 | "dijit/_WidgetBase", |
---|
20 | "dojox/widget/_Invalidating", |
---|
21 | "dojox/widget/Selection", |
---|
22 | "dojox/calendar/time", |
---|
23 | "./StoreMixin"], |
---|
24 | |
---|
25 | function( |
---|
26 | declare, |
---|
27 | lang, |
---|
28 | arr, |
---|
29 | win, |
---|
30 | event, |
---|
31 | html, |
---|
32 | has, |
---|
33 | query, |
---|
34 | dom, |
---|
35 | domStyle, |
---|
36 | domClass, |
---|
37 | domConstruct, |
---|
38 | domGeometry, |
---|
39 | on, |
---|
40 | date, |
---|
41 | locale, |
---|
42 | when, |
---|
43 | _WidgetBase, |
---|
44 | _Invalidating, |
---|
45 | Selection, |
---|
46 | timeUtil, |
---|
47 | StoreMixin){ |
---|
48 | |
---|
49 | /*===== |
---|
50 | var __GridClickEventArgs = { |
---|
51 | // summary: |
---|
52 | // The event dispatched when the grid is clicked or double-clicked. |
---|
53 | // date: Date |
---|
54 | // The start of the previously displayed time interval, if any. |
---|
55 | // triggerEvent: Event |
---|
56 | // The event at the origin of this event. |
---|
57 | }; |
---|
58 | =====*/ |
---|
59 | |
---|
60 | /*===== |
---|
61 | var __ItemMouseEventArgs = { |
---|
62 | // summary: |
---|
63 | // The event dispatched when an item is clicked, double-clicked or context-clicked. |
---|
64 | // item: Object |
---|
65 | // The item clicked. |
---|
66 | // renderer: dojox/calendar/_RendererMixin |
---|
67 | // The item renderer clicked. |
---|
68 | // triggerEvent: Event |
---|
69 | // The event at the origin of this event. |
---|
70 | }; |
---|
71 | =====*/ |
---|
72 | |
---|
73 | /*===== |
---|
74 | var __itemEditingEventArgs = { |
---|
75 | // summary: |
---|
76 | // An item editing event. |
---|
77 | // item: Object |
---|
78 | // The render item that is being edited. Set/get the startTime and/or endTime properties to customize editing behavior. |
---|
79 | // storeItem: Object |
---|
80 | // The real data from the store. DO NOT change properties, but you may use properties of this item in the editing behavior logic. |
---|
81 | // editKind: String |
---|
82 | // Kind of edit: "resizeBoth", "resizeStart", "resizeEnd" or "move". |
---|
83 | // dates: Date[] |
---|
84 | // The computed date/time of the during the event editing. One entry per edited date (touch use case). |
---|
85 | // startTime: Date? |
---|
86 | // The start time of data item. |
---|
87 | // endTime: Date? |
---|
88 | // The end time of data item. |
---|
89 | // sheet: String |
---|
90 | // For views with several sheets (columns view for example), the sheet when the event occurred. |
---|
91 | // source: dojox/calendar/ViewBase |
---|
92 | // The view where the event occurred. |
---|
93 | // eventSource: String |
---|
94 | // The device that triggered the event. This property can take the following values: |
---|
95 | // |
---|
96 | // - "mouse", |
---|
97 | // - "keyboard", |
---|
98 | // - "touch" |
---|
99 | // triggerEvent: Event |
---|
100 | // The event at the origin of this event. |
---|
101 | }; |
---|
102 | =====*/ |
---|
103 | |
---|
104 | /*===== |
---|
105 | var __rendererLifecycleEventArgs = { |
---|
106 | // summary: |
---|
107 | // An renderer lifecycle event. |
---|
108 | // renderer: Object |
---|
109 | // The renderer. |
---|
110 | // source: dojox/calendar/ViewBase |
---|
111 | // The view where the event occurred. |
---|
112 | // item:Object? |
---|
113 | // The item that will be displayed by the renderer for the "rendererCreated" and "rendererReused" events. |
---|
114 | }; |
---|
115 | =====*/ |
---|
116 | |
---|
117 | return declare("dojox.calendar.ViewBase", [_WidgetBase, StoreMixin, _Invalidating, Selection], { |
---|
118 | |
---|
119 | // summary: |
---|
120 | // The dojox.calendar.ViewBase widget is the base of calendar view widgets |
---|
121 | |
---|
122 | // datePackage: Object |
---|
123 | // JavaScript namespace to find Calendar routines. Uses Gregorian Calendar routines at dojo.date by default. |
---|
124 | datePackage: date, |
---|
125 | |
---|
126 | _calendar: "gregorian", |
---|
127 | |
---|
128 | // viewKind: String |
---|
129 | // Kind of the view. Used by the calendar widget to determine how to configure the view. |
---|
130 | viewKind: null, |
---|
131 | |
---|
132 | // _layoutStep: [protected] Integer |
---|
133 | // The number of units displayed by a visual layout unit (i.e. a column or a row) |
---|
134 | _layoutStep: 1, |
---|
135 | |
---|
136 | // _layoutStep: [protected] Integer |
---|
137 | // The unit displayed by a visual layout unit (i.e. a column or a row) |
---|
138 | _layoutUnit: "day", |
---|
139 | |
---|
140 | // resizeCursor: String |
---|
141 | // CSS value to apply to the cursor while resizing an item renderer. |
---|
142 | resizeCursor: "n-resize", |
---|
143 | |
---|
144 | // formatItemTimeFunc: Function |
---|
145 | // Optional function to format the time of day of the item renderers. |
---|
146 | // The function takes the date and render data object as arguments and returns a String. |
---|
147 | formatItemTimeFunc: null, |
---|
148 | |
---|
149 | _cssDays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], |
---|
150 | |
---|
151 | _getFormatItemTimeFuncAttr: function(){ |
---|
152 | if(this.owner != null){ |
---|
153 | return this.owner.get("formatItemTimeFunc"); |
---|
154 | } |
---|
155 | return this.formatItemTimeFunc; |
---|
156 | }, |
---|
157 | |
---|
158 | // The listeners added by the view itself. |
---|
159 | _viewHandles: null, |
---|
160 | |
---|
161 | // doubleTapDelay: Integer |
---|
162 | // The maximum time amount in milliseconds between to touchstart events that trigger a double-tap event. |
---|
163 | doubleTapDelay: 300, |
---|
164 | |
---|
165 | constructor: function(/*Object*/ args){ |
---|
166 | args = args || {}; |
---|
167 | |
---|
168 | this._calendar = args.datePackage ? args.datePackage.substr(args.datePackage.lastIndexOf(".")+1) : this._calendar; |
---|
169 | this.dateModule = args.datePackage ? lang.getObject(args.datePackage, false) : date; |
---|
170 | this.dateClassObj = this.dateModule.Date || Date; |
---|
171 | this.dateLocaleModule = args.datePackage ? lang.getObject(args.datePackage+".locale", false) : locale; |
---|
172 | |
---|
173 | this.rendererPool = []; |
---|
174 | this.rendererList = []; |
---|
175 | this.itemToRenderer = {}; |
---|
176 | this._viewHandles = []; |
---|
177 | }, |
---|
178 | |
---|
179 | destroy: function(preserveDom){ |
---|
180 | // renderers |
---|
181 | while(this.rendererList.length > 0){ |
---|
182 | this._destroyRenderer(this.rendererList.pop()); |
---|
183 | } |
---|
184 | for(var kind in this._rendererPool){ |
---|
185 | var pool = this._rendererPool[kind]; |
---|
186 | if(pool){ |
---|
187 | while(pool.length > 0){ |
---|
188 | this._destroyRenderer(pool.pop()); |
---|
189 | } |
---|
190 | } |
---|
191 | } |
---|
192 | |
---|
193 | while(this._viewHandles.length > 0){ |
---|
194 | this._viewHandles.pop().remove(); |
---|
195 | } |
---|
196 | |
---|
197 | this.inherited(arguments); |
---|
198 | }, |
---|
199 | |
---|
200 | |
---|
201 | resize: function(changeSize){ |
---|
202 | // summary: |
---|
203 | // Function to call when the view is resized. |
---|
204 | // If the view is in a Dijit container or in a Dojo mobile container, it will be automatically called. |
---|
205 | // On other use cases, this method must called when the window is resized and/or when the orientation has changed. |
---|
206 | if(changeSize){ |
---|
207 | domGeometry.setMarginBox(this.domNode, changeSize); |
---|
208 | } |
---|
209 | }, |
---|
210 | |
---|
211 | _getTopOwner: function(){ |
---|
212 | // summary: |
---|
213 | // Returns the top owner: the calendar or the parent view. |
---|
214 | var p = this; |
---|
215 | while(p.owner != undefined){ |
---|
216 | p = p.owner; |
---|
217 | } |
---|
218 | return p; |
---|
219 | }, |
---|
220 | |
---|
221 | _createRenderData: function(){ |
---|
222 | // summary: |
---|
223 | // Creates the object that contains all the data needed to render this widget. |
---|
224 | // tags: |
---|
225 | // protected |
---|
226 | }, |
---|
227 | |
---|
228 | _validateProperties: function(){ |
---|
229 | // summary: |
---|
230 | // Validates the widget properties before the rendering pass. |
---|
231 | // tags: |
---|
232 | // protected |
---|
233 | }, |
---|
234 | |
---|
235 | _setText: function(node, text, allowHTML){ |
---|
236 | // summary: |
---|
237 | // Creates a text node under the parent node after having removed children nodes if any. |
---|
238 | // node: Node |
---|
239 | // The node that will contain the text node. |
---|
240 | // text: String |
---|
241 | // The text to set to the text node. |
---|
242 | if(text != null){ |
---|
243 | if(!allowHTML && node.hasChildNodes()){ |
---|
244 | // span > textNode |
---|
245 | node.childNodes[0].childNodes[0].nodeValue = text; |
---|
246 | }else{ |
---|
247 | |
---|
248 | while(node.hasChildNodes()){ |
---|
249 | node.removeChild(node.lastChild); |
---|
250 | } |
---|
251 | |
---|
252 | var tNode = win.doc.createElement("span"); |
---|
253 | if(has("dojo-bidi")){ |
---|
254 | this.applyTextDir(tNode, text); |
---|
255 | } |
---|
256 | |
---|
257 | if(allowHTML){ |
---|
258 | tNode.innerHTML = text; |
---|
259 | }else{ |
---|
260 | tNode.appendChild(win.doc.createTextNode(text)); |
---|
261 | } |
---|
262 | node.appendChild(tNode); |
---|
263 | } |
---|
264 | } |
---|
265 | }, |
---|
266 | |
---|
267 | isAscendantHasClass: function(node, ancestor, className){ |
---|
268 | // summary: |
---|
269 | // Determines if a node has an ascendant node that has the css class specified. |
---|
270 | // node: Node |
---|
271 | // The DOM node. |
---|
272 | // ancestor: Node |
---|
273 | // The ancestor node used to limit the search in hierarchy. |
---|
274 | // className: String |
---|
275 | // The css class name. |
---|
276 | // returns: Boolean |
---|
277 | |
---|
278 | while(node != ancestor && node != document){ |
---|
279 | |
---|
280 | if(domClass.contains(node, className)){ |
---|
281 | return true; |
---|
282 | } |
---|
283 | |
---|
284 | node = node.parentNode; |
---|
285 | } |
---|
286 | return false; |
---|
287 | }, |
---|
288 | |
---|
289 | isWeekEnd: function(date){ |
---|
290 | // summary: |
---|
291 | // Determines whether the specified date is a week-end. |
---|
292 | // This method is using dojo.date.locale.isWeekend() method as |
---|
293 | // dojox.date.XXXX calendars are not supporting this method. |
---|
294 | // date: Date |
---|
295 | // The date to test. |
---|
296 | return locale.isWeekend(date); |
---|
297 | }, |
---|
298 | |
---|
299 | getWeekNumberLabel: function(date){ |
---|
300 | // summary: |
---|
301 | // Returns the week number string from dojo.date.locale.format() method as |
---|
302 | // dojox.date.XXXX calendar are not supporting the "w" pattern. |
---|
303 | // date: Date |
---|
304 | // The date to format. |
---|
305 | if(date.toGregorian){ |
---|
306 | date = date.toGregorian(); |
---|
307 | } |
---|
308 | return locale.format(date, { |
---|
309 | selector: "date", |
---|
310 | datePattern: "w"}); |
---|
311 | }, |
---|
312 | |
---|
313 | floorToDay: function(date, reuse){ |
---|
314 | // summary: |
---|
315 | // Floors the specified date to the start of day. |
---|
316 | // date: Date |
---|
317 | // The date to floor. |
---|
318 | // reuse: Boolean |
---|
319 | // Whether use the specified instance or create a new one. Default is false. |
---|
320 | // returns: Date |
---|
321 | return timeUtil.floorToDay(date, reuse, this.dateClassObj); |
---|
322 | }, |
---|
323 | |
---|
324 | floorToMonth: function(date, reuse){ |
---|
325 | // summary: |
---|
326 | // Floors the specified date to the start of the date's month. |
---|
327 | // date: Date |
---|
328 | // The date to floor. |
---|
329 | // reuse: Boolean |
---|
330 | // Whether use the specified instance or create a new one. Default is false. |
---|
331 | // returns: Date |
---|
332 | return timeUtil.floorToMonth(date, reuse, this.dateClassObj); |
---|
333 | }, |
---|
334 | |
---|
335 | |
---|
336 | floorDate: function(date, unit, steps, reuse){ |
---|
337 | // summary: |
---|
338 | // floors the date to the unit. |
---|
339 | // date: Date |
---|
340 | // The date/time to floor. |
---|
341 | // unit: String |
---|
342 | // The unit. Valid values are "minute", "hour", "day". |
---|
343 | // steps: Integer |
---|
344 | // For "day" only 1 is valid. |
---|
345 | // reuse: Boolean |
---|
346 | // Whether use the specified instance or create a new one. Default is false. |
---|
347 | // returns: Date |
---|
348 | return timeUtil.floor(date, unit, steps, reuse, this.dateClassObj); |
---|
349 | }, |
---|
350 | |
---|
351 | isToday: function(date){ |
---|
352 | // summary: |
---|
353 | // Returns whether the specified date is in the current day. |
---|
354 | // date: Date |
---|
355 | // The date to test. |
---|
356 | // renderData: Object |
---|
357 | // The current renderData |
---|
358 | // returns: Boolean |
---|
359 | return timeUtil.isToday(date, this.dateClassObj); |
---|
360 | }, |
---|
361 | |
---|
362 | isStartOfDay: function(d){ |
---|
363 | // summary: |
---|
364 | // Tests if the specified date represents the starts of day. |
---|
365 | // d:Date |
---|
366 | // The date to test. |
---|
367 | // returns: Boolean |
---|
368 | return timeUtil.isStartOfDay(d, this.dateClassObj, this.dateModule); |
---|
369 | }, |
---|
370 | |
---|
371 | isOverlapping: function(renderData, start1, end1, start2, end2, includeLimits){ |
---|
372 | // summary: |
---|
373 | // Computes if the first time range defined by the start1 and end1 parameters |
---|
374 | // is overlapping the second time range defined by the start2 and end2 parameters. |
---|
375 | // renderData: Object |
---|
376 | // The render data. |
---|
377 | // start1: Date |
---|
378 | // The start time of the first time range. |
---|
379 | // end1: Date |
---|
380 | // The end time of the first time range. |
---|
381 | // start2: Date |
---|
382 | // The start time of the second time range. |
---|
383 | // end2: Date |
---|
384 | // The end time of the second time range. |
---|
385 | // includeLimits: Boolean |
---|
386 | // Whether include the end time or not. |
---|
387 | // returns: Boolean |
---|
388 | if(start1 == null || start2 == null || end1 == null || end2 == null){ |
---|
389 | return false; |
---|
390 | } |
---|
391 | |
---|
392 | var cal = renderData.dateModule; |
---|
393 | |
---|
394 | if(includeLimits){ |
---|
395 | if(cal.compare(start1, end2) == 1 || cal.compare(start2, end1) == 1){ |
---|
396 | return false; |
---|
397 | } |
---|
398 | }else if(cal.compare(start1, end2) != -1 || cal.compare(start2, end1) != -1){ |
---|
399 | return false; |
---|
400 | } |
---|
401 | return true; |
---|
402 | }, |
---|
403 | |
---|
404 | computeRangeOverlap: function(renderData, start1, end1, start2, end2, includeLimits){ |
---|
405 | // summary: |
---|
406 | // Computes the overlap time range of the time ranges. |
---|
407 | // Returns a vector of Date with at index 0 the start time and at index 1 the end time. |
---|
408 | // renderData: Object. |
---|
409 | // The render data. |
---|
410 | // start1: Date |
---|
411 | // The start time of the first time range. |
---|
412 | // end1: Date |
---|
413 | // The end time of the first time range. |
---|
414 | // start2: Date |
---|
415 | // The start time of the second time range. |
---|
416 | // end2: Date |
---|
417 | // The end time of the second time range. |
---|
418 | // includeLimits: Boolean |
---|
419 | // Whether include the end time or not. |
---|
420 | // returns: Date[] |
---|
421 | var cal = renderData.dateModule; |
---|
422 | |
---|
423 | if(start1 == null || start2 == null || end1 == null || end2 == null){ |
---|
424 | return null; |
---|
425 | } |
---|
426 | |
---|
427 | var comp1 = cal.compare(start1, end2); |
---|
428 | var comp2 = cal.compare(start2, end1); |
---|
429 | |
---|
430 | if(includeLimits){ |
---|
431 | |
---|
432 | if(comp1 == 0 || comp1 == 1 || comp2 == 0 || comp2 == 1){ |
---|
433 | return null; |
---|
434 | } |
---|
435 | } else if(comp1 == 1 || comp2 == 1){ |
---|
436 | return null; |
---|
437 | } |
---|
438 | |
---|
439 | return [ |
---|
440 | this.newDate(cal.compare(start1, start2)>0 ? start1: start2, renderData), |
---|
441 | this.newDate(cal.compare(end1, end2)>0 ? end2: end1, renderData) |
---|
442 | ]; |
---|
443 | }, |
---|
444 | |
---|
445 | isSameDay : function(date1, date2){ |
---|
446 | // summary: |
---|
447 | // Tests if the specified dates are in the same day. |
---|
448 | // date1: Date |
---|
449 | // The first date. |
---|
450 | // date2: Date |
---|
451 | // The second date. |
---|
452 | // returns: Boolean |
---|
453 | if(date1 == null || date2 == null){ |
---|
454 | return false; |
---|
455 | } |
---|
456 | |
---|
457 | return date1.getFullYear() == date2.getFullYear() && |
---|
458 | date1.getMonth() == date2.getMonth() && |
---|
459 | date1.getDate() == date2.getDate(); |
---|
460 | |
---|
461 | }, |
---|
462 | |
---|
463 | computeProjectionOnDate: function(renderData, refDate, date, max){ |
---|
464 | // summary: |
---|
465 | // Computes the time to pixel projection in a day. |
---|
466 | // renderData: Object |
---|
467 | // The render data. |
---|
468 | // refDate: Date |
---|
469 | // The reference date that defines the destination date. |
---|
470 | // date: Date |
---|
471 | // The date to project. |
---|
472 | // max: Integer |
---|
473 | // The size in pixels of the representation of a day. |
---|
474 | // tags: |
---|
475 | // protected |
---|
476 | // returns: Number |
---|
477 | |
---|
478 | var cal = renderData.dateModule; |
---|
479 | |
---|
480 | if(max <= 0 || cal.compare(date, refDate) == -1){ |
---|
481 | return 0; |
---|
482 | } |
---|
483 | |
---|
484 | var referenceDate = this.floorToDay(refDate, false, renderData); |
---|
485 | |
---|
486 | if(date.getDate() != referenceDate.getDate()){ |
---|
487 | if(date.getMonth() == referenceDate.getMonth()){ |
---|
488 | if(date.getDate() < referenceDate.getDate()){ |
---|
489 | return 0; |
---|
490 | } else if(date.getDate() > referenceDate.getDate()){ |
---|
491 | return max; |
---|
492 | } |
---|
493 | }else{ |
---|
494 | if(date.getFullYear() == referenceDate.getFullYear()){ |
---|
495 | if(date.getMonth() < referenceDate.getMonth()){ |
---|
496 | return 0; |
---|
497 | } else if(date.getMonth() > referenceDate.getMonth()){ |
---|
498 | return max; |
---|
499 | } |
---|
500 | }else{ |
---|
501 | if(date.getFullYear() < referenceDate.getFullYear()){ |
---|
502 | return 0; |
---|
503 | } else if(date.getFullYear() > referenceDate.getFullYear()){ |
---|
504 | return max; |
---|
505 | } |
---|
506 | } |
---|
507 | } |
---|
508 | } |
---|
509 | |
---|
510 | var res; |
---|
511 | |
---|
512 | if(this.isSameDay(refDate, date)){ |
---|
513 | |
---|
514 | var d = lang.clone(refDate); |
---|
515 | var minTime = 0; |
---|
516 | |
---|
517 | if(renderData.minHours != null && renderData.minHours != 0){ |
---|
518 | d.setHours(renderData.minHours); |
---|
519 | minTime = d.getHours() * 3600 + d.getMinutes() * 60 + d.getSeconds(); |
---|
520 | } |
---|
521 | |
---|
522 | d = lang.clone(refDate); |
---|
523 | |
---|
524 | var maxTime; |
---|
525 | if(renderData.maxHours == null || renderData.maxHours == 24){ |
---|
526 | maxTime = 86400; // 24h x 60m x 60s |
---|
527 | }else{ |
---|
528 | d.setHours(renderData.maxHours); |
---|
529 | maxTime = d.getHours() * 3600 + d.getMinutes() * 60 + d.getSeconds(); |
---|
530 | } |
---|
531 | |
---|
532 | //precision is the second |
---|
533 | //use this API for daylight time issues. |
---|
534 | var delta = date.getHours() * 3600 + date.getMinutes() * 60 + date.getSeconds() - minTime; |
---|
535 | |
---|
536 | if(delta < 0){ |
---|
537 | return 0; |
---|
538 | } |
---|
539 | if(delta > maxTime){ |
---|
540 | return max; |
---|
541 | } |
---|
542 | |
---|
543 | res = (max * delta)/(maxTime - minTime); |
---|
544 | |
---|
545 | }else{ |
---|
546 | |
---|
547 | if(date.getDate() < refDate.getDate() && |
---|
548 | date.getMonth() == refDate.getMonth()){ |
---|
549 | return 0; |
---|
550 | } |
---|
551 | |
---|
552 | var d2 = this.floorToDay(date); |
---|
553 | var dp1 = renderData.dateModule.add(refDate, "day", 1); |
---|
554 | dp1 = this.floorToDay(dp1, false, renderData); |
---|
555 | |
---|
556 | if(cal.compare(d2, refDate) == 1 && cal.compare(d2, dp1) == 0 || cal.compare(d2, dp1) == 1){ |
---|
557 | res = max; |
---|
558 | }else{ |
---|
559 | res = 0; |
---|
560 | } |
---|
561 | } |
---|
562 | |
---|
563 | return res; |
---|
564 | }, |
---|
565 | |
---|
566 | getTime: function(e, x, y, touchIndex){ |
---|
567 | // summary: |
---|
568 | // Returns the time displayed at the specified point by this component. |
---|
569 | // e: Event |
---|
570 | // Optional mouse event. |
---|
571 | // x: Number |
---|
572 | // Position along the x-axis with respect to the sheet container used if event is not defined. |
---|
573 | // y: Number |
---|
574 | // Position along the y-axis with respect to the sheet container (scroll included) used if event is not defined. |
---|
575 | // touchIndex: Integer |
---|
576 | // If parameter 'e' is not null and a touch event, the index of the touch to use. |
---|
577 | // returns: Date |
---|
578 | return null; |
---|
579 | }, |
---|
580 | |
---|
581 | newDate: function(obj){ |
---|
582 | // summary: |
---|
583 | // Creates a new Date object. |
---|
584 | // obj: Object |
---|
585 | // This object can have several values: |
---|
586 | // |
---|
587 | // - the time in milliseconds since gregorian epoch. |
---|
588 | // - a Date instance |
---|
589 | // returns: Date |
---|
590 | return timeUtil.newDate(obj, this.dateClassObj); |
---|
591 | }, |
---|
592 | |
---|
593 | _isItemInView: function(item){ |
---|
594 | // summary: |
---|
595 | // Computes whether the specified item is entirely in the view or not. |
---|
596 | // item: Object |
---|
597 | // The item to test |
---|
598 | // returns: Boolean |
---|
599 | var rd = this.renderData; |
---|
600 | var cal = rd.dateModule; |
---|
601 | |
---|
602 | if(cal.compare(item.startTime, rd.startTime) == -1){ |
---|
603 | return false; |
---|
604 | } |
---|
605 | |
---|
606 | return cal.compare(item.endTime, rd.endTime) != 1; |
---|
607 | }, |
---|
608 | |
---|
609 | _ensureItemInView: function(item){ |
---|
610 | // summary: |
---|
611 | // If needed, moves the item to be entirely in view. |
---|
612 | // item: Object |
---|
613 | // The item to test |
---|
614 | // returns: Boolean |
---|
615 | // Whether the item has been moved to be in view or not. |
---|
616 | // tags: |
---|
617 | // protected |
---|
618 | |
---|
619 | var rd = this.renderData; |
---|
620 | var cal = rd.dateModule; |
---|
621 | |
---|
622 | var duration = Math.abs(cal.difference(item.startTime, item.endTime, "millisecond")); |
---|
623 | var fixed = false; |
---|
624 | |
---|
625 | if(cal.compare(item.startTime, rd.startTime) == -1){ |
---|
626 | item.startTime = rd.startTime; |
---|
627 | item.endTime = cal.add(item.startTime, "millisecond", duration); |
---|
628 | fixed = true; |
---|
629 | }else if(cal.compare(item.endTime, rd.endTime) == 1){ |
---|
630 | item.endTime = rd.endTime; |
---|
631 | item.startTime = cal.add(item.endTime, "millisecond", -duration); |
---|
632 | fixed = true; |
---|
633 | } |
---|
634 | return fixed; |
---|
635 | }, |
---|
636 | |
---|
637 | ///////////////////////////////////////////////////////// |
---|
638 | // |
---|
639 | // Scrollable |
---|
640 | // |
---|
641 | ///////////////////////////////////////////////////////// |
---|
642 | |
---|
643 | // scrollable: Boolean |
---|
644 | // Indicates whether the view can be scrolled or not. |
---|
645 | scrollable: true, |
---|
646 | |
---|
647 | // autoScroll: Boolean |
---|
648 | // Indicates whether the view can be scrolled automatically. |
---|
649 | // Auto scrolling is used when moving focus to a non visible renderer using keyboard |
---|
650 | // and while editing an item. |
---|
651 | autoScroll: true, |
---|
652 | |
---|
653 | _autoScroll: function(gx, gy, orientation){ |
---|
654 | // summary: |
---|
655 | // Starts or stops the auto scroll according to the mouse cursor position during an item editing. |
---|
656 | // gx: Integer |
---|
657 | // The position of the mouse cursor along the x-axis. |
---|
658 | // gy: Integer |
---|
659 | // The position of the mouse cursor along the y-axis. |
---|
660 | // tags: |
---|
661 | // extension |
---|
662 | |
---|
663 | return false; |
---|
664 | }, |
---|
665 | |
---|
666 | // scrollMethod: String |
---|
667 | // Method used to scroll the view, for example the scroll of column view. |
---|
668 | // Valid value are: |
---|
669 | // |
---|
670 | // - "auto": let the view decide (default), |
---|
671 | // - "css": use css 3d transform, |
---|
672 | // - "dom": use the scrollTop property. |
---|
673 | scrollMethod: "auto", |
---|
674 | |
---|
675 | _setScrollMethodAttr: function(value){ |
---|
676 | if(this.scrollMethod != value){ |
---|
677 | this.scrollMethod = value; |
---|
678 | |
---|
679 | // reset |
---|
680 | if(this._domScroll !== undefined){ |
---|
681 | if(this._domScroll){ |
---|
682 | domStyle.set(this.sheetContainer, this._cssPrefix+"transform", "translateY(0px)"); |
---|
683 | }else{ |
---|
684 | this.scrollContainer.scrollTop = 0; |
---|
685 | } |
---|
686 | } |
---|
687 | |
---|
688 | delete this._domScroll; |
---|
689 | var pos = this._getScrollPosition(); |
---|
690 | delete this._scrollPos; |
---|
691 | |
---|
692 | this._setScrollPosition(pos); |
---|
693 | } |
---|
694 | |
---|
695 | }, |
---|
696 | |
---|
697 | _startAutoScroll: function(step){ |
---|
698 | // summary: |
---|
699 | // Starts the auto scroll of the view (if it's scrollable). Used only during editing. |
---|
700 | // tags: |
---|
701 | // protected |
---|
702 | var sp = this._scrollProps; |
---|
703 | if(!sp){ |
---|
704 | sp = this._scrollProps = {}; |
---|
705 | } |
---|
706 | |
---|
707 | sp.scrollStep = step; |
---|
708 | |
---|
709 | if (!sp.isScrolling){ |
---|
710 | sp.isScrolling = true; |
---|
711 | sp.scrollTimer = setInterval(lang.hitch(this, this._onScrollTimer_tick), 10); |
---|
712 | } |
---|
713 | }, |
---|
714 | |
---|
715 | _stopAutoScroll: function(){ |
---|
716 | // summary: |
---|
717 | // Stops the auto scroll of the view (if it's scrollable). Used only during editing. |
---|
718 | // tags: |
---|
719 | // protected |
---|
720 | var sp = this._scrollProps; |
---|
721 | |
---|
722 | if (sp && sp.isScrolling) { |
---|
723 | clearInterval(sp.scrollTimer); |
---|
724 | sp.scrollTimer = null; |
---|
725 | } |
---|
726 | this._scrollProps = null; |
---|
727 | }, |
---|
728 | |
---|
729 | _onScrollTimer_tick: function(pos){ |
---|
730 | }, |
---|
731 | |
---|
732 | _scrollPos: 0, |
---|
733 | |
---|
734 | getCSSPrefix: function(){ |
---|
735 | // summary: |
---|
736 | // Utility method that return the specific CSS prefix |
---|
737 | // for non standard CSS properties. Ex: -moz-border-radius. |
---|
738 | if(has("ie")){ |
---|
739 | return "-ms-"; |
---|
740 | } |
---|
741 | if(has("webkit")){ |
---|
742 | return "-webkit-"; |
---|
743 | } |
---|
744 | if(has("mozilla")){ |
---|
745 | return "-moz-"; |
---|
746 | } |
---|
747 | if(has("opera")){ |
---|
748 | return "-o-"; |
---|
749 | } |
---|
750 | return ""; |
---|
751 | }, |
---|
752 | |
---|
753 | _setScrollPosition: function(pos){ |
---|
754 | // summary: |
---|
755 | // Sets the scroll position (if the view is scrollable), using the scroll method defined. |
---|
756 | // tags: |
---|
757 | // protected |
---|
758 | |
---|
759 | if(this._scrollPos == pos){ |
---|
760 | return; |
---|
761 | } |
---|
762 | |
---|
763 | // determine scroll method once. |
---|
764 | if(this._domScroll === undefined){ |
---|
765 | |
---|
766 | var sm = this.get("scrollMethod"); |
---|
767 | if(sm === "auto"){ |
---|
768 | this._domScroll = !has("ios") && !has("android") && !has("webkit"); |
---|
769 | }else{ |
---|
770 | this._domScroll = sm === "dom"; |
---|
771 | } |
---|
772 | } |
---|
773 | |
---|
774 | var containerSize = domGeometry.getMarginBox(this.scrollContainer); |
---|
775 | var sheetSize = domGeometry.getMarginBox(this.sheetContainer); |
---|
776 | var max = sheetSize.h - containerSize.h; |
---|
777 | |
---|
778 | if(pos < 0){ |
---|
779 | pos = 0; |
---|
780 | }else if(pos > max){ |
---|
781 | pos = max; |
---|
782 | } |
---|
783 | |
---|
784 | this._scrollPos = pos; |
---|
785 | |
---|
786 | if(this._domScroll){ |
---|
787 | this.scrollContainer.scrollTop = pos; |
---|
788 | }else{ |
---|
789 | if(!this._cssPrefix){ |
---|
790 | this._cssPrefix = this.getCSSPrefix(); |
---|
791 | } |
---|
792 | domStyle.set(this.sheetContainer, this._cssPrefix+"transform", "translateY(-"+pos+"px)"); |
---|
793 | } |
---|
794 | }, |
---|
795 | |
---|
796 | _getScrollPosition: function(){ |
---|
797 | // summary: |
---|
798 | // Returns the scroll position (if the view is scrollable), using the scroll method defined. |
---|
799 | // tags: |
---|
800 | // protected |
---|
801 | |
---|
802 | return this._scrollPos; |
---|
803 | }, |
---|
804 | |
---|
805 | scrollView: function(dir){ |
---|
806 | // summary: |
---|
807 | // If the view is scrollable, scrolls it to the specified direction. |
---|
808 | // dir: Integer |
---|
809 | // Direction of the scroll. Valid values are -1 and 1. |
---|
810 | // tags: |
---|
811 | // extension |
---|
812 | }, |
---|
813 | |
---|
814 | ensureVisibility: function(start, end, margin, visibilityTarget, duration){ |
---|
815 | // summary: |
---|
816 | // Scrolls the view if the [start, end] time range is not visible or only partially visible. |
---|
817 | // start: Date |
---|
818 | // Start time of the range of interest. |
---|
819 | // end: Date |
---|
820 | // End time of the range of interest. |
---|
821 | // margin: int |
---|
822 | // Margin in minutes around the time range. |
---|
823 | // visibilityTarget: String |
---|
824 | // The end(s) of the time range to make visible. |
---|
825 | // Valid values are: "start", "end", "both". |
---|
826 | // duration: Number |
---|
827 | // Optional, the maximum duration of the scroll animation. |
---|
828 | // tags: |
---|
829 | // extension |
---|
830 | |
---|
831 | }, |
---|
832 | |
---|
833 | //////////////////////////////////////////////////////// |
---|
834 | // |
---|
835 | // Store & Items |
---|
836 | // |
---|
837 | //////////////////////////////////////////////////////// |
---|
838 | |
---|
839 | _getStoreAttr: function(){ |
---|
840 | if(this.owner){ |
---|
841 | return this.owner.get("store"); |
---|
842 | } |
---|
843 | return this.store; |
---|
844 | }, |
---|
845 | |
---|
846 | _setItemsAttr: function(value){ |
---|
847 | this._set("items", value); |
---|
848 | this.displayedItemsInvalidated = true; |
---|
849 | }, |
---|
850 | |
---|
851 | _refreshItemsRendering: function(){ |
---|
852 | var rd = this.renderData; |
---|
853 | this._computeVisibleItems(rd); |
---|
854 | this._layoutRenderers(rd); |
---|
855 | }, |
---|
856 | |
---|
857 | invalidateLayout: function(){ |
---|
858 | // summary: |
---|
859 | // Triggers a re-layout of the renderers. |
---|
860 | this._layoutRenderers(this.renderData); |
---|
861 | }, |
---|
862 | |
---|
863 | //////////////////////////////////////////////////////// |
---|
864 | // |
---|
865 | // Layout |
---|
866 | // |
---|
867 | //////////////////////////////////////////////////////// |
---|
868 | |
---|
869 | computeOverlapping: function(layoutItems, func){ |
---|
870 | // summary: |
---|
871 | // Computes the overlap layout of a list of items. A lane and extent properties are added to each layout item. |
---|
872 | // layoutItems: Object[] |
---|
873 | // List of layout items, each item must have a start and end properties. |
---|
874 | // addedPass: Function |
---|
875 | // Whether computes the extent of each item renderer on free sibling lanes. |
---|
876 | // returns: Object |
---|
877 | // tags: |
---|
878 | // protected |
---|
879 | |
---|
880 | |
---|
881 | if(layoutItems.length == 0){ |
---|
882 | return { |
---|
883 | numLanes: 0, |
---|
884 | addedPassRes: [1] |
---|
885 | }; |
---|
886 | } |
---|
887 | |
---|
888 | var lanes = []; |
---|
889 | |
---|
890 | for(var i=0; i<layoutItems.length; i++){ |
---|
891 | var layoutItem = layoutItems[i]; |
---|
892 | this._layoutPass1(layoutItem, lanes); |
---|
893 | } |
---|
894 | |
---|
895 | var addedPassRes = null; |
---|
896 | if(func){ |
---|
897 | addedPassRes = lang.hitch(this, func)(lanes); |
---|
898 | } |
---|
899 | |
---|
900 | return { |
---|
901 | numLanes: lanes.length, |
---|
902 | addedPassRes: addedPassRes |
---|
903 | }; |
---|
904 | }, |
---|
905 | |
---|
906 | _layoutPass1: function (layoutItem, lanes){ |
---|
907 | // summary: |
---|
908 | // First pass of the overlap layout. Find a lane where the item can be placed or create a new one. |
---|
909 | // layoutItem: Object |
---|
910 | // An object that contains a start and end properties at least. |
---|
911 | // lanes: |
---|
912 | // The array of lanes. |
---|
913 | // tags: |
---|
914 | // protected |
---|
915 | var stop = true; |
---|
916 | |
---|
917 | for(var i=0; i<lanes.length; i++){ |
---|
918 | var lane = lanes[i]; |
---|
919 | stop = false; |
---|
920 | for(var j=0; j<lane.length && !stop; j++){ |
---|
921 | if(lane[j].start < layoutItem.end && layoutItem.start < lane[j].end){ |
---|
922 | // one already placed item is overlapping |
---|
923 | stop = true; |
---|
924 | lane[j].extent = 1; |
---|
925 | } |
---|
926 | } |
---|
927 | if(!stop){ |
---|
928 | //we have found a place |
---|
929 | layoutItem.lane = i; |
---|
930 | layoutItem.extent = -1; |
---|
931 | lane.push(layoutItem); |
---|
932 | return; |
---|
933 | } |
---|
934 | } |
---|
935 | |
---|
936 | //no place found -> add a lane |
---|
937 | lanes.push([layoutItem]); |
---|
938 | layoutItem.lane = lanes.length-1; |
---|
939 | layoutItem.extent = -1; |
---|
940 | }, |
---|
941 | |
---|
942 | |
---|
943 | |
---|
944 | _layoutInterval: function(renderData, index, start, end, items){ |
---|
945 | // summary: |
---|
946 | // For each item in the items list: retrieve a renderer, compute its location and size and add it to the DOM. |
---|
947 | // renderData: Object |
---|
948 | // The render data. |
---|
949 | // index: Integer |
---|
950 | // The index of the interval. |
---|
951 | // start: Date |
---|
952 | // The start time of the displayed date interval. |
---|
953 | // end: Date |
---|
954 | // The end time of the displayed date interval. |
---|
955 | // items: Object[] |
---|
956 | // The list of the items to represent. |
---|
957 | // tags: |
---|
958 | // extension |
---|
959 | }, |
---|
960 | |
---|
961 | // layoutPriorityFunction: Function |
---|
962 | // An optional comparison function use to determine the order the item will be laid out |
---|
963 | // The function is used to sort an array and must, as any sorting function, take two items |
---|
964 | // as argument and must return an integer whose sign define order between arguments. |
---|
965 | // By default, a comparison by start time then end time is used. |
---|
966 | layoutPriorityFunction: null, |
---|
967 | |
---|
968 | _sortItemsFunction: function(a, b){ |
---|
969 | var res = this.dateModule.compare(a.startTime, b.startTime); |
---|
970 | if(res == 0){ |
---|
971 | res = -1 * this.dateModule.compare(a.endTime, b.endTime); |
---|
972 | } |
---|
973 | return res; |
---|
974 | }, |
---|
975 | |
---|
976 | _layoutRenderers: function(renderData){ |
---|
977 | // summary: |
---|
978 | // Renders the data items. This method will call the _layoutInterval() method. |
---|
979 | // renderData: Object |
---|
980 | // The render data. |
---|
981 | // tags: |
---|
982 | // protected |
---|
983 | if(!renderData.items){ |
---|
984 | return; |
---|
985 | } |
---|
986 | |
---|
987 | // recycle renderers first |
---|
988 | this._recycleItemRenderers(); |
---|
989 | |
---|
990 | var cal = renderData.dateModule; |
---|
991 | |
---|
992 | // Date |
---|
993 | var startDate = this.newDate(renderData.startTime); |
---|
994 | |
---|
995 | // Date and time |
---|
996 | var startTime = lang.clone(startDate); |
---|
997 | |
---|
998 | var endDate; |
---|
999 | |
---|
1000 | var items = renderData.items.concat(); |
---|
1001 | |
---|
1002 | var itemsTemp = [], events; |
---|
1003 | |
---|
1004 | var index = 0; |
---|
1005 | |
---|
1006 | while(cal.compare(startDate, renderData.endTime) == -1 && items.length > 0){ |
---|
1007 | |
---|
1008 | endDate = cal.add(startDate, this._layoutUnit, this._layoutStep); |
---|
1009 | endDate = this.floorToDay(endDate, true, renderData); |
---|
1010 | |
---|
1011 | var endTime = lang.clone(endDate); |
---|
1012 | |
---|
1013 | if(renderData.minHours){ |
---|
1014 | startTime.setHours(renderData.minHours); |
---|
1015 | } |
---|
1016 | |
---|
1017 | if(renderData.maxHours && renderData.maxHours != 24){ |
---|
1018 | endTime = cal.add(endDate, "day", -1); |
---|
1019 | endTime = this.floorToDay(endTime, true, renderData); |
---|
1020 | endTime.setHours(renderData.maxHours); |
---|
1021 | } |
---|
1022 | |
---|
1023 | // look for events that overlap the current sub interval |
---|
1024 | events = arr.filter(items, function(item){ |
---|
1025 | var r = this.isOverlapping(renderData, item.startTime, item.endTime, startTime, endTime); |
---|
1026 | if(r){ |
---|
1027 | // item was not fully processed as it overlaps another sub interval |
---|
1028 | if(cal.compare(item.endTime, endTime) == 1){ |
---|
1029 | itemsTemp.push(item); |
---|
1030 | } |
---|
1031 | }else{ |
---|
1032 | itemsTemp.push(item); |
---|
1033 | } |
---|
1034 | return r; |
---|
1035 | }, this); |
---|
1036 | |
---|
1037 | items = itemsTemp; |
---|
1038 | itemsTemp = []; |
---|
1039 | |
---|
1040 | // if event are in the current sub interval, layout them |
---|
1041 | if(events.length > 0){ |
---|
1042 | // Sort the item according a sorting function, by default start time then end time comparison are used. |
---|
1043 | events.sort(lang.hitch(this, this.layoutPriorityFunction ? this.layoutPriorityFunction : this._sortItemsFunction)); |
---|
1044 | this._layoutInterval(renderData, index, startTime, endTime, events); |
---|
1045 | } |
---|
1046 | |
---|
1047 | startDate = endDate; |
---|
1048 | startTime = lang.clone(startDate); |
---|
1049 | |
---|
1050 | index++; |
---|
1051 | } |
---|
1052 | |
---|
1053 | this._onRenderersLayoutDone(this); |
---|
1054 | }, |
---|
1055 | |
---|
1056 | ///////////////////////////////////////////////////////////////// |
---|
1057 | // |
---|
1058 | // Renderers management |
---|
1059 | // |
---|
1060 | //////////////////////////////////////////////////////////////// |
---|
1061 | |
---|
1062 | _recycleItemRenderers: function(remove){ |
---|
1063 | // summary: |
---|
1064 | // Recycles all the item renderers. |
---|
1065 | // remove: Boolean |
---|
1066 | // Whether remove the DOM node from it parent. |
---|
1067 | // tags: |
---|
1068 | // protected |
---|
1069 | while(this.rendererList.length>0){ |
---|
1070 | this._recycleRenderer(this.rendererList.pop(), remove); |
---|
1071 | } |
---|
1072 | this.itemToRenderer = {}; |
---|
1073 | }, |
---|
1074 | |
---|
1075 | // rendererPool: [protected] Array |
---|
1076 | // The stack of recycled renderers available. |
---|
1077 | rendererPool: null, |
---|
1078 | |
---|
1079 | // rendererList: [protected] Array |
---|
1080 | // The list of used renderers |
---|
1081 | rendererList: null, |
---|
1082 | |
---|
1083 | // itemToRenderer: [protected] Object |
---|
1084 | // The associated array item to renderer list. |
---|
1085 | itemToRenderer: null, |
---|
1086 | |
---|
1087 | getRenderers: function(item){ |
---|
1088 | // summary: |
---|
1089 | // Returns the renderers that are currently used to displayed the speficied item. |
---|
1090 | // Returns an array of objects that contains two properties: |
---|
1091 | // - container: The DOM node that contains the renderer. |
---|
1092 | // - renderer: The dojox.calendar._RendererMixin instance. |
---|
1093 | // Do not keep references on the renderers are they are recycled and reused for other items. |
---|
1094 | // item: Object |
---|
1095 | // The data or render item. |
---|
1096 | // returns: Object[] |
---|
1097 | if(item == null || item.id == null){ |
---|
1098 | return null; |
---|
1099 | } |
---|
1100 | var list = this.itemToRenderer[item.id]; |
---|
1101 | return list == null ? null : list.concat(); |
---|
1102 | }, |
---|
1103 | |
---|
1104 | _rendererHandles: {}, |
---|
1105 | |
---|
1106 | // itemToRendererKindFunc: Function |
---|
1107 | // An optional function to associate a kind of renderer ("horizontal", "label" or null) with the specified item. |
---|
1108 | // By default, if an item is lasting more that 24 hours an horizontal item is used, otherwise a label is used. |
---|
1109 | itemToRendererKindFunc: null, |
---|
1110 | |
---|
1111 | _itemToRendererKind: function(item){ |
---|
1112 | // summary: |
---|
1113 | // Associates a kind of renderer with a data item. |
---|
1114 | // item: Object |
---|
1115 | // The data item. |
---|
1116 | // returns: String |
---|
1117 | // tags: |
---|
1118 | // protected |
---|
1119 | if(this.itemToRendererKindFunc){ |
---|
1120 | return this.itemToRendererKindFunc(item); |
---|
1121 | } |
---|
1122 | return this._defaultItemToRendererKindFunc(item); // String |
---|
1123 | }, |
---|
1124 | |
---|
1125 | _defaultItemToRendererKindFunc:function(item){ |
---|
1126 | // tags: |
---|
1127 | // private |
---|
1128 | return null; |
---|
1129 | }, |
---|
1130 | |
---|
1131 | _createRenderer: function(item, kind, rendererClass, cssClass){ |
---|
1132 | // summary: |
---|
1133 | // Creates an item renderer of the specified kind. A renderer is an object with the "container" and "instance" properties. |
---|
1134 | // item: Object |
---|
1135 | // The data item. |
---|
1136 | // kind: String |
---|
1137 | // The kind of renderer. |
---|
1138 | // rendererClass: Object |
---|
1139 | // The class to instantiate to create the renderer. |
---|
1140 | // returns: Object |
---|
1141 | // tags: |
---|
1142 | // protected |
---|
1143 | |
---|
1144 | if(item != null && kind != null && rendererClass != null){ |
---|
1145 | |
---|
1146 | var res=null, renderer=null; |
---|
1147 | |
---|
1148 | var pool = this.rendererPool[kind]; |
---|
1149 | |
---|
1150 | if(pool != null){ |
---|
1151 | res = pool.shift(); |
---|
1152 | } |
---|
1153 | |
---|
1154 | if (res == null){ |
---|
1155 | |
---|
1156 | renderer = new rendererClass; |
---|
1157 | |
---|
1158 | res = { |
---|
1159 | renderer: renderer, |
---|
1160 | container: renderer.domNode, |
---|
1161 | kind: kind |
---|
1162 | }; |
---|
1163 | |
---|
1164 | this._onRendererCreated({renderer:res, source:this, item:item}); |
---|
1165 | |
---|
1166 | } else { |
---|
1167 | renderer = res.renderer; |
---|
1168 | |
---|
1169 | this._onRendererReused({renderer:renderer, source:this, item:item}); |
---|
1170 | } |
---|
1171 | |
---|
1172 | renderer.owner = this; |
---|
1173 | renderer.set("rendererKind", kind); |
---|
1174 | renderer.set("item", item); |
---|
1175 | |
---|
1176 | var list = this.itemToRenderer[item.id]; |
---|
1177 | if (list == null) { |
---|
1178 | this.itemToRenderer[item.id] = list = []; |
---|
1179 | } |
---|
1180 | list.push(res); |
---|
1181 | |
---|
1182 | this.rendererList.push(res); |
---|
1183 | return res; |
---|
1184 | } |
---|
1185 | return null; |
---|
1186 | }, |
---|
1187 | |
---|
1188 | _onRendererCreated: function(e){ |
---|
1189 | if(e.source == this){ |
---|
1190 | this.onRendererCreated(e); |
---|
1191 | } |
---|
1192 | if(this.owner != null){ |
---|
1193 | this.owner._onRendererCreated(e); |
---|
1194 | } |
---|
1195 | }, |
---|
1196 | |
---|
1197 | onRendererCreated: function(e){ |
---|
1198 | // summary: |
---|
1199 | // Event dispatched when an item renderer has been created. |
---|
1200 | // e: __rendererLifecycleEventArgs |
---|
1201 | // The renderer lifecycle event. |
---|
1202 | // tags: |
---|
1203 | // callback |
---|
1204 | }, |
---|
1205 | |
---|
1206 | _onRendererRecycled: function(e){ |
---|
1207 | if(e.source == this){ |
---|
1208 | this.onRendererRecycled(e); |
---|
1209 | } |
---|
1210 | if(this.owner != null){ |
---|
1211 | this.owner._onRendererRecycled(e); |
---|
1212 | } |
---|
1213 | }, |
---|
1214 | |
---|
1215 | onRendererRecycled: function(e){ |
---|
1216 | // summary: |
---|
1217 | // Event dispatched when an item renderer has been recycled. |
---|
1218 | // e: __rendererLifecycleEventArgs |
---|
1219 | // The renderer lifecycle event. |
---|
1220 | // tags: |
---|
1221 | // callback |
---|
1222 | |
---|
1223 | }, |
---|
1224 | |
---|
1225 | _onRendererReused: function(e){ |
---|
1226 | if(e.source == this){ |
---|
1227 | this.onRendererReused(e); |
---|
1228 | } |
---|
1229 | if(this.owner != null){ |
---|
1230 | this.owner._onRendererReused(e); |
---|
1231 | } |
---|
1232 | }, |
---|
1233 | |
---|
1234 | onRendererReused: function(e){ |
---|
1235 | // summary: |
---|
1236 | // Event dispatched when an item renderer that was recycled is reused. |
---|
1237 | // e: __rendererLifecycleEventArgs |
---|
1238 | // The renderer lifecycle event. |
---|
1239 | // tags: |
---|
1240 | // callback |
---|
1241 | }, |
---|
1242 | |
---|
1243 | _onRendererDestroyed: function(e){ |
---|
1244 | if(e.source == this){ |
---|
1245 | this.onRendererDestroyed(e); |
---|
1246 | } |
---|
1247 | if(this.owner != null){ |
---|
1248 | this.owner._onRendererDestroyed(e); |
---|
1249 | } |
---|
1250 | }, |
---|
1251 | |
---|
1252 | onRendererDestroyed: function(e){ |
---|
1253 | // summary: |
---|
1254 | // Event dispatched when an item renderer is destroyed. |
---|
1255 | // e: __rendererLifecycleEventArgs |
---|
1256 | // The renderer lifecycle event. |
---|
1257 | // tags: |
---|
1258 | // callback |
---|
1259 | }, |
---|
1260 | |
---|
1261 | _onRenderersLayoutDone: function(view){ |
---|
1262 | // tags: |
---|
1263 | // private |
---|
1264 | |
---|
1265 | this.onRenderersLayoutDone(view); |
---|
1266 | if(this.owner != null){ |
---|
1267 | this.owner._onRenderersLayoutDone(view); |
---|
1268 | } |
---|
1269 | }, |
---|
1270 | |
---|
1271 | onRenderersLayoutDone: function(view){ |
---|
1272 | // summary: |
---|
1273 | // Event triggered when item renderers layout has been done. |
---|
1274 | // tags: |
---|
1275 | // callback |
---|
1276 | }, |
---|
1277 | |
---|
1278 | _recycleRenderer: function(renderer, remove){ |
---|
1279 | // summary: |
---|
1280 | // Recycles the item renderer to be reused in the future. |
---|
1281 | // renderer: dojox/calendar/_RendererMixin |
---|
1282 | // The item renderer to recycle. |
---|
1283 | // tags: |
---|
1284 | // protected |
---|
1285 | |
---|
1286 | this._onRendererRecycled({renderer:renderer, source:this}); |
---|
1287 | |
---|
1288 | var pool = this.rendererPool[renderer.kind]; |
---|
1289 | |
---|
1290 | if(pool == null){ |
---|
1291 | this.rendererPool[renderer.kind] = [renderer]; |
---|
1292 | }else{ |
---|
1293 | pool.push(renderer); |
---|
1294 | } |
---|
1295 | |
---|
1296 | if(remove){ |
---|
1297 | renderer.container.parentNode.removeChild(renderer.container); |
---|
1298 | } |
---|
1299 | |
---|
1300 | domStyle.set(renderer.container, "display", "none"); |
---|
1301 | |
---|
1302 | renderer.renderer.owner = null; |
---|
1303 | renderer.renderer.set("item", null); |
---|
1304 | }, |
---|
1305 | |
---|
1306 | _destroyRenderer: function(renderer){ |
---|
1307 | // summary: |
---|
1308 | // Destroys the item renderer. |
---|
1309 | // renderer: dojox/calendar/_RendererMixin |
---|
1310 | // The item renderer to destroy. |
---|
1311 | // tags: |
---|
1312 | // protected |
---|
1313 | this._onRendererDestroyed({renderer:renderer, source:this}); |
---|
1314 | |
---|
1315 | var ir = renderer.renderer; |
---|
1316 | |
---|
1317 | if(ir["destroy"]){ |
---|
1318 | ir.destroy(); |
---|
1319 | } |
---|
1320 | |
---|
1321 | html.destroy(renderer.container); |
---|
1322 | }, |
---|
1323 | |
---|
1324 | _destroyRenderersByKind: function(kind){ |
---|
1325 | // tags: |
---|
1326 | // private |
---|
1327 | |
---|
1328 | var list = []; |
---|
1329 | for(var i=0;i<this.rendererList.length;i++){ |
---|
1330 | var ir = this.rendererList[i]; |
---|
1331 | if(ir.kind == kind){ |
---|
1332 | this._destroyRenderer(ir); |
---|
1333 | }else{ |
---|
1334 | list.push(ir); |
---|
1335 | } |
---|
1336 | } |
---|
1337 | |
---|
1338 | this.rendererList = list; |
---|
1339 | |
---|
1340 | var pool = this.rendererPool[kind]; |
---|
1341 | if(pool){ |
---|
1342 | while(pool.length > 0){ |
---|
1343 | this._destroyRenderer(pool.pop()); |
---|
1344 | } |
---|
1345 | } |
---|
1346 | |
---|
1347 | }, |
---|
1348 | |
---|
1349 | |
---|
1350 | _updateEditingCapabilities: function(item, renderer){ |
---|
1351 | // summary: |
---|
1352 | // Update the moveEnabled and resizeEnabled properties of a renderer according to its event current editing state. |
---|
1353 | // item: Object |
---|
1354 | // The store data item. |
---|
1355 | // renderer: dojox/calendar/_RendererMixin |
---|
1356 | // The item renderer. |
---|
1357 | // tags: |
---|
1358 | // protected |
---|
1359 | |
---|
1360 | var moveEnabled = this.isItemMoveEnabled(item, renderer.rendererKind); |
---|
1361 | var resizeEnabled = this.isItemResizeEnabled(item, renderer.rendererKind); |
---|
1362 | var changed = false; |
---|
1363 | |
---|
1364 | if(moveEnabled != renderer.get("moveEnabled")){ |
---|
1365 | renderer.set("moveEnabled", moveEnabled); |
---|
1366 | changed = true; |
---|
1367 | } |
---|
1368 | if(resizeEnabled != renderer.get("resizeEnabled")){ |
---|
1369 | renderer.set("resizeEnabled", resizeEnabled); |
---|
1370 | changed = true; |
---|
1371 | } |
---|
1372 | |
---|
1373 | if(changed){ |
---|
1374 | renderer.updateRendering(); |
---|
1375 | } |
---|
1376 | }, |
---|
1377 | |
---|
1378 | updateRenderers: function(obj, stateOnly){ |
---|
1379 | // summary: |
---|
1380 | // Updates all the renderers that represents the specified item(s). |
---|
1381 | // obj: Object |
---|
1382 | // A render item or an array of render items. |
---|
1383 | // stateOnly: Boolean |
---|
1384 | // Whether only the state of the item has changed (selected, edited, edited, focused) or a more global change has occured. |
---|
1385 | // tags: |
---|
1386 | // protected |
---|
1387 | |
---|
1388 | if(obj == null){ |
---|
1389 | return; |
---|
1390 | } |
---|
1391 | |
---|
1392 | var items = lang.isArray(obj) ? obj : [obj]; |
---|
1393 | |
---|
1394 | for(var i=0; i<items.length; i++){ |
---|
1395 | |
---|
1396 | var item = items[i]; |
---|
1397 | |
---|
1398 | if(item == null || item.id == null){ |
---|
1399 | continue; |
---|
1400 | } |
---|
1401 | |
---|
1402 | var list = this.itemToRenderer[item.id]; |
---|
1403 | |
---|
1404 | if(list == null){ |
---|
1405 | continue; |
---|
1406 | } |
---|
1407 | |
---|
1408 | var selected = this.isItemSelected(item); |
---|
1409 | var hovered = this.isItemHovered(item); |
---|
1410 | var edited = this.isItemBeingEdited(item); |
---|
1411 | var focused = this.showFocus ? this.isItemFocused(item) : false; |
---|
1412 | |
---|
1413 | for(var j = 0; j < list.length; j++){ |
---|
1414 | |
---|
1415 | var renderer = list[j].renderer; |
---|
1416 | renderer.set("hovered", hovered); |
---|
1417 | renderer.set("selected", selected); |
---|
1418 | renderer.set("edited", edited); |
---|
1419 | renderer.set("focused", focused); |
---|
1420 | renderer.set("storeState", this.getItemStoreState(item)); |
---|
1421 | |
---|
1422 | this.applyRendererZIndex(item, list[j], hovered, selected, edited, focused); |
---|
1423 | |
---|
1424 | if(!stateOnly){ |
---|
1425 | renderer.set("item", item); // force content refresh |
---|
1426 | if(renderer.updateRendering){ |
---|
1427 | renderer.updateRendering(); // reuse previously set dimensions |
---|
1428 | } |
---|
1429 | } |
---|
1430 | } |
---|
1431 | |
---|
1432 | } |
---|
1433 | }, |
---|
1434 | |
---|
1435 | applyRendererZIndex: function(item, renderer, hovered, selected, edited, focused){ |
---|
1436 | // summary: |
---|
1437 | // Applies the z-index to the renderer based on the state of the item. |
---|
1438 | // This methods is setting a z-index of 20 is the item is selected or edited |
---|
1439 | // and the current lane value computed by the overlap layout (i.e. the renderers |
---|
1440 | // are stacked according to their lane). |
---|
1441 | // item: Object |
---|
1442 | // The render item. |
---|
1443 | // renderer: Object |
---|
1444 | // A renderer associated with the render item. |
---|
1445 | // hovered: Boolean |
---|
1446 | // Whether the item is hovered or not. |
---|
1447 | // selected: Boolean |
---|
1448 | // Whether the item is selected or not. |
---|
1449 | // edited: Boolean |
---|
1450 | // Whether the item is being edited not not. |
---|
1451 | // focused: Boolean |
---|
1452 | // Whether the item is focused not not. |
---|
1453 | // tags: |
---|
1454 | // protected |
---|
1455 | |
---|
1456 | domStyle.set(renderer.container, {"zIndex": edited || selected ? 20: item.lane == undefined ? 0 : item.lane}); |
---|
1457 | }, |
---|
1458 | |
---|
1459 | getIdentity: function(item){ |
---|
1460 | return this.owner ? this.owner.getIdentity(item) : item.id; |
---|
1461 | }, |
---|
1462 | |
---|
1463 | ///////////////////////////////////////////////////// |
---|
1464 | // |
---|
1465 | // Hovered item |
---|
1466 | // |
---|
1467 | //////////////////////////////////////////////////// |
---|
1468 | |
---|
1469 | _setHoveredItem: function(item, renderer){ |
---|
1470 | // summary: |
---|
1471 | // Sets the current hovered item. |
---|
1472 | // item: Object |
---|
1473 | // The data item. |
---|
1474 | // renderer: dojox/calendar/_RendererMixin |
---|
1475 | // The item renderer. |
---|
1476 | // tags: |
---|
1477 | // protected |
---|
1478 | |
---|
1479 | if(this.owner){ |
---|
1480 | this.owner._setHoveredItem(item, renderer); |
---|
1481 | return; |
---|
1482 | } |
---|
1483 | |
---|
1484 | if(this.hoveredItem && item && this.hoveredItem.id != item.id || |
---|
1485 | item == null || this.hoveredItem == null){ |
---|
1486 | var old = this.hoveredItem; |
---|
1487 | this.hoveredItem = item; |
---|
1488 | |
---|
1489 | this.updateRenderers([old, this.hoveredItem], true); |
---|
1490 | |
---|
1491 | if(item && renderer){ |
---|
1492 | this._updateEditingCapabilities(item._item ? item._item : item, renderer); |
---|
1493 | } |
---|
1494 | } |
---|
1495 | }, |
---|
1496 | |
---|
1497 | // hoveredItem: Object |
---|
1498 | // The currently hovered data item. |
---|
1499 | hoveredItem: null, |
---|
1500 | |
---|
1501 | isItemHovered: function(item){ |
---|
1502 | // summary: |
---|
1503 | // Returns whether the specified item is hovered or not. |
---|
1504 | // item: Object |
---|
1505 | // The item. |
---|
1506 | // returns: Boolean |
---|
1507 | if (this._isEditing && this._edProps){ |
---|
1508 | return item.id == this._edProps.editedItem.id; |
---|
1509 | } |
---|
1510 | return this.owner ? |
---|
1511 | this.owner.isItemHovered(item) : |
---|
1512 | this.hoveredItem != null && this.hoveredItem.id == item.id; |
---|
1513 | |
---|
1514 | }, |
---|
1515 | |
---|
1516 | isItemFocused: function(item){ |
---|
1517 | // summary: |
---|
1518 | // Returns whether the specified item is focused or not. |
---|
1519 | // item: Object |
---|
1520 | // The item. |
---|
1521 | // returns: Boolean |
---|
1522 | return this._isItemFocused ? this._isItemFocused(item) : false; |
---|
1523 | }, |
---|
1524 | |
---|
1525 | //////////////////////////////////////////////////////////////////// |
---|
1526 | // |
---|
1527 | // Selection delegation |
---|
1528 | // |
---|
1529 | /////////////////////////////////////////////////////////////////// |
---|
1530 | |
---|
1531 | _setSelectionModeAttr: function(value){ |
---|
1532 | if(this.owner){ |
---|
1533 | this.owner.set("selectionMode", value); |
---|
1534 | }else{ |
---|
1535 | this.inherited(arguments); |
---|
1536 | } |
---|
1537 | }, |
---|
1538 | |
---|
1539 | _getSelectionModeAttr: function(value){ |
---|
1540 | if(this.owner){ |
---|
1541 | return this.owner.get("selectionMode"); |
---|
1542 | } |
---|
1543 | return this.inherited(arguments); |
---|
1544 | }, |
---|
1545 | |
---|
1546 | _setSelectedItemAttr: function(value){ |
---|
1547 | if(this.owner){ |
---|
1548 | this.owner.set("selectedItem", value); |
---|
1549 | }else{ |
---|
1550 | this.inherited(arguments); |
---|
1551 | } |
---|
1552 | }, |
---|
1553 | |
---|
1554 | _getSelectedItemAttr: function(value){ |
---|
1555 | if(this.owner){ |
---|
1556 | return this.owner.get("selectedItem"); |
---|
1557 | } |
---|
1558 | return this.selectedItem; // no getter on super class (dojox.widget.Selection) |
---|
1559 | }, |
---|
1560 | |
---|
1561 | _setSelectedItemsAttr: function(value){ |
---|
1562 | if(this.owner){ |
---|
1563 | this.owner.set("selectedItems", value); |
---|
1564 | }else{ |
---|
1565 | this.inherited(arguments); |
---|
1566 | } |
---|
1567 | }, |
---|
1568 | |
---|
1569 | _getSelectedItemsAttr: function(){ |
---|
1570 | if(this.owner){ |
---|
1571 | return this.owner.get("selectedItems"); |
---|
1572 | } |
---|
1573 | return this.inherited(arguments); |
---|
1574 | }, |
---|
1575 | |
---|
1576 | isItemSelected: function(item){ |
---|
1577 | if(this.owner){ |
---|
1578 | return this.owner.isItemSelected(item); |
---|
1579 | } |
---|
1580 | return this.inherited(arguments); |
---|
1581 | }, |
---|
1582 | |
---|
1583 | selectFromEvent: function(e, item, renderer, dispatch){ |
---|
1584 | if(this.owner){ |
---|
1585 | this.owner.selectFromEvent(e, item, renderer, dispatch); |
---|
1586 | }else{ |
---|
1587 | this.inherited(arguments); |
---|
1588 | } |
---|
1589 | }, |
---|
1590 | |
---|
1591 | setItemSelected: function(item, value){ |
---|
1592 | if(this.owner){ |
---|
1593 | this.owner.setItemSelected(item, value); |
---|
1594 | }else{ |
---|
1595 | this.inherited(arguments); |
---|
1596 | } |
---|
1597 | }, |
---|
1598 | |
---|
1599 | //////////////////////////////////////////////////////////////////// |
---|
1600 | // |
---|
1601 | // Event creation |
---|
1602 | // |
---|
1603 | /////////////////////////////////////////////////////////////////// |
---|
1604 | |
---|
1605 | createItemFunc: null, |
---|
1606 | /*===== |
---|
1607 | createItemFunc: function(view, d, e){ |
---|
1608 | // summary: |
---|
1609 | // A user supplied function that creates a new event. |
---|
1610 | // view: ViewBase |
---|
1611 | // the current view, |
---|
1612 | // d: Date |
---|
1613 | // the date at the clicked location. |
---|
1614 | // e: MouseEvemt |
---|
1615 | // the mouse event (can be used to return null for example) |
---|
1616 | |
---|
1617 | }, |
---|
1618 | =====*/ |
---|
1619 | |
---|
1620 | |
---|
1621 | _getCreateItemFuncAttr: function(){ |
---|
1622 | if(this.owner){ |
---|
1623 | return this.owner.get("createItemFunc"); |
---|
1624 | } |
---|
1625 | return this.createItemFunc; |
---|
1626 | }, |
---|
1627 | |
---|
1628 | // createOnGridClick: Boolean |
---|
1629 | // Indicates whether the user can create new event by clicking and dragging the grid. |
---|
1630 | // A createItem function must be defined on the view or the calendar object. |
---|
1631 | createOnGridClick: false, |
---|
1632 | |
---|
1633 | _getCreateOnGridClickAttr: function(){ |
---|
1634 | if(this.owner){ |
---|
1635 | return this.owner.get("createOnGridClick"); |
---|
1636 | } |
---|
1637 | return this.createOnGridClick; |
---|
1638 | }, |
---|
1639 | |
---|
1640 | //////////////////////////////////////////////////////////////////// |
---|
1641 | // |
---|
1642 | // Event creation |
---|
1643 | // |
---|
1644 | /////////////////////////////////////////////////////////////////// |
---|
1645 | |
---|
1646 | _gridMouseDown: false, |
---|
1647 | _tempIdCount: 0, |
---|
1648 | _tempItemsMap: null, |
---|
1649 | |
---|
1650 | _onGridMouseDown: function(e){ |
---|
1651 | // tags: |
---|
1652 | // private |
---|
1653 | this._gridMouseDown = true; |
---|
1654 | |
---|
1655 | this.showFocus = false; |
---|
1656 | |
---|
1657 | if(this._isEditing){ |
---|
1658 | this._endItemEditing("mouse", false); |
---|
1659 | } |
---|
1660 | |
---|
1661 | this._doEndItemEditing(this.owner, "mouse"); |
---|
1662 | |
---|
1663 | this.set("focusedItem", null); |
---|
1664 | this.selectFromEvent(e, null, null, true); |
---|
1665 | |
---|
1666 | if(this._setTabIndexAttr){ |
---|
1667 | this[this._setTabIndexAttr].focus(); |
---|
1668 | } |
---|
1669 | |
---|
1670 | if(this._onRendererHandleMouseDown){ |
---|
1671 | |
---|
1672 | var f = this.get("createItemFunc"); |
---|
1673 | |
---|
1674 | if(!f){ |
---|
1675 | return; |
---|
1676 | } |
---|
1677 | |
---|
1678 | var newItem = this._createdEvent = f(this, this.getTime(e), e); |
---|
1679 | |
---|
1680 | var store = this.get("store"); |
---|
1681 | |
---|
1682 | if(!newItem || store == null){ |
---|
1683 | return; |
---|
1684 | } |
---|
1685 | |
---|
1686 | // calendar needs an ID to work with |
---|
1687 | if(store.getIdentity(newItem) == undefined){ |
---|
1688 | var id = "_tempId_" + (this._tempIdCount++); |
---|
1689 | newItem[store.idProperty] = id; |
---|
1690 | if(this._tempItemsMap == null){ |
---|
1691 | this._tempItemsMap = {}; |
---|
1692 | } |
---|
1693 | this._tempItemsMap[id] = true; |
---|
1694 | } |
---|
1695 | |
---|
1696 | var newRenderItem = this.itemToRenderItem(newItem, store); |
---|
1697 | newRenderItem._item = newItem; |
---|
1698 | this._setItemStoreState(newItem, "unstored"); |
---|
1699 | |
---|
1700 | // add the new temporary item to the displayed list and force view refresh |
---|
1701 | var owner = this._getTopOwner(); |
---|
1702 | var items = owner.get("items"); |
---|
1703 | |
---|
1704 | owner.set("items", items ? items.concat([newRenderItem]) : [newRenderItem]); |
---|
1705 | |
---|
1706 | this._refreshItemsRendering(); |
---|
1707 | |
---|
1708 | // renderer created in _refreshItemsRenderering() |
---|
1709 | var renderers = this.getRenderers(newItem); |
---|
1710 | if(renderers && renderers.length>0){ |
---|
1711 | var renderer = renderers[0]; |
---|
1712 | if(renderer){ |
---|
1713 | // trigger editing |
---|
1714 | this._onRendererHandleMouseDown(e, renderer.renderer, "resizeEnd"); |
---|
1715 | this._startItemEditing(newRenderItem, "mouse"); |
---|
1716 | } |
---|
1717 | } |
---|
1718 | } |
---|
1719 | }, |
---|
1720 | |
---|
1721 | _onGridMouseMove: function(e){ |
---|
1722 | // tags: |
---|
1723 | // private |
---|
1724 | }, |
---|
1725 | |
---|
1726 | _onGridMouseUp: function(e){ |
---|
1727 | // tags: |
---|
1728 | // private |
---|
1729 | }, |
---|
1730 | |
---|
1731 | _onGridTouchStart: function(e){ |
---|
1732 | // tags: |
---|
1733 | // private |
---|
1734 | |
---|
1735 | var p = this._edProps; |
---|
1736 | |
---|
1737 | this._gridProps = { |
---|
1738 | event: e, |
---|
1739 | fromItem: this.isAscendantHasClass(e.target, this.eventContainer, "dojoxCalendarEvent") |
---|
1740 | }; |
---|
1741 | |
---|
1742 | if(this._isEditing){ |
---|
1743 | |
---|
1744 | if(this._gridProps){ |
---|
1745 | this._gridProps.editingOnStart = true; |
---|
1746 | } |
---|
1747 | |
---|
1748 | lang.mixin(p, this._getTouchesOnRenderers(e, p.editedItem)); |
---|
1749 | |
---|
1750 | if(p.touchesLen == 0){ |
---|
1751 | |
---|
1752 | if(p && p.endEditingTimer){ |
---|
1753 | clearTimeout(p.endEditingTimer); |
---|
1754 | p.endEditingTimer = null; |
---|
1755 | } |
---|
1756 | this._endItemEditing("touch", false); |
---|
1757 | } |
---|
1758 | } |
---|
1759 | |
---|
1760 | this._doEndItemEditing(this.owner, "touch"); |
---|
1761 | |
---|
1762 | event.stop(e); |
---|
1763 | |
---|
1764 | }, |
---|
1765 | |
---|
1766 | _doEndItemEditing: function(obj, eventSource){ |
---|
1767 | // tags: |
---|
1768 | // private |
---|
1769 | |
---|
1770 | if(obj && obj._isEditing){ |
---|
1771 | var p = obj._edProps; |
---|
1772 | if(p && p.endEditingTimer){ |
---|
1773 | clearTimeout(p.endEditingTimer); |
---|
1774 | p.endEditingTimer = null; |
---|
1775 | } |
---|
1776 | obj._endItemEditing(eventSource, false); |
---|
1777 | } |
---|
1778 | }, |
---|
1779 | |
---|
1780 | _onGridTouchEnd: function(e){ |
---|
1781 | // tags: |
---|
1782 | // private |
---|
1783 | }, |
---|
1784 | |
---|
1785 | _onGridTouchMove: function(e){ |
---|
1786 | // tags: |
---|
1787 | // private |
---|
1788 | }, |
---|
1789 | |
---|
1790 | __fixEvt: function(e){ |
---|
1791 | // summary: |
---|
1792 | // Extension point for a view to add some event properties to a calendar event. |
---|
1793 | // tags: |
---|
1794 | // callback |
---|
1795 | return e; |
---|
1796 | }, |
---|
1797 | |
---|
1798 | _dispatchCalendarEvt: function(e, name){ |
---|
1799 | // summary: |
---|
1800 | // Adds view properties to event and enable bubbling at owner level. |
---|
1801 | // e: Event |
---|
1802 | // The dispatched event. |
---|
1803 | // name: String |
---|
1804 | // The event name. |
---|
1805 | // tags: |
---|
1806 | // protected |
---|
1807 | |
---|
1808 | e = this.__fixEvt(e); |
---|
1809 | this[name](e); |
---|
1810 | if(this.owner){ |
---|
1811 | this.owner[name](e); |
---|
1812 | } |
---|
1813 | return e; |
---|
1814 | }, |
---|
1815 | |
---|
1816 | _onGridClick: function(e){ |
---|
1817 | // tags: |
---|
1818 | // private |
---|
1819 | if(!e.triggerEvent){ |
---|
1820 | e = { |
---|
1821 | date: this.getTime(e), |
---|
1822 | triggerEvent: e |
---|
1823 | }; |
---|
1824 | } |
---|
1825 | |
---|
1826 | this._dispatchCalendarEvt(e, "onGridClick"); |
---|
1827 | }, |
---|
1828 | |
---|
1829 | onGridClick: function(e){ |
---|
1830 | // summary: |
---|
1831 | // Event dispatched when the grid has been clicked. |
---|
1832 | // e: __GridClickEventArgs |
---|
1833 | // The event dispatched when the grid is clicked. |
---|
1834 | // tags: |
---|
1835 | // callback |
---|
1836 | }, |
---|
1837 | |
---|
1838 | _onGridDoubleClick: function(e){ |
---|
1839 | // tags: |
---|
1840 | // private |
---|
1841 | |
---|
1842 | if(!e.triggerEvent){ |
---|
1843 | e = { |
---|
1844 | date: this.getTime(e), |
---|
1845 | triggerEvent: e |
---|
1846 | }; |
---|
1847 | } |
---|
1848 | |
---|
1849 | this._dispatchCalendarEvt(e, "onGridDoubleClick"); |
---|
1850 | }, |
---|
1851 | |
---|
1852 | onGridDoubleClick: function(e){ |
---|
1853 | // summary: |
---|
1854 | // Event dispatched when the grid has been double-clicked. |
---|
1855 | // e: __GridClickEventArgs |
---|
1856 | // The event dispatched when the grid is double-clicked. |
---|
1857 | // tags: |
---|
1858 | // protected |
---|
1859 | |
---|
1860 | }, |
---|
1861 | |
---|
1862 | _onItemClick: function(e){ |
---|
1863 | // tags: |
---|
1864 | // private |
---|
1865 | |
---|
1866 | this._dispatchCalendarEvt(e, "onItemClick"); |
---|
1867 | }, |
---|
1868 | |
---|
1869 | onItemClick: function(e){ |
---|
1870 | // summary: |
---|
1871 | // Event dispatched when an item renderer has been clicked. |
---|
1872 | // e: __ItemMouseEventArgs |
---|
1873 | // The event dispatched when an item is clicked. |
---|
1874 | // tags: |
---|
1875 | // callback |
---|
1876 | |
---|
1877 | }, |
---|
1878 | |
---|
1879 | _onItemDoubleClick: function(e){ |
---|
1880 | // tags: |
---|
1881 | // private |
---|
1882 | |
---|
1883 | this._dispatchCalendarEvt(e, "onItemDoubleClick"); |
---|
1884 | }, |
---|
1885 | |
---|
1886 | onItemDoubleClick: function(e){ |
---|
1887 | // summary: |
---|
1888 | // Event dispatched when an item renderer has been double-clicked. |
---|
1889 | // e: __ItemMouseEventArgs |
---|
1890 | // The event dispatched when an item is double-clicked. |
---|
1891 | // tags: |
---|
1892 | // callback |
---|
1893 | |
---|
1894 | }, |
---|
1895 | |
---|
1896 | _onItemContextMenu: function(e){ |
---|
1897 | this._dispatchCalendarEvt(e, "onItemContextMenu"); |
---|
1898 | // tags: |
---|
1899 | // private |
---|
1900 | |
---|
1901 | }, |
---|
1902 | |
---|
1903 | onItemContextMenu: function(e){ |
---|
1904 | // summary: |
---|
1905 | // Event dispatched when an item renderer has been context-clicked. |
---|
1906 | // e: __ItemMouseEventArgs |
---|
1907 | // The event dispatched when an item is context-clicked. |
---|
1908 | // tags: |
---|
1909 | // callback |
---|
1910 | |
---|
1911 | }, |
---|
1912 | |
---|
1913 | ////////////////////////////////////////////////////////// |
---|
1914 | // |
---|
1915 | // Editing |
---|
1916 | // |
---|
1917 | ////////////////////////////////////////////////////////// |
---|
1918 | |
---|
1919 | _getStartEndRenderers: function(item){ |
---|
1920 | // summary: |
---|
1921 | // Returns an array that contains the first and last renderers of an item |
---|
1922 | // that are currently displayed. They could be the same renderer if only one renderer is used. |
---|
1923 | // item: Object |
---|
1924 | // The render item. |
---|
1925 | // returns: Object[] |
---|
1926 | // tags: |
---|
1927 | // protected |
---|
1928 | |
---|
1929 | |
---|
1930 | var list = this.itemToRenderer[item.id]; |
---|
1931 | |
---|
1932 | if(list == null){ |
---|
1933 | return null; |
---|
1934 | } |
---|
1935 | |
---|
1936 | // trivial and most common use case. |
---|
1937 | if(list.length == 1){ |
---|
1938 | var node = list[0].renderer; |
---|
1939 | return [node, node]; |
---|
1940 | } |
---|
1941 | |
---|
1942 | var rd = this.renderData; |
---|
1943 | var resizeStartFound = false; |
---|
1944 | var resizeEndFound = false; |
---|
1945 | |
---|
1946 | var res = []; |
---|
1947 | |
---|
1948 | for(var i=0; i<list.length; i++){ |
---|
1949 | |
---|
1950 | var ir = list[i].renderer; |
---|
1951 | |
---|
1952 | if (!resizeStartFound){ |
---|
1953 | resizeStartFound = rd.dateModule.compare(ir.item.range[0], ir.item.startTime) == 0; |
---|
1954 | res[0] = ir; |
---|
1955 | } |
---|
1956 | |
---|
1957 | if (!resizeEndFound){ |
---|
1958 | resizeEndFound = rd.dateModule.compare(ir.item.range[1], ir.item.endTime) == 0; |
---|
1959 | res[1] = ir; |
---|
1960 | } |
---|
1961 | |
---|
1962 | if (resizeStartFound && resizeEndFound){ |
---|
1963 | break; |
---|
1964 | } |
---|
1965 | } |
---|
1966 | |
---|
1967 | return res; |
---|
1968 | }, |
---|
1969 | |
---|
1970 | // editable: Boolean |
---|
1971 | // A flag that indicates whether or not the user can edit |
---|
1972 | // items in the data provider. |
---|
1973 | // If <code>true</code>, the item renderers in the control are editable. |
---|
1974 | // The user can click on an item renderer, or use the keyboard or touch devices, to move or resize the associated event. |
---|
1975 | editable: true, |
---|
1976 | |
---|
1977 | // moveEnabled: Boolean |
---|
1978 | // A flag that indicates whether the user can move items displayed. |
---|
1979 | // If <code>true</code>, the user can move the items. |
---|
1980 | moveEnabled: true, |
---|
1981 | |
---|
1982 | // resizeEnabled: Boolean |
---|
1983 | // A flag that indicates whether the items can be resized. |
---|
1984 | // If `true`, the control supports resizing of items. |
---|
1985 | resizeEnabled: true, |
---|
1986 | |
---|
1987 | isItemEditable: function(item, rendererKind){ |
---|
1988 | // summary: |
---|
1989 | // Computes whether particular item renderer can be edited or not. |
---|
1990 | // By default it is using the editable property value. |
---|
1991 | // item: Object |
---|
1992 | // The item represented by the renderer. |
---|
1993 | // rendererKind: String |
---|
1994 | // The kind of renderer. |
---|
1995 | // returns: Boolean |
---|
1996 | return this.getItemStoreState(item) != "storing" && this.editable && (this.owner ? this.owner.isItemEditable(item, rendererKind) : true); |
---|
1997 | }, |
---|
1998 | |
---|
1999 | isItemMoveEnabled: function(item, rendererKind){ |
---|
2000 | // summary: |
---|
2001 | // Computes whether particular item renderer can be moved. |
---|
2002 | // By default it is using the moveEnabled property value. |
---|
2003 | // item: Object |
---|
2004 | // The item represented by the renderer. |
---|
2005 | // rendererKind: String |
---|
2006 | // The kind of renderer. |
---|
2007 | // returns: Boolean |
---|
2008 | return this.isItemEditable(item, rendererKind) && this.moveEnabled && |
---|
2009 | (this.owner ? this.owner.isItemMoveEnabled(item, rendererKind): true); |
---|
2010 | }, |
---|
2011 | |
---|
2012 | isItemResizeEnabled: function(item, rendererKind){ |
---|
2013 | // summary: |
---|
2014 | // Computes whether particular item renderer can be resized. |
---|
2015 | // By default it is using the resizedEnabled property value. |
---|
2016 | // item: Object |
---|
2017 | // The item represented by the renderer. |
---|
2018 | // rendererKind: String |
---|
2019 | // The kind of renderer. |
---|
2020 | // returns: Boolean |
---|
2021 | |
---|
2022 | return this.isItemEditable(item, rendererKind) && this.resizeEnabled && |
---|
2023 | (this.owner ? this.owner.isItemResizeEnabled(item, rendererKind): true); |
---|
2024 | }, |
---|
2025 | |
---|
2026 | // _isEditing: Boolean |
---|
2027 | // Whether an item is being edited or not. |
---|
2028 | _isEditing: false, |
---|
2029 | |
---|
2030 | isItemBeingEdited: function(item){ |
---|
2031 | // summary: |
---|
2032 | // Returns whether an item is being edited or not. |
---|
2033 | // item: Object |
---|
2034 | // The item to test. |
---|
2035 | // returns: Boolean |
---|
2036 | return this._isEditing && this._edProps && this._edProps.editedItem && this._edProps.editedItem.id == item.id; |
---|
2037 | }, |
---|
2038 | |
---|
2039 | _setEditingProperties: function(props){ |
---|
2040 | // summary: |
---|
2041 | // Registers the editing properties used by the editing functions. |
---|
2042 | // This method should only be called by editing interaction mixins like Mouse, Keyboard and Touch. |
---|
2043 | // tags: |
---|
2044 | // protected |
---|
2045 | |
---|
2046 | this._edProps = props; |
---|
2047 | }, |
---|
2048 | |
---|
2049 | _startItemEditing: function(item, eventSource){ |
---|
2050 | // summary: |
---|
2051 | // Configures the component, renderers to start one (mouse) of several (touch, keyboard) editing gestures. |
---|
2052 | // item: Object |
---|
2053 | // The item that will be edited. |
---|
2054 | // eventSource: String |
---|
2055 | // "mouse", "keyboard", "touch" |
---|
2056 | // tags: |
---|
2057 | // protected |
---|
2058 | |
---|
2059 | this._isEditing = true; |
---|
2060 | this._getTopOwner()._isEditing = true; |
---|
2061 | var p = this._edProps; |
---|
2062 | |
---|
2063 | p.editedItem = item; |
---|
2064 | p.storeItem = item._item; |
---|
2065 | p.eventSource = eventSource; |
---|
2066 | |
---|
2067 | p.secItem = this._secondarySheet ? this._findRenderItem(item.id, this._secondarySheet.renderData.items) : null; |
---|
2068 | p.ownerItem = this.owner ? this._findRenderItem(item.id, this.items) : null; |
---|
2069 | |
---|
2070 | if (!p.liveLayout){ |
---|
2071 | p.editSaveStartTime = item.startTime; |
---|
2072 | p.editSaveEndTime = item.endTime; |
---|
2073 | |
---|
2074 | p.editItemToRenderer = this.itemToRenderer; |
---|
2075 | p.editItems = this.renderData.items; |
---|
2076 | p.editRendererList = this.rendererList; |
---|
2077 | |
---|
2078 | this.renderData.items = [p.editedItem]; |
---|
2079 | var id = p.editedItem.id; |
---|
2080 | |
---|
2081 | this.itemToRenderer = {}; |
---|
2082 | this.rendererList = []; |
---|
2083 | var list = p.editItemToRenderer[id]; |
---|
2084 | |
---|
2085 | p.editRendererIndices = []; |
---|
2086 | |
---|
2087 | arr.forEach(list, lang.hitch(this, function(ir, i){ |
---|
2088 | if(this.itemToRenderer[id] == null){ |
---|
2089 | this.itemToRenderer[id] = [ir]; |
---|
2090 | }else{ |
---|
2091 | this.itemToRenderer[id].push(ir); |
---|
2092 | } |
---|
2093 | this.rendererList.push(ir); |
---|
2094 | })); |
---|
2095 | |
---|
2096 | // remove in old map & list the occurrence used by the edited item |
---|
2097 | p.editRendererList = arr.filter(p.editRendererList, function(ir){ |
---|
2098 | return ir != null && ir.renderer.item.id != id; |
---|
2099 | }); |
---|
2100 | delete p.editItemToRenderer[id]; |
---|
2101 | } |
---|
2102 | |
---|
2103 | // graphic feedback refresh |
---|
2104 | this._layoutRenderers(this.renderData); |
---|
2105 | |
---|
2106 | this._onItemEditBegin({ |
---|
2107 | item: item, |
---|
2108 | storeItem: p.storeItem, |
---|
2109 | eventSource: eventSource |
---|
2110 | }); |
---|
2111 | }, |
---|
2112 | |
---|
2113 | _onItemEditBegin: function(e){ |
---|
2114 | // tags: |
---|
2115 | // private |
---|
2116 | |
---|
2117 | this._editStartTimeSave = this.newDate(e.item.startTime); |
---|
2118 | this._editEndTimeSave = this.newDate(e.item.endTime); |
---|
2119 | |
---|
2120 | this._dispatchCalendarEvt(e, "onItemEditBegin"); |
---|
2121 | }, |
---|
2122 | |
---|
2123 | onItemEditBegin: function(e){ |
---|
2124 | // summary: |
---|
2125 | // Event dispatched when the item is entering the editing mode. |
---|
2126 | // tags: |
---|
2127 | // callback |
---|
2128 | |
---|
2129 | }, |
---|
2130 | |
---|
2131 | _endItemEditing: function(/*String*/eventSource, /*Boolean*/canceled){ |
---|
2132 | // summary: |
---|
2133 | // Leaves the item editing mode. |
---|
2134 | // item: Object |
---|
2135 | // The item that was edited. |
---|
2136 | // eventSource: String |
---|
2137 | // "mouse", "keyboard", "touch" |
---|
2138 | // tags: |
---|
2139 | // protected |
---|
2140 | |
---|
2141 | this._isEditing = false; |
---|
2142 | this._getTopOwner()._isEditing = false; |
---|
2143 | |
---|
2144 | var p = this._edProps; |
---|
2145 | |
---|
2146 | arr.forEach(p.handles, function(handle){ |
---|
2147 | handle.remove(); |
---|
2148 | }); |
---|
2149 | |
---|
2150 | if (!p.liveLayout){ |
---|
2151 | this.renderData.items = p.editItems; |
---|
2152 | this.rendererList = p.editRendererList.concat(this.rendererList); |
---|
2153 | lang.mixin(this.itemToRenderer, p.editItemToRenderer); |
---|
2154 | } |
---|
2155 | |
---|
2156 | this._onItemEditEnd(lang.mixin(this._createItemEditEvent(), { |
---|
2157 | item: p.editedItem, |
---|
2158 | storeItem: p.storeItem, |
---|
2159 | eventSource: eventSource, |
---|
2160 | completed: !canceled |
---|
2161 | })); |
---|
2162 | |
---|
2163 | this._layoutRenderers(this.renderData); |
---|
2164 | |
---|
2165 | this._edProps = null; |
---|
2166 | }, |
---|
2167 | |
---|
2168 | _onItemEditEnd: function(e){ |
---|
2169 | // tags: |
---|
2170 | // private |
---|
2171 | |
---|
2172 | this._dispatchCalendarEvt(e, "onItemEditEnd"); |
---|
2173 | |
---|
2174 | if(!e.isDefaultPrevented()){ |
---|
2175 | |
---|
2176 | var store = this.get("store"); |
---|
2177 | |
---|
2178 | // updated store item |
---|
2179 | var storeItem = this.renderItemToItem(e.item, store); |
---|
2180 | |
---|
2181 | var s = this._getItemStoreStateObj(e.item); |
---|
2182 | |
---|
2183 | if(s != null && s.state == "unstored"){ |
---|
2184 | |
---|
2185 | if(e.completed){ |
---|
2186 | // renderItemToItem cannot find the original data item |
---|
2187 | // (as it does not exist in the store yet) to mixin with. |
---|
2188 | // so we must do it here. |
---|
2189 | storeItem = lang.mixin(s.item, storeItem); |
---|
2190 | this._setItemStoreState(storeItem, "storing"); |
---|
2191 | var oldID = store.getIdentity(storeItem); |
---|
2192 | var options = null; |
---|
2193 | |
---|
2194 | if(this._tempItemsMap && this._tempItemsMap[oldID]){ |
---|
2195 | options = {temporaryId: oldID}; |
---|
2196 | delete this._tempItemsMap[oldID]; |
---|
2197 | delete storeItem[store.idProperty]; |
---|
2198 | } |
---|
2199 | |
---|
2200 | // add to the store. |
---|
2201 | when(store.add(storeItem, options), lang.hitch(this, function(res){ |
---|
2202 | var id; |
---|
2203 | if(lang.isObject(res)){ |
---|
2204 | id = store.getIdentity(res); |
---|
2205 | }else{ |
---|
2206 | id = res; |
---|
2207 | } |
---|
2208 | |
---|
2209 | if(id != oldID){ |
---|
2210 | this._removeRenderItem(oldID); |
---|
2211 | } |
---|
2212 | })); |
---|
2213 | |
---|
2214 | }else{ // creation canceled |
---|
2215 | // cleanup items list |
---|
2216 | |
---|
2217 | this._removeRenderItem(s.id); |
---|
2218 | } |
---|
2219 | |
---|
2220 | } else if(e.completed){ |
---|
2221 | // Inject new properties in data store item |
---|
2222 | // and apply data changes |
---|
2223 | this._setItemStoreState(storeItem, "storing"); |
---|
2224 | store.put(storeItem); |
---|
2225 | }else{ |
---|
2226 | e.item.startTime = this._editStartTimeSave; |
---|
2227 | e.item.endTime = this._editEndTimeSave; |
---|
2228 | } |
---|
2229 | } |
---|
2230 | }, |
---|
2231 | |
---|
2232 | _removeRenderItem: function(id){ |
---|
2233 | |
---|
2234 | var owner = this._getTopOwner(); |
---|
2235 | var items = owner.get("items"); |
---|
2236 | var l = items.length; |
---|
2237 | var found = false; |
---|
2238 | for(var i=l-1; i>=0; i--){ |
---|
2239 | if(items[i].id == id){ |
---|
2240 | items.splice(i, 1); |
---|
2241 | found = true; |
---|
2242 | break; |
---|
2243 | } |
---|
2244 | } |
---|
2245 | this._cleanItemStoreState(id); |
---|
2246 | if(found){ |
---|
2247 | owner.set("items", items); //force a complete relayout |
---|
2248 | this.invalidateLayout(); |
---|
2249 | } |
---|
2250 | }, |
---|
2251 | |
---|
2252 | onItemEditEnd: function(e){ |
---|
2253 | // summary: |
---|
2254 | // Event dispatched when the item is leaving the editing mode. |
---|
2255 | // tags: |
---|
2256 | // protected |
---|
2257 | |
---|
2258 | }, |
---|
2259 | |
---|
2260 | _createItemEditEvent: function(){ |
---|
2261 | // tags: |
---|
2262 | // private |
---|
2263 | |
---|
2264 | var e = { |
---|
2265 | cancelable: true, |
---|
2266 | bubbles: false, |
---|
2267 | __defaultPrevent: false |
---|
2268 | }; |
---|
2269 | |
---|
2270 | e.preventDefault = function(){ |
---|
2271 | this.__defaultPrevented = true; |
---|
2272 | }; |
---|
2273 | |
---|
2274 | e.isDefaultPrevented = function(){ |
---|
2275 | return this.__defaultPrevented; |
---|
2276 | }; |
---|
2277 | |
---|
2278 | return e; |
---|
2279 | }, |
---|
2280 | |
---|
2281 | |
---|
2282 | _startItemEditingGesture: function(dates, editKind, eventSource, e){ |
---|
2283 | // summary: |
---|
2284 | // Starts the editing gesture. |
---|
2285 | // date: Date[] |
---|
2286 | // The reference dates (at least one). |
---|
2287 | // editKind: String |
---|
2288 | // Kind of edit: "resizeBoth", "resizeStart", "resizeEnd" or "move". |
---|
2289 | // eventSource: String |
---|
2290 | // "mouse", "keyboard", "touch" |
---|
2291 | // e: Event |
---|
2292 | // The event at the origin of the editing gesture. |
---|
2293 | // tags: |
---|
2294 | // protected |
---|
2295 | |
---|
2296 | var p = this._edProps; |
---|
2297 | |
---|
2298 | if(!p || p.editedItem == null){ |
---|
2299 | return; |
---|
2300 | } |
---|
2301 | |
---|
2302 | this._editingGesture = true; |
---|
2303 | |
---|
2304 | var item = p.editedItem; |
---|
2305 | |
---|
2306 | p.editKind = editKind; |
---|
2307 | |
---|
2308 | this._onItemEditBeginGesture(this.__fixEvt(lang.mixin(this._createItemEditEvent(), { |
---|
2309 | item: item, |
---|
2310 | storeItem: p.storeItem, |
---|
2311 | startTime: item.startTime, |
---|
2312 | endTime: item.endTime, |
---|
2313 | editKind: editKind, |
---|
2314 | rendererKind: p.rendererKind, |
---|
2315 | triggerEvent: e, |
---|
2316 | dates: dates, |
---|
2317 | eventSource: eventSource |
---|
2318 | }))); |
---|
2319 | |
---|
2320 | p.itemBeginDispatched = true; |
---|
2321 | |
---|
2322 | }, |
---|
2323 | |
---|
2324 | |
---|
2325 | _onItemEditBeginGesture: function(e){ |
---|
2326 | // tags: |
---|
2327 | // private |
---|
2328 | var p = this._edProps; |
---|
2329 | |
---|
2330 | var item = p.editedItem; |
---|
2331 | var dates = e.dates; |
---|
2332 | |
---|
2333 | p.editingTimeFrom = []; |
---|
2334 | p.editingTimeFrom[0] = dates[0]; |
---|
2335 | |
---|
2336 | p.editingItemRefTime = []; |
---|
2337 | p.editingItemRefTime[0] = this.newDate(p.editKind == "resizeEnd" ? item.endTime : item.startTime); |
---|
2338 | |
---|
2339 | if (p.editKind == "resizeBoth"){ |
---|
2340 | p.editingTimeFrom[1] = dates[1]; |
---|
2341 | p.editingItemRefTime[1] = this.newDate(item.endTime); |
---|
2342 | } |
---|
2343 | |
---|
2344 | var cal = this.renderData.dateModule; |
---|
2345 | |
---|
2346 | p.inViewOnce = this._isItemInView(item); |
---|
2347 | |
---|
2348 | if(p.rendererKind == "label" || this.roundToDay){ |
---|
2349 | p._itemEditBeginSave = this.newDate(item.startTime); |
---|
2350 | p._itemEditEndSave = this.newDate(item.endTime); |
---|
2351 | } |
---|
2352 | |
---|
2353 | p._initDuration = cal.difference(item.startTime, item.endTime, item.allDay?"day":"millisecond"); |
---|
2354 | |
---|
2355 | this._dispatchCalendarEvt(e, "onItemEditBeginGesture"); |
---|
2356 | |
---|
2357 | if (!e.isDefaultPrevented()){ |
---|
2358 | |
---|
2359 | if (e.eventSource == "mouse"){ |
---|
2360 | var cursor = e.editKind=="move"?"move":this.resizeCursor; |
---|
2361 | p.editLayer = domConstruct.create("div", { |
---|
2362 | style: "position: absolute; left:0; right:0; bottom:0; top:0; z-index:30; tabIndex:-1; background-image:url('"+this._blankGif+"'); cursor: "+cursor, |
---|
2363 | onresizestart: function(e){return false;}, |
---|
2364 | onselectstart: function(e){return false;} |
---|
2365 | }, this.domNode); |
---|
2366 | p.editLayer.focus(); |
---|
2367 | } |
---|
2368 | } |
---|
2369 | }, |
---|
2370 | |
---|
2371 | onItemEditBeginGesture: function(e){ |
---|
2372 | // summary: |
---|
2373 | // Event dispatched when an editing gesture is beginning. |
---|
2374 | // e: __itemEditingEventArgs |
---|
2375 | // The editing event. |
---|
2376 | // tags: |
---|
2377 | // callback |
---|
2378 | |
---|
2379 | }, |
---|
2380 | |
---|
2381 | _waDojoxAddIssue: function(d, unit, steps){ |
---|
2382 | // summary: |
---|
2383 | // Workaround an issue of dojox.date.XXXXX.date.add() function |
---|
2384 | // that does not support the subtraction of time correctly (normalization issues). |
---|
2385 | // d: Date |
---|
2386 | // Reference date. |
---|
2387 | // unit: String |
---|
2388 | // Unit to add. |
---|
2389 | // steps: Integer |
---|
2390 | // Number of units to add. |
---|
2391 | // tags: |
---|
2392 | // protected |
---|
2393 | |
---|
2394 | var cal = this.renderData.dateModule; |
---|
2395 | if(this._calendar != "gregorian" && steps < 0){ |
---|
2396 | var gd = d.toGregorian(); |
---|
2397 | gd = date.add(gd, unit, steps); |
---|
2398 | return new this.renderData.dateClassObj(gd); |
---|
2399 | }else{ |
---|
2400 | return cal.add(d, unit, steps); |
---|
2401 | } |
---|
2402 | }, |
---|
2403 | |
---|
2404 | _computeItemEditingTimes: function(item, editKind, rendererKind, times, eventSource){ |
---|
2405 | // tags: |
---|
2406 | // private |
---|
2407 | |
---|
2408 | var cal = this.renderData.dateModule; |
---|
2409 | var p = this._edProps; |
---|
2410 | var diff = cal.difference(p.editingTimeFrom[0], times[0], "millisecond"); |
---|
2411 | times[0] = this._waDojoxAddIssue(p.editingItemRefTime[0], "millisecond", diff); |
---|
2412 | |
---|
2413 | if(editKind == "resizeBoth"){ |
---|
2414 | diff = cal.difference(p.editingTimeFrom[1], times[1], "millisecond"); |
---|
2415 | times[1] = this._waDojoxAddIssue(p.editingItemRefTime[1], "millisecond", diff); |
---|
2416 | } |
---|
2417 | return times; |
---|
2418 | }, |
---|
2419 | |
---|
2420 | _moveOrResizeItemGesture: function(dates, eventSource, e){ |
---|
2421 | // summary: |
---|
2422 | // Moves or resizes an item. |
---|
2423 | // dates: Date[] |
---|
2424 | // The reference dates. |
---|
2425 | // editKind: String |
---|
2426 | // Kind of edit: "resizeStart", "resizeEnd", "resizeBoth" or "move". |
---|
2427 | // eventSource: String |
---|
2428 | // "mouse", "keyboard", "touch" |
---|
2429 | // e: Event |
---|
2430 | // The event at the origin of the editing gesture. |
---|
2431 | // tags: |
---|
2432 | // private |
---|
2433 | |
---|
2434 | if(!this._isEditing || dates[0] == null){ |
---|
2435 | return; |
---|
2436 | } |
---|
2437 | |
---|
2438 | var p = this._edProps; |
---|
2439 | var item = p.editedItem; |
---|
2440 | var rd = this.renderData; |
---|
2441 | var cal = rd.dateModule; |
---|
2442 | var editKind = p.editKind; |
---|
2443 | |
---|
2444 | var newTimes = [dates[0]]; |
---|
2445 | |
---|
2446 | if(editKind == "resizeBoth"){ |
---|
2447 | newTimes[1] = dates[1]; |
---|
2448 | } |
---|
2449 | |
---|
2450 | newTimes = this._computeItemEditingTimes(item, p.editKind, p.rendererKind, newTimes, eventSource); |
---|
2451 | |
---|
2452 | var newTime = newTimes[0]; // usual use case |
---|
2453 | |
---|
2454 | var moveOrResizeDone = false; |
---|
2455 | |
---|
2456 | var oldStart = lang.clone(item.startTime); |
---|
2457 | var oldEnd = lang.clone(item.endTime); |
---|
2458 | |
---|
2459 | // swap cannot used using keyboard as a gesture is made of one single change (loss of start/end context). |
---|
2460 | var allowSwap = p.eventSource == "keyboard" ? false : this.allowStartEndSwap; |
---|
2461 | |
---|
2462 | // Update the Calendar with the edited value. |
---|
2463 | if(editKind == "move"){ |
---|
2464 | |
---|
2465 | if(cal.compare(item.startTime, newTime) != 0){ |
---|
2466 | var duration = cal.difference(item.startTime, item.endTime, "millisecond"); |
---|
2467 | item.startTime = this.newDate(newTime); |
---|
2468 | item.endTime = cal.add(item.startTime, "millisecond", duration); |
---|
2469 | moveOrResizeDone = true; |
---|
2470 | } |
---|
2471 | |
---|
2472 | }else if(editKind == "resizeStart"){ |
---|
2473 | |
---|
2474 | if(cal.compare(item.startTime, newTime) != 0){ |
---|
2475 | if(cal.compare(item.endTime, newTime) != -1){ |
---|
2476 | item.startTime = this.newDate(newTime); |
---|
2477 | }else{ // swap detected |
---|
2478 | if(allowSwap){ |
---|
2479 | item.startTime = this.newDate(item.endTime); |
---|
2480 | item.endTime = this.newDate(newTime); |
---|
2481 | p.editKind = editKind = "resizeEnd"; |
---|
2482 | if(eventSource == "touch"){ // invert touches as well! |
---|
2483 | p.resizeEndTouchIndex = p.resizeStartTouchIndex; |
---|
2484 | p.resizeStartTouchIndex = -1; |
---|
2485 | } |
---|
2486 | }else{ // block the swap but keep the time of day |
---|
2487 | item.startTime = this.newDate(item.endTime); |
---|
2488 | item.startTime.setHours(newTime.getHours()); |
---|
2489 | item.startTime.setMinutes(newTime.getMinutes()); |
---|
2490 | item.startTime.setSeconds(newTime.getSeconds()); |
---|
2491 | } |
---|
2492 | } |
---|
2493 | moveOrResizeDone = true; |
---|
2494 | } |
---|
2495 | |
---|
2496 | }else if(editKind == "resizeEnd"){ |
---|
2497 | |
---|
2498 | if(cal.compare(item.endTime, newTime) != 0){ |
---|
2499 | if(cal.compare(item.startTime, newTime) != 1){ |
---|
2500 | item.endTime = this.newDate(newTime); |
---|
2501 | }else{ // swap detected |
---|
2502 | |
---|
2503 | if(allowSwap){ |
---|
2504 | item.endTime = this.newDate(item.startTime); |
---|
2505 | item.startTime = this.newDate(newTime); |
---|
2506 | p.editKind = editKind = "resizeStart"; |
---|
2507 | if(eventSource == "touch"){ // invert touches as well! |
---|
2508 | p.resizeStartTouchIndex = p.resizeEndTouchIndex; |
---|
2509 | p.resizeEndTouchIndex = -1; |
---|
2510 | } |
---|
2511 | }else{ // block the swap but keep the time of day |
---|
2512 | item.endTime = this.newDate(item.startTime); |
---|
2513 | item.endTime.setHours(newTime.getHours()); |
---|
2514 | item.endTime.setMinutes(newTime.getMinutes()); |
---|
2515 | item.endTime.setSeconds(newTime.getSeconds()); |
---|
2516 | } |
---|
2517 | } |
---|
2518 | |
---|
2519 | moveOrResizeDone = true; |
---|
2520 | } |
---|
2521 | }else if(editKind == "resizeBoth"){ |
---|
2522 | |
---|
2523 | moveOrResizeDone = true; |
---|
2524 | |
---|
2525 | var start = this.newDate(newTime); |
---|
2526 | var end = this.newDate(newTimes[1]); |
---|
2527 | |
---|
2528 | if(cal.compare(start, end) != -1){ // swap detected |
---|
2529 | if(allowSwap){ |
---|
2530 | var t = start; |
---|
2531 | start = end; |
---|
2532 | end = t; |
---|
2533 | }else{ // as both ends are moved, the simple way is to forbid the move gesture. |
---|
2534 | moveOrResizeDone = false; |
---|
2535 | } |
---|
2536 | } |
---|
2537 | |
---|
2538 | if(moveOrResizeDone){ |
---|
2539 | item.startTime = start; |
---|
2540 | item.endTime = end; |
---|
2541 | } |
---|
2542 | |
---|
2543 | }else{ |
---|
2544 | return false; |
---|
2545 | } |
---|
2546 | |
---|
2547 | if(!moveOrResizeDone){ |
---|
2548 | return false; |
---|
2549 | } |
---|
2550 | |
---|
2551 | var evt = lang.mixin(this._createItemEditEvent(), { |
---|
2552 | item: item, |
---|
2553 | storeItem: p.storeItem, |
---|
2554 | startTime: item.startTime, |
---|
2555 | endTime: item.endTime, |
---|
2556 | editKind: editKind, |
---|
2557 | rendererKind: p.rendererKind, |
---|
2558 | triggerEvent: e, |
---|
2559 | eventSource: eventSource |
---|
2560 | }); |
---|
2561 | |
---|
2562 | // trigger snapping, rounding, minimal duration, boundaries checks etc. |
---|
2563 | if(editKind == "move"){ |
---|
2564 | this._onItemEditMoveGesture(evt); |
---|
2565 | }else{ |
---|
2566 | this._onItemEditResizeGesture(evt); |
---|
2567 | } |
---|
2568 | |
---|
2569 | // prevent invalid range |
---|
2570 | if(cal.compare(item.startTime, item.endTime) == 1){ |
---|
2571 | var tmp = item.startTime; |
---|
2572 | item.startTime = item.endTime; |
---|
2573 | item.endTime = tmp; |
---|
2574 | } |
---|
2575 | |
---|
2576 | moveOrResizeDone = |
---|
2577 | cal.compare(oldStart, item.startTime) != 0 || |
---|
2578 | cal.compare(oldEnd, item.endTime) != 0; |
---|
2579 | |
---|
2580 | if(!moveOrResizeDone){ |
---|
2581 | return false; |
---|
2582 | } |
---|
2583 | |
---|
2584 | this._layoutRenderers(this.renderData); |
---|
2585 | |
---|
2586 | if(p.liveLayout && p.secItem != null){ |
---|
2587 | p.secItem.startTime = item.startTime; |
---|
2588 | p.secItem.endTime = item.endTime; |
---|
2589 | this._secondarySheet._layoutRenderers(this._secondarySheet.renderData); |
---|
2590 | }else if(p.ownerItem != null && this.owner.liveLayout){ |
---|
2591 | p.ownerItem.startTime = item.startTime; |
---|
2592 | p.ownerItem.endTime = item.endTime; |
---|
2593 | this.owner._layoutRenderers(this.owner.renderData); |
---|
2594 | } |
---|
2595 | |
---|
2596 | return true; |
---|
2597 | }, |
---|
2598 | |
---|
2599 | _findRenderItem: function(id, list){ |
---|
2600 | // tags: |
---|
2601 | // private |
---|
2602 | |
---|
2603 | list = list || this.renderData.items; |
---|
2604 | for(var i=0; i<list.length; i++){ |
---|
2605 | if(list[i].id == id){ |
---|
2606 | return list[i]; |
---|
2607 | } |
---|
2608 | } |
---|
2609 | return null; |
---|
2610 | }, |
---|
2611 | |
---|
2612 | _onItemEditMoveGesture: function(e){ |
---|
2613 | // tags: |
---|
2614 | // private |
---|
2615 | |
---|
2616 | this._dispatchCalendarEvt(e, "onItemEditMoveGesture"); |
---|
2617 | |
---|
2618 | if(!e.isDefaultPrevented()){ |
---|
2619 | |
---|
2620 | var p = e.source._edProps; |
---|
2621 | var rd = this.renderData; |
---|
2622 | var cal = rd.dateModule; |
---|
2623 | var newStartTime, newEndTime; |
---|
2624 | |
---|
2625 | if(p.rendererKind == "label" || (this.roundToDay && !e.item.allDay)){ |
---|
2626 | |
---|
2627 | newStartTime = this.floorToDay(e.item.startTime, false, rd); |
---|
2628 | newStartTime.setHours(p._itemEditBeginSave.getHours()); |
---|
2629 | newStartTime.setMinutes(p._itemEditBeginSave.getMinutes()); |
---|
2630 | |
---|
2631 | newEndTime = cal.add(newStartTime, "millisecond", p._initDuration); |
---|
2632 | |
---|
2633 | }else if(e.item.allDay){ |
---|
2634 | newStartTime = this.floorToDay(e.item.startTime, true); |
---|
2635 | newEndTime = cal.add(newStartTime, "day", p._initDuration); |
---|
2636 | }else{ |
---|
2637 | newStartTime = this.floorDate(e.item.startTime, this.snapUnit, this.snapSteps); |
---|
2638 | newEndTime = cal.add(newStartTime, "millisecond", p._initDuration); |
---|
2639 | } |
---|
2640 | |
---|
2641 | e.item.startTime = newStartTime; |
---|
2642 | e.item.endTime = newEndTime; |
---|
2643 | |
---|
2644 | if(!p.inViewOnce){ |
---|
2645 | p.inViewOnce = this._isItemInView(e.item); |
---|
2646 | } |
---|
2647 | |
---|
2648 | // to prevent strange behaviors use constraint in items already fully in view. |
---|
2649 | if(p.inViewOnce && this.stayInView){ |
---|
2650 | this._ensureItemInView(e.item); |
---|
2651 | } |
---|
2652 | } |
---|
2653 | }, |
---|
2654 | |
---|
2655 | _DAY_IN_MILLISECONDS: 24 * 60 * 60 * 1000, |
---|
2656 | |
---|
2657 | onItemEditMoveGesture: function(e){ |
---|
2658 | // summary: |
---|
2659 | // Event dispatched during a move editing gesture. |
---|
2660 | // e: __itemEditingEventArgs |
---|
2661 | // The editing event. |
---|
2662 | // tags: |
---|
2663 | // callback |
---|
2664 | |
---|
2665 | }, |
---|
2666 | |
---|
2667 | _onItemEditResizeGesture: function(e){ |
---|
2668 | // tags: |
---|
2669 | // private |
---|
2670 | |
---|
2671 | this._dispatchCalendarEvt(e, "onItemEditResizeGesture"); |
---|
2672 | |
---|
2673 | if(!e.isDefaultPrevented()){ |
---|
2674 | |
---|
2675 | var p = e.source._edProps; |
---|
2676 | var rd = this.renderData; |
---|
2677 | var cal = rd.dateModule; |
---|
2678 | |
---|
2679 | var newStartTime = e.item.startTime; |
---|
2680 | var newEndTime = e.item.endTime; |
---|
2681 | |
---|
2682 | if(e.editKind == "resizeStart"){ |
---|
2683 | if(e.item.allDay){ |
---|
2684 | newStartTime = this.floorToDay(e.item.startTime, false, this.renderData); |
---|
2685 | }else if(this.roundToDay){ |
---|
2686 | newStartTime = this.floorToDay(e.item.startTime, false, rd); |
---|
2687 | newStartTime.setHours(p._itemEditBeginSave.getHours()); |
---|
2688 | newStartTime.setMinutes(p._itemEditBeginSave.getMinutes()); |
---|
2689 | }else{ |
---|
2690 | newStartTime = this.floorDate(e.item.startTime, this.snapUnit, this.snapSteps); |
---|
2691 | } |
---|
2692 | }else if(e.editKind == "resizeEnd"){ |
---|
2693 | if(e.item.allDay){ |
---|
2694 | if(!this.isStartOfDay(e.item.endTime)){ |
---|
2695 | newEndTime = this.floorToDay(e.item.endTime, false, this.renderData); |
---|
2696 | newEndTime = cal.add(newEndTime, "day", 1); |
---|
2697 | } |
---|
2698 | }else if(this.roundToDay){ |
---|
2699 | newEndTime = this.floorToDay(e.item.endTime, false, rd); |
---|
2700 | newEndTime.setHours(p._itemEditEndSave.getHours()); |
---|
2701 | newEndTime.setMinutes(p._itemEditEndSave.getMinutes()); |
---|
2702 | }else{ |
---|
2703 | newEndTime = this.floorDate(e.item.endTime, this.snapUnit, this.snapSteps); |
---|
2704 | |
---|
2705 | if(e.eventSource == "mouse"){ |
---|
2706 | newEndTime = cal.add(newEndTime, this.snapUnit, this.snapSteps); |
---|
2707 | } |
---|
2708 | } |
---|
2709 | }else{ // Resize both |
---|
2710 | newStartTime = this.floorDate(e.item.startTime, this.snapUnit, this.snapSteps); |
---|
2711 | newEndTime = this.floorDate(e.item.endTime, this.snapUnit, this.snapSteps); |
---|
2712 | newEndTime = cal.add(newEndTime, this.snapUnit, this.snapSteps); |
---|
2713 | } |
---|
2714 | |
---|
2715 | e.item.startTime = newStartTime; |
---|
2716 | e.item.endTime = newEndTime; |
---|
2717 | |
---|
2718 | var minimalDay = e.item.allDay || p._initDuration >= this._DAY_IN_MILLISECONDS && !this.allowResizeLessThan24H; |
---|
2719 | |
---|
2720 | this.ensureMinimalDuration(this.renderData, e.item, |
---|
2721 | minimalDay ? "day" : this.minDurationUnit, |
---|
2722 | minimalDay ? 1 : this.minDurationSteps, |
---|
2723 | e.editKind); |
---|
2724 | |
---|
2725 | if(!p.inViewOnce){ |
---|
2726 | p.inViewOnce = this._isItemInView(e.item); |
---|
2727 | } |
---|
2728 | |
---|
2729 | // to prevent strange behaviors use constraint in items already fully in view. |
---|
2730 | if(p.inViewOnce && this.stayInView){ |
---|
2731 | this._ensureItemInView(e.item); |
---|
2732 | } |
---|
2733 | } |
---|
2734 | }, |
---|
2735 | |
---|
2736 | onItemEditResizeGesture: function(e){ |
---|
2737 | // summary: |
---|
2738 | // Event dispatched during a resize editing gesture. |
---|
2739 | // e: __itemEditingEventArgs |
---|
2740 | // The editing event. |
---|
2741 | // tags: |
---|
2742 | // callback |
---|
2743 | |
---|
2744 | }, |
---|
2745 | |
---|
2746 | _endItemEditingGesture: function(/*String*/eventSource, /*Event*/e){ |
---|
2747 | // tags: |
---|
2748 | // protected |
---|
2749 | |
---|
2750 | if(!this._isEditing){ |
---|
2751 | return; |
---|
2752 | } |
---|
2753 | |
---|
2754 | this._editingGesture = false; |
---|
2755 | |
---|
2756 | var p = this._edProps; |
---|
2757 | var item = p.editedItem; |
---|
2758 | |
---|
2759 | p.itemBeginDispatched = false; |
---|
2760 | |
---|
2761 | this._onItemEditEndGesture(lang.mixin(this._createItemEditEvent(), { |
---|
2762 | item: item, |
---|
2763 | storeItem: p.storeItem, |
---|
2764 | startTime: item.startTime, |
---|
2765 | endTime: item.endTime, |
---|
2766 | editKind: p.editKind, |
---|
2767 | rendererKind: p.rendererKind, |
---|
2768 | triggerEvent: e, |
---|
2769 | eventSource: eventSource |
---|
2770 | })); |
---|
2771 | |
---|
2772 | }, |
---|
2773 | |
---|
2774 | _onItemEditEndGesture: function(e){ |
---|
2775 | // tags: |
---|
2776 | // private |
---|
2777 | |
---|
2778 | var p = this._edProps; |
---|
2779 | |
---|
2780 | delete p._itemEditBeginSave; |
---|
2781 | delete p._itemEditEndSave; |
---|
2782 | |
---|
2783 | this._dispatchCalendarEvt(e, "onItemEditEndGesture"); |
---|
2784 | |
---|
2785 | if (!e.isDefaultPrevented()){ |
---|
2786 | if(p.editLayer){ |
---|
2787 | if(has("ie")){ |
---|
2788 | p.editLayer.style.cursor = "default"; |
---|
2789 | } |
---|
2790 | setTimeout(lang.hitch(this, function(){ |
---|
2791 | if(this.domNode){ // for unit tests |
---|
2792 | this.domNode.focus(); |
---|
2793 | p.editLayer.parentNode.removeChild(p.editLayer); |
---|
2794 | p.editLayer = null; |
---|
2795 | } |
---|
2796 | }), 10); |
---|
2797 | |
---|
2798 | } |
---|
2799 | } |
---|
2800 | }, |
---|
2801 | |
---|
2802 | onItemEditEndGesture: function(e){ |
---|
2803 | // summary: |
---|
2804 | // Event dispatched at the end of an editing gesture. |
---|
2805 | // e: __itemEditingEventArgs |
---|
2806 | // The editing event. |
---|
2807 | // tags: |
---|
2808 | // callback |
---|
2809 | |
---|
2810 | }, |
---|
2811 | |
---|
2812 | ensureMinimalDuration: function(renderData, item, unit, steps, editKind){ |
---|
2813 | // summary: |
---|
2814 | // During the resize editing gesture, ensures that the item has the specified minimal duration. |
---|
2815 | // renderData: Object |
---|
2816 | // The render data. |
---|
2817 | // item: Object |
---|
2818 | // The edited item. |
---|
2819 | // unit: String |
---|
2820 | // The unit used to define the minimal duration. |
---|
2821 | // steps: Integer |
---|
2822 | // The number of time units. |
---|
2823 | // editKind: String |
---|
2824 | // The edit kind: "resizeStart" or "resizeEnd". |
---|
2825 | var minTime; |
---|
2826 | var cal = renderData.dateModule; |
---|
2827 | |
---|
2828 | if(editKind == "resizeStart"){ |
---|
2829 | minTime = cal.add(item.endTime, unit, -steps); |
---|
2830 | if(cal.compare(item.startTime, minTime) == 1){ |
---|
2831 | item.startTime = minTime; |
---|
2832 | } |
---|
2833 | } else { |
---|
2834 | minTime = cal.add(item.startTime, unit, steps); |
---|
2835 | if(cal.compare(item.endTime, minTime) == -1){ |
---|
2836 | item.endTime = minTime; |
---|
2837 | } |
---|
2838 | } |
---|
2839 | }, |
---|
2840 | |
---|
2841 | // doubleTapDelay: Integer |
---|
2842 | // The maximum delay between two taps needed to trigger an "itemDoubleClick" event, in touch context. |
---|
2843 | doubleTapDelay: 300, |
---|
2844 | |
---|
2845 | // snapUnit: String |
---|
2846 | // The unit of the snapping to apply during the editing of an event. |
---|
2847 | // "day", "hour" and "minute" are valid values. |
---|
2848 | snapUnit: "minute", |
---|
2849 | |
---|
2850 | // snapSteps: Integer |
---|
2851 | // The number of units used to compute the snapping of the edited item. |
---|
2852 | snapSteps: 15, |
---|
2853 | |
---|
2854 | // minDurationUnit: "String" |
---|
2855 | // The unit used to define the minimal duration of the edited item. |
---|
2856 | // "day", "hour" and "minute" are valid values. |
---|
2857 | minDurationUnit: "hour", |
---|
2858 | |
---|
2859 | // minDurationSteps: Integer |
---|
2860 | // The number of units used to define the minimal duration of the edited item. |
---|
2861 | minDurationSteps: 1, |
---|
2862 | |
---|
2863 | // liveLayout: Boolean |
---|
2864 | // If true, all the events are laid out during the editing gesture. If false, only the edited event is laid out. |
---|
2865 | liveLayout: false, |
---|
2866 | |
---|
2867 | // stayInView: Boolean |
---|
2868 | // Specifies during editing, if the item is already in view, if the item must stay in the time range defined by the view or not. |
---|
2869 | stayInView: true, |
---|
2870 | |
---|
2871 | // allowStartEndSwap: Boolean |
---|
2872 | // Specifies if the start and end time of an item can be swapped during an editing gesture. Note that using the keyboard this property is ignored. |
---|
2873 | allowStartEndSwap: true, |
---|
2874 | |
---|
2875 | // allowResizeLessThan24H: Boolean |
---|
2876 | // If an event has a duration greater than 24 hours, indicates if using a resize gesture, it can be resized to last less than 24 hours. |
---|
2877 | // This flag is usually used when two different kind of renderers are used (MatrixView) to prevent changing the kind of renderer during an editing gesture. |
---|
2878 | allowResizeLessThan24H: false |
---|
2879 | |
---|
2880 | }); |
---|
2881 | }); |
---|