~t7-vla7-lz/psiphon/psiphon

« back to all changes in this revision

Viewing changes to trunk/testing/selenium_scripts/selenium/tests/html/dojo-0.4.0-mini/src/dnd/HtmlDragManager.js

  • Committer: Eugene Fryntov
  • Date: 2016-11-15 22:13:59 UTC
  • mfrom: (373.1.1 psiphon)
  • Revision ID: e.fryntov@psiphon.ca-20161115221359-f6s56ue1a54n4ijj
merged lp:~t7-vla7-lz/psiphon/psiphon @ 374

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
        Copyright (c) 2004-2006, The Dojo Foundation
3
 
        All Rights Reserved.
4
 
 
5
 
        Licensed under the Academic Free License version 2.1 or above OR the
6
 
        modified BSD license. For more information on Dojo licensing, see:
7
 
 
8
 
                http://dojotoolkit.org/community/licensing.shtml
9
 
*/
10
 
 
11
 
dojo.provide("dojo.dnd.HtmlDragManager");
12
 
dojo.require("dojo.dnd.DragAndDrop");
13
 
dojo.require("dojo.event.*");
14
 
dojo.require("dojo.lang.array");
15
 
dojo.require("dojo.html.common");
16
 
dojo.require("dojo.html.layout");
17
 
 
18
 
// NOTE: there will only ever be a single instance of HTMLDragManager, so it's
19
 
// safe to use prototype properties for book-keeping.
20
 
