PDA

View Full Version : treePanel Plugin: Ext.ux.tree.TreePanel.CopyDropNode



willf1976
9 Aug 2009, 10:43 PM
Hi All

I have made a simple treePanel plugin which allows for a copy of a node to be created when it is dropped into the tree (as opposed to the default functionality where the node is just moved).

The plugin includes some properties which can be used to set up simple logic for when a node is copied instead of moved (such as defining an array of components whose nodes will be copied when they are dropped into the treePanel).

The class also adds some events to the treePanel class which you can attach listeners to in order to define your own logical for when a node is copied instead of moved. Please see the documentation with in the class for more details.

Note: This plugin needs to be applied to the treePanel which the nodes will be dropped to and does not need to be on the treePanel where the nodes are dragged from.

Please let me know if you find any bugs or having suggestions.

Best regards

Will Ferrer

Update (09/03/09): This code now uses Ext.ux.tree.TreePanel.toObject to copy childNodes that have been dynamically added to branches. This code is available in thread: http://www.extjs.com/forum/showthread.php?t=20793.

Here is Ext.ux.tree.TreePanel.toObject:


/*
original author: dpasichnik
modified by: Will Ferrer
date: 09/03/09
history:
09/03/09 -- posted to ExtJS forums
*/
/**
This code is based on dpasichnik's treeSerializer found at:
http://www.extjs.com/forum/showthread.php?t=20793
*/
/**
* Returns a object that represents the tree
* @param {Function} nodeFilter (optional) A function, which when passed the node, returns true or false to include
* or exclude the node.
* @param {Function} attributeFilter (optional) A function, which when passed an attribute name, and an attribute value,
* returns true or false to include or exclude the attribute.
* @param {Object} attributeMapping (optional) An associative array which can you use to remap attribute names on the nodes as they are converted to an object. Keys in the array represent attributes to be remapped, and their associated values represent the new keys that those attributes will be remapped onto in the returned object.
* @return {String}
*/
Ext.tree.TreePanel.prototype.toObject = function(nodeFilter, attributeFilter, attributeMapping){
return this.getRootNode().toObject(nodeFilter, attributeFilter, attributeMapping);
};

/**
* Returns an object that represents the node
* @param {Function} nodeFilter (optional) A function, which when passed the node, returns true or false to include
* or exclude the node.
* @param {Function} attributeFilter (optional) A function, which when passed an attribute name, and an attribute value,
* returns true or false to include or exclude the attribute.
* @param {Object} attributeMapping (optional) An associative array which can you use to remap attribute names on the nodes as they are converted to an object. Keys in the array represent attributes to be remapped, and their associated values represent the new keys that those attributes will be remapped onto in the returned object.
* @return {String}
*/

Ext.tree.TreeNode.prototype.toObject = function(nodeFilter, attributeFilter, attributeMapping){
// Exclude nodes based on caller-supplied filtering function
if (nodeFilter && (nodeFilter(this) == false)) {
return {};
}
var c = false, returnObj = {};

// Add the id attribute unless the attribute filter rejects it.
if (!attributeFilter || attributeFilter("id", this.id)) {
returnObj.id = this.id;
c = true;
}

// Add all user-added attributes unless rejected by the attributeFilter.
for(var key in this.attributes) {
if ((key != 'id') && (!attributeFilter || attributeFilter(key, this.attributes[key]))) {
if (attributeMapping && attributeMapping[key]) {
thisKey = attributeMapping[key];
} else {
thisKey = key;
}
returnObj[thisKey] = this.attributes[key];
c = true;
}
}
// Add child nodes if any
var children = this.childNodes;
var clen = children.length;
if(clen != 0){
returnObj['children'] = [];
for(var i = 0; i < clen; i++){
returnObj['children'][i] = children[i].toObject(nodeFilter, attributeFilter, attributeMapping);
}
}
return returnObj;
}
Ext.ux.tree.TreePanel.CopyDropNode:



