[619] | 1 | /* |
---|
| 2 | * Ext JS Library 2.2.1 |
---|
| 3 | * Copyright(c) 2006-2009, Ext JS, LLC. |
---|
| 4 | * licensing@extjs.com |
---|
| 5 | * |
---|
| 6 | * http://extjs.com/license |
---|
| 7 | */ |
---|
| 8 | |
---|
| 9 | /** |
---|
| 10 | * @class Ext.tree.TreeDropZone |
---|
| 11 | * @extends Ext.dd.DropZone |
---|
| 12 | * @constructor |
---|
| 13 | * @param {String/HTMLElement/Element} tree The {@link Ext.tree.TreePanel} for which to enable dropping |
---|
| 14 | * @param {Object} config |
---|
| 15 | */ |
---|
| 16 | if(Ext.dd.DropZone){ |
---|
| 17 | |
---|
| 18 | Ext.tree.TreeDropZone = function(tree, config){ |
---|
| 19 | /** |
---|
| 20 | * @cfg {Boolean} allowParentInsert |
---|
| 21 | * Allow inserting a dragged node between an expanded parent node and its first child that will become a |
---|
| 22 | * sibling of the parent when dropped (defaults to false) |
---|
| 23 | */ |
---|
| 24 | this.allowParentInsert = false; |
---|
| 25 | /** |
---|
| 26 | * @cfg {String} allowContainerDrop |
---|
| 27 | * True if drops on the tree container (outside of a specific tree node) are allowed (defaults to false) |
---|
| 28 | */ |
---|
| 29 | this.allowContainerDrop = false; |
---|
| 30 | /** |
---|
| 31 | * @cfg {String} appendOnly |
---|
| 32 | * True if the tree should only allow append drops (use for trees which are sorted, defaults to false) |
---|
| 33 | */ |
---|
| 34 | this.appendOnly = false; |
---|
| 35 | Ext.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config); |
---|
| 36 | /** |
---|
| 37 | * The TreePanel for this drop zone |
---|
| 38 | * @type Ext.tree.TreePanel |
---|
| 39 | * @property |
---|
| 40 | */ |
---|
| 41 | this.tree = tree; |
---|
| 42 | /** |
---|
| 43 | * Arbitrary data that can be associated with this tree and will be included in the event object that gets |
---|
| 44 | * passed to any nodedragover event handler (defaults to {}) |
---|
| 45 | * @type Ext.tree.TreePanel |
---|
| 46 | * @property |
---|
| 47 | */ |
---|
| 48 | this.dragOverData = {}; |
---|
| 49 | // private |
---|
| 50 | this.lastInsertClass = "x-tree-no-status"; |
---|
| 51 | }; |
---|
| 52 | |
---|
| 53 | Ext.extend(Ext.tree.TreeDropZone, Ext.dd.DropZone, { |
---|
| 54 | /** |
---|
| 55 | * @cfg {String} ddGroup |
---|
| 56 | * A named drag drop group to which this object belongs. If a group is specified, then this object will only |
---|
| 57 | * interact with other drag drop objects in the same group (defaults to 'TreeDD'). |
---|
| 58 | */ |
---|
| 59 | ddGroup : "TreeDD", |
---|
| 60 | |
---|
| 61 | /** |
---|
| 62 | * @cfg {String} expandDelay |
---|
| 63 | * The delay in milliseconds to wait before expanding a target tree node while dragging a droppable node |
---|
| 64 | * over the target (defaults to 1000) |
---|
| 65 | */ |
---|
| 66 | expandDelay : 1000, |
---|
| 67 | |
---|
| 68 | // private |
---|
| 69 | expandNode : function(node){ |
---|
| 70 | if(node.hasChildNodes() && !node.isExpanded()){ |
---|
| 71 | node.expand(false, null, this.triggerCacheRefresh.createDelegate(this)); |
---|
| 72 | } |
---|
| 73 | }, |
---|
| 74 | |
---|
| 75 | // private |
---|
| 76 | queueExpand : function(node){ |
---|
| 77 | this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]); |
---|
| 78 | }, |
---|
| 79 | |
---|
| 80 | // private |
---|
| 81 | cancelExpand : function(){ |
---|
| 82 | if(this.expandProcId){ |
---|
| 83 | clearTimeout(this.expandProcId); |
---|
| 84 | this.expandProcId = false; |
---|
| 85 | } |
---|
| 86 | }, |
---|
| 87 | |
---|
| 88 | // private |
---|
| 89 | isValidDropPoint : function(n, pt, dd, e, data){ |
---|
| 90 | if(!n || !data){ return false; } |
---|
| 91 | var targetNode = n.node; |
---|
| 92 | var dropNode = data.node; |
---|
| 93 | // default drop rules |
---|
| 94 | if(!(targetNode && targetNode.isTarget && pt)){ |
---|
| 95 | return false; |
---|
| 96 | } |
---|
| 97 | if(pt == "append" && targetNode.allowChildren === false){ |
---|
| 98 | return false; |
---|
| 99 | } |
---|
| 100 | if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){ |
---|
| 101 | return false; |
---|
| 102 | } |
---|
| 103 | if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){ |
---|
| 104 | return false; |
---|
| 105 | } |
---|
| 106 | // reuse the object |
---|
| 107 | var overEvent = this.dragOverData; |
---|
| 108 | overEvent.tree = this.tree; |
---|
| 109 | overEvent.target = targetNode; |
---|
| 110 | overEvent.data = data; |
---|
| 111 | overEvent.point = pt; |
---|
| 112 | overEvent.source = dd; |
---|
| 113 | overEvent.rawEvent = e; |
---|
| 114 | overEvent.dropNode = dropNode; |
---|
| 115 | overEvent.cancel = false; |
---|
| 116 | var result = this.tree.fireEvent("nodedragover", overEvent); |
---|
| 117 | return overEvent.cancel === false && result !== false; |
---|
| 118 | }, |
---|
| 119 | |
---|
| 120 | // private |
---|
| 121 | getDropPoint : function(e, n, dd){ |
---|
| 122 | var tn = n.node; |
---|
| 123 | if(tn.isRoot){ |
---|
| 124 | return tn.allowChildren !== false ? "append" : false; // always append for root |
---|
| 125 | } |
---|
| 126 | var dragEl = n.ddel; |
---|
| 127 | var t = Ext.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight; |
---|
| 128 | var y = Ext.lib.Event.getPageY(e); |
---|
| 129 | var noAppend = tn.allowChildren === false || tn.isLeaf(); |
---|
| 130 | if(this.appendOnly || tn.parentNode.allowChildren === false){ |
---|
| 131 | return noAppend ? false : "append"; |
---|
| 132 | } |
---|
| 133 | var noBelow = false; |
---|
| 134 | if(!this.allowParentInsert){ |
---|
| 135 | noBelow = tn.hasChildNodes() && tn.isExpanded(); |
---|
| 136 | } |
---|
| 137 | var q = (b - t) / (noAppend ? 2 : 3); |
---|
| 138 | if(y >= t && y < (t + q)){ |
---|
| 139 | return "above"; |
---|
| 140 | }else if(!noBelow && (noAppend || y >= b-q && y <= b)){ |
---|
| 141 | return "below"; |
---|
| 142 | }else{ |
---|
| 143 | return "append"; |
---|
| 144 | } |
---|
| 145 | }, |
---|
| 146 | |
---|
| 147 | // private |
---|
| 148 | onNodeEnter : function(n, dd, e, data){ |
---|
| 149 | this.cancelExpand(); |
---|
| 150 | }, |
---|
| 151 | |
---|
| 152 | // private |
---|
| 153 | onNodeOver : function(n, dd, e, data){ |
---|
| 154 | var pt = this.getDropPoint(e, n, dd); |
---|
| 155 | var node = n.node; |
---|
| 156 | |
---|
| 157 | // auto node expand check |
---|
| 158 | if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){ |
---|
| 159 | this.queueExpand(node); |
---|
| 160 | }else if(pt != "append"){ |
---|
| 161 | this.cancelExpand(); |
---|
| 162 | } |
---|
| 163 | |
---|
| 164 | // set the insert point style on the target node |
---|
| 165 | var returnCls = this.dropNotAllowed; |
---|
| 166 | if(this.isValidDropPoint(n, pt, dd, e, data)){ |
---|
| 167 | if(pt){ |
---|
| 168 | var el = n.ddel; |
---|
| 169 | var cls; |
---|
| 170 | if(pt == "above"){ |
---|
| 171 | returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between"; |
---|
| 172 | cls = "x-tree-drag-insert-above"; |
---|
| 173 | }else if(pt == "below"){ |
---|
| 174 | returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between"; |
---|
| 175 | cls = "x-tree-drag-insert-below"; |
---|
| 176 | }else{ |
---|
| 177 | returnCls = "x-tree-drop-ok-append"; |
---|
| 178 | cls = "x-tree-drag-append"; |
---|
| 179 | } |
---|
| 180 | if(this.lastInsertClass != cls){ |
---|
| 181 | Ext.fly(el).replaceClass(this.lastInsertClass, cls); |
---|
| 182 | this.lastInsertClass = cls; |
---|
| 183 | } |
---|
| 184 | } |
---|
| 185 | } |
---|
| 186 | return returnCls; |
---|
| 187 | }, |
---|
| 188 | |
---|
| 189 | // private |
---|
| 190 | onNodeOut : function(n, dd, e, data){ |
---|
| 191 | this.cancelExpand(); |
---|
| 192 | this.removeDropIndicators(n); |
---|
| 193 | }, |
---|
| 194 | |
---|
| 195 | // private |
---|
| 196 | onNodeDrop : function(n, dd, e, data){ |
---|
| 197 | var point = this.getDropPoint(e, n, dd); |
---|
| 198 | var targetNode = n.node; |
---|
| 199 | targetNode.ui.startDrop(); |
---|
| 200 | if(!this.isValidDropPoint(n, point, dd, e, data)){ |
---|
| 201 | targetNode.ui.endDrop(); |
---|
| 202 | return false; |
---|
| 203 | } |
---|
| 204 | // first try to find the drop node |
---|
| 205 | var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null); |
---|
| 206 | var dropEvent = { |
---|
| 207 | tree : this.tree, |
---|
| 208 | target: targetNode, |
---|
| 209 | data: data, |
---|
| 210 | point: point, |
---|
| 211 | source: dd, |
---|
| 212 | rawEvent: e, |
---|
| 213 | dropNode: dropNode, |
---|
| 214 | cancel: !dropNode, |
---|
| 215 | dropStatus: false |
---|
| 216 | }; |
---|
| 217 | var retval = this.tree.fireEvent("beforenodedrop", dropEvent); |
---|
| 218 | if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){ |
---|
| 219 | targetNode.ui.endDrop(); |
---|
| 220 | return dropEvent.dropStatus; |
---|
| 221 | } |
---|
| 222 | // allow target changing |
---|
| 223 | targetNode = dropEvent.target; |
---|
| 224 | if(point == "append" && !targetNode.isExpanded()){ |
---|
| 225 | targetNode.expand(false, null, function(){ |
---|
| 226 | this.completeDrop(dropEvent); |
---|
| 227 | }.createDelegate(this)); |
---|
| 228 | }else{ |
---|
| 229 | this.completeDrop(dropEvent); |
---|
| 230 | } |
---|
| 231 | return true; |
---|
| 232 | }, |
---|
| 233 | |
---|
| 234 | // private |
---|
| 235 | completeDrop : function(de){ |
---|
| 236 | var ns = de.dropNode, p = de.point, t = de.target; |
---|
| 237 | if(!Ext.isArray(ns)){ |
---|
| 238 | ns = [ns]; |
---|
| 239 | } |
---|
| 240 | var n; |
---|
| 241 | for(var i = 0, len = ns.length; i < len; i++){ |
---|
| 242 | n = ns[i]; |
---|
| 243 | if(p == "above"){ |
---|
| 244 | t.parentNode.insertBefore(n, t); |
---|
| 245 | }else if(p == "below"){ |
---|
| 246 | t.parentNode.insertBefore(n, t.nextSibling); |
---|
| 247 | }else{ |
---|
| 248 | t.appendChild(n); |
---|
| 249 | } |
---|
| 250 | } |
---|
| 251 | n.ui.focus(); |
---|
| 252 | if(Ext.enableFx && this.tree.hlDrop){ |
---|
| 253 | n.ui.highlight(); |
---|
| 254 | } |
---|
| 255 | t.ui.endDrop(); |
---|
| 256 | this.tree.fireEvent("nodedrop", de); |
---|
| 257 | }, |
---|
| 258 | |
---|
| 259 | // private |
---|
| 260 | afterNodeMoved : function(dd, data, e, targetNode, dropNode){ |
---|
| 261 | if(Ext.enableFx && this.tree.hlDrop){ |
---|
| 262 | dropNode.ui.focus(); |
---|
| 263 | dropNode.ui.highlight(); |
---|
| 264 | } |
---|
| 265 | this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e); |
---|
| 266 | }, |
---|
| 267 | |
---|
| 268 | // private |
---|
| 269 | getTree : function(){ |
---|
| 270 | return this.tree; |
---|
| 271 | }, |
---|
| 272 | |
---|
| 273 | // private |
---|
| 274 | removeDropIndicators : function(n){ |
---|
| 275 | if(n && n.ddel){ |
---|
| 276 | var el = n.ddel; |
---|
| 277 | Ext.fly(el).removeClass([ |
---|
| 278 | "x-tree-drag-insert-above", |
---|
| 279 | "x-tree-drag-insert-below", |
---|
| 280 | "x-tree-drag-append"]); |
---|
| 281 | this.lastInsertClass = "_noclass"; |
---|
| 282 | } |
---|
| 283 | }, |
---|
| 284 | |
---|
| 285 | // private |
---|
| 286 | beforeDragDrop : function(target, e, id){ |
---|
| 287 | this.cancelExpand(); |
---|
| 288 | return true; |
---|
| 289 | }, |
---|
| 290 | |
---|
| 291 | // private |
---|
| 292 | afterRepair : function(data){ |
---|
| 293 | if(data && Ext.enableFx){ |
---|
| 294 | data.node.ui.highlight(); |
---|
| 295 | } |
---|
| 296 | this.hideProxy(); |
---|
| 297 | } |
---|
| 298 | }); |
---|
| 299 | |
---|
| 300 | } |
---|