Ticket #6285: low_level_draggable_droppable_like_scriptaculous.patch
| File low_level_draggable_droppable_like_scriptaculous.patch, 27.3 kB (added by harobed, 9 months ago) |
|---|
-
dojo/dnd/Mover.js
39 39 this.host.onMove(this, {l: m.l + e.pageX, t: m.t + e.pageY}); 40 40 }, 41 41 onMouseUp: function(e){ 42 this.e = e; 42 43 if(this.mouseButton == e.button){ 43 44 this.destroy(); 44 45 } -
dojo/dnd/Droppable.js
1 if(!dojo._hasResource["dojo.dnd.Droppable"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. 2 dojo._hasResource["dojo.dnd.Droppable"] = true; 3 dojo.provide("dojo.dnd.Droppable"); 4 5 dojo.declare("dojo.dnd.DroppableManager", null, { 6 _drops: [], 7 constructor: function() { 8 }, 9 add: function(/*DOMNode|string*/id, /*Object*/params) { 10 // summary: register a node (id) in droppable manager to make an 11 // element react when a Draggable is droped onto it. 12 // 13 // id: DOM id or DOM Node 14 // params: Object, a dict of parameters, recognized parameters are: 15 // hoverclass: String 16 // if set, the Droppable node will have this additional CSS 17 // class when an accepted Draggable is hovered over it. 18 // greedy: Boolean (default: true) 19 // if true stops processing hovering (donât look for other 20 // Droppables that are under the Draggable) 21 // onOver: Function 22 // called whenever a Draggable is moved over the Droppable 23 // and the Droppable is affected (would accept it). The 24 // callback gets two parameters: the Draggable, the Droppable element. 25 // onDrop: Function 26 // called whenever a Draggable is released over the Droppable 27 // and the Droppable is accepts it. The callback gets three 28 // parameters: the Draggable element, the Droppable element 29 // and the Event. You can extract additional information about 30 // the drop â like if the Ctrl or Shift keys were 31 // pressed â from the Event object. 32 if (!params) { params = {}; } 33 if (params.greedy == undefined) params.greedy = true; 34 var new_record = { 35 element: dojo.byId(id), 36 hoverclass: params.hoverclass || null, 37 greedy: params.greedy, 38 onOver: params.onOver || null, 39 onDrop: params.onDrop || null 40 } 41 42 this._drops.push(new_record); 43 }, 44 remove: function(/*DOMNode|string*/ id) { 45 // summary: remove a node (id) from droppable manager. 46 // 47 // id: DOM id or DOM Node 48 var element_to_remove = dojo.byId(id); 49 this._drops = dojo.filter(this._drops, function(item){ return item.element!=element_to_remove }); 50 }, 51 reset: function() { 52 // TODO 53 }, 54 onOver: function(/*Event*/event, /*DOMNode*/draggable_element, dont_call_callback) { 55 // summary: called whenever a Draggable element move. This method 56 // go in search of Droppable element in DroppableManager. 57 // If matched onOver event function is called on element found. 58 // 59 // event: mouse event 60 // draggable_element: DOM Node dragged 61 // dont_call_callback: if true then don't call onOver callback 62 // return dropped element found 63 var dropped = this._findTarget(event.x, event.y, draggable_element); 64 if ((dont_call_callback != true) && (dropped != null)) { 65 if (dropped.onOver != null) { 66 dropped.onOver(event, draggable_element) 67 } 68 } 69 return dropped; 70 }, 71 onDrop: function(/*Event*/event, /*DOMNode*/draggable_element, dont_call_callback) { 72 // summary: called whenever a Draggable element is dropped. This method 73 // go in search of Droppable element in DroppableManager. 74 // If matched onDrop event function is called on element found. 75 // 76 // event: mouse event 77 // draggable_element: DOM Node dragged 78 // dont_call_callback: if true then don't call onDrop callback 79 // return dropped element found 80 var dropped = this._findTarget(event.x, event.y, draggable_element); 81 if ((dont_call_callback != true) && (dropped != null)) { 82 if (dropped.onDrop != null) { 83 dropped.onDrop(event, draggable_element) 84 } 85 } 86 return dropped; 87 }, 88 _findTarget: function(/*integer*/x, /*integer*/ y, skip_element) { 89 // summary: this method look for DOM Node droppable in _drops array 90 // which is contain x, y 91 // return: droppable element or null 92 for(var i = 0;i < this._drops.length;i++) { 93 if (this._drops[i].element == skip_element) continue; 94 if (dojo.within(this._drops[i].element, x, y)) 95 return this._drops[i]; 96 } 97 return null; 98 } 99 }); 100 101 dojo.dnd._droppables = null; 102 103 dojo.dnd.droppables = function() { 104 if (!dojo.dnd._droppables) { 105 dojo.dnd._droppables = new dojo.dnd.DroppableManager(); 106 } 107 return dojo.dnd._droppables; 108 }; 109 110 } // _hasResource -
dojo/dnd/Draggable.js
1 if(!dojo._hasResource["dojo.dnd.Draggable"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. 2 dojo._hasResource["dojo.dnd.Draggable"] = true; 3 dojo.provide("dojo.dnd.Draggable"); 4 5 dojo.require("dojo.dnd.Moveable"); 6 dojo.require("dojo.dnd.Droppable"); 7 8 dojo.declare("dojo.dnd.Draggable", dojo.dnd.Moveable, { 9 constructor: function(node, params) { 10 // summary: an object, which makes a node draggable 11 // node: Node: a node (or node's id) to be draggable 12 // params: Object: an optional object with additional parameters; 13 // following parameters are recognized: 14 // handle: Node: a node (or node's id), which is used as a mouse handle 15 // if omitted, the node itself is user a a handle 16 // delay: Number: delay move by this number of pixels 17 // revert: Boolean: If set to true, the element returns to its original 18 // position when the drags ends. False by default. 19 // zindex: Number: The css zindex of the draggable item. 1000 by default. 20 // constraint: String: f set to âhorizontalâ or âverticalâ the drag will 21 // be constrained to take place only horizontally or vertically. 22 // ghosting: Boolean: Clones the element and drags the clone, 23 // leaving the original in place until the clone is dropped. 24 // onStart: Function: Called when a drag is initiated. 25 // onDrag: Function: Called repeatedly a mouse moves, if mouse position 26 // changed from previous call. 27 // onEnd: Function: Called when a drag is ended. 28 if (!params) { params = {}; } 29 this.ghosting = params.ghosting ? params.ghosting : false; 30 this.revert = params.revert ? params.revert : false; 31 }, 32 getAvatar: function() { 33 this._backup_box = dojo.marginBox(this.node); 34 if (this.ghosting) { 35 var clone = this.node.cloneNode(true); 36 clone.id = clone.id + "clone"; 37 clone.style.visibility = "hidden"; 38 clone.style.position = "absolute"; 39 this.node.parentNode.insertBefore(clone, this.node); 40 return clone; 41 } else { 42 this._backup_style_position = this.node.style.position; 43 this._backup_style_left = this.node.style.left; 44 this._backup_style_top = this.node.style.top; 45 return this.node; 46 } 47 }, 48 // mouse event processors 49 onMouseDown: function(e){ 50 // summary: event processor for onmousedown, creates a Mover for the node 51 // e: Event: mouse event 52 if(this.skip && dojo.dnd.isFormElement(e)){ return; } 53 if(this.delay){ 54 //console.log("delay"); 55 this.events.push(dojo.connect(this.handle, "onmousemove", this, "onMouseMove")); 56 this.events.push(dojo.connect(this.handle, "onmouseup", this, "onMouseUp")); 57 this._lastX = e.pageX; 58 this._lastY = e.pageY; 59 }else{ 60 //console.log("onMouseDown"); 61 //console.dir(e); 62 new this.mover(this.getAvatar(), e, this); 63 //console.log("apres"); 64 } 65 dojo.stopEvent(e); 66 }, 67 onMouseMove: function(e){ 68 // summary: event processor for onmousemove, used only for delayed drags 69 // e: Event: mouse event 70 if(Math.abs(e.pageX - this._lastX) > this.delay || Math.abs(e.pageY - this._lastY) > this.delay){ 71 this.onMouseUp(e); 72 new this.mover(this.getAvatar(), e, this); 73 dojo.dnd.droppables.onOver(e, this.node); 74 } 75 dojo.stopEvent(e); 76 }, 77 onMouseUp: function(e){ 78 // summary: event processor for onmouseup, used only for delayed delayed drags 79 // e: Event: mouse event 80 dojo.disconnect(this.events.pop()); 81 dojo.disconnect(this.events.pop()); 82 }, 83 onMoveStart: function(/* dojo.dnd.Mover */ mover){ 84 // summary: called before every move operation 85 dojo.publish("/dnd/move/start", [mover]); 86 dojo.addClass(dojo.body(), "dojoMove"); 87 dojo.addClass(mover.node, "dojoMoveItem"); 88 }, 89 onMoveStop: function(/* dojo.dnd.Mover */ mover){ 90 // summary: called after every move operation 91 //mover.node.parentNode.removeChild(mover.node); 92 //this.inherited(arguments); 93 var droppable = dojo.dnd.droppables(); 94 var dropped = droppable.onDrop({x: mover.e.pageX, y: mover.e.pageY}, this.node); 95 if (this.ghosting) { 96 if ((this.revert) && (dropped == null)) { 97 dojo.require("dojox.fx"); 98 var actual_box = dojo.marginBox(mover.node); 99 var actual_box = dojo.marginBox(mover.node); 100 var clone = mover.node; 101 dojox.fx.slideBy({ 102 node: mover.node, 103 top: this._backup_box.t - actual_box.t, 104 left: this._backup_box.l - actual_box.l, 105 duration:200, 106 onEnd: function() { clone.parentNode.removeChild(clone); } 107 }).play(); 108 } else mover.node.parentNode.removeChild(mover.node); 109 } else { 110 if ((this.revert) && (dropped == null)) { 111 dojo.require("dojox.fx"); 112 var actual_box = dojo.marginBox(mover.node); 113 dojox.fx.slideBy({ 114 node: mover.node, 115 top: this._backup_box.t - actual_box.t, 116 left: this._backup_box.l - actual_box.l, 117 duration:600, 118 onEnd: dojo.hitch(this, "_removeNodeModification", mover.node) 119 }).play(); 120 } else this._removeNodeModification(mover.node); 121 122 } 123 }, 124 _removeNodeModification: function(node) { 125 node.style.left = this._backup_style_left; 126 node.style.top = this._backup_style_top; 127 node.style.position = this._backup_style_position; 128 if (node.style.length == 0) 129 node.removeAttribute("style"); 130 131 dojo.removeClass(node, "dojoMoveItem"); 132 133 if (node.getAttribute("class") == "") 134 node.removeAttribute("class"); 135 }, 136 onFirstMove: function(/* dojo.dnd.Mover */ mover) { 137 if (mover.node.style.visibility == "hidden") 138 mover.node.style.visibility = "visible"; 139 }, 140 onMoved: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){ 141 var droppable = dojo.dnd.droppables(); 142 143 droppable.onOver({x: leftTop.l - mover.marginBox.l, y: leftTop.t - mover.marginBox.t}, mover.node); 144 } 145 }); 146 147 } -
dojo/tests/dnd/test_droppable.html
1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 2 "http://www.w3.org/TR/html4/strict.dtd"> 3 <!-- 4 we use a strict-mode DTD to ensure that the box model is the same for these 5 basic tests 6 --> 7 <html> 8 <head> 9 <title>testing Dojo DnD Droppable</title> 10 11 <script type="text/javascript" src="../../dojo.js" djConfig="isDebug: true, parseOnLoad: true"></script> 12 13 <script type="text/javascript" src="../../dnd/Draggable.js"></script> 14 <script type="text/javascript" src="../../dnd/Droppable.js"></script> 15 <script type="text/javascript"> 16 dojo.require("doh.runner"); 17 18 var element1_state = ""; 19 var element2_state = ""; 20 var element3_state = ""; 21 var element4_state = ""; 22 23 function resetTableStates() 24 { 25 dojo.byId("element1_state").innerHTML = "-"; 26 dojo.byId("element2_state").innerHTML = "-"; 27 dojo.byId("element3_state").innerHTML = "-"; 28 dojo.byId("element4_state").innerHTML = "-"; 29 } 30 31 function updatePositionElement() 32 { 33 for(i = 1 ; i < 5 ; i++) { 34 x1 = dojo.byId("element_" + i).offsetLeft; 35 y1 = dojo.byId("element_" + i).offsetTop; 36 x2 = dojo.byId("element_" + i).offsetLeft + dojo.byId("element_" + i).offsetWidth; 37 y2 = dojo.byId("element_" + i).offsetTop + dojo.byId("element_" + i).offsetHeight; 38 39 dojo.byId("element" + i + "_x1y1x2y2").innerHTML = x1 + "," + y1 + "," + x2 + "," + y2; 40 } 41 } 42 43 dojo.addOnLoad(function() { updatePositionElement() }); 44 45 dojo.declare("TestDroppableManager", dojo.dnd.DroppableManager, { 46 onOver: function(/*Event*/event, /*DOMNode*/draggable_element) { 47 updatePositionElement(); 48 dojo.byId("onover_event_x").innerHTML = event.x; 49 dojo.byId("onover_event_y").innerHTML = event.y; 50 if (draggable_element != undefined) 51 dojo.byId("onover_draggable_id").innerHTML = draggable_element.id; 52 53 return this.inherited(arguments); 54 }, 55 onDrop: function(/*Event*/event, /*DOMNode*/draggable_element) { 56 updatePositionElement(); 57 dojo.byId("ondrop_event_x").innerHTML = event.x; 58 dojo.byId("ondrop_event_y").innerHTML = event.y; 59 if (draggable_element != undefined) 60 dojo.byId("ondrop_draggable_id").innerHTML = draggable_element.id; 61 62 return this.inherited(arguments); 63 } 64 }); 65 66 dojo.dnd.droppables = function() { 67 if (!dojo.dnd._droppables) { 68 dojo.dnd._droppables = new TestDroppableManager(); 69 } 70 return dojo.dnd._droppables; 71 }; 72 73 dojo.addOnLoad(function(){ 74 doh.register("t", 75 [ 76 function testAdd(t) { 77 var droppables = dojo.dnd.droppables(); 78 // Add element 1 with no parameter 79 droppables.add("element_1"); 80 81 // Add element 2 82 droppables.add( 83 dojo.byId("element_2"), 84 { 85 hoverclass: "droppable", 86 greedy: false, 87 onOver: function(event, draggable_element) { 88 element2_state = "onOver"; 89 resetTableStates(); 90 dojo.byId("element2_state").innerHTML = "onOver"; 91 console.log("onOver element2"); 92 }, 93 onDrop: function(event, draggable_element) { 94 element2_state = "onDrop"; 95 resetTableStates(); 96 dojo.byId("element2_state").innerHTML = "onDrop"; 97 console.log("onDrop element2"); 98 } 99 } 100 ); 101 102 // Add element 3 103 droppables.add("element_3"); 104 105 // Add element 4 106 droppables.add( 107 "element_4", 108 { 109 onOver: function(event, draggable_element) { 110 element4_state = "onOver"; 111 resetTableStates(); 112 dojo.byId("element4_state").innerHTML = "onOver"; 113 console.log("onOver element4"); 114 }, 115 onDrop: function(event, draggable_element) { 116 element4_state = "onDrop"; 117 resetTableStates(); 118 dojo.byId("element4_state").innerHTML = "onDrop"; 119 console.log("onDrop element4"); 120 } 121 } 122 ); 123 124 // First droppable element added 125 t.is(dojo.byId("element_1"), droppables._drops[0].element); 126 t.is(null, droppables._drops[0].hoverclass); 127 t.is(true, droppables._drops[0].greedy); 128 t.is(null, droppables._drops[0].onOver); 129 t.is(null, droppables._drops[0].onDrop); 130 131 // Second droppable element added 132 t.is(dojo.byId("element_2"), droppables._drops[1].element); 133 t.is("droppable", droppables._drops[1].hoverclass); 134 t.is(false, droppables._drops[1].greedy); 135 t.isnot(null, droppables._drops[1].onOver); 136 t.isnot(null, droppables._drops[1].onDrop); 137 138 // ... 139 t.is(dojo.byId("element_3"), droppables._drops[2].element); 140 t.is(dojo.byId("element_4"), droppables._drops[3].element); 141 }, 142 function testRemove(t) { 143 var droppables = dojo.dnd.droppables(); 144 145 droppables.remove("element_3"); 146 t.is(dojo.byId("element_1"), droppables._drops[0].element); 147 t.is(dojo.byId("element_2"), droppables._drops[1].element); 148 t.is(dojo.byId("element_4"), droppables._drops[2].element); 149 }, 150 function testFindTarget(t) { 151 var droppables = dojo.dnd.droppables(); 152 153 t.is( 154 dojo.byId("element_1"), 155 droppables._findTarget( 156 dojo.byId("element_1").offsetLeft + 2, // x 157 dojo.byId("element_1").offsetTop + 2 // y 158 ).element 159 ); 160 161 162 t.is( 163 dojo.byId("element_2"), 164 droppables._findTarget( 165 dojo.byId("element_2").offsetLeft + 2, // x 166 dojo.byId("element_2").offsetTop + 2 // y 167 ).element 168 ); 169 170 t.is( 171 null, 172 droppables._findTarget( 173 dojo.byId("element_3").offsetLeft + 2, // x 174 dojo.byId("element_3").offsetTop + 2 // y 175 ) 176 ); 177 178 t.is( 179 dojo.byId("element_4"), 180 droppables._findTarget( 181 dojo.byId("element_4").offsetLeft + 2, // x 182 dojo.byId("element_4").offsetTop + 2 // y 183 ).element 184 ); 185 }, 186 function testOnOverAndOnDrop(t) { 187 var droppables = dojo.dnd.droppables(); 188 189 // Add element previously deleted 190 droppables.add( 191 "element_3", 192 { 193 onOver: function(event, draggable_element) { 194 element3_state = "onOver"; 195 resetTableStates(); 196 dojo.byId("element3_state").innerHTML = "onOver"; 197 console.log("onOver element3"); 198 }, 199 onDrop: function(event, draggable_element) { 200 element3_state = "onDrop"; 201 resetTableStates(); 202 dojo.byId("element3_state").innerHTML = "onDrop"; 203 console.log("onDrop element3"); 204 } 205 } 206 ); 207 208 // Test onOver element 2 209 event = { 210 x: dojo.byId("element_2").offsetLeft + 2, 211 y: dojo.byId("element_2").offsetTop + 2 212 } 213 element2_state = ""; 214 droppables.onOver(event, undefined); 215 t.is(element2_state, "onOver"); 216 217 // Test onDrop element 2 218 droppables.onDrop(event, undefined); 219 t.is(element2_state, "onDrop"); 220 221 // Test onOver element 3 222 event = { 223 x: dojo.byId("element_3").offsetLeft + 2, 224 y: dojo.byId("element_3").offsetTop + 2 225 } 226 element3_state = ""; 227 droppables.onOver(event, undefined); 228 t.is(element3_state, "onOver"); 229 230 // Test onDrop element 3 231 droppables.onDrop(event, undefined); 232 t.is(element3_state, "onDrop"); 233 234 // Test onOver element 4 235 event = { 236 x: dojo.byId("element_4").offsetLeft + 2, 237 y: dojo.byId("element_4").offsetTop + 2 238 } 239 element4_state = ""; 240 droppables.onOver(event, undefined); 241 t.is(element4_state, "onOver"); 242 243 // Test onDrop element 4 244 droppables.onDrop(event, undefined); 245 t.is(element4_state, "onDrop"); 246 } 247 ] 248 ); 249 doh.run(); 250 }); 251 252 dojo.addOnLoad(function() { 253 var drag1 = new dojo.dnd.Draggable("element_1"); 254 var drag2 = new dojo.dnd.Draggable("element_2", {ghosting: true}); 255 var drag3 = new dojo.dnd.Draggable("element_3", {revert: true}); 256 var drag4 = new dojo.dnd.Draggable("element_4", {ghosting: true, revert: true}); 257 }); 258 </script> 259 </head> 260 <body> 261 <h1>Dojo Dnd Droppable</h1> 262 263 <table border="1" cellspacing="0"> 264 <tr> 265 <th> </th> 266 <th>Element 1</th> 267 <th>Element 2</th> 268 <th>Element 3</th> 269 <th>Element 4</th> 270 </tr> 271 <tr> 272 <th>State</th> 273 <td style="text-align:center" id="element1_state">-</td> 274 <td style="text-align:center" id="element2_state">-</td> 275 <td style="text-align:center" id="element3_state">-</td> 276 <td style="text-align:center" id="element4_state">-</td> 277 </tr> 278 <tr> 279 <th>x1,y1,x2,y2</th> 280 <td style="text-align:center" id="element1_x1y1x2y2">-</td> 281 <td style="text-align:center" id="element2_x1y1x2y2">-</td> 282 <td style="text-align:center" id="element3_x1y1x2y2">-</td> 283 <td style="text-align:center" id="element4_x1y1x2y2">-</td> 284 </tr> 285 </table> 286 <br /> 287 <table border="1" cellspacing="0"> 288 <tr> 289 <th> </th> 290 <th>event.x</th> 291 <th>event.y</th> 292 <th>draggable_element.id</th> 293 </tr> 294 <tr> 295 <th>onOver</th> 296 <td style="text-align:center" id="onover_event_x">-</td> 297 <td style="text-align:center" id="onover_event_y">-</td> 298 <td style="text-align:center" id="onover_draggable_id">-</td> 299 </tr> 300 <tr> 301 <th>onDrop</th> 302 <td style="text-align:center" id="ondrop_event_x">-</td> 303 <td style="text-align:center" id="ondrop_event_y">-</td> 304 <td style="text-align:center" id="ondrop_draggable_id">-</td> 305 </tr> 306 </table> 307 308 <p id="element_1">Element 1</p> 309 <p id="element_2">Element 2</p> 310 <p id="element_3">Element 3</p> 311 <p style="height:60em">Big space</p> 312 <p id="element_4">Element 4 <span id="subelement4">other element in element4</span></p> 313 </body> 314 </html> -
dojo/tests/dnd/test_draggable.html
1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 2 "http://www.w3.org/TR/html4/strict.dtd"> 3 <!-- 4 we use a strict-mode DTD to ensure that the box model is the same for these 5 basic tests 6 --> 7 <html> 8 <head> 9 <title>testing Dojo DnD Draggable</title> 10 11 <script type="text/javascript" src="../../dojo.js" djConfig="isDebug: true, parseOnLoad: true"></script> 12 13 <script type="text/javascript" src="../../dnd/Draggable.js"></script> 14 <script type="text/javascript" src="../../dnd/Droppable.js"></script> 15 <script type="text/javascript"> 16 dojo.require("doh.runner"); 17 18 dojo.addOnLoad(function() { 19 var drag1 = new dojo.dnd.Draggable("element_1"); 20 var drag2 = new dojo.dnd.Draggable("element_2", {ghosting: true}); 21 var drag3 = new dojo.dnd.Draggable("element_3", {revert: true}); 22 var drag4 = new dojo.dnd.Draggable("element_4", {ghosting: true, revert: true}); 23 }); 24 </script> 25 </head> 26 <body> 27 <h1>testing Dojo DnD Draggable</h1> 28 29 <p id="element_1">Element 1</p> 30 <p id="element_2">Element 2</p> 31 <p id="element_3">Element 3</p> 32 <p id="element_4">Element 4</p> 33 </body> 34 </html>