Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
0.00% |
0 / 5 |
CRAP | |
0.00% |
0 / 136 |
| EditorImageDialog | |
0.00% |
0 / 1 |
|
0.00% |
0 / 5 |
600 | |
0.00% |
0 / 136 |
| __construct | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| create | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 4 |
|||
| getFormId | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| buildForm | |
0.00% |
0 / 1 |
306 | |
0.00% |
0 / 101 |
|||
| submitForm | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 27 |
|||
| <?php | |
| /** | |
| * @file | |
| * Contains \Drupal\editor\Form\EditorImageDialog. | |
| */ | |
| namespace Drupal\editor\Form; | |
| use Drupal\Component\Utility\Bytes; | |
| use Drupal\Core\Form\FormBase; | |
| use Drupal\Core\Form\FormStateInterface; | |
| use Drupal\filter\Entity\FilterFormat; | |
| use Drupal\Core\Ajax\AjaxResponse; | |
| use Drupal\Core\Ajax\HtmlCommand; | |
| use Drupal\editor\Ajax\EditorDialogSave; | |
| use Drupal\Core\Ajax\CloseModalDialogCommand; | |
| use Symfony\Component\DependencyInjection\ContainerInterface; | |
| use Drupal\Core\Entity\EntityStorageInterface; | |
| /** | |
| * Provides an image dialog for text editors. | |
| */ | |
| class EditorImageDialog extends FormBase { | |
| /** | |
| * The file storage service. | |
| * | |
| * @var \Drupal\Core\Entity\EntityStorageInterface | |
| */ | |
| protected $fileStorage; | |
| /** | |
| * Constructs a form object for image dialog. | |
| * | |
| * @param \Drupal\Core\Entity\EntityStorageInterface $file_storage | |
| * The file storage service. | |
| */ | |
| public function __construct(EntityStorageInterface $file_storage) { | |
| $this->fileStorage = $file_storage; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public static function create(ContainerInterface $container) { | |
| return new static( | |
| $container->get('entity.manager')->getStorage('file') | |
| ); | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getFormId() { | |
| return 'editor_image_dialog'; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| * | |
| * @param \Drupal\filter\Entity\FilterFormat $filter_format | |
| * The filter format for which this dialog corresponds. | |
| */ | |
| public function buildForm(array $form, FormStateInterface $form_state, FilterFormat $filter_format = NULL) { | |
| // This form is special, in that the default values do not come from the | |
| // server side, but from the client side, from a text editor. We must cache | |
| // this data in form state, because when the form is rebuilt, we will be | |
| // receiving values from the form, instead of the values from the text | |
| // editor. If we don't cache it, this data will be lost. | |
| if (isset($form_state->getUserInput()['editor_object'])) { | |
| // By convention, the data that the text editor sends to any dialog is in | |
| // the 'editor_object' key. And the image dialog for text editors expects | |
| // that data to be the attributes for an <img> element. | |
| $image_element = $form_state->getUserInput()['editor_object']; | |
| $form_state->set('image_element', $image_element); | |
| $form_state->setCached(TRUE); | |
| } | |
| else { | |
| // Retrieve the image element's attributes from form state. | |
| $image_element = $form_state->get('image_element') ?: []; | |
| } | |
| $form['#tree'] = TRUE; | |
| $form['#attached']['library'][] = 'editor/drupal.editor.dialog'; | |
| $form['#prefix'] = '<div id="editor-image-dialog-form">'; | |
| $form['#suffix'] = '</div>'; | |
| $editor = editor_load($filter_format->id()); | |
| // Construct strings to use in the upload validators. | |
| $image_upload = $editor->getImageUploadSettings(); | |
| if (!empty($image_upload['dimensions'])) { | |
| $max_dimensions = $image_upload['dimensions']['max_width'] . '×' . $image_upload['dimensions']['max_height']; | |
| } | |
| else { | |
| $max_dimensions = 0; | |
| } | |
| $max_filesize = min(Bytes::toInt($image_upload['max_size']), file_upload_max_size()); | |
| $existing_file = isset($image_element['data-entity-uuid']) ? \Drupal::entityManager()->loadEntityByUuid('file', $image_element['data-entity-uuid']) : NULL; | |
| $fid = $existing_file ? $existing_file->id() : NULL; | |
| $form['fid'] = array( | |
| '#title' => $this->t('Image'), | |
| '#type' => 'managed_file', | |
| '#upload_location' => $image_upload['scheme'] . '://' . $image_upload['directory'], | |
| '#default_value' => $fid ? array($fid) : NULL, | |
| '#upload_validators' => array( | |
| 'file_validate_extensions' => array('gif png jpg jpeg'), | |
| 'file_validate_size' => array($max_filesize), | |
| 'file_validate_image_resolution' => array($max_dimensions), | |
| ), | |
| '#required' => TRUE, | |
| ); | |
| $form['attributes']['src'] = array( | |
| '#title' => $this->t('URL'), | |
| '#type' => 'textfield', | |
| '#default_value' => isset($image_element['src']) ? $image_element['src'] : '', | |
| '#maxlength' => 2048, | |
| '#required' => TRUE, | |
| ); | |
| // If the editor has image uploads enabled, show a managed_file form item, | |
| // otherwise show a (file URL) text form item. | |
| if ($image_upload['status']) { | |
| $form['attributes']['src']['#access'] = FALSE; | |
| $form['attributes']['src']['#required'] = FALSE; | |
| } | |
| else { | |
| $form['fid']['#access'] = FALSE; | |
| $form['fid']['#required'] = FALSE; | |
| } | |
| // The alt attribute is *required*, but we allow users to opt-in to empty | |
| // alt attributes for the very rare edge cases where that is valid by | |
| // specifying two double quotes as the alternative text in the dialog. | |
| // However, that *is* stored as an empty alt attribute, so if we're editing | |
| // an existing image (which means the src attribute is set) and its alt | |
| // attribute is empty, then we show that as two double quotes in the dialog. | |
| // @see https://www.drupal.org/node/2307647 | |
| $alt = isset($image_element['alt']) ? $image_element['alt'] : ''; | |
| if ($alt === '' && !empty($image_element['src'])) { | |
| $alt = '""'; | |
| } | |
| $form['attributes']['alt'] = array( | |
| '#title' => $this->t('Alternative text'), | |
| '#placeholder' => $this->t('Short description for the visually impaired'), | |
| '#type' => 'textfield', | |
| '#required' => TRUE, | |
| '#required_error' => $this->t('Alternative text is required.<br />(Only in rare cases should this be left empty. To create empty alternative text, enter <code>""</code> — two double quotes without any content).'), | |
| '#default_value' => $alt, | |
| '#maxlength' => 2048, | |
| ); | |
| // When Drupal core's filter_align is being used, the text editor may | |
| // offer the ability to change the alignment. | |
| if (isset($image_element['data-align']) && $filter_format->filters('filter_align')->status) { | |
| $form['align'] = array( | |
| '#title' => $this->t('Align'), | |
| '#type' => 'radios', | |
| '#options' => array( | |
| 'none' => $this->t('None'), | |
| 'left' => $this->t('Left'), | |
| 'center' => $this->t('Center'), | |
| 'right' => $this->t('Right'), | |
| ), | |
| '#default_value' => $image_element['data-align'] === '' ? 'none' : $image_element['data-align'], | |
| '#wrapper_attributes' => array('class' => array('container-inline')), | |
| '#attributes' => array('class' => array('container-inline')), | |
| '#parents' => array('attributes', 'data-align'), | |
| ); | |
| } | |
| // When Drupal core's filter_caption is being used, the text editor may | |
| // offer the ability to in-place edit the image's caption: show a toggle. | |
| if (isset($image_element['hasCaption']) && $filter_format->filters('filter_caption')->status) { | |
| $form['caption'] = array( | |
| '#title' => $this->t('Caption'), | |
| '#type' => 'checkbox', | |
| '#default_value' => $image_element['hasCaption'] === 'true', | |
| '#parents' => array('attributes', 'hasCaption'), | |
| ); | |
| } | |
| $form['actions'] = array( | |
| '#type' => 'actions', | |
| ); | |
| $form['actions']['save_modal'] = array( | |
| '#type' => 'submit', | |
| '#value' => $this->t('Save'), | |
| // No regular submit-handler. This form only works via JavaScript. | |
| '#submit' => array(), | |
| '#ajax' => array( | |
| 'callback' => '::submitForm', | |
| 'event' => 'click', | |
| ), | |
| ); | |
| return $form; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function submitForm(array &$form, FormStateInterface $form_state) { | |
| $response = new AjaxResponse(); | |
| // Convert any uploaded files from the FID values to data-entity-uuid | |
| // attributes and set data-entity-type to 'file'. | |
| $fid = $form_state->getValue(array('fid', 0)); | |
| if (!empty($fid)) { | |
| $file = $this->fileStorage->load($fid); | |
| $file_url = file_create_url($file->getFileUri()); | |
| // Transform absolute image URLs to relative image URLs: prevent problems | |
| // on multisite set-ups and prevent mixed content errors. | |
| $file_url = file_url_transform_relative($file_url); | |
| $form_state->setValue(array('attributes', 'src'), $file_url); | |
| $form_state->setValue(array('attributes', 'data-entity-uuid'), $file->uuid()); | |
| $form_state->setValue(array('attributes', 'data-entity-type'), 'file'); | |
| } | |
| // When the alt attribute is set to two double quotes, transform it to the | |
| // empty string: two double quotes signify "empty alt attribute". See above. | |
| if (trim($form_state->getValue(array('attributes', 'alt'))) === '""') { | |
| $form_state->setValue(array('attributes', 'alt'), ''); | |
| } | |
| if ($form_state->getErrors()) { | |
| unset($form['#prefix'], $form['#suffix']); | |
| $form['status_messages'] = [ | |
| '#type' => 'status_messages', | |
| '#weight' => -10, | |
| ]; | |
| $response->addCommand(new HtmlCommand('#editor-image-dialog-form', $form)); | |
| } | |
| else { | |
| $response->addCommand(new EditorDialogSave($form_state->getValues())); | |
| $response->addCommand(new CloseModalDialogCommand()); | |
| } | |
| return $response; | |
| } | |
| } |