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

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

Added Dojo 1.9.3 release.

  • Property svn:executable set to *
File size: 13.0 KB
Line 
1define(["dojo/_base/array", "dojo/_base/lang", "dojo/_base/declare", "dojo/dom", "dojo/dom-geometry", "dojo/_base/window", "dojo/on", "dojo/_base/event", "dojo/keys"],
2
3        function(arr, lang, declare, dom, domGeometry, win, on, event, keys){
4                       
5        return declare("dojox.calendar.Touch", null, {
6               
7                // summary:
8                //              This plugin is managing the touch interactions on item renderers displayed by a calendar view.         
9                               
10                // touchStartEditingTimer: Integer
11                //              The delay of one touch over the renderer before setting the item in editing mode.               
12                touchStartEditingTimer: 500,
13               
14                // touchEndEditingTimer: Integer
15                //              The delay after which the item is leaving the editing mode after the previous editing gesture, in touch context.
16                touchEndEditingTimer: 10000,
17               
18                postMixInProperties: function(){
19                       
20                        this.on("rendererCreated", lang.hitch(this, function(irEvent){
21                               
22                                var renderer = irEvent.renderer.renderer;
23                                               
24                                this.own(on(renderer.domNode, "touchstart", lang.hitch(this, function(e){
25                                        this._onRendererTouchStart(e, renderer);
26                                })));
27                               
28                        }));
29                },
30               
31                _onRendererTouchStart: function(e, renderer){
32                        // tags:
33                        //              private
34                        var p = this._edProps; 
35                       
36                        if(p && p.endEditingTimer){
37                                clearTimeout(p.endEditingTimer);
38                                p.endEditingTimer = null;
39                        }                               
40
41                        var theItem = renderer.item.item;
42
43                        if(p && p.endEditingTimer){
44                                clearTimeout(p.endEditingTimer);
45                                p.endEditingTimer = null;
46                        }
47
48                        if(p != null && p.item != theItem){
49                                // another item is edited.
50                                // stop previous item
51                                if(p.startEditingTimer){
52                                        clearTimeout(p.startEditingTimer);
53                                }
54
55                                this._endItemEditing("touch", false);
56                                p = null;
57
58                        }
59
60                        // initialize editing properties
61                        if(!p){
62                               
63                                // register event listeners to manage gestures.
64                                var handles = [];
65                               
66                                handles.push(on(win.doc, "touchend", lang.hitch(this, this._docEditingTouchEndHandler)));
67                                handles.push(on(this.itemContainer, "touchmove", lang.hitch(this, this._docEditingTouchMoveHandler)));                                         
68                               
69                                this._setEditingProperties({
70                                        touchMoved: false,
71                                        item: theItem,
72                                        renderer: renderer,
73                                        rendererKind: renderer.rendererKind,
74                                        event: e,
75                                        handles: handles,
76                                        liveLayout: this.liveLayout
77                                });
78
79                                p = this._edProps;
80                        }
81
82                        if(this._isEditing){
83                                                                       
84                                // get info on touches
85                                lang.mixin(p, this._getTouchesOnRenderers(e, p.editedItem));
86                               
87                                // start an editing gesture.
88                                this._startTouchItemEditingGesture(e);
89                               
90                        } else {
91                               
92                                // initial touch that will trigger or not the editing
93                       
94                                if(e.touches.length > 1){
95                                        event.stop(e);
96                                        return;
97                                }
98                               
99                                // set the selection state without dispatching (on touch end) after a short amount of time.
100                                // to allow a bit of time to scroll without selecting (graphically at least)                                                                                   
101                                this._touchSelectionTimer = setTimeout(lang.hitch(this, function(){                                                                     
102                                       
103                                        this._saveSelectedItems = this.get("selectedItems");
104                                                       
105                                        var changed = this.selectFromEvent(e, theItem._item, renderer, false);
106                                       
107                                        if(changed){                                   
108                                                this._pendingSelectedItem = theItem;
109                                        }else{
110                                                delete this._saveSelectedItems;
111                                        }
112                                        this._touchSelectionTimer = null;
113                                }), 200);
114                               
115                                p.start = {x: e.touches[0].screenX, y: e.touches[0].screenY};
116                               
117                                if(this.isItemEditable(p.item, p.rendererKind)){
118                                                                       
119                                        // editing gesture timer
120                                        this._edProps.startEditingTimer = setTimeout(lang.hitch(this, function(){                                                                                       
121                                               
122                                                // we are editing, so the item *must* be selected.
123                                                if(this._touchSelectionTimer){                                                 
124                                                        clearTimeout(this._touchSelectionTimer);
125                                                        delete this._touchSelectionTime;
126                                                }
127                                                if(this._pendingSelectedItem){                                                 
128                                                        this.dispatchChange(this._saveSelectedItems == null ? null : this._saveSelectedItems[0], this._pendingSelectedItem, null, e);
129                                                        delete this._saveSelectedItems;
130                                                        delete this._pendingSelectedItem;
131                                                }else{                                                 
132                                                        this.selectFromEvent(e, theItem._item, renderer);
133                                                }
134                                                                                                                                                                       
135                                                this._startItemEditing(p.item, "touch", e);
136                                               
137                                                p.moveTouchIndex = 0;
138                                               
139                                                // A move gesture is initiated even if we don't move
140                                                this._startItemEditingGesture([this.getTime(e)], "move", "touch", e);
141                                               
142                                        }), this.touchStartEditingTimer);
143                               
144                                }                               
145                        }                                                       
146                },
147               
148                _docEditingTouchMoveHandler: function(e){
149                        // tags:
150                        //              private
151                        var p = this._edProps;
152                                                                               
153                        // When the screen is touched, it can dispatch move events if the
154                        // user press the finger a little more...
155                        var touch = {x: e.touches[0].screenX, y: e.touches[0].screenY};                                                                                                         
156                        if(p.startEditingTimer &&
157                                        (Math.abs(touch.x - p.start.x) > 25 ||
158                                         Math.abs(touch.y - p.start.y) > 25)) {
159                                               
160                                // scroll use case, do not edit
161                                clearTimeout(p.startEditingTimer);
162                                p.startEditingTimer = null;
163                               
164                                clearTimeout(this._touchSelectionTimer);
165                                this._touchSelectionTimer = null;                               
166                               
167                                if(this._pendingSelectedItem){                                 
168                                        delete this._pendingSelectedItem;
169                                        this.selectFromEvent(e, null, null, false);
170                                }                       
171                        }
172                       
173                        p.touchMoved = true;
174                                                               
175                        if(this._editingGesture){                               
176                       
177                                event.stop(e);
178                               
179                                if(p.itemBeginDispatched){
180                                       
181                                        var times = [];
182                                        var d = p.editKind == "resizeEnd" ? p.editedItem.endTime : p.editedItem.startTime;
183                                       
184                                        switch(p.editKind){
185                                                case "move":
186                                                  var touchIndex = p.moveTouchIndex == null || p.moveTouchIndex < 0 ? 0 : p.moveTouchIndex;
187                                                        times[0] = this.getTime(e, -1, -1, touchIndex);                                                 
188                                                        break;
189                                                case "resizeStart":
190                                                        times[0] = this.getTime(e, -1, -1, p.resizeStartTouchIndex);                                                   
191                                                        break;
192                                                case "resizeEnd":
193                                                        times[0] = this.getTime(e, -1, -1, p.resizeEndTouchIndex);                                                     
194                                                        break;
195                                                case "resizeBoth":
196                                                        times[0] = this.getTime(e, -1, -1, p.resizeStartTouchIndex);
197                                                        times[1] = this.getTime(e, -1, -1, p.resizeEndTouchIndex);
198                                                        break;                                                 
199                                        }
200                                                                                                               
201                                        this._moveOrResizeItemGesture(times, "touch", e);
202                                       
203                                        if(p.editKind == "move"){
204                                                if(this.renderData.dateModule.compare(p.editedItem.startTime, d) == -1){
205                                                        this.ensureVisibility(p.editedItem.startTime, p.editedItem.endTime, "start", this.autoScrollTouchMargin);                                                       
206                                                }else{
207                                                        this.ensureVisibility(p.editedItem.startTime, p.editedItem.endTime, "end", this.autoScrollTouchMargin);
208                                                }
209                                        }else if(e.editKind == "resizeStart" || e.editKind == "resizeBoth"){
210                                                this.ensureVisibility(p.editedItem.startTime, p.editedItem.endTime, "start", this.autoScrollTouchMargin);       
211                                        }else{
212                                                this.ensureVisibility(p.editedItem.startTime, p.editedItem.endTime, "end", this.autoScrollTouchMargin);
213                                        }
214                                                                                                                                               
215                                }                       
216                        } // else scroll, if any, is delegated to sub class                                                     
217                                               
218                },
219               
220                // autoScrollTouchMargin: Integer
221                //              The minimum number of minutes of margin around the edited event.
222                autoScrollTouchMargin: 10,
223               
224                _docEditingTouchEndHandler: function(e){
225                        // tags:
226                        //              private
227                        event.stop(e);
228                       
229                        var p = this._edProps;
230                       
231                        if(p.startEditingTimer){
232                                clearTimeout(p.startEditingTimer);
233                                p.startEditingTimer = null;
234                        }
235                                                               
236                        if(this._isEditing){
237                               
238                                lang.mixin(p, this._getTouchesOnRenderers(e, p.editedItem));
239                               
240                                if(this._editingGesture){
241                               
242                                        if(p.touchesLen == 0){
243                                               
244                                                // all touches were removed => end of editing gesture
245                                                this._endItemEditingGesture("touch", e);
246                                               
247                                                if(this.touchEndEditingTimer > 0){
248                                               
249                                                        // Timer that trigger the end of the item editing mode.
250                                                        p.endEditingTimer = setTimeout(lang.hitch(this, function(){                                                                                                                     
251                                                                                                                                       
252                                                                this._endItemEditing("touch", false);                                                                                                                   
253                                                               
254                                                        }), this.touchEndEditingTimer);
255                                                } // else validation must be explicit
256                                               
257                                        }else{
258                                                                                               
259                                                if(this._editingGesture){
260                                                        this._endItemEditingGesture("touch", e);
261                                                }
262                                                // there touches of interest on item, process them.
263                                                this._startTouchItemEditingGesture(e);                                         
264                                        }
265                                }
266                               
267                        }else if(!p.touchMoved){
268                                                                                               
269                                event.stop(e);
270                                       
271                                arr.forEach(p.handles, function(handle){
272                                        handle.remove();
273                                });
274                                                               
275                                if(this._touchSelectionTimer){                                 
276                                        // selection timer was not reached to a proper selection.
277                                        clearTimeout(this._touchSelectionTimer);
278                                        this.selectFromEvent(e, p.item._item, p.renderer, true);
279                                       
280                                }else if(this._pendingSelectedItem){
281                                        // selection timer was reached, dispatch change event
282                                        this.dispatchChange(this._saveSelectedItems.length == 0 ? null : this._saveSelectedItems[0],
283                                                this._pendingSelectedItem, null, e); // todo renderer ?
284                                        delete this._saveSelectedItems;
285                                        delete this._pendingSelectedItem;                                       
286                                }
287                                                               
288                                if(this._pendingDoubleTap && this._pendingDoubleTap.item == p.item){                                                   
289                                        this._onItemDoubleClick({
290                                                triggerEvent: e,
291                                                renderer: p.renderer,
292                                                item: p.item._item
293                                        });
294                                       
295                                        clearTimeout(this._pendingDoubleTap.timer);
296                                       
297                                        delete this._pendingDoubleTap;                                 
298                                       
299                                }else{
300                                       
301                                        this._pendingDoubleTap = {
302                                                item: p.item,
303                                                timer: setTimeout(lang.hitch(this, function(){
304                                                                delete this._pendingDoubleTap;                                                         
305                                                        }), this.doubleTapDelay)
306                                        };
307                                                                                                                                                                               
308                                        this._onItemClick({
309                                                triggerEvent: e,
310                                                renderer: p.renderer,
311                                                item: p.item._item
312                                        });
313                                }
314                                                               
315                                this._edProps = null;
316                                                       
317                        }else{
318                                // scroll view has finished.                                                                   
319                               
320                                if(this._saveSelectedItems){                                                                   
321                                                                                       
322                                        // selection without dipatching was done, but the view scrolled,
323                                        // so revert last selection
324                                  this.set("selectedItems", this._saveSelectedItems);                                   
325                                        delete this._saveSelectedItems;
326                                        delete this._pendingSelectedItem;
327                                }                                                               
328                                                       
329                                arr.forEach(p.handles, function(handle){
330                                        handle.remove();
331                                });
332                                                       
333                                this._edProps = null;                           
334                        }
335                },
336               
337                _startTouchItemEditingGesture: function(e){
338                        // summary:
339                        //              Determines if a editing gesture is starting according to touches. 
340                        // tags:
341                        //              private
342
343                        var p = this._edProps;
344
345                        var fromResizeStart = p.resizeStartTouchIndex != -1;
346                        var fromResizeEnd = p.resizeEndTouchIndex != -1;
347
348                        if(fromResizeStart && fromResizeEnd || // initial gesture using two touches
349                                        this._editingGesture && p.touchesLen == 2 &&
350                                        (fromResizeEnd && p.editKind == "resizeStart" ||
351                                         fromResizeStart && p.editKind =="resizeEnd")){ // gesture one after the other touch
352
353                                if(this._editingGesture && p.editKind != "resizeBoth"){ // stop ongoing gesture
354                                        this._endItemEditingGesture("touch", e);
355                                }
356
357                                p.editKind = "resizeBoth";
358
359                                this._startItemEditingGesture([this.getTime(e, -1, -1, p.resizeStartTouchIndex),
360                                        this.getTime(e, -1, -1, p.resizeEndTouchIndex)],
361                                        p.editKind, "touch", e);
362
363                        }else if(fromResizeStart && p.touchesLen == 1 && !this._editingGesture){
364
365                                this._startItemEditingGesture([this.getTime(e, -1, -1, p.resizeStartTouchIndex)],
366                                        "resizeStart", "touch", e);
367
368                        }else if(fromResizeEnd && p.touchesLen == 1 && !this._editingGesture){
369
370                                this._startItemEditingGesture([this.getTime(e, -1, -1, p.resizeEndTouchIndex)],
371                                        "resizeEnd", "touch", e);
372
373                        } else {
374                                // A move gesture is initiated even if we don't move
375                                this._startItemEditingGesture([this.getTime(e)], "move", "touch", e);
376                        }                                       
377                },
378               
379                _getTouchesOnRenderers: function(e, item){
380                        // summary:
381                        //              Returns the touch indices that are on a editing handles or body of the renderers
382                        // tags:
383                        //              private
384                        // item: Object
385                        //              The render item.
386                        // e: Event
387                        //              The touch event.
388                        // tags:
389                        //              private
390                       
391                        var irs = this._getStartEndRenderers(item);
392                                                                               
393                        var resizeStartTouchIndex = -1;                 
394                        var resizeEndTouchIndex = -1;                   
395                        var moveTouchIndex = -1;
396                        var hasResizeStart = irs[0] != null && irs[0].resizeStartHandle != null;
397                        var hasResizeEnd = irs[1] != null && irs[1].resizeEndHandle != null;
398                        var len = 0;
399                        var touched = false;                   
400                        var list = this.itemToRenderer[item.id];
401                                                                                                               
402                        for(var i=0; i<e.touches.length; i++){
403                               
404                                if(resizeStartTouchIndex == -1 && hasResizeStart){
405                                        touched = dom.isDescendant(e.touches[i].target, irs[0].resizeStartHandle);
406                                        if(touched){
407                                                resizeStartTouchIndex = i;
408                                                len++;
409                                        }
410                                }
411                               
412                                if(resizeEndTouchIndex == -1 && hasResizeEnd){
413                                        touched = dom.isDescendant(e.touches[i].target, irs[1].resizeEndHandle);
414                                        if(touched){
415                                                resizeEndTouchIndex = i;
416                                                len++;
417                                        }
418                                }
419
420                                if(resizeStartTouchIndex == -1 && resizeEndTouchIndex == -1){
421
422                                        for (var j=0; j<list.length; j++){
423                                          touched = dom.isDescendant(e.touches[i].target, list[j].container);
424                                                if(touched){
425                                                        moveTouchIndex = i;
426                                                        len++;
427                                                        break;
428                                                }
429                                        }
430                                }
431
432                                if(resizeStartTouchIndex != -1 && resizeEndTouchIndex != -1 && moveTouchIndex != -1){
433                                        // all touches of interest were found, ignore other ones.
434                                  break;       
435                                }
436                        }
437
438                        return {
439                                touchesLen: len,
440                                resizeStartTouchIndex: resizeStartTouchIndex,
441                                resizeEndTouchIndex: resizeEndTouchIndex,
442                                moveTouchIndex: moveTouchIndex
443                        };
444                }
445
446        });
447
448});
Note: See TracBrowser for help on using the repository browser.