/*
author: Will Ferrer
date: 09/02/09
history:
08/09/09 -- posted to ExtJS forums
08/09/09 -- minor structural changes and changed class name
08/13/09 -- fixed a problem where copying nodes inside the same tree could result in duplicate node its.
08/21/09 -- added superclass.constructor.call for posterities sake
08/24/09 -- acceptFromComponents property added
09/02/09 -- added acceptFromSelf property
*/
/**
* @class Ext.ux.tree.TreePanel.CopyDropNode
* @extends Ext.util.Observable
* A simple plug in for TreePanel that allows you to make nodes dropped into the tree panel be copied instead of moved to the panel.
* Plugin includes properties that can be configured to discern what nodes should be copied and what nodes shouldn't.
* This plugin also adds some events to the treePanel on which the plugin was applied -- these events provide additional control over when a node is copied.
* In order to override the logic used in this plug in to determine whether a node should be copied or not, a boolean value of doCopy may be set on the node which is being dropped.
* You may also control this functionality by modifying the drop event itself -- please see the beforecopydropnode event definition for more details.
* @constructor
* @param {Object} config The config object
* @ptype ux-tree-treepanel-copydropnode
*/
Ext.ns('Ext.ux.tree.TreePanel');
Ext.ux.tree.TreePanel.CopyDropNode = function(config){
Ext.apply(this, config);
Ext.ux.tree.TreePanel.CopyDropNode.superclass.constructor.call(this);
};/*
author: Will Ferrer
date: 09/03/09
history:
08/09/09 -- posted to ExtJS forums
08/09/09 -- minor structural changes and changed class name
08/13/09 -- fixed a problem where copying nodes inside the same tree could result in duplicate node its.
08/21/09 -- added superclass.constructor.call for posterities sake
08/24/09 -- acceptFromComponents property added
09/02/09 -- added acceptFromSelf property
09/03/09 -- added fullBranchCopy, nodeFilter, attributeFilter, attributeMapping
09/04/09 -- added parent.copyDropNode = this;
*/
/**
* @class Ext.ux.tree.TreePanel.CopyDropNode
* @extends Ext.util.Observable
* A simple plug in for TreePanel that allows you to make nodes dropped into the tree panel be copied instead of moved to the panel.
* Plugin includes properties that can be configured to discern what nodes should be copied and what nodes shouldn't.
* This plugin also adds some events to the treePanel on which the plugin was applied -- these events provide additional control over when a node is copied.
* In order to override the logic used in this plug in to determine whether a node should be copied or not, a boolean value of doCopy may be set on the node which is being dropped.
* You may also control this functionality by modifying the drop event itself -- please see the beforecopydropnode event definition for more details.
* @constructor
* @param {Object} config The config object
* @ptype ux-tree-treepanel-copydropnode
*/
Ext.ns('Ext.ux.tree.TreePanel');
Ext.ux.tree.TreePanel.CopyDropNode = function(config){
Ext.apply(this, config);
Ext.ux.tree.TreePanel.CopyDropNode.superclass.constructor.call(this);
};
Ext.extend(Ext.ux.tree.TreePanel.CopyDropNode, Ext.util.Observable, {
//Public Properties:
/**
* @cfg {Boolean} enabled
* Whether or not copying is enabled -- if set to false this plug in will stop copying nodes. Defaults to true.
*/
enabled : true,
/**
* @cfg {Mixed} copyFromComponents
* An array of component ids or null to disable the feature. When a node is dropped on the tree we will check to see if the id of the tree the node was dragged from is present in this array, if it is we will copy the node rather than moving it. If set to null then which tree the node was dragged from won't be a factor in whether it is coppied or not. Defaults to null.
*/
copyFromComponents : null,
/**
* @cfg {Boolean} rejectFromComponents
* An array of component ids or null to disable the feature. When a node is dropped on the tree we will check to see if the id of the tree the node was dragged from is present in this array, if it is we will accept the drag opperation. Defaults to null.
*/
acceptFromComponents : null,
/**
* @cfg {Boolean} acceptFromSelf
* Whether or not to accept drags from with in the same tree. Defaults to true.
*/
acceptFromSelf : true,
/**
* @cfg {Boolean} copyLeafs
* Allow copying of leaf nodes. Defaults to true.
*/
copyLeafs : true,
/**
* @cfg {Boolean} copyLeafs
* Allow copying of branch nodes. Defaults to true.
*/
copyBranches : true,
/**
* @cfg {Boolean} preventCopyFromSelf
* Prevent a copy from occuring when droping nodes that originated in this tree panel
*/
preventCopyFromSelf : true,
/**
* @cfg {Boolean} copyInSameTreeChangeId
* When a copy takes place with in the same tree that the nodes orgenated from should we generated a new id for that node () in order to prevent duplicate nodes. Defaults to true.
*/
copyInSameTreeChangeId : true,
/**
* @cfg {Boolean} copyToDifferentTreeChangeId
* When a copy takes place between 2 trees should we generated a new id for that node () in order to prevent duplicate nodes. Defaults to false.
*/
copyToDifferentTreeChangeId : true,

//!!NOTE: The following features requires Ext.ux.tree.TreePanel.toObject which can be found at: http://www.extjs.com/forum/showthread.php?t=20793.
/**
* @cfg {Boolean} fullBranchCopy
* If set to true child nodes that have been added to branches of the tree will be properly coppied when you copy a branch node -- other wise these child nodes may not be coppied properly. Defaults to false.
*/
fullBranchCopy : false,
/**
* @cfg {Function|null} nodeFilter
* A function that will be used when a fullBranchCopyOccures -- which when passed the node, returns true or false to include or exclude the node. Defaults to null;
*/
nodeFilter : null,
/**
* @cfg {Function|null} attributeFilter
* A function that will be used when a fullBranchCopyOccures -- which when passed an attribute name, and an attribute value, returns true or false to include or exclude the attribute.. Defaults to null;
*/
attributeFilter : null,
/**
* @cfg {Array|null} attributeMapping
* A associative array that will be used when a fullBranchCopyOccures -- which can you use to remap attribute names on the nodes as they are converted to an object. Keys in the array represent attributes to be remapped, and their associated values represent the new keys that those attributes will be remapped onto in the returned object. Defaults to null;
*/
attributeMapping : null,
//Private Functions:
//@private
init: function(parent){
this.parent = parent;
this.parent.copyDropNode = this;
this.parent.on('beforenodedrop', this.onBeforeNodeDrop, this);
this.parent.addEvents(
/**
* @event beforecopydropnode
* Fires right before the copyDropNode function is run. This happens every time the treePanels beforenodedrop event fires. If you would like to override the standard logic used to define if a copy occures or not you may set a boolean value on the event object passed to the listener -- set a value of doCopy true or false to manually dictate whether or not a copy should occure. You may also return false from this event in order to stop the drop action from completeing enterly.
* @param {Ext.ux.tree.TreePanel.CopyDropNode} this
* @param {Object} e The dropNode event contains: (tree: The TreePanel, target: The node being targeted for the drop, data: The drag data from the drag source, point: The point of the drop - append, above or below, source: The drag source, rawEvent: Raw mouse event, dropNode: Drop node(s) provided by the source OR you can supply node(s) to be inserted by setting them on this object., cancel: Set this to true to cancel the drop, dropStatus: If the default drop action is cancelled but the drop is valid, setting this to true will prevent the animated "repair" from appearing.
*/
'beforecopydropnode',
/**
* @event aftercopydropnode
* Fires right after the copyDropNode function is run.
* @param {Ext.ux.tree.TreePanel.CopyDropNode} this
* @param {Boolean} copied true if a copy occured, false if one did not occure
* @param {Object} newNode the new node that was created when the copy occured
* @param {Object} e The dropNode event contains: (tree: The TreePanel, target: The node being targeted for the drop, data: The drag data from the drag source, point: The point of the drop - append, above or below, source: The drag source, rawEvent: Raw mouse event, dropNode: Drop node(s) provided by the source OR you can supply node(s) to be inserted by setting them on this object., cancel: Set this to true to cancel the drop, dropStatus: If the default drop action is cancelled but the drop is valid, setting this to true will prevent the animated "repair" from appearing.
*/
'aftercopydropnode'
);
},
//@private
onBeforeNodeDrop: function(e){
var finishDrop = this.parent.fireEvent("beforecopydropnode", this, e);

var enabled = this.enabled;
var copyFromComponents = (typeof(this.copyFromComponents)=='string')?[this.copyFromComponents]:this.copyFromComponents;
var acceptFromComponents = (typeof(this.acceptFromComponents)=='string')?[this.acceptFromComponents]:this.acceptFromComponents;

var copyLeafs = this.copyLeafs;
var copyBranches = this.copyBranches;
var preventCopyFromSelf = this.preventCopyFromSelf;
var acceptFromSelf = this.acceptFromSelf;

var node = e.dropNode;
var isLeaf = (typeof(node.attributes.leaf)!='undefined' && node.attributes.leaf);
var fromTreeId = e.source.tree.id;
var toTreeId = e.tree.id;
var fromSelf = (fromTreeId == toTreeId);

var doCopy = e.doCopy;
doCopy = (typeof(doCopy)=='undefined')?node.doCopy:doCopy;

var newNode;

finishDrop = ((Ext.isArray(acceptFromComponents) && this.inArray(acceptFromComponents, fromTreeId)) || !acceptFromComponents || (fromSelf && acceptFromSelf))?finishDrop:false;

if (finishDrop) {
if (enabled) {
if (typeof(doCopy)=='undefined') {
doCopy = ((Ext.isArray(copyFromComponents) && this.inArray(copyFromComponents, fromTreeId)) || !copyFromComponents);
doCopy = ((isLeaf && copyLeafs) || (!isLeaf && copyBranches))?doCopy:false;
doCopy = (!preventCopyFromSelf || !fromSelf)?doCopy:false;
}
newNode = (doCopy)?this.copyDropNode(e, node):null;
this.parent.fireEvent("aftercopydropnode", this, doCopy, newNode, e);
}
return true;
} else {
return false;
}
},
//@private
copyDropNode : function (e, node) {
//We make a new node based on the attributes of the node that was going to be dropped and then we swap it over the old node that was on the event in order to cause the new node to be added rather than the old node to be moved. Then the rest of the standard drag and drop functionality will proceed as normal.
var fromSelf = (node.ownerTree.id == e.tree.id), attributes;
if (this.fullBranchCopy) {
attributes = node.toObject(this.nodeFilter, this.attributeFilter, this.attributeMapping);
} else {
attributes = node.attributes
}
var newNode = new Ext.tree.AsyncTreeNode(attributes);

if ((fromSelf && this.copyInSameTreeChangeId) || (!fromSelf && this.copyToDifferentTreeChangeId)) {
var dummyNode = new Ext.tree.AsyncTreeNode({});
newNode.setId(dummyNode.id);
}
e.dropStatus = true;
e.dropNode = newNode;
return newNode;
},
//@private
inArray : function (array, value, caseSensitive) {
var i;
for (i=0; i < array.length; i++) {
// use === to check for Matches. ie., identical (===),
if(caseSensitive){ //performs match even the string is case sensitive
if (array[i].toLowerCase() == value.toLowerCase()) {
return true;
}
}else{
if (array[i] == value) {
return true;
}
}
}
return false;
}
});
Ext.preg('ux-tree-treepanel-copydropnode', Ext.ux.tree.TreePanel.CopyDropNode);

