source: Dev/trunk/src/client/dojox/calendar/MonthColumnView.js @ 529

Last change on this file since 529 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 39.4 KB
Line 
1define([
2"./ViewBase",
3"dijit/_TemplatedMixin",
4"./_VerticalScrollBarBase",
5"dojo/text!./templates/MonthColumnView.html",
6"dojo/_base/declare",
7"dojo/_base/event",
8"dojo/_base/lang",
9"dojo/_base/array",
10"dojo/_base/sniff",
11"dojo/_base/fx",
12"dojo/_base/html",
13"dojo/on",
14"dojo/dom",
15"dojo/dom-class",
16"dojo/dom-style",
17"dojo/dom-geometry",
18"dojo/dom-construct",
19"dojo/mouse",
20"dojo/query",
21"dojo/i18n",
22"dojox/html/metrics"],
23
24function(
25        ViewBase,
26        _TemplatedMixin,
27        _VerticalScrollBarBase,
28        template,
29        declare,
30        event,
31        lang,
32        arr,
33        has,
34        fx,
35        html,
36        on,
37        dom,
38        domClass,
39        domStyle,
40        domGeometry,
41        domConstruct,
42        mouse,
43        query,
44        i18n,
45        metrics){
46       
47        /*=====
48        var __ColumnClickEventArgs = {
49                // summary:
50                //              A column click event.
51                // index: Integer
52                //              The column index.
53                // date: Date
54                //              The date displayed by the column.
55                // triggerEvent: Event
56                //              The origin event.
57        };
58        =====*/
59                               
60        return declare("dojox.calendar.MonthColumnView", [ViewBase, _TemplatedMixin], {
61
62                // summary:
63                //              The month column view is a calendar view used to display a month per column where each cell of the column is a day.
64
65                baseClass: "dojoxCalendarMonthColumnView",
66               
67                templateString: template,
68               
69                // viewKind: String
70                //              Type of the view. Used by the calendar widget to determine how to configure the view.
71                //              This view kind is "columns".
72                viewKind: "monthColumns",
73               
74                // scroll container is the focusable item to enable scrolling using up and down arrows
75                _setTabIndexAttr: "domNode",
76               
77                // renderData: Object
78                //              The render data is the object that contains all the properties needed to render the component.
79                renderData: null,               
80                               
81                // startDate: Date
82                //              The start date of the time interval displayed.
83                //              If not set at initialization time, will be set to current day.
84                startDate: null,
85                       
86                // columnCount: Integer
87                //              The number of column to display (from the startDate).
88                columnCount: 6,
89               
90                // daySize: Integer
91                //              The desired size in pixels of an hour on the screen.
92                //              Note that the effective size may be different as the time slot size must be an integer.
93                daySize: 30,
94               
95                // showCellLabel: Boolean
96                //              Whether display or not the grid cells label (usually the day of month).
97                showCellLabel: true,
98               
99                // showHiddenItems: Boolean
100                //              Whether show or not the hidden items.
101                //              By default the events that are shorter than a day are not displayed using vertical renderers by this widget.
102                //              But the grid cells that contains one or several hidden items display a decoration.
103                showHiddenItems: true,
104                       
105                // verticalRenderer: Class
106                //              The class use to create vertical renderers.
107                verticalRenderer: null,
108               
109                // percentOverlap: Integer
110                //              The percentage of the renderer width used to superimpose one item renderer on another
111                //              when two events are overlapping.
112                percentOverlap: 0,
113                               
114                // horizontalGap: Integer
115                //              The number of pixels between two item renderers.
116                horizontalGap: 4,
117               
118                // columnHeaderFormatLength: String
119                //              Length of the column labels. Valid values are "wide" or "abbr".
120                columnHeaderFormatLength: null,
121               
122                // gridCellDatePattern: String
123                //              The date pattern of the cell labels. By default a custom function is used to compute the label.
124                gridCellDatePattern: null,
125               
126                // roundToDay: [private] Boolean
127                roundToDay: true,
128               
129                // _layoutUnit: String
130                //              Unit of layout: each column is displaying a month.
131                _layoutUnit: "month",
132               
133                _columnHeaderHandlers: null,
134               
135                constructor: function(){
136                        this.invalidatingProperties = ["columnCount", "startDate", "daySize", "percentOverlap", "verticalRenderer",
137                                "columnHeaderDatePattern", "horizontalGap", "scrollBarRTLPosition", "itemToRendererKindFunc",
138                                "layoutPriorityFunction", "textDir", "items", "showCellLabel", "showHiddenItems"];
139                        this._columnHeaderHandlers = [];
140                },
141               
142                postCreate: function(){
143                        this.inherited(arguments);
144                        this.keyboardUpDownUnit = "day";       
145                        this.keyboardUpDownSteps =  1;                 
146                        this.keyboardLeftRightUnit = "month";                   
147                        this.keyboardLeftRightSteps = 1;
148                        this.allDayKeyboardUpDownUnit = "day";                 
149                        this.allDayKeyboardUpDownSteps = 1;     
150                        this.allDayKeyboardLeftRightUnit = "month";                     
151                        this.allDayKeyboardLeftRightSteps = 1;
152                },
153               
154                destroy: function(preserveDom){
155                        this._cleanupColumnHeader();
156                        if(this.scrollBar){
157                                this.scrollBar.destroy(preserveDom);
158                        }
159                        this.inherited(arguments);
160                },
161               
162                _scrollBar_onScroll: function(value){
163                        // tags:
164                        //              private
165                        this.scrollContainer.scrollTop = value;
166                },
167               
168                buildRendering: function(){
169                        // tags:
170                        //              private
171                        this.inherited(arguments);
172                        if(this.vScrollBar){
173                                this.scrollBar = new _VerticalScrollBarBase(
174                                        {content: this.vScrollBarContent},
175                                        this.vScrollBar);
176                                       
177                                this.scrollBar.on("scroll", lang.hitch(this, this._scrollBar_onScroll));
178                                this._viewHandles.push(
179                                        on(this.scrollContainer, mouse.wheel, 
180                                                dojo.hitch(this, this._mouseWheelScrollHander)));
181                        }
182                },
183               
184                postscript: function(){
185                        this.inherited(arguments);
186                        this._initialized = true;
187                        if(!this.invalidRendering){
188                                this.refreshRendering();
189                        }
190                },
191               
192                _setVerticalRendererAttr: function(value){
193                        this._destroyRenderersByKind("vertical");
194                        this._set("verticalRenderer", value);   
195                },
196                               
197                _createRenderData: function(){
198                       
199                        var rd = {};
200                                               
201                        rd.daySize = this.get("daySize");                               
202                        rd.scrollbarWidth = metrics.getScrollbar().w + 1;
203                                       
204                        rd.dateLocaleModule = this.dateLocaleModule;
205                        rd.dateClassObj = this.dateClassObj;
206                        rd.dateModule = this.dateModule; // arithmetics on Dates
207                       
208                        rd.dates = [];
209                                               
210                        rd.columnCount = this.get("columnCount");
211
212                        var d = this.get("startDate");
213               
214                        if (d == null){
215                                d = new rd.dateClassObj();
216                        }
217
218                        d = this.floorToMonth(d, false, rd);
219                       
220                        this.startDate = d;
221                        var currentMonth = d.getMonth();
222                        var maxDayCount = 0;                   
223                       
224                        for(var col = 0; col < rd.columnCount ; col++){
225                               
226                                var dates = [];
227                                rd.dates.push(dates);
228                               
229                                while(d.getMonth() == currentMonth){                                                   
230                                        dates.push(d);
231                                        d = rd.dateModule.add(d, "day", 1);
232                                        d = this.floorToDay(d, false, rd);                                     
233                                }
234                               
235                                currentMonth = d.getMonth();
236                               
237                                if(maxDayCount < dates.length){
238                                        maxDayCount = dates.length;
239                                }                                               
240                        }
241                                               
242                        rd.startTime = new rd.dateClassObj(rd.dates[0][0]);                     
243                        rd.endTime = new rd.dateClassObj(dates[dates.length-1]);
244                        rd.endTime = rd.dateModule.add(rd.endTime, "day", 1);
245                                               
246                        rd.maxDayCount = maxDayCount;
247                        rd.sheetHeight = rd.daySize * maxDayCount;
248                       
249                        if(this.displayedItemsInvalidated && !this._isEditing){
250                                this.displayedItemsInvalidated = false;
251                                this._computeVisibleItems(rd);
252                                                               
253                        }else if (this.renderData){
254                                rd.items = this.renderData.items;
255                        }
256                       
257                        return rd;
258                },
259               
260                _validateProperties: function() {
261                       
262                        this.inherited(arguments);
263                                               
264                        if (this.columnCount<1 || isNaN(this.columnCount)){
265                                this.columnCount = 1;                           
266                        }
267                       
268                        if(this.daySize<5 || isNaN(this.daySize)){
269                                this.daySize = 5;
270                        }
271                       
272                },
273               
274                _setStartDateAttr: function(value){
275                        this.displayedItemsInvalidated = true;                 
276                        this._set("startDate", value);
277                },
278               
279                _setColumnCountAttr: function(value){                   
280                        this.displayedItemsInvalidated = true;
281                        this._set("columnCount", value);
282                },
283               
284                __fixEvt:function(e){
285                        e.sheet = "primary";
286                        e.source = this;
287                        return e;
288                },
289               
290                //////////////////////////////////////////
291                //
292                // Formatting functions
293                //
294                //////////////////////////////////////////
295               
296                _formatColumnHeaderLabel: function(/*Date*/d){                 
297                        // summary:
298                        //              Computes the column header label for the specified date.
299                        // d: Date
300                        //              The date to format
301                        // tags:
302                        //              protected
303                       
304                        var len = "wide";
305                       
306                        if(this.columnHeaderFormatLength){
307                                len = this.columnHeaderFormatLength;
308                        }
309                       
310                        var months = this.renderData.dateLocaleModule.getNames("months", len, "standAlone");
311                       
312                        return months[d.getMonth()];
313                },
314               
315                _formatGridCellLabel: function(d, row, col){
316                        // summary:
317                        //              Computes the column header label for the specified date.
318                        //              By default a formatter is used, optionally the <code>gridCellDatePattern</code>
319                        //              property can be used to set a custom date pattern to the formatter.
320                        // d: Date
321                        //              The date to format.
322                        // row: Integer
323                        //              The row that displays the current date.
324                        // col: Integer
325                        //              The column that displays the current date.
326                        // tags:
327                        //              protected
328
329                        var format, rb;
330                       
331                        if(d == null){
332                                return "";
333                        }
334                       
335                        if(this.gridCellPattern){
336                                return this.renderData.dateLocaleModule.format(d, {
337                                        selector: 'date',
338                                        datePattern: this.gridCellDatePattern
339                                });
340                        }else{
341                                rb = i18n.getLocalization("dojo.cldr", this._calendar);
342                                format = rb["dateFormatItem-d"];
343                       
344                                var days = this.renderData.dateLocaleModule.getNames("days", "abbr", "standAlone");
345                                       
346                                return days[d.getDay()].substring(0, 1) + " " + this.renderData.dateLocaleModule.format(d, {
347                                        selector: 'date',
348                                        datePattern: format
349                                });
350                        }
351                },
352               
353                //////////////////////////////////////////
354                //
355                // Time of day management
356                //
357                //////////////////////////////////////////
358               
359                // scrollPosition: Integer
360                //              The scroll position of the view.
361                scrollPosition: null,
362                               
363                // scrollBarRTLPosition: String
364                //              Position of the scroll bar in right-to-left display.
365                //              Valid values are "left" and "right", default value is "left".
366                scrollBarRTLPosition: "left",
367                                       
368                _setScrollPositionAttr: function(value){
369                        this._setScrollPosition(value.date, value.duration, value.easing);
370                },
371               
372                _getScrollPositionAttr: function(){
373                        return {date: (this.scrollContainer.scrollTop / this.daySize) + 1};
374                },
375               
376                _setScrollPosition: function(date, maxDuration, easing){
377                        // tags:
378                        //              private
379                       
380                        if(date < 1){
381                                date = 1;
382                        }else if(date>31){
383                                date = 31;
384                        }
385                       
386                        var position = (date-1) * this.daySize;
387                       
388                        if(maxDuration) {
389                               
390                                if(this._scrollAnimation){
391                                        this._scrollAnimation.stop();
392                                }
393                               
394                                var duration = Math.abs(((position - this.scrollContainer.scrollTop) * maxDuration) / this.renderData.sheetHeight);
395                               
396                                this._scrollAnimation = new fx.Animation({
397                                        curve: [this.scrollContainer.scrollTop, position],
398                                        duration: duration,
399                                        easing: easing,
400                                        onAnimate: lang.hitch(this, function(position) {
401                                                this._setScrollImpl(position);
402                                        })
403                                });
404                                                               
405                                this._scrollAnimation.play();
406
407                        }else{
408                                this._setScrollImpl(position);
409                        }
410                },
411               
412                _setScrollImpl: function(v){
413                        // tags:
414                        //              private
415                       
416                        this.scrollContainer.scrollTop = v;
417                        if(this.scrollBar){
418                                this.scrollBar.set("value", v);
419                        }
420                },
421               
422                ensureVisibility: function(start, end, visibilityTarget, margin, duration){
423                       
424                        // summary:
425                        //              Scrolls the view if the [start, end] time range is not visible or only partially visible.
426                        // start: Date
427                        //              Start time of the range of interest.
428                        // end: Date
429                        //              End time of the range of interest.
430                        // margin: Integer
431                        //              Margin in minutes around the time range.
432                        // visibilityTarget: String
433                        //              The end(s) of the time range to make visible.
434                        //              Valid values are: "start", "end", "both".       
435                        // duration: Number
436                        //              Optional, the maximum duration of the scroll animation.
437                       
438                        margin = margin == undefined ? 1 : margin;
439                       
440                        if(this.scrollable && this.autoScroll){
441                                                       
442                                var s = start.getDate() - margin; // -1 because day of months starts at 1 and not 0
443                                if(this.isStartOfDay(end)){
444                                        end = this._waDojoxAddIssue(end, "day", -1);
445                                }
446                                var e = end.getDate() + margin;
447                               
448                                var viewStart = this.get("scrollPosition").date;
449                                var r = domGeometry.getContentBox(this.scrollContainer);
450                                var viewEnd = (this.get("scrollPosition").date + (r.h/this.daySize));
451                               
452                                var visible = false;
453                                var target = null;
454                               
455                                switch(visibilityTarget){
456                                        case "start":
457                                                visible = s >= viewStart && s <= viewEnd;
458                                                target = s ;
459                                                break;
460                                        case "end":
461                                                visible = e >= viewStart && e <= viewEnd;
462                                                target = e - (viewEnd - viewStart);
463                                                break;
464                                        case "both":
465                                                visible = s >= viewStart && e <= viewEnd;
466                                                target = s;
467                                                break;
468                                }
469                               
470                                if(!visible){
471                                        this._setScrollPosition(target, duration);
472                                }
473                        }
474                },
475               
476                scrollView: function(dir){
477                        // summary:
478                        //              Scrolls the view to the specified direction of one time slot duration.
479                        // dir: Integer
480                        //              Direction of the scroll. Valid values are -1 and 1.
481                        //
482                        var pos = this.get("scrollPosition").date + dir;
483                        this._setScrollPosition(pos);
484                },
485               
486                _mouseWheelScrollHander: function(e){
487                        // summary:
488                        //              Mouse wheel handler.
489                        // tags:
490                        //              protected
491                        this.scrollView(e.wheelDelta > 0 ? -1 : 1);
492                },             
493               
494                //////////////////////////////////////////
495                //
496                // HTML structure management
497                //
498                //////////////////////////////////////////             
499       
500                refreshRendering: function(){
501                        if(!this._initialized){
502                                return;
503                        }
504                                               
505                        this._validateProperties();
506
507                        var oldRd = this.renderData;
508                        var rd = this._createRenderData();
509                        this.renderData = rd;                   
510                        this._createRendering(rd, oldRd);
511                        this._layoutRenderers(rd);
512                },
513               
514                _createRendering: function(/*Object*/renderData, /*Object*/oldRenderData){
515                        // tags:
516                        //              private
517                        domStyle.set(this.sheetContainer, "height", renderData.sheetHeight + "px");
518                        // padding for the scroll bar.
519                        this._configureScrollBar(renderData);
520                        this._buildColumnHeader(renderData, oldRenderData);                     
521                        this._buildGrid(renderData, oldRenderData);
522                        this._buildItemContainer(renderData, oldRenderData);
523                },
524               
525                _configureScrollBar: function(renderData){
526                        // summary:
527                        //              Sets the scroll bar size and position.
528                        // renderData: Object
529                        //              The render data.
530                        // tags:
531                        //              protected
532                       
533                        if(has("ie") && this.scrollBar){
534                                domStyle.set(this.scrollBar.domNode, "width", (renderData.scrollbarWidth + 1) + "px");
535                        }
536                                               
537                        var atRight = this.isLeftToRight() ? true : this.scrollBarRTLPosition == "right";
538                        var rPos = atRight ? "right" : "left";
539                        var lPos = atRight? "left" : "right";
540                       
541                        if(this.scrollBar){
542                                this.scrollBar.set("maximum", renderData.sheetHeight);                 
543                                domStyle.set(this.scrollBar.domNode, rPos, 0);
544                                domStyle.set(this.scrollBar.domNode, lPos, "auto");
545                        }
546                        domStyle.set(this.scrollContainer, rPos, renderData.scrollbarWidth + "px");
547                        domStyle.set(this.scrollContainer, lPos, "0");
548                        domStyle.set(this.columnHeader, rPos, renderData.scrollbarWidth + "px");
549                        domStyle.set(this.columnHeader, lPos, "0");
550                        if(this.buttonContainer && this.owner != null && this.owner.currentView == this){
551                                domStyle.set(this.buttonContainer, rPos, renderData.scrollbarWidth + "px");
552                                domStyle.set(this.buttonContainer, lPos, "0");
553                        }
554                },
555               
556                _columnHeaderClick: function(e){
557                        // tags:
558                        //              private
559
560                        event.stop(e);
561                        var index = query("td", this.columnHeaderTable).indexOf(e.currentTarget);
562                        this._onColumnHeaderClick({
563                                index: index,
564                                date: this.renderData.dates[index][0],
565                                triggerEvent: e
566                        });                                             
567                },
568               
569                _buildColumnHeader: function(renderData, oldRenderData){                               
570                        // summary:
571                        //              Creates incrementally the HTML structure of the column header and configures its content.
572                        //
573                        // renderData:
574                        //              The render data to display.
575                        //
576                        // oldRenderData:
577                        //              The previously render data displayed, if any.
578                        // tags:
579                        //              private
580
581
582                        var table = this.columnHeaderTable;
583                       
584                        if (!table){
585                                return;
586                        }
587                                       
588                        var count = renderData.columnCount - (oldRenderData ? oldRenderData.columnCount : 0);
589                       
590                        if(has("ie") == 8){
591                                // workaround Internet Explorer 8 bug.
592                                // if on the table, width: 100% and table-layout: fixed are set
593                                // and columns are removed, width of remaining columns is not
594                                // recomputed: must rebuild all.
595                                if(this._colTableSave == null){
596                                        this._colTableSave = lang.clone(table);
597                                }else if(count < 0){
598                                        this._cleanupColumnHeader();
599                                        this.columnHeader.removeChild(table);
600                                        domConstruct.destroy(table);
601                                        table = lang.clone(this._colTableSave);
602                                        this.columnHeaderTable = table;
603                                        this.columnHeader.appendChild(table);
604                                        count = renderData.columnCount;
605                                }
606                               
607                        } // else incremental dom add/remove for real browsers.
608                                       
609                        var tbodies = query("tbody", table);
610                       
611                        var trs = query("tr", table);
612                        var tbody, tr, td;
613                       
614                        if (tbodies.length == 1){
615                                tbody = tbodies[0];
616                        }else{
617                                tbody = html.create("tbody", null, table);
618                        }
619                       
620                        if (trs.length == 1){
621                                tr = trs[0];
622                        }else{
623                                tr = domConstruct.create("tr", null, tbody);
624                        }
625                                                 
626                        // Build HTML structure (incremental)
627                        if(count > 0){ // creation                             
628                                for(var i=0; i < count; i++){
629                                                                                                               
630                                        td = domConstruct.create("td", null, tr);
631                                       
632                                        var h = [];
633                                        h.push(on(td, "click", lang.hitch(this, this._columnHeaderClick)));
634                                                                               
635                                        if(has("touch")){                                       
636                                                h.push(on(td, "touchstart", function(e){
637                                                        event.stop(e);
638                                                        domClass.add(e.currentTarget, "Active");
639                                                }));
640                                               
641                                                h.push(on(td, "touchend", function(e){                 
642                                                        event.stop(e);                 
643                                                        domClass.remove(e.currentTarget, "Active");                     
644                                                }));
645                                        }else{
646                                                h.push(on(td, "mousedown", function(e){
647                                                        event.stop(e);
648                                                        domClass.add(e.currentTarget, "Active");
649                                                }));
650                                                                                               
651                                                h.push(on(td, "mouseup", function(e){
652                                                        event.stop(e);
653                                                        domClass.remove(e.currentTarget, "Active");
654                                                }));                                   
655                                               
656                                                h.push(on(td, "mouseover", function(e){
657                                                        event.stop(e);
658                                                        domClass.add(e.currentTarget, "Hover");
659                                                }));
660                                                                                       
661                                                h.push(on(td, "mouseout", function(e){
662                                                        event.stop(e);
663                                                        domClass.remove(e.currentTarget, "Hover");
664                                                }));
665                                       
666                                        }
667                                       
668                                        this._columnHeaderHandlers.push(h);                                     
669                                }
670                               
671                        }else{ // deletion
672                                count = -count;
673                                for(var i=0; i < count; i++){
674                                        td = tr.lastChild;
675                                        tr.removeChild(td);
676                                        domConstruct.destroy(td);
677                                        var list = this._columnHeaderHandlers.pop();
678                                        while(list.length>0){
679                                                list.pop().remove();
680                                        }
681                                }
682                        }
683                       
684                        // fill & configure             
685                        query("td", table).forEach(function(td, i){
686                                td.className = "";                                                                                     
687                                if(i == 0){
688                                        domClass.add(td, "first-child");
689                                }else if(i == this.renderData.columnCount-1){
690                                        domClass.add(td, "last-child");
691                                }
692                                var d = renderData.dates[i][0];
693                                this._setText(td, this._formatColumnHeaderLabel(d));
694                                this.styleColumnHeaderCell(td, d, renderData);                                         
695                        }, this);
696                                               
697                },
698               
699                _cleanupColumnHeader: function(){
700                        // tags:
701                        //              private
702
703                        while(this._columnHeaderHandlers.length > 0){
704                                var list = this._columnHeaderHandlers.pop();
705                                while(list.length > 0){
706                                        list.pop().remove();
707                                }
708                        }
709                },
710               
711                styleColumnHeaderCell: function(node, date, renderData){
712                        // summary:
713                        //              Styles the CSS classes to the node that displays a column header cell.
714                        //              By default this method is does nothing and is designed to be overridden.
715                        // node: Node
716                        //              The DOM node that displays the column in the grid.
717                        // date: Date
718                        //              The date displayed by this column
719                        // renderData: Object                   
720                        //              The render data.                       
721                        // tags:
722                        //              protected
723
724                },
725               
726                _buildGrid: function (renderData, oldRenderData){
727                        // summary:
728                        //              Creates incrementally the HTML structure of the grid and configures its content.
729                        //
730                        // renderData:
731                        //              The render data to display.
732                        //
733                        // oldRenderData:
734                        //              The previously render data displayed, if any.
735                        // tags:
736                        //              private
737
738
739                        var table = this.gridTable;
740                       
741                        if(!table){
742                                return;
743                        }
744                       
745                        domStyle.set(table, "height", renderData.sheetHeight + "px");                           
746
747                        var rowDiff = renderData.maxDayCount - (oldRenderData ? oldRenderData.maxDayCount : 0);
748                        var addRows = rowDiff > 0;
749                       
750                        var colDiff  = renderData.columnCount - (oldRenderData ? oldRenderData.columnCount : 0);
751                       
752                        if(has("ie") == 8){
753                                // workaround Internet Explorer 8 bug.
754                                // if on the table, width: 100% and table-layout: fixed are set
755                                // and columns are removed, width of remaining columns is not
756                                // recomputed: must rebuild all.
757                                if(this._gridTableSave == null){
758                                        this._gridTableSave = lang.clone(table);
759                                }else if(colDiff < 0){                                 
760                                        this.grid.removeChild(table);
761                                        domConstruct.destroy(table);
762                                        table = lang.clone(this._gridTableSave);
763                                        this.gridTable = table;
764                                        this.grid.appendChild(table);
765                                        colDiff = renderData.columnCount;
766                                        rowDiff = renderData.maxDayCount;
767                                        addRows = true;
768                                }                               
769                        }
770                       
771                        var tbodies = query("tbody", table);
772                        var tbody;
773
774                        if(tbodies.length == 1){
775                                tbody = tbodies[0];
776                        }else{
777                                tbody = domConstruct.create("tbody", null, table);
778                        }
779
780                        // Build rows HTML structure (incremental)
781                        if(addRows){ // creation
782                                for(var i=0; i<rowDiff; i++){
783                                        domConstruct.create("tr", null, tbody);
784                                }               
785                        }else{ // deletion               
786                                rowDiff = -rowDiff;
787                                for(var i=0; i<rowDiff; i++){
788                                        tbody.removeChild(tbody.lastChild);
789                                }
790                        }
791
792                        var rowIndex = renderData.maxDayCount - rowDiff;
793                       
794                        var addCols = addRows || colDiff >0;
795                        colDiff = addCols ? colDiff : -colDiff;
796                       
797                        query("tr", table).forEach(function(tr, i){
798                               
799                                if(addCols){ // creation
800                                        var len = i >= rowIndex ? renderData.columnCount : colDiff;
801                                        for(var i=0; i<len; i++){
802                                                var td = domConstruct.create("td", null, tr);
803                                                domConstruct.create("span", null, td);
804                                        }
805                                }else{ // deletion
806                                        for(var i=0; i<colDiff; i++){
807                                                tr.removeChild(tr.lastChild);
808                                        }
809                                }
810                        });
811
812                        // Set the CSS classes
813
814                        query("tr", table).forEach(function (tr, row){
815                               
816                                tr.className = "";
817                                // compatibility layer for IE7 & 8 that does not support :first-child and :last-child pseudo selectors
818                                if(row == 0){
819                                        domClass.add(tr, "first-child");
820                                }
821                                if(row == renderData.maxDayCount-1){
822                                        domClass.add(tr, "last-child");
823                                }
824
825                                query("td", tr).forEach(function (td, col){
826                                       
827                                        td.className = "";
828                                       
829                                        if(col == 0){
830                                                domClass.add(td, "first-child");
831                                        }
832                                       
833                                        if(col == renderData.columnCount-1){
834                                                domClass.add(td, "last-child");
835                                        }
836                                       
837                                        var d = null;
838                                        if(row < renderData.dates[col].length) {
839                                                d = renderData.dates[col][row];
840                                        }
841                                       
842                                        var span = query("span", td)[0];
843                                        this._setText(span, this.showCellLabel ? this._formatGridCellLabel(d, row, col): null);
844                                       
845                                        this.styleGridCell(td, d, col, row, renderData);
846                                       
847                                }, this);
848                        }, this);
849
850                },
851               
852                // styleGridCellFunc: Function
853                //              Custom function to customize the appearance of a grid cell by installing custom CSS class on the node.
854                //              The signature of the function must be the same then the styleGridCell one.
855                //              By default the defaultStyleGridCell function is used.
856                styleGridCellFunc: null,
857               
858                defaultStyleGridCell: function(node, date, col, row, renderData){
859                        // summary:
860                        //              Styles the CSS classes to the node that displays a column.
861                        //              By default this method is setting the following CSS classes:
862                        //              - "dojoxCalendarToday" class name if the date displayed is the current date,
863                        //              - "dojoxCalendarWeekend" if the date represents a weekend,
864                        //              - the CSS class corresponding of the displayed day of week ("Sun", "Mon" and so on),
865                        // node: Node
866                        //              The DOM node that displays the cell in the grid.
867                        // date: Date
868                        //              The date displayed by this cell.
869                        // col: Integer
870                        //              The column index of this cell.
871                        // row: Integer
872                        //              The row index of this cell.
873                        // renderData: Object
874                        //              The render data.
875                        // tags:
876                        //              protected
877                       
878                        if(date == null){
879                                return;
880                        }
881                        domClass.add(node, this._cssDays[date.getDay()]);
882                        if(this.isToday(date)){                         
883                                domClass.add(node, "dojoxCalendarToday");
884                        }else if(this.isWeekEnd(date)){
885                                domClass.add(node, "dojoxCalendarWeekend");
886                        }                                       
887                },
888               
889                styleGridCell: function(node, date, col, row, renderData){
890                        // summary:
891                        //              Styles the CSS classes to the node that displays a column.
892                        //              Delegates to styleGridCellFunc if defined or defaultStyleGridCell otherwise.
893                        // node: Node
894                        //              The DOM node that displays the cell in the grid.
895                        // date: Date
896                        //              The date displayed by this cell.
897                        // col: Integer
898                        //              The column index of this cell.
899                        // row: Integer
900                        //              The row index of this cell.
901                        // renderData: Object
902                        //              The render data.
903                        // tags:
904                        //              protected
905
906                        if(this.styleGridCellFunc){
907                                this.styleGridCellFunc(node, date, col, row, renderData);
908                        }else{
909                                this.defaultStyleGridCell(node, date, col, row, renderData);
910                        }                               
911                },
912                                                       
913                _buildItemContainer: function(renderData, oldRenderData){
914                        // summary:
915                        //              Creates the HTML structure of the item container and configures its content.
916                        // renderData:
917                        //              The render data to display.
918                        // oldRenderData:
919                        //              The previously render data displayed, if any.
920                        // tags:
921                        //              private
922
923                       
924                        var table = this.itemContainerTable;
925                       
926                        if (!table){
927                                return;
928                        }
929                       
930                        var bgCols = [];
931       
932                        domStyle.set(table, "height", renderData.sheetHeight + "px");                   
933                       
934                        var count = renderData.columnCount - (oldRenderData ? oldRenderData.columnCount : 0);
935                       
936                        if(has("ie") == 8){
937                                // workaround Internet Explorer 8 bug.
938                                // if on the table, width: 100% and table-layout: fixed are set
939                                // and columns are removed, width of remaining columns is not
940                                // recomputed: must rebuild all.
941                                if(this._itemTableSave == null){
942                                        this._itemTableSave = lang.clone(table);
943                                }else if(count < 0){
944                                        this.itemContainer.removeChild(table);
945                                        this._recycleItemRenderers(true);
946                                        domConstruct.destroy(table);
947                                        table = lang.clone(this._itemTableSave);
948                                        this.itemContainerTable = table;
949                                        this.itemContainer.appendChild(table);
950                                        count = renderData.columnCount;
951                                }
952                               
953                        } // else incremental dom add/remove for real browsers.
954                       
955                        var tbodies = query("tbody", table);
956                        var trs = query("tr", table);
957                        var tbody, tr, td;
958                       
959                        if (tbodies.length == 1){
960                                tbody = tbodies[0];
961                        }else{
962                                tbody = domConstruct.create("tbody", null, table);
963                        }
964                       
965                        if (trs.length == 1){
966                                tr = trs[0];
967                        }else{
968                                tr = domConstruct.create("tr", null, tbody);
969                        }                                       
970                                                               
971                        // Build HTML structure (incremental)
972                        if(count>0){ // creation
973                                for(var i=0; i < count; i++){
974                                        td = domConstruct.create("td", null, tr);       
975                                        domConstruct.create("div", {"className": "dojoxCalendarContainerColumn"}, td);
976                                }
977                        }else{ // deletion               
978                                count = -count;
979                                for(var i=0; i < count; i++){
980                                        tr.removeChild(tr.lastChild);
981                                }
982                        }       
983                       
984                        query("td>div", table).forEach(function(div, i){
985
986                                domStyle.set(div, {
987                                        "height": renderData.sheetHeight + "px"
988                                });
989                                bgCols.push(div);               
990                        }, this);
991                       
992                        renderData.cells = bgCols;
993                },                     
994               
995                ///////////////////////////////////////////////////////////////
996                //
997                // Layout
998                //
999                ///////////////////////////////////////////////////////////////
1000               
1001                _overlapLayoutPass2: function(lanes){
1002                        // summary:
1003                        //              Second pass of the overlap layout (optional). Compute the extent of each layout item.
1004                        // lanes:
1005                        //              The array of lanes.
1006                        // tags:
1007                        //              private
1008                        var i,j,lane, layoutItem;
1009                        // last lane, no extent possible
1010                        lane = lanes[lanes.length-1];
1011                       
1012                        for(j = 0; j < lane.length; j++){
1013                                lane[j].extent = 1;
1014                        }
1015                                               
1016                        for(i=0; i<lanes.length-1; i++){
1017                                lane = lanes[i];
1018                               
1019                                for(var j=0; j<lane.length; j++){       
1020                                        layoutItem = lane[j];
1021                                       
1022                                        // if item was already overlapping another one there is no extent possible.
1023                                        if(layoutItem.extent == -1){
1024                                                layoutItem.extent = 1;
1025                                                var space = 0;
1026                                               
1027                                                var stop = false;
1028                                               
1029                                                for(var k = i + 1; k < lanes.length && !stop; k++){
1030                                                        var ccol = lanes[k];
1031                                                        for(var l = 0; l < ccol.length && !stop; l++){
1032                                                                var layoutItem2 = ccol[l];
1033                                                               
1034                                                                if(layoutItem.start < layoutItem2.end && layoutItem2.start < layoutItem.end){
1035                                                                        stop = true;
1036                                                                }
1037                                                        }
1038                                                        if(!stop){
1039                                                                //no hit in the entire lane
1040                                                                space++;
1041                                                        }
1042                                                }
1043                                                layoutItem.extent += space;
1044                                        }
1045                                }
1046                        }
1047                },
1048               
1049                _defaultItemToRendererKindFunc: function(item){
1050                        // tags:
1051                        //              private
1052
1053                        if(item.allDay){
1054                                return "vertical";
1055                        }
1056                        var dur = Math.abs(this.renderData.dateModule.difference(item.startTime, item.endTime, "minute"));
1057                        return dur >= 1440 ? "vertical" : null;
1058                },
1059               
1060                _layoutRenderers: function(renderData){
1061                        this.hiddenEvents = {};
1062                        this.inherited(arguments);
1063                },
1064               
1065                _layoutInterval: function(/*Object*/renderData, /*Integer*/index, /*Date*/start, /*Date*/end, /*Object[]*/items){
1066                        // tags:
1067                        //              private
1068
1069                        var verticalItems = [];
1070                        var hiddenItems = [];
1071                        renderData.colW = this.itemContainer.offsetWidth / renderData.columnCount;
1072                       
1073                        for(var i=0; i<items.length; i++){
1074                                var item = items[i];
1075                                if(this._itemToRendererKind(item) == "vertical"){
1076                                        verticalItems.push(item);
1077                                }else if(this.showHiddenItems){
1078                                        hiddenItems.push(item);                                 
1079                                }
1080                        }
1081                       
1082                        if(verticalItems.length > 0){
1083                                this._layoutVerticalItems(renderData, index, start, end, verticalItems);
1084                        }
1085                        if(hiddenItems.length > 0){
1086                                this._layoutBgItems(renderData, index, start, end, hiddenItems);
1087                        }
1088                },
1089               
1090                _dateToYCoordinate: function(renderData, d, start){
1091                        // tags:
1092                        //              private
1093
1094                        var pos = 0;
1095                        if(start || d.getHours() != 0 || d.getMinutes() != 0){
1096                                pos = (d.getDate()-1) * this.renderData.daySize;
1097                        }else{
1098                                var d2 = this._waDojoxAddIssue(d, "day", -1);
1099                                pos = this.renderData.daySize + ((d2.getDate()-1) * this.renderData.daySize);
1100                        }                       
1101                        pos += (d.getHours()*60+d.getMinutes())*this.renderData.daySize/1440;
1102                       
1103                        return pos;
1104                },
1105               
1106                _layoutVerticalItems: function(/*Object*/renderData, /*Integer*/index, /*Date*/startTime, /*Date*/endTime, /*Object[]*/items){
1107                        // tags:
1108                        //              private
1109
1110                        if(this.verticalRenderer == null){
1111                                return;
1112                        }
1113                       
1114                        var cell = renderData.cells[index];
1115                        var layoutItems = [];                   
1116                       
1117                        // step 1 compute projected position and size
1118                        for(var i = 0; i < items.length; i++){
1119                               
1120                                var item = items[i];
1121                                var overlap = this.computeRangeOverlap(renderData, item.startTime, item.endTime, startTime, endTime);
1122                               
1123                                var top = this._dateToYCoordinate(renderData, overlap[0], true);
1124                                var bottom = this._dateToYCoordinate(renderData, overlap[1], false);
1125                               
1126                                if (bottom > top){
1127                                        var litem = lang.mixin({
1128                                                start: top,
1129                                                end: bottom,
1130                                                range: overlap,
1131                                                item: item
1132                                        }, item);
1133                                        layoutItems.push(litem);
1134                                }
1135                        }
1136                       
1137                        // step 2: compute overlapping layout
1138                        var numLanes = this.computeOverlapping(layoutItems, this._overlapLayoutPass2).numLanes;
1139
1140                        var hOverlap = this.percentOverlap / 100;
1141
1142                        // step 3: create renderers and apply layout
1143                        for(i=0; i<layoutItems.length; i++){
1144
1145                                item = layoutItems[i];                                 
1146                                var lane = item.lane;
1147                                var extent = item.extent;
1148
1149                                var w;
1150                                var posX;                               
1151
1152                                if(hOverlap == 0) {
1153                                        //no overlap and a padding between each event
1154                                        w = numLanes == 1 ? renderData.colW : ((renderData.colW - (numLanes - 1) * this.horizontalGap)/ numLanes);
1155                                        posX = lane * (w + this.horizontalGap);
1156                                        w = extent == 1 ? w : w * extent + (extent-1) * this.horizontalGap;
1157                                        w = 100 * w / renderData.colW;
1158                                        posX = 100 * posX / renderData.colW;
1159                                } else {
1160                                        // an overlap
1161                                        w = numLanes == 1 ? 100 : (100 / (numLanes - (numLanes - 1) * hOverlap));
1162                                        posX = lane * (w - hOverlap*w);
1163                                        w = extent == 1 ? w : w * ( extent - (extent-1) * hOverlap);
1164                                }
1165
1166                                var ir = this._createRenderer(item, "vertical", this.verticalRenderer, "dojoxCalendarVertical");
1167
1168                                domStyle.set(ir.container, {
1169                                        "top": item.start + "px",
1170                                        "left": posX + "%",
1171                                        "width": w + "%",
1172                                        "height": (item.end-item.start+1) + "px"
1173                                });
1174
1175                                var edited = this.isItemBeingEdited(item);
1176                                var selected = this.isItemSelected(item);
1177                                var hovered = this.isItemHovered(item);
1178                                var focused = this.isItemFocused(item);
1179                               
1180                                var renderer = ir.renderer;
1181
1182                                renderer.set("hovered", hovered);
1183                                renderer.set("selected", selected);
1184                                renderer.set("edited", edited);
1185                                renderer.set("focused", this.showFocus ? focused : false);
1186                               
1187                                renderer.set("storeState", this.getItemStoreState(item));
1188                               
1189                                renderer.set("moveEnabled", this.isItemMoveEnabled(item._item, "vertical"));
1190                                renderer.set("resizeEnabled", this.isItemResizeEnabled(item._item, "vertical"));
1191                               
1192                                this.applyRendererZIndex(item, ir, hovered, selected, edited, focused);
1193
1194                                if(renderer.updateRendering){
1195                                        renderer.updateRendering(w, item.end-item.start+1);
1196                                }
1197
1198                                domConstruct.place(ir.container, cell);
1199                                domStyle.set(ir.container, "display", "block");
1200                        }
1201                },
1202               
1203                _getCellAt: function(rowIndex, columnIndex, rtl){
1204                        // tags:
1205                        //              private
1206
1207                        if((rtl == undefined || rtl == true) && !this.isLeftToRight()){
1208                                columnIndex = this.renderData.columnCount -1 - columnIndex;
1209                        }
1210                        return this.gridTable.childNodes[0].childNodes[rowIndex].childNodes[columnIndex];
1211                },
1212               
1213                invalidateLayout: function(){
1214                        //make sure to clear hiddens object state
1215                        query("td", this.gridTable).forEach(function(td){
1216                                domClass.remove(td, "dojoxCalendarHiddenEvents");
1217                        });
1218                        this.inherited(arguments);                     
1219                },
1220               
1221                _layoutBgItems: function(/*Object*/renderData, /*Integer*/col, /*Date*/startTime, /*Date*/endTime, /*Object[]*/items){
1222                        // tags:
1223                        //              private
1224
1225                        var bgItems = {};
1226                        for(var i = 0; i < items.length; i++){
1227                               
1228                                var item = items[i];
1229                                var overlap = this.computeRangeOverlap(renderData, item.startTime, item.endTime, startTime, endTime);
1230                                var start = overlap[0].getDate()-1;
1231                                // handle use case where end time is first day of next month.
1232                                var end;
1233                                if(this.isStartOfDay(overlap[1])){
1234                                        end = this._waDojoxAddIssue(overlap[1], "day", -1);
1235                                        end = end.getDate()-1;
1236                                }else{
1237                                        end = overlap[1].getDate()-1;
1238                                }
1239                               
1240                                for (var d=start; d<=end; d++){
1241                                        bgItems[d] = true;
1242                                }
1243                        }                                       
1244       
1245                        for(var row in bgItems) {
1246                                if(bgItems[row]){
1247                                        var node = this._getCellAt(row, col, false);
1248                                        domClass.add(node, "dojoxCalendarHiddenEvents");
1249                                }
1250                        }                       
1251                },
1252               
1253                _sortItemsFunction: function(a, b){
1254                        // tags:
1255                        //              private
1256
1257                        var res = this.dateModule.compare(a.startTime, b.startTime);
1258                        if(res == 0){
1259                                res = -1 * this.dateModule.compare(a.endTime, b.endTime);
1260                        }
1261                        return this.isLeftToRight() ? res : -res;
1262                },
1263               
1264                ///////////////////////////////////////////////////////////////
1265                //
1266                // View to time projection
1267                //
1268                ///////////////////////////////////////////////////////////////
1269               
1270                getTime: function(e, x, y, touchIndex){
1271                        // summary:
1272                        //              Returns the time displayed at the specified point by this component.
1273                        // e: Event
1274                        //              Optional mouse event.
1275                        // x: Number
1276                        //              Position along the x-axis with respect to the sheet container used if event is not defined.
1277                        // y: Number
1278                        //              Position along the y-axis with respect to the sheet container (scroll included) used if event is not defined.
1279                        // touchIndex: Integer
1280                        //              If parameter 'e' is not null and a touch event, the index of the touch to use.
1281                        // returns: Date
1282                       
1283                        if (e != null){                         
1284                                var refPos = domGeometry.position(this.itemContainer, true);
1285                               
1286                                if(e.touches){                                                                 
1287                                       
1288                                        touchIndex = touchIndex==undefined ? 0 : touchIndex;
1289                                                                       
1290                                        x = e.touches[touchIndex].pageX - refPos.x;
1291                                        y = e.touches[touchIndex].pageY - refPos.y;                                                                     
1292                                       
1293                                }else{
1294                                       
1295                                        x = e.pageX - refPos.x;                                 
1296                                        y = e.pageY - refPos.y;                                 
1297                                }
1298                        }
1299                       
1300                        var r = domGeometry.getContentBox(this.itemContainer);
1301                       
1302                        if(!this.isLeftToRight()){
1303                                x = r.w - x;
1304                        }
1305                       
1306                        if (x < 0){
1307                                x = 0;
1308                        }else if(x > r.w){
1309                                x = r.w-1;
1310                        }
1311                       
1312                        if (y < 0){
1313                                y = 0;
1314                        }else if(y > r.h){
1315                                y = r.h-1;
1316                        }
1317                       
1318                        var col = Math.floor(x / (r.w / this.renderData.columnCount));
1319                        var row = Math.floor(y / (r.h / this.renderData.maxDayCount));
1320                       
1321                        var date = null;
1322                        if(col < this.renderData.dates.length &&
1323                                 row < this.renderData.dates[col].length){                     
1324                                date = this.newDate(this.renderData.dates[col][row]);                   
1325                        }
1326       
1327                        return date;
1328                },
1329               
1330                ///////////////////////////////////////////////////////////////
1331                //
1332                // Events
1333                //
1334                ///////////////////////////////////////////////////////////////
1335               
1336                _onGridMouseUp: function(e){
1337                       
1338                        // tags:
1339                        //              private
1340
1341                       
1342                        this.inherited(arguments);
1343                       
1344                        if (this._gridMouseDown) {
1345                                this._gridMouseDown = false;
1346                               
1347                                this._onGridClick({
1348                                        date: this.getTime(e),
1349                                        triggerEvent: e
1350                                });
1351                        }                       
1352                },                     
1353                       
1354                _onGridTouchStart: function(e){
1355                        // tags:
1356                        //              private
1357
1358                       
1359                        this.inherited(arguments);                     
1360                       
1361                        var g = this._gridProps;                                               
1362
1363                        g.moved= false;
1364                        g.start= e.touches[0].screenY;
1365                        g.scrollTop= this.scrollContainer.scrollTop;
1366                },
1367               
1368                _onGridTouchMove: function(e){
1369                        // tags:
1370                        //              private
1371
1372                        this.inherited(arguments);                                             
1373                       
1374                        if (e.touches.length > 1 && !this._isEditing){
1375                                event.stop(e);                         
1376                                return;
1377                        }                       
1378                       
1379                        if(this._gridProps && !this._isEditing){
1380                               
1381                                var touch = {x: e.touches[0].screenX, y: e.touches[0].screenY};
1382                               
1383                                var p = this._edProps;
1384                               
1385                                if (!p || p &&
1386                                        (Math.abs(touch.x - p.start.x) > 25 ||
1387                                         Math.abs(touch.y - p.start.y) > 25)) {
1388                                                                                                                                               
1389                                        this._gridProps.moved = true;
1390                                        var d = e.touches[0].screenY - this._gridProps.start;
1391                                        var value = this._gridProps.scrollTop - d;
1392                                        var max = this.itemContainer.offsetHeight - this.scrollContainer.offsetHeight;
1393                                        if (value < 0){
1394                                                this._gridProps.start = e.touches[0].screenY;
1395                                                this._setScrollImpl(0);
1396                                                this._gridProps.scrollTop = 0;
1397                                        }else if(value > max){
1398                                                this._gridProps.start = e.touches[0].screenY;
1399                                                this._setScrollImpl(max);
1400                                                this._gridProps.scrollTop = max;
1401                                        }else{
1402                                                this._setScrollImpl(value);
1403                                        }
1404                                }
1405                        }
1406                },
1407               
1408                _onGridTouchEnd: function(e){
1409                        // tags:
1410                        //              private
1411
1412                        //event.stop(e);
1413                                                               
1414                        this.inherited(arguments);
1415                                                                       
1416                        var g = this._gridProps;                                       
1417                       
1418                        if(g){
1419                                if(!this._isEditing){
1420                                        if(!g.moved){
1421                                               
1422                                                // touched on grid and on touch start editing was ongoing.
1423                                                if(!g.fromItem && !g.editingOnStart){                                                           
1424                                                        this.selectFromEvent(e, null, null, true);
1425                                                }                       
1426                                               
1427                                                if(!g.fromItem){
1428                                               
1429                                                        if(this._pendingDoubleTap && this._pendingDoubleTap.grid){
1430                                                                                                                       
1431                                                                this._onGridDoubleClick({
1432                                                                        date: this.getTime(this._gridProps.event),
1433                                                                        triggerEvent: this._gridProps.event
1434                                                                });
1435                                                               
1436                                                                clearTimeout(this._pendingDoubleTap.timer);
1437                                               
1438                                                                delete this._pendingDoubleTap;
1439                                                               
1440                                                        }else{
1441                                                                                                                       
1442                                                                this._onGridClick({
1443                                                                        date: this.getTime(this._gridProps.event),
1444                                                                        triggerEvent: this._gridProps.event
1445                                                                });
1446                                                               
1447                                                                this._pendingDoubleTap = {
1448                                                                        grid: true,
1449                                                                        timer: setTimeout(lang.hitch(this, function(){
1450                                                                                        delete this._pendingDoubleTap;
1451                                                                        }), this.doubleTapDelay)
1452                                                                };
1453                                                        }
1454                                                }       
1455                                        }
1456                                }
1457                               
1458                                this._gridProps = null;
1459                        }
1460                },
1461               
1462                _onColumnHeaderClick: function(e){
1463                        // tags:
1464                        //              private
1465
1466                        this._dispatchCalendarEvt(e, "onColumnHeaderClick");
1467                },
1468               
1469                onColumnHeaderClick: function(e){
1470                        // summary:
1471                        //              Event dispatched when a column header cell is dispatched.
1472                        // e: __ColumnClickEventArgs
1473                        // tags:
1474                        //              callback
1475
1476                },
1477               
1478
1479                ///////////////////////////////////////////////////////////////
1480                //
1481                // View limits
1482                //
1483                ///////////////////////////////////////////////////////////////
1484                                               
1485                _onScrollTimer_tick: function(){
1486                        // tags:
1487                        //              private
1488
1489                        this._setScrollImpl(this.scrollContainer.scrollTop + this._scrollProps.scrollStep);
1490                },
1491               
1492                ////////////////////////////////////////////
1493                //
1494                // Editing
1495                //
1496                ///////////////////////////////////////////                                             
1497               
1498                snapUnit: "day",
1499                snapSteps: 1,
1500                minDurationUnit: "day",
1501                minDurationSteps: 1,
1502                liveLayout: false,
1503                stayInView: true,
1504                allowStartEndSwap: true,
1505                allowResizeLessThan24H: false
1506               
1507        });
1508});
Note: See TracBrowser for help on using the repository browser.