Ticket #6445: dndBetween.patch
| File dndBetween.patch, 9.7 kB (added by cwalters, 4 months ago) |
|---|
-
tests/tree/test_Tree_DnD.html
168 168 <tr> 169 169 <td> 170 170 <h2>Collection Count Summary</h2> 171 <p>You can't drop items onto this tree.</p> 171 <p> 172 You can't drop items onto this tree, but you can reorder categories. The between threshold 173 is set to 5, so if you are near the top or bottom of a node the drop will be above or below it. 174 </p> 172 175 <div dojoType="dijit.tree.TreeStoreModel" jsId="catModel" 173 176 store="catStore" query="{id: '0'}"></div> 174 177 <div class="container" dojoType="dijit.Tree" id="collectionsTree" model="catModel" 175 getLabel="catTreeCustomLabel" dndController="dijit._tree.dndSource" 178 getLabel="catTreeCustomLabel" dndController="dijit._tree.dndSource" betweenThreshold="5" 176 179 checkAcceptance="dndAccept" getIconClass="getIcon"></div> 177 180 </td> 178 181 <td> -
_tree/dndSource.js
12 12 skipForm: false, 13 13 dragThreshold: 0, 14 14 accept: ["text"], 15 betweenThreshold: 0, 15 16 16 17 constructor: function(tree, params){ 17 18 // summary: a constructor of the Source … … 22 23 // horizontal: Boolean: a horizontal container, if true, vertical otherwise or when omitted 23 24 // copyOnly: Boolean: always copy items, if true, use a state of Ctrl key otherwise 24 25 // skipForm: Boolean: don't start the drag operation, if clicked on form elements 26 // betweenThreshold: Integer: distance from upper/lower edge of node to allow drop to reorder nodes 25 27 // the rest of parameters are passed to the selector 26 28 if(!params){ params = {}; } 27 29 dojo.mixin(this, params); … … 40 42 this.mouseDown = false; 41 43 this.targetAnchor = null; 42 44 this.targetBox = null; 43 this. before = true;45 this.dropPosition = "Over"; 44 46 this._lastX = 0; 45 47 this._lastY = 0; 46 48 … … 102 104 this.inherited("onMouseMove", arguments); 103 105 var m = dojo.dnd.manager(); 104 106 if(this.isDragging){ 105 // calculate before/after 106 107 if (this.allowBetween){ // not implemented yet for tree since it has no concept of order 108 var before = false; 107 if(this.betweenThreshold > 0){ 108 // calculate before/after/over 109 var dropPosition = "Over"; 109 110 if(this.current){ 110 111 if(!this.targetBox || this.targetAnchor != this.current){ 111 112 this.targetBox = { … … 115 116 }; 116 117 } 117 118 if(this.horizontal){ 118 before = (e.pageX - this.targetBox.xy.x) < (this.targetBox.w / 2); 119 if((e.pageX - this.targetBox.xy.x) <= this.betweenThreshold){ 120 dropPosition = "Before"; 121 }else if((e.pageX - this.targetBox.xy.x) >= (this.targetBox.w - this.betweenThreshold)){ 122 dropPosition = "After"; 123 } 119 124 }else{ 120 before = (e.pageY - this.targetBox.xy.y) < (this.targetBox.h / 2); 125 if((e.pageY - this.targetBox.xy.y) <= this.betweenThreshold){ 126 dropPosition = "Before"; 127 }else if((e.pageY - this.targetBox.xy.y) >= (this.targetBox.h - this.betweenThreshold)){ 128 dropPosition = "After"; 129 } 121 130 } 122 131 } 123 if(this.current != this.targetAnchor || before != this.before){ 124 this._markTargetAnchor(before); 125 m.canDrop(!this.current || m.source != this || !(this.current.id in this.selection)); 132 if(this.current != this.targetAnchor || dropPosition != this.dropPosition){ 133 this._markTargetAnchor(dropPosition); 134 var n = this._getChildByEvent(e); // the TreeNode 135 if(n && this.checkItemAcceptance(n,m.source)){ 136 m.canDrop(!this.current || m.source != this || !(this.current.id in this.selection)); 137 } 126 138 } 127 139 } 128 140 }else{ … … 264 276 this.isDragging = false; 265 277 266 278 // Compute the new parent item 267 var targetWidget = dijit.getEnclosingWidget(target), 279 var targetWidget = dijit.getEnclosingWidget(target); 280 var newParentItem; 281 var insertIndex; 282 newParentItem = (targetWidget && targetWidget.item) || tree.item; 283 if(this.dropPosition == "Before" || this.dropPosition == "After"){ 284 newParentItem = (targetWidget.getParent() && targetWidget.getParent().item) || tree.item; 285 // Compute the insert index for reordering 286 insertIndex = targetWidget.getIndexInParent(); 287 if(this.dropPosition == "After"){ 288 insertIndex = targetWidget.getIndexInParent() + 1; 289 } 290 }else{ 268 291 newParentItem = (targetWidget && targetWidget.item) || tree.item; 292 } 269 293 270 294 // If we are dragging from another source (or at least, another source 271 295 // that points to a different data store), then we need to make new data … … 286 310 childItem = childTreeNode.item, 287 311 oldParentItem = childTreeNode.getParent().item; 288 312 289 model.pasteItem(childItem, oldParentItem, newParentItem, copy); 313 if(typeof insertIndex == "number"){ 314 if(newParentItem == oldParentItem && childTreeNode.getIndexInParent() < insertIndex){ 315 insertIndex -= 1; 316 } 317 } 318 model.pasteItem(childItem, oldParentItem, newParentItem, copy, insertIndex); 290 319 }else{ 291 320 model.newItem(newItemsParams[idx], newParentItem); 292 321 } … … 304 333 this._unmarkTargetAnchor(); 305 334 this.targetAnchor = null; 306 335 } 307 this. before = true;336 this.dropPosition = "Over"; 308 337 this.isDragging = false; 309 338 this.mouseDown = false; 310 339 delete this.mouseButton; … … 324 353 this.inherited("onOutEvent",arguments); 325 354 dojo.dnd.manager().outSource(this); 326 355 }, 327 _markTargetAnchor: function( before){328 // summary: assigns a class to the current target anchor based on " before" status329 // before: Boolean: insert before, if true, after otherwise330 if(this.current == this.targetAnchor && this. before == before){ return; }356 _markTargetAnchor: function(dropPosition){ 357 // summary: assigns a class to the current target anchor based on "dropPosition" status 358 // dropPosition: String: the class to assign based on the drop target action 359 if(this.current == this.targetAnchor && this.dropPosition == dropPosition){ return; } 331 360 if(this.targetAnchor){ 332 this._removeItemClass(this.targetAnchor, this. before ? "Before" : "After");361 this._removeItemClass(this.targetAnchor, this.dropPosition); 333 362 } 334 363 this.targetAnchor = this.current; 335 364 this.targetBox = null; 336 this. before = before;365 this.dropPosition = dropPosition; 337 366 if(this.targetAnchor){ 338 this._addItemClass(this.targetAnchor, this. before ? "Before" : "After");367 this._addItemClass(this.targetAnchor, this.dropPosition); 339 368 } 340 369 }, 341 370 _unmarkTargetAnchor: function(){ 342 // summary: removes a class of the current target anchor based on " before" status371 // summary: removes a class of the current target anchor based on "dropPosition" status 343 372 if(!this.targetAnchor){ return; } 344 this._removeItemClass(this.targetAnchor, this. before ? "Before" : "After");373 this._removeItemClass(this.targetAnchor, this.dropPosition); 345 374 this.targetAnchor = null; 346 375 this.targetBox = null; 347 this. before = true;376 this.dropPosition = "Over"; 348 377 }, 349 378 _markDndStatus: function(copy){ 350 379 // summary: changes source's state based on "copy" status -
Tree.js
331 331 dndController: null, 332 332 333 333 //parameters to pull off of the tree and pass on to the dndController as its params 334 dndParams: ["onDndDrop","itemCreator","onDndCancel","checkAcceptance", "checkItemAcceptance", "dragThreshold" ],334 dndParams: ["onDndDrop","itemCreator","onDndCancel","checkAcceptance", "checkItemAcceptance", "dragThreshold", "betweenThreshold"], 335 335 336 336 //declare the above items so they can be pulled from the tree's markup 337 337 onDndDrop:null, … … 340 340 checkAcceptance:null, 341 341 checkItemAcceptance:null, 342 342 dragThreshold:0, 343 betweenThreshold:0, 343 344 344 345 _publish: function(/*String*/ topicName, /*Object*/ message){ 345 346 // summary: … … 1090 1091 return this.store.newItem(args, pInfo); 1091 1092 }, 1092 1093 1093 pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy ){1094 pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy, /*int?*/ insertIndex){ 1094 1095 // summary: 1095 1096 // Move or copy an item from one parent item to another. 1096 1097 // Used in drag & drop … … 1114 1115 1115 1116 // modify target item's children attribute to include this item 1116 1117 if(newParentItem){ 1117 store.setValues(newParentItem, parentAttr, 1118 store.getValues(newParentItem, parentAttr).concat(childItem)); 1118 if(typeof insertIndex == "number"){ 1119 var childItems = store.getValues(newParentItem, parentAttr); 1120 childItems.splice(insertIndex, 0, childItem); 1121 store.setValues(newParentItem, parentAttr, childItems); 1122 }else{ 1123 store.setValues(newParentItem, parentAttr, 1124 store.getValues(newParentItem, parentAttr).concat(childItem)); 1125 } 1119 1126 } 1120 1127 }, 1121 1128 … … 1290 1297 // added to the root of the tree, for example to add a flag like root=true 1291 1298 }, 1292 1299 1293 pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy ){1300 pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy, /*int?*/ insertIndex){ 1294 1301 // summary: 1295 1302 // Move or copy an item from one parent item to another. 1296 1303 // Used in drag & drop … … 1304 1311 } 1305 1312 dijit.tree.TreeStoreModel.prototype.pasteItem.call(this, childItem, 1306 1313 oldParentItem === this.root ? null : oldParentItem, 1307 newParentItem === this.root ? null : newParentItem 1314 newParentItem === this.root ? null : newParentItem, 1315 insertIndex 1308 1316 ); 1309 1317 if(newParentItem === this.root){ 1310 1318 // It's onAddToRoot()'s responsibility to modify the item so it matches