ppiche
11 Oct 2009, 10:20 AM
Sorry to ask this question, as I am not an expert in ExtJS. I was trying the example of ExtJS with two trees and I search for a way to copy instead of moving the files to the other tree and found your post. Can I have some help on how to modify the example to do the trick?

here is the example page I was working with:
http://www.extjs.com/deploy/ext/examples/tree/two-trees.html

Thanks in advance

willf1976
12 Oct 2009, 3:01 PM
Hi PPiche

First of all make sure you have saved/included in your page both the js files needed for the plugin to work:
Ext.ux.tree.TreePanel.toObject.js
Ext.ux.tree.TreePanel.CopyDropNode.js


And then modify the right tree (the one you want to have files copied into) to include the plugin -- here is an example of adding the plugin with lazy instantiation (lazy instantiation means that the plugin isn't created until the tree is finished being created)


var tree2 = new Tree.TreePanel({
animate:true,
autoScroll:true,
//rootVisible: false,
loader: new Ext.tree.TreeLoader({
dataUrl:'get-nodes.php',
baseParams: {path:'extjs'} // custom http params
}),
plugins : [
{ptype :'ux-tree-treepanel-copydropnode'}
],
containerScroll: true,
border: false,
enableDD:true,
dropConfig: {appendOnly:true}
});


Or if you don't want to use lazy instantiation you can write it like this (in this case it will do the exact same thing)


var tree2 = new Tree.TreePanel({
animate:true,
autoScroll:true,
//rootVisible: false,
loader: new Ext.tree.TreeLoader({
dataUrl:'get-nodes.php',
baseParams: {path:'extjs'} // custom http params
}),
plugins : [
new Ext.ux.tree.TreePanel.CopyDropNode()
],
containerScroll: true,
border: false,
enableDD:true,
dropConfig: {appendOnly:true}
});

I hope it all works for you :).

Best Regards

Will Ferrer

Mjollnir26
18 Apr 2010, 11:39 PM
This works perfectly, thank you!

aborjinos
29 Apr 2010, 1:25 AM
Hi willf1976
this sounds very cool and it is what i need

but when i tried this script in ff an error occurs

Error: Ext.preg is not a function
Source File: js/core/Ext.ux.tree.TreePanel.CopyDropNode.js
Line: 230

and line 230 is

Ext.preg('ux-tree-treepanel-copydropnode', Ext.ux.tree.TreePanel.CopyDropNode);I am using 2.2.1 version and
adapter/ext/ext-base.js and ext-all-debug.js are included

Do you know what i have to do? Any solution would be great.

Thanks

willf1976
30 Apr 2010, 1:37 AM
Hi Aborjinos

I think the problem may be that you are using an old version of extjs that I never tested this plug in with.

I actually only started using extjs extensively around version 3. I suspect that version 2 doesn't use preg (registers an xtype for a plug in).

I am currently using a slightly updated version of this plug in which I will post in this thread.

Best regards

Will


Hi willf1976
this sounds very cool and it is what i need

but when i tried this script in ff an error occurs

Error: Ext.preg is not a function
Source File: js/core/Ext.ux.tree.TreePanel.CopyDropNode.js
Line: 230

and line 230 is

Ext.preg('ux-tree-treepanel-copydropnode', Ext.ux.tree.TreePanel.CopyDropNode);I am using 2.2.1 version and
adapter/ext/ext-base.js and ext-all-debug.js are included

Do you know what i have to do? Any solution would be great.

Thanks

willf1976
30 Apr 2010, 1:39 AM
Hi All

I have made some changes to this plug in. The changes I have made may cause some issues for those using the plug in already so I am giving the update its own post instead of posting it over the previous version:



