source: Dev/trunk/src/client/dojox/layout/dnd/PlottedDnd.js @ 532

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

Added Dojo 1.9.3 release.

File size: 14.6 KB
Line 
1dojo.provide("dojox.layout.dnd.PlottedDnd");
2
3dojo.require("dojo.dnd.Source");
4dojo.require("dojo.dnd.Manager");
5dojo.require("dojox.layout.dnd.Avatar");
6
7dojo.declare("dojox.layout.dnd.PlottedDnd", [dojo.dnd.Source], {
8        // summary:
9        //              dnd source handling plotted zone to show the dropping area
10        GC_OFFSET_X: dojo.dnd.manager().OFFSET_X,
11        GC_OFFSET_Y: dojo.dnd.manager().OFFSET_Y,
12       
13        constructor: function(/*Node*/node, /*Object*/params){
14               
15                this.childBoxes                 = null;
16                this.dropIndicator              = new dojox.layout.dnd.DropIndicator("dndDropIndicator", "div");
17                this.withHandles                = params.withHandles;
18                this.handleClasses              = params.handleClasses;
19                this.opacity                    = params.opacity;
20                this.allowAutoScroll    = params.allowAutoScroll;//MODIF MYS
21                this.dom                = params.dom;
22                this.singular                   = true;
23                this.skipForm                   = true;
24                this._over                              = false;
25                this.defaultHandleClass = "GcDndHandle";
26                this.isDropped                  = false;
27                this._timer                             = null;
28                //Initialize the params to calculate offset
29                this.isOffset = (params.isOffset)?true:false;
30                this.offsetDrag = (params.offsetDrag) ? params.offsetDrag : {x:0,y:0};
31                this.hideSource = params.hideSource ? params.hideSource : true;
32                this._drop = this.dropIndicator.create();
33               
34        },
35       
36        _calculateCoords : function(/*Boolean*/height){
37                // summary:
38                //              Calculate each position of children
39                dojo.forEach(this.node.childNodes, function(child){
40                        var c = dojo.coords(child, true);
41                        child.coords = {
42                                xy: c,
43                                w: child.offsetWidth / 2,
44                                h: child.offsetHeight / 2,
45                                mw: c.w
46                        };
47                        if(height){
48                                child.coords.mh = c.h;
49                        }
50                }, this);
51        },
52       
53        _legalMouseDown: function(/*Event*/e){
54                // summary:
55                //              Checks if user clicked on "approved" items.
56                if(!this.withHandles){ return true; }
57                for(var node = (e.target); node && node != this.node; node = node.parentNode){
58                        if(dojo.hasClass(node, this.defaultHandleClass)){
59                                return true;
60                        }
61                }
62                return false;   // Boolean
63        },
64       
65        setDndItemSelectable: function(/*Node*/node, /*Boolean*/isSelectable) {
66                // summary:
67                //              set an item as selectable
68                for(var _node = node; _node && node != this.node; _node = _node.parentNode) {
69                        if (dojo.hasClass(_node,"dojoDndItem")) {
70                                dojo.setSelectable(_node, isSelectable);
71                                return;
72                        }
73                }
74        },
75       
76        getDraggedWidget: function(/*Node*/node) {
77                // summary:
78                //              Return one or more widget selected during the drag.
79                var _node = node;
80                while (_node && _node.nodeName.toLowerCase()!="body" && !dojo.hasClass(_node,"dojoDndItem")) {
81                        _node = _node.parentNode;
82                }
83                return (_node) ? dijit.byNode(_node) : null;
84        },
85       
86        isAccepted: function(/*Node*/ node) {
87                // summary:
88                //              test if this node can be accepted
89                var _dndType = (node) ? node.getAttribute("dndtype") : null;
90                return (_dndType && _dndType in this.accept);
91        },
92       
93        onDndStart:function(/*Object*/source, /*Array*/nodes, /*Object*/copy){
94                // summary:
95                //              Called to initiate the DnD operation.
96
97                this.firstIndicator = (source == this);
98                this._calculateCoords(true);
99                //this.isDropped = true;
100                var m = dojo.dnd.manager();
101                if(nodes[0].coords){
102                        this._drop.style.height = nodes[0].coords.mh + "px";
103                        dojo.style(m.avatar.node, "width", nodes[0].coords.mw + "px");
104                }else{
105                        this._drop.style.height = m.avatar.node.clientHeight+"px";
106                }
107                this.dndNodes = nodes;
108                dojox.layout.dnd.PlottedDnd.superclass.onDndStart.call(this,source, nodes, copy);
109                if(source == this && this.hideSource){
110                        dojo.forEach(nodes, function(n){
111                                dojo.style(n, "display","none");
112                        });
113                }
114                       
115        },
116
117        onDndCancel:function(){
118                // summary:
119                //              Called to cancel the DnD operation.
120                var m = dojo.dnd.manager();
121                if(m.source == this && this.hideSource){
122                        var nodes = this.getSelectedNodes();
123                        dojo.forEach(nodes, function(n){
124                                dojo.style(n, "display","");
125                        });
126                }
127                dojox.layout.dnd.PlottedDnd.superclass.onDndCancel.call(this);
128                this.deleteDashedZone();
129        },
130       
131        onDndDrop: function(source,nodes,copy,target) {
132                // summary:
133                //              Called to finish the DnD operation
134                try{
135                        if(!this.isAccepted(nodes[0])){
136                                this.onDndCancel();
137                        }else{
138                                if(source == this && this._over && this.dropObject){
139                                        this.current = this.dropObject.c;
140                                }
141                                dojox.layout.dnd.PlottedDnd.superclass.onDndDrop.call(this, source, nodes, copy, target);
142                                this._calculateCoords(true);
143                        }
144                }catch(e){
145                        console.warn(e);
146                }
147        },
148                       
149        onMouseDown: function(/*Event*/e) {
150                // summary:
151                //              Event processor for onmousedown.
152                if(this.current == null){
153                        this.selection = {};
154                }else{
155                        if(this.current == this.anchor){
156                                this.anchor = null;
157                        }
158                }
159                if(this.current !== null){
160                        var c = dojo.coords(this.current, true);
161                        this.current.coords = {
162                                xy: c,
163                                w: this.current.offsetWidth / 2,
164                                h: this.current.offsetHeight / 2,
165                                mh: c.h,
166                                mw: c.w
167                        };
168                        this._drop.style.height = this.current.coords.mh + "px";
169                       
170                        if(this.isOffset){
171                                if(this.offsetDrag.x == 0 && this.offsetDrag.y == 0){
172                                        var NoOffsetDrag = true;
173                                        var coords = dojo.coords(this._getChildByEvent(e));
174                                        this.offsetDrag.x = coords.x - e.pageX;
175                                        this.offsetDrag.y = coords.y - e.clientY;
176                                }
177                                if(this.offsetDrag.y < 16 && this.current != null){
178                                        this.offsetDrag.y = this.GC_OFFSET_Y;
179                                }
180
181                                var m = dojo.dnd.manager();
182                                m.OFFSET_X = this.offsetDrag.x;
183                                m.OFFSET_Y = this.offsetDrag.y;
184                                if (NoOffsetDrag) {
185                                        this.offsetDrag.x = 0;
186                                        this.offsetDrag.y = 0;
187                                }
188                        }
189                }
190               
191                if(dojo.dnd.isFormElement(e)){
192                        this.setDndItemSelectable(e.target,true);
193                }else{
194                        this.containerSource = true;
195                        var _draggedWidget = this.getDraggedWidget(e.target);
196                        if(_draggedWidget && _draggedWidget.dragRestriction){
197                        // FIXME: not clear what this was supposed to mean ... this code needs more cleanups.
198                        //      dragRestriction = true;
199                        }else{
200                                dojox.layout.dnd.PlottedDnd.superclass.onMouseDown.call(this,e);
201                        }
202                }
203        },
204
205        onMouseUp: function(/*Event*/e) {
206                // summary:
207                //              Event processor for onmouseup.
208                dojox.layout.dnd.PlottedDnd.superclass.onMouseUp.call(this,e);
209                this.containerSource = false;
210                if (!dojo.isIE && this.mouseDown){
211                        this.setDndItemSelectable(e.target,true);
212                }
213                var m = dojo.dnd.manager();
214                m.OFFSET_X = this.GC_OFFSET_X;
215                m.OFFSET_Y = this.GC_OFFSET_Y;
216        },
217       
218        onMouseMove: function(e) {
219                // summary:
220                //              Event processor for onmousemove
221                var m = dojo.dnd.manager();
222                if(this.isDragging) {
223                        var before = false;
224                        if(this.current != null || (this.current == null && !this.dropObject)){
225                                if(this.isAccepted(m.nodes[0]) || this.containerSource){
226                                        before = this.setIndicatorPosition(e);
227                                }
228                        }
229                        if(this.current != this.targetAnchor || before != this.before){
230                                this._markTargetAnchor(before);
231                                m.canDrop(!this.current || m.source != this || !(this.current.id in this.selection));
232                        }
233
234                        if(this.allowAutoScroll){
235                                this._checkAutoScroll(e);
236                        }
237                }else{
238                        if(this.mouseDown && this.isSource){
239                                var nodes = this.getSelectedNodes();
240                                if(nodes.length){
241                                        m.startDrag(this, nodes, this.copyState(dojo.isCopyKey(e)));
242                                }
243                        }
244
245                        if(this.allowAutoScroll){
246                                this._stopAutoScroll();
247                        }
248                }
249        },
250       
251        _markTargetAnchor: function(/*Boolean*/before){
252                // summary:
253                //              Assigns a class to the current target anchor based on "before" status
254                if(this.current == this.targetAnchor && this.before == before){ return; }
255                this.targetAnchor = this.current;
256                this.targetBox = null;
257                this.before = before;
258        },
259       
260        _unmarkTargetAnchor: function(){
261                // summary:
262                //              Removes a class of the current target anchor based on "before" status.
263                if(!this.targetAnchor){ return; }
264                this.targetAnchor = null;
265                this.targetBox = null;
266                this.before = true;
267        },
268       
269        setIndicatorPosition: function(/*Event*/e) {
270                // summary:
271                //              set the position of the drop indicator
272                var before = false;
273                if(this.current){
274                        if (!this.current.coords || this.allowAutoScroll) {
275                                this.current.coords = {
276                                        xy: dojo.coords(this.current, true),
277                                        w: this.current.offsetWidth / 2,
278                                        h: this.current.offsetHeight / 2
279                                };
280                        }
281                        before = this.horizontal ?
282                                (e.pageX - this.current.coords.xy.x) < this.current.coords.w :
283                                (e.pageY - this.current.coords.xy.y) < this.current.coords.h
284                        this.insertDashedZone(before);
285                }else{
286                        if(!this.dropObject /*|| dojo.isIE*/){ this.insertDashedZone(false); }
287                }
288                return before;
289        },
290       
291
292        onOverEvent:function(){
293                this._over = true;
294                dojox.layout.dnd.PlottedDnd.superclass.onOverEvent.call(this);
295                if (this.isDragging) {
296                        var m = dojo.dnd.manager();
297                        if (!this.current && !this.dropObject && this.getSelectedNodes()[0] && this.isAccepted(m.nodes[0]))
298                                this.insertDashedZone(false);
299                }
300        },
301       
302        onOutEvent: function() {
303                this._over = false;
304                this.containerSource = false;
305                dojox.layout.dnd.PlottedDnd.superclass.onOutEvent.call(this);
306                if (this.dropObject) this.deleteDashedZone();
307        },
308       
309        deleteDashedZone: function() {
310                // summary:
311                //              hide the dashed zone
312                this._drop.style.display = "none";
313                        var next = this._drop.nextSibling;
314                        while (next != null) {
315                                next.coords.xy.y -= parseInt(this._drop.style.height);
316                                next = next.nextSibling;
317                        }
318                delete this.dropObject;
319        },
320       
321        insertDashedZone: function(/*Boolean*/before) {
322                // summary:
323                //              Insert the dashed zone at the right place
324                if(this.dropObject){
325                        if( before == this.dropObject.b &&
326                                ((this.current && this.dropObject.c == this.current.id) ||
327                                (!this.current && !this.dropObject.c))
328                        ){
329                                return;
330                        }else{
331                                this.deleteDashedZone();
332                        }
333                }
334                this.dropObject = { n: this._drop, c: this.current ? this.current.id : null, b: before};
335                if(this.current){
336                        dojo.place(this._drop, this.current, before ? "before" : "after");
337                        if(!this.firstIndicator){
338                                var next = this._drop.nextSibling;
339                                while(next != null){
340                                        next.coords.xy.y += parseInt(this._drop.style.height);
341                                        next = next.nextSibling;
342                                }
343                        }else{
344                                this.firstIndicator = false;
345                        }
346                }else{
347                        this.node.appendChild(this._drop);
348                }
349                this._drop.style.display = "";
350        },
351       
352        insertNodes: function(/*Boolean*/addSelected, /*Array*/data, /*Boolean*/before, /*Node*/anchor){
353                // summary:
354                //              Inserts new data items (see Dojo Container's insertNodes method for details).
355                if(this.dropObject){
356                        dojo.style(this.dropObject.n,"display","none");
357                        dojox.layout.dnd.PlottedDnd.superclass.insertNodes.call(this,true,data,true,this.dropObject.n);
358                        this.deleteDashedZone();
359                }else{
360                         return dojox.layout.dnd.PlottedDnd.superclass.insertNodes.call(this,addSelected,data,before,anchor);
361                }
362                var _widget = dijit.byId(data[0].getAttribute("widgetId"));
363                if (_widget) {
364                        dojox.layout.dnd._setGcDndHandle(_widget, this.withHandles, this.handleClasses);
365                        if(this.hideSource)
366                                dojo.style(_widget.domNode, "display", "");
367                }
368        },
369       
370        _checkAutoScroll: function(e){
371                if(this._timer){
372                        clearTimeout(this._timer);
373                }
374                this._stopAutoScroll();
375                var node = this.dom,
376                        y = this._sumAncestorProperties(node,"offsetTop")
377                ;
378                //Down
379                if( (e.pageY - node.offsetTop +30 ) > node.clientHeight ){
380                        this.autoScrollActive = true;
381                        this._autoScrollDown(node);
382                } else if ( (node.scrollTop > 0) && (e.pageY - y) < 30){
383                        //Up
384                        this.autoScrollActive = true;
385                        this._autoScrollUp(node);
386                }
387        },
388
389        _autoScrollUp: function(node){
390                if( this.autoScrollActive && node.scrollTop > 0) {
391                        node.scrollTop -= 30;
392                        this._timer = setTimeout(dojo.hitch(this,"_autoScrollUp",node), 100);
393                }
394        },
395
396        _autoScrollDown: function(node){
397                if( this.autoScrollActive && (node.scrollTop < (node.scrollHeight-node.clientHeight))){
398                        node.scrollTop += 30;
399                        this._timer = setTimeout(dojo.hitch(this, "_autoScrollDown",node), 100);
400                }
401        },
402
403        _stopAutoScroll: function(){
404                this.autoScrollActive = false;
405        },
406
407        _sumAncestorProperties: function(node, prop){
408                // summary:
409                //              Returns the sum of the passed property on all ancestors of node.
410                node = dojo.byId(node);
411                if(!node){ return 0; }
412               
413                var retVal = 0;
414                while(node){
415                        var val = node[prop];
416                        if(val){
417                                retVal += val - 0;
418                                if(node == dojo.body()){ break; }// opera and khtml #body & #html has the same values, we only need one value
419                        }
420                        node = node.parentNode;
421                }
422                return retVal;  //      integer
423        }
424       
425});
426
427dojox.layout.dnd._setGcDndHandle = function(service,withHandles,handleClasses, first) {
428        var cls = "GcDndHandle";
429        if(!first){
430                dojo.query(".GcDndHandle", service.domNode).removeClass(cls);
431        }
432        if(!withHandles){
433                dojo.addClass(service.domNode, cls);
434        }else{
435                var _hasHandle = false;
436                for(var i = handleClasses.length - 1; i >= 0; i--){
437                        var _node = dojo.query("." + handleClasses[i], service.domNode)[0];
438                        if(_node){
439                                _hasHandle = true;
440                                if(handleClasses[i] != cls){
441                                        var _gripNode = dojo.query("." + cls, service.domNode);
442                                        if(_gripNode.length == 0){
443                                                dojo.removeClass(service.domNode, cls);
444                                        }else{
445                                                _gripNode.removeClass(cls);
446                                        }
447                                        dojo.addClass(_node, cls);
448                                }
449                        }
450                }
451                if(!_hasHandle){
452                        dojo.addClass(service.domNode, cls);
453                }
454        }
455};
456
457dojo.declare("dojox.layout.dnd.DropIndicator", null, {
458        // summary:
459        //              An empty widget to show at the user the drop zone of the widget.
460        constructor: function(/*String*/cn, /*String*/tag) {
461                this.tag = tag || "div";
462                this.style = cn || null;
463        },
464
465        isInserted : function(){
466                return (this.node.parentNode && this.node.parentNode.nodeType==1);
467        },
468
469        create : function(/*Node*//*nodeRef*/){
470                if(this.node && this.isInserted()){ return this.node; }
471                var h = "90px",
472                        el = dojo.doc.createElement(this.tag);
473                       
474                if(this.style){
475                        el.className = this.style;
476                        el.style.height = h;
477                }else{
478                        // FIXME: allow this to be done mostly in CSS?
479                        dojo.style(el, {
480                                position:"relative",
481                                border:"1px dashed #F60",
482                                margin:"2px",
483                                height: h
484                        })
485                }
486                this.node = el;
487                return el;
488        },
489       
490        destroy : function(){
491                if(!this.node || !this.isInserted()){ return; }
492                this.node.parentNode.removeChild(this.node);
493                this.node = null;
494        }
495});
496
497dojo.extend(dojo.dnd.Manager, {
498       
499        canDrop: function(flag){
500                var canDropFlag = this.target && flag;
501                if(this.canDropFlag != canDropFlag){
502                        this.canDropFlag = canDropFlag;
503                        if(this.avatar){ this.avatar.update(); }
504                }
505               
506        },
507       
508        makeAvatar: function(){
509                // summary:
510                //              Makes the avatar, it is separate to be overwritten dynamically, if needed.
511                return (this.source.declaredClass == "dojox.layout.dnd.PlottedDnd") ?
512                        new dojox.layout.dnd.Avatar(this, this.source.opacity) :
513                        new dojo.dnd.Avatar(this)
514                ;
515        }
516});
517
518if(dojo.isIE){
519        dojox.layout.dnd.handdleIE = [
520                dojo.subscribe("/dnd/start", null, function(){
521                        IEonselectstart = document.body.onselectstart;
522                        document.body.onselectstart = function(){ return false; };
523                }),
524                dojo.subscribe("/dnd/cancel", null, function(){
525                        document.body.onselectstart = IEonselectstart;
526                }),
527                dojo.subscribe("/dnd/drop", null, function(){
528                        document.body.onselectstart = IEonselectstart;
529                })
530        ];
531        dojo.addOnWindowUnload(function(){
532                dojo.forEach(dojox.layout.dnd.handdleIE, dojo.unsubscribe);
533        });
534}
Note: See TracBrowser for help on using the repository browser.