[TASK] Migrate to ExtJS 4: Migrate PageTree and Context-Menu
authorOliver Hader <oliver@typo3.org>
Wed, 7 Dec 2011 16:10:41 +0000 (17:10 +0100)
committerSteffen Ritter <info@rs-websystems.de>
Tue, 13 Dec 2011 07:51:36 +0000 (08:51 +0100)
1. Migrate page tree.
2. Migrate context menu.

Change-Id: I53502d25a11bfa61ffd66f600875f2952e930f8d
Resolves: #32191
Releases: 4.7
Reviewed-on: http://review.typo3.org/7103
Tested-by: Stefan Neufeind
Reviewed-by: Steffen Ritter
Tested-by: Steffen Ritter
39 files changed:
t3lib/core_autoload.php
t3lib/js/extjs/components/pagetree/javascript/Ext.ux.state.TreePanel.js
t3lib/js/extjs/components/pagetree/javascript/actions.js
t3lib/js/extjs/components/pagetree/javascript/app.js
t3lib/js/extjs/components/pagetree/javascript/contextmenu.js
t3lib/js/extjs/components/pagetree/javascript/deletiondropzone.js
t3lib/js/extjs/components/pagetree/javascript/filteringtree.js
t3lib/js/extjs/components/pagetree/javascript/loadorder.txt
t3lib/js/extjs/components/pagetree/javascript/nodeui.js [deleted file]
t3lib/js/extjs/components/pagetree/javascript/pagetreecolumn.js [new file with mode: 0644]
t3lib/js/extjs/components/pagetree/javascript/toppanel.js
t3lib/js/extjs/components/pagetree/javascript/tree.js
t3lib/js/extjs/components/pagetree/javascript/treedropzone.js [new file with mode: 0644]
t3lib/js/extjs/components/pagetree/javascript/treeeditor.js
t3lib/js/extjs/components/pagetree/javascript/treeviewdragdrop.js [new file with mode: 0644]
t3lib/js/extjs/tree/tree.js
t3lib/tree/class.t3lib_tree_abstracttree.php
t3lib/tree/class.t3lib_tree_node.php
t3lib/tree/class.t3lib_tree_nodecollection.php
t3lib/tree/class.t3lib_tree_representationnode.php
t3lib/tree/extdirect/class.t3lib_tree_extdirect_abstractextjstree.php [deleted file]
t3lib/tree/extdirect/class.t3lib_tree_extdirect_node.php [deleted file]
t3lib/tree/extjs/class.t3lib_tree_extjs_abstractextjstree.php [new file with mode: 0644]
t3lib/tree/extjs/class.t3lib_tree_extjs_abstractstatefulextjstree.php [new file with mode: 0644]
t3lib/tree/extjs/class.t3lib_tree_extjs_node.php [new file with mode: 0644]
t3lib/tree/interfaces/interface.t3lib_tree_comparablenode.php [new file with mode: 0644]
t3lib/tree/interfaces/interface.t3lib_tree_draggableanddropable.php [new file with mode: 0644]
t3lib/tree/interfaces/interface.t3lib_tree_labeleditable.php [new file with mode: 0644]
t3lib/tree/interfaces/interface.t3lib_tree_recordbasednode.php [new file with mode: 0644]
t3lib/tree/interfaces/interface.t3lib_tree_renderablenode.php [new file with mode: 0644]
t3lib/tree/navigationtree/class.t3lib_tree_navigationtree_node.php [new file with mode: 0644]
t3lib/tree/pagetree/class.t3lib_tree_pagetree_commands.php
t3lib/tree/pagetree/class.t3lib_tree_pagetree_dataprovider.php
t3lib/tree/pagetree/class.t3lib_tree_pagetree_indicator.php
t3lib/tree/pagetree/class.t3lib_tree_pagetree_node.php
t3lib/tree/pagetree/extdirect/class.t3lib_tree_pagetree_extdirect_commands.php
t3lib/tree/pagetree/extdirect/class.t3lib_tree_pagetree_extdirect_tree.php
typo3/sysext/t3skin/stylesheets/structure/element_pagetree.css
typo3/sysext/t3skin/stylesheets/visual/element_pagetree.css