/*
author: Will Ferrer
date: 09/03/09
history:
08/09/09 -- posted to ExtJS forums
08/09/09 -- minor structural changes and changed class name
08/13/09 -- fixed a problem where copying nodes inside the same tree could result in duplicate node its.
08/21/09 -- added superclass.constructor.call for posterities sake
08/24/09 -- acceptFromComponents property added
09/02/09 -- added acceptFromSelf property
09/03/09 -- added fullBranchCopy, nodeFilter, attributeFilter, attributeMapping
09/04/09 -- added parent.copyDropNode = this;
04/13/10 -- made it so that the copied node is passed to listeners so they may modify it.
04/26/10 -- added onEndDrag function
*/
/**
* @class Ext.ux.tree.TreePanel.CopyDropNode
* @extends Ext.util.Observable
* A simple plug in for TreePanel that allows you to make nodes dropped into the tree panel be copied instead of moved to the panel.
* Plugin includes properties that can be configured to discern what nodes should be copied and what nodes shouldn't.
* This plugin also adds some events to the treePanel on which the plugin was applied -- these events provide additional control over when a node is copied.
* In order to override the logic used in this plug in to determine whether a node should be copied or not, a boolean value of doCopy may be set on the node which is being dropped.
* You may also control this functionality by modifying the drop event itself -- please see the beforecopydropnode event definition for more details.
* @constructor
* @param {Object} config The config object
* @ptype ux-tree-treepanel-copydropnode
*/
Ext.ns('Ext.ux.tree.TreePanel');
Ext.ux.tree.TreePanel.CopyDropNode = function(config){
Ext.apply(this, config);
Ext.ux.tree.TreePanel.CopyDropNode.superclass.constructor.call(this);
};
Ext.extend(Ext.ux.tree.TreePanel.CopyDropNode, Ext.util.Observable, {
//Public Properties:
/**
* @cfg {Boolean} enabled
* Whether or not copying is enabled -- if set to false this plug in will stop copying nodes. Defaults to true.
*/
enabled : true,
/**
* @cfg {Mixed} copyFromComponents
* An array of component ids or null to disable the feature. When a node is dropped on the tree we will check to see if the id of the tree the node was dragged from is present in this array, if it is we will copy the node rather than moving it. If set to null then which tree the node was dragged from won't be a factor in whether it is coppied or not. Defaults to null.
*/
copyFromComponents : null,
/**
* @cfg {Boolean} rejectFromComponents
* An array of component ids or null to disable the feature. When a node is dropped on the tree we will check to see if the id of the tree the node was dragged from is present in this array, if it is we will accept the drag opperation. Defaults to null.
*/
acceptFromComponents : null,
/**
* @cfg {Boolean} acceptFromSelf
* Whether or not to accept drags from with in the same tree. Defaults to true.
*/
acceptFromSelf : true,
/**
* @cfg {Boolean} copyLeafs
* Allow copying of leaf nodes. Defaults to true.
*/
copyLeafs : true,
/**
* @cfg {Boolean} copyLeafs
* Allow copying of branch nodes. Defaults to true.
*/
copyBranches : true,
/**
* @cfg {Boolean} preventCopyFromSelf
* Prevent a copy from occuring when droping nodes that originated in this tree panel
*/
preventCopyFromSelf : true,
/**
* @cfg {Boolean} copyInSameTreeChangeId
* When a copy takes place with in the same tree that the nodes orgenated from should we generated a new id for that node () in order to prevent duplicate nodes. Defaults to true.
*/
copyInSameTreeChangeId : true,
/**
* @cfg {Boolean} copyToDifferentTreeChangeId
* When a copy takes place between 2 trees should we generated a new id for that node () in order to prevent duplicate nodes. Defaults to false.
*/
copyToDifferentTreeChangeId : true,

//!!NOTE: The following features requires Ext.ux.tree.TreePanel.toObject which can be found at: http://www.extjs.com/forum/showthread.php?t=20793.
/**
* @cfg {Boolean} fullBranchCopy
* If set to true child nodes that have been added to branches of the tree will be properly coppied when you copy a branch node -- other wise these child nodes may not be coppied properly. Defaults to false.
*/
fullBranchCopy : false,
/**
* @cfg {Function|null} nodeFilter
* A function that will be used when a fullBranchCopyOccures -- which when passed the node, returns true or false to include or exclude the node. Defaults to null;
*/
nodeFilter : null,
/**
* @cfg {Function|null} attributeFilter
* A function that will be used when a fullBranchCopyOccures -- which when passed an attribute name, and an attribute value, returns true or false to include or exclude the attribute.. Defaults to null;
*/
attributeFilter : null,
/**
* @cfg {Array|null} attributeMapping
* A associative array that will be used when a fullBranchCopyOccures -- which can you use to remap attribute names on the nodes as they are converted to an object. Keys in the array represent attributes to be remapped, and their associated values represent the new keys that those attributes will be remapped onto in the returned object. Defaults to null;
*/
attributeMapping : null,
//Private Functions:
//@private
init: function(parent){
this.parent = parent;
this.parent.copyDropNode = this;
this.parent.on('beforenodedrop', this.onBeforeNodeDrop, this);
this.parent.on('enddrag', this.onEndDrag, this);
this.parent.addEvents(
/**
* @event beforecopydropnode
* Fires right before the copyDropNode function is run. This happens every time the treePanels beforenodedrop event fires. If you would like to override the standard logic used to define if a copy occures or not you may set a boolean value on the event object passed to the listener -- set a value of doCopy true or false to manually dictate whether or not a copy should occure. You may also return false from this event in order to stop the drop action from completeing enterly.
* @param {Ext.ux.tree.TreePanel.CopyDropNode} this
* @param {Object} e The dropNode event contains: (tree: The TreePanel, target: The node being targeted for the drop, data: The drag data from the drag source, point: The point of the drop - append, above or below, source: The drag source, rawEvent: Raw mouse event, dropNode: Drop node(s) provided by the source OR you can supply node(s) to be inserted by setting them on this object., cancel: Set this to true to cancel the drop, dropStatus: If the default drop action is cancelled but the drop is valid, setting this to true will prevent the animated "repair" from appearing.
*/
'beforecopydropnode',
/**
* @event aftercopydropnode
* Fires right after the copyDropNode function is run.
* @param {Ext.ux.tree.TreePanel.CopyDropNode} this
* @param {Object} e The dropNode event contains: (tree: The TreePanel, target: The node being targeted for the drop, data: The drag data from the drag source, point: The point of the drop - append, above or below, source: The drag source, rawEvent: Raw mouse event, dropNode: Drop node(s) provided by the source OR you can supply node(s) to be inserted by setting them on this object., cancel: Set this to true to cancel the drop, dropStatus: If the default drop action is cancelled but the drop is valid, setting this to true will prevent the animated "repair" from appearing.
*/
'aftercopydropnode'
);
},
//@private
onBeforeNodeDrop: function(e){
var enabled = this.enabled;
var copyFromComponents = (typeof(this.copyFromComponents)=='string')?[this.copyFromComponents]:this.copyFromComponents;
var acceptFromComponents = (typeof(this.acceptFromComponents)=='string')?[this.acceptFromComponents]:this.acceptFromComponents;

var copyLeafs = this.copyLeafs;
var copyBranches = this.copyBranches;
var preventCopyFromSelf = this.preventCopyFromSelf;
var acceptFromSelf = this.acceptFromSelf;

var node = e.dropNode;
var isLeaf = (!Ext.isEmpty(node.attributes.leaf) && node.attributes.leaf)?true:false;
var fromTreeId = e.source.tree.id;
var toTreeId = e.tree.id;
var fromSelf = (fromTreeId == toTreeId)?true:false;

var doCopy = e.doCopy;
doCopy = (typeof(doCopy)=='undefined')?node.doCopy:doCopy;

var newNode;
if (enabled) {
if (typeof(doCopy)=='undefined') {
doCopy = ((Ext.isArray(copyFromComponents) && this.inArray(copyFromComponents, fromTreeId)) || !copyFromComponents);
doCopy = ((isLeaf && copyLeafs) || (!isLeaf && copyBranches))?doCopy:false;
doCopy = (!preventCopyFromSelf || !fromSelf)?doCopy:false;
}
newNode = (doCopy)?this.copyDropNode(e, node):null;
}
var finishDrop = this.parent.fireEvent("beforecopydropnode", this, e);
finishDrop = ((Ext.isArray(acceptFromComponents) && this.inArray(acceptFromComponents, fromTreeId)) || !acceptFromComponents || (fromSelf && acceptFromSelf))?finishDrop:false;

if (finishDrop) {
e.tree.on('nodedrop', function (e) {
this.parent.fireEvent("aftercopydropnode", this, e);
}, this, {single:true});
//this.parent.fireEvent("aftercopydropnode", this, doCopy, newNode, e);
return true;
} else {
return false;
}
},
//@private
onEndDrag: function(target, node, e){
this.parent.fireEvent("aftercopydropnode", this, node, e);
},
//@private
copyDropNode : function (e, node) {
//We make a new node based on the attributes of the node that was going to be dropped and then we swap it over the old node that was on the event in order to cause the new node to be added rather than the old node to be moved. Then the rest of the standard drag and drop functionality will proceed as normal.
var fromSelf = (node.ownerTree.id == e.tree.id), attributes;
if (this.fullBranchCopy) {
attributes = node.toObject(this.nodeFilter, this.attributeFilter, this.attributeMapping);
} else {
attributes = node.attributes
}

var newNode = new Ext.tree.AsyncTreeNode(attributes);

if ((fromSelf && this.copyInSameTreeChangeId) || (!fromSelf && this.copyToDifferentTreeChangeId)) {
var dummyNode = new Ext.tree.AsyncTreeNode({});
newNode.setId(dummyNode.id);
}
e.dropStatus = true;
e.dropNode = newNode;
e.dropNode.ownerTree = node.ownerTree;

return newNode;
},
//@private
inArray : function (array, value, caseSensitive) {
var i;
for (i=0; i < array.length; i++) {
// use === to check for Matches. ie., identical (===),
if(caseSensitive){ //performs match even the string is case sensitive
if (array[i].toLowerCase() == value.toLowerCase()) {
return true;
}
}else{
if (array[i] == value) {
return true;
}
}
}
return false;
}
});
Ext.preg('ux-tree-treepanel-copydropnode', Ext.ux.tree.TreePanel.CopyDropNode);

willf1976
30 Apr 2010, 1:42 AM
Hi All