dojo.declare("dojo.dnd.HtmlDragManager", dojo.dnd.DragManager, {
21
 
        /**
22
 
         * There are several sets of actions that the DnD code cares about in the
23
 
         * HTML context:
24
 
         *      1.) mouse-down ->
25
 
         *                      (draggable selection)
26
 
         *                      (dragObject generation)
27
 
         *              mouse-move ->
28
 
         *                      (draggable movement)
29
 
         *                      (droppable detection)
30
 
         *                      (inform droppable)
31
 
         *                      (inform dragObject)
32
 
         *              mouse-up
33
 
         *                      (inform/destroy dragObject)
34
 
         *                      (inform draggable)
35
 
         *                      (inform droppable)
36
 
         *      2.) mouse-down -> mouse-down
37
 
         *                      (click-hold context menu)
38
 
         *      3.) mouse-click ->
39
 
         *                      (draggable selection)
40
 
         *              shift-mouse-click ->
41
 
         *                      (augment draggable selection)
42
 
         *              mouse-down ->
43
 
         *                      (dragObject generation)
44
 
         *              mouse-move ->
45
 
         *                      (draggable movement)
46
 
         *                      (droppable detection)
47
 
         *                      (inform droppable)
48
 
         *                      (inform dragObject)
49
 
         *              mouse-up
50
 
         *                      (inform draggable)
51
 
         *                      (inform droppable)
52
 
         *      4.) mouse-up
53
 
         *                      (clobber draggable selection)
54
 
         */
55
 
        disabled: false, // to kill all dragging!
56
 
        nestedTargets: false,
57
 
        mouseDownTimer: null, // used for click-hold operations
58
 
        dsCounter: 0,
59
 
        dsPrefix: "dojoDragSource",
60
 
 
61
 
        // dimension calculation cache for use durring drag
62
 
        dropTargetDimensions: [],
63
 
 
64
 
        currentDropTarget: null,
65
 
        // currentDropTargetPoints: null,
66
 
        previousDropTarget: null,
67
 
        _dragTriggered: false,
68
 
 
69
 
        selectedSources: [],
70
 
        dragObjects: [],
71
 
 
72
 
        // mouse position properties
73
 
        currentX: null,
74
 
        currentY: null,
75
 
        lastX: null,
76
 
        lastY: null,
77
 
        mouseDownX: null,
78
 
        mouseDownY: null,
79
 
        threshold: 7,
80
 
 
81
 
        dropAcceptable: false,
82
 
 
83
 
        cancelEvent: function(e){ e.stopPropagation(); e.preventDefault();},
84
 
 
85
 
        // method over-rides
86
 
        registerDragSource: function(ds){
87
 
                //dojo.profile.start("register DragSource");
88
 
 
89
 
                if(ds["domNode"]){
90
 
                        // FIXME: dragSource objects SHOULD have some sort of property that
91
 
                        // references their DOM node, we shouldn't just be passing nodes and
92
 
                        // expecting it to work.
93
 
                        //dojo.profile.start("register DragSource 1");
94
 
                        var dp = this.dsPrefix;
95
 
                        var dpIdx = dp+"Idx_"+(this.dsCounter++);
96
 
                        ds.dragSourceId = dpIdx;
97
 
                        this.dragSources[dpIdx] = ds;
98
 
                        ds.domNode.setAttribute(dp, dpIdx);
99
 
                        //dojo.profile.end("register DragSource 1");
100
 
 
101
 
                        //dojo.profile.start("register DragSource 2");
102
 
 
103
 
                        // so we can drag links
104
 
                        if(dojo.render.html.ie){
105
 
                                //dojo.profile.start("register DragSource IE");
106
 
                                
107
 
                                dojo.event.browser.addListener(ds.domNode, "ondragstart", this.cancelEvent);
108
 
                                // terribly slow
109
 
                                //dojo.event.connect(ds.domNode, "ondragstart", this.cancelEvent);
110
 
                                //dojo.profile.end("register DragSource IE");
111
 
 
112
 
                        }
113
 
                        //dojo.profile.end("register DragSource 2");
114
 
 
115
 
                }
116
 
                //dojo.profile.end("register DragSource");
117
 
        },
118
 
 
119
 
        unregisterDragSource: function(ds){
120
 
                if (ds["domNode"]){
121
 
                        var dp = this.dsPrefix;
122
 
                        var dpIdx = ds.dragSourceId;
123
 
                        delete ds.dragSourceId;
124
 
                        delete this.dragSources[dpIdx];
125
 
                        ds.domNode.setAttribute(dp, null);
126
 
                        if(dojo.render.html.ie){
127
 
                                dojo.event.browser.removeListener(ds.domNode, "ondragstart", this.cancelEvent);                 
128
 
                        }
129
 
                }
130
 
        },
131
 
 
132
 
        registerDropTarget: function(dt){
133
 
                this.dropTargets.push(dt);
134
 
        },
135
 
 
136
 
        unregisterDropTarget: function(dt){
137
 
                var index = dojo.lang.find(this.dropTargets, dt, true);
138
 
                if (index>=0) {
139
 
                        this.dropTargets.splice(index, 1);
140
 
                }
141
 
        },
142
 
 
143
 
        /**
144
 
        * Get the DOM element that is meant to drag.
145
 
        * Loop through the parent nodes of the event target until
146
 
        * the element is found that was created as a DragSource and 
147
 
        * return it.
148
 
        *
149
 
        * @param event object The event for which to get the drag source.
150
 
        */
151
 
        getDragSource: function(e){
152
 
                var tn = e.target;
153
 
                if(tn === dojo.body()){ return; }
154
 
                var ta = dojo.html.getAttribute(tn, this.dsPrefix);
155
 
                while((!ta)&&(tn)){
156
 
                        tn = tn.parentNode;
157
 
                        if((!tn)||(tn === dojo.body())){ return; }
158
 
                        ta = dojo.html.getAttribute(tn, this.dsPrefix);
159
 
                }
160
 
                return this.dragSources[ta];
161
 
        },
162
 
 
163
 
        onKeyDown: function(e){
164
 
        },
165
 
 
166
 
        onMouseDown: function(e){
167
 
                if(this.disabled) { return; }
168
 
 
169
 
                // only begin on left click
170
 
                if(dojo.render.html.ie) {
171
 
                        if(e.button != 1) { return; }
172
 
                } else if(e.which != 1) {
173
 
                        return;
174
 
                }
175
 
 
176
 
                var target = e.target.nodeType == dojo.html.TEXT_NODE ?
177
 
                        e.target.parentNode : e.target;
178
 
 
179
 
                // do not start drag involvement if the user is interacting with
180
 
                // a form element.
181
 
                if(dojo.html.isTag(target, "button", "textarea", "input", "select", "option")) {
182
 
                        return;
183
 
                }
184
 
 
185
 
                // find a selection object, if one is a parent of the source node
186
 
                var ds = this.getDragSource(e);
187
 
                
188
 
                // this line is important.  if we aren't selecting anything then
189
 
                // we need to return now, so preventDefault() isn't called, and thus
190
 
                // the event is propogated to other handling code
191
 
                if(!ds){ return; }
192
 
 
193
 
                if(!dojo.lang.inArray(this.selectedSources, ds)){
194
 
                        this.selectedSources.push(ds);
195
 
                        ds.onSelected();
196
 
                }
197
 
 
198
 
                this.mouseDownX = e.pageX;
199
 
                this.mouseDownY = e.pageY;
200
 
 
201
 
                // Must stop the mouse down from being propogated, or otherwise can't
202
 
                // drag links in firefox.
203
 
                // WARNING: preventing the default action on all mousedown events
204
 
                // prevents user interaction with the contents.
205
 
                e.preventDefault();
206
 
 
207
 
                dojo.event.connect(document, "onmousemove", this, "onMouseMove");
208
 
        },
209
 
 
210
 
        onMouseUp: function(e, cancel){
211
 
                // if we aren't dragging then ignore the mouse-up
212
 
                // (in particular, don't call preventDefault(), because other
213
 
                // code may need to process this event)
214
 
                if(this.selectedSources.length==0){
215
 
                        return;
216
 
                }
217
 
 
218
 
                this.mouseDownX = null;
219
 
                this.mouseDownY = null;
220
 
                this._dragTriggered = false;
221
 
                // e.preventDefault();
222
 
                e.dragSource = this.dragSource;
223
 
                // let ctrl be used for multiselect or another action
224
 
                // if I use same key to trigger treeV3 node selection and here,
225
 
                // I have bugs with drag'n'drop. why ?? no idea..
226
 
                if((!e.shiftKey)&&(!e.ctrlKey)){ 
227
 
                //if(!e.shiftKey){
228
 
                        if(this.currentDropTarget) {
229
 
                                this.currentDropTarget.onDropStart();
230
 
                        }
231
 
                        dojo.lang.forEach(this.dragObjects, function(tempDragObj){
232
 
                                var ret = null;
233
 
                                if(!tempDragObj){ return; }
234
 
                                if(this.currentDropTarget) {
235
 
                                        e.dragObject = tempDragObj;
236
 
 
237
 
                                        // NOTE: we can't get anything but the current drop target
238
 
                                        // here since the drag shadow blocks mouse-over events.
239
 
                                        // This is probelematic for dropping "in" something
240
 
                                        var ce = this.currentDropTarget.domNode.childNodes;
241
 
                                        if(ce.length > 0){
242
 
                                                e.dropTarget = ce[0];
243
 
                                                while(e.dropTarget == tempDragObj.domNode){
244
 
                                                        e.dropTarget = e.dropTarget.nextSibling;
245
 
                                                }
246
 
                                        }else{
247
 
                                                e.dropTarget = this.currentDropTarget.domNode;
248
 
                                        }
249
 
                                        if(this.dropAcceptable){
250
 
                                                ret = this.currentDropTarget.onDrop(e);
251
 
                                        }else{
252
 
                                                 this.currentDropTarget.onDragOut(e);
253
 
                                        }
254
 
                                }
255
 
 
256
 
                                e.dragStatus = this.dropAcceptable && ret ? "dropSuccess" : "dropFailure";
257
 
                                // decouple the calls for onDragEnd, so they don't block the execution here
258
 
                                // ie. if the onDragEnd would call an alert, the execution here is blocked until the
259
 
                                // user has confirmed the alert box and then the rest of the dnd code is executed
260
 
                                // while the mouse doesnt "hold" the dragged object anymore ... and so on
261
 
                                dojo.lang.delayThese([
262
 
                                        function() {
263
 
                                                // in FF1.5 this throws an exception, see 
264
 
                                                // http://dojotoolkit.org/pipermail/dojo-interest/2006-April/006751.html
265
 
                                                try{
266
 
                                                        tempDragObj.dragSource.onDragEnd(e)
267
 
                                                } catch(err) {
268
 
                                                        // since the problem seems passing e, we just copy all 
269
 
                                                        // properties and try the copy ...
270
 
                                                        var ecopy = {};
271
 
                                                        for (var i in e) {
272
 
                                                                if (i=="type") { // the type property contains the exception, no idea why...
273
 
                                                                        ecopy.type = "mouseup";
274
 
                                                                        continue;
275
 
                                                                }
276
 
                                                                ecopy[i] = e[i];
277
 
                                                        }
278
 
                                                        tempDragObj.dragSource.onDragEnd(ecopy);
279
 
                                                }
280
 
                                        }
281
 
                                        , function() {tempDragObj.onDragEnd(e)}]);
282
 
                        }, this);
283
 
 
284
 
                        this.selectedSources = [];
285
 
                        this.dragObjects = [];
286
 
                        this.dragSource = null;
287
 
                        if(this.currentDropTarget) {
288
 
                                this.currentDropTarget.onDropEnd();
289
 
                        }
290
 
                } else {
291
 
                        //dojo.debug("special click");
292
 
                }
293
 
 
294
 
                dojo.event.disconnect(document, "onmousemove", this, "onMouseMove");
295
 
                this.currentDropTarget = null;
296
 
        },
297
 
 
298
 
        onScroll: function(){
299
 
                //dojo.profile.start("DNDManager updateoffset");
300
 
                for(var i = 0; i < this.dragObjects.length; i++) {
301
 
                        if(this.dragObjects[i].updateDragOffset) {
302
 
                                this.dragObjects[i].updateDragOffset();
303
 
                        }
304
 
                }
305
 
                //dojo.profile.end("DNDManager updateoffset");
306
 
 
307
 
                // TODO: do not recalculate, only adjust coordinates
308
 
                if (this.dragObjects.length) {
309
 
                        this.cacheTargetLocations();
310
 
                }
311
 
        },
312
 
 
313
 
        _dragStartDistance: function(x, y){
314
 
                if((!this.mouseDownX)||(!this.mouseDownX)){
315
 
                        return;
316
 
                }
317
 
                var dx = Math.abs(x-this.mouseDownX);
318
 
                var dx2 = dx*dx;
319
 
                var dy = Math.abs(y-this.mouseDownY);
320
 
                var dy2 = dy*dy;
321
 
                return parseInt(Math.sqrt(dx2+dy2), 10);
322
 
        },
323
 
 
324
 
        cacheTargetLocations: function(){
325
 
                dojo.profile.start("cacheTargetLocations");
326
 
 
327
 
                this.dropTargetDimensions = [];
328
 
                dojo.lang.forEach(this.dropTargets, function(tempTarget){
329
 
                        var tn = tempTarget.domNode;
330
 
                        //only cache dropTarget which can accept current dragSource
331
 
                        if(!tn || dojo.lang.find(tempTarget.acceptedTypes, this.dragSource.type) < 0){ return; }
332
 
                        var abs = dojo.html.getAbsolutePosition(tn, true);
333
 
                        var bb = dojo.html.getBorderBox(tn);
334
 
                        this.dropTargetDimensions.push([
335
 
                                [abs.x, abs.y], // upper-left
336
 
                                // lower-right
337
 
                                [ abs.x+bb.width, abs.y+bb.height ],
338
 
                                tempTarget
339
 
                        ]);
340
 
                        //dojo.debug("Cached for "+tempTarget)
341
 
                }, this);
342
 
 
343
 
                dojo.profile.end("cacheTargetLocations");
344
 
 
345
 
                //dojo.debug("Cache locations")
346
 
        },
347
 
 
348
 
        onMouseMove: function(e){
349
 
                if((dojo.render.html.ie)&&(e.button != 1)){
350
 
                        // Oooops - mouse up occurred - e.g. when mouse was not over the
351
 
                        // window. I don't think we can detect this for FF - but at least
352
 
                        // we can be nice in IE.
353
 
                        this.currentDropTarget = null;
354
 
                        this.onMouseUp(e, true);
355
 
                        return;
356
 
                }
357
 
 
358
 
                // if we've got some sources, but no drag objects, we need to send
359
 
                // onDragStart to all the right parties and get things lined up for
360
 
                // drop target detection
361
 
 
362
 
                if(     (this.selectedSources.length)&&
363
 
                        (!this.dragObjects.length) ){
364
 
                        var dx;
365
 
                        var dy;
366
 
                        if(!this._dragTriggered){
367
 
                                this._dragTriggered = (this._dragStartDistance(e.pageX, e.pageY) > this.threshold);
368
 
                                if(!this._dragTriggered){ return; }
369
 
                                dx = e.pageX - this.mouseDownX;
370
 
                                dy = e.pageY - this.mouseDownY;
371
 
                        }
372
 
 
373
 
                        // the first element is always our dragSource, if there are multiple
374
 
                        // selectedSources (elements that move along) then the first one is the master
375
 
                        // and for it the events will be fired etc.
376
 
                        this.dragSource = this.selectedSources[0];
377
 
                        
378
 
                        dojo.lang.forEach(this.selectedSources, function(tempSource){
379
 
                                if(!tempSource){ return; }
380
 
                                var tdo = tempSource.onDragStart(e);
381
 
                                if(tdo){
382
 
                                        tdo.onDragStart(e);
383
 
 
384
 
                                        // "bump" the drag object to account for the drag threshold
385
 
                                        tdo.dragOffset.y += dy;
386
 
                                        tdo.dragOffset.x += dx;
387
 
                                        tdo.dragSource = tempSource;
388
 
 
389
 
                                        this.dragObjects.push(tdo);
390
 
                                }
391
 
                        }, this);
392
 
 
393
 
                        /* clean previous drop target in dragStart */
394
 
                        this.previousDropTarget = null;
395
 
 
396
 
                        this.cacheTargetLocations();
397
 
                }
398
 
 
399
 
                // FIXME: we need to add dragSources and dragObjects to e
400
 
                dojo.lang.forEach(this.dragObjects, function(dragObj){
401
 
                        if(dragObj){ dragObj.onDragMove(e); }
402
 
                });
403
 
 
404
 
                // if we have a current drop target, check to see if we're outside of
405
 
                // it. If so, do all the actions that need doing.
406
 
                if(this.currentDropTarget){
407
 
                        //dojo.debug(dojo.html.hasParent(this.currentDropTarget.domNode))
408
 
                        var c = dojo.html.toCoordinateObject(this.currentDropTarget.domNode, true);
409
 
                        //              var dtp = this.currentDropTargetPoints;
410
 
                        var dtp = [
411
 
                                [c.x,c.y], [c.x+c.width, c.y+c.height]
412
 
                        ];
413
 
                }
414
 
 
415
 
                if((!this.nestedTargets)&&(dtp)&&(this.isInsideBox(e, dtp))){
416
 
                        if(this.dropAcceptable){
417
 
                                this.currentDropTarget.onDragMove(e, this.dragObjects);
418
 
                        }
419
 
                }else{
420
 
                        // FIXME: need to fix the event object!
421
 
                        // see if we can find a better drop target
422
 
                        var bestBox = this.findBestTarget(e);
423
 
 
424
 
                        if(bestBox.target === null){
425
 
                                if(this.currentDropTarget){
426
 
                                        this.currentDropTarget.onDragOut(e);
427
 
                                        this.previousDropTarget = this.currentDropTarget;
428
 
                                        this.currentDropTarget = null;
429
 
                                        // this.currentDropTargetPoints = null;
430
 
                                }
431
 
                                this.dropAcceptable = false;
432
 
                                return;
433
 
                        }
434
 
 
435
 
                        if(this.currentDropTarget !== bestBox.target){
436
 
                                if(this.currentDropTarget){
437
 
                                        this.previousDropTarget = this.currentDropTarget;
438
 
                                        this.currentDropTarget.onDragOut(e);
439
 
                                }
440
 
                                this.currentDropTarget = bestBox.target;
441
 
                                // this.currentDropTargetPoints = bestBox.points;
442
 
                                e.dragObjects = this.dragObjects;
443
 
                                this.dropAcceptable = this.currentDropTarget.onDragOver(e);
444
 
 
445
 
                        }else{
446
 
                                if(this.dropAcceptable){
447
 
                                        this.currentDropTarget.onDragMove(e, this.dragObjects);
448
 
                                }
449
 
                        }
450
 
                }
451
 
        },
452
 
 
453
 
        findBestTarget: function(e) {
454
 
                var _this = this;
455
 
                var bestBox = new Object();
456
 
                bestBox.target = null;
457
 
                bestBox.points = null;
458
 
                dojo.lang.every(this.dropTargetDimensions, function(tmpDA) {
459
 
                        if(!_this.isInsideBox(e, tmpDA)){
460
 
                                return true;
461
 
                        }
462
 
 
463
 
                        bestBox.target = tmpDA[2];
464
 
                        bestBox.points = tmpDA;
465
 
                        // continue iterating only if _this.nestedTargets == true
466
 
                        return Boolean(_this.nestedTargets);
467
 
                });
468
 
 
469
 
                return bestBox;
470
 
        },
471
 
 
472
 
        isInsideBox: function(e, coords){
473
 
                if(     (e.pageX > coords[0][0])&&
474
 
                        (e.pageX < coords[1][0])&&
475
 
                        (e.pageY > coords[0][1])&&
476
 
                        (e.pageY < coords[1][1]) ){
477
 
                        return true;
478
 
                }
479
 
                return false;
480
 
        },
481
 
 
482
 
        onMouseOver: function(e){
483
 
        },
484
 
 
485
 
        onMouseOut: function(e){
486
 
        }
487
 
});
488
 
 
489
 
dojo.dnd.dragManager = new dojo.dnd.HtmlDragManager();
490
 
 
491
 
// global namespace protection closure
492
 
(function(){
493
 
        var d = document;
494
 
        var dm = dojo.dnd.dragManager;
495
 
        //TODO: when focus manager is ready, dragManager should be rewritten to use it
496
 
        // set up event handlers on the document (or no?)
497
 
        dojo.event.connect(d, "onkeydown", dm, "onKeyDown");
498
 
        dojo.event.connect(d, "onmouseover", dm, "onMouseOver");
499
 
        dojo.event.connect(d, "onmouseout", dm, "onMouseOut");
500
 
        dojo.event.connect(d, "onmousedown", dm, "onMouseDown");
501
 
        dojo.event.connect(d, "onmouseup", dm, "onMouseUp");
502
 
        // TODO: process scrolling of elements, not only window (focus manager would 
503
 
        // probably come to rescue here as well)
504
 
        dojo.event.connect(window, "onscroll", dm, "onScroll");
505
 
})();