'', 'uri' => '', 'icon_class' => '', ]; } /** * {@inheritdoc} */ public function blockForm($form, FormStateInterface $form_state): array { $config = $this->configuration; $display_uri = NULL; if (!empty($config['uri'])) { 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. $url = Url::fromUri($config['uri']); if (\Drupal::currentUser()->hasPermission('link to any page') || $url->access()) { $display_uri = static::getUriAsDisplayableString($config['uri']); } } catch (\InvalidArgumentException) { // If $item->uri is invalid, show value as is, so the user can see what // to edit. $display_uri = $config['uri']; } } // @todo Logic related to the uri component has been borrowed from // Drupal\link\Plugin\Field\FieldWidget\LinkWidget. // Will be fixed in https://www.drupal.org/project/drupal/issues/3450518. $form['uri'] = [ '#type' => 'entity_autocomplete', '#title' => $this->t('URL'), '#default_value' => $display_uri, '#element_validate' => [[static::class, 'validateUriElement']], '#attributes' => [ 'data-autocomplete-first-character-denylist' => '/#?', ], // @todo The user should be able to select an entity type. Will be fixed // in https://www.drupal.org/node/2423093. '#target_type' => 'node', '#maxlength' => 2048, '#required' => TRUE, '#process_default_value' => FALSE, ]; $form['title'] = [ '#type' => 'textfield', '#title' => $this->t('Link text'), '#default_value' => $config['title'], '#required' => TRUE, '#maxlength' => 255, ]; $form['icon_class'] = [ '#type' => 'textfield', '#title' => $this->t('Icon CSS class'), '#default_value' => $config['icon_class'], '#element_validate' => [[static::class, 'validateIconClassElement']], '#required' => TRUE, '#maxlength' => 64, ]; return $form; } /** * Form element validation handler for the 'icon_class' element. * * Disallows saving invalid class values. */ public static function validateIconClassElement(array $element, FormStateInterface $form_state, array $form): void { $icon = $element['#value']; if (!preg_match('/^[a-z0-9_-]+$/', $icon)) { $form_state->setError($element, t('The machine-readable name must contain only lowercase letters, numbers, underscores and hyphens.')); } } /** * Form element validation handler for the 'uri' element. * * Disallows saving inaccessible or untrusted URLs. */ public static function validateUriElement($element, FormStateInterface $form_state, $form): void { $uri = static::getUserEnteredStringAsUri($element['#value']); $form_state->setValueForElement($element, $uri); // If getUserEnteredStringAsUri() mapped the entered value to an 'internal:' // URI , ensure the raw value begins with '/', '?' or '#'. // @todo '' is valid input for BC reasons, may be removed by // https://www.drupal.org/node/2421941 if (parse_url($uri, PHP_URL_SCHEME) === 'internal' && !in_array($element['#value'][0], ['/', '?', '#'], TRUE) && !str_starts_with($element['#value'], '')) { $form_state->setError($element, new TranslatableMarkup('Manually entered paths should start with one of the following characters: / ? #')); return; } } /** * Gets the user-entered string as a URI. * * The following two forms of input are mapped to URIs: * - entity autocomplete ("label (entity id)") strings: to 'entity:' URIs; * - strings without a detectable scheme: to 'internal:' URIs. * * This method is the inverse of ::getUriAsDisplayableString(). * * @param string $string * The user-entered string. * * @return string * The URI, if a non-empty $uri was passed. * * @see static::getUriAsDisplayableString() */ protected static function getUserEnteredStringAsUri($string):string { // By default, assume the entered string is a URI. $uri = trim($string); // Detect entity autocomplete string, map to 'entity:' URI. $entity_id = EntityAutocomplete::extractEntityIdFromAutocompleteInput($string); if ($entity_id !== NULL) { // @todo Support entity types other than 'node'. Will be fixed in // https://www.drupal.org/node/2423093. $uri = 'entity:node/' . $entity_id; } // Support linking to nothing. elseif (in_array($string, ['', '', '