function LinkWidget::formElement
Same name in other branches
- 9 core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php \Drupal\link\Plugin\Field\FieldWidget\LinkWidget::formElement()
- 8.9.x core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php \Drupal\link\Plugin\Field\FieldWidget\LinkWidget::formElement()
- 11.x core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php \Drupal\link\Plugin\Field\FieldWidget\LinkWidget::formElement()
Overrides WidgetInterface::formElement
File
-
core/
modules/ link/ src/ Plugin/ Field/ FieldWidget/ LinkWidget.php, line 181
Class
- LinkWidget
- Plugin implementation of the 'link' widget.
Namespace
Drupal\link\Plugin\Field\FieldWidgetCode
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
/** @var \Drupal\link\LinkItemInterface $item */
$item = $items[$delta];
$display_uri = NULL;
if (!$item->isEmpty()) {
try {
// The current field value could have been entered by a different user.
// However, if it is inaccessible to the current user, do not display it
// to them.
if (\Drupal::currentUser()->hasPermission('link to any page') || $item->getUrl()
->access()) {
$display_uri = static::getUriAsDisplayableString($item->uri);
}
} catch (\InvalidArgumentException $e) {
// If $item->uri is invalid, show value as is, so the user can see what
// to edit.
// @todo Add logging here in https://www.drupal.org/project/drupal/issues/3348020
$display_uri = $item->uri;
}
}
$element['uri'] = [
'#type' => 'url',
'#title' => $this->t('URL'),
'#placeholder' => $this->getSetting('placeholder_url'),
'#default_value' => $display_uri,
'#element_validate' => [
[
static::class,
'validateUriElement',
],
],
'#maxlength' => 2048,
'#required' => $element['#required'],
'#link_type' => $this->getFieldSetting('link_type'),
];
// If the field is configured to support internal links, it cannot use the
// 'url' form element and we have to do the validation ourselves.
if ($this->supportsInternalLinks()) {
$element['uri']['#type'] = 'entity_autocomplete';
// @todo The user should be able to select an entity type. Will be fixed
// in https://www.drupal.org/node/2423093.
$element['uri']['#target_type'] = 'node';
// Disable autocompletion when the first character is '/', '#' or '?'.
$element['uri']['#attributes']['data-autocomplete-first-character-blacklist'] = '/#?';
// The link widget is doing its own processing in
// static::getUriAsDisplayableString().
$element['uri']['#process_default_value'] = FALSE;
}
// If the field is configured to allow only internal links, add a useful
// element prefix and description.
if (!$this->supportsExternalLinks()) {
$element['uri']['#field_prefix'] = rtrim(Url::fromRoute('<front>', [], [
'absolute' => TRUE,
])->toString(), '/');
$element['uri']['#description'] = $this->t('This must be an internal path such as %add-node. You can also start typing the title of a piece of content to select it. Enter %front to link to the front page. Enter %nolink to display link text only. Enter %button to display keyboard-accessible link text only.', [
'%add-node' => '/node/add',
'%front' => '<front>',
'%nolink' => '<nolink>',
'%button' => '<button>',
]);
}
elseif ($this->supportsExternalLinks() && $this->supportsInternalLinks()) {
$element['uri']['#description'] = $this->t('Start typing the title of a piece of content to select it. You can also enter an internal path such as %add-node or an external URL such as %url. Enter %front to link to the front page. Enter %nolink to display link text only. Enter %button to display keyboard-accessible link text only.', [
'%front' => '<front>',
'%add-node' => '/node/add',
'%url' => 'https://example.com',
'%nolink' => '<nolink>',
'%button' => '<button>',
]);
}
elseif ($this->supportsExternalLinks() && !$this->supportsInternalLinks()) {
$element['uri']['#description'] = $this->t('This must be an external URL such as %url.', [
'%url' => 'https://example.com',
]);
}
// Make uri required on the front-end when title filled-in.
if (!$this->isDefaultValueWidget($form_state) && $this->getFieldSetting('title') !== DRUPAL_DISABLED && !$element['uri']['#required']) {
$parents = $element['#field_parents'];
$parents[] = $this->fieldDefinition
->getName();
$selector = $root = array_shift($parents);
if ($parents) {
$selector = $root . '[' . implode('][', $parents) . ']';
}
$element['uri']['#states']['required'] = [
':input[name="' . $selector . '[' . $delta . '][title]"]' => [
'filled' => TRUE,
],
];
}
$element['title'] = [
'#type' => 'textfield',
'#title' => $this->t('Link text'),
'#placeholder' => $this->getSetting('placeholder_title'),
'#default_value' => $items[$delta]->title ?? NULL,
'#maxlength' => 255,
'#access' => $this->getFieldSetting('title') != DRUPAL_DISABLED,
'#required' => $this->getFieldSetting('title') === DRUPAL_REQUIRED && $element['#required'],
];
// Post-process the title field to make it conditionally required if URL is
// non-empty. Omit the validation on the field edit form, since the field
// settings cannot be saved otherwise.
//
// Validate that title field is filled out (regardless of uri) when it is a
// required field.
if (!$this->isDefaultValueWidget($form_state) && $this->getFieldSetting('title') === DRUPAL_REQUIRED) {
$element['#element_validate'][] = [
static::class,
'validateTitleElement',
];
$element['#element_validate'][] = [
static::class,
'validateTitleNoLink',
];
if (!$element['title']['#required']) {
// Make title required on the front-end when URI filled-in.
$parents = $element['#field_parents'];
$parents[] = $this->fieldDefinition
->getName();
$selector = $root = array_shift($parents);
if ($parents) {
$selector = $root . '[' . implode('][', $parents) . ']';
}
$element['title']['#states']['required'] = [
':input[name="' . $selector . '[' . $delta . '][uri]"]' => [
'filled' => TRUE,
],
];
}
}
// Ensure that a URI is always entered when an optional title field is
// submitted.
if (!$this->isDefaultValueWidget($form_state) && $this->getFieldSetting('title') == DRUPAL_OPTIONAL) {
$element['#element_validate'][] = [
static::class,
'validateTitleNoLink',
];
}
// Exposing the attributes array in the widget is left for alternate and more
// advanced field widgets.
$element['attributes'] = [
'#type' => 'value',
'#tree' => TRUE,
'#value' => !empty($items[$delta]->options['attributes']) ? $items[$delta]->options['attributes'] : [],
'#attributes' => [
'class' => [
'link-field-widget-attributes',
],
],
];
// If cardinality is 1, ensure a proper label is output for the field.
if ($this->fieldDefinition
->getFieldStorageDefinition()
->getCardinality() == 1) {
// If the link title is disabled, use the field definition label as the
// title of the 'uri' element.
if ($this->getFieldSetting('title') == DRUPAL_DISABLED) {
$element['uri']['#title'] = $element['#title'];
// By default the field description is added to the title field. Since
// the title field is disabled, we add the description, if given, to the
// uri element instead.
if (!empty($element['#description'])) {
if (empty($element['uri']['#description'])) {
$element['uri']['#description'] = $element['#description'];
}
else {
// If we have the description of the type of field together with
// the user provided description, we want to make a distinction
// between "core help text" and "user entered help text". To make
// this distinction more clear, we put them in an unordered list.
$element['uri']['#description'] = [
'#theme' => 'item_list',
'#items' => [
// Assume the user-specified description has the most relevance,
// so place it first.
$element['#description'],
$element['uri']['#description'],
],
];
}
}
}
else {
$element += [
'#type' => 'fieldset',
];
}
}
return $element;
}
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.