Here is an updated version of this plug in which may not work quite the same as it did before if you already using the plug in. For this reason I am posting it separately instead of just posting it over the old version of the plug in.




/*
author: Will Ferrer
date: 09/03/09
history:
08/09/09 -- posted to ExtJS forums
08/09/09 -- minor structural changes and changed class name
08/13/09 -- fixed a problem where copying nodes inside the same tree could result in duplicate node its.
08/21/09 -- added superclass.constructor.call for posterities sake
08/24/09 -- acceptFromComponents property added
09/02/09 -- added acceptFromSelf property
09/03/09 -- added fullBranchCopy, nodeFilter, attributeFilter, attributeMapping
09/04/09 -- added parent.copyDropNode = this;
04/13/10 -- made it so that the copied node is passed to listeners so they may modify it.
04/26/10 -- added onEndDrag function
*/
/**
* @class Ext.ux.tree.TreePanel.CopyDropNode
* @extends Ext.util.Observable
* A simple plug in for TreePanel that allows you to make nodes dropped into the tree panel be copied instead of moved to the panel.
* Plugin includes properties that can be configured to discern what nodes should be copied and what nodes shouldn't.
* This plugin also adds some events to the treePanel on which the plugin was applied -- these events provide additional control over when a node is copied.
* In order to override the logic used in this plug in to determine whether a node should be copied or not, a boolean value of doCopy may be set on the node which is being dropped.
* You may also control this functionality by modifying the drop event itself -- please see the beforecopydropnode event definition for more details.
* @constructor
* @param {Object} config The config object
* @ptype ux-tree-treepanel-copydropnode
*/
Ext.ns('Ext.ux.tree.TreePanel');
Ext.ux.tree.TreePanel.CopyDropNode = function(config){
Ext.apply(this, config);
Ext.ux.tree.TreePanel.CopyDropNode.superclass.constructor.call(this);
};
Ext.extend(Ext.ux.tree.TreePanel.CopyDropNode, Ext.util.Observable, {
//Public Properties:
/**
* @cfg {Boolean} enabled
* Whether or not copying is enabled -- if set to false this plug in will stop copying nodes. Defaults to true.
*/
enabled : true,
/**
* @cfg {Mixed} copyFromComponents
* An array of component ids or null to disable the feature. When a node is dropped on the tree we will check to see if the id of the tree the node was dragged from is present in this array, if it is we will copy the node rather than moving it. If set to null then which tree the node was dragged from won't be a factor in whether it is coppied or not. Defaults to null.
*/
copyFromComponents : null,
/**
* @cfg {Boolean} rejectFromComponents
* An array of component ids or null to disable the feature. When a node is dropped on the tree we will check to see if the id of the tree the node was dragged from is present in this array, if it is we will accept the drag opperation. Defaults to null.
*/
acceptFromComponents : null,
/**
* @cfg {Boolean} acceptFromSelf
* Whether or not to accept drags from with in the same tree. Defaults to true.
*/
acceptFromSelf : true,
/**
* @cfg {Boolean} copyLeafs
* Allow copying of leaf nodes. Defaults to true.
*/
copyLeafs : true,
/**
* @cfg {Boolean} copyLeafs
* Allow copying of branch nodes. Defaults to true.
*/
copyBranches : true,
/**
* @cfg {Boolean} preventCopyFromSelf
* Prevent a copy from occuring when droping nodes that originated in this tree panel
*/
preventCopyFromSelf : true,
/**
* @cfg {Boolean} copyInSameTreeChangeId
* When a copy takes place with in the same tree that the nodes orgenated from should we generated a new id for that node () in order to prevent duplicate nodes. Defaults to true.
*/
copyInSameTreeChangeId : true,
/**
* @cfg {Boolean} copyToDifferentTreeChangeId
* When a copy takes place between 2 trees should we generated a new id for that node () in order to prevent duplicate nodes. Defaults to false.
*/
copyToDifferentTreeChangeId : true,

//!!NOTE: The following features requires Ext.ux.tree.TreePanel.toObject which can be found at: http://www.extjs.com/forum/showthread.php?t=20793.
/**
* @cfg {Boolean} fullBranchCopy
* If set to true child nodes that have been added to branches of the tree will be properly coppied when you copy a branch node -- other wise these child nodes may not be coppied properly. Defaults to false.
*/
fullBranchCopy : false,
/**
* @cfg {Function|null} nodeFilter
* A function that will be used when a fullBranchCopyOccures -- which when passed the node, returns true or false to include or exclude the node. Defaults to null;
*/
nodeFilter : null,
/**
* @cfg {Function|null} attributeFilter
* A function that will be used when a fullBranchCopyOccures -- which when passed an attribute name, and an attribute value, returns true or false to include or exclude the attribute.. Defaults to null;
*/
attributeFilter : null,
/**
* @cfg {Array|null} attributeMapping
* A associative array that will be used when a fullBranchCopyOccures -- which can you use to remap attribute names on the nodes as they are converted to an object. Keys in the array represent attributes to be remapped, and their associated values represent the new keys that those attributes will be remapped onto in the returned object. Defaults to null;
*/
attributeMapping : null,
//Private Functions:
//@private
init: function(parent){
this.parent = parent;
this.parent.copyDropNode = this;
this.parent.on('beforenodedrop', this.onBeforeNodeDrop, this);
this.parent.on('enddrag', this.onEndDrag, this);
this.parent.addEvents(
/**
* @event beforecopydropnode
* Fires right before the copyDropNode function is run. This happens every time the treePanels beforenodedrop event fires. If you would like to override the standard logic used to define if a copy occures or not you may set a boolean value on the event object passed to the listener -- set a value of doCopy true or false to manually dictate whether or not a copy should occure. You may also return false from this event in order to stop the drop action from completeing enterly.
* @param {Ext.ux.tree.TreePanel.CopyDropNode} this
* @param {Object} e The dropNode event contains: (tree: The TreePanel, target: The node being targeted for the drop, data: The drag data from the drag source, point: The point of the drop - append, above or below, source: The drag source, rawEvent: Raw mouse event, dropNode: Drop node(s) provided by the source OR you can supply node(s) to be inserted by setting them on this object., cancel: Set this to true to cancel the drop, dropStatus: If the default drop action is cancelled but the drop is valid, setting this to true will prevent the animated "repair" from appearing.
*/
'beforecopydropnode',
/**
* @event aftercopydropnode
* Fires right after the copyDropNode function is run.
* @param {Ext.ux.tree.TreePanel.CopyDropNode} this
* @param {Object} e The dropNode event contains: (tree: The TreePanel, target: The node being targeted for the drop, data: The drag data from the drag source, point: The point of the drop - append, above or below, source: The drag source, rawEvent: Raw mouse event, dropNode: Drop node(s) provided by the source OR you can supply node(s) to be inserted by setting them on this object., cancel: Set this to true to cancel the drop, dropStatus: If the default drop action is cancelled but the drop is valid, setting this to true will prevent the animated "repair" from appearing.
*/
'aftercopydropnode'
);
},
//@private
onBeforeNodeDrop: function(e){
var enabled = this.enabled;
var copyFromComponents = (typeof(this.copyFromComponents)=='string')?[this.copyFromComponents]:this.copyFromComponents;
var acceptFromComponents = (typeof(this.acceptFromComponents)=='string')?[this.acceptFromComponents]:this.acceptFromComponents;

var copyLeafs = this.copyLeafs;
var copyBranches = this.copyBranches;
var preventCopyFromSelf = this.preventCopyFromSelf;
var acceptFromSelf = this.acceptFromSelf;

var node = e.dropNode;
var isLeaf = (!Ext.isEmpty(node.attributes.leaf) && node.attributes.leaf)?true:false;
var fromTreeId = e.source.tree.id;
var toTreeId = e.tree.id;
var fromSelf = (fromTreeId == toTreeId)?true:false;

var doCopy = e.doCopy;
doCopy = (typeof(doCopy)=='undefined')?node.doCopy:doCopy;

var newNode;
if (enabled) {
if (typeof(doCopy)=='undefined') {
doCopy = ((Ext.isArray(copyFromComponents) && this.inArray(copyFromComponents, fromTreeId)) || !copyFromComponents);
doCopy = ((isLeaf && copyLeafs) || (!isLeaf && copyBranches))?doCopy:false;
doCopy = (!preventCopyFromSelf || !fromSelf)?doCopy:false;
}
newNode = (doCopy)?this.copyDropNode(e, node):null;
}
var finishDrop = this.parent.fireEvent("beforecopydropnode", this, e);
finishDrop = ((Ext.isArray(acceptFromComponents) && this.inArray(acceptFromComponents, fromTreeId)) || !acceptFromComponents || (fromSelf && acceptFromSelf))?finishDrop:false;

if (finishDrop) {
e.tree.on('nodedrop', function (e) {
this.parent.fireEvent("aftercopydropnode", this, e);
}, this, {single:true});
//this.parent.fireEvent("aftercopydropnode", this, doCopy, newNode, e);
return true;
} else {
return false;
}
},
//@private
onEndDrag: function(target, node, e){
this.parent.fireEvent("aftercopydropnode", this, node, e);
},
//@private
copyDropNode : function (e, node) {
//We make a new node based on the attributes of the node that was going to be dropped and then we swap it over the old node that was on the event in order to cause the new node to be added rather than the old node to be moved. Then the rest of the standard drag and drop functionality will proceed as normal.
var fromSelf = (node.ownerTree.id == e.tree.id), attributes;
if (this.fullBranchCopy) {
attributes = node.toObject(this.nodeFilter, this.attributeFilter, this.attributeMapping);
} else {
attributes = node.attributes
}

var newNode = new Ext.tree.AsyncTreeNode(attributes);

if ((fromSelf && this.copyInSameTreeChangeId) || (!fromSelf && this.copyToDifferentTreeChangeId)) {
var dummyNode = new Ext.tree.AsyncTreeNode({});
newNode.setId(dummyNode.id);
}
e.dropStatus = true;
e.dropNode = newNode;
e.dropNode.ownerTree = node.ownerTree;

return newNode;
},
//@private
inArray : function (array, value, caseSensitive) {
var i;
for (i=0; i < array.length; i++) {
// use === to check for Matches. ie., identical (===),
if(caseSensitive){ //performs match even the string is case sensitive
if (array[i].toLowerCase() == value.toLowerCase()) {
return true;
}
}else{
if (array[i] == value) {
return true;
}
}
}
return false;
}
});
Ext.preg('ux-tree-treepanel-copydropnode', Ext.ux.tree.TreePanel.CopyDropNode);

