X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/6e39d509471fe9b4e2660e0d1631b350d0c66f40..refs/heads/old:/src/widgets/tree/TreeDropZone.js?ds=sidebyside diff --git a/src/widgets/tree/TreeDropZone.js b/src/widgets/tree/TreeDropZone.js index c77d892d..a422cbe9 100644 --- a/src/widgets/tree/TreeDropZone.js +++ b/src/widgets/tree/TreeDropZone.js @@ -1,321 +1,321 @@ /*! - * Ext JS Library 3.1.0 - * Copyright(c) 2006-2009 Ext JS, LLC - * licensing@extjs.com - * http://www.extjs.com/license + * Ext JS Library 3.3.1 + * Copyright(c) 2006-2010 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license */ -/** - * @class Ext.tree.TreeDropZone - * @extends Ext.dd.DropZone - * @constructor - * @param {String/HTMLElement/Element} tree The {@link Ext.tree.TreePanel} for which to enable dropping - * @param {Object} config - */ -if(Ext.dd.DropZone){ - -Ext.tree.TreeDropZone = function(tree, config){ - /** - * @cfg {Boolean} allowParentInsert - * Allow inserting a dragged node between an expanded parent node and its first child that will become a - * sibling of the parent when dropped (defaults to false) - */ - this.allowParentInsert = config.allowParentInsert || false; - /** - * @cfg {String} allowContainerDrop - * True if drops on the tree container (outside of a specific tree node) are allowed (defaults to false) - */ - this.allowContainerDrop = config.allowContainerDrop || false; - /** - * @cfg {String} appendOnly - * True if the tree should only allow append drops (use for trees which are sorted, defaults to false) - */ - this.appendOnly = config.appendOnly || false; - - Ext.tree.TreeDropZone.superclass.constructor.call(this, tree.getTreeEl(), config); - /** - * The TreePanel for this drop zone - * @type Ext.tree.TreePanel - * @property - */ - this.tree = tree; - /** - * Arbitrary data that can be associated with this tree and will be included in the event object that gets - * passed to any nodedragover event handler (defaults to {}) - * @type Ext.tree.TreePanel - * @property - */ - this.dragOverData = {}; - // private - this.lastInsertClass = "x-tree-no-status"; -}; - -Ext.extend(Ext.tree.TreeDropZone, Ext.dd.DropZone, { - /** - * @cfg {String} ddGroup - * A named drag drop group to which this object belongs. If a group is specified, then this object will only - * interact with other drag drop objects in the same group (defaults to 'TreeDD'). - */ - ddGroup : "TreeDD", - - /** - * @cfg {String} expandDelay - * The delay in milliseconds to wait before expanding a target tree node while dragging a droppable node - * over the target (defaults to 1000) - */ - expandDelay : 1000, - - // private - expandNode : function(node){ - if(node.hasChildNodes() && !node.isExpanded()){ - node.expand(false, null, this.triggerCacheRefresh.createDelegate(this)); - } - }, - - // private - queueExpand : function(node){ - this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]); - }, - - // private - cancelExpand : function(){ - if(this.expandProcId){ - clearTimeout(this.expandProcId); - this.expandProcId = false; - } - }, - - // private - isValidDropPoint : function(n, pt, dd, e, data){ - if(!n || !data){ return false; } - var targetNode = n.node; - var dropNode = data.node; - // default drop rules - if(!(targetNode && targetNode.isTarget && pt)){ - return false; - } - if(pt == "append" && targetNode.allowChildren === false){ - return false; - } - if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){ - return false; - } - if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){ - return false; - } - // reuse the object - var overEvent = this.dragOverData; - overEvent.tree = this.tree; - overEvent.target = targetNode; - overEvent.data = data; - overEvent.point = pt; - overEvent.source = dd; - overEvent.rawEvent = e; - overEvent.dropNode = dropNode; - overEvent.cancel = false; - var result = this.tree.fireEvent("nodedragover", overEvent); - return overEvent.cancel === false && result !== false; - }, - - // private - getDropPoint : function(e, n, dd){ - var tn = n.node; - if(tn.isRoot){ - return tn.allowChildren !== false ? "append" : false; // always append for root - } - var dragEl = n.ddel; - var t = Ext.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight; - var y = Ext.lib.Event.getPageY(e); - var noAppend = tn.allowChildren === false || tn.isLeaf(); - if(this.appendOnly || tn.parentNode.allowChildren === false){ - return noAppend ? false : "append"; - } - var noBelow = false; - if(!this.allowParentInsert){ - noBelow = tn.hasChildNodes() && tn.isExpanded(); - } - var q = (b - t) / (noAppend ? 2 : 3); - if(y >= t && y < (t + q)){ - return "above"; - }else if(!noBelow && (noAppend || y >= b-q && y <= b)){ - return "below"; - }else{ - return "append"; - } - }, - - // private - onNodeEnter : function(n, dd, e, data){ - this.cancelExpand(); - }, - - onContainerOver : function(dd, e, data) { - if (this.allowContainerDrop && this.isValidDropPoint({ ddel: this.tree.getRootNode().ui.elNode, node: this.tree.getRootNode() }, "append", dd, e, data)) { - return this.dropAllowed; - } - return this.dropNotAllowed; - }, - - // private - onNodeOver : function(n, dd, e, data){ - var pt = this.getDropPoint(e, n, dd); - var node = n.node; - - // auto node expand check - if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){ - this.queueExpand(node); - }else if(pt != "append"){ - this.cancelExpand(); - } - - // set the insert point style on the target node - var returnCls = this.dropNotAllowed; - if(this.isValidDropPoint(n, pt, dd, e, data)){ - if(pt){ - var el = n.ddel; - var cls; - if(pt == "above"){ - returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between"; - cls = "x-tree-drag-insert-above"; - }else if(pt == "below"){ - returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between"; - cls = "x-tree-drag-insert-below"; - }else{ - returnCls = "x-tree-drop-ok-append"; - cls = "x-tree-drag-append"; - } - if(this.lastInsertClass != cls){ - Ext.fly(el).replaceClass(this.lastInsertClass, cls); - this.lastInsertClass = cls; - } - } - } - return returnCls; - }, - - // private - onNodeOut : function(n, dd, e, data){ - this.cancelExpand(); - this.removeDropIndicators(n); - }, - - // private - onNodeDrop : function(n, dd, e, data){ - var point = this.getDropPoint(e, n, dd); - var targetNode = n.node; - targetNode.ui.startDrop(); - if(!this.isValidDropPoint(n, point, dd, e, data)){ - targetNode.ui.endDrop(); - return false; - } - // first try to find the drop node - var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null); - return this.processDrop(targetNode, data, point, dd, e, dropNode); - }, - - onContainerDrop : function(dd, e, data){ - if (this.allowContainerDrop && this.isValidDropPoint({ ddel: this.tree.getRootNode().ui.elNode, node: this.tree.getRootNode() }, "append", dd, e, data)) { - var targetNode = this.tree.getRootNode(); - targetNode.ui.startDrop(); - var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, 'append', e) : null); - return this.processDrop(targetNode, data, 'append', dd, e, dropNode); - } - return false; - }, - - // private - processDrop: function(target, data, point, dd, e, dropNode){ - var dropEvent = { - tree : this.tree, - target: target, - data: data, - point: point, - source: dd, - rawEvent: e, - dropNode: dropNode, - cancel: !dropNode, - dropStatus: false - }; - var retval = this.tree.fireEvent("beforenodedrop", dropEvent); - if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){ - target.ui.endDrop(); - return dropEvent.dropStatus; - } - - target = dropEvent.target; - if(point == 'append' && !target.isExpanded()){ - target.expand(false, null, function(){ - this.completeDrop(dropEvent); - }.createDelegate(this)); - }else{ - this.completeDrop(dropEvent); - } - return true; - }, - - // private - completeDrop : function(de){ - var ns = de.dropNode, p = de.point, t = de.target; - if(!Ext.isArray(ns)){ - ns = [ns]; - } - var n; - for(var i = 0, len = ns.length; i < len; i++){ - n = ns[i]; - if(p == "above"){ - t.parentNode.insertBefore(n, t); - }else if(p == "below"){ - t.parentNode.insertBefore(n, t.nextSibling); - }else{ - t.appendChild(n); - } - } - n.ui.focus(); - if(Ext.enableFx && this.tree.hlDrop){ - n.ui.highlight(); - } - t.ui.endDrop(); - this.tree.fireEvent("nodedrop", de); - }, - - // private - afterNodeMoved : function(dd, data, e, targetNode, dropNode){ - if(Ext.enableFx && this.tree.hlDrop){ - dropNode.ui.focus(); - dropNode.ui.highlight(); - } - this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e); - }, - - // private - getTree : function(){ - return this.tree; - }, - - // private - removeDropIndicators : function(n){ - if(n && n.ddel){ - var el = n.ddel; - Ext.fly(el).removeClass([ - "x-tree-drag-insert-above", - "x-tree-drag-insert-below", - "x-tree-drag-append"]); - this.lastInsertClass = "_noclass"; - } - }, - - // private - beforeDragDrop : function(target, e, id){ - this.cancelExpand(); - return true; - }, - - // private - afterRepair : function(data){ - if(data && Ext.enableFx){ - data.node.ui.highlight(); - } - this.hideProxy(); - } -}); - +/** + * @class Ext.tree.TreeDropZone + * @extends Ext.dd.DropZone + * @constructor + * @param {String/HTMLElement/Element} tree The {@link Ext.tree.TreePanel} for which to enable dropping + * @param {Object} config + */ +if(Ext.dd.DropZone){ + +Ext.tree.TreeDropZone = function(tree, config){ + /** + * @cfg {Boolean} allowParentInsert + * Allow inserting a dragged node between an expanded parent node and its first child that will become a + * sibling of the parent when dropped (defaults to false) + */ + this.allowParentInsert = config.allowParentInsert || false; + /** + * @cfg {String} allowContainerDrop + * True if drops on the tree container (outside of a specific tree node) are allowed (defaults to false) + */ + this.allowContainerDrop = config.allowContainerDrop || false; + /** + * @cfg {String} appendOnly + * True if the tree should only allow append drops (use for trees which are sorted, defaults to false) + */ + this.appendOnly = config.appendOnly || false; + + Ext.tree.TreeDropZone.superclass.constructor.call(this, tree.getTreeEl(), config); + /** + * The TreePanel for this drop zone + * @type Ext.tree.TreePanel + * @property + */ + this.tree = tree; + /** + * Arbitrary data that can be associated with this tree and will be included in the event object that gets + * passed to any nodedragover event handler (defaults to {}) + * @type Ext.tree.TreePanel + * @property + */ + this.dragOverData = {}; + // private + this.lastInsertClass = "x-tree-no-status"; +}; + +Ext.extend(Ext.tree.TreeDropZone, Ext.dd.DropZone, { + /** + * @cfg {String} ddGroup + * A named drag drop group to which this object belongs. If a group is specified, then this object will only + * interact with other drag drop objects in the same group (defaults to 'TreeDD'). + */ + ddGroup : "TreeDD", + + /** + * @cfg {String} expandDelay + * The delay in milliseconds to wait before expanding a target tree node while dragging a droppable node + * over the target (defaults to 1000) + */ + expandDelay : 1000, + + // private + expandNode : function(node){ + if(node.hasChildNodes() && !node.isExpanded()){ + node.expand(false, null, this.triggerCacheRefresh.createDelegate(this)); + } + }, + + // private + queueExpand : function(node){ + this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]); + }, + + // private + cancelExpand : function(){ + if(this.expandProcId){ + clearTimeout(this.expandProcId); + this.expandProcId = false; + } + }, + + // private + isValidDropPoint : function(n, pt, dd, e, data){ + if(!n || !data){ return false; } + var targetNode = n.node; + var dropNode = data.node; + // default drop rules + if(!(targetNode && targetNode.isTarget && pt)){ + return false; + } + if(pt == "append" && targetNode.allowChildren === false){ + return false; + } + if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){ + return false; + } + if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){ + return false; + } + // reuse the object + var overEvent = this.dragOverData; + overEvent.tree = this.tree; + overEvent.target = targetNode; + overEvent.data = data; + overEvent.point = pt; + overEvent.source = dd; + overEvent.rawEvent = e; + overEvent.dropNode = dropNode; + overEvent.cancel = false; + var result = this.tree.fireEvent("nodedragover", overEvent); + return overEvent.cancel === false && result !== false; + }, + + // private + getDropPoint : function(e, n, dd){ + var tn = n.node; + if(tn.isRoot){ + return tn.allowChildren !== false ? "append" : false; // always append for root + } + var dragEl = n.ddel; + var t = Ext.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight; + var y = Ext.lib.Event.getPageY(e); + var noAppend = tn.allowChildren === false || tn.isLeaf(); + if(this.appendOnly || tn.parentNode.allowChildren === false){ + return noAppend ? false : "append"; + } + var noBelow = false; + if(!this.allowParentInsert){ + noBelow = tn.hasChildNodes() && tn.isExpanded(); + } + var q = (b - t) / (noAppend ? 2 : 3); + if(y >= t && y < (t + q)){ + return "above"; + }else if(!noBelow && (noAppend || y >= b-q && y <= b)){ + return "below"; + }else{ + return "append"; + } + }, + + // private + onNodeEnter : function(n, dd, e, data){ + this.cancelExpand(); + }, + + onContainerOver : function(dd, e, data) { + if (this.allowContainerDrop && this.isValidDropPoint({ ddel: this.tree.getRootNode().ui.elNode, node: this.tree.getRootNode() }, "append", dd, e, data)) { + return this.dropAllowed; + } + return this.dropNotAllowed; + }, + + // private + onNodeOver : function(n, dd, e, data){ + var pt = this.getDropPoint(e, n, dd); + var node = n.node; + + // auto node expand check + if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){ + this.queueExpand(node); + }else if(pt != "append"){ + this.cancelExpand(); + } + + // set the insert point style on the target node + var returnCls = this.dropNotAllowed; + if(this.isValidDropPoint(n, pt, dd, e, data)){ + if(pt){ + var el = n.ddel; + var cls; + if(pt == "above"){ + returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between"; + cls = "x-tree-drag-insert-above"; + }else if(pt == "below"){ + returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between"; + cls = "x-tree-drag-insert-below"; + }else{ + returnCls = "x-tree-drop-ok-append"; + cls = "x-tree-drag-append"; + } + if(this.lastInsertClass != cls){ + Ext.fly(el).replaceClass(this.lastInsertClass, cls); + this.lastInsertClass = cls; + } + } + } + return returnCls; + }, + + // private + onNodeOut : function(n, dd, e, data){ + this.cancelExpand(); + this.removeDropIndicators(n); + }, + + // private + onNodeDrop : function(n, dd, e, data){ + var point = this.getDropPoint(e, n, dd); + var targetNode = n.node; + targetNode.ui.startDrop(); + if(!this.isValidDropPoint(n, point, dd, e, data)){ + targetNode.ui.endDrop(); + return false; + } + // first try to find the drop node + var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null); + return this.processDrop(targetNode, data, point, dd, e, dropNode); + }, + + onContainerDrop : function(dd, e, data){ + if (this.allowContainerDrop && this.isValidDropPoint({ ddel: this.tree.getRootNode().ui.elNode, node: this.tree.getRootNode() }, "append", dd, e, data)) { + var targetNode = this.tree.getRootNode(); + targetNode.ui.startDrop(); + var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, 'append', e) : null); + return this.processDrop(targetNode, data, 'append', dd, e, dropNode); + } + return false; + }, + + // private + processDrop: function(target, data, point, dd, e, dropNode){ + var dropEvent = { + tree : this.tree, + target: target, + data: data, + point: point, + source: dd, + rawEvent: e, + dropNode: dropNode, + cancel: !dropNode, + dropStatus: false + }; + var retval = this.tree.fireEvent("beforenodedrop", dropEvent); + if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){ + target.ui.endDrop(); + return dropEvent.dropStatus; + } + + target = dropEvent.target; + if(point == 'append' && !target.isExpanded()){ + target.expand(false, null, function(){ + this.completeDrop(dropEvent); + }.createDelegate(this)); + }else{ + this.completeDrop(dropEvent); + } + return true; + }, + + // private + completeDrop : function(de){ + var ns = de.dropNode, p = de.point, t = de.target; + if(!Ext.isArray(ns)){ + ns = [ns]; + } + var n; + for(var i = 0, len = ns.length; i < len; i++){ + n = ns[i]; + if(p == "above"){ + t.parentNode.insertBefore(n, t); + }else if(p == "below"){ + t.parentNode.insertBefore(n, t.nextSibling); + }else{ + t.appendChild(n); + } + } + n.ui.focus(); + if(Ext.enableFx && this.tree.hlDrop){ + n.ui.highlight(); + } + t.ui.endDrop(); + this.tree.fireEvent("nodedrop", de); + }, + + // private + afterNodeMoved : function(dd, data, e, targetNode, dropNode){ + if(Ext.enableFx && this.tree.hlDrop){ + dropNode.ui.focus(); + dropNode.ui.highlight(); + } + this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e); + }, + + // private + getTree : function(){ + return this.tree; + }, + + // private + removeDropIndicators : function(n){ + if(n && n.ddel){ + var el = n.ddel; + Ext.fly(el).removeClass([ + "x-tree-drag-insert-above", + "x-tree-drag-insert-below", + "x-tree-drag-append"]); + this.lastInsertClass = "_noclass"; + } + }, + + // private + beforeDragDrop : function(target, e, id){ + this.cancelExpand(); + return true; + }, + + // private + afterRepair : function(data){ + if(data && Ext.enableFx){ + data.node.ui.highlight(); + } + this.hideProxy(); + } +}); + } \ No newline at end of file