Issue #2999549 by mtift, Daniel Korte, mherchel, alexpott, larowlan: Allow button tag in LinkGenerator for better accessibility

(cherry picked from commit 8ed835c0bc)
merge-requests/64/head
Alex Pott 2020-03-13 22:18:35 +00:00
parent 2ee538c275
commit 485db38e54
No known key found for this signature in database
GPG Key ID: 31905460D4A69276
4 changed files with 77 additions and 7 deletions

View File

@ -0,0 +1,19 @@
<?php
namespace Drupal\Core;
/**
* This class holds a <button> generated from the <button> route.
*
* Unlike \Drupal\Core\Render\Element\Button, this is not for generating
* buttons for forms. This class is for putting a button in a list of links
* such as a multi-level menu.
*/
class GeneratedButton extends GeneratedLink {
/**
* {@inheritdoc}
*/
const TAG = 'button';
}

View File

@ -7,6 +7,7 @@ use Drupal\Component\Utility\Html;
use Drupal\Component\Render\MarkupInterface; use Drupal\Component\Render\MarkupInterface;
use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\GeneratedLink; use Drupal\Core\GeneratedLink;
use Drupal\Core\GeneratedButton;
use Drupal\Core\GeneratedNoLink; use Drupal\Core\GeneratedNoLink;
use Drupal\Core\Link; use Drupal\Core\Link;
use Drupal\Core\Render\RendererInterface; use Drupal\Core\Render\RendererInterface;
@ -165,19 +166,41 @@ class LinkGenerator implements LinkGeneratorInterface {
if ($url->isExternal()) { if ($url->isExternal()) {
$generated_link = new GeneratedLink(); $generated_link = new GeneratedLink();
$attributes['href'] = $url->toString(FALSE); $attributes['href'] = $url->toString(FALSE);
return $this->doGenerate($generated_link, $attributes, $variables);
} }
elseif ($url->isRouted() && $url->getRouteName() === '<nolink>') { if ($url->isRouted() && $url->getRouteName() === '<nolink>') {
$generated_link = new GeneratedNoLink(); $generated_link = new GeneratedNoLink();
unset($attributes['href']); unset($attributes['href']);
return $this->doGenerate($generated_link, $attributes, $variables);
} }
else { if ($url->isRouted() && $url->getRouteName() === '<button>') {
$generated_url = $url->toString(TRUE); $generated_link = new GeneratedButton();
$generated_link = GeneratedLink::createFromObject($generated_url); $attributes['type'] = 'button';
// The result of the URL generator is a plain-text URL to use as the href unset($attributes['href']);
// attribute, and it is escaped by \Drupal\Core\Template\Attribute. return $this->doGenerate($generated_link, $attributes, $variables);
$attributes['href'] = $generated_url->getGeneratedUrl();
} }
$generated_url = $url->toString(TRUE);
$generated_link = GeneratedLink::createFromObject($generated_url);
// The result of the URL generator is a plain-text URL to use as the href
// attribute, and it is escaped by \Drupal\Core\Template\Attribute.
$attributes['href'] = $generated_url->getGeneratedUrl();
return $this->doGenerate($generated_link, $attributes, $variables);
}
/**
* Generates the link.
*
* @param Drupal\Core\GeneratedLink $generated_link
* The generated link, along with its associated cacheability metadata.
* @param array $attributes
* The attributes of the generated link.
* @param array $variables
* The link text, url, and other options.
*
* @return Drupal\Core\GeneratedLink
* The generated link, along with its associated cacheability metadata.
*/
protected function doGenerate($generated_link, $attributes, $variables) {
if (!($variables['text'] instanceof MarkupInterface)) { if (!($variables['text'] instanceof MarkupInterface)) {
$variables['text'] = Html::escape($variables['text']); $variables['text'] = Html::escape($variables['text']);
} }

View File

@ -412,6 +412,13 @@ system.theme_settings_theme:
requirements: requirements:
_access: 'TRUE' _access: 'TRUE'
'<button>':
path: ''
options:
_no_path: TRUE
requirements:
_access: 'TRUE'
'<current>': '<current>':
path: '<current>' path: '<current>'

View File

@ -3,6 +3,7 @@
namespace Drupal\Tests\Core\Utility; namespace Drupal\Tests\Core\Utility;
use Drupal\Component\Render\MarkupInterface; use Drupal\Component\Render\MarkupInterface;
use Drupal\Core\GeneratedButton;
use Drupal\Core\GeneratedNoLink; use Drupal\Core\GeneratedNoLink;
use Drupal\Core\GeneratedUrl; use Drupal\Core\GeneratedUrl;
use Drupal\Core\Language\Language; use Drupal\Core\Language\Language;
@ -199,6 +200,26 @@ class LinkGeneratorTest extends UnitTestCase {
$this->assertSame('<a href="">Test</a>', (string) $result); $this->assertSame('<a href="">Test</a>', (string) $result);
} }
/**
* Tests the generate() method with the <button> route.
*
* @covers ::generate
*/
public function testGenerateButton() {
$this->urlGenerator->expects($this->never())
->method('generateFromRoute');
$this->moduleHandler->expects($this->once())
->method('alter')
->with('link', $this->isType('array'));
$url = Url::fromRoute('<button>');
$url->setUrlGenerator($this->urlGenerator);
$result = $this->linkGenerator->generate('Test', $url);
$this->assertTrue($result instanceof GeneratedButton);
$this->assertSame('<button type="button">Test</button>', (string) $result);
}
/** /**
* Tests the generate() method with an external URL. * Tests the generate() method with an external URL.
* *