Ticket #6445: dndBetween.patch

File dndBetween.patch, 9.7 kB (added by cwalters, 4 months ago)
  • tests/tree/test_Tree_DnD.html

     
    168168        <tr> 
    169169                <td> 
    170170                        <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> 
    172175                        <div dojoType="dijit.tree.TreeStoreModel" jsId="catModel" 
    173176                                store="catStore" query="{id: '0'}"></div> 
    174177                        <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" 
    176179                                checkAcceptance="dndAccept" getIconClass="getIcon"></div> 
    177180                </td> 
    178181                <td> 
  • _tree/dndSource.js

     
    1212        skipForm: false, 
    1313        dragThreshold: 0, 
    1414        accept: ["text"], 
     15        betweenThreshold: 0, 
    1516         
    1617        constructor: function(tree, params){ 
    1718                // summary: a constructor of the Source 
     
    2223                //      horizontal: Boolean: a horizontal container, if true, vertical otherwise or when omitted 
    2324                //      copyOnly: Boolean: always copy items, if true, use a state of Ctrl key otherwise 
    2425                //      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 
    2527                //      the rest of parameters are passed to the selector 
    2628                if(!params){ params = {}; } 
    2729                dojo.mixin(this, params); 
     
    4042                this.mouseDown = false; 
    4143                this.targetAnchor = null; 
    4244                this.targetBox = null; 
    43                 this.before = true; 
     45                this.dropPosition = "Over"; 
    4446                this._lastX = 0; 
    4547                this._lastY = 0; 
    4648 
     
    102104                this.inherited("onMouseMove", arguments); 
    103105                var m = dojo.dnd.manager(); 
    104106                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"; 
    109110                                if(this.current){ 
    110111                                        if(!this.targetBox || this.targetAnchor != this.current){ 
    111112                                                this.targetBox = { 
     
    115116                                                }; 
    116117                                        } 
    117118                                        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                                                } 
    119124                                        }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                                                } 
    121130                                        } 
    122131                                } 
    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                                        } 
    126138                                } 
    127139                        } 
    128140                }else{ 
     
    264276                        this.isDragging = false; 
    265277 
    266278                        // 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{ 
    268291                                newParentItem = (targetWidget && targetWidget.item) || tree.item; 
     292                        } 
    269293 
    270294                        // If we are dragging from another source (or at least, another source 
    271295                        // that points to a different data store), then we need to make new data 
     
    286310                                                childItem = childTreeNode.item, 
    287311                                                oldParentItem = childTreeNode.getParent().item; 
    288312 
    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); 
    290319                                }else{ 
    291320                                        model.newItem(newItemsParams[idx], newParentItem); 
    292321                                } 
     
    304333                        this._unmarkTargetAnchor(); 
    305334                        this.targetAnchor = null; 
    306335                } 
    307                 this.before = true; 
     336                this.dropPosition = "Over"; 
    308337                this.isDragging = false; 
    309338                this.mouseDown = false; 
    310339                delete this.mouseButton; 
     
    324353                this.inherited("onOutEvent",arguments);  
    325354                dojo.dnd.manager().outSource(this); 
    326355        }, 
    327         _markTargetAnchor: function(before){ 
    328                 // summary: assigns a class to the current target anchor based on "before" status 
    329                 // before: Boolean: insert before, if true, after otherwise 
    330                 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; } 
    331360                if(this.targetAnchor){ 
    332                         this._removeItemClass(this.targetAnchor, this.before ? "Before" : "After"); 
     361                        this._removeItemClass(this.targetAnchor, this.dropPosition); 
    333362                } 
    334363                this.targetAnchor = this.current; 
    335364                this.targetBox = null; 
    336                 this.before = before; 
     365                this.dropPosition = dropPosition; 
    337366                if(this.targetAnchor){ 
    338                         this._addItemClass(this.targetAnchor, this.before ? "Before" : "After"); 
     367                        this._addItemClass(this.targetAnchor, this.dropPosition); 
    339368                } 
    340369        }, 
    341370        _unmarkTargetAnchor: function(){ 
    342                 // summary: removes a class of the current target anchor based on "before" status 
     371                // summary: removes a class of the current target anchor based on "dropPosition" status 
    343372                if(!this.targetAnchor){ return; } 
    344                 this._removeItemClass(this.targetAnchor, this.before ? "Before" : "After"); 
     373                this._removeItemClass(this.targetAnchor, this.dropPosition); 
    345374                this.targetAnchor = null; 
    346375                this.targetBox = null; 
    347                 this.before = true; 
     376                this.dropPosition = "Over"; 
    348377        }, 
    349378        _markDndStatus: function(copy){ 
    350379                // summary: changes source's state based on "copy" status 
  • Tree.js

     
    331331        dndController: null, 
    332332 
    333333        //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"], 
    335335 
    336336        //declare the above items so they can be pulled from the tree's markup 
    337337        onDndDrop:null, 
     
    340340        checkAcceptance:null,    
    341341        checkItemAcceptance:null, 
    342342        dragThreshold:0, 
     343        betweenThreshold:0, 
    343344 
    344345        _publish: function(/*String*/ topicName, /*Object*/ message){ 
    345346                // summary: 
     
    10901091                return this.store.newItem(args, pInfo); 
    10911092        }, 
    10921093 
    1093         pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy){ 
     1094        pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy, /*int?*/ insertIndex){ 
    10941095                // summary: 
    10951096                //              Move or copy an item from one parent item to another. 
    10961097                //              Used in drag & drop 
     
    11141115 
    11151116                // modify target item's children attribute to include this item 
    11161117                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                        } 
    11191126                } 
    11201127        }, 
    11211128 
     
    12901297                //              added to the root of the tree, for example to add a flag like root=true 
    12911298        }, 
    12921299 
    1293         pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy){ 
     1300        pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy, /*int?*/ insertIndex){ 
    12941301                // summary: 
    12951302                //              Move or copy an item from one parent item to another. 
    12961303                //              Used in drag & drop 
     
    13041311                } 
    13051312                dijit.tree.TreeStoreModel.prototype.pasteItem.call(this, childItem, 
    13061313                        oldParentItem === this.root ? null : oldParentItem, 
    1307                         newParentItem === this.root ? null : newParentItem 
     1314                        newParentItem === this.root ? null : newParentItem, 
     1315                        insertIndex 
    13081316                ); 
    13091317                if(newParentItem === this.root){ 
    13101318                        // It's onAddToRoot()'s responsibility to modify the item so it matches