sam.vloeberghs
15 Nov 2010, 4:09 AM
Hi Willf1976,

I have a simalar setup as ppiche,mentioned in this topic, based on this example:
http://dev.sencha.com/deploy/ext/examples/tree/two-trees.html

When I drag a node to from the left tree to the right three, all works fine! The node is copied.
But I can't seem to get a reference to the node that has been dropped in the right three..

How can I get a reference to this Treenode?

Greetings
Sam Vloeberghs

willf1976
16 Nov 2010, 6:57 PM
Hi Sam

You can always use the findChild and findChildBy methods of the treeNode, or use a listener on the CopyDropNode class to modify our record the node as it is being copied. Also this post reminded me I should post my latest version of the plugin -- see below.


/*
author: Will Ferrer
date: 09/03/09
history:
08/09/09 -- posted to ExtJS forums
08/09/09 -- minor structural changes and changed class name
08/13/09 -- fixed a problem where copying nodes inside the same tree could result in duplicate node its.
08/21/09 -- added superclass.constructor.call for posterities sake
08/24/09 -- acceptFromComponents property added
09/02/09 -- added acceptFromSelf property
09/03/09 -- added fullBranchCopy, nodeFilter, attributeFilter, attributeMapping
09/04/09 -- added parent.copyDropNode = this;
04/13/10 -- made it so that the copied node is passed to listeners so they may modify it.
04/26/10 -- added onEndDrag function
05/04/10 -- load nodes after add
06/18/10 -- prevented the copying from taking place when it shouldn't.
*/
/**
* @class Ext.ux.tree.TreePanel.CopyDropNode
* @extends Ext.util.Observable
* A simple plug in for TreePanel that allows you to make nodes dropped into the tree panel be copied instead of moved to the panel.
* Plugin includes properties that can be configured to discern what nodes should be copied and what nodes shouldn't.
* This plugin also adds some events to the treePanel on which the plugin was applied -- these events provide additional control over when a node is copied.
* In order to override the logic used in this plug in to determine whether a node should be copied or not, a boolean value of doCopy may be set on the node which is being dropped.
* You may also control this functionality by modifying the drop event itself -- please see the beforecopydropnode event definition for more details.
* @constructor
* @param {Object} config The config object
* @ptype ux-tree-treepanel-copydropnode
*/
Ext.ns('Ext.ux.tree.TreePanel');
Ext.ux.tree.TreePanel.CopyDropNode = function(config){
Ext.apply(this, config);
Ext.ux.tree.TreePanel.CopyDropNode.superclass.constructor.call(this);
};
Ext.extend(Ext.ux.tree.TreePanel.CopyDropNode, Ext.util.Observable, {
//Public Properties:
/**
* @cfg {Boolean} enabled
* Whether or not copying is enabled -- if set to false this plug in will stop copying nodes. Defaults to true.
*/
enabled : true,
/**
* @cfg {Mixed} copyFromComponents
* An array of component ids or null to disable the feature. When a node is dropped on the tree we will check to see if the id of the tree the node was dragged from is present in this array, if it is we will copy the node rather than moving it. If set to null then which tree the node was dragged from won't be a factor in whether it is coppied or not. Defaults to null.
*/
copyFromComponents : null,
/**
* @cfg {Boolean} rejectFromComponents
* An array of component ids or null to disable the feature. When a node is dropped on the tree we will check to see if the id of the tree the node was dragged from is present in this array, if it is we will accept the drag opperation. Defaults to null.
*/
acceptFromComponents : null,
/**
* @cfg {Boolean} acceptFromSelf
* Whether or not to accept drags from with in the same tree. Defaults to true.
*/
acceptFromSelf : true,
/**
* @cfg {Boolean} copyLeafs
* Allow copying of leaf nodes. Defaults to true.
*/
copyLeafs : true,
/**
* @cfg {Boolean} copyLeafs
* Allow copying of branch nodes. Defaults to true.
*/
copyBranches : true,
/**
* @cfg {Boolean} preventCopyFromSelf
* Prevent a copy from occuring when droping nodes that originated in this tree panel
*/
preventCopyFromSelf : true,
/**
* @cfg {Boolean} copyInSameTreeChangeId
* When a copy takes place with in the same tree that the nodes orgenated from should we generated a new id for that node () in order to prevent duplicate nodes. Defaults to true.
*/
copyInSameTreeChangeId : true,
/**
* @cfg {Boolean} copyToDifferentTreeChangeId
* When a copy takes place between 2 trees should we generated a new id for that node () in order to prevent duplicate nodes. Defaults to false.
*/
copyToDifferentTreeChangeId : true,

//!!NOTE: The following features requires Ext.ux.tree.TreePanel.toObject which can be found at: http://www.extjs.com/forum/showthread.php?t=20793.
/**
* @cfg {Boolean} fullBranchCopy
* If set to true child nodes that have been added to branches of the tree will be properly coppied when you copy a branch node -- other wise these child nodes may not be coppied properly. Defaults to false.
*/
fullBranchCopy : false,
/**
* @cfg {Function|null} nodeFilter
* A function that will be used when a fullBranchCopyOccures -- which when passed the node, returns true or false to include or exclude the node. Defaults to null;
*/
nodeFilter : null,
/**
* @cfg {Function|null} attributeFilter
* A function that will be used when a fullBranchCopyOccures -- which when passed an attribute name, and an attribute value, returns true or false to include or exclude the attribute.. Defaults to null;
*/
attributeFilter : null,
/**
* @cfg {Array|null} attributeMapping
* A associative array that will be used when a fullBranchCopyOccures -- which can you use to remap attribute names on the nodes as they are converted to an object. Keys in the array represent attributes to be remapped, and their associated values represent the new keys that those attributes will be remapped onto in the returned object. Defaults to null;
*/
attributeMapping : null,
/**
* @cfg {Boolean} loadCoppiedNodes
* Whether or not to load coppied nodes -- be aware that nodes that have not been loaded do not have there children attribute transfered into childNodes. Defaults to true;
*/
loadCoppiedNodes : true,
//Private Functions:
// @private
init: function(parent){
this.parent = parent;
this.parent.copyDropNode = this;
this.parent.on('beforenodedrop', this.onBeforeNodeDrop, this);
this.parent.on('enddrag', this.onEndDrag, this);
this.parent.addEvents(
/**
* @event beforecopydropnode
* Fires right before the copyDropNode function is run. This happens every time the treePanels beforenodedrop event fires. If you would like to override the standard logic used to define if a copy occures or not you may set a boolean value on the event object passed to the listener -- set a value of doCopy true or false to manually dictate whether or not a copy should occure. You may also return false from this event in order to stop the drop action from completeing enterly.
* @param {Ext.ux.tree.TreePanel.CopyDropNode} this
* @param {Object} e The dropNode event contains: (tree: The TreePanel, target: The node being targeted for the drop, data: The drag data from the drag source, point: The point of the drop - append, above or below, source: The drag source, rawEvent: Raw mouse event, dropNode: Drop node(s) provided by the source OR you can supply node(s) to be inserted by setting them on this object., cancel: Set this to true to cancel the drop, dropStatus: If the default drop action is cancelled but the drop is valid, setting this to true will prevent the animated "repair" from appearing.
*/
'beforecopydropnode',
/**
* @event aftercopydropnode
* Fires right after the copyDropNode function is run.
* @param {Ext.ux.tree.TreePanel.CopyDropNode} this
* @param {Object} e The dropNode event contains: (tree: The TreePanel, target: The node being targeted for the drop, data: The drag data from the drag source, point: The point of the drop - append, above or below, source: The drag source, rawEvent: Raw mouse event, dropNode: Drop node(s) provided by the source OR you can supply node(s) to be inserted by setting them on this object., cancel: Set this to true to cancel the drop, dropStatus: If the default drop action is cancelled but the drop is valid, setting this to true will prevent the animated "repair" from appearing.
*/
'aftercopydropnode'
);
},
// @private
onBeforeNodeDrop: function(e){
var enabled = this.enabled;
var copyFromComponents = (typeof(this.copyFromComponents)=='string')?[this.copyFromComponents]:this.copyFromComponents;
var acceptFromComponents = (typeof(this.acceptFromComponents)=='string')?[this.acceptFromComponents]:this.acceptFromComponents;

var copyLeafs = this.copyLeafs;
var copyBranches = this.copyBranches;
var preventCopyFromSelf = this.preventCopyFromSelf;
var acceptFromSelf = this.acceptFromSelf;

var node = e.dropNode;
var isLeaf = (!Ext.isEmpty(node.attributes.leaf) && node.attributes.leaf)?true:false;
var fromTreeId = e.source.tree.id;
var toTreeId = e.tree.id;
var fromSelf = (fromTreeId == toTreeId)?true:false;

var doCopy = e.doCopy;
doCopy = (typeof(doCopy)=='undefined')?node.doCopy:doCopy;

var newNode;
if (enabled) {
if (typeof(doCopy)=='undefined') {
doCopy = ((Ext.isArray(copyFromComponents) && Ext.ux.inArray(fromTreeId, copyFromComponents)) || !copyFromComponents);
doCopy = ((isLeaf && copyLeafs) || (!isLeaf && copyBranches))?doCopy:false;
doCopy = (!preventCopyFromSelf || !fromSelf)?doCopy:false;
}
newNode = (doCopy)?this.copyDropNode(e, node):null;
}

if (!Ext.isEmpty(newNode)) {
var finishDrop = this.parent.fireEvent("beforecopydropnode", this, e);
finishDrop = ((Ext.isArray(acceptFromComponents) && Ext.ux.inArray(fromTreeId, acceptFromComponents)) || !acceptFromComponents || (fromSelf && acceptFromSelf))?finishDrop:false;

if (finishDrop) {
e.tree.on('nodedrop', function (e) {
if (this.loadCoppiedNodes) {
var loader = e.dropNode.loader || e.dropNode.attributes.loader || e.dropNode.getOwnerTree().getLoader();
loader.load(e.dropNode, e.dropNode.loadComplete.createDelegate(e.dropNode, [false, false, null, null]), e.dropNode);
}
this.parent.fireEvent("aftercopydropnode", this, e);
}, this, {single:true});
//this.parent.fireEvent("aftercopydropnode", this, doCopy, newNode, e);
return true;
} else {
return false;
}
}

},
// @private
onEndDrag: function(target, node, e){
this.parent.fireEvent("aftercopydropnode", this, node, e);
},
// @private
copyDropNode : function (e, node) {
//We make a new node based on the attributes of the node that was going to be dropped and then we swap it over the old node that was on the event in order to cause the new node to be added rather than the old node to be moved. Then the rest of the standard drag and drop functionality will proceed as normal.
var fromSelf = (node.ownerTree.id == e.tree.id), attributes;
if (this.fullBranchCopy) {
attributes = node.toObject(this.nodeFilter, this.attributeFilter, this.attributeMapping);
} else {
attributes = node.attributes
}

var newNode = new Ext.tree.AsyncTreeNode(attributes);

if ((fromSelf && this.copyInSameTreeChangeId) || (!fromSelf && this.copyToDifferentTreeChangeId)) {
var dummyNode = new Ext.tree.AsyncTreeNode({});
newNode.setId(dummyNode.id);
}

e.dropStatus = true;
e.dropNode = newNode;
e.dropNode.ownerTree = node.ownerTree;

return newNode;
},
// @private
inArray : function (array, value, caseSensitive) {
var i;
for (i=0; i < array.length; i++) {
// use === to check for Matches. ie., identical (===),
if(caseSensitive){ //performs match even the string is case sensitive
if (array[i].toLowerCase() == value.toLowerCase()) {
return true;
}
}else{
if (array[i] == value) {
return true;
}
}
}
return false;
}
});
Ext.preg('ux-tree-treepanel-copydropnode', Ext.ux.tree.TreePanel.CopyDropNode);

