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