Skip to content

Commit

Permalink
[BUGFIX] TypoLink is executed fully without href attribute
Browse files Browse the repository at this point in the history
In #87992 an early return was added to have <a> tags
with just an "id" or "name" attribute. This is all nice,
but when used further typolink settings (such as userFunc
or custom "title"), these options were never run.

This change now uses typolink() natively again and
removes the introduced "resolveAnchorLinK" workaround.

Added tests show that additional attributes are executed
and links without href are actually created (was previously
untested).

Resolves: #96464
Related: #87992
Releases: main, 11.5
Change-Id: I67d4090228684fc89f72bc3d6367109437040ccf
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/72894
Tested-by: core-ci <typo3@b13.com>
Tested-by: Oliver Bartsch <bo@cedev.de>
Tested-by: Stefan Bürk <stefan@buerk.tech>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Oliver Bartsch <bo@cedev.de>
Reviewed-by: Stefan Bürk <stefan@buerk.tech>
Reviewed-by: Benni Mack <benni@typo3.org>
  • Loading branch information
bmack committed Jan 6, 2022
1 parent 1c58946 commit b72d3fd
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4583,17 +4583,27 @@ public function typoLink($linkText, $conf)
$target = $resolvedLinkParameters['target'];
$title = $resolvedLinkParameters['title'];

$linkDetails = [];
if (!$linkParameter) {
return $this->resolveAnchorLink($linkText, $conf ?? []);
}

// Detecting kind of link and resolve all necessary parameters
$linkService = GeneralUtility::makeInstance(LinkService::class);
try {
$linkDetails = $linkService->resolve($linkParameter);
} catch (UnknownLinkHandlerException | InvalidPathException $exception) {
$this->logger->warning('The link could not be generated', ['exception' => $exception]);
return $linkText;
// Support anchors without href value if id or name attribute is present.
$aTagParams = (string)$this->stdWrapValue('ATagParams', $conf ?? []);
$aTagParams = GeneralUtility::get_tag_attributes($aTagParams);
// If it looks like an anchor tag, render it anyway
if (isset($aTagParams['id']) || isset($aTagParams['name'])) {
$linkDetails = [
'type' => 'inpage',
'url' => '',
];
}
} else {
// Detecting kind of link and resolve all necessary parameters
$linkService = GeneralUtility::makeInstance(LinkService::class);
try {
$linkDetails = $linkService->resolve($linkParameter);
} catch (UnknownLinkHandlerException | InvalidPathException $exception) {
$this->logger->warning('The link could not be generated', ['exception' => $exception]);
return $linkText;
}
}

$linkDetails['typoLinkParameter'] = $linkParameter;
Expand Down Expand Up @@ -6466,27 +6476,6 @@ public function getTypoScriptFrontendController()
return $this->typoScriptFrontendController ?: $GLOBALS['TSFE'] ?? null;
}

/**
* Support anchors without href value
* Changes ContentObjectRenderer::typolink to render a tag without href,
* if id or name attribute is present.
*
* @param string $linkText
* @param array $conf Typolink configuration decoded as array
* @return string Full a-Tag or just the linktext if id or name are not set.
*/
protected function resolveAnchorLink(string $linkText, array $conf): string
{
$anchorTag = '<a ' . $this->getATagParams($conf) . '>';
$aTagParams = GeneralUtility::get_tag_attributes($anchorTag);
// If it looks like a anchor tag, render it anyway
if (isset($aTagParams['id']) || isset($aTagParams['name'])) {
return $anchorTag . $linkText . '</a>';
}
// Otherwise just return the link text
return $linkText;
}

/**
* Get content length of the current tag that could also contain nested tag contents
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,62 @@ public function linkToPageIsProcessed(string $parameter, string $expectation, bo
self::assertSame($expectation, (string)$response->getBody());
}

public function linkWithoutAnchorIsGeneratedDataProvider(): array
{
return [
'empty parameter does not create a link' => [
[
'parameter' => '',
],
'no link',
'no link',
],
'empty parameter with additional ATagParams does not create a link' => [
[
'parameter' => '',
'ATagParams' => 'data-any="where"',
],
'no link',
'no link',
],
'empty parameter with additional ATagParams with id creates a link' => [
[
'parameter' => '',
'ATagParams' => 'id="c13" data-any="where"',
],
'a link',
'<a id="c13" data-any="where">a link</a>',
],
'empty parameter with additional ATagParams with id creates a link and adds title' => [
[
'parameter' => '',
'ATagParams' => 'id="c13" data-any="where"',
'title' => 'custom title',
],
'a link',
'<a title="custom title" id="c13" data-any="where">a link</a>',
],
];
}

/**
* @test
* @dataProvider linkWithoutAnchorIsGeneratedDataProvider
*/
public function linkWithoutAnchorIsGenerated(array $instructions, string $linkText, string $expectation): void
{
$sourcePageId = 1100;
$request = (new InternalRequest('https://acme.us/'))
->withPageId($sourcePageId)
->withInstructions(
[
$this->createTypoLinkInstruction($instructions, $linkText),
]
);
$response = $this->executeFrontendSubRequest($request);
self::assertSame($expectation, (string)$response->getBody());
}

/**
* @param string $parameter
* @param AbstractInstruction ...$instructions
Expand Down

0 comments on commit b72d3fd

Please sign in to comment.