Let me know if that helps :)

Will Ferrer

nicholasnet
7 Jan 2011, 3:21 PM
I am trying to use this code to copy node within a tree but it is not working. Can anybody please give me some insight. Here are my codes.


DMR.AssetsTree = Ext.extend(Ext.tree.TreePanel,
{
/* @private */
constructor: function(config)
{
DMR.AssetsTree.superclass.constructor.call(this, config);
},
initComponent: function()
{
var cfg =
{
autoScroll:true,
animate:true,
useArrows: true,
title:'Title',
animate:true,
containerScroll:true,
width:200,
minSize:175,
collapseMode:'mini',
maxSize:400
};
Ext.applyIf(this, cfg);
Ext.applyIf(this.initialConfig, cfg);
cfg =
{
enableDD:true,
rootVisible:false,
currentFolderId: null,
ref: 'assetsTree',
masker: null,
addFolderWindow: new DMR.AddFolderWindow
({
tree: this
}),
//selModel: new Ext.tree.MultiSelectionModel(),
dropConfig:
{
isValidDropPoint : function(n, pt, dd, e, data)
{
if(!n || !data)
{
return false;
}
var targetNode = n.node;
var dropNode = data.node;

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;
}

//This is where folderId rule kicks in
if(dropNode.attributes.folderId === targetNode.attributes.folderId)
{
return false;
}

//End of rule

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;
}
},
root:
{
nodeType:'async',
allowDrop:false
},
tbar:
[{
text:'Create new folder',
tooltip:'Create new folder',
iconCls:'add16',
scope: this,
handler: function(btn, e)
{
this.addFolderWindow.show();
}
}],
loader: new Ext.tree.TreeLoader
({
dataUrl: BASEURL
})
};

Ext.apply(this, cfg);
//need this to work sometimes:
Ext.apply(this.initialConfig, cfg);

DMR.AssetsTree.superclass.initComponent.apply(this, arguments);
},
onRender: function (container, position)
{
DMR.AssetsTree.superclass.onRender.apply(this, arguments);
this.masker = new Ext.LoadMask(this.el, {msg:"Refreshing..."});
},
// template method
/* @private */
initEvents: function()
{
//call parent - be very careful to always call the parent, otherwise you may break the component
DMR.AssetsTree.superclass.initEvents.apply(this, arguments);
},
// template method
/* @private */
afterRender: function()
{
DMR.AssetsTree.superclass.afterRender.apply(this, arguments);
},
/* @private */
beforeDestroy: function()
{
//Call parent
DMR.AssetsTree.superclass.beforeDestroy.apply(this, arguments);
},
onDestroy: function()
{
this.addFolderWindow.destroy();
DMR.AssetsTree.superclass.onDestroy.apply(this, arguments);
}
//End template methods of Ext's Component Life Cycle
//-----------------------------------------------------------------------------
//Begin new or replaced methods
});

