diff --git a/core/lib/Drupal/Core/Link.php b/core/lib/Drupal/Core/Link.php index e435d44279..d3f115e07f 100644 --- a/core/lib/Drupal/Core/Link.php +++ b/core/lib/Drupal/Core/Link.php @@ -29,6 +29,49 @@ class Link implements RenderableInterface { */ protected $url; + /** + * The link attributes. + * + * @var array + */ + protected $attributes = []; + + /** + * The link attributes that are needed for dialog use. + * + * @var array + */ + protected $dialogAttributes; + + /** + * Returns the link attributes. + * + * @return array + * The link attributes. + */ + public function getAttributes() { + // @todo Should we not merge dialogAttributes and attributes here? + // Merging gives that attributes that will actually be used. + $attributes = $this->attributes; + if ($this->dialogAttributes) { + if (!isset($attributes['class']) || !in_array('use-ajax', $attributes['class'])) { + $attributes['class'][] = 'use-ajax'; + } + $attributes = array_merge($attributes, $this->dialogAttributes); + } + return $attributes; + } + + /** + * Sets the link attributes. + * + * @param array $attributes + * The link attributes. + */ + public function setAttributes(array $attributes) { + $this->attributes = $attributes; + } + /** * Constructs a new Link object. * @@ -133,6 +176,7 @@ public function setUrl(Url $url) { * @see \Drupal\Core\Link::toRenderable() */ public function toString() { + // @todo Ensure this method takes into account attributes. return $this->getLinkGenerator()->generateFromLink($this); } @@ -140,11 +184,56 @@ public function toString() { * {@inheritdoc} */ public function toRenderable() { - return [ + $renderable = [ '#type' => 'link', '#url' => $this->url, '#title' => $this->text, + '#attributes' => $this->getAttributes(), ]; + if ($this->dialogAttributes) { + $renderable['#attached'] = [ + 'library' => [ + 'core/drupal.dialog.ajax', + ], + ]; + } + return $renderable; + } + + /** + * Changes the link to open in a dialog. + * + * @param string $type + * The dialog type 'modal' or 'dialog', defaults to 'modal'. + * @param string $renderer + * The dialog renderer. Core provides the 'off_canvas' renderer which uses + * the off-canvas dialog. Other modules can provide dialog renderers by + * defining a service that is tagged with the name + * 'render.main_content_renderer' and tagged with a format in the pattern of + * 'drupal_[dialogType].[dialogRenderer]'. + * @param array $options + * The dialog options. + * + * @return $this + */ + public function openInDialog($type = 'modal', $renderer = NULL, array $options = []) { + if (!in_array($type, ['dialog', 'modal'])) { + throw new \UnexpectedValueException("The dialog type must be either 'dialog' or 'modal'"); + } + // @todo Do we actually need to check this? + $main_content_renders = \Drupal::getContainer()->getParameter('main_content_renderers'); + $renderer_key = "drupal_$type" . ($renderer ? ".$renderer" : ''); + if (!isset($main_content_renders[$renderer_key])) { + throw new \UnexpectedValueException("The renderer '$renderer_key' is not available."); + } + $this->dialogAttributes['data-dialog-type'] = $type; + if ($renderer) { + $this->dialogAttributes['data-dialog-renderer'] = $renderer; + } + if ($options) { + $this->dialogAttributes['data-dialog-options'] = json_encode($options); + } + return $this; } }