diff --git a/Classes/Backend/Service/NewContentUrlBuilder.php b/Classes/Backend/Service/NewContentUrlBuilder.php index ffb812ec..28692c24 100644 --- a/Classes/Backend/Service/NewContentUrlBuilder.php +++ b/Classes/Backend/Service/NewContentUrlBuilder.php @@ -91,7 +91,7 @@ protected function getNewContentEditUrl(Container $container, int $columnNumber, StringUtility::getUniqueId('NEW') => array_replace($ttContentDefVals, ['pid' => $target]), ], ], - 'redirect' => $this->getReturnUrl(), + 'redirect' => $this->getReturnUrlWithAnchor(abs($target)), ]; return (string)$this->uriBuilder->buildUriFromRoute('tce_db', $urlParameters); } @@ -104,7 +104,7 @@ protected function getNewContentEditUrl(Container $container, int $columnNumber, 'defVals' => [ 'tt_content' => $ttContentDefVals, ], - 'returnUrl' => $this->getReturnUrl(), + 'returnUrl' => $this->getReturnUrlWithAnchor(abs($target)), ]; return (string)$this->uriBuilder->buildUriFromRoute('record_edit', $urlParameters); } @@ -118,7 +118,7 @@ protected function getNewContentWizardUrl(PageLayoutContext $context, Container 'colPos' => $columnNumber, 'tx_container_parent' => $container->getUidOfLiveWorkspace(), 'uid_pid' => $uidPid, - 'returnUrl' => $this->getReturnUrl(), + 'returnUrl' => $this->getReturnUrlWithAnchor(abs($uidPid)), ]; return (string)$this->uriBuilder->buildUriFromRoute('new_content_element_wizard', $urlParameters); } @@ -152,4 +152,9 @@ protected function getReturnUrl(): string } return (string)$request->getAttribute('normalizedParams')->getRequestUri(); } + + protected function getReturnUrlWithAnchor(int $recordUid): string + { + return $this->getReturnUrl() . '#element-tt_content-' . $recordUid; + } } diff --git a/Tests/Acceptance/Backend/LayoutCest.php b/Tests/Acceptance/Backend/LayoutCest.php index 2c811f6e..389b25c1 100644 --- a/Tests/Acceptance/Backend/LayoutCest.php +++ b/Tests/Acceptance/Backend/LayoutCest.php @@ -198,6 +198,7 @@ public function canCreateContentElementInContainer(BackendTester $I, PageTree $p $I->click('Close'); $I->waitForElementNotVisible('#t3js-ui-block'); $I->canSeeElement($contentInContainerColumn); + $I->assertSame('#element-tt_content-1', $I->executeJS('return window.location.hash')); } public function canCreateContentElementInTranslatedContainerInFreeMode(BackendTester $I, PageTree $pageTree) diff --git a/Tests/Functional/Backend/Service/NewContentUriBuilderTest.php b/Tests/Functional/Backend/Service/NewContentUriBuilderTest.php index 707e6f2a..da41f6b1 100644 --- a/Tests/Functional/Backend/Service/NewContentUriBuilderTest.php +++ b/Tests/Functional/Backend/Service/NewContentUriBuilderTest.php @@ -51,6 +51,33 @@ public function getNewContentUrlAfterChildContainsUidOfLiveWorkspaceAsContainerP $newContentUriBuilder = new NewContentUrlBuilder($tcaRegistry, $containerColumnConfigurationService, $containerService, $uriBuilder); $newContentUrl = $newContentUriBuilder->getNewContentUrlAfterChild($pageLayoutContext, $container, 111, 112); self::assertStringContainsString('tx_container_parent=1', $newContentUrl, 'should container uid of live workspace record'); + self::assertStringEndsWith('#element-tt_content-112', $this->getReturnUrlParameter($newContentUrl)); + } + + #[Test] + public function getNewContentEditUrlAfterChildContainsReturnAnchor(): void + { + $container = new Container(['uid' => 2, 'CType' => 'b13-container'], []); + $pageLayoutContext = $this->getMockBuilder(PageLayoutContext::class) + ->disableOriginalConstructor() + ->getMock(); + $tcaRegistry = $this->getMockBuilder(Registry::class) + ->disableOriginalConstructor() + ->onlyMethods(['getAllowedCTypesInColumn']) + ->getMock(); + $tcaRegistry->expects(self::once())->method('getAllowedCTypesInColumn')->with('b13-container', 111)->willReturn(['header']); + $containerColumnConfigurationService = $this->getMockBuilder(ContainerColumnConfigurationService::class) + ->disableOriginalConstructor() + ->getMock(); + $containerService = $this->getMockBuilder(ContainerService::class) + ->disableOriginalConstructor() + ->getMock(); + $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); + $newContentUriBuilder = new NewContentUrlBuilder($tcaRegistry, $containerColumnConfigurationService, $containerService, $uriBuilder); + + $newContentUrl = $newContentUriBuilder->getNewContentUrlAfterChild($pageLayoutContext, $container, 111, 112); + + self::assertStringEndsWith('#element-tt_content-112', $this->getReturnUrlParameter($newContentUrl)); } #[Test] @@ -72,11 +99,14 @@ public function getNewContentUrlAtTopOfColumnContainsUidOfLiveWorkspaceAsContain $containerColumnConfigurationService->expects(self::once())->method('isMaxitemsReached')->willReturn(false); $containerService = $this->getMockBuilder(ContainerService::class) ->disableOriginalConstructor() + ->onlyMethods(['getNewContentElementAtTopTargetInColumn']) ->getMock(); + $containerService->expects(self::once())->method('getNewContentElementAtTopTargetInColumn')->willReturn(-2); $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); $newContentUriBuilder = new NewContentUrlBuilder($tcaRegistry, $containerColumnConfigurationService, $containerService, $uriBuilder); $newContentUrl = $newContentUriBuilder->getNewContentUrlAtTopOfColumn($pageLayoutContext, $container, 111); self::assertStringContainsString('tx_container_parent=1', $newContentUrl, 'should container uid of live workspace record'); + self::assertStringEndsWith('#element-tt_content-2', $this->getReturnUrlParameter($newContentUrl)); } #[Test] @@ -135,13 +165,15 @@ public function getNewContentUrlAtTopOfColumnWithSingleAllowedCTypeAndSaveAndClo ], 'saveAndClose' => true, ]; - $newContentUrl = urldecode($this->getNewContentUrlAtTopOfColumnWithSingleAllowedCType('tx_container_test')); - self::assertStringContainsString('/record/commit?', $newContentUrl); - self::assertMatchesRegularExpression('/data\[tt_content\]\[NEW[^\]]+\]\[header\]=Example header/', $newContentUrl); - self::assertMatchesRegularExpression('/data\[tt_content\]\[NEW[^\]]+\]\[CType\]=tx_container_test/', $newContentUrl); - self::assertMatchesRegularExpression('/data\[tt_content\]\[NEW[^\]]+\]\[colPos\]=111/', $newContentUrl); - self::assertMatchesRegularExpression('/data\[tt_content\]\[NEW[^\]]+\]\[tx_container_parent\]=1/', $newContentUrl); - self::assertMatchesRegularExpression('/data\[tt_content\]\[NEW[^\]]+\]\[pid\]=-5/', $newContentUrl); + $newContentUrl = $this->getNewContentUrlAtTopOfColumnWithSingleAllowedCType('tx_container_test'); + $decodedNewContentUrl = urldecode($newContentUrl); + self::assertStringContainsString('/record/commit?', $decodedNewContentUrl); + self::assertMatchesRegularExpression('/data\[tt_content\]\[NEW[^\]]+\]\[header\]=Example header/', $decodedNewContentUrl); + self::assertMatchesRegularExpression('/data\[tt_content\]\[NEW[^\]]+\]\[CType\]=tx_container_test/', $decodedNewContentUrl); + self::assertMatchesRegularExpression('/data\[tt_content\]\[NEW[^\]]+\]\[colPos\]=111/', $decodedNewContentUrl); + self::assertMatchesRegularExpression('/data\[tt_content\]\[NEW[^\]]+\]\[tx_container_parent\]=1/', $decodedNewContentUrl); + self::assertMatchesRegularExpression('/data\[tt_content\]\[NEW[^\]]+\]\[pid\]=-5/', $decodedNewContentUrl); + self::assertStringEndsWith('#element-tt_content-5', $this->getRedirectParameter($newContentUrl)); } protected function getNewContentUrlAtTopOfColumnWithSingleAllowedCType(string $allowedCType): string @@ -169,4 +201,22 @@ protected function getNewContentUrlAtTopOfColumnWithSingleAllowedCType(string $a $newContentUriBuilder = new NewContentUrlBuilder($tcaRegistry, $containerColumnConfigurationService, $containerService, $uriBuilder); return (string)$newContentUriBuilder->getNewContentUrlAtTopOfColumn($pageLayoutContext, $container, 111); } + + private function getReturnUrlParameter(string $url): string + { + return $this->getStringQueryParameter($url, 'returnUrl'); + } + + private function getRedirectParameter(string $url): string + { + return $this->getStringQueryParameter($url, 'redirect'); + } + + private function getStringQueryParameter(string $url, string $name): string + { + parse_str((string)parse_url($url, PHP_URL_QUERY), $queryParameters); + self::assertArrayHasKey($name, $queryParameters); + self::assertIsString($queryParameters[$name]); + return $queryParameters[$name]; + } }