Ext.reg('DMR_Assets_Tree', DMR.AssetsTree);

willf1976
10 Jan 2011, 12:39 PM
Hi nicholasnet

A few things occur to me right off the bat -- for one what version of ext are you using? I hope this isn't the cause of your problem but we haven't updated our product (which is where all of our testing happens) past version 3.2.1. When we tried updating to a newer ext all sorts of things broke down and we haven't gotten around to dealing with these issues yet.

Secondly I wounder if could be be a problem unrelated to the plugin code -- I notice you have the line:
if(dropNode.attributes.folderId === targetNode.attributes.folderId)
{
return false;
}

Could this be returning false and preventing the rest of the process?

Lastly -- are you getting any kind of js error? Is the node being moved instead of copied? Or is nothing happening at all? That info might help me get a better idea of what could be going wrong.

Best regards

Will Ferrer


I am trying to use this code to copy node within a tree but it is not working. Can anybody please give me some insight. Here are my codes.


DMR.AssetsTree = Ext.extend(Ext.tree.TreePanel,
{
/* @private */
constructor: function(config)
{
DMR.AssetsTree.superclass.constructor.call(this, config);
},
initComponent: function()
{
var cfg =
{
autoScroll:true,
animate:true,
useArrows: true,
title:'Title',
animate:true,
containerScroll:true,
width:200,
minSize:175,
collapseMode:'mini',
maxSize:400
};
Ext.applyIf(this, cfg);
Ext.applyIf(this.initialConfig, cfg);
cfg =
{
enableDD:true,
rootVisible:false,
currentFolderId: null,
ref: 'assetsTree',
masker: null,
addFolderWindow: new DMR.AddFolderWindow
({
tree: this
}),
//selModel: new Ext.tree.MultiSelectionModel(),
dropConfig:
{
isValidDropPoint : function(n, pt, dd, e, data)
{
if(!n || !data)
{
return false;
}
var targetNode = n.node;
var dropNode = data.node;

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;
}

//This is where folderId rule kicks in
if(dropNode.attributes.folderId === targetNode.attributes.folderId)
{
return false;
}

//End of rule

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;
}
},
root:
{
nodeType:'async',
allowDrop:false
},
tbar:
[{
text:'Create new folder',
tooltip:'Create new folder',
iconCls:'add16',
scope: this,
handler: function(btn, e)
{
this.addFolderWindow.show();
}
}],
loader: new Ext.tree.TreeLoader
({
dataUrl: BASEURL
})
};

Ext.apply(this, cfg);
//need this to work sometimes:
Ext.apply(this.initialConfig, cfg);

DMR.AssetsTree.superclass.initComponent.apply(this, arguments);
},
onRender: function (container, position)
{
DMR.AssetsTree.superclass.onRender.apply(this, arguments);
this.masker = new Ext.LoadMask(this.el, {msg:"Refreshing..."});
},
// template method
/* @private */
initEvents: function()
{
//call parent - be very careful to always call the parent, otherwise you may break the component
DMR.AssetsTree.superclass.initEvents.apply(this, arguments);
},
// template method
/* @private */
afterRender: function()
{
DMR.AssetsTree.superclass.afterRender.apply(this, arguments);
},
/* @private */
beforeDestroy: function()
{
//Call parent
DMR.AssetsTree.superclass.beforeDestroy.apply(this, arguments);
},
onDestroy: function()
{
this.addFolderWindow.destroy();
DMR.AssetsTree.superclass.onDestroy.apply(this, arguments);
}
//End template methods of Ext's Component Life Cycle
//-----------------------------------------------------------------------------
//Begin new or replaced methods
});

Ext.reg('DMR_Assets_Tree', DMR.AssetsTree);

mcryan
17 Jan 2011, 3:42 AM
Excellent plugin!

I do have a question though, what if there are some nodes that you want copied, and others that you want moved on the same panel?

mcryan
17 Jan 2011, 5:05 AM
Nevermind, I read through the code and see that all the functionality is there!

Excellent plugin, thanks!

willf1976
18 Jan 2011, 12:12 PM
Hi mcryan

I am glad you like the plug in :).

Hope it servers you well.

Will Ferrer