diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/PageTree/PageTree.js b/typo3/sysext/backend/Resources/Public/JavaScript/PageTree/PageTree.js index bb8ad61cb0859e03990069a1027a24fdf301a53e..de269ce253f82b5a222e5139b317f1506c2377d6 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/PageTree/PageTree.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/PageTree/PageTree.js @@ -109,7 +109,7 @@ define(['jquery', var title = TYPO3.lang.pagetree_networkErrorTitle; var desc = TYPO3.lang.pagetree_networkErrorDesc; - if (error && (error.target.status || error.target.statusText)) { + if (error && error.target && (error.target.status || error.target.statusText)) { title += ' - ' + (error.target.status || '') + ' ' + (error.target.statusText || ''); } @@ -199,7 +199,7 @@ define(['jquery', PageTree.prototype.nodeRightClick = function (node) { d3.event.preventDefault(); - var $node = $(node).closest('svg').find('.nodes .node[data-uid=' + this.identifier + ']'); + var $node = $(node).closest('svg').find('.nodes .node[data-uid=' + this.stateIdentifier + ']'); if ($node.length) { ContextMenu.show( @@ -213,7 +213,7 @@ define(['jquery', }; PageTree.prototype.contextmenu = function (node) { - var $node = $(node).closest('svg').find('.nodes .node[data-uid=' + this.identifier + ']'); + var $node = $(node).closest('svg').find('.nodes .node[data-uid=' + this.stateIdentifier + ']'); if ($node.length) { ContextMenu.show( @@ -391,8 +391,8 @@ define(['jquery', _this.loadData(); } else { node.name = node.newName; - _this.svg.select('.node-placeholder[data-uid="' + node.identifier + '"]').remove(); - _this.update(); + _this.svg.select('.node-placeholder[data-uid="' + node.stateIdentifier + '"]').remove(); + _this.loadData(); _this.nodesRemovePlaceholder(); } } else { diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/PageTree/PageTreeDragDrop.js b/typo3/sysext/backend/Resources/Public/JavaScript/PageTree/PageTreeDragDrop.js index 25c8c0bbc500ee81f1ea356720ce660a535b87c4..b171d0476c32845a6f1fa16341598a0d7dc788da 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/PageTree/PageTreeDragDrop.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/PageTree/PageTreeDragDrop.js @@ -91,7 +91,7 @@ define([ tree.settings.allowRecursiveDelete ) { _this.dropZoneDelete = tree.nodesContainer - .select('.node[data-uid="' + node.identifier + '"]') + .select('.node[data-uid="' + node.stateIdentifier + '"]') .append('g') .attr('class', 'nodes-drop-zone') .attr('height', tree.settings.nodeHeight); @@ -139,7 +139,7 @@ define([ var $svg = $(this).closest('svg'); var $nodesBg = $svg.find('.nodes-bg'); var $nodesWrap = $svg.find('.nodes-wrapper'); - var $nodeBg = $nodesBg.find('.node-bg[data-uid=' + node.identifier + ']'); + var $nodeBg = $nodesBg.find('.node-bg[data-uid=' + node.stateIdentifier + ']'); var $nodeDd = $svg.siblings('.node-dd'); if ($nodeBg.length && (!node.isDragged)) { @@ -174,7 +174,7 @@ define([ tree.settings.nodeDragPosition = false; if (node.isOver - || (tree.settings.nodeOver.node && tree.settings.nodeOver.node.parentsUid.indexOf(node.identifier) !== -1) + || (tree.settings.nodeOver.node && tree.settings.nodeOver.node.parentsUid.indexOf(node.stateIdentifier) !== -1) || !tree.isOverSvg) { _this.addNodeDdClass({ $nodeDd: $nodeDd, $nodesWrap: $nodesWrap, className: 'nodrop' }); @@ -250,7 +250,7 @@ define([ if ( !(node.isOver - || (tree.settings.nodeOver.node && tree.settings.nodeOver.node.parentsUid.indexOf(node.identifier) !== -1) + || (tree.settings.nodeOver.node && tree.settings.nodeOver.node.parentsUid.indexOf(node.stateIdentifier) !== -1) || !tree.settings.canNodeDrag || !tree.isOverSvg ) diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/SvgTree.js b/typo3/sysext/backend/Resources/Public/JavaScript/SvgTree.js index 6af870e72ffc06cc9a261006627041a123aa5615..123ceb6c3fd1f4a180cb09433f0c5ac4a07cc216 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/SvgTree.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/SvgTree.js @@ -196,6 +196,7 @@ define( .on('mouseout', function () { _this.isOverSvg = false; }); + this.container = this.svg .append('g') .attr('class', 'nodes-wrapper') @@ -269,7 +270,7 @@ define( var title = TYPO3.lang.pagetree_networkErrorTitle; var desc = TYPO3.lang.pagetree_networkErrorDesc; - if (error.target.status || error.target.statusText) { + if (error && error.target && (error.target.status || error.target.statusText)) { title += ' - ' + (error.target.status || '') + ' ' + (error.target.statusText || ''); } @@ -312,7 +313,7 @@ define( var currentNode = nodes[i]; if (currentNode.depth < currentDepth) { node.parents.push(i); - node.parentsUid.push(nodes[i].identifier); + node.parentsUid.push(nodes[i].stateIdentifier); currentDepth = currentNode.depth; } } @@ -320,12 +321,18 @@ define( node.open = true; } + // create stateIdentifier if doesn't exist (for category tree) + if (!node.stateIdentifier) { + var parentId = (node.parents.length) ? node.parents[node.parents.length - 1] : node.identifier; + node.stateIdentifier = parentId + '_' + node.identifier; + } + if (typeof node.checked === 'undefined') { node.checked = false; _this.settings.unselectableElements.push(node.identifier); } - //dispatch event + // dispatch event _this.dispatch.call('prepareLoadedNode', _this, node); return node; }); @@ -371,7 +378,7 @@ define( var pathAboveMounts = 0; this.data.nodes.forEach(function (n, i) { - //delete n.children; + // delete n.children; n.x = n.depth * _this.settings.indentWidth; if (n.readableRootline) { @@ -436,11 +443,11 @@ define( var visibleNodes = this.data.nodes.slice(position, position + visibleRows); var nodes = this.nodesContainer.selectAll('.node').data(visibleNodes, function (d) { - return d.identifier; + return d.stateIdentifier; }); var nodesBg = this.nodesBgContainer.selectAll('.node-bg').data(visibleNodes, function (d) { - return d.identifier; + return d.stateIdentifier; }); // delete nodes without corresponding data @@ -488,7 +495,7 @@ define( .attr('xlink:href', this.getIconOverlayId); } - //dispatch event + // dispatch event this.dispatch.call('updateNodes', this, nodes); }, @@ -504,7 +511,7 @@ define( .merge(nodesBg) .attr('width', '100%') .attr('height', this.settings.nodeHeight) - .attr('data-uid', this.getNodeIdentifier) + .attr('data-uid', this.getNodeStateIdentifier) .attr('transform', this.getNodeBgTransform) .on('mouseover', function (node) { _this.nodeBgEvents().mouseOver(node, this); @@ -530,7 +537,7 @@ define( var self = {}; self.mouseOver = function (node, element) { - var elementNodeBg = _this.svg.select('.nodes-bg .node-bg[data-uid="' + node.identifier + '"]'); + var elementNodeBg = _this.svg.select('.nodes-bg .node-bg[data-uid="' + node.stateIdentifier + '"]'); node.isOver = true; _this.settings.nodeOver.node = node; @@ -544,7 +551,7 @@ define( }; self.mouseOut = function (node, element) { - var elementNodeBg = _this.svg.select('.nodes-bg .node-bg[data-uid="' + node.identifier + '"]'); + var elementNodeBg = _this.svg.select('.nodes-bg .node-bg[data-uid="' + node.stateIdentifier + '"]'); node.isOver = false; _this.settings.nodeOver.node = false; @@ -558,7 +565,7 @@ define( }; self.click = function (node, element) { - var $nodeBg = $(element).closest('svg').find('.nodes-bg .node-bg[data-uid=' + node.identifier + ']'); + var $nodeBg = $(element).closest('svg').find('.nodes-bg .node-bg[data-uid=' + node.stateIdentifier + ']'); _this.nodes.forEach(function (node) { if (node.selected === true) { @@ -597,12 +604,12 @@ define( .exit() .remove(); - //create + // create links.enter() .append('path') .attr('class', 'link') - //create + update + // create + update .merge(links) .attr('d', this.getLinkPath.bind(_this)); }, @@ -625,7 +632,7 @@ define( var icons = this.iconsContainer .selectAll('.icon-def') .data(iconsArray, function (i) { - return i.identifier; + return i.stateIdentifier; }); icons @@ -636,7 +643,7 @@ define( return 'icon-' + i.identifier; }) .append(function (i) { - //workaround for IE11 where you can't simply call .html(content) on svg + // workaround for IE11 where you can't simply call .html(content) on svg var parser = new DOMParser(); var markupText = i.icon.replace('<svg', '<g').replace('/svg>', '/g>'); markupText = "<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'>" + markupText + '</svg>'; @@ -734,7 +741,7 @@ define( .attr('class', this.getNodeClass) .attr('transform', this.getNodeTransform) .attr('data-table', 'pages') - .attr('data-uid', this.getNodeIdentifier) + .attr('data-uid', this.getNodeStateIdentifier) .attr('title', this.getNodeTitle) .on('mouseover', function (node) { _this.nodeBgEvents().mouseOver(node, this); @@ -771,6 +778,16 @@ define( return node.identifier; }, + /** + * Computes the tree item state identifier based on the data + * + * @param {Node} node + * @returns {String} + */ + getNodeStateIdentifier: function (node) { + return node.stateIdentifier; + }, + /** * Computes the tree item label based on the data * @@ -788,7 +805,7 @@ define( * @returns {String} */ getNodeClass: function (node) { - return 'node identifier-' + node.identifier; + return 'node identifier-' + node.stateIdentifier; }, /** @@ -991,7 +1008,7 @@ define( this.exclusiveSelectedNode = node; } else if (exclusiveKeys.indexOf('' + node.identifier) === -1 && this.exclusiveSelectedNode) { - //current node is not exclusive, but other exclusive node is already selected + // current node is not exclusive, but other exclusive node is already selected this.exclusiveSelectedNode.checked = false; this.dispatch.call('nodeSelectedAfter', this, this.exclusiveSelectedNode); this.exclusiveSelectedNode = null; diff --git a/typo3/sysext/core/Tests/Acceptance/Backend/Formhandler/CategoryTreeCest.php b/typo3/sysext/core/Tests/Acceptance/Backend/Formhandler/CategoryTreeCest.php index 1070795fbac285d20cce2f5e9192349de0b12fcb..797dd5e8bc3ea39316bf63655336cfebf22f4b39 100644 --- a/typo3/sysext/core/Tests/Acceptance/Backend/Formhandler/CategoryTreeCest.php +++ b/typo3/sysext/core/Tests/Acceptance/Backend/Formhandler/CategoryTreeCest.php @@ -59,13 +59,13 @@ class CategoryTreeCest $I->executeJS('$(\'.icon-actions-view-list-collapse\').click();'); $I->wait(1); $I->executeJS('$(\'a[data-table="sys_category"] .icon-actions-view-list-expand\').click();'); - $I->wait(1); + $I->waitForElementVisible('#recordlist-sys_category tr[data-uid="7"] a[data-original-title="Edit record"]'); // Select category with id 7 $I->click('#recordlist-sys_category tr[data-uid="7"] a[data-original-title="Edit record"]'); // Change title and level to root $I->fillField('input[data-formengine-input-name="data[sys_category][7][title]"]', 'level-1-4'); - $I->click('.identifier-7 text.node-name'); - $I->click('.identifier-3 text.node-name'); + $I->click('.identifier-0_7 text.node-name'); + $I->click('.identifier-0_3 text.node-name'); $I->click('button[name="_savedok"]'); // Wait for tree and check if isset level-1-4 $I->waitForElement('.svg-tree-wrapper svg'); diff --git a/typo3/sysext/core/Tests/Acceptance/Backend/Page/AddPageInPageModuleCest.php b/typo3/sysext/core/Tests/Acceptance/Backend/Page/AddPageInPageModuleCest.php index 5df8c2be1a9fc526f7b908e3baddb3c511dd1eb9..29e0779fd8a1be61e2992fe0d7be1bc198e9b960 100644 --- a/typo3/sysext/core/Tests/Acceptance/Backend/Page/AddPageInPageModuleCest.php +++ b/typo3/sysext/core/Tests/Acceptance/Backend/Page/AddPageInPageModuleCest.php @@ -49,7 +49,7 @@ class AddPageInPageModuleCest $typo3NavigationContainer = '.scaffold-content-navigation-component'; $I->waitForElement($typo3NavigationContainer); $rootNode = 'a.x-tree-node-anchor > span'; - $rootNodeIcon = '.node.identifier-0 .node-icon'; + $rootNodeIcon = '.node.identifier-0_0 .node-icon'; $rootNodeContextMenuMore = '#contentMenu0 a.list-group-item-submenu'; //create new wizard $contextMenuNew = '#contentMenu1 .list-group-item[data-callback-action=newPageWizard]'; diff --git a/typo3/sysext/core/Tests/Acceptance/Backend/Template/TemplateCest.php b/typo3/sysext/core/Tests/Acceptance/Backend/Template/TemplateCest.php index 018e0a87b1425753e163aef2270973433e52c748..54e2fe2bba0e662a8beda6b22d47d1d6c4279147 100644 --- a/typo3/sysext/core/Tests/Acceptance/Backend/Template/TemplateCest.php +++ b/typo3/sysext/core/Tests/Acceptance/Backend/Template/TemplateCest.php @@ -49,7 +49,7 @@ class TemplateCest $I->wantTo('show templates overview on root page (uid = 0)'); $I->switchToIFrame(); // click on root page - $I->click('.node.identifier-0'); + $I->click('.node.identifier-0_0'); $I->switchToIFrame('list_frame'); $I->waitForElementVisible('#ts-overview'); $I->see('This is an overview of the pages in the database containing one or more template records. Click a page title to go to the page.'); @@ -57,7 +57,7 @@ class TemplateCest $I->wantTo('show templates overview on website root page (uid = 1 and pid = 0)'); $I->switchToIFrame(); // click on website root page - $I->click('.node.identifier-1'); + $I->click('.node.identifier-0_1'); $I->switchToIFrame('list_frame'); $I->waitForText('No template'); $I->see('There was no template on this page!'); @@ -80,7 +80,7 @@ class TemplateCest { $I->wantTo('create a new site template'); $I->switchToIFrame(); - $I->click('.node.identifier-1'); + $I->click('.node.identifier-0_1'); $I->switchToIFrame('list_frame'); $I->waitForText('Create new website'); $I->click("//input[@name='newWebsite']");