View source
<?php
namespace Drupal\link\Plugin\Field\FieldWidget;
use Drupal\Core\Entity\Element\EntityAutocomplete;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\link\LinkItemInterface;
use Symfony\Component\Validator\ConstraintViolation;
use Symfony\Component\Validator\ConstraintViolationListInterface;
class LinkWidget extends WidgetBase {
public static function defaultSettings() {
return array(
'placeholder_url' => '',
'placeholder_title' => '',
) + parent::defaultSettings();
}
protected static function getUriAsDisplayableString($uri) {
$scheme = parse_url($uri, PHP_URL_SCHEME);
$displayable_string = $uri;
if ($scheme === 'internal') {
$uri_reference = explode(':', $uri, 2)[1];
$path = parse_url($uri, PHP_URL_PATH);
if ($path === '/') {
$uri_reference = '<front>' . substr($uri_reference, 1);
}
$displayable_string = $uri_reference;
}
elseif ($scheme === 'entity') {
list($entity_type, $entity_id) = explode('/', substr($uri, 7), 2);
$entity_manager = \Drupal::entityManager();
if ($entity_manager
->getDefinition($entity_type, FALSE) && ($entity = \Drupal::entityManager()
->getStorage($entity_type)
->load($entity_id))) {
$displayable_string = EntityAutocomplete::getEntityLabels(array(
$entity,
));
}
}
return $displayable_string;
}
protected static function getUserEnteredStringAsUri($string) {
$uri = $string;
$entity_id = EntityAutocomplete::extractEntityIdFromAutocompleteInput($string);
if ($entity_id !== NULL) {
$uri = 'entity:node/' . $entity_id;
}
elseif (!empty($string) && parse_url($string, PHP_URL_SCHEME) === NULL) {
if (strpos($string, '<front>') === 0) {
$string = '/' . substr($string, strlen('<front>'));
}
$uri = 'internal:' . $string;
}
return $uri;
}
public static function validateUriElement($element, FormStateInterface $form_state, $form) {
$uri = static::getUserEnteredStringAsUri($element['#value']);
$form_state
->setValueForElement($element, $uri);
if (parse_url($uri, PHP_URL_SCHEME) === 'internal' && !in_array($element['#value'][0], [
'/',
'?',
'#',
], TRUE) && substr($element['#value'], 0, 7) !== '<front>') {
$form_state
->setError($element, t('Manually entered paths should start with /, ? or #.'));
return;
}
}
public static function validateTitleElement(&$element, FormStateInterface $form_state, $form) {
if ($element['uri']['#value'] !== '' && $element['title']['#value'] === '') {
$element['title']['#required'] = TRUE;
$form_state
->setError($element['title'], t('@name field is required.', array(
'@name' => $element['title']['#title'],
)));
}
}
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
$item = $items[$delta];
$element['uri'] = array(
'#type' => 'url',
'#title' => $this
->t('URL'),
'#placeholder' => $this
->getSetting('placeholder_url'),
'#default_value' => !$item
->isEmpty() && (\Drupal::currentUser()
->hasPermission('link to any page') || $item
->getUrl()
->access()) ? static::getUriAsDisplayableString($item->uri) : NULL,
'#element_validate' => array(
array(
get_called_class(),
'validateUriElement',
),
),
'#maxlength' => 2048,
'#required' => $element['#required'],
);
if ($this
->supportsInternalLinks()) {
$element['uri']['#type'] = 'entity_autocomplete';
$element['uri']['#target_type'] = 'node';
$element['uri']['#attributes']['data-autocomplete-first-character-blacklist'] = '/#?';
$element['uri']['#process_default_value'] = FALSE;
}
if (!$this
->supportsExternalLinks()) {
$element['uri']['#field_prefix'] = rtrim(\Drupal::url('<front>', array(), array(
'absolute' => TRUE,
)), '/');
}
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.', array(
'%front' => '<front>',
'%add-node' => '/node/add',
'%url' => 'http://example.com',
));
}
elseif ($this
->supportsExternalLinks() && !$this
->supportsInternalLinks()) {
$element['uri']['#description'] = $this
->t('This must be an external URL such as %url.', array(
'%url' => 'http://example.com',
));
}
$element['title'] = array(
'#type' => 'textfield',
'#title' => $this
->t('Link text'),
'#placeholder' => $this
->getSetting('placeholder_title'),
'#default_value' => isset($items[$delta]->title) ? $items[$delta]->title : NULL,
'#maxlength' => 255,
'#access' => $this
->getFieldSetting('title') != DRUPAL_DISABLED,
);
if (!$this
->isDefaultValueWidget($form_state) && $this
->getFieldSetting('title') == DRUPAL_REQUIRED) {
$element['#element_validate'][] = array(
get_called_class(),
'validateTitleElement',
);
}
$element['attributes'] = array(
'#type' => 'value',
'#tree' => TRUE,
'#value' => !empty($items[$delta]->options['attributes']) ? $items[$delta]->options['attributes'] : array(),
'#attributes' => array(
'class' => array(
'link-field-widget-attributes',
),
),
);
if ($this->fieldDefinition
->getFieldStorageDefinition()
->getCardinality() == 1) {
if ($this
->getFieldSetting('title') == DRUPAL_DISABLED) {
$element['uri']['#title'] = $element['#title'];
}
else {
$element += array(
'#type' => 'fieldset',
);
}
}
return $element;
}
protected function supportsInternalLinks() {
$link_type = $this
->getFieldSetting('link_type');
return (bool) ($link_type & LinkItemInterface::LINK_INTERNAL);
}
protected function supportsExternalLinks() {
$link_type = $this
->getFieldSetting('link_type');
return (bool) ($link_type & LinkItemInterface::LINK_EXTERNAL);
}
public function settingsForm(array $form, FormStateInterface $form_state) {
$elements = parent::settingsForm($form, $form_state);
$elements['placeholder_url'] = array(
'#type' => 'textfield',
'#title' => $this
->t('Placeholder for URL'),
'#default_value' => $this
->getSetting('placeholder_url'),
'#description' => $this
->t('Text that will be shown inside the field until a value is entered. This hint is usually a sample value or a brief description of the expected format.'),
);
$elements['placeholder_title'] = array(
'#type' => 'textfield',
'#title' => $this
->t('Placeholder for link text'),
'#default_value' => $this
->getSetting('placeholder_title'),
'#description' => $this
->t('Text that will be shown inside the field until a value is entered. This hint is usually a sample value or a brief description of the expected format.'),
'#states' => array(
'invisible' => array(
':input[name="instance[settings][title]"]' => array(
'value' => DRUPAL_DISABLED,
),
),
),
);
return $elements;
}
public function settingsSummary() {
$summary = array();
$placeholder_title = $this
->getSetting('placeholder_title');
$placeholder_url = $this
->getSetting('placeholder_url');
if (empty($placeholder_title) && empty($placeholder_url)) {
$summary[] = $this
->t('No placeholders');
}
else {
if (!empty($placeholder_title)) {
$summary[] = $this
->t('Title placeholder: @placeholder_title', array(
'@placeholder_title' => $placeholder_title,
));
}
if (!empty($placeholder_url)) {
$summary[] = $this
->t('URL placeholder: @placeholder_url', array(
'@placeholder_url' => $placeholder_url,
));
}
}
return $summary;
}
public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
foreach ($values as &$value) {
$value['uri'] = static::getUserEnteredStringAsUri($value['uri']);
$value += [
'options' => [],
];
}
return $values;
}
public function flagErrors(FieldItemListInterface $items, ConstraintViolationListInterface $violations, array $form, FormStateInterface $form_state) {
foreach ($violations as $offset => $violation) {
$parameters = $violation
->getParameters();
if (isset($parameters['@uri'])) {
$parameters['@uri'] = static::getUriAsDisplayableString($parameters['@uri']);
$violations
->set($offset, new ConstraintViolation($this
->t($violation
->getMessageTemplate(), $parameters), $violation
->getMessageTemplate(), $parameters, $violation
->getRoot(), $violation
->getPropertyPath(), $violation
->getInvalidValue(), $violation
->getPlural(), $violation
->getCode()));
}
}
parent::flagErrors($items, $violations, $form, $form_state);
}
}