index 4b44887..883285c 100644 (file)
@@ -196,16 +196,15 @@ $t3libClasses = array(
        't3lib_tree_abstractdataprovider' => PATH_t3lib . 'tree/class.t3lib_tree_abstractdataprovider.php',
        't3lib_tree_abstractstateprovider' => PATH_t3lib . 'tree/class.t3lib_tree_abstractstateprovider.php',
        't3lib_tree_node' => PATH_t3lib . 'tree/class.t3lib_tree_node.php',
-       't3lib_tree_representationnode' => PATH_t3lib . 'tree/class.t3lib_tree_representationnode.php',
        't3lib_tree_nodecollection' => PATH_t3lib . 'tree/class.t3lib_tree_nodecollection.php',
        't3lib_tree_sortednodecollection' => PATH_t3lib . 'tree/class.t3lib_tree_sortednodecollection.php',
-       't3lib_tree_extdirect_abstractextjstree' => PATH_t3lib . 'tree/extdirect/class.t3lib_tree_extdirect_abstractextjstree.php',
-       't3lib_tree_comparablenode' => PATH_t3lib . 'interfaces/tree/interface.t3lib_tree_comparablenode.php',
-       't3lib_tree_draggableanddropable' => PATH_t3lib . 'interfaces/tree/interface.t3lib_tree_draggableanddropable.php',
-       't3lib_tree_labeleditable' => PATH_t3lib . 'interfaces/tree/interface.t3lib_tree_labeleditable.php',
-       't3lib_tree_renderer_abstract' => PATH_t3lib . 'tree/renderer/class.t3lib_tree_renderer_abstract.php',
-       't3lib_tree_renderer_unorderedlist' => PATH_t3lib . 'tree/renderer/class.t3lib_tree_renderer_unorderedlist.php',
-       't3lib_tree_renderer_extjsjson' => PATH_t3lib . 'tree/renderer/class.t3lib_tree_renderer_extjsjson.php',
+       't3lib_tree_extjs_abstractextjstree' => PATH_t3lib . 'tree/extjs/class.t3lib_tree_extjs_abstractextjstree.php',
+       't3lib_tree_extjs_abstractstatefulextjstree' => PATH_t3lib . 'tree/extjs/class.t3lib_tree_extjs_abstractstatefulextjstree.php',
+       't3lib_tree_comparablenode' => PATH_t3lib . 'tree/interfaces/interface.t3lib_tree_comparablenode.php',
+       't3lib_tree_renderablenode' => PATH_t3lib . 'tree/interfaces/interface.t3lib_tree_renderablenode.php',
+       't3lib_tree_draggableanddropable' => PATH_t3lib . 'tree/interfaces/interface.t3lib_tree_draggableanddropable.php',
+       't3lib_tree_labeleditable' => PATH_t3lib . 'tree/interfaces/interface.t3lib_tree_labeleditable.php',
+       't3lib_tree_recordbasednode' => PATH_t3lib . 'tree/interfaces/interface.t3lib_tree_recordbasednode.php',
        't3lib_contextmenu_abstractcontextmenu' => PATH_t3lib . 'contextmenu/class.t3lib_contextmenu_abstractcontextmenu.php',
        't3lib_contextmenu_abstractdataprovider' => PATH_t3lib . 'contextmenu/class.t3lib_contextmenu_abstractdataprovider.php',
        't3lib_contextmenu_action' => PATH_t3lib . 'contextmenu/class.t3lib_contextmenu_action.php',
@@ -225,7 +224,8 @@ $t3libClasses = array(
        't3lib_contextmenu_pagetree_extdirect_contextmenu' => PATH_t3lib . 'contextmenu/pagetree/extdirect/class.t3lib_contextmenu_pagetree_extdirect_contextmenu.php',
        't3lib_tree_pagetree_dataprovider' => PATH_t3lib . 'tree/pagetree/class.t3lib_tree_pagetree_dataprovider.php',
        't3lib_tree_pagetree_node' => PATH_t3lib . 'tree/pagetree/class.t3lib_tree_pagetree_node.php',
-       't3lib_tree_extdirect_node' => PATH_t3lib . 'tree/extdirect/class.t3lib_tree_extdirect_node.php',
+       't3lib_tree_extjs_node' => PATH_t3lib . 'tree/extjs/class.t3lib_tree_extjs_node.php',
+       't3lib_tree_navigationtree_node' => PATH_t3lib . 'tree/navigationtree/class.t3lib_tree_navigationtree_node.php',
        't3lib_tree_pagetree_nodecollection' => PATH_t3lib . 'tree/pagetree/class.t3lib_tree_pagetree_nodecollection.php',
        't3lib_tree_pagetree_commands' => PATH_t3lib . 'tree/pagetree/class.t3lib_tree_pagetree_commands.php',
        't3lib_contextmenu_pagetree_dataprovider' => PATH_t3lib . 'contextmenu/pagetree/class.t3lib_contextmenu_pagetree_dataprovider.php',
@@ -238,4 +238,4 @@ $t3libClasses = array(
 $tslibClasses = require(PATH_typo3 . 'sysext/cms/ext_autoload.php');
 
 return array_merge($t3libClasses, $tslibClasses);
-?>
\ No newline at end of file
+?>
index 348d94c..a781831 100644 (file)
 *
 *  This copyright notice MUST APPEAR in all copies of the script!
 ***************************************************************/
-Ext.ns('Ext.ux.state');
-
-// dummy constructor
-Ext.ux.state.TreePanel = function() {};
-
 /**
  * State Provider for a tree panel
  */
-Ext.override(Ext.ux.state.TreePanel, {
+Ext.define('Ext.ux.state.TreePanel', {
+       extend: 'Ext.state.Stateful',
+
        /**
-        * Initializes the plugin
-        * @param {Ext.tree.TreePanel} tree
-        * @private
+        * Mixin constructor
+        * @param {Object} config
+        *
         */
-       init:function(tree) {
-               tree.lastSelectedNode = null;
-               tree.isRestoringState = false;
-               tree.stateHash = {};
-
-               // install event handlers on TreePanel
-               tree.on({
-                       // add path of expanded node to stateHash
-                        beforeexpandnode:function(n) {
-                               if (this.isRestoringState) {
-                                       return;
-                               }
-                               var saveID = n.id;
-                               this.stateHash[saveID.substr(1)] = 1;
-                       },
-
-                       // delete path and all subpaths of collapsed node from stateHash
-                       beforecollapsenode:function(n) {
-                               if (this.isRestoringState) {
-                                       return;
-                               }
-
-                               var deleteID = n.id;
-                               delete this.stateHash[deleteID.substr(1)];
-                       },
-
-                       beforeclick: function(node) {
-                               if (this.isRestoringState) {
-                                       return;
-                               }
-                               this.stateHash['lastSelectedNode'] = node.id;
-                       }
-               });
-
-                       // update state on node expand or collapse
-               tree.stateEvents = tree.stateEvents || [];
-               tree.stateEvents.push('expandnode', 'collapsenode', 'click');
-
-               // add state related props to the tree
-               Ext.apply(tree, {
-                       // keeps expanded nodes paths keyed by node.ids
-                       stateHash:{},
-
-                       restoreState: function() {
-                               this.isRestoringState = true;
-                                       // get last selected node
-                               for (var pageID in this.stateHash) {
-                                       var pageNode = this.getNodeById('p' + pageID);
-                                       if (pageNode) {
-                                               pageNode.on({
-                                                       expand: {
-                                                               single:true,
-                                                               scope:this,
-                                                               fn: this.restoreState
+       constructor: function (config) {
+               if (config.stateful) {
+                               // Install event handlers on TreePanel
+                       this.on({
+                                       // Add path of expanded node to stateHash
+                               beforeitemexpand: function (node) {
+                                               if (this.isRestoringState) {
+                                                       return;
+                                               }
+                                               this.stateHash[String(node.getNodeData('id'))] = node.getId();
+                                       },
+                                       // Delete collapsed node from stateHash
+                               beforeitemcollapse: function (node) {
+                                               if (this.isRestoringState) {
+                                                       return;
+                                               }
+                                               delete this.stateHash[String(node.getNodeData('id'))];
+                                       },
+                                       // Update last selected node in stateHash
+                               selectionchange: function (view, node) {
+                                       this.onStateChange();
+                                               if (this.isRestoringState) {
+                                                       return;
+                                               }
+                                               if (this.getSelectionModel().getLastSelected()) {
+                                                       this.stateHash['lastSelectedNode'] = this.getSelectionModel().getLastSelected().getId();
+                                               }
+                                       },
+                               scope: this
+                       });
+                               // Add/override state properties
+                       Ext.apply(this, {
+                                       // Update state on node expand, collapse or selection change
+                               stateEvents: ['itemexpand', 'itemcollapse', 'selectionchange'],
+                                       // Avoid updating state while restoring
+                               isRestoringState: false,
+                                       // State object
+                               stateHash: {},
+                               /**
+                                * Restore tree state into the saved state
+                                *
+                                */
+                               restoreState: function() {
+                                       if (this.stateful) {
+                                               this.isRestoringState = true;
+                                                       // Expand paths according to stateHash
+                                               for (var pageID in this.stateHash) {
+                                                       var pageNode = this.getStore().getNodeById(this.stateHash[pageID]);
+                                                       if (pageNode && !pageNode.isLeaf() && !pageNode.isExpanded()) {
+                                                               pageNode.on({
+                                                                       expand: {
+                                                                               single: true,
+                                                                               scope: this,
+                                                                               fn: this.restoreState
+                                                                       }
+                                                               });
+                                                               pageNode.set('expanded', true);
+                                                               pageNode.commit();
+                                                               this.refreshNode(pageNode);
+                                                               pageNode.fireEvent('expand', pageNode);
                                                        }
-                                               });
-                                               if (pageNode.expanded === false && pageNode.rendered == true) {
-                                                       pageNode.expand();
                                                }
-                                       }
-                               }
-                               if (this.stateHash['lastSelectedNode']) {
-                                       var node = this.getNodeById(this.stateHash['lastSelectedNode']);
-                                       if (node) {
-                                               this.selectPath(node.getPath());
-
-                                               var contentId = TYPO3.Backend.ContentContainer.getIdFromUrl() ||
-                                                       String(fsMod.recentIds['web']) || '-1';
-
-                                               var isCurrentSelectedNode = (
-                                                       String(node.attributes.nodeData.id) === contentId ||
-                                                       contentId.indexOf('pages' + String(node.attributes.nodeData.id)) !== -1
-                                               );
-
-                                               if (contentId !== '-1' && !isCurrentSelectedNode && this.app.isVisible() &&
-                                                       this.commandProvider && this.commandProvider.singleClick
-                                               ) {
-                                                       this.commandProvider.singleClick(node, this);
+                                                       // Get last selected node
+                                               if (this.stateHash['lastSelectedNode']) {
+                                                       var node = this.getStore().getNodeById(this.stateHash['lastSelectedNode']);
+                                                       if (node) {
+                                                               this.selectPath(node.getPath());
+                               
+                                                               var contentId = TYPO3.Backend.ContentContainer.getIdFromUrl() ||
+                                                                       String(fsMod.recentIds['web']) || '-1';
+                               
+                                                               var isCurrentSelectedNode = (
+                                                                       String(node.getNodeData('id')) === contentId ||
+                                                                       contentId.indexOf('pages' + node.getNodeData('id')) !== -1
+                                                               );
+                               
+                                                               if (contentId !== '-1' 
+                                                                       && !isCurrentSelectedNode
+                                                                       && this == this.app.getTree()
+                                                                       && this.commandProvider
+                                                                       && this.commandProvider.singleClick
+                                                               ) {
+                                                                       this.commandProvider.singleClick(node, this);
+                                                               }
+                                                       }
                                                }
+                                               this.isRestoringState = false;
                                        }
+                               },
+                               /**
+                                * Return stateHash for save by state manager
+                                *
+                                */
+                               getState: function() {
+                                       return {
+                                               stateHash: this.stateHash
+                                       };
                                }
-
-                               this.isRestoringState = false;
-                       },
-
-                       // apply state on tree initialization
-                       applyState:function(state) {
-                               if(state) {
-                                       Ext.apply(this, state);
-
-                                       // it is too early to expand paths here
-                                       // so do it once on root load
-                                       this.root.on({
-                                               load: {
-                                                       single:true,
-                                                       scope:this,
-                                                       fn: this.restoreState
-                                               }
-                                       });
-                               }
-                       },
-
-                       // returns stateHash for save by state manager
-                       getState:function() {
-                               return {stateHash:this.stateHash};
-                       }
-               });
+                       });
+                       this.callParent(arguments);
+               }
        }
 });
index 1dbb5b0..3b49474 100644 (file)
@@ -61,8 +61,8 @@ TYPO3.Components.PageTree.Actions = {
                tree.t3ContextInfo.inCopyMode = false;
 
                if (tree.t3ContextNode) {
-                       tree.t3ContextNode.attributes.nodeData.t3InCutMode = false;
-                       tree.t3ContextNode.attributes.nodeData.t3InCopyMode = false;
+                       tree.t3ContextNode.setNodeData('t3InCutMode', false);
+                       tree.t3ContextNode.setNodeData('t3InCopyMode', false);
                        tree.t3ContextNode = null;
                }
        },
@@ -71,51 +71,55 @@ TYPO3.Components.PageTree.Actions = {
         * Updates an existing node with the given alternative. The new tree node
         * is returned afterwards.
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Tree} tree
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {Boolean} isExpanded
         * @param {Object} updatedNode
         * @param {Function} callback
-        * @return {Ext.tree.TreeNode}
+        * @return {Ext.data.NodeInterface}
         */
-       updateNode: function(node, isExpanded, updatedNode, callback) {
+       updateNode: function(tree, node, isExpanded, updatedNode, callback) {
                if (!updatedNode) {
                        return null;
                }
 
-               updatedNode.uiProvider = node.ownerTree.uiProvider;
-               var newTreeNode = new Ext.tree.TreeNode(updatedNode);
+               var newTreeNode = Ext.create('TYPO3.Components.PageTree.Model', updatedNode);
 
                var refreshCallback = this.restoreNodeStateAfterRefresh;
                if (callback) {
-                       refreshCallback = refreshCallback.createSequence(callback);
+                       refreshCallback = Ext.Function.createSequence(refreshCallback, callback);
                }
 
                node.parentNode.replaceChild(newTreeNode, node);
-               newTreeNode.ownerTree.refreshNode(newTreeNode, refreshCallback);
-
+               newTreeNode.set('expanded', isExpanded);
+               tree.refreshNode(newTreeNode, refreshCallback, tree);
                return newTreeNode;
        },
 
        /**
         * Restores the node state
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Tree} tree
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {Boolean} isExpanded
         * @return {void}
         */
-       restoreNodeStateAfterRefresh: function(node, isExpanded) {
-               node.parentNode.expand(false, false);
-               if (isExpanded) {
-                       node.expand(false, false);
-               } else {
-                       node.collapse(false, false);
+       restoreNodeStateAfterRefresh: function (records, operation, successful) {
+               if (successful && operation.node) {
+                       var node = operation.node;
+                       node.parentNode.expand(false);
+                       if (node.isExpanded()) {
+                               node.expand(false);
+                       } else {
+                               node.collapse(false);
+                       }
                }
        },
 
        /**
         * Shows deletion confirmation window
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {TYPO3.Components.PageTree.Tree} tree
         * @param {Function} callback
         * @param {Boolean} recursiveDelete
@@ -130,10 +134,10 @@ TYPO3.Components.PageTree.Actions = {
                        message = TYPO3.Components.PageTree.LLL.recursiveDeleteDialogMessage;
                }
 
-               Ext.Msg.show({
+               Ext.MessageBox.show({
                        title: title,
                        msg: message,
-                       buttons: Ext.Msg.YESNO,
+                       buttons: Ext.MessageBox.YESNO,
                        fn: function (answer) {
                                if (answer === 'yes') {
                                        TYPO3.Components.PageTree.Actions.deleteNode(node, tree, callback);
@@ -141,21 +145,21 @@ TYPO3.Components.PageTree.Actions = {
                                }
                                return false;
                        },
-                       animEl: 'elId'
+                       animateTarget: tree.getView().getNode(node).id
                });
        },
 
        /**
         * Deletes a node directly
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {TYPO3.Components.PageTree.Tree} tree
         * @param {Function} callback
         * @return {void}
         */
        deleteNode: function(node, tree, callback) {
                TYPO3.Components.PageTree.Commands.deleteNode(
-                       node.attributes.nodeData,
+                       node.get('nodeData'),
                        function(response) {
                                var succeeded = this.evaluateResponse(response);
                                if (Ext.isFunction(callback)) {
@@ -165,7 +169,7 @@ TYPO3.Components.PageTree.Actions = {
                                if (succeeded) {
                                                // the node may not be removed in workspace mode
                                        if (top.TYPO3.configuration.inWorkspace && response.id) {
-                                               this.updateNode(node, node.isExpanded(), response);
+                                               this.updateNode(tree, node, node.isExpanded(), response);
                                        } else {
                                                node.remove();
                                        }
@@ -178,13 +182,13 @@ TYPO3.Components.PageTree.Actions = {
        /**
         * Removes a node either directly or first shows deletion popup
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {TYPO3.Components.PageTree.Tree} tree
         * @return {void}
         */
        removeNode: function(node, tree) {
                if (TYPO3.Components.PageTree.Configuration.displayDeleteConfirmation) {
-                       this.confirmDelete(node);
+                       this.confirmDelete(node, tree);
                } else {
                        this.deleteNode(node, tree);
                }
@@ -194,19 +198,19 @@ TYPO3.Components.PageTree.Actions = {
         * Restores a given node and moves it to the given destination inside the tree. Use this
         * method if you want to add it as the first child of the destination.
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {Ext.data.NodeInterface} node
         * @param {TYPO3.Components.PageTree.Tree} tree
-        * @param {Ext.tree.TreeNode} destination
+        * @param {Ext.data.NodeInterface} destination
         * @return {void}
         */
        restoreNodeToFirstChildOfDestination: function(node, tree, destination) {
                TYPO3.Components.PageTree.Commands.restoreNode(
-                       node.attributes.nodeData,
-                       destination.attributes.nodeData.id,
-                       function(updatedNode) {
+                       node.get('nodeData'),
+                       destination.get('nodeData').id,
+                       function (updatedNode) {
                                if (this.evaluateResponse(updatedNode)) {
-                                       var newTreeNode = new Ext.tree.TreeNode(
-                                               Ext.apply(node.attributes, updatedNode)
+                                       var newTreeNode = Ext.create('TYPO3.Components.PageTree.Model',
+                                               Ext.apply(node.fields, updatedNode)
                                        );
                                        destination.insertBefore(newTreeNode, destination.firstChild);
                                }
@@ -219,19 +223,19 @@ TYPO3.Components.PageTree.Actions = {
         * Restores a given node and moves it to the given destination inside the tree. Use this
         * method if you want to add the node after the destination node.
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {TYPO3.Components.PageTree.Tree} tree
-        * @param {Ext.tree.TreeNode} destination
+        * @param {TYPO3.Components.PageTree.Model} destination
         * @return {void}
         */
        restoreNodeAfterDestination: function(node, tree, destination) {
                TYPO3.Components.PageTree.Commands.restoreNode(
-                       node.attributes.nodeData,
-                       -destination.attributes.nodeData.id,
-                       function(updatedNode) {
+                       node.get('nodeData'),
+                       -destination.get('nodeData').id,
+                       function (updatedNode) {
                                if (this.evaluateResponse(updatedNode)) {
-                                       var newTreeNode = new Ext.tree.TreeNode(
-                                               Ext.apply(node.attributes, updatedNode)
+                                       var newTreeNode = Ext.create('TYPO3.Components.PageTree.Model',
+                                               Ext.apply(node.fields, updatedNode)
                                        );
                                        destination.parentNode.insertBefore(newTreeNode, destination.nextSibling);
                                }
@@ -243,7 +247,7 @@ TYPO3.Components.PageTree.Actions = {
        /**
         * Collapses a whole tree branch
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @return {void}
         */
        collapseBranch: function(node) {
@@ -253,7 +257,7 @@ TYPO3.Components.PageTree.Actions = {
        /**
         * Expands a whole tree branch
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @return {void}
         */
        expandBranch: function(node) {
@@ -263,13 +267,13 @@ TYPO3.Components.PageTree.Actions = {
        /**
         * Opens a popup windows for previewing the given node/page
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @return {void}
         */
        viewPage: function(node) {
                var frontendWindow = window.open('', 'newTYPO3frontendWindow');
                TYPO3.Components.PageTree.Commands.getViewLink(
-                       node.attributes.nodeData,
+                       node.get('nodeData'),
                        function(result) {
                                frontendWindow.location = result;
                                frontendWindow.focus();
@@ -280,13 +284,13 @@ TYPO3.Components.PageTree.Actions = {
        /**
         * Creates a temporary tree mount point
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {TYPO3.Components.PageTree.Tree} tree
         * @return {void}
         */
        mountAsTreeRoot: function(node, tree) {
                TYPO3.Components.PageTree.Commands.setTemporaryMountPoint(
-                       node.attributes.nodeData,
+                       node.get('nodeData'),
                        function(response) {
                                if (TYPO3.Components.PageTree.Configuration.temporaryMountPoint) {
                                        TYPO3.Backend.NavigationContainer.PageTree.removeIndicator(
@@ -297,19 +301,18 @@ TYPO3.Components.PageTree.Actions = {
                                TYPO3.Components.PageTree.Configuration.temporaryMountPoint = response;
                                TYPO3.Backend.NavigationContainer.PageTree.addTemporaryMountPointIndicator();
 
-                               var selectedNode = TYPO3.Backend.NavigationContainer.PageTree.getSelected();
+                               var selectedNode = tree.getSelectionModel().getLastSelected();
                                tree.stateId = 'Pagetree' + TYPO3.Components.PageTree.Configuration.temporaryMountPoint;
-                               tree.refreshTree(function() {
-                                       var nodeIsSelected = false;
+                                       // Refresh tree and restore last selection if under the temporary mount
+                               tree.refreshTree(function () {
+                                       var selectionModel = tree.getSelectionModel();
                                        if (selectedNode) {
-                                               nodeIsSelected = TYPO3.Backend.NavigationContainer.PageTree.select(
-                                                       selectedNode.attributes.nodeData.id
-                                               );
+                                               selectionModel.deselect(selectedNode);
+                                               selectionModel.select(selectedNode);
                                        }
-
-                                       var node = (nodeIsSelected ? TYPO3.Backend.NavigationContainer.PageTree.getSelected() : null);
-                                       if (node) {
-                                               this.singleClick(node, tree);
+                                       selectedNode = selectionModel.getLastSelected();
+                                       if (selectedNode) {
+                                               this.singleClick(selectedNode, tree);
                                        } else {
                                                this.singleClick(tree.getRootNode().firstChild, tree);
                                        }
@@ -322,63 +325,67 @@ TYPO3.Components.PageTree.Actions = {
        /**
         * Opens the edit page properties dialog
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
+        * @param {TYPO3.Components.PageTree.Tree} tree
         * @return {void}
         */
-       editPageProperties: function(node) {
-               node.select();
+       editPageProperties: function(node, tree) {
+               tree.getSelectionModel().select(node);
                TYPO3.Backend.ContentContainer.setUrl(
-                       'alt_doc.php?edit[pages][' + node.attributes.nodeData.id + ']=edit'
+                       'alt_doc.php?edit[pages][' + node.getNodeData('id') + ']=edit'
                );
        },
 
        /**
         * Opens the new page wizard
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
+        * @param {TYPO3.Components.PageTree.Tree} tree
         * @return {void}
         */
-       newPageWizard: function(node) {
-               node.select();
+       newPageWizard: function(node, tree) {
+               tree.getSelectionModel().select(node);
                TYPO3.Backend.ContentContainer.setUrl(
-                       'db_new.php?id=' + node.attributes.nodeData.id + '&pagesOnly=1'
+                       'db_new.php?id=' + node.getNodeData('id') + '&pagesOnly=1'
                );
        },
 
        /**
         * Opens the info popup
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @return {void}
         */
        openInfoPopUp: function(node) {
-               launchView('pages', node.attributes.nodeData.id);
+               launchView('pages', node.getNodeData('id'));
        },
 
        /**
         * Opens the history popup
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
+        * @param {TYPO3.Components.PageTree.Tree} tree  
         * @return {void}
         */
-       openHistoryPopUp: function(node) {
-               node.select();
+       openHistoryPopUp: function(node, tree) {
+               tree.getSelectionModel().select(node);
                TYPO3.Backend.ContentContainer.setUrl(
-                       'show_rechis.php?element=pages:' + node.attributes.nodeData.id
+                       'show_rechis.php?element=pages:' + node.getNodeData('id')
                );
        },
 
        /**
         * Opens the export .t3d file dialog
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
+        * @param {TYPO3.Components.PageTree.Tree} tree
         * @return {void}
         */
-       exportT3d: function(node) {
-               node.select();
+       exportT3d: function(node, tree) {
+               tree.getSelectionModel().select(node);
                TYPO3.Backend.ContentContainer.setUrl(
                        'sysext/impexp/app/index.php?tx_impexp[action]=export&' +
-                               'id=0&tx_impexp[pagetree][id]=' + node.attributes.nodeData.id +
+                               'id=0&tx_impexp[pagetree][id]=' + node.getNodeData('id') +
                                '&tx_impexp[pagetree][levels]=0' +
                                '&tx_impexp[pagetree][tables][]=_ALL'
                );
@@ -387,13 +394,14 @@ TYPO3.Components.PageTree.Actions = {
        /**
         * Opens the import .t3d file dialog
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
+        * @param {TYPO3.Components.PageTree.Tree} tree 
         * @return {void}
         */
-       importT3d: function(node) {
-               node.select();
+       importT3d: function(node, tree) {
+               tree.getSelectionModel().select(node);
                TYPO3.Backend.ContentContainer.setUrl(
-                       'sysext/impexp/app/index.php?id=' + node.attributes.nodeData.id +
+                       'sysext/impexp/app/index.php?id=' + node.getNodeData('id') +
                                '&table=pages&tx_impexp[action]=import'
                );
        },
@@ -401,13 +409,13 @@ TYPO3.Components.PageTree.Actions = {
        /**
         * Enables the cut mode of a node
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {TYPO3.Components.PageTree.Tree} tree
         * @return {void}
         */
        enableCutMode: function(node, tree) {
                this.disableCopyMode(node, tree);
-               node.attributes.nodeData.t3InCutMode = true;
+               node.setNodeData('t3InCutMode', true);
                tree.t3ContextInfo.inCutMode = true;
                tree.t3ContextNode = node;
        },
@@ -415,25 +423,25 @@ TYPO3.Components.PageTree.Actions = {
        /**
         * Disables the cut mode of a node
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {TYPO3.Components.PageTree.Tree} tree
         * @return {void}
         */
        disableCutMode: function(node, tree) {
                this.releaseCutAndCopyModes(tree);
-               node.attributes.nodeData.t3InCutMode = false;
+               node.setNodeData('t3InCutMode', false);
        },
 
        /**
         * Enables the copy mode of a node
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {TYPO3.Components.PageTree.Tree} tree
         * @return {void}
         */
        enableCopyMode: function(node, tree) {
                this.disableCutMode(node, tree);
-               node.attributes.nodeData.t3InCopyMode = true;
+               node.setNodeData('t3InCopyMode', true);
                tree.t3ContextInfo.inCopyMode = true;
                tree.t3ContextNode = node;
        },
@@ -441,19 +449,19 @@ TYPO3.Components.PageTree.Actions = {
        /**
         * Disables the copy mode of a node
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {TYPO3.Components.PageTree.Tree} tree
         * @return {void}
         */
        disableCopyMode: function(node, tree) {
                this.releaseCutAndCopyModes(tree);
-               node.attributes.nodeData.t3InCopyMode = false;
+               node.setNodeData('t3InCopyMode', false);
        },
 
        /**
         * Pastes the cut/copy context node into the given node
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {TYPO3.Components.PageTree.Tree} tree
         * @return {void}
         */
@@ -463,10 +471,10 @@ TYPO3.Components.PageTree.Actions = {
                }
 
                if (tree.t3ContextInfo.inCopyMode) {
-                       var newNode = tree.t3ContextNode = new Ext.tree.TreeNode(tree.t3ContextNode.attributes);
+                       var newNode = tree.t3ContextNode = Ext.create('TYPO3.Components.PageTree.Model', tree.t3ContextNode.fields);
                        newNode.id = 'fakeNode';
                        node.insertBefore(newNode, node.childNodes[0]);
-                       node.attributes.nodeData.t3InCopyMode = false;
+                       node.setNodeData('t3InCopyMode', false);
                        this.copyNodeToFirstChildOfDestination(newNode, tree);
 
                } else if (tree.t3ContextInfo.inCutMode) {
@@ -475,7 +483,7 @@ TYPO3.Components.PageTree.Actions = {
                        }
 
                        node.appendChild(tree.t3ContextNode);
-                       node.attributes.nodeData.t3InCutMode = false;
+                       node.setNodeData('t3InCutMode', false);
                        this.moveNodeToFirstChildOfDestination(node, tree);
                }
        },
@@ -483,7 +491,7 @@ TYPO3.Components.PageTree.Actions = {
        /**
         * Pastes a cut/copy context node after the given node
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {TYPO3.Components.PageTree.Tree} tree
         * @return {void}
         */
@@ -493,19 +501,18 @@ TYPO3.Components.PageTree.Actions = {
                }
 
                if (tree.t3ContextInfo.inCopyMode) {
-                       var newNode = tree.t3ContextNode = new Ext.tree.TreeNode(tree.t3ContextNode.attributes);
+                       var newNode = tree.t3ContextNode = Ext.create('TYPO3.Components.PageTree.Model', tree.t3ContextNode.fields);
                        newNode.id = 'fakeNode';
                        node.parentNode.insertBefore(newNode, node.nextSibling);
-                       node.attributes.nodeData.t3InCopyMode = false;
+                       node.setNodeData('t3InCopyMode', false);
                        this.copyNodeAfterDestination(newNode, tree);
 
                } else if (tree.t3ContextInfo.inCutMode) {
                        if (node.getPath().indexOf(tree.t3ContextNode.id) !== -1) {
                                return;
                        }
-
                        node.parentNode.insertBefore(tree.t3ContextNode, node.nextSibling);
-                       node.attributes.nodeData.t3InCutMode = false;
+                       node.setNodeData('t3InCutMode', false);
                        this.moveNodeAfterDestination(node, tree);
                }
        },
@@ -513,17 +520,17 @@ TYPO3.Components.PageTree.Actions = {
        /**
         * Moves the current tree context node after the given node
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {TYPO3.Components.PageTree.Tree} tree
         * @return {void}
         */
        moveNodeAfterDestination: function(node, tree) {
                TYPO3.Components.PageTree.Commands.moveNodeAfterDestination(
-                       tree.t3ContextNode.attributes.nodeData,
-                       node.attributes.nodeData.id,
-                       function(response) {
+                       tree.t3ContextNode.get('nodeData'),
+                       node.getNodeData('id'),
+                       function (response) {
                                if (this.evaluateResponse(response) && tree.t3ContextNode) {
-                                       this.updateNode(tree.t3ContextNode, tree.t3ContextNode.isExpanded(), response);
+                                       this.updateNode(tree, tree.t3ContextNode, tree.t3ContextNode.isExpanded(), response);
                                }
                                this.releaseCutAndCopyModes(tree);
                        },
@@ -534,17 +541,17 @@ TYPO3.Components.PageTree.Actions = {
        /**
         * Moves the current tree context node as the first child of the given node
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {TYPO3.Components.PageTree.Tree} tree
         * @return {void}
         */
        moveNodeToFirstChildOfDestination: function(node, tree) {
                TYPO3.Components.PageTree.Commands.moveNodeToFirstChildOfDestination(
-                       tree.t3ContextNode.attributes.nodeData,
-                       node.attributes.nodeData.id,
-                       function(response) {
+                       tree.t3ContextNode.get('nodeData'),
+                       node.getNodeData('id'),
+                       function (response) {
                                if (this.evaluateResponse(response) && tree.t3ContextNode) {
-                                       this.updateNode(tree.t3ContextNode, tree.t3ContextNode.isExpanded(), response);
+                                       this.updateNode(tree, tree.t3ContextNode, tree.t3ContextNode.isExpanded(), response);
                                }
                                this.releaseCutAndCopyModes(tree);
                        },
@@ -555,19 +562,21 @@ TYPO3.Components.PageTree.Actions = {
        /**
         * Inserts a new node after the given node
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {TYPO3.Components.PageTree.Tree} tree
         * @return {void}
         */
-       insertNodeAfterDestination: function(node, tree) {
+       insertNodeAfterDestination: function (node, tree) {
                TYPO3.Components.PageTree.Commands.insertNodeAfterDestination(
-                       tree.t3ContextNode.attributes.nodeData,
-                       node.previousSibling.attributes.nodeData.id,
+                       tree.t3ContextNode.get('nodeData'),
+                       node.previousSibling.getNodeData('id'),
                        tree.t3ContextInfo.serverNodeType,
-                       function(response) {
+                       function (response) {
                                if (this.evaluateResponse(response)) {
-                                       this.updateNode(node, node.isExpanded(), response, function(node) {
-                                               tree.triggerEdit(node);
+                                       this.updateNode(tree, node, node.isExpanded(), response, function (records, operation, successful) {
+                                               if (successful && operation.node) {
+                                                       tree.getPlugin('treeEditor').startEdit(operation.node, tree.getView().getHeaderAtIndex(0));
+                                               }
                                        });
                                }
                                this.releaseCutAndCopyModes(tree);
@@ -579,18 +588,20 @@ TYPO3.Components.PageTree.Actions = {
        /**
         * Inserts a new node as the first child of the given node
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {TYPO3.Components.PageTree.Tree} tree
         * @return {void}
         */
        insertNodeToFirstChildOfDestination: function(node, tree) {
                TYPO3.Components.PageTree.Commands.insertNodeToFirstChildOfDestination(
-                       tree.t3ContextNode.attributes.nodeData,
+                       tree.t3ContextNode.get('nodeData'),
                        tree.t3ContextInfo.serverNodeType,
-                       function(response) {
+                       function (response) {
                                if (this.evaluateResponse(response)) {
-                                       this.updateNode(node, true, response, function(node) {
-                                               tree.triggerEdit(node);
+                                       this.updateNode(tree, node, true, response, function (records, operation, successful) {
+                                               if (successful && operation.node) {
+                                                       tree.getPlugin('treeEditor').startEdit(operation.node, tree.getView().getHeaderAtIndex(0));
+                                               }
                                        });
                                }
                                this.releaseCutAndCopyModes(tree);
@@ -602,18 +613,20 @@ TYPO3.Components.PageTree.Actions = {
        /**
         * Copies the current tree context node after the given node
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {TYPO3.Components.PageTree.Tree} tree
         * @return {void}
         */
        copyNodeAfterDestination: function(node, tree) {
                TYPO3.Components.PageTree.Commands.copyNodeAfterDestination(
-                       tree.t3ContextNode.attributes.nodeData,
-                       node.previousSibling.attributes.nodeData.id,
-                       function(response) {
+                       tree.t3ContextNode.get('nodeData'),
+                       node.previousSibling.getNodeData('id'),
+                       function (response) {
                                if (this.evaluateResponse(response)) {
-                                       this.updateNode(node, true, response, function(node) {
-                                               tree.triggerEdit(node);
+                                       this.updateNode(tree, node, true, response, function (records, operation, successful) {
+                                               if (successful && operation.node) {
+                                                       tree.getPlugin('treeEditor').startEdit(operation.node, tree.getView().getHeaderAtIndex(0));
+                                               }
                                        });
                                }
                                this.releaseCutAndCopyModes(tree);
@@ -625,18 +638,20 @@ TYPO3.Components.PageTree.Actions = {
        /**
         * Copies the current tree context node as the first child of the given node
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {TYPO3.Components.PageTree.Tree} tree
         * @return {void}
         */
        copyNodeToFirstChildOfDestination: function(node, tree) {
                TYPO3.Components.PageTree.Commands.copyNodeToFirstChildOfDestination(
-                       tree.t3ContextNode.attributes.nodeData,
-                       node.parentNode.attributes.nodeData.id,
-                       function(response) {
+                       tree.t3ContextNode.get('nodeData'),
+                       node.parentNode.getNodeData('id'),
+                       function (response) {
                                if (this.evaluateResponse(response)) {
-                                       this.updateNode(node, true, response, function(node) {
-                                               tree.triggerEdit(node);
+                                       this.updateNode(tree, node, true, response, function (records, operation, successful) {
+                                               if (successful && operation.node) {
+                                                       tree.getPlugin('treeEditor').startEdit(operation.node, tree.getView().getHeaderAtIndex(0));
+                                               }
                                        });
                                }
                                this.releaseCutAndCopyModes(tree);
@@ -648,15 +663,16 @@ TYPO3.Components.PageTree.Actions = {
        /**
         * Visibilizes a page
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {Ext.data.NodeInterface} node
+        * @param {TYPO3.Components.PageTree.Tree} tree
         * @return {void}
         */
-       enablePage: function(node) {
+       enablePage: function(node, tree) {
                TYPO3.Components.PageTree.Commands.visiblyNode(
-                       node.attributes.nodeData,
+                       node.get('nodeData'),
                        function(response) {
                                if (this.evaluateResponse(response)) {
-                                       this.updateNode(node, node.isExpanded(), response);
+                                       this.updateNode(tree, node, node.isExpanded(), response);
                                }
                        },
                        this
@@ -666,15 +682,16 @@ TYPO3.Components.PageTree.Actions = {
        /**
         * Disables a page
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {Ext.data.NodeInterface} node
+        * @param {TYPO3.Components.PageTree.Tree} tree
         * @return {void}
         */
-       disablePage: function(node) {
+       disablePage: function(node, tree) {
                TYPO3.Components.PageTree.Commands.disableNode(
-                       node.attributes.nodeData,
-                       function(response) {
+                       node.get('nodeData'),
+                       function (response) {
                                if (this.evaluateResponse(response)) {
-                                       this.updateNode(node, node.isExpanded(), response);
+                                       this.updateNode(tree, node, node.isExpanded(), response);
                                }
                        },
                        this
@@ -684,11 +701,11 @@ TYPO3.Components.PageTree.Actions = {
        /**
         * Reloads the content frame with the current module and node id
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {TYPO3.Components.PageTree.Tree} tree
         * @return {void}
         */
-       singleClick: function(node, tree) {
+       singleClick: function (node, tree) {
                tree.currentSelectedNode = node;
 
                var separator = '?';
@@ -696,68 +713,77 @@ TYPO3.Components.PageTree.Actions = {
                        separator = '&';
                }
 
-               node.select();
-               if (tree.stateHash) {
-                       tree.stateHash.lastSelectedNode = node.id;
-               }
+               tree.getSelectionModel().select(node);
 
-               fsMod.recentIds['web'] = node.attributes.nodeData.id;
+               fsMod.recentIds['web'] = node.getNodeData('id');
 
                TYPO3.Backend.ContentContainer.setUrl(
-                       TS.PATH_typo3 + currentSubScript + separator + 'id=' + node.attributes.nodeData.id
+                       TS.PATH_typo3 + currentSubScript + separator + 'id=' + node.getNodeData('id')
                );
        },
 
        /**
         * Opens a configured url inside the content frame
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {TYPO3.Components.PageTree.Tree} tree
         * @param {Object} contextItem
         * @return {void}
         */
-       openCustomUrlInContentFrame: function(node, tree, contextItem) {
+       openCustomUrlInContentFrame: function (node, tree, contextItem) {
                if (!contextItem.customAttributes || !contextItem.customAttributes.contentUrl) {
                        return;
                }
 
-               node.select();
+               tree.getSelectionModel().select(node);
                TYPO3.Backend.ContentContainer.setUrl(
-                       contextItem.customAttributes.contentUrl.replace('###ID###', node.attributes.nodeData.id)
+                       contextItem.customAttributes.contentUrl.replace('###ID###', node.getNodeData('id'))
                );
        },
 
        /**
         * Updates the title of a node
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {String} newText
         * @param {String} oldText
         * @param {TYPO3.Components.PageTree.TreeEditor} treeEditor
+        * @param {TYPO3.Components.PageTree.Tree} tree
+        * @param {String} dataIndex
         * @return {void}
         */
-       saveTitle: function(node, newText, oldText, treeEditor) {
-               this.singleClick(node.editNode, node.editNode.ownerTree);
+       saveTitle: function (node, newText, oldText, treeEditor, tree, dataIndex) {
+               this.singleClick(node, tree);
                if (newText === oldText || newText == '') {
                        treeEditor.updateNodeText(
                                node,
-                               node.editNode.attributes.nodeData.editableText,
-                               Ext.util.Format.htmlEncode(oldText)
+                               node.getNodeData('editableText'),
+                               Ext.util.Format.htmlEncode(oldText),
+                               dataIndex,
+                               tree
                        );
                        return;
                }
 
                TYPO3.Components.PageTree.Commands.updateLabel(
-                       node.editNode.attributes.nodeData,
+                       node.get('nodeData'),
                        newText,
                        function(response) {
                                if (this.evaluateResponse(response)) {
-                                       treeEditor.updateNodeText(node, response.editableText, response.updatedText);
+                                       treeEditor.updateNodeText(
+                                               node,
+                                               response.editableText,
+                                               response.updatedText,
+                                               dataIndex,
+                                               tree
+                                       );
                                } else {
                                        treeEditor.updateNodeText(
                                                node,
-                                               node.editNode.attributes.nodeData.editableText,
-                                               Ext.util.Format.htmlEncode(oldText)
+                                               node.getNodeData('editableText'),
+                                               Ext.util.Format.htmlEncode(oldText),
+                                               dataIndex,
+                                               tree
                                        );
                                }
                        },
index 6a178f5..2701f93 100644 (file)
 *
 *  This copyright notice MUST APPEAR in all copies of the script!
 ***************************************************************/
-Ext.namespace('TYPO3.Components.PageTree');
-
 /**
  * @class TYPO3.Components.PageTree.App
  *
  * Page tree main application that controls setups the components
  *
  * @namespace TYPO3.Components.PageTree
- * @extends Ext.Panel
+ * @extends Ext.panel.Panel
  * @author Stefan Galinski <stefan.galinski@gmail.com>
  */
-TYPO3.Components.PageTree.App = Ext.extend(Ext.Panel, {
+Ext.define('TYPO3.Components.PageTree.App', {
+       extend: 'Ext.panel.Panel',
+
        /**
         * Panel id
         *
@@ -45,7 +45,7 @@ TYPO3.Components.PageTree.App = Ext.extend(Ext.Panel, {
        /**
         * Border
         *
-        * @type {Boolean}
+        * @type {String}
         */
        border: false,
 
@@ -54,14 +54,38 @@ TYPO3.Components.PageTree.App = Ext.extend(Ext.Panel, {
         *
         * @type {String}
         */
-       layout:'fit',
+       layout: 'border',
 
        /**
-        * Active tree
+        * Components defaults
         *
-        * @type {TYPO3.Components.PageTree.Tree}
+        * @type {Object}
         */
-       activeTree: null,
+        defaults: {
+                border: false,
+        },
+       
+       /**
+        * Tree containe
+        *
+        * @type {String}
+        */
+        items: [{
+                       itemId: 'topPanelItems',
+                       height: 49,
+                       region: 'north',
+                       cls: 'typo3-pageTree-topPanelItems'
+               },{
+                       itemId: 'treeContainer',
+                       autoScroll: false,
+                       layout: 'card',
+                       region: 'center'
+               },{
+                       xtype: 'container',
+                       itemId: 'deletionDropZoneContainer',
+                       cls: 'typo3-pageTree-deletionDropZoneContainer',
+                       region: 'south'
+        }],
 
        /**
         * Initializes the application
@@ -72,112 +96,89 @@ TYPO3.Components.PageTree.App = Ext.extend(Ext.Panel, {
         * @return {void}
         */
        initComponent: function() {
-               TYPO3.Components.PageTree.DataProvider.loadResources(function(response) {
-                       TYPO3.Components.PageTree.LLL = response['LLL'];
-                       TYPO3.Components.PageTree.Configuration = response['Configuration'];
-                       TYPO3.Components.PageTree.Sprites = response['Sprites'];
-
-                       var tree = this.activeTree = new TYPO3.Components.PageTree.Tree({
-                               id: this.id + '-tree',
-                               deletionDropZoneId: this.id + '-deletionDropZone',
-                               ddGroup: this.id,
-                               stateful: true,
-                               stateId: 'Pagetree' + TYPO3.Components.PageTree.Configuration.temporaryMountPoint,
-                               stateEvents: [],
-                               autoScroll: true,
-                               autoHeight: false,
-                               plugins: new Ext.ux.state.TreePanel(),
-                               commandProvider: TYPO3.Components.PageTree.Actions,
-                               contextMenuProvider: TYPO3.Components.PageTree.ContextMenuDataProvider,
-                               treeDataProvider: TYPO3.Components.PageTree.DataProvider,
-                               app: this,
-                               listeners: {
-                                       resize: {
-                                               fn: function() {
-                                                       var treeContainer = Ext.getCmp(this.id + '-treeContainer');
-                                                       Ext.getCmp(this.id + '-filteringTree').setSize(treeContainer.getSize());
-                                                       treeContainer.doLayout();
-                                               },
-                                               scope: this,
-                                               buffer: 250
-                                       }
-                               }
-                       });
-
-                       var filteringTree = new TYPO3.Components.PageTree.FilteringTree({
-                               id: this.id + '-filteringTree',
-                               deletionDropZoneId: this.id + '-deletionDropZone',
-                               ddGroup: this.id,
-                               autoScroll: true,
-                               autoHeight: false,
-                               commandProvider: TYPO3.Components.PageTree.Actions,
-                               contextMenuProvider: TYPO3.Components.PageTree.ContextMenuDataProvider,
-                               treeDataProvider: TYPO3.Components.PageTree.DataProvider,
-                               app: this
-                       }).hide();
-
-                       var topPanel = new TYPO3.Components.PageTree.TopPanel({
-                               dataProvider: TYPO3.Components.PageTree.DataProvider,
-                               filteringTree: filteringTree,
-                               ddGroup: this.id,
-                               tree: tree,
-                               app: this
-                       });
-
-                       var deletionDropZone = new TYPO3.Components.PageTree.DeletionDropZone({
-                               id: this.id + '-deletionDropZone',
-                               commandProvider: TYPO3.Components.PageTree.Actions,
-                               ddGroup: this.id,
-                               app: this,
-                               region: 'south',
-                               height: 35
-                       });
-
-                       var topPanelItems = new Ext.Panel({
-                               id: this.id + '-topPanelItems',
-                               border: false,
-                               region: 'north',
-                               height: 49,
-                               items: [
-                                       topPanel, {
-                                               border: false,
-                                               id: this.id + '-indicatorBar'
-                                       }
-                               ]
-                       });
-
-                       this.add({
-                               layout: 'border',
-                               items: [
-                                       topPanelItems,
-                                       {
-                                               border: false,
-                                               id: this.id + '-treeContainer',
-                                               region: 'center',
-                                               layout: 'fit',
-                                               items: [tree, filteringTree]
-                                       },
-                                       deletionDropZone
-                               ]
-                       });
-
-                       if (TYPO3.Components.PageTree.Configuration.temporaryMountPoint) {
-                               topPanelItems.on('afterrender', function() {
+               this.addListener('render', function () {
+                       TYPO3.Components.PageTree.DataProvider.loadResources(function(response) {
+                               TYPO3.Components.PageTree.LLL = response['LLL'];
+                               TYPO3.Components.PageTree.Configuration = response['Configuration'];
+                               TYPO3.Components.PageTree.Sprites = response['Sprites'];
+       
+                               var tree = Ext.create('TYPO3.Components.PageTree.Tree', {
+                                       id: this.getId() + '-tree',
+                                       deletionDropZoneId: this.getId() + '-deletionDropZone',
+                                       ddGroup: this.getId(),
+                                       stateful: true,
+                                       stateId: 'Pagetree' + TYPO3.Components.PageTree.Configuration.temporaryMountPoint,
+                                       commandProvider: TYPO3.Components.PageTree.Actions,
+                                       contextMenuProvider: TYPO3.Components.PageTree.ContextMenuDataProvider,
+                                       treeDataProvider: TYPO3.Components.PageTree.DataProvider,
+                                       app: this
+                               });
+       
+                               var filteringTree = Ext.create('TYPO3.Components.PageTree.FilteringTree', {
+                                       id: this.getId() + '-filteringTree',
+                                       deletionDropZoneId: this.getId() + '-deletionDropZone',
+                                       ddGroup: this.getId(),
+                                       commandProvider: TYPO3.Components.PageTree.Actions,
+                                       contextMenuProvider: TYPO3.Components.PageTree.ContextMenuDataProvider,
+                                       stateful: false,
+                                       treeDataProvider: TYPO3.Components.PageTree.DataProvider,
+                                       app: this
+                               });
+       
+                               var topPanelItems = this.getComponent('topPanelItems');
+                               topPanelItems.add([
+                                               Ext.create('TYPO3.Components.PageTree.TopPanel', {
+                                                       border: false,
+                                                       dataProvider: TYPO3.Components.PageTree.DataProvider,
+                                                       filteringTree: filteringTree,
+                                                       ddGroup: this.getId(),
+                                                       height: 49,
+                                                       itemId: 'topPanel',
+                                                       tree: tree,
+                                                       app: this
+                                               }),
+                                               {
+                                                       xtype: 'container',
+                                                       border: false,
+                                                       defaultType: 'component',
+                                                       id: this.getId() + '-indicatorBar',
+                                                       itemId: 'indicatorBar'
+                                               }
+                               ]);
+       
+                               var treeContainer = this.getComponent('treeContainer');
+                               treeContainer.add([tree, filteringTree]);
+                               treeContainer.addListener(
+                                       'render',
+                                       function (panel) { panel.getLayout().setActiveItem(0); }
+                               );
+       
+                               var deletionDropZoneContainer = this.getComponent('deletionDropZoneContainer');
+                               deletionDropZoneContainer.add({
+                                       xtype: 'typo3deletiondropzone',
+                                       height: 35,
+                                       id: this.getId() + '-deletionDropZone',
+                                       commandProvider: TYPO3.Components.PageTree.Actions,
+                                       ddGroup: this.getId(),
+                                       layout: 'anchor',
+                                       app: this
+                               });
+
+                               if (TYPO3.Components.PageTree.Configuration.temporaryMountPoint) {
                                        this.addTemporaryMountPointIndicator();
-                               }, this);
-                       }
-
-                       if (TYPO3.Components.PageTree.Configuration.indicator !== '') {
-                               this.addIndicatorItems();
-                       }
-                       this.doLayout();
-
-                       this.ownerCt.on('resize', function() {
+                               }
+       
+                               if (TYPO3.Components.PageTree.Configuration.indicator !== '') {
+                                       this.addIndicatorItems();
+                               }
                                this.doLayout();
-                       });
+       
+                               this.ownerCt.on('resize', function() {
+                                       this.doLayout();
+                               }, this);
+                       }, this);
                }, this);
-
-               TYPO3.Components.PageTree.App.superclass.initComponent.apply(this, arguments);
+               this.callParent();
        },
 
        /**
@@ -187,9 +188,8 @@ TYPO3.Components.PageTree.App = Ext.extend(Ext.Panel, {
         */
        addIndicatorItems: function() {
                this.addIndicator({
-                       border: false,
-                       id: this.id + '-indicatorBar-indicatorTitle',
-                       cls: this.id + '-indicatorBar-item',
+                       id: this.getId() + '-indicatorBar-indicatorTitle',
+                       cls: this.getId() + '-indicatorBar-item',
                        html: TYPO3.Components.PageTree.Configuration.indicator
                });
        },
@@ -201,14 +201,13 @@ TYPO3.Components.PageTree.App = Ext.extend(Ext.Panel, {
         */
        addTemporaryMountPointIndicator: function() {
                this.temporaryMountPointInfoIndicator = this.addIndicator({
-                       border: false,
-                       id: this.id + '-indicatorBar-temporaryMountPoint',
-                       cls: this.id + '-indicatorBar-item',
+                       id: this.getId() + '-indicatorBar-temporaryMountPoint',
+                       cls: this.getId() + '-indicatorBar-item',
 
                        listeners: {
                                afterrender: {
                                        fn: function() {
-                                               var element = Ext.fly(this.id + '-indicatorBar-temporaryMountPoint-clear');
+                                               var element = Ext.get(this.getId() + '-indicatorBar-temporaryMountPoint-clear');
                                                element.on('click', function() {
                                                        TYPO3.BackendUserSettings.ExtDirect.unsetKey(
                                                                'pageTree_temporaryMountPoint',
@@ -225,18 +224,21 @@ TYPO3.Components.PageTree.App = Ext.extend(Ext.Panel, {
                                        scope: this
                                }
                        },
-
-                       html: '<p>' +
-                                       '<span id="' + this.id + '-indicatorBar-temporaryMountPoint-info' + '" ' +
-                                               'class="' + this.id + '-indicatorBar-item-leftIcon ' +
-                                                       TYPO3.Components.PageTree.Sprites.Info + '">&nbsp;' +
-                                       '</span>' +
-                                       '<span id="' + this.id + '-indicatorBar-temporaryMountPoint-clear' + '" ' +
-                                               'class="' + this.id + '-indicatorBar-item-rightIcon ' + '">X' +
-                                       '</span>' +
-                                       TYPO3.Components.PageTree.LLL.temporaryMountPointIndicatorInfo + '<br />' +
-                                               TYPO3.Components.PageTree.Configuration.temporaryMountPoint +
+                       renderData: {
+                               appId: this.getId(),
+                               spriteIconCls: TYPO3.Components.PageTree.Sprites.Info,
+                               label: TYPO3.Components.PageTree.LLL.temporaryMountPointIndicatorInfo,
+                               mountPoint: TYPO3.Components.PageTree.Configuration.temporaryMountPoint
+                       },
+                       renderTpl: Ext.create('Ext.XTemplate',
+                               '<p>',
+                               '<span id="{appId}-indicatorBar-temporaryMountPoint-info" class="{appId}-indicatorBar-item-leftIcon {spriteIconCls}">&nbsp;</span>',
+                               '{label}',
+                               '<span id="{appId}-indicatorBar-temporaryMountPoint-clear" class="{appId}-indicatorBar-item-rightIcon t3-icon t3-icon-actions t3-icon-actions-input t3-icon-input-clear t3-tceforms-input-clearer">&nbsp;</span>',
+                               '</p>',
+                               '<p>{mountPoint}',
                                '</p>'
+                       )
                });
        },
 
@@ -248,23 +250,18 @@ TYPO3.Components.PageTree.App = Ext.extend(Ext.Panel, {
         */
        addIndicator: function(component) {
                if (component.listeners && component.listeners.afterrender) {
-                       component.listeners.afterrender.fn = component.listeners.afterrender.fn.createSequence(
-                               this.afterTopPanelItemAdded, this
-                       );
+                       component.listeners.afterrender.fn = Ext.Function.createSequence(component.listeners.afterrender.fn, this.afterTopPanelItemAdded, this);
                } else {
-                       if (component.listeners) {
-                               component.listeners = {}
+                       if (!component.listeners) {
+                               component.listeners = {};
                        }
-
                        component.listeners.afterrender = {
                                scope: this,
                                fn: this.afterTopPanelItemAdded
                        }
                }
-
-               var indicator = Ext.getCmp(this.id + '-indicatorBar').add(component);
-               this.doLayout();
-
+               var indicatorBar = this.down('component[itemId=indicatorBar]');
+               var indicator = indicatorBar.add(component);
                return indicator;
        },
 
@@ -275,8 +272,15 @@ TYPO3.Components.PageTree.App = Ext.extend(Ext.Panel, {
         * @return {void}
         */
        afterTopPanelItemAdded: function(component) {
-               var topPanelItems = Ext.getCmp(this.id + '-topPanelItems');
-               topPanelItems.setHeight(topPanelItems.getHeight() + component.getHeight() + 3);
+               var topPanel = this.down('component[itemId=topPanel]');
+               var indicatorBar = this.down('component[itemId=indicatorBar]');
+               var height = 0;
+               indicatorBar.items.each(function (item) {
+                       height += item.getHeight() + 3;
+               });
+               indicatorBar.setHeight(height);
+               topPanelItems = this.down('component[itemId=topPanelItems]');
+               topPanelItems.setHeight(topPanel.getHeight() + indicatorBar.getHeight());
                this.doLayout();
        },
 
@@ -287,9 +291,9 @@ TYPO3.Components.PageTree.App = Ext.extend(Ext.Panel, {
         * @return {void}
         */
        removeIndicator: function(component) {
-               var topPanelItems = Ext.getCmp(this.id + '-topPanelItems');
+               var topPanelItems = this.down('component[itemId=topPanelItems]');
                topPanelItems.setHeight(topPanelItems.getHeight() - component.getHeight() - 3);
-               Ext.getCmp(this.id + '-indicatorBar').remove(component);
+               Ext.getCmp(this.getId() + '-indicatorBar').remove(component);
                this.doLayout();
        },
 
@@ -318,11 +322,11 @@ TYPO3.Components.PageTree.App = Ext.extend(Ext.Panel, {
         */
        refreshTree: function() {
                if (!isNaN(fsMod.recentIds['web']) && fsMod.recentIds['web'] !== '') {
-                       this.select(fsMod.recentIds['web'], true);
+                       this.select(fsMod.recentIds['web']);
                }
 
                TYPO3.Components.PageTree.DataProvider.getIndicators(function(response) {
-                       var indicators = Ext.getCmp(this.id + '-indicatorBar-indicatorTitle');
+                       var indicators = Ext.getCmp(this.getId() + '-indicatorBar-indicatorTitle');
                        if (indicators) {
                                this.removeIndicator(indicators);
                        }
@@ -333,7 +337,7 @@ TYPO3.Components.PageTree.App = Ext.extend(Ext.Panel, {
                        }
                }, this);
 
-               this.activeTree.refreshTree();
+               this.getTree().refreshTree();
        },
 
        /**
@@ -342,43 +346,44 @@ TYPO3.Components.PageTree.App = Ext.extend(Ext.Panel, {
         * @return {TYPO3.Components.PageTree.Tree}
         */
        getTree: function() {
-               return this.activeTree;
+               return this.down('component[itemId=treeContainer]').getLayout().getActiveItem();
        },
 
        /**
-        * Selects a node defined by the page id. If the second parameter is set, we
-        * store the new location into the state hash.
+        * Sets the current active tree
+        * @param {TYPO3.Components.PageTree.Tree} tree
+        * @return {TYPO3.Components.PageTree.Tree}
+        */
+       setTree: function(tree) {
+               var layout = this.down('component[itemId=treeContainer]').getLayout();
+               layout.setActiveItem(tree);
+               return layout.getActiveItem(tree);
+       },
+
+       /**
+        * Selects a node defined by the page id.
         *
         * @param {int} pageId
-        * @param {Boolean} saveState
         * @return {Boolean}
         */
-       select: function(pageId, saveState) {
-               if (saveState !== false) {
-                       saveState = true;
-               }
-
+       select: function(pageId) {
                var tree = this.getTree();
                var succeeded = false;
                var node = tree.getRootNode().findChild('realId', pageId, true);
                if (node) {
                        succeeded = true;
                        tree.selectPath(node.getPath());
-                       if (!!saveState && tree.stateHash) {
-                               tree.stateHash.lastSelectedNode = node.id;
-                       }
                }
-
                return succeeded;
        },
 
        /**
         * Returns the currently selected node
         *
-        * @return {Ext.tree.TreeNode}
+        * @return {Ext.data.NodeInterface}
         */
        getSelected: function() {
-               var node = this.getTree().getSelectionModel().getSelectedNode();
+               var node = this.getTree().getSelectionModel().getLastSelected();
                return node ? node : null;
        }
 });
@@ -389,15 +394,12 @@ TYPO3.Components.PageTree.App = Ext.extend(Ext.Panel, {
  * @return {TYPO3.Components.PageTree.App}
  */
 TYPO3.ModuleMenu.App.registerNavigationComponent('typo3-pagetree', function() {
-       TYPO3.Backend.NavigationContainer.PageTree = new TYPO3.Components.PageTree.App();
+       TYPO3.Backend.NavigationContainer.PageTree = Ext.create('TYPO3.Components.PageTree.App');
 
                // compatibility code
-    top.nav = TYPO3.Backend.NavigationContainer.PageTree;
-    top.nav_frame = TYPO3.Backend.NavigationContainer.PageTree;
-    top.content.nav_frame = TYPO3.Backend.NavigationContainer.PageTree;
+       top.nav = TYPO3.Backend.NavigationContainer.PageTree;
+       top.nav_frame = TYPO3.Backend.NavigationContainer.PageTree;
+       top.content.nav_frame = TYPO3.Backend.NavigationContainer.PageTree;
 
        return TYPO3.Backend.NavigationContainer.PageTree;
 });
-
-// XTYPE Registration
-Ext.reg('TYPO3.Components.PageTree.App', TYPO3.Components.PageTree.App);
index 32501b6..5c6ed68 100644 (file)
@@ -23,8 +23,6 @@
 *
 *  This copyright notice MUST APPEAR in all copies of the script!
 ***************************************************************/
-Ext.namespace('TYPO3.Components.PageTree');
-
 /**
  * @class TYPO3.Components.PageTree.ContextMenu
  *
@@ -34,11 +32,12 @@ Ext.namespace('TYPO3.Components.PageTree');
  * @extends Ext.menu.Menu
  * @author Stefan Galinski <stefan.galinski@gmail.com>
  */
-TYPO3.Components.PageTree.ContextMenu = Ext.extend(Ext.menu.Menu, {
+Ext.define('TYPO3.Components.PageTree.ContextMenu', {
+       extend: 'Ext.menu.Menu',
        /**
         * Context menu node
         *
-        * @cfg {Ext.tree.TreeNode}
+        * @cfg {TYPO3.Components.PageTree.Model}
         */
        node: null,
 
@@ -66,15 +65,15 @@ TYPO3.Components.PageTree.ContextMenu = Ext.extend(Ext.menu.Menu, {
        /**
         * Listeners
         *
-        * The itemclick event triggers the configured single click action
+        * The click event triggers the configured single click action
         */
        listeners: {
-               itemclick: {
-                       fn: function (item) {
-                               if (this.pageTree.commandProvider[item.callbackAction]) {
+               click: {
+                       fn: function (menu, item) {
+                               if (item && this.pageTree.commandProvider[item.callbackAction]) {
                                        if (item.parentMenu.pageTree.stateHash) {
-                                               fsMod.recentIds['web'] = item.parentMenu.node.attributes.nodeData.id;
-                                               item.parentMenu.pageTree.stateHash['lastSelectedNode'] = item.parentMenu.node.id;
+                                               fsMod.recentIds['web'] = item.parentMenu.node.getNodeData('id');
+                                               item.parentMenu.pageTree.stateHash['lastSelectedNode'] = item.parentMenu.node.getId();
                                        }
 
                                        this.pageTree.commandProvider[item.callbackAction](
@@ -90,12 +89,12 @@ TYPO3.Components.PageTree.ContextMenu = Ext.extend(Ext.menu.Menu, {
        /**
         * Fills the menu with the actions
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {TYPO3.Components.PageTree.Tree} pageTree
         * @param {Object} contextMenuConfiguration
         * @return {void}
         */
-       fill: function(node, pageTree, contextMenuConfiguration) {
+       fill: function (node, pageTree, contextMenuConfiguration) {
                this.node = node;
                this.pageTree = pageTree;
 
@@ -103,9 +102,11 @@ TYPO3.Components.PageTree.ContextMenu = Ext.extend(Ext.menu.Menu, {
                if (components.length) {
                        for (var component in components) {
                                if (components[component] === '-') {
-                                       this.addSeparator();
+                                       this.add({
+                                               xtype: 'menuseparator'
+                                       });
                                } else if (typeof components[component] === 'object') {
-                                       this.addItem(components[component]);
+                                       this.add(components[component]);
                                }
                        }
                }
@@ -119,7 +120,7 @@ TYPO3.Components.PageTree.ContextMenu = Ext.extend(Ext.menu.Menu, {
         * @param {int} level
         * @return {Object}
         */
-       preProcessContextMenuConfiguration: function(contextMenuConfiguration, level) {
+       preProcessContextMenuConfiguration: function (contextMenuConfiguration, level) {
                level = level || 0;
                if (level > 5) {
                        return [];
@@ -138,7 +139,7 @@ TYPO3.Components.PageTree.ContextMenu = Ext.extend(Ext.menu.Menu, {
                                );
 
                                if (subMenuComponents.length) {
-                                       var subMenu = new TYPO3.Components.PageTree.ContextMenu({
+                                       var subMenu = Ext.create('TYPO3.Components.PageTree.ContextMenu', {
                                                id: this.id + '-sub' + ++subMenus,
                                                items: subMenuComponents,
                                                node: this.node,
@@ -150,7 +151,8 @@ TYPO3.Components.PageTree.ContextMenu = Ext.extend(Ext.menu.Menu, {
                                                cls: 'contextMenu-subMenu',
                                                menu: subMenu,
                                                icon: contextMenuConfiguration[singleAction]['icon'],
-                                               iconCls: contextMenuConfiguration[singleAction]['class']
+                                               iconCls: contextMenuConfiguration[singleAction]['class'],
+                                               xtype: 'menuitem'
                                        };
                                }
                        } else if (contextMenuConfiguration[singleAction]['type'] === 'divider') {
@@ -163,22 +165,14 @@ TYPO3.Components.PageTree.ContextMenu = Ext.extend(Ext.menu.Menu, {
 
                                if (typeof contextMenuConfiguration[singleAction] === 'object') {
                                        var component = {
-                                               'text': contextMenuConfiguration[singleAction]['label'],
-                                               'icon': contextMenuConfiguration[singleAction]['icon'],
-                                               'iconCls': contextMenuConfiguration[singleAction]['class'],
-                                               'callbackAction': contextMenuConfiguration[singleAction]['callbackAction'],
-                                               'customAttributes': contextMenuConfiguration[singleAction]['customAttributes']
+                                               text: contextMenuConfiguration[singleAction]['label'],
+                                               icon: contextMenuConfiguration[singleAction]['icon'],
+                                               iconCls: contextMenuConfiguration[singleAction]['class'],
+                                               callbackAction: contextMenuConfiguration[singleAction]['callbackAction'],
+                                               customAttributes: contextMenuConfiguration[singleAction]['customAttributes'],
+                                               xtype: 'menuitem'
                                        };
 
-                                       component.itemTpl = Ext.menu.Item.prototype.itemTpl = new Ext.XTemplate(
-                                               '<a id="{id}" class="{cls}" hidefocus="true" unselectable="on" href="{href}">',
-                                                       '<span class="{hrefTarget}">',
-                                                               '<img src="{icon}" class="x-menu-item-icon {iconCls}" unselectable="on" />',
-                                                       '</span>',
-                                                       '<span class="x-menu-item-text">{text}</span>',
-                                               '</a>'
-                                       );
-
                                        components[index++] = component;
                                }
                        }
@@ -192,6 +186,3 @@ TYPO3.Components.PageTree.ContextMenu = Ext.extend(Ext.menu.Menu, {
                return components;
        }
 });
-
-// XTYPE Registration
-Ext.reg('TYPO3.Components.PageTree.ContextMenu', TYPO3.Components.PageTree.ContextMenu);
index 443f96f..a89afdb 100644 (file)
  *
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
-Ext.namespace('TYPO3.Components.PageTree');
-
 /**
  * @class TYPO3.Components.PageTree.DeletionDropZone
  *
  * Deletion Drop Zone
  *
  * @namespace TYPO3.Components.PageTree
- * @extends Ext.Panel
+ * @extends Ext.panel.Panel
  * @author Stefan Galinski <stefan.galinski@gmail.com>
  */
-TYPO3.Components.PageTree.DeletionDropZone = Ext.extend(Ext.Panel, {
+Ext.define('TYPO3.Components.PageTree.DeletionDropZone', {
+       extend: 'Ext.panel.Panel',
+       alias: 'widget.typo3deletiondropzone',
+
        /**
         * Border
         *
@@ -110,10 +111,7 @@ TYPO3.Components.PageTree.DeletionDropZone = Ext.extend(Ext.Panel, {
 
                                this.getEl().on('mouseout', function(e) {
                                        if (!e.within(this.getEl(), true)) {
-                                               this.removeClass(this.id + '-activateProxyOver');
-                                               if (!this.app.activeTree.shouldCopyNode) {
-                                                       this.app.activeTree.copyHint.show();
-                                               }
+                                               this.removeCls(this.id + '-activateProxyOver');
                                        }
                                }, this);
                        }
@@ -139,7 +137,7 @@ TYPO3.Components.PageTree.DeletionDropZone = Ext.extend(Ext.Panel, {
                        '">&nbsp;</span><span id="' + this.id + '-text">' +
                        TYPO3.Components.PageTree.LLL.dropToRemove + '</span></p>';
 
-               TYPO3.Components.PageTree.DeletionDropZone.superclass.initComponent.apply(this, arguments);
+               this.callParent(arguments);
        },
 
 
@@ -149,44 +147,49 @@ TYPO3.Components.PageTree.DeletionDropZone = Ext.extend(Ext.Panel, {
         * @return {void}
         */
        createDropZone: function() {
-               (new Ext.dd.DropZone(this.getEl(), {
+               Ext.create('Ext.dd.DropZone', this.getEl(), {
                        ddGroup: this.ddGroup,
 
-                       notifyOver: function(ddProxy, e) {
-                               ddProxy.setDragElPos(e.xy[0], e.xy[1] - 60);
-                               return this.id + '-proxyOver';
-                       }.createDelegate(this),
-
-                       notifyEnter: function() {
-                               this.addClass(this.id + '-activateProxyOver');
-                               if (!this.app.activeTree.shouldCopyNode) {
-                                       this.app.activeTree.copyHint.hide();
-                               }
-
-                               return this.id + '-proxyOver';
-                       }.createDelegate(this),
-
-                       notifyDrop: function(ddProxy, e, n) {
-                               var node = n.node;
-                               if (!node) {
-                                       return;
-                               }
-
-                               var tree = node.ownerTree;
-                               var nodeHasChildNodes = (node.hasChildNodes() || node.isExpandable());
-
-                               var callback = null;
-                               if (!top.TYPO3.configuration.inWorkspace && !nodeHasChildNodes) {
-                                       callback = this.setRecoverState.createDelegate(this);
-                               }
-
-                               if (nodeHasChildNodes) {
-                                       node.ownerTree.commandProvider.confirmDelete(node, tree, callback, true);
-                               } else {
-                                       node.ownerTree.commandProvider.deleteNode(node, tree, callback);
-                               }
-                       }.createDelegate(this)
-               }));
+                       notifyOver: Ext.Function.bind(
+                               function(ddProxy, e) {
+                                       ddProxy.setDragElPos(e.xy[0], e.xy[1] - 60);
+                                       return this.id + '-proxyOver';
+                               },
+                               this
+                       ),
+
+                       notifyEnter: Ext.Function.bind(
+                               function() {
+                                       this.addCls(this.id + '-activateProxyOver');
+                                       return this.id + '-proxyOver';
+                               },
+                               this
+                       ),
+
+                       notifyDrop: Ext.Function.bind(
+                               function (ddProxy, e, dragData) {
+                                       var view = dragData.view,
+                                               tree = view.panel,
+                                               node = view.getRecord(dragData.item);
+                                       if (!node) {
+                                               return;
+                                       }
+                                       var nodeHasChildNodes = (node.hasChildNodes() || node.isExpandable());
+       
+                                       var callback = null;
+                                       if (!top.TYPO3.configuration.inWorkspace && !nodeHasChildNodes) {
+                                               callback = Ext.Function.bind(this.setRecoverState, this);
+                                       }
+       
+                                       if (nodeHasChildNodes) {
+                                               tree.commandProvider.confirmDelete(node, tree, callback, true);
+                                       } else {
+                                               tree.commandProvider.deleteNode(node, tree, callback);
+                                       }
+                               },
+                               this
+                       )
+               });
        },
 
        /**
@@ -207,7 +210,7 @@ TYPO3.Components.PageTree.DeletionDropZone = Ext.extend(Ext.Panel, {
                this.setHeight(50);
                this.updateIcon(TYPO3.Components.PageTree.Sprites.TrashCanRestore);
                this.updateText(
-                       node.text + '<br />' +
+                       node.get('text') + '<br />' +
                        '<span class="' + this.id + '-restore">' +
                                '<span class="' + this.id + '-restoreText">' +
                                TYPO3.Components.PageTree.LLL.dropZoneElementRemoved +
@@ -218,13 +221,17 @@ TYPO3.Components.PageTree.DeletionDropZone = Ext.extend(Ext.Panel, {
                this.app.doLayout();
 
                ++this.amountOfDrops;
-               (function() {
-                       if (!--this.amountOfDrops) {
-                               this.toOriginState();
-                       }
-               }).defer(10000, this);
+               Ext.Function.defer(
+                       function() {
+                               if (!--this.amountOfDrops) {
+                                       this.toOriginState();
+                               }
+                       },
+                       10000,
+                       this
+               );
 
-               this.textClickHandler = this.restoreNode.createDelegate(this, [node, tree]);
+               this.textClickHandler = Ext.Function.bind(this.restoreNode, this, [node, tree]);
                Ext.get(this.id + '-text').on('click', this.textClickHandler);
 
                this.isPreviousSibling = false;
@@ -283,7 +290,7 @@ TYPO3.Components.PageTree.DeletionDropZone = Ext.extend(Ext.Panel, {
                this.previousNode = this.textClickHandler = null;
                this.isPreviousSibling = false;
 
-               if (hide && !this.app.activeTree.dragZone.dragging) {
+               if (hide && !this.app.getTree().getView().getPlugin('treeViewDragDrop').dragZone.dragging) {
                        this.hide();
                }
 
@@ -310,13 +317,14 @@ TYPO3.Components.PageTree.DeletionDropZone = Ext.extend(Ext.Panel, {
                this.updateText(TYPO3.Components.PageTree.LLL.dropZoneElementRestored);
                this.app.doLayout();
 
-               (function() {
-                       if (this.textClickHandler) {
-                               this.toOriginState();
-                       }
-               }).defer(3000, this);
+               Ext.Function.defer(
+                       function() {
+                               if (this.textClickHandler) {
+                                       this.toOriginState();
+                               }
+                       },
+                       3000,
+                       this
+               );
        }
 });
-
-// XTYPE Registration
-Ext.reg('TYPO3.Components.PageTree.DeletionDropZone', TYPO3.Components.PageTree.DeletionDropZone);
index 7ee0d88..5b24822 100644 (file)
@@ -23,8 +23,6 @@
 *
 *  This copyright notice MUST APPEAR in all copies of the script!
 ***************************************************************/
-Ext.namespace('TYPO3.Components.PageTree');
-
 /**
  * @class TYPO3.Components.PageTree.FilteringTree
  *
@@ -34,7 +32,9 @@ Ext.namespace('TYPO3.Components.PageTree');
  * @extends TYPO3.Components.PageTree.Tree
  * @author Stefan Galinski <stefan.galinski@gmail.com>
  */
-TYPO3.Components.PageTree.FilteringTree = Ext.extend(TYPO3.Components.PageTree.Tree, {
+Ext.define('TYPO3.Components.PageTree.FilteringTree', {
+       extend: 'TYPO3.Components.PageTree.Tree',
+
        /**
         * Search word
         *
@@ -47,29 +47,45 @@ TYPO3.Components.PageTree.FilteringTree = Ext.extend(TYPO3.Components.PageTree.T
         *
         * @return {void}
         */
-       addTreeLoader: function() {
-               this.loader = new Ext.tree.TreeLoader({
-                       directFn: this.treeDataProvider.getFilteredTree,
-                       paramOrder: 'nodeId,attributes,searchWord',
-                       nodeParameter: 'nodeId',
-                       baseAttrs: {
-                               uiProvider: this.uiProvider
-                       },
-
-                       listeners: {
-                               beforeload: function(treeLoader, node) {
-                                       if (!node.ownerTree.searchWord || node.ownerTree.searchWord === '') {
-                                               return false;
+       addStore: function (store) {
+               this.store = Ext.data.StoreManager.lookup(this.getId() + 'FilteredPageTreeStore');
+               if (!this.store) {
+                       this.store = Ext.create('Ext.data.TreeStore', {
+                               clearOnLoad: false,
+                               listeners: {
+                                       beforeload: {
+                                               fn: function (store, operation) {
+                                                       if (!this.searchWord || this.searchWord === '') {
+                                                               return false;
+                                                       }
+                                                       if (operation.node) {
+                                                               var node = operation.node;
+                                                               node.removeAll();
+                                                               node.commit();
+                                                               operation.params = {
+                                                                       nodeId: node.getNodeData('id'),
+                                                                       nodeData: node.get('nodeData'),
+                                                                       searchWord: this.searchWord
+                                                                       
+                                                               };
+                                                       }
+                                               },
+                                               scope: this
                                        }
-
-                                       treeLoader.baseParams.nodeId = node.id;
-                                       treeLoader.baseParams.searchWord = node.ownerTree.searchWord;
-                                       treeLoader.baseParams.attributes = node.attributes.nodeData;
-                               }
-                       }
-               });
+                               },
+                               model: 'TYPO3.Components.PageTree.Model',
+                               nodeParam: 'nodeId',
+                               proxy: {
+                                       type: 'direct',
+                                       paramOrder: ['nodeId', 'nodeData', 'searchWord'],
+                                       directFn: this.treeDataProvider.getFilteredTree,
+                                       reader: {
+                                           type: 'json'
+                                       }
+                               },
+                               root: this.rootNodeConfig,
+                               storeId: this.getId() + 'FilteredPageTreeStore'
+                       });
+               }
        }
 });
-
-// XTYPE Registration
-Ext.reg('TYPO3.Components.PageTree.FilteringTree', TYPO3.Components.PageTree.FilteringTree);
index a649b22..84566ae 100644 (file)
@@ -1,10 +1,12 @@
 treeeditor.js
+pagetreecolumn.js
+contextmenu.js
+Ext.ux.state.TreePanel.js
+treedropzone.js
+treeviewdragdrop.js
 tree.js
 filteringtree.js
-nodeui.js
-deletiondropzone.js
 toppanel.js
-contextmenu.js
+deletiondropzone.js
 actions.js
-Ext.ux.state.TreePanel.js
 app.js
diff --git a/t3lib/js/extjs/components/pagetree/javascript/nodeui.js b/t3lib/js/extjs/components/pagetree/javascript/nodeui.js
deleted file mode 100644 (file)
index 1a10660..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-/***************************************************************
-*  Copyright notice
-*
-*  (c) 2010-2011 Stefan Galinski <stefan.galinski@gmail.com>
-*  All rights reserved
-*
-*  This script is part of the TYPO3 project. The TYPO3 project is
-*  free software; you can redistribute it and/or modify
-*  it under the terms of the GNU General Public License as published by
-*  the Free Software Foundation; either version 2 of the License, or
-*  (at your option) any later version.
-*
-*  The GNU General Public License can be found at
-*  http://www.gnu.org/copyleft/gpl.html.
-*  A copy is found in the textfile GPL.txt and important notices to the license
-*  from the author is found in LICENSE.txt distributed with these scripts.
-*
-*
-*  This script is distributed in the hope that it will be useful,
-*  but WITHOUT ANY WARRANTY; without even the implied warranty of
-*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-*  GNU General Public License for more details.
-*
-*  This copyright notice MUST APPEAR in all copies of the script!
-***************************************************************/
-Ext.namespace('TYPO3.Components.PageTree');
-
-/**
- * @class TYPO3.Components.PageTree.DeletionDropZone
- *
- * Tree Node User Interface that can handle sprite icons and more
- *
- * @namespace TYPO3.Components.PageTree
- * @extends Ext.tree.TreeNodeUI
- * @author Stefan Galinski <stefan.galinski@gmail.com>
- */
-TYPO3.Components.PageTree.PageTreeNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
-       /**
-        * Adds the sprite icon and adds an event to open the context menu on a single click at the icon node
-        *
-        * @param {Ext.tree.TreeNode} n
-        * @param {Object} a
-        * @param {Ext.tree.TreeNode} targetNode
-        * @param {Boolean} bulkRender
-        * @return {void}
-        */
-       renderElements : function(n, a, targetNode, bulkRender) {
-               // add some indent caching, this helps performance when rendering a large tree
-        this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
-
-        var cb = Ext.isBoolean(a.checked),
-            nel,
-            href = this.getHref(a.href),
-                       rootline = '';
-
-                       // TYPO3 modification to show the readable rootline above the user mounts
-               if (a.readableRootline !== '') {
-                       var rootline = '<li class="x-tree-node-readableRootline">' + a.readableRootline + '</li>';
-               }
-
-               var buf = [rootline,'<li class="x-tree-node"><div ext:tree-node-id="',n.id,'" class="x-tree-node-el x-tree-node-leaf x-unselectable ', a.cls,'" unselectable="on">',
-            '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
-            '<img alt="" src="', this.emptyIcon, '" class="x-tree-ec-icon x-tree-elbow" />',
-//            '<img alt="" src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
-                       a.spriteIconCode, // TYPO3: add sprite icon code
-            cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : '/>')) : '',
-            '<a hidefocus="on" class="x-tree-node-anchor" href="',href,'" tabIndex="1" ',
-             a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "", '><span unselectable="on">',n.text,"</span></a></div>",
-            '<ul class="x-tree-node-ct" style="display:none;"></ul>',
-            "</li>"].join('');
-
-        if(bulkRender !== true && n.nextSibling && (nel = n.nextSibling.ui.getEl())){
-            this.wrap = Ext.DomHelper.insertHtml("beforeBegin", nel, buf);
-        }else{
-            this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf);
-        }
-
-
-        this.elNode = this.wrap.childNodes[0];
-        this.ctNode = this.wrap.childNodes[1];
-        var cs = this.elNode.childNodes;
-        this.indentNode = cs[0];
-        this.ecNode = cs[1];
-//        this.iconNode = cs[2];
-               this.iconNode = (cs[2].firstChild.tagName === 'SPAN' ? cs[2].firstChild : cs[2]); // TYPO3: get possible overlay icon
-        var index = 3; // TYPO3: index 4?
-        if(cb){
-            this.checkbox = cs[3];
-            // fix for IE6
-            this.checkbox.defaultChecked = this.checkbox.checked;
-            index++;
-        }
-        this.anchor = cs[index];
-        this.textNode = cs[index].firstChild;
-
-                       // TYPO3: call the context menu on a single click (Beware of drag&drop!)
-               if (!TYPO3.Components.PageTree.Configuration.disableIconLinkToContextmenu
-                       || TYPO3.Components.PageTree.Configuration.disableIconLinkToContextmenu === '0'
-               ) {
-                       Ext.fly(this.iconNode).on('click', function(event) {
-                               this.getOwnerTree().fireEvent('contextmenu', this, event);
-                               event.stopEvent();
-                       }, n);
-               }
-       },
-
-       /**
-        * Adds a quick tip to the sprite icon
-        *
-        * @param {Ext.tree.TreeNode} node
-        * @param {Object} tip
-        * @param {String} title
-        * @return {void}
-        */
-    onTipChange : function(node, tip, title) {
-               TYPO3.Components.PageTree.PageTreeNodeUI.superclass.onTipChange.apply(this, arguments);
-
-        if(this.rendered){
-            var hasTitle = Ext.isDefined(title);
-            if(this.iconNode.setAttributeNS){
-                this.iconNode.setAttributeNS("ext", "qtip", tip);
-                if(hasTitle){
-                    this.iconNode.setAttributeNS("ext", "qtitle", title);
-                }
-            }else{
-                this.iconNode.setAttribute("ext:qtip", tip);
-                if(hasTitle){
-                    this.iconNode.setAttribute("ext:qtitle", title);
-                }
-            }
-        }
-    },
-
-       /**
-        * Returns the drag and drop handles
-        *
-        * @return {Object}
-        */
-       getDDHandles: function() {
-               var ddHandles = [this.iconNode, this.textNode, this.elNode];
-               var handlesIndex = ddHandles.length;
-               
-               var textNode = Ext.get(this.textNode);
-               for (var i = 0; i < textNode.dom.childNodes.length; ++i) {
-                       if (textNode.dom.childNodes[i].nodeName === 'SPAN') {
-                               ddHandles[handlesIndex++] = textNode.dom.childNodes[i];
-                               if (textNode.dom.childNodes[i].childNodes) {
-                                       ddHandles[handlesIndex++] = textNode.dom.childNodes[i].childNodes[0];
-                               }
-                       }
-               }
-
-               return ddHandles;
-    },
-
-       /**
-        * Only set the onOver class if we are not in dragging mode
-        *
-        * @return {void}
-        */
-       onOver: function() {
-               if (!this.node.ownerTree.dontSetOverClass) {
-                       TYPO3.Components.PageTree.PageTreeNodeUI.superclass.onOver.apply(this, arguments);
-               }
-       }
-});
-
-// XTYPE Registration
-Ext.reg('TYPO3.Components.PageTree.PageTreeNodeUI', TYPO3.Components.PageTree.PageTreeNodeUI);
diff --git a/t3lib/js/extjs/components/pagetree/javascript/pagetreecolumn.js b/t3lib/js/extjs/components/pagetree/javascript/pagetreecolumn.js
new file mode 100644 (file)
index 0000000..e4941d3
--- /dev/null
@@ -0,0 +1,166 @@
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2011 Stanislas Rolland <typo3@sjbr.ca>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*  A copy is found in the textfile GPL.txt and important notices to the license
+*  from the author is found in LICENSE.txt distributed with these scripts.
+*
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+/**
+ * @class TYPO3.Components.PageTree.Column
+ *
+ * Page tree column
+ *
+ * @namespace TYPO3.Components.PageTree
+ * @extends Ext.grid.column.Column
+ * @author Stanislas Rolland <typo3@sjbr.ca>
+ */
+Ext.define('TYPO3.Components.PageTree.Column', {
+       extend: 'Ext.grid.column.Column',
+       alias: 'widget.pagetreecolumn',
+       
+       /**
+        * Render a row of the page tree adding relevant icons depending on record depth and record type
+        *
+        */
+       initComponent: function() {
+               var origRenderer = this.renderer || this.defaultRenderer,
+                       origScope = this.scope || window;
+
+               this.renderer = function(value, metaData, record, rowIdx, colIdx, store, view) {
+                       var buf   = [],
+                               format = Ext.String.format,
+                               depth = record.getDepth(),
+                               treePrefix = Ext.baseCSSPrefix + 'tree-',
+                               elbowPrefix = treePrefix + 'elbow-',
+                               expanderCls = treePrefix + 'expander',
+                               imgText = '<img src="{1}" class="{0}" />',
+                               checkboxText = '<input type="button" role="checkbox" class="{0}" {1} />',
+                               formattedValue = origRenderer.apply(origScope, arguments),
+                               checked = null,
+                               href = record.getNodeData('href'),
+                               target = record.getNodeData('hrefTarget'),
+                               cls = record.getNodeData('cls'),
+                               readableRootline = record.getNodeData('readableRootline');
+       
+                       while (record) {
+                               if (!record.isRoot() || (record.isRoot() && view.rootVisible)) {
+                                       if (record.getDepth() === depth) {
+                                                       // Add TYPO3 sprite icon code
+                                               buf.unshift(record.getNodeData('spriteIconCode'));
+                                                       // Check if nodeData['checked'] is boolean
+                                               checked = record.getNodeData('checked');
+                                               if (Ext.isBoolean(checked)) {
+                                                       buf.unshift(format(
+                                                               checkboxText,
+                                                               (treePrefix + 'checkbox') + (checked ? ' ' + treePrefix + 'checkbox-checked' : ''),
+                                                               checked ? 'aria-checked="true"' : ''
+                                                       ));
+                                                       if (checked) {
+                                                               metaData.tdCls += (' ' + treePrefix + 'checked');
+                                                       }
+                                               }
+                                                       // Remove +/arrow from the TYPO3 root
+                                               if (record.getDepth() === 1) {
+                                                       buf.unshift(format(imgText, (elbowPrefix + 'empty'), Ext.BLANK_IMAGE_URL));
+                                               } else if (record.isLast()) {
+                                                       if (record.isExpandable()) {
+                                                               buf.unshift(format(imgText, (elbowPrefix + 'end-plus ' + expanderCls), Ext.BLANK_IMAGE_URL));
+                                                       } else {
+                                                               buf.unshift(format(imgText, (elbowPrefix + 'end'), Ext.BLANK_IMAGE_URL));
+                                                       }
+                                               } else {
+                                                       if (record.isExpandable()) {
+                                                               buf.unshift(format(imgText, (elbowPrefix + 'plus ' + expanderCls), Ext.BLANK_IMAGE_URL));
+                                                       } else {
+                                                               buf.unshift(format(imgText, (treePrefix + 'elbow'), Ext.BLANK_IMAGE_URL));
+                                                       }
+                                               }
+                                       } else {
+                                                       // Remove elbow from the TYPO3 root
+                                               if (record.isLast() || record.getDepth() === 1) {
+                                                       buf.unshift(format(imgText, (elbowPrefix + 'empty'), Ext.BLANK_IMAGE_URL));
+                                               } else if (record.getDepth() !== 1) {
+                                                       buf.unshift(format(imgText, (elbowPrefix + 'line'), Ext.BLANK_IMAGE_URL));
+                                               }                      
+                                       }
+                               }
+                               record = record.parentNode;
+                       } 
+                       if (href) {
+                               buf.push('<a href="', href, '" target="', target, '">', formattedValue, '</a>');
+                       } else {
+                               buf.push(formattedValue);
+                       }
+                       if (cls) {
+                               metaData.tdCls += ' ' + cls;
+                       }
+                               // Show the readable rootline above the user mounts
+                       if (readableRootline !== '') {
+                               buf.unshift('<div class="x-tree-node-readableRootline">' + readableRootline + '</div>');
+                       }
+                       return buf.join('');
+               };
+               this.callParent(arguments);
+       },
+
+       defaultRenderer: function (value) {
+               return value;
+       },
+       /**
+        * Create editing field with correct margin left
+        *
+        */
+        getEditor: function (record, defaultField) {
+               var depth = parseInt(record.getDepth()),
+                       marginLeft = 51;
+               if (depth > 2) {
+                       marginLeft += (depth-2)*16;
+               }
+               var field = this.field;
+               if (!field && this.editor) {
+                       field = this.editor;
+                       delete this.editor;
+               }
+
+               if (!field && defaultField) {
+                       field = defaultField;
+               }
+
+               if (field) {
+                       if (Ext.isString(field)) {
+                               field = { xtype: field };
+                       }
+                       if (field.isFormField) {
+                               field.setFieldStyle({
+                                       marginLeft: marginLeft + 'px'
+                               });
+                       }
+                       if (Ext.isObject(field) && !field.isFormField) {
+                               field = Ext.ComponentManager.create(field, 'textfield');
+                               this.field = field;
+                       }
+                       Ext.apply(field, {
+                               name: this.dataIndex
+                       });
+                       return field;
+               }
+       }
+});
index f80299d..04d28f9 100644 (file)
 *
 *  This copyright notice MUST APPEAR in all copies of the script!
 ***************************************************************/
-Ext.namespace('TYPO3.Components.PageTree');
-
 /**
  * @class TYPO3.Components.PageTree.TopPanel
  *
  * Top Panel
  *
  * @namespace TYPO3.Components.PageTree
- * @extends Ext.Panel
+ * @extends Ext.panel.Panel
  * @author Stefan Galinski <stefan.galinski@gmail.com>
  */
-TYPO3.Components.PageTree.TopPanel = Ext.extend(Ext.Panel, {
+Ext.define('TYPO3.Components.PageTree.TopPanel', {
+       extend: 'Ext.panel.Panel',
+
        /**
         * Component Id
         *
@@ -43,37 +43,48 @@ TYPO3.Components.PageTree.TopPanel = Ext.extend(Ext.Panel, {
        id: 'typo3-pagetree-topPanel',
 
        /**
-        * Border
+        * Toolbar Object
         *
-        * @type {Boolean}
+        * @type {Ext.Toolbar}
         */
-       border: false,
+       dockedItems: [{
+               xtype: 'toolbar',
+               dock: 'top',
+               itemId: 'topToolbar'
+       }],
 
        /**
-        * Toolbar Object
+        * Panel CSS
         *
-        * @type {Ext.Toolbar}
+        * @type {String}
         */
-       tbar: new Ext.Toolbar(),
-
+       cls: 'typo3-pagetree-topPanel',
+       
        /**
-        * Currently Clicked Toolbar Button
+        * Body CSS
         *
-        * @type {Ext.Button}
+        * @type {String}
         */
-       currentlyClickedButton: null,
+       bodyCls: 'typo3-pagetree-topPanel-item',
+       
+       /**
+        * Layout
+        *
+        * @type {String}
+        */
+       layout: 'anchor',
 
        /**
-        * Currently Shown Panel
+        * Currently Clicked Toolbar Button
         *
-        * @type {Ext.Component}
+        * @type {Ext.Button}
         */
-       currentlyShownPanel: null,
+       currentlyClickedButton: null,
 
        /**
         * Filtering Indicator Item
         *
-        * @type {Ext.Panel}
+        * @type {Ext.panel.Panel}
         */
        filteringIndicator: null,
 
@@ -118,39 +129,21 @@ TYPO3.Components.PageTree.TopPanel = Ext.extend(Ext.Panel, {
         * @return {void}
         */
        initComponent: function() {
-               this.currentlyShownPanel = new Ext.Panel({
-                       id: this.id + '-defaultPanel',
-                       cls: this.id + '-item'
-               });
-               this.items = [this.currentlyShownPanel];
-
-               TYPO3.Components.PageTree.TopPanel.superclass.initComponent.apply(this, arguments);
-
+               this.callParent();
+                       // Node insertion feature
                this.addDragDropNodeInsertionFeature();
-
+                       // Filter feature
                if (!TYPO3.Components.PageTree.Configuration.hideFilter
                        || TYPO3.Components.PageTree.Configuration.hideFilter === '0'
                ) {
                        this.addFilterFeature();
                }
-
-               this.getTopToolbar().addItem({xtype: 'tbfill'});
+                       // Refresh feature
+               this.getDockedComponent('topToolbar').add({xtype: 'tbfill'});
                this.addRefreshTreeFeature();
        },
 
        /**
-        * Returns a custom button template to fix some nasty webkit issues
-        * by removing some useless wrapping html code
-        *
-        * @return {void}
-        */
-       getButtonTemplate: function() {
-               return new Ext.Template(
-                       '<div id="{4}" class="x-btn {3}"><button type="{0}"">&nbsp;</button></div>'
-               );
-       },
-
-       /**
         * Adds a button to the components toolbar with a related component
         *
         * @param {Object} button
@@ -158,7 +151,6 @@ TYPO3.Components.PageTree.TopPanel = Ext.extend(Ext.Panel, {
         * @return {void}
         */
        addButton: function(button, connectedWidget) {
-               button.template = this.getButtonTemplate();
                if (!button.hasListener('click')) {
                        button.on('click', this.topbarButtonCallback);
                }
@@ -169,7 +161,7 @@ TYPO3.Components.PageTree.TopPanel = Ext.extend(Ext.Panel, {
                        this.add(connectedWidget);
                }
 
-               this.getTopToolbar().addItem(button);
+               this.getDockedComponent('topToolbar').add(button);
                this.doLayout();
        },
 
@@ -182,44 +174,45 @@ TYPO3.Components.PageTree.TopPanel = Ext.extend(Ext.Panel, {
        topbarButtonCallback: function() {
                var topPanel = this.ownerCt.ownerCt;
 
-               topPanel.currentlyShownPanel.hide();
                if (topPanel.currentlyClickedButton) {
                        topPanel.currentlyClickedButton.toggle(false);
+                       if (topPanel.currentlyClickedButton.connectedWidget) {
+                               topPanel.currentlyClickedButton.connectedWidget.hide();
+                       }
                }
 
                if (topPanel.currentlyClickedButton === this) {
                        topPanel.currentlyClickedButton = null;
-                       topPanel.currentlyShownPanel = topPanel.get(topPanel.id + '-defaultPanel');
+                       if (this.connectedWidget) {
+                               this.connectedWidget.hide();
+                       }
                } else {
                        this.toggle(true);
                        topPanel.currentlyClickedButton = this;
-                       topPanel.currentlyShownPanel = this.connectedWidget;
+                       if (this.connectedWidget) {
+                               this.connectedWidget.show();
+                       }
                }
-
-               topPanel.currentlyShownPanel.show();
        },
 
        /**
         * Loads the filtering tree nodes with the given search word
         *
-        * @param {Ext.form.TextField} textField
+        * @param {Ext.form.field.Trigger} textField
         * @return {void}
         */
-       createFilterTree: function(textField) {
+       createFilterTree: function (textField) {
                var searchWord = textField.getValue();
                var isNumber = TYPO3.Utility.isNumber(searchWord);
                var hasMinLength = (searchWord.length > 2 || searchWord.length <= 0);
                if ((!hasMinLength && !isNumber) || searchWord === this.filteringTree.searchWord) {
                        return;
                }
-
                this.filteringTree.searchWord = searchWord;
                if (this.filteringTree.searchWord === '') {
-                       this.app.activeTree = this.tree;
-
                        textField.setHideTrigger(true);
-                       this.filteringTree.hide();
-                       this.tree.show().refreshTree(function() {
+                       this.app.setTree(this.tree);
+                       this.tree.refreshTree(function() {
                                textField.focus(false, 500);
                        }, this);
 
@@ -229,7 +222,6 @@ TYPO3.Components.PageTree.TopPanel = Ext.extend(Ext.Panel, {
                        }
                } else {
                        var selectedNode = this.app.getSelected();
-                       this.app.activeTree = this.filteringTree;
 
                        if (!this.filteringIndicator) {
                                this.filteringIndicator = this.app.addIndicator(
@@ -237,20 +229,20 @@ TYPO3.Components.PageTree.TopPanel = Ext.extend(Ext.Panel, {
                                );
                        }
 
-                       textField.setHideTrigger(false);
-                       this.tree.hide();
                        this.app.ownerCt.getEl().mask('', 'x-mask-loading-message');
-                       this.app.ownerCt.getEl().addClass('t3-mask-loading');
-                       this.filteringTree.show().refreshTree(function() {
+                       this.app.ownerCt.getEl().addCls('t3-mask-loading');
+                       this.app.setTree(this.filteringTree);
+                       this.filteringTree.refreshTree(function() {
                                if (selectedNode) {
-                                       this.app.select(selectedNode.attributes.nodeData.id, false);
+                                       this.app.select(selectedNode.getNodeData('id'));
                                }
-                               textField.focus();
                                this.app.ownerCt.getEl().unmask();
+                               textField.setHideTrigger(false);
+                               textField.triggerWrap.setWidth(0);
+                               this.forceComponentLayout();
+                               textField.focus();
                        }, this);
                }
-
-               this.doLayout();
        },
 
        /**
@@ -261,26 +253,27 @@ TYPO3.Components.PageTree.TopPanel = Ext.extend(Ext.Panel, {
         */
        createIndicatorItem: function(textField) {
                return {
-                       border: false,
-                       id: this.app.id + '-indicatorBar-filter',
-                       cls: this.app.id + '-indicatorBar-item',
-                       html: '<p>' +
-                                       '<span id="' + this.app.id + '-indicatorBar-filter-info' + '" ' +
-                                               'class="' + this.app.id + '-indicatorBar-item-leftIcon ' +
-                                                       TYPO3.Components.PageTree.Sprites.Info + '">&nbsp;' +
-                                       '</span>' +
-                                       '<span id="' + this.app.id + '-indicatorBar-filter-clear' + '" ' +
-                                               'class="' + this.app.id + '-indicatorBar-item-rightIcon ' + '">X' +
-                                       '</span>' +
-                                       TYPO3.Components.PageTree.LLL.activeFilterMode +
-                               '</p>',
+                       id: this.app.getId() + '-indicatorBar-filter',
+                       cls: this.app.getId() + '-indicatorBar-item',
+                       renderData: {
+                               appId: this.app.getId(),
+                               spriteIconCls: TYPO3.Components.PageTree.Sprites.Info,
+                               label: TYPO3.Components.PageTree.LLL.activeFilterMode
+                       },
+                       renderTpl: Ext.create('Ext.XTemplate',
+                               '<p>',
+                               '<span id="{appId}-indicatorBar-filter-info" class="{appId}-indicatorBar-item-leftIcon {spriteIconCls}">&nbsp;</span>',
+                               '&nbsp;{label}&nbsp;',
+                               '<span id="{appId}-indicatorBar-filter-clear" class="{appId}-indicatorBar-item-rightIcon">X</span>',
+                               '</p>'
+                       ),
                        filteringTree: this.filteringTree,
 
                        listeners: {
                                afterrender: {
                                        scope: this,
-                                       fn: function() {
-                                               var element = Ext.fly(this.app.id + '-indicatorBar-filter-clear');
+                                       fn: function(component) {
+                                               var element = Ext.get(this.app.getId() + '-indicatorBar-filter-clear');
                                                element.on('click', function() {
                                                        textField.setValue('');
                                                        this.createFilterTree(textField);
@@ -297,71 +290,65 @@ TYPO3.Components.PageTree.TopPanel = Ext.extend(Ext.Panel, {
         * @return {void}
         */
        addFilterFeature: function() {
-               var topPanelButton = new Ext.Button({
-                       id: this.id + '-button-filter',
-                       cls: this.id + '-button',
+               var topPanelButton = Ext.create('Ext.button.Button', {
+                       id: this.getId() + '-button-filter',
+                       cls: this.getId() + '-button',
                        iconCls: TYPO3.Components.PageTree.Sprites.Filter,
                        tooltip: TYPO3.Components.PageTree.LLL.buttonFilter
                });
 
-               var textField = new Ext.form.TriggerField({
-                       id: this.id + '-filter',
+               var textField = Ext.create('Ext.form.field.Trigger', {
+                       id: this.getId() + '-filter',
+                       border: false,
                        enableKeyEvents: true,
-                       triggerClass: TYPO3.Components.PageTree.Sprites.InputClear,
+                       labelWidth: 0,
+                       triggerCls: TYPO3.Components.PageTree.Sprites.InputClear,
                        value: TYPO3.Components.PageTree.LLL.searchTermInfo,
 
                        listeners: {
                                blur: {
-                                       scope: this,
-                                       fn:function(textField) {
+                                       fn: function (textField) {
                                                if (textField.getValue() === '') {
                                                        textField.setValue(TYPO3.Components.PageTree.LLL.searchTermInfo);
-                                                       textField.addClass(this.id + '-filter-defaultText');
+                                                       textField.inputEl.addCls(this.getId() + '-filter-defaultText');
                                                }
-                                       }
+                                       },
+                                       scope: this
                                },
 
                                focus: {
-                                       scope: this,
-                                       fn: function(textField) {
+                                       fn: function (textField) {
                                                if (textField.getValue() === TYPO3.Components.PageTree.LLL.searchTermInfo) {
                                                        textField.setValue('');
-                                                       textField.removeClass(this.id + '-filter-defaultText');
+                                                       textField.inputEl.removeCls(this.getId() + '-filter-defaultText');
                                                }
-                                       }
+                                       },
+                                       scope: this
                                },
 
                                keydown: {
                                        fn: this.createFilterTree,
                                        scope: this,
                                        buffer: 1000
-                               }
-                       }
-               });
-
-               textField.setHideTrigger(true);
-               textField.onTriggerClick = function() {
-                       textField.setValue('');
-                       this.createFilterTree(textField);
-               }.createDelegate(this);
-
-               var topPanelWidget = new Ext.Panel({
-                       border: false,
-                       id: this.id + '-filterWrap',
-                       cls: this.id + '-item',
-                       items: [textField],
+                               },
 
-                       listeners: {
                                show: {
-                                       scope: this,
-                                       fn: function(panel) {
-                                               panel.get(this.id + '-filter').focus();
-                                       }
+                                       fn: function () { this.focus(); }
                                }
                        }
                });
 
-               this.addButton(topPanelButton, topPanelWidget);
+               textField.setHideTrigger(true);
+               textField.onTriggerClick = Ext.Function.bind(
+                       function (textField) {
+                               textField.setValue('');
+                               this.createFilterTree(textField);
+                       },
+                       this,
+                       [textField]
+               );
+
+               this.addButton(topPanelButton, textField);
        },
 
        /**
@@ -370,28 +357,32 @@ TYPO3.Components.PageTree.TopPanel = Ext.extend(Ext.Panel, {
         * @return {void}
         */
        createNewNodeToolbar: function() {
-               this.dragZone = new Ext.dd.DragZone(this.getEl(), {
+               this.dragZone = Ext.create('Ext.dd.DragZone', this.getEl(), {
                        ddGroup: this.ownerCt.ddGroup,
                        topPanel: this.ownerCt,
 
                        endDrag: function() {
-                               this.topPanel.app.activeTree.dontSetOverClass = false;
+                               this.topPanel.app.getTree().dontSetOverClass = false;
                        },
 
-                       getDragData: function(event) {
+                       getDragData: function (event) {
                                this.proxyElement = document.createElement('div');
-
-                               var node = Ext.getCmp(event.getTarget('.x-btn').id);
-                               node.shouldCreateNewNode = true;
-
+                               var clickedButton = event.getTarget('.x-btn');
+                               if (clickedButton) {
+                                       var node = Ext.getCmp(clickedButton.id);
+                               }
+                               if (node) {
+                                       node.shouldCreateNewNode = true;
+                               }
                                return {
                                        ddel: this.proxyElement,
-                                       item: node
+                                       item: node,
+                                       records: [node]
                                }
                        },
 
                        onInitDrag: function() {
-                               this.topPanel.app.activeTree.dontSetOverClass = true;
+                               this.topPanel.app.getTree().dontSetOverClass = true;
                                var clickedButton = this.dragData.item;
                                var cls = clickedButton.initialConfig.iconCls;
 
@@ -405,18 +396,18 @@ TYPO3.Components.PageTree.TopPanel = Ext.extend(Ext.Panel, {
                        }
                });
 
-                       // listens on the escape key to stop the dragging
-               (new Ext.KeyMap(document, {
+                       // Listens on the escape key to stop the dragging
+               Ext.create('Ext.util.KeyMap', document, {
                        key: Ext.EventObject.ESC,
                        scope: this,
                        buffer: 250,
                        fn: function(event) {
                                if (this.dragZone.dragging) {
-                                       Ext.dd.DragDropMgr.stopDrag(event);
+                                       Ext.dd.DragDropManager.stopDrag(event);
                                        this.dragZone.onInvalidDrop(event);
                                }
                        }
-               }, 'keydown'));
+               }, 'keydown');
        },
 
        /**
@@ -425,11 +416,16 @@ TYPO3.Components.PageTree.TopPanel = Ext.extend(Ext.Panel, {
         * @return {void}
         */
        addDragDropNodeInsertionFeature: function() {
-               var newNodeToolbar = new Ext.Toolbar({
-                       border: false,
-                       id: this.id + '-item-newNode',
-                       cls: this.id + '-item',
+               var topPanelButton = Ext.create('Ext.button.Button', {
+                       id: this.getId() + '-button-newNode',
+                       cls: this.getId() + '-button',
+                       iconCls: TYPO3.Components.PageTree.Sprites.NewNode,
+                       tooltip: TYPO3.Components.PageTree.LLL.buttonNewNode
+               });
 
+               var newNodeToolbar = Ext.create('Ext.toolbar.Toolbar', {
+                       id: this.getId() + '-item-newNode',
+                       cls: this.getId() + '-item',
                        listeners: {
                                render: {
                                        fn: this.createNewNodeToolbar
@@ -438,20 +434,10 @@ TYPO3.Components.PageTree.TopPanel = Ext.extend(Ext.Panel, {
                });
 
                this.dataProvider.getNodeTypes(function(response) {
-                       for (var i = 0; i < response.length; ++i) {
-                               response[i].template = this.getButtonTemplate();
-                               newNodeToolbar.addItem(response[i]);
-                       }
+                       newNodeToolbar.add(response);
                        newNodeToolbar.doLayout();
                }, this);
 
-               var topPanelButton = new Ext.Button({
-                       id: this.id + '-button-newNode',
-                       cls: this.id + '-button',
-                       iconCls: TYPO3.Components.PageTree.Sprites.NewNode,
-                       tooltip: TYPO3.Components.PageTree.LLL.buttonNewNode
-               });
-
                this.addButton(topPanelButton, newNodeToolbar);
        },
 
@@ -461,9 +447,9 @@ TYPO3.Components.PageTree.TopPanel = Ext.extend(Ext.Panel, {
         * @return {void}
         */
        addRefreshTreeFeature: function() {
-               var topPanelButton = new Ext.Button({
-                       id: this.id + '-button-refresh',
-                       cls: this.id + '-button',
+               var topPanelButton = Ext.create('Ext.button.Button', {
+                       id: this.getId() + '-button-refresh',
+                       cls: this.getId() + '-button',
                        iconCls: TYPO3.Components.PageTree.Sprites.Refresh,
                        tooltip: TYPO3.Components.PageTree.LLL.buttonRefresh,
 
@@ -471,7 +457,7 @@ TYPO3.Components.PageTree.TopPanel = Ext.extend(Ext.Panel, {
                                click: {
                                        scope: this,
                                        fn: function() {
-                                               this.app.activeTree.refreshTree();
+                                               this.app.getTree().refreshTree();
                                        }
                                }
                        }
@@ -480,6 +466,3 @@ TYPO3.Components.PageTree.TopPanel = Ext.extend(Ext.Panel, {
                this.addButton(topPanelButton);
        }
 });
-
-// XTYPE Registration
-Ext.reg('TYPO3.Components.PageTree.TopPanel', TYPO3.Components.PageTree.TopPanel);
index 7319b02..fe61c6a 100644 (file)
 *
 *  This copyright notice MUST APPEAR in all copies of the script!
 ***************************************************************/
-Ext.namespace('TYPO3.Components.PageTree');
-
 /**
  * @class TYPO3.Components.PageTree.Tree
  *
  * Generic Tree Panel
  *
  * @namespace TYPO3.Components.PageTree
- * @extends Ext.tree.TreePanel
+ * @extends Ext.tree.Panel
  * @author Stefan Galinski <stefan.galinski@gmail.com>
  */
-TYPO3.Components.PageTree.Tree = Ext.extend(Ext.tree.TreePanel, {
+Ext.define('TYPO3.Components.PageTree.Model', {
+       extend: 'Ext.data.Model',
+       fields: [{
+               name: 'id',
+               type: 'string',
+               defaultValue: 'root'
+       },{
+               name: 'realId',
+               type: 'string'
+       },{
+               name: 'text',
+               type: 'string'
+       },{
+               name: 'depth',
+               type: 'int'
+       },{
+               name: 'root',
+               type: 'boolean'
+       },{
+               name: 'leaf',
+               type: 'boolean'
+       },{
+               name: 'parentId',
+               type: 'string'
+       },{
+               name: 'isFirst',
+               type: 'boolean'
+       },{
+               name: 'index',
+               type: 'int'
+       },{
+               name: 'isLast',
+               type: 'boolean'
+       },{
+               name: 'isExpandable',
+               type: 'boolean'
+       },{
+               name: 'isInsertedNode',
+               type: 'boolean'
+       },{
+               name: 'nodeData',
+               type: 'object'
+       }],
+       hasMany: {
+               name: 'children',
+               associationKey: 'children',
+               model: 'TYPO3.Components.PageTree.Model'
+       },
+               // Set method for nodeData fields
+       setNodeData: function (field, value) {
+               var nodeData = this.get('nodeData');
+               nodeData[field] = value;
+               this.set('nodeData', Ext.merge(this.get('nodeData'), nodeData));
+       },
+               // Get method for nodeData fields
+       getNodeData: function (field) {
+               return this.get('nodeData')[field];
+       }
+});
+Ext.define('TYPO3.Components.PageTree.Tree', {
+       extend: 'Ext.tree.Panel',
+       /**
+        * Use extended stateful mixin
+        *
+        * @type {Object}
+        */
+       mixins: {
+               state: 'Ext.ux.state.TreePanel'
+       },
+
+       /**
+        * View configuration
+        *
+        * @type {Object}
+        */
+       viewConfig: {
+               autoScroll: false,
+               border: false,
+               toggleOnDblClick: false
+       },
+
+       /**
+        * Columns
+        *
+        * @type {TYPO3.Components.PageTree.Column}[]
+        */
+       columns: [{
+                       xtype: 'pagetreecolumn',
+                       dataIndex: 'text',
+                       flex: 1,
+                       editor: {
+                               xtype: 'textfield',
+                               allowBlank: false
+                       }
+       }],
+
+       /**
+        * Header
+        *
+        * @type {Boolean}
+        */
+       hideHeaders: true,
+       preventHeader: true,
+
        /**
         * Border
         *
         * @type {Boolean}
         */
+       autoScroll: false,
        border: false,
 
        /**
-        * Indicates if the root node is visible
+        * Body css
         *
-        * @type {Boolean}
+        * @type {String}
         */
-       rootVisible: false,
+       bodyCls: 'typo3-pagetree',
 
        /**
-        * Tree Editor Instance (Inline Edit)
+        * Indicates if the root node is visible
         *
-        * @type {TYPO3.Components.PageTree.TreeEditor}
+        * @type {Boolean}
         */
-       treeEditor: null,
+       rootVisible: false,
 
        /**
         * Currently Selected Node
         *
-        * @type {Ext.tree.TreeNode}
+        * @type {TYPO3.Components.PageTree.Model}
         */
        currentSelectedNode: null,
 
@@ -78,18 +180,18 @@ TYPO3.Components.PageTree.Tree = Ext.extend(Ext.tree.TreePanel, {
        ddGroup: '',
 
        /**
-        * Indicates if the label should be editable
+        * Id of deletionDropZone
         *
-        * @cfg {Boolean}
+        * @cfg {String}
         */
-       labelEdit: true,
+       deletionDropZoneId: '',
 
        /**
-        * User Interface Provider
+        * Indicates if the label should be editable
         *
-        * @cfg {Ext.tree.TreeNodeUI}
+        * @cfg {Boolean}
         */
-       uiProvider: null,
+       labelEdit: true,
 
        /**
         * Data Provider
@@ -103,7 +205,7 @@ TYPO3.Components.PageTree.Tree = Ext.extend(Ext.tree.TreePanel, {
         *
         * @cfg {Object}
         */
-       commandProvider : null,
+       commandProvider: null,
 
        /**
         * Context menu provider
@@ -113,18 +215,18 @@ TYPO3.Components.PageTree.Tree = Ext.extend(Ext.tree.TreePanel, {
        contextMenuProvider: null,
 
        /**
-        * Id of the deletion drop zone if any
+        * Main applicaton
         *
-        * @cfg {String}
+        * @cfg {TYPO3.Components.PageTree.App}
         */
-       deletionDropZoneId: '',
+       app: null,
 
        /**
-        * Main applicaton
+        * Page Tree Store
         *
-        * @cfg {TYPO3.Components.PageTree.App}
+        * @type {Object}
         */
-       app: null,
+       store: null,
 
        /**
         * Root Node Configuration
@@ -140,16 +242,9 @@ TYPO3.Components.PageTree.Tree = Ext.extend(Ext.tree.TreePanel, {
        },
 
        /**
-        * Indicator if the control key is pressed
-        *
-        * @type {Boolean}
-        */
-       isControlPressed: false,
-
-       /**
         * Context Node
         *
-        * @type {Ext.tree.TreeNode}
+        * @type {TYPO3.Components.PageTree.Model}
         */
        t3ContextNode: null,
 
@@ -158,68 +253,52 @@ TYPO3.Components.PageTree.Tree = Ext.extend(Ext.tree.TreePanel, {
         *
         * @type {Object}
         */
-       t3ContextInfo: {
+        t3ContextInfo: {
                inCopyMode: false,
                inCutMode: false
        },
 
        /**
-        * Registered clicks for the double click feature
+        * Number of clicks to ignore for the label edit on dblclick feature
+        * Will be set to 2 by the tree editor
         *
         * @type {int}
         */
-       clicksRegistered: 0,
+       inhibitClicks: 0,
 
        /**
-        * Indicator if the control key was pressed
+        * Constructor
+        * Plugins are built by the parent constructor
         *
-        * @type {Boolean}
-        */
-       controlKeyPressed: false,
-
-       /**
-        * Listeners
-        *
-        * Event handlers that handle click events and synchronizes the label edit,
-        * double click and single click events in a useful way.
+        * @param {Object} config
+        * @return {void}
         */
-       listeners: {
-                       // single click handler that only triggers after a delay to let the double click event
-                       // a possibility to be executed (needed for label edit)
-               click: {
-                       fn: function(node, event) {
-                               if (this.clicksRegistered === 2) {
-                                       this.clicksRegistered = 0;
-                                       event.stopEvent();
-                                       return false;
-                               }
-
-                               this.clicksRegistered = 0;
-                               if (this.commandProvider.singleClick) {
-                                       this.commandProvider.singleClick(node, this);
-                               }
-                       },
-                       delay: 400
-               },
-
-                       // prevent the expanding / collapsing on double click
-               beforedblclick: {
-                       fn: function() {
-                               return false;
-                       }
-               },
-
-                       // prevents label edit on a selected node
-               beforeclick: {
-                       fn: function(node, event) {
-                               if (!this.clicksRegistered && this.getSelectionModel().isSelected(node)) {
-                                       node.fireEvent('click', node, event);
-                                       ++this.clicksRegistered;
-                                       return false;
-                               }
-                               ++this.clicksRegistered;
-                       }
+       constructor: function (config) {
+                       // Inline label editing feature
+               this.labelEdit = config.labelEdit || this.labelEdit;
+               if (this.labelEdit ) {
+                       var plugins = config.plugins || [];
+                       config.plugins = plugins.concat(
+                               Ext.create('TYPO3.Components.PageTree.TreeEditor', {
+                                       clicksToEdit: 2,
+                                       pluginId: 'treeEditor'
+                               })
+                       );
+               }
+                       // Drag & drop feature
+               if (this.enableDD) {
+                       config.viewConfig = Ext.applyIf(config.viewConfig || {}, this.viewConfig);
+                       var plugins = config.viewConfig.plugins || [];
+                       config.viewConfig.plugins = plugins.concat(
+                               Ext.create('TYPO3.Components.PageTree.plugin.TreeViewDragDrop', {
+                                       ddGroup: config.ddGroup,
+                                       pluginId: 'treeViewDragDrop'
+                               })
+                       );
+                       config.viewConfig.allowCopy = true;
                }
+                       // Call parent constructor
+               this.callParent([config]);
        },
 
        /**
@@ -227,28 +306,74 @@ TYPO3.Components.PageTree.Tree = Ext.extend(Ext.tree.TreePanel, {
         *
         * @return {void}
         */
-       initComponent: function() {
-               if (!this.uiProvider) {
-                       this.uiProvider = TYPO3.Components.PageTree.PageTreeNodeUI;
-               }
-               Ext.dd.DragDropMgr.useCache = false;
-               this.root = new Ext.tree.AsyncTreeNode(this.rootNodeConfig);
-               this.addTreeLoader();
-
-               if (this.labelEdit) {
-                       this.enableInlineEditor();
-               }
-
+       initComponent: function () {
+                       // Add the tree store
+               this.addStore();
+                       // Add single click handler that only triggers after a delay to let the double click event
+                       // a possibility to be executed (needed for label edit)
+               this.addListener('itemclick', this.onItemSingleClick, null, { delay: 400 });
+                       // Init component
+               this.callParent();
+                       // Drag & drop feature
                if (this.enableDD) {
-                       this.dragConfig = {ddGroup: this.ddGroup};
-                       this.enableDragAndDrop();
+                       this.getView().addListener('afterrender', this.enableDragAndDrop, this);
                }
-
+                       // Context menu feature
                if (this.contextMenuProvider) {
                        this.enableContextMenu();
                }
-
-               TYPO3.Components.PageTree.Tree.superclass.initComponent.apply(this, arguments);
+       },
+        
+       /**
+        * Adds the store to the tree
+        *
+        * @return {void}
+        */
+       addStore: function () {
+               this.store = Ext.data.StoreManager.lookup(this.getId() + 'PageTreeStore');
+               if (!this.store) {
+                       this.store = Ext.create('Ext.data.TreeStore', {
+                               clearOnLoad: false,
+                               listeners: {
+                                               // Remove nodes and add params to read operation
+                                       beforeload: {
+                                               fn: function (store, operation, options) {
+                                                       if (operation.node) {
+                                                               var node = operation.node;
+                                                               node.removeAll();
+                                                               node.commit();
+                                                               operation.params = {
+                                                                       nodeId: node.getNodeData('id'),
+                                                                       nodeData: node.get('nodeData')
+                                                                       
+                                                               };
+                                                       }
+                                               }
+                                       },
+                                               // Restore state on initial load
+                                       load: {
+                                               fn: function (store, node, records, successful) {
+                                                       if (successful) {
+                                                               this.restoreState();
+                                                       }
+                                               },
+                                               scope: this
+                                       }
+                               },
+                               model: 'TYPO3.Components.PageTree.Model',
+                               nodeParam: 'nodeId',
+                               proxy: {
+                                       type: 'direct',
+                                       directFn: this.treeDataProvider.getNextTreeLevel,
+                                       paramOrder: ['nodeId', 'nodeData'],
+                                       reader: {
+                                           type: 'json'
+                                       }
+                               },
+                               root: this.rootNodeConfig,
+                               storeId: this.getId() + 'PageTreeStore'
+                       });
+               }
        },
 
        /**
@@ -258,9 +383,9 @@ TYPO3.Components.PageTree.Tree = Ext.extend(Ext.tree.TreePanel, {
         * @param {Object} scope
         * return {void}
         */
-       refreshTree: function(callback, scope) {
-                       // remove readable rootline elements while refreshing
-               if (!this.inRefreshingMode) {
+       refreshTree: function (callback, scope) {
+                       // Remove readable rootline elements while refreshing
+               if (!this.store.isLoading()) {
                        var rootlineElements = Ext.select('.x-tree-node-readableRootline');
                        if (rootlineElements) {
                                rootlineElements.each(function(element) {
@@ -268,70 +393,54 @@ TYPO3.Components.PageTree.Tree = Ext.extend(Ext.tree.TreePanel, {
                                });
                        }
                }
-
-               this.refreshNode(this.root, callback, scope);
+               this.refreshNode(this.getRootNode(), callback, scope);
        },
 
        /**
         * Refreshes a given node
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {Function} callback
         * @param {Object} scope
         * return {void}
         */
-       refreshNode: function(node, callback, scope) {
-               if (this.inRefreshingMode) {
-                       return;
-               }
-
-               scope = scope || node;
-               this.inRefreshingMode = true;
-               var loadCallback = function(node) {
-                       node.ownerTree.inRefreshingMode = false;
-                       if (node.ownerTree.restoreState) {
-                               node.ownerTree.restoreState(node.getPath());
-                       }
-               };
-
-               if (callback) {
-                       loadCallback = callback.createSequence(loadCallback);
-               }
-
-               this.getLoader().load(node, loadCallback, scope);
+       refreshNode: function (node, callback, scope) {
+               this.store.load({
+                       node: node,
+                       callback: callback || Ext.emptyFn,
+                       scope: scope || this
+               });
        },
 
        /**
-        * Adds a tree loader implementation that uses the directFn feature
+        * Handles singe click on tree item
         *
-        * return {void}
+        * return {Boolean}
         */
-       addTreeLoader: function() {
-               this.loader = new Ext.tree.TreeLoader({
-                       directFn: this.treeDataProvider.getNextTreeLevel,
-                       paramOrder: 'nodeId,attributes',
-                       nodeParameter: 'nodeId',
-                       baseAttrs: {
-                               uiProvider: this.uiProvider
-                       },
-
-                               // an id can never be zero in ExtJS, but this is needed
-                               // for the root line feature or it will never be working!
-                       createNode: function(attr) {
-                               if (attr.id == 0) {
-                                       attr.id = 'siteRootNode';
-                               }
-
-                               return Ext.tree.TreeLoader.prototype.createNode.call(this, attr);
-                       },
+       onItemSingleClick: function (view, node, item, index, event) {
+               var tree = view.panel;
+                       // Check if the tree editor was triggered by dblclick
+                       // If so, stop the next two clicks
+               if (tree.inhibitClicks) {
+                       --tree.inhibitClicks;
+                       event.stopEvent();
+                       return false;
+               }
 
-                       listeners: {
-                               beforeload: function(treeLoader, node) {
-                                       treeLoader.baseParams.nodeId = node.id;
-                                       treeLoader.baseParams.attributes = node.attributes.nodeData;
-                               }
+               if (tree.commandProvider.singleClick) {
+                       tree.commandProvider.singleClick(node, tree);
+               }
+                       // Fire the context menu on a single click on the node icon (Beware of drag&drop!)
+               if (!TYPO3.Components.PageTree.Configuration.disableIconLinkToContextmenu
+                       || TYPO3.Components.PageTree.Configuration.disableIconLinkToContextmenu === '0'
+               ) {
+                       var target = event.getTarget('span.t3-icon-apps-pagetree');
+                       if (target) {
+                               view.fireEvent('itemcontextmenu', view, node, item, index, event);
+                               event.stopEvent();
                        }
-               });
+               }
+               return true;
        },
 
        /**
@@ -340,58 +449,33 @@ TYPO3.Components.PageTree.Tree = Ext.extend(Ext.tree.TreePanel, {
         * return {void}
         */
        enableContextMenu: function() {
-               this.contextMenu = new TYPO3.Components.PageTree.ContextMenu();
-
-               this.on('contextmenu', function(node, event) {
-                       this.openContextMenu(node, event);
+               this.contextMenu = Ext.create('TYPO3.Components.PageTree.ContextMenu', { pageTree: this });
+               this.getView().on('itemcontextmenu', function (view, node, item, index, event) {
+                       view.panel.openContextMenu(view, node, item, index, event);
                });
        },
 
        /**
         * Open a context menu for the given node
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {Ext.EventObject} event
         * return {void}
         */
-       openContextMenu: function(node, event) {
-               var attributes = Ext.apply(node.attributes.nodeData, {
-                       t3ContextInfo: node.ownerTree.t3ContextInfo
-               });
-
-               this.contextMenuProvider.getActionsForNodeArray(
-                       attributes,
-                       function(configuration) {
-                               this.contextMenu.removeAll();
-                               this.contextMenu.fill(node, this, configuration);
-                               if (this.contextMenu.items.length) {
-                                       this.contextMenu.showAt(event.getXY());
-
+       openContextMenu: function(view, node, item, index, event) {
+               var tree = view.panel;
+               node.setNodeData('t3ContextInfo', tree.t3ContextInfo);
+               tree.contextMenuProvider.getActionsForNodeArray(
+                       node.get('nodeData'),
+                       function (configuration) {
+                               tree.contextMenu.removeAll();
+                               tree.contextMenu.fill(node, tree, configuration);
+                               if (tree.contextMenu.items.length) {
+                                       tree.contextMenu.showAt(event.getXY());
                                }
-                       },
-                       this
+                       }
                );
-       },
-
-       /**
-        * Initialize the inline editor for the given tree.
-        *
-        * @return {void}
-        */
-       enableInlineEditor: function() {
-               this.treeEditor = new TYPO3.Components.PageTree.TreeEditor(this);
-       },
-
-       /**
-        * Triggers the editing of the node if the tree editor is available
-        *
-        * @param {Ext.tree.TreeNode} node
-        * @return {void}
-        */
-       triggerEdit: function(node) {
-               if (this.treeEditor) {
-                       this.treeEditor.triggerEdit(node);
-               }
+               event.stopEvent();
        },
 
        /**
@@ -400,208 +484,144 @@ TYPO3.Components.PageTree.Tree = Ext.extend(Ext.tree.TreePanel, {
         * return {void}
         */
        enableDragAndDrop: function() {
-                       // init proxy element
-               this.on('startdrag', this.initDd, this);
-               this.on('enddrag', this.stopDd, this);
-
-                       // node is moved
-               this.on('movenode', this.moveNode, this);
-
-                       // new node is created/copied
-               this.on('beforenodedrop', this.beforeDropNode, this);
-               this.on('nodedrop', this.dropNode, this);
-
-                       // listens on the ctrl key to toggle the copy mode
-               (new Ext.KeyMap(document, {
-                       key: Ext.EventObject.CONTROL,
-                       scope: this,
-                       buffer: 250,
-                       fn: function() {
-                               if (!this.controlKeyPressed && this.dragZone.dragging && this.copyHint) {
-                                       if (this.shouldCopyNode) {
-                                               this.copyHint.show();
-                                       } else {
-                                               this.copyHint.hide();
-                                       }
-
-                                       this.shouldCopyNode = !this.shouldCopyNode;
-                                       this.dragZone.proxy.el.toggleClass('typo3-pagetree-copy');
-                               }
-                               this.controlKeyPressed = true;
-                       }
-               }, 'keydown'));
-
-               (new Ext.KeyMap(document, {
-                       key: Ext.EventObject.CONTROL,
-                       scope: this,
-                       fn: function() {
-                               this.controlKeyPressed = false;
-                       }
-               }, 'keyup'));
-
-                       // listens on the escape key to stop the dragging
-               (new Ext.KeyMap(document, {
-                       key: Ext.EventObject.ESC,
-                       scope: this,
-                       buffer: 250,
-                       fn: function(event) {
-                               if (this.dragZone.dragging) {
-                                       Ext.dd.DragDropMgr.stopDrag(event);
-                                       this.dragZone.onInvalidDrop(event);
-                               }
-                       }
-               }, 'keydown'));
+               var view = this.getView();
+               var dragZone = view.getPlugin('treeViewDragDrop').dragZone;
+
+                       // Show drop zone before drag, otherwise the proxy is never notified
+               dragZone.onBeforeDrag = Ext.Function.bind(this.startDeletionDropZone, view);
+                       // Hide the drop zone after the drag completes
+               dragZone.onMouseUp = Ext.Function.bind(this.stopDeletionDropZone, view);
+               dragZone.endDrag = Ext.Function.bind(this.stopDeletionDropZone, view);
+               dragZone.afterInvalidDrop = Ext.Function.bind(this.stopDeletionDropZone, view, [true]);
+
+                       // Node is moved
+               this.on('itemmove', this.moveNode, this);
+
+                       // New node is created/copied
+               view.on('beforedrop', this.beforeDropNode, this);
+               view.on('drop', this.dropNode, this);
        },
 
        /**
-        * Disables the deletion drop zone if configured
+        * Enables the deletion drop zone if configured
         *
         * @return {void}
         */
-       stopDd: function() {
-               if (this.deletionDropZoneId) {
-                       Ext.getCmp(this.deletionDropZoneId).hide();
-                       this.app.doLayout();
-               }
-       },
-
-       /**
-        * Enables the deletion drop zone if configured. Also it creates the
-        * shown dd proxy element.
-        *
-        * @param {TYPO3.Components.PageTree.Tree} treePanel
-        * @param {Ext.tree.TreeNode} node
-        * @return {void}
-        */
-       initDd: function(treePanel, node) {
-               var nodeHasChildNodes = (node.hasChildNodes() || node.isExpandable());
-               if (this.deletionDropZoneId &&
+       startDeletionDropZone: function (dragData, event) {
+               var view = dragData.view,
+                       tree = view.panel,
+                       node = view.getRecord(dragData.item),
+                       nodeHasChildNodes = (node.hasChildNodes() || node.isExpandable());
+               var tree = this.panel;
+               if (tree.deletionDropZoneId &&
                        (!nodeHasChildNodes ||
                        (nodeHasChildNodes && TYPO3.Components.PageTree.Configuration.canDeleteRecursivly)
                )) {
-                       Ext.getCmp(this.deletionDropZoneId).show();
-                       this.app.doLayout();
+                       Ext.getCmp(tree.deletionDropZoneId).show();
                }
-               this.initDDProxyElement();
        },
 
        /**
-        * Adds the copy hint to the proxy element
+        * Disables the deletion drop zone if configured
         *
         * @return {void}
         */
-       initDDProxyElement: function() {
-               this.shouldCopyNode = false;
-               this.copyHint = new Ext.Element(document.createElement('div')).addClass(this.id + '-copy');
-               this.copyHint.dom.appendChild(document.createTextNode(TYPO3.Components.PageTree.LLL.copyHint));
-               this.copyHint.setVisibilityMode(Ext.Element.DISPLAY);
-               this.dragZone.proxy.el.shadow = false;
-               this.dragZone.proxy.ghost.dom.appendChild(this.copyHint.dom);
+       stopDeletionDropZone: function (forceStop) {
+               var tree = this.panel;
+               if (tree.deletionDropZoneId && (!this.getPlugin('treeViewDragDrop').dragZone.dragging || forceStop)) {
+                       Ext.getCmp(tree.deletionDropZoneId).hide();
+               }
        },
 
        /**
-        * Creates a Fake Node
+        * Creates a place holder node when a new node is about to be dropped
         *
-        * This must be done to prevent the calling of the moveNode event.
-        *
-        * @param {object} dragElement
+        * @param {HTMLElement node} node
+        * @param {object} dragData
+        * @param {TYPO3.Components.PageTree.Model} overNode
+        * @param {string} dropPosition
+        * @return {boolean}
         */
-       beforeDropNode: function(dragElement) {
-               if (dragElement.data && dragElement.data.item && dragElement.data.item.shouldCreateNewNode) {
-                       this.t3ContextInfo.serverNodeType = dragElement.data.item.nodeType;
-                       dragElement.dropNode = new Ext.tree.TreeNode({
+       beforeDropNode: function (node, dragData, overNode, dropPosition) {
+               if (dragData && dragData.item && dragData.item.shouldCreateNewNode) {
+                               // Inserting a new node of the type that was selected in the top panel
+                       this.t3ContextInfo.serverNodeType = dragData.item.nodeType;
+                       dragData.dropNode = Ext.create('TYPO3.Components.PageTree.Model', {
                                text: TYPO3.Components.PageTree.LLL.fakeNodeHint,
                                leaf: true,
                                isInsertedNode: true
                        });
-
-                               // fix incorrect cancel value
-                       dragElement.cancel = false;
-
-               } else if (this.shouldCopyNode) {
-                       dragElement.dropNode.ui.onOut();
-                       var attributes = dragElement.dropNode.attributes;
-                       attributes.isCopiedNode = true;
-                       attributes.id = 'fakeNode';
-                       dragElement.dropNode = new Ext.tree.TreeNode(attributes);
+                       dragData.records = [dragData.dropNode];
                }
-
                return true;
        },
 
        /**
-        * Differentiate between the copy and insert event
+        * Handle the copy and insert events
         *
-        * @param {Ext.tree.TreeDropZone} dragElement
+        * @param {HTMLElement node} node
+        * @param {object} dragData
+        * @param {TYPO3.Components.PageTree.Model} overNode
+        * @param {string} dropPosition
         * return {void}
         */
-       dropNode: function(dragElement) {
-               this.controlKeyPressed = false;
-               if (dragElement.dropNode.attributes.isInsertedNode) {
-                       dragElement.dropNode.attributes.isInsertedNode = false;
-                       this.insertNode(dragElement.dropNode);
-               } else if (dragElement.dropNode.attributes.isCopiedNode) {
-                       dragElement.dropNode.attributes.isCopiedNode = false;
-                       this.copyNode(dragElement.dropNode)
+       dropNode: function (node, dragData, overNode, dropPosition) {
+               if (dragData.dropNode) {
+                       if (dragData.dropNode.get('isInsertedNode')) {
+                               dragData.dropNode.set('isInsertedNode', false);
+                               this.insertNode(dragData.dropNode);
+                       }
+               } else if (dragData.copy) {
+                       this.copyNode(dragData.records[0]);
                }
        },
 
        /**
         * Moves a node
         *
-        * @param {TYPO3.Components.PageTree.Tree} tree
-        * @param {Ext.tree.TreeNode} movedNode
-        * @param {Ext.tree.TreeNode} oldParent
-        * @param {Ext.tree.TreeNode} newParent
+        * @param {TYPO3.Components.PageTree.Model} movedNode
+        * @param {TYPO3.Components.PageTree.Model} oldParent
+        * @param {TYPO3.Components.PageTree.Model} newParent
         * @param {int} position
         * return {void}
         */
-       moveNode: function(tree, movedNode, oldParent, newParent, position) {
-               this.controlKeyPressed = false;
-               tree.t3ContextNode = movedNode;
-
+       moveNode: function (movedNode, oldParent, newParent, position) {
+               this.t3ContextNode = movedNode;
                if (position === 0) {
-                       this.commandProvider.moveNodeToFirstChildOfDestination(newParent, tree);
+                       this.commandProvider.moveNodeToFirstChildOfDestination(newParent, this);
                } else {
                        var previousSiblingNode = newParent.childNodes[position - 1];
-                       this.commandProvider.moveNodeAfterDestination(previousSiblingNode, tree);
+                       this.commandProvider.moveNodeAfterDestination(previousSiblingNode, this);
                }
        },
 
        /**
         * Inserts a node
         *
-        * @param {Ext.tree.TreeNode} movedNode
+        * @param {TYPO3.Components.PageTree.Model} node
         * return {void}
         */
-       insertNode: function(movedNode) {
-               this.t3ContextNode = movedNode.parentNode;
-
-               movedNode.disable();
-               if (movedNode.previousSibling) {
-                       this.commandProvider.insertNodeAfterDestination(movedNode, this);
+       insertNode: function (node) {
+               this.t3ContextNode = node.parentNode;
+               if (node.previousSibling) {
+                       this.commandProvider.insertNodeAfterDestination(node, this);
                } else {
-                       this.commandProvider.insertNodeToFirstChildOfDestination(movedNode, this);
+                       this.commandProvider.insertNodeToFirstChildOfDestination(node, this);
                }
        },
 
        /**
         * Copies a node
         *
-        * @param {Ext.tree.TreeNode} movedNode
+        * @param {TYPO3.Components.PageTree.Model} movedNode
         * return {void}
         */
-       copyNode: function(movedNode) {
-               this.t3ContextNode = movedNode;
-
-               movedNode.disable();
-               if (movedNode.previousSibling) {
-                       this.commandProvider.copyNodeAfterDestination(movedNode, this);
+       copyNode: function (node) {
+               this.t3ContextNode = node;
+               if (node.previousSibling) {
+                       this.commandProvider.copyNodeAfterDestination(node, this);
                } else {
-                       this.commandProvider.copyNodeToFirstChildOfDestination(movedNode, this);
+                       this.commandProvider.copyNodeToFirstChildOfDestination(node, this);
                }
        }
 });
-
-// XTYPE Registration
-Ext.reg('TYPO3.Components.PageTree.Tree', TYPO3.Components.PageTree.Tree);
diff --git a/t3lib/js/extjs/components/pagetree/javascript/treedropzone.js b/t3lib/js/extjs/components/pagetree/javascript/treedropzone.js
new file mode 100644 (file)
index 0000000..2f4888c
--- /dev/null
@@ -0,0 +1,112 @@
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2011 Stanislas Rolland <typo3@sjbr.ca>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*  A copy is found in the textfile GPL.txt and important notices to the license
+*  from the author is found in LICENSE.txt distributed with these scripts.
+*
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+/**
+ * @class TYPO3.Components.PageTree.ViewDropZone
+ *
+ * handleNodeDrop method is modified in order to process copied nodes
+ * 
+ * Based on ExtJS 4.0.7.
+ * Should be reviewed on ExtJS upgrade
+ *
+ * @namespace TYPO3.Components.PageTree
+ * @extends Ext.tree.ViewDropZone
+ * @author Stanislas Rolland <typo3@sjbr.ca>
+ */
+Ext.define('TYPO3.Components.PageTree.ViewDropZone', {
+       extend: 'Ext.tree.ViewDropZone',
+
+       handleNodeDrop: function(data, targetNode, position) {
+               var me = this,
+                       view = me.view,
+                       parentNode = targetNode.parentNode,
+                       store = view.getStore(),
+                       recordDomNodes = [],
+                       records, i, len,
+                       insertionMethod, argList,
+                       needTargetExpand,
+                       transferData,
+                       processDrop;
+
+               if (data.copy) {
+                       records = data.records;
+                       data.records = [];
+                       for (i = 0, len = records.length; i < len; i++) {
+                               data.records.push(Ext.apply({}, records[i].data));
+                       }
+               }
+
+               me.cancelExpand();
+
+               if (position == 'before') {
+                       insertionMethod = parentNode.insertBefore;
+                       argList = [null, targetNode];
+                       targetNode = parentNode;
+               } else if (position == 'after') {
+                       if (targetNode.nextSibling) {
+                               insertionMethod = parentNode.insertBefore;
+                               argList = [null, targetNode.nextSibling];
+                       } else {
+                               insertionMethod = parentNode.appendChild;
+                               argList = [null];
+                       }
+                       targetNode = parentNode;
+               } else {
+                       if (!targetNode.isExpanded()) {
+                               needTargetExpand = true;
+                       }
+                       insertionMethod = targetNode.appendChild;
+                       argList = [null];
+               }
+
+               transferData = function() {
+                       var node;
+                       for (i = 0, len = data.records.length; i < len; i++) {
+                               argList[0] = data.records[i];
+                               node = insertionMethod.apply(targetNode, argList);
+                                       // We need to update the records array in order to process the copied nodes in the drop event handler
+                               data.records[i] = node;
+
+                               if (Ext.enableFx && me.dropHighlight) {
+                                       recordDomNodes.push(view.getNode(node));
+                               }
+                       }
+
+                       if (Ext.enableFx && me.dropHighlight) {
+                               Ext.Array.forEach(recordDomNodes, function(n) {
+                                       if (n) {
+                                               Ext.fly(n.firstChild ? n.firstChild : n).highlight(me.dropHighlightColor);
+                                       }
+                               });
+                       }
+               };
+
+               if (needTargetExpand) {
+                       targetNode.expand(false, transferData);
+               } else {
+                       transferData();
+               }
+       }
+});
\ No newline at end of file
index 0d12e7d..5daa34e 100644 (file)
@@ -23,8 +23,6 @@
 *
 *  This copyright notice MUST APPEAR in all copies of the script!
 ***************************************************************/
-Ext.namespace('TYPO3.Components.PageTree');
-
 /**
  * @class TYPO3.Components.PageTree.TreeEditor
  *
@@ -32,30 +30,46 @@ Ext.namespace('TYPO3.Components.PageTree');
  * editable label.
  *
  * @namespace TYPO3.Components.PageTree
- * @extends Ext.tree.TreeEditor
+ * @extends Ext.ux.tree.TreeEditing
  * @author Stefan Galinski <stefan.galinski@gmail.com>
  */
-TYPO3.Components.PageTree.TreeEditor = Ext.extend(Ext.tree.TreeEditor, {
-       /**
-        * Don't send any save events if the value wasn't changed
-        *
-        * @type {Boolean}
-        */
-       ignoreNoChange: false,
+Ext.define('TYPO3.Components.PageTree.TreeEditor', {
+       extend: 'Ext.grid.plugin.CellEditing',
+       alias: 'plugin.pagetreeeditor',
 
        /**
-        * Edit delay
-        *
-        * @type {int}
+        * @override
+        * @private Collects all information necessary for any subclasses to perform their editing functions.
+        * @param record
+        * @param columnHeader
+        * @returns {Object} The editing context based upon the passed record and column
         */
-       editDelay: 250,
+       getEditingContext: function (record, columnHeader) {
+               var me = this,
+                       grid = me.grid,
+                       store = grid.store,
+                       colIdx,
+                       editor,
+                       originalValue,
+                       value;
 
-       /**
-        * Indicates if an underlying shadow should be shown
-        *
-        * @type {Boolean}
-        */
-       shadow: false,
+               if (Ext.isNumber(columnHeader)) {
+                       colIdx = columnHeader;
+                       columnHeader = grid.headerCt.getHeaderAtIndex(colIdx);
+               } else {
+                       colIdx = columnHeader.getIndex();
+               }
+
+               return {
+                       column: columnHeader,
+                       colIdx: colIdx,
+                       field: columnHeader.dataIndex,
+                       grid: grid,
+                       originalValue: record.getNodeData('editableText'),
+                       record: record,
+                       tree: grid
+               };
+       },
 
        /**
         * Listeners
@@ -63,80 +77,66 @@ TYPO3.Components.PageTree.TreeEditor = Ext.extend(Ext.tree.TreeEditor, {
         * Handles the synchronization between the edited label and the shown label.
         */
        listeners: {
-               beforecomplete: function(node) {
-                       this.updatedValue = this.getValue();
-                       if (this.updatedValue === '') {
-                               this.cancelEdit();
-                               return false;
-                       }
-                       this.setValue(this.editNode.attributes.prefix + Ext.util.Format.htmlEncode(this.updatedValue) + this.editNode.attributes.suffix);
-               },
-
-               complete: {
-                       fn: function(node, newValue, oldValue) {
-                               if (newValue === oldValue) {
-                                       this.fireEvent('canceledit', this);
+               beforeedit: {
+                       fn: function (editEvent) {
+                               var tree = editEvent.tree;
+                                       // Prevent editing the currently selected node
+                                       // Prevent editing if the node is not editable
+                               if (editEvent.record == tree.currentSelectedNode || !editEvent.record.getNodeData('editable')) {
+                                       if (tree.currentSelectedNode) {
+                                               tree.getView().select(tree.currentSelectedNode);
+                                       }
                                        return false;
                                }
-
-                               this.editNode.getOwnerTree().commandProvider.saveTitle(node, this.updatedValue, oldValue, this);
+                                       // Inhibit clicks on the tree while editing
+                               tree.inhibitClicks = 2;
                        }
                },
-
-               startEdit: {
-                       fn: function(element, value) {
-                               this.field.selectText();
+               validateedit: {
+                       fn: function (treeEditor, editEvent) {
+                               var editorField = treeEditor.getEditor(editEvent.record, editEvent.column);
+                               this.newValue = editorField.getValue();
+                               if (this.newValue === '' || this.newValue === editEvent.originalValue) {
+                                       var tree = editEvent.tree;
+                                       if (tree.currentSelectedNode) {
+                                               tree.getView().select(tree.currentSelectedNode);
+                                       }
+                                       return false;
+                               } else {
+                                       editorField.setValue(editEvent.record.getNodeData('prefix') + Ext.util.Format.htmlEncode(this.newValue) + editEvent.record.getNodeData('suffix'));
+                               }
+                               
                        }
                },
-
-               canceledit: function() {
-                       var tree = this.editNode.getOwnerTree();
-                       if (tree.currentSelectedNode) {
-                               tree.currentSelectedNode.select();
+               edit: {
+                       fn: function (treeEditor, editEvent) {
+                               var tree = editEvent.tree;
+                               tree.commandProvider.saveTitle(editEvent.record, this.newValue, editEvent.originalValue, treeEditor, tree, editEvent.field);
                        }
                }
        },
+       cancelEdit: function () {
+               var tree = this.grid;
+               if (tree.currentSelectedNode) {
+                       tree.getView().select(tree.currentSelectedNode);
+               }
+               this.callParent(arguments);
+       },
 
        /**
-        * Updates the edit node
+        * Updates the text field
         *
-        * @param {Ext.tree.TreeNode} node
+        * @param {TYPO3.Components.PageTree.Model} node
         * @param {String} editableText
-        * @param {String} updatedNode
+        * @param {String} updatedText
+        * @param {String} dataIndex
+        * @param {TYPO3.Components.PageTree.Tree} tree
         * @return {void}
         */
-       updateNodeText: function(node, editableText, updatedNode) {
-               this.editNode.setText(this.editNode.attributes.prefix + updatedNode + this.editNode.attributes.suffix);
-               this.editNode.attributes.editableText = editableText;
-       },
-
-       /**
-        * Overridden method to set another editable text than the node text attribute
-        *
-        * @param {Ext.tree.TreeNode} node
-        * @return {Boolean}
-        */
-       triggerEdit: function(node) {
-               this.completeEdit();
-               if (node.attributes.editable !== false) {
-                       this.editNode = node;
-                       if (this.tree.autoScroll) {
-                               Ext.fly(node.ui.getEl()).scrollIntoView(this.tree.body);
-                       }
-
-                       var value = node.text || '';
-                       if (!Ext.isGecko && Ext.isEmpty(node.text)) {
-                               node.setText(' ');
-                       }
-
-                               // TYPO3 MODIFICATION to use another attribute
-                       value = node.attributes.editableText;
-
-                       this.autoEditTimer = this.startEdit.defer(this.editDelay, this, [node.ui.textNode, value]);
-                       return false;
-               }
+       updateNodeText: function (record, editableText, updatedText, dataIndex, tree) {
+               record.set(dataIndex, record.getNodeData('prefix') + updatedText + record.getNodeData('suffix'));
+               record.setNodeData('editableText', editableText);
+               record.commit();
+               tree.getView().refresh(record.getId());
        }
 });
-
-// XTYPE Registration
-Ext.reg('TYPO3.Components.PageTree.TreeEditor', TYPO3.Components.PageTree.TreeEditor);
diff --git a/t3lib/js/extjs/components/pagetree/javascript/treeviewdragdrop.js b/t3lib/js/extjs/components/pagetree/javascript/treeviewdragdrop.js
new file mode 100644 (file)
index 0000000..b0c5bee
--- /dev/null
@@ -0,0 +1,65 @@
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2011 Stanislas Rolland <typo3@sjbr.ca>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*  A copy is found in the textfile GPL.txt and important notices to the license
+*  from the author is found in LICENSE.txt distributed with these scripts.
+*
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+/**
+ * @class TYPO3.Components.PageTree.plugin.TreeViewDragDrop
+ *
+ * onViewRender method is modified in order to use TYPO3.Components.PageTree.ViewDropZone
+ *
+ * @namespace TYPO3.Components.PageTree
+ * @extends Ext.tree.plugin.TreeViewDragDrop
+ * @author Stanislas Rolland <typo3@sjbr.ca>
+ */
+Ext.define('TYPO3.Components.PageTree.plugin.TreeViewDragDrop', {
+    extend: 'Ext.tree.plugin.TreeViewDragDrop',
+    alias: 'plugin.pagetreeviewdragdrop',
+
+    onViewRender: function(view) {
+        var me = this;
+
+        if (me.enableDrag) {
+            me.dragZone = Ext.create('Ext.tree.ViewDragZone', {
+                view: view,
+                ddGroup: me.dragGroup || me.ddGroup,
+                dragText: me.dragText,
+                repairHighlightColor: me.nodeHighlightColor,
+                repairHighlight: me.nodeHighlightOnRepair
+            });
+        }
+
+        if (me.enableDrop) {
+            me.dropZone = Ext.create('TYPO3.Components.PageTree.ViewDropZone', {
+                view: view,
+                ddGroup: me.dropGroup || me.ddGroup,
+                allowContainerDrops: me.allowContainerDrops,
+                appendOnly: me.appendOnly,
+                allowParentInserts: me.allowParentInserts,
+                expandDelay: me.expandDelay,
+                dropHighlightColor: me.nodeHighlightColor,
+                dropHighlight: me.nodeHighlightOnDrop
+            });
+        }
+    }
+});
\ No newline at end of file
index f0cad39..bbd2624 100644 (file)
  *
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
-
-Ext.ns('TYPO3.Components', 'TYPO3.Components.Tree');
-
 /**
  * TYPO3window - General TYPO3 tree component
  */
+Ext.ns('TYPO3.Components.Tree');
 
 TYPO3.Components.Tree = {};
 TYPO3.Components.Tree.StandardTreeItemData = [];
 
-TYPO3.Components.Tree.StandardTree = function(config) {
-       var conf = Ext.apply({
-               header: false,
-               width: 280,
-               rootVisible: false,
-               useArrows: false,
-               lines: true,
-               autoScroll: true,
-               containerScroll: true,
-               exclusiveSelectedKey: null,
-               stateful: true,
-               filterOptionStartsWith: true,
-               countSelectedNodes: 0,
-               loader: new Ext.tree.TreeLoader({
-                       preloadChildren: true,
-                       clearOnLoad: false
-               }),
-               root: new Ext.tree.AsyncTreeNode({
-                       text: TYPO3.l10n.localize('tcatree'),
-                       id: 'root',
-                       expanded: true,
-                       children: TYPO3.Components.Tree.StandardTreeItemData[config.id]
-               }),
-               collapseFirst: false,
-               listeners: {
-                       'checkchange': function(checkedNode, checked) {
-                               if (Ext.isFunction(this.checkChangeHandler)) {
-                                       this.checkChangeHandler.call(this, checkedNode, checked);
-                               }
-                       },
-                       scope: this
-               }
-       }, config);
-       TYPO3.Components.Tree.StandardTree.superclass.constructor.call(this, conf);
-};
-
-
-Ext.extend(TYPO3.Components.Tree.StandardTree, Ext.tree.TreePanel, {
-
+Ext.define('TYPO3.Components.Tree.StandardTree', {
+       extend: 'Ext.tree.Panel',
+       
+       constructor: function(config) {
+               var conf = Ext.apply({
+                       header: false,
+                       width: 280,
+                       rootVisible: false,
+                       useArrows: false,
+                       lines: true,
+                       autoScroll: true,
+                       containerScroll: true,
+                       exclusiveSelectedKey: null,
+                       stateful: true,
+                       filterOptionStartsWith: true,
+                       countSelectedNodes: 0,
+                               // Needs to be migrated to ExtJS 4
+                       loader: new Ext.tree.TreeLoader({
+                               preloadChildren: true,
+                               clearOnLoad: false
+                       }),
+                       root: new Ext.tree.AsyncTreeNode({
+                               text: TYPO3.l10n.localize('tcatree'),
+                               id: 'root',
+                               expanded: true,
+                               children: TYPO3.Components.Tree.StandardTreeItemData[config.id]
+                       }),
+                       collapseFirst: false,
+                       listeners: {
+                               'checkchange': function(checkedNode, checked) {
+                                       if (Ext.isFunction(this.checkChangeHandler)) {
+                                               this.checkChangeHandler.call(this, checkedNode, checked);
+                                       }
+                               },
+                               scope: this
+                       }
+               }, config);
+               this.callParent([conf]);
+       },
        initComponent: function() {
-               Ext.apply(this, {
-                       tbar: this.initialConfig.showHeader ? TYPO3.Components.Tree.Toolbar([], this) : null
-               });
-               TYPO3.Components.Tree.StandardTree.superclass.initComponent.call(this);
+               if (this.initialConfig.showHeader) {
+                       Ext.apply(this, {
+                               dockedItems: [{
+                                       xtype: 'toolbar',
+                                       dock: 'top',
+                                       items: TYPO3.Components.Tree.Toolbar([], this)
+                               }]
+                       });
+               }
+               this.callParent(arguments);
        },
        filterTree: function(filterText) {
                var text = filterText.getValue();
@@ -139,7 +143,7 @@ TYPO3.Components.Tree.Toolbar = function(items, scope) {
                                ]
                        }
                },
-               new Ext.form.TextField({
+               Ext.create('Ext.form.field.Text', {
                        width: 150,
                        emptyText: TYPO3.l10n.localize('tcatree.findItem'),
                        enableKeyEvents: true,
index cda0925..5ba1ae3 100644 (file)
@@ -63,7 +63,7 @@ abstract class t3lib_tree_AbstractTree {
        }
 
        /**
-        * @param t3lib_tree_renderer_Abstract $dataProvider
+        * @param t3lib_tree_renderer_Abstract $nodeRenderer
         * @return void
         */
        public function setNodeRenderer(t3lib_tree_renderer_Abstract $nodeRenderer) {
@@ -83,6 +83,15 @@ abstract class t3lib_tree_AbstractTree {
         * @return t3lib_tree_Node
         */
        abstract public function getRoot();
+
+       /**
+        * @param mixed $search
+        * @return t3lib_tree_Node
+        */
+       public function find($search) {
+               return $this->getRoot()->find($search);
+       }
+
 }
 
 ?>
\ No newline at end of file
index dd09888..319307c 100644 (file)
@@ -62,7 +62,6 @@ class t3lib_tree_Node implements t3lib_tree_ComparableNode, Serializable {
         * This is useful for the deserialization.
         *
         * @param array $data
-        * @return void
         */
        public function __construct(array $data = array()) {
                if (count($data)) {
@@ -107,7 +106,7 @@ class t3lib_tree_Node implements t3lib_tree_ComparableNode, Serializable {
         * @return boolean
         */
        public function hasChildNodes() {
-               if ($this->childNodes !== NULL) {
+               if ($this->childNodes != NULL && $this->childNodes->count() > 0) {
                        return TRUE;
                }
 
@@ -214,7 +213,7 @@ class t3lib_tree_Node implements t3lib_tree_ComparableNode, Serializable {
         * @param array $data
         * @return void
         */
-       public function dataFromArray($data) {
+       public function dataFromArray(array $data) {
                $this->setId($data['id']);
 
                if (isset($data['parentNode']) && $data['parentNode'] !== '') {
@@ -255,6 +254,43 @@ class t3lib_tree_Node implements t3lib_tree_ComparableNode, Serializable {
                }
                $this->dataFromArray($arrayRepresentation);
        }
+
+       /**
+        * searches the tree to find an node
+        *
+        * @param mixed $search
+        * @return t3lib_tree_Node
+        */
+       public function find($search) {
+               $result = NULL;
+
+               if($this->getId() == $search) {
+                       $result = $this;
+               } elseif($this->hasChildNodes() && $this->getChildNodes() != NULL) {
+                       foreach ($this->getChildNodes() AS $childNode) {
+                               $result = $childNode->find($search);
+                               if ($result != NULL) {
+                                       break;
+                               }
+                       }
+               }
+
+               return $result;
+       }
+
+       public function getLevel() {
+               if ($this->getParentNode() == NULL) {
+                       return 0;
+               } else {
+                       $i = 1;
+                       $node = $this->getParentNode();
+                       while ($node != NULL) {
+                               $node = $node->getParentNode();
+                               $i++;
+                       }
+                       return $i;
+               }
+       }
 }
 
 ?>
\ No newline at end of file
index 266f11e..e1a9293 100644 (file)
@@ -62,7 +62,9 @@ class t3lib_tree_NodeCollection extends ArrayObject {
         *
         * @noapi
         * @see t3lib_tree_Node::compareTo
-        * @return void
+        * @param t3lib_tree_Node $node
+        * @param t3lib_tree_Node $otherNode
+        * @return int
         */
        public function nodeCompare(t3lib_tree_Node $node, t3lib_tree_Node $otherNode) {
                return $node->compareTo($otherNode);
index 8a9482a..4c64a73 100644 (file)
@@ -32,6 +32,7 @@
  * @author Steffen Ritter <info@steffen-ritter.net>
  * @package TYPO3
  * @subpackage t3lib
+ * @deprecated Not needed anymore as of 4.7, will be removed on 4.9
  */
 class t3lib_tree_RepresentationNode extends t3lib_tree_Node {
        /**
@@ -69,6 +70,10 @@ class t3lib_tree_RepresentationNode extends t3lib_tree_Node {
         */
        protected $callbackAction = '';
 
+       public function __construct() {
+               t3lib_div::deprecationLog("The Class t3lib_tree_RepresentationNode is deprecated as of TYPO3 4.7, will be removed in 4.9");
+       }
+
        /**
         * @param string $class
         * @return void
diff --git a/t3lib/tree/extdirect/class.t3lib_tree_extdirect_abstractextjstree.php b/t3lib/tree/extdirect/class.t3lib_tree_extdirect_abstractextjstree.php
deleted file mode 100644 (file)
index 8dcfe32..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-<?php
-/***************************************************************
- *  Copyright notice
- *
- *  (c) 2010-2011 TYPO3 Tree Team <http://forge.typo3.org/projects/typo3v4-extjstrees>
- *  All rights reserved
- *
- *  This script is part of the TYPO3 project. The TYPO3 project is
- *  free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  The GNU General Public License can be found at
- *  http://www.gnu.org/copyleft/gpl.html.
- *  A copy is found in the textfile GPL.txt and important notices to the license
- *  from the author is found in LICENSE.txt distributed with these scripts.
- *
- *
- *  This script is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  This copyright notice MUST APPEAR in all copies of the script!
- ***************************************************************/
-
-/**
- * Abstract ExtJS tree based on ExtDirect
- *
- * @author Stefan Galinski <stefan.galinski@gmail.com>
- * @package TYPO3
- * @subpackage t3lib
- */
-abstract class t3lib_tree_ExtDirect_AbstractExtJsTree extends t3lib_tree_AbstractTree {
-
-       /**
-        * State Provider
-        *
-        * @var t3lib_tree_AbstractStateProvider
-        */
-       protected $stateProvider = NULL;
-
-       /**
-        * @param t3lib_tree_AbstractStateProvider $stateProvider
-        * @return void
-        */
-       public function setStateProvider(t3lib_tree_AbstractStateProvider $stateProvider) {
-               $this->stateProvider = $stateProvider;
-       }
-
-       /**
-        * @return t3lib_tree_AbstractStateProvider
-        */
-       public function getStateProvider() {
-               return $this->stateProvider;
-       }
-
-       /**
-        * Fetches the next tree level
-        *
-        * @abstract
-        * @param int $nodeId
-        * @param stdClass $nodeData
-        * @return array
-        */
-       abstract public function getNextTreeLevel($nodeId, $nodeData);
-}
-
-?>
\ No newline at end of file
diff --git a/t3lib/tree/extdirect/class.t3lib_tree_extdirect_node.php b/t3lib/tree/extdirect/class.t3lib_tree_extdirect_node.php
deleted file mode 100644 (file)
index 625ad00..0000000
+++ /dev/null
@@ -1,635 +0,0 @@
-<?php
-/***************************************************************
-*  Copyright notice
-*
-*  (c) 2010-2011 TYPO3 Tree Team <http://forge.typo3.org/projects/typo3v4-extjstrees>
-*  All rights reserved
-*
-*  This script is part of the TYPO3 project. The TYPO3 project is
-*  free software; you can redistribute it and/or modify
-*  it under the terms of the GNU General Public License as published by
-*  the Free Software Foundation; either version 2 of the License, or
-*  (at your option) any later version.
-*
-*  The GNU General Public License can be found at
-*  http://www.gnu.org/copyleft/gpl.html.
-*  A copy is found in the textfile GPL.txt and important notices to the license
-*  from the author is found in LICENSE.txt distributed with these scripts.
-*
-*
-*  This script is distributed in the hope that it will be useful,
-*  but WITHOUT ANY WARRANTY; without even the implied warranty of
-*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-*  GNU General Public License for more details.
-*
-*  This copyright notice MUST APPEAR in all copies of the script!
-***************************************************************/
-
-/**
- * Node for the usage with ExtDirect and ExtJS
- *
- * @author Stefan Galinski <stefan.galinski@gmail.com>
- * @package TYPO3
- * @subpackage t3lib
- */
-class t3lib_tree_extdirect_Node extends t3lib_tree_Node {
-       /**
-        * Node type
-        *
-        * @var string
-        */
-       protected $type = '';
-
-       /**
-        * Leaf Node Indicator
-        *
-        * @var bool
-        */
-       protected $leaf = TRUE;
-
-       /**
-        * Indicator if the node is expanded
-        *
-        * @var bool
-        */
-       protected $expanded = FALSE;
-
-       /**
-        * Indicator if the node can be expanded
-        *
-        * @var bool
-        */
-       protected $expandable = FALSE;
-
-       /**
-        * Indicator if the node is draggable
-        *
-        * @var bool
-        */
-       protected $draggable = TRUE;
-
-       /**
-        * Indicator if the node is allowed as a drop target
-        *
-        * @var bool
-        */
-       protected $isDropTarget = TRUE;
-
-       /**
-        * Label
-        *
-        * @var string
-        */
-       protected $text = '';
-
-       /**
-        * Editable Label text
-        *
-        * @var string
-        */
-       protected $editableText = '';
-
-       /**
-        * Prefix text of the label
-        *
-        * @var string
-        */
-       protected $prefix = '';
-
-       /**
-        * Suffix text of the label
-        *
-        * @var string
-        */
-       protected $suffix = '';
-
-       /**
-        * CSS Class
-        *
-        * @var string
-        */
-       protected $cls = '';
-
-       /**
-        * Quick Tip
-        *
-        * @var string
-        */
-       protected $qtip = '';
-
-       /**
-        * Sprite Icon HTML
-        *
-        * @var string
-        */
-       protected $spriteIconCode = '';
-
-       /**
-        * Text source field (title, nav_title, ...)
-        *
-        * @var string
-        */
-       protected $t3TextSourceField = '';
-
-       /**
-        * Indicator if the copy mode is activated
-        *
-        * @var bool
-        */
-       protected $t3InCopyMode = FALSE;
-
-       /**
-        * Indicator if the cut mode is activated
-        *
-        * @var bool
-        */
-       protected $t3InCutMode = FALSE;
-
-       /**
-        * Database record (not serialized or merged into the result array!)
-        *
-        * @var array
-        */
-       protected $record = array();
-
-       /**
-        * Context Info
-        *
-        * @var array
-        */
-       protected $contextInfo = array();
-
-       /**
-        * Indicator if the label is editable
-        *
-        * @var bool
-        */
-       protected $labelIsEditable = TRUE;
-
-       /**
-        * Indicator if the node can have children's
-        *
-        * @var bool
-        */
-       protected $allowChildren = TRUE;
-
-       /**
-        * Set's the node type
-        *
-        * @param string $type
-        * @return void
-        */
-       public function setType($type) {
-               $this->type = $type;
-       }
-
-       /**
-        * Returns the node type
-        *
-        * @return string
-        */
-       public function getType() {
-               return $this->type;
-       }
-
-       /**
-        * Sets the leaf node indicator
-        *
-        * @param bool $isLeaf
-        * @return void
-        */
-       public function setLeaf($isLeaf) {
-               $this->leaf = ($isLeaf == TRUE);
-       }
-
-       /**
-        * Returns if the node is a leaf node
-        *
-        * @return bool
-        */
-       public function isLeafNode() {
-               return $this->leaf;
-       }
-
-       /**
-        * Sets the expandable indicator
-        *
-        * @param bool $expandable
-        * @return void
-        */
-       public function setExpandable($expandable) {
-               $this->expandable = ($expandable == TRUE);
-       }
-
-       /**
-        * Returns the expandable indicator
-        *
-        * @return bool
-        */
-       public function isExpandable() {
-               return $this->expandable;
-       }
-
-       /**
-        * Sets the expanded indicator
-        *
-        * @param bool $expanded
-        * @return void
-        */
-       public function setExpanded($expanded) {
-               $this->expanded = ($expanded == TRUE);
-       }
-
-       /**
-        * Returns the expanded indicator
-        *
-        * @return bool
-        */
-       public function isExpanded() {
-               if ($this->isLeafNode()) {
-                       return TRUE;
-               }
-
-               return $this->expanded;
-       }
-
-       /**
-        * Sets the draggable indicator
-        *
-        * @param bool $draggable
-        * @return void
-        */
-       public function setDraggable($draggable) {
-               $this->draggable = ($draggable == TRUE);
-       }
-
-       /**
-        * Returns the draggable indicator
-        *
-        * @return bool
-        */
-       public function isDraggable() {
-               return $this->draggable;
-       }
-
-       /**
-        * Sets the indicator if the node can be a drop target
-        *
-        * @param bool $isDropTarget
-        * @return void
-        */
-       public function setIsDropTarget($isDropTarget) {
-               $this->isDropTarget = ($isDropTarget == TRUE);
-       }
-
-       /**
-        * Returns the indicator if the node is a drop target
-        *
-        * @return bool
-        */
-       public function isDropTarget() {
-               return $this->isDropTarget;
-       }
-
-       /**
-        * Sets the label of the node with the source field and the prefix
-        *
-        * @param string $text
-        * @param string $textSourceField
-        * @param string $prefix
-        * @param string $suffix
-        * @return void
-        */
-       public function setText($text, $textSourceField = 'title', $prefix = '', $suffix = '') {
-               $this->text = $text;
-               $this->t3TextSourceField = $textSourceField;
-               $this->prefix = $prefix;
-               $this->suffix = $suffix;
-       }
-
-       /**
-        * Returns the label
-        *
-        * @return string
-        */
-       public function getText() {
-               return $this->text;
-       }
-
-       /**
-        * Sets the editable text
-        *
-        * @param string $editableText
-        * @return void
-        */
-       public function setEditableText($editableText) {
-               $this->editableText = $editableText;
-       }
-
-       /**
-        * Returns the editable text
-        *
-        * @return string
-        */
-       public function getEditableText() {
-               return $this->editableText;
-       }
-
-       /**
-        * Returns the source field of the label
-        *
-        * @return string
-        */
-       public function getTextSourceField() {
-               return $this->t3TextSourceField;
-       }
-
-       /**
-        * Sets the paste copy indicator
-        *
-        * @param boolean $inCopyMode
-        * @return void
-        */
-       public function setInCopyMode($inCopyMode) {
-               $this->t3InCopyMode = ($inCopyMode == TRUE);
-       }
-
-       /**
-        * Returns the copy mode indicator
-        *
-        * @return bool
-        */
-       public function isInCopyMode() {
-               return $this->t3InCopyMode;
-       }
-
-       /**
-        * Sets the paste cut indicator
-        *
-        * @param boolean $inCutMode
-        * @return void
-        */
-       public function setInCutMode($inCutMode) {
-               $this->t3InCutMode = ($inCutMode == TRUE);
-       }
-
-       /**
-        * Returns the cut mode indicator
-        *
-        * @return bool
-        */
-       public function isInCutMode() {
-               return $this->t3InCutMode;
-       }
-
-       /**
-        * Returns the prefix text of the label
-        *
-        * @return string
-        */
-       public function getPrefix() {
-               return $this->prefix;
-       }
-
-       /**
-        * Returns the suffix text of the label
-        *
-        * @return string
-        */
-       public function getSuffix() {
-               return $this->suffix;
-       }
-
-       /**
-        * Sets the css class(es)
-        *
-        * @param string $class
-        * @return void
-        */
-       public function setCls($class) {
-               $this->cls = $class;
-       }
-
-       /**
-        * Returns the css class(es)
-        *
-        * @return string
-        */
-       public function getCls() {
-               return $this->cls;
-       }
-
-       /**
-        * Sets the quick tip
-        *
-        * @param string $qtip
-        * @return void
-        */
-       public function setQTip($qtip) {
-               $this->qtip = $qtip;
-       }
-
-       /**
-        * Returns the quick tip
-        *
-        * @return string
-        */
-       public function getQTip() {
-               return $this->qtip;
-       }
-
-       /**
-        * Sets the sprite icon code
-        *
-        * @param string $spriteIcon
-        * @return void
-        */
-       public function setSpriteIconCode($spriteIcon) {
-               $this->spriteIconCode = $spriteIcon;
-       }
-
-       /**
-        * Returns the sprite icon code
-        *
-        * @return string
-        */
-       public function getSpriteIconCode() {
-               return $this->spriteIconCode;
-       }
-
-       /**
-        * Sets the indicator if the label is editable
-        *
-        * @param bool $labelIsEditable
-        * @return void
-        */
-       public function setLabelIsEditable($labelIsEditable) {
-               $this->labelIsEditable = ($labelIsEditable == TRUE);
-       }
-
-       /**
-        * Returns the editable label indicator
-        *
-        * @return bool
-        */
-       public function isLabelEditable() {
-               return $this->labelIsEditable;
-       }
-
-       /**
-        * Sets the database record array
-        *
-        * @param array $record
-        * @return void
-        */
-       public function setRecord($record) {
-               $this->record = (array) $record;
-       }
-
-       /**
-        * Returns the database record array
-        *
-        * @return array
-        */
-       public function getRecord() {
-               return $this->record;
-       }
-
-       /**
-        * Sets the context info
-        *
-        * @param array $contextInfo
-        * @return void
-        */
-       public function setContextInfo($contextInfo) {
-               $this->contextInfo = (array) $contextInfo;
-       }
-
-       /**
-        * Returns the context info
-        *
-        * @return array
-        */
-       public function getContextInfo() {
-               return (array) $this->contextInfo;
-       }
-
-       /**
-        * Sets the child nodes collection
-        *
-        * @param t3lib_tree_NodeCollection $childNodes
-        * @return void
-        */
-       public function setChildNodes(t3lib_tree_NodeCollection $childNodes) {
-               parent::setChildNodes($childNodes);
-
-               if ($childNodes->count()) {
-                       $this->setLeaf(FALSE);
-               }
-       }
-
-       /**
-        * Sets the indicator if the node can have child nodes
-        *
-        * @param boolean $allowChildren
-        * @return void
-        */
-       public function setAllowChildren($allowChildren) {
-               $this->allowChildren = ($allowChildren == TRUE);
-       }
-
-       /**
-        * Checks if the node can have child nodes
-        *
-        * @return bool
-        */
-       public function canHaveChildren() {
-               return $this->allowChildren;
-       }
-
-       /**
-        * Returns the node in an array representation that can be used for serialization
-        *
-        * @param bool $addChildNodes
-        * @return array
-        */
-       public function toArray($addChildNodes = TRUE) {
-               $arrayRepresentation = array(
-                       'serializeClassName' => get_class($this),
-                       'id' => $this->getId(),
-                       'type' => $this->getType(),
-                       'editableText' => $this->getEditableText(),
-                       'text' => $this->getPrefix() . $this->getText() . $this->getSuffix(),
-                       'cls' => $this->getCls(),
-                       'prefix' => $this->getPrefix(),
-                       'suffix' => $this->getSuffix(),
-                       'qtip' => $this->getQTip(),
-                       'expanded' => $this->isExpanded(),
-                       'expandable' => $this->isExpandable(),
-                       'draggable' => $this->isDraggable(),
-                       'isTarget' => $this->isDropTarget(),
-                       'spriteIconCode' => $this->getSpriteIconCode(),
-                       't3TextSourceField' => $this->getTextSourceField(),
-                       't3InCopyMode' => $this->isInCopyMode(),
-                       't3InCutMode' => $this->isInCutMode(),
-                       't3ContextInfo' => $this->getContextInfo(),
-                       'editable' => $this->isLabelEditable(),
-                       'allowChildren' => $this->canHaveChildren(),
-               );
-
-                       // only set the leaf attribute if the node has children's,
-                       // otherwise you cannot add child's to real leaf nodes
-               if (!$this->isLeafNode()) {
-                       $arrayRepresentation['leaf'] = FALSE;
-               }
-
-                       // Suhosin(?) or some other strange environment thingy prevents
-                       // the direct copy of an array into an index of the same array
-               $copy = $arrayRepresentation;
-               $arrayRepresentation['nodeData'] = $copy;
-
-               if ($this->hasChildNodes()) {
-                       $arrayRepresentation['children'] = $this->childNodes->toArray();
-               }
-
-               return $arrayRepresentation;
-       }
-
-       /**
-        * Sets data of the node by a given data array
-        *
-        * @param array $data
-        * @return void
-        */
-       public function dataFromArray($data) {
-               parent::dataFromArray($data);
-
-               $this->setType($data['type']);
-               $this->setText($data['label'], $data['t3TextSourceField'], $data['prefix'], $data['suffix']);
-               $this->setEditableText($data['editableText']);
-               $this->setCls($data['cls']);
-               $this->setQTip($data['qtip']);
-               $this->setExpanded($data['expanded']);
-               $this->setExpandable($data['expandable']);
-               $this->setDraggable($data['draggable']);
-               $this->setIsDropTarget($data['isTarget']);
-               $this->setSpriteIconCode($data['spriteIconCode']);
-               $this->setInCopyMode($data['t3InCopyMode']);
-               $this->setInCutMode($data['t3InCutMode']);
-               $this->setContextInfo($data['t3ContextInfo']);
-               $this->setLabelIsEditable($data['editable']);
-               $this->setAllowChildren($data['allowChildren']);
-
-                       // only set the leaf attribute if it's applied
-                       // otherwise you cannot insert nodes into this one
-               if (isset($data['leaf'])) {
-                       $this->setLeaf(FALSE);
-               }
-       }
-}
-
-if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/tree/extdirect/class.t3lib_tree_extdirect_node.php'])) {
-       include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/tree/extdirect/class.t3lib_tree_extdirect_node.php']);
-}
-
-?>
\ No newline at end of file
diff --git a/t3lib/tree/extjs/class.t3lib_tree_extjs_abstractextjstree.php b/t3lib/tree/extjs/class.t3lib_tree_extjs_abstractextjstree.php
new file mode 100644 (file)
index 0000000..b776290
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2010-2011 TYPO3 Tree Team <http://forge.typo3.org/projects/typo3v4-extjstrees>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Abstract ExtJS tree based on ExtDirect
+ *
+ * @author Stefan Galinski <stefan.galinski@gmail.com>
+ * @package TYPO3
+ * @subpackage t3lib
+ */
+abstract class t3lib_tree_ExtJs_AbstractExtJsTree extends t3lib_tree_AbstractTree {
+
+       /**
+        * Fetches the next tree level
+        *
+        * @abstract
+        * @param int $nodeId
+        * @param stdClass $nodeData
+        * @return array
+        */
+       abstract public function getNextTreeLevel($nodeId, $nodeData);
+}
+
+?>
\ No newline at end of file
diff --git a/t3lib/tree/extjs/class.t3lib_tree_extjs_abstractstatefulextjstree.php b/t3lib/tree/extjs/class.t3lib_tree_extjs_abstractstatefulextjstree.php
new file mode 100644 (file)
index 0000000..6ac45d2
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2010-2011 TYPO3 Tree Team <http://forge.typo3.org/projects/typo3v4-extjstrees>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Abstract ExtJS tree based on ExtDirect
+ * extends with StateProvider
+ *
+ * @author Steffen Ritter
+ * @package TYPO3
+ * @subpackage t3lib
+ */
+abstract class t3lib_tree_ExtJs_AbstractStatefulExtJsTree extends t3lib_tree_ExtJs_AbstractExtJsTree {
+
+       /**
+        * State Provider
+        *
+        * @var t3lib_tree_AbstractStateProvider
+        */
+       protected $stateProvider = NULL;
+
+       /**
+        * @param t3lib_tree_AbstractStateProvider $stateProvider
+        * @return void
+        */
+       public function setStateProvider(t3lib_tree_AbstractStateProvider $stateProvider) {
+               $this->stateProvider = $stateProvider;
+       }
+
+       /**
+        * @return t3lib_tree_AbstractStateProvider
+        */
+       public function getStateProvider() {
+               return $this->stateProvider;
+       }
+
+}
+
+?>
\ No newline at end of file
diff --git a/t3lib/tree/extjs/class.t3lib_tree_extjs_node.php b/t3lib/tree/extjs/class.t3lib_tree_extjs_node.php
new file mode 100644 (file)
index 0000000..517f306
--- /dev/null
@@ -0,0 +1,590 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2010-2011 TYPO3 Tree Team <http://forge.typo3.org/projects/typo3v4-extjstrees>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Node for the usage with ExtDirect and ExtJS
+ *
+ * @author Stefan Galinski <stefan.galinski@gmail.com>
+ * @package TYPO3
+ * @subpackage t3lib
+ */
+class t3lib_tree_ExtJs_Node extends t3lib_tree_Node implements t3lib_tree_RenderableNode {
+
+       /**
+        * Indicator if the node is allowDrag
+        *
+        * @var bool
+        */
+       protected $allowDrag = TRUE;
+
+       /**
+        * Indicator if the node is allowed as a drop target
+        *
+        * @var bool
+        */
+       protected $allowDrop = TRUE;
+
+       /**
+        * Indicator if the noded is checked
+        * three-state: TRUE|FALSE|NULL
+        * NULL won't show a checkbox
+        *
+        * @var boolean|NULL
+        */
+       protected $checked = NULL;
+
+       /**
+        * CSS Class
+        *
+        * @var string
+        */
+       protected $cls = '';
+
+       /**
+        * The number of parents this node has. ...
+        *
+        * @var int
+        */
+       protected $depth;
+
+       /**
+        * Indicator if the node can be expanded
+        *
+        * @var bool
+        */
+       protected $expandable = TRUE;
+
+       /**
+        * Indicator if the node is expanded
+        *
+        * @var bool
+        */
+       protected $expanded = FALSE;
+
+       /**
+        * An URL for a link that's created when this config is specified.
+        *
+        * @var string|NULL
+        */
+       protected $href = NULL;
+
+       /**
+        * Target for link in $href
+        *
+        * @var string
+        */
+       protected $hrefTarget = '';
+
+       /**
+        * URL for this node's icon file
+        *
+        * @var string
+        */
+       protected $icon;
+
+       /**
+        * URL for this node's icon css class
+        *
+        * @var string
+        */
+       protected $iconCls;
+
+
+       /**
+        * The position of the node inside its parents
+        * starting from 0
+        *
+        * @var int
+        */
+       protected $index;
+
+
+       /**
+        * True if this is the first node.
+        *
+        * @var boolean
+        */
+       protected $isFirst;
+
+       /**
+        * True if this is the last node
+        */
+       protected $isLast;
+
+       /**
+        * Leaf Node Indicator
+        *
+        * @var bool
+        */
+       protected $leaf = TRUE;
+
+       /**
+        * Quick Tip
+        *
+        * @var string
+        */
+       protected $qtip = '';
+
+       /**
+        * Quick Tip title
+        *
+        * @var string
+        */
+       protected $qtitle = '';
+
+       /**
+        * is root node?
+        *
+        * @var boolean
+        */
+       protected $root = FALSE;
+
+       /**
+        * Label
+        *
+        * @var string
+        */
+       protected $text = '';
+
+       /**
+        * Sets the leaf node indicator
+        *
+        * @param bool $isLeaf
+        * @return void
+        */
+       public function setLeaf($isLeaf) {
+               $this->leaf = ($isLeaf == TRUE);
+       }
+
+       /**
+        * Returns if the node is a leaf node
+        *
+        * @return bool
+        */
+       public function isLeafNode() {
+               return $this->leaf;
+       }
+
+       /**
+        * Sets the expandable indicator
+        *
+        * @param bool $expandable
+        * @return void
+        */
+       public function setExpandable($expandable) {
+               $this->expandable = ($expandable == TRUE);
+       }
+
+       /**
+        * Returns the expandable indicator
+        *
+        * @return bool
+        */
+       public function isExpandable() {
+               return $this->expandable;
+       }
+
+       /**
+        * Sets the expanded indicator
+        *
+        * @param bool $expanded
+        * @return void
+        */
+       public function setExpanded($expanded) {
+               $this->expanded = ($expanded == TRUE);
+       }
+
+       /**
+        * Returns the expanded indicator
+        *
+        * @return bool
+        */
+       public function isExpanded() {
+               if ($this->isLeafNode()) {
+                       return TRUE;
+               }
+
+               return $this->expanded;
+       }
+
+       /**
+        * Sets the allowDrag indicator
+        *
+        * @param bool $draggable
+        * @return void
+        */
+       public function setAllowDrag($draggable) {
+               $this->allowDrag = ($draggable == TRUE);
+       }
+
+       /**
+        * Returns the allowDrag indicator
+        *
+        * @return bool
+        */
+       public function isDraggable() {
+               return $this->allowDrag;
+       }
+
+       /**
+        * Sets the indicator if the node can be a drop target
+        *
+        * @param bool $isDropTarget
+        * @return void
+        */
+       public function setAllowDrop($isDropTarget) {
+               $this->allowDrop = ($isDropTarget == TRUE);
+       }
+
+       /**
+        * Returns the indicator if the node is a drop target
+        *
+        * @return bool
+        */
+       public function allowDrop() {
+               return $this->allowDrop;
+       }
+
+       /**
+        * Sets the label of the node with the source field and the prefix
+        *
+        * @param string $text
+        * @return void
+        */
+       public function setText($text) {
+               $this->text = $text;
+       }
+
+       /**
+        * Returns the label
+        *
+        * @return string
+        */
+       public function getText() {
+               return $this->text;
+       }
+
+       /**
+        * Sets the css class(es)
+        *
+        * @param string $class
+        * @return void
+        */
+       public function setCls($class) {
+               $this->cls = $class;
+       }
+
+       /**
+        * Returns the css class(es)
+        *
+        * @return string
+        */
+       public function getCls() {
+               return $this->cls;
+       }
+
+       /**
+        * Sets the quick tip
+        *
+        * @param string $qtip
+        * @return void
+        */
+       public function setQTip($qtip) {
+               $this->qtip = $qtip;
+       }
+
+       /**
+        * Returns the quick tip
+        *
+        * @return string
+        */
+       public function getQTip() {
+               return $this->qtip;
+       }
+
+       /**
+        * Sets the child nodes collection
+        *
+        * @param t3lib_tree_NodeCollection $childNodes
+        * @return void
+        */
+       public function setChildNodes(t3lib_tree_NodeCollection $childNodes) {
+               parent::setChildNodes($childNodes);
+
+               if ($childNodes->count()) {
+                       $this->setLeaf(FALSE);
+               }
+       }
+
+       /**
+        * Returns the node in an array representation that can be used for serialization
+        *
+        * @param bool $addChildNodes
+        * @return array
+        */
+       public function toArray($addChildNodes = TRUE) {
+               $arrayRepresentation = array(
+                       'serializeClassName' => get_class($this),
+                       'allowDrag' => $this->isDraggable(),
+                       'allowDrop' => $this->allowDrop(),
+                       'checked'       => $this->getChecked(),
+                       'cls' => $this->getCls(),
+                       'depth' => $this->getDepth(),
+                       'expandable' => $this->isExpandable(),
+                       'expanded' => $this->isExpanded(),
+                       'href' => $this->getHref(),
+                       'hrefTarget' => $this->getHrefTarget(),
+                       'id' => $this->getId(),
+                       'icon' => $this->getIcon(),
+                       'iconCls' => $this->getIconCls(),
+                       'index' => $this->getIndex(),
+                       'isFirst' => $this->getIsFirst(),
+                       'isLast' => $this->getIsLast(),
+                       'parentId' => (!$this->getRoot() && $this->getParentNode() ? $this->getParentNode()->getId() : ''),
+                       'qtip' => $this->getQTip(),
+                       'qtitle' => $this->getQtitle(),
+                       'root' => $this->getRoot(),
+                       'text' => $this->getText(),
+               );
+
+                       // do not provide config if empty
+               if (trim($this->href) == '') {
+                       unset($arrayRepresentation['href']);
+                       unset($arrayRepresentation['hrefTarget']);
+               }
+
+                       // only added check option if checkbox should be shown
+               if($this->getChecked() == NULL) {
+                       unset($arrayRepresentation['checked']);
+               }
+                       // only set the leaf attribute if the node has children's,
+                       // otherwise you cannot add child's to real leaf nodes
+               if (!$this->isLeafNode()) {
+                       $arrayRepresentation['leaf'] = FALSE;
+               }
+
+               // Suhosin(?) or some other strange environment thingy prevents
+               // the direct copy of an array into an index of the same array
+               $copy = $arrayRepresentation;
+               $arrayRepresentation['nodeData'] = $copy;
+
+               if ($this->hasChildNodes() && $addChildNodes) {
+                       $arrayRepresentation['children'] = $this->childNodes->toArray();
+               }
+
+               return $arrayRepresentation;
+       }
+
+       /**
+        * Sets data of the node by a given data array
+        *
+        * @param array $data
+        * @return void
+        */
+       public function dataFromArray($data) {
+               parent::dataFromArray($data);
+
+               $this->setText($data['label']);
+               $this->setCls($data['cls']);
+               $this->setQTip($data['qtip']);
+               $this->setExpanded($data['expanded']);
+               $this->setExpandable($data['expandable']);
+               $this->setAllowDrag($data['allowDrag']);
+               $this->setAllowDrop($data['isTarget']);
+               $this->setChecked(isset($data['checked']) ? (bool)$data['checked'] : NULL);
+
+               // only set the leaf attribute if it's applied
+               // otherwise you cannot insert nodes into this one
+               if (isset($data['leaf'])) {
+                       $this->setLeaf(FALSE);
+               }
+       }
+
+       /**
+        * @param bool|NULL $checked
+        */
+       public function setChecked($checked) {
+               $this->checked = $checked;
+       }
+
+       /**
+        * @return bool|NULL
+        */
+       public function getChecked() {
+               return $this->checked;
+       }
+
+       /**
+        * @param int $depth
+        */
+       public function setDepth($depth) {
+               $this->depth = $depth;
+       }
+
+       /**
+        * @return int
+        */
+       public function getDepth() {
+               return $this->depth;
+       }
+
+       /**
+        * @param NULL|string $href
+        */
+       public function setHref($href) {
+               $this->href = $href;
+       }
+
+       /**
+        * @return NULL|string
+        */
+       public function getHref() {
+               return $this->href;
+       }
+
+       /**
+        * @param string $hrefTarget
+        */
+       public function setHrefTarget($hrefTarget) {
+               $this->hrefTarget = $hrefTarget;
+       }
+
+       /**
+        * @return string
+        */
+       public function getHrefTarget() {
+               return $this->hrefTarget;
+       }
+
+       /**
+        * @param string $icon
+        */
+       public function setIcon($icon) {
+               $this->icon = $icon;
+       }
+
+       /**
+        * @return string
+        */
+       public function getIcon() {
+               return $this->icon;
+       }
+
+       /**
+        * @param string $iconCls
+        */
+       public function setIconCls($iconCls) {
+               $this->iconCls = $iconCls;
+       }
+
+       /**
+        * @return string
+        */
+       public function getIconCls() {
+               return $this->iconCls;
+       }
+
+       /**
+        * @param int $index
+        */
+       public function setIndex($index) {
+               $this->index = $index;
+       }
+
+       /**
+        * @return int
+        */
+       public function getIndex() {
+               return $this->index;
+       }
+
+       /**
+        * @param boolean $isFirst
+        */
+       public function setIsFirst($isFirst) {
+               $this->isFirst = $isFirst;
+       }
+
+       /**
+        * @return boolean
+        */
+       public function getIsFirst() {
+               return $this->isFirst;
+       }
+
+       public function setIsLast($isLast) {
+               $this->isLast = $isLast;
+       }
+
+       public function getIsLast() {
+               return $this->isLast;
+       }
+
+
+       /**
+        * @param string $qtitle
+        */
+       public function setQtitle($qtitle) {
+               $this->qtitle = $qtitle;
+       }
+
+       /**
+        * @return string
+        */
+       public function getQtitle() {
+               return $this->qtitle;
+       }
+
+       /**
+        * @param boolean $root
+        */
+       public function setRoot($root) {
+               $this->root = $root;
+       }
+
+       /**
+        * @return boolean
+        */
+       public function getRoot() {
+               return $this->root;
+       }
+
+       /**
+        * returns a string representation
+        *
+        * @return string
+        */
+       public function toString() {
+               return $this->getText();
+       }
+}
+
+if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/tree/extjs/class.t3lib_tree_extjs_node.php'])) {
+       include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/tree/extjs/class.t3lib_tree_extjs_node.php']);
+}
+
+?>
\ No newline at end of file
diff --git a/t3lib/tree/interfaces/interface.t3lib_tree_comparablenode.php b/t3lib/tree/interfaces/interface.t3lib_tree_comparablenode.php
new file mode 100644 (file)
index 0000000..ed7c093
--- /dev/null
@@ -0,0 +1,69 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2010-2011 TYPO3 Tree Team <http://forge.typo3.org/projects/typo3v4-extjstrees>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Interface that defines the comparison of nodes
+ *
+ * @author Stefan Galinski <stefan.galinski@gmail.com>
+ * @package TYPO3
+ * @subpackage t3lib
+ */
+interface t3lib_tree_ComparableNode {
+       /**
+        * Compare Node against another one
+        *
+        * Returns:
+        * 1 if the current node is greater than the $other,
+        * -1 if $other is greater than the current node and
+        * 0 if the nodes are equal
+        *
+        * <strong>Example</strong>
+        * <pre>
+        *       if ($this->sortValue > $other->sortValue) {
+        *              return 1;
+        *      } elseif ($this->sortValue < $other->sortValue) {
+        *              return -1;
+        *      } else {
+        *              return 0;
+        *      }
+        * </pre>
+        *
+        * @param t3lib_tree_Node $other
+        * @return integer see description
+        */
+       public function compareTo($other);
+
+       /**
+        * Compares a node if it's identical to another node by the id property.
+        *
+        * @param t3lib_tree_Node $other
+        * @return boolean
+        */
+       public function equals(t3lib_tree_Node $other);
+
+}
+?>
\ No newline at end of file
diff --git a/t3lib/tree/interfaces/interface.t3lib_tree_draggableanddropable.php b/t3lib/tree/interfaces/interface.t3lib_tree_draggableanddropable.php
new file mode 100644 (file)
index 0000000..2bdf9cd
--- /dev/null
@@ -0,0 +1,75 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2010-2011 TYPO3 Tree Team <http://forge.typo3.org/projects/typo3v4-extjstrees>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Describes necessary methods if the nodes are allowDrag and dropable
+ * within the tree.
+ *
+ * @author Stefan Galinski <stefan.galinski@gmail.com>
+ * @author Steffen Ritter <info@steffen-ritter.net>
+ * @package TYPO3
+ * @subpackage t3lib
+ */
+interface t3lib_tree_DraggableAndDropable {
+       /**
+        * Moves given node inside a destination node
+        *
+        * @param t3lib_tree_Node $node
+        * @param t3lib_tree_Node $destination
+        * @return void
+        */
+       public function moveNodeInDestinationNode($node, $destination);
+
+       /**
+        * Moves given node after a destination node
+        *
+        * @param t3lib_tree_Node $node
+        * @param t3lib_tree_Node $destination
+        * @return void
+        */
+       public function moveNodeAfterDestinationNode($node, $destination);
+
+       /**
+        * Copies given node inside a destination node
+        *
+        * @param t3lib_tree_Node $node
+        * @param t3lib_tree_Node $destination
+        * @return void
+        */
+       public function copyNodeInDestinationNode($node, $destination);
+
+       /**
+        * Copies given node after a destination node
+        *
+        * @param t3lib_tree_Node $node
+        * @param t3lib_tree_Node $destination
+        * @return void
+        */
+       public function copyNodeAfterDestinationNode($node, $destination);
+
+}
+?>
\ No newline at end of file
diff --git a/t3lib/tree/interfaces/interface.t3lib_tree_labeleditable.php b/t3lib/tree/interfaces/interface.t3lib_tree_labeleditable.php
new file mode 100644 (file)
index 0000000..52f7ce8
--- /dev/null
@@ -0,0 +1,46 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2010-2011 TYPO3 Tree Team <http://forge.typo3.org/projects/typo3v4-extjstrees>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *&nb