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