Example #1
0
 /**
  * {@inheritdoc}
  *
  * @param \Drupal\filter\Entity\FilterFormat $filter_format
  *   The filter format for which this dialog corresponds.
  */
 public function buildForm(array $form, array &$form_state, FilterFormat $filter_format = NULL)
 {
     // The default values are set directly from \Drupal::request()->request,
     // provided by the editor plugin opening the dialog.
     if (!isset($form_state['image_element'])) {
         $form_state['image_element'] = isset($form_state['input']['editor_object']) ? $form_state['input']['editor_object'] : array();
     }
     $image_element = $form_state['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->format);
     // Construct strings to use in the upload validators.
     $image_upload = $editor->getImageUploadSettings();
     if (!empty($image_upload['dimensions'])) {
         $max_dimensions = $image_upload['dimensions']['max_width'] . 'x' . $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-editor-file-uuid']) ? entity_load_by_uuid('file', $image_element['data-editor-file-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;
     }
     $form['attributes']['alt'] = array('#title' => $this->t('Alternative text'), '#type' => 'textfield', '#required' => TRUE, '#default_value' => isset($image_element['alt']) ? $image_element['alt'] : '', '#maxlength' => 2048);
     $form['dimensions'] = array('#type' => 'item', '#title' => $this->t('Image size'), '#field_prefix' => '<div class="container-inline">', '#field_suffix' => '</div>');
     $form['dimensions']['width'] = array('#title' => $this->t('Width'), '#title_display' => 'invisible', '#type' => 'number', '#default_value' => isset($image_element['width']) ? $image_element['width'] : '', '#size' => 8, '#maxlength' => 8, '#min' => 1, '#max' => 99999, '#placeholder' => $this->t('width'), '#field_suffix' => ' x ', '#parents' => array('attributes', 'width'));
     $form['dimensions']['height'] = array('#title' => $this->t('Height'), '#title_display' => 'invisible', '#type' => 'number', '#default_value' => isset($image_element['height']) ? $image_element['height'] : '', '#size' => 8, '#maxlength' => 8, '#min' => 1, '#max' => 99999, '#placeholder' => $this->t('height'), '#field_suffix' => $this->t('pixels'), '#parents' => array('attributes', 'height'));
     // When Drupal core's filter_caption is being used, the text editor may
     // offer the ability to change the alignment.
     if (isset($image_element['data-align'])) {
         $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'])) {
         $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'), '#submit' => array(), '#ajax' => array('callback' => array($this, 'submitForm'), 'event' => 'click'));
     return $form;
 }
Example #2
0
 /**
  * {@inheritdoc}
  */
 public function getAttachments()
 {
     $user = \Drupal::currentUser();
     $user_format_ids = array_keys(filter_formats($user));
     $manager = \Drupal::service('plugin.manager.editor');
     $definitions = $manager->getDefinitions();
     // Filter the current user's formats to those that support inline editing.
     $formats = array();
     foreach ($user_format_ids as $format_id) {
         if ($editor = editor_load($format_id)) {
             $editor_id = $editor->getEditor();
             if (isset($definitions[$editor_id]['supports_inline_editing']) && $definitions[$editor_id]['supports_inline_editing'] === TRUE) {
                 $formats[] = $format_id;
             }
         }
     }
     // Get the attachments for all text editors that the user might use.
     $attachments = $manager->getAttachments($formats);
     // Also include editor.module's formatted text editor.
     $attachments['library'][] = 'editor/quickedit.inPlaceEditor.formattedText';
     return $attachments;
 }
Example #3
0
 /**
  * Retrieves text editor libraries and JavaScript settings.
  *
  * @param array $format_ids
  *   An array of format IDs as returned by array_keys(filter_formats()).
  *
  * @return array
  *   An array of attachments, for use with #attached.
  *
  * @see \Drupal\Core\Render\AttachmentsResponseProcessorInterface::processAttachments()
  */
 public function getAttachments(array $format_ids)
 {
     $attachments = array('library' => array());
     $settings = array();
     foreach ($format_ids as $format_id) {
         $editor = editor_load($format_id);
         if (!$editor) {
             continue;
         }
         $plugin = $this->createInstance($editor->getEditor());
         $plugin_definition = $plugin->getPluginDefinition();
         // Libraries.
         $attachments['library'] = array_merge($attachments['library'], $plugin->getLibraries($editor));
         // Format-specific JavaScript settings.
         $settings['editor']['formats'][$format_id] = array('format' => $format_id, 'editor' => $editor->getEditor(), 'editorSettings' => $plugin->getJSSettings($editor), 'editorSupportsContentFiltering' => $plugin_definition['supports_content_filtering'], 'isXssSafe' => $plugin_definition['is_xss_safe']);
     }
     // Allow other modules to alter all JavaScript settings.
     $this->moduleHandler->alter('editor_js_settings', $settings);
     if (empty($attachments['library']) && empty($settings)) {
         return array();
     }
     $attachments['drupalSettings'] = $settings;
     return $attachments;
 }
Example #4
0
 /**
  * Verifies unicorn editor configuration.
  *
  * @param string $format_id
  *   The format machine name.
  * @param bool $ponies_too
  *   The expected value of the ponies_too setting.
  */
 protected function verifyUnicornEditorConfiguration($format_id, $ponies_too = TRUE)
 {
     $editor = editor_load($format_id);
     $settings = $editor->getSettings();
     $this->assertIdentical($editor->getEditor(), 'unicorn', 'The text editor is configured correctly.');
     $this->assertIdentical($settings['ponies_too'], $ponies_too, 'The text editor settings are stored correctly.');
     $this->drupalGet('admin/config/content/formats/manage/' . $format_id);
     $select = $this->xpath('//select[@name="editor[editor]"]');
     $select_is_disabled = $this->xpath('//select[@name="editor[editor]" and @disabled="disabled"]');
     $options = $this->xpath('//select[@name="editor[editor]"]/option');
     $this->assertTrue(count($select) === 1, 'The Text Editor select exists.');
     $this->assertTrue(count($select_is_disabled) === 0, 'The Text Editor select is not disabled.');
     $this->assertTrue(count($options) === 2, 'The Text Editor select has two options.');
     $this->assertTrue((string) $options[1]['selected'] === 'selected', 'Option 2 ("Unicorn Editor") is selected.');
 }
Example #5
0
        if ($is_admin == "group") {
            if ($member[mb_id] != $group[gr_admin]) {
                alert("그룹이 틀립니다.");
            }
        }
        $required_bo_table = "";
        $update_bo_table = "readonly='readonly' style='background-color:#dddddd'";
    }
}
if ($is_admin != "super") {
    $group = get_group($board[gr_id]);
    $is_admin = is_admin($member[mb_id]);
}
$g4[title] = $html_title;
include_once "./admin.head.php";
echo editor_load();
?>

<?php 
echo subtitle("게시판 생성");
?>
<form id='fboardform' method='post' action='#' onsubmit="return fboardform_submit(this)" enctype="multipart/form-data">
<table class='normal3'>
<col width="40" />
<col width="170" />
<col />
<tr>
    <td></td>
    <th>TABLE</th>
    <td>
        <input type='hidden' name='w'     value='<?php 
Example #6
0
 /**
  * {@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'), '#submit' => array(), '#ajax' => array('callback' => '::submitForm', 'event' => 'click'));
     return $form;
 }
Example #7
0
  /**
   * {@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.
      $file_element = $form_state->getUserInput()['editor_object'];
      $form_state->set('file_element', $file_element);
      $form_state->setCached(TRUE);
    }
    else {
      // Retrieve the image element's attributes from form state.
      $file_element = $form_state->get('file_element') ?: [];
    }

    $form['#tree'] = TRUE;
    $form['#attached']['library'][] = 'editor/drupal.editor.dialog';
    $form['#prefix'] = '<div id="editor-file-dialog-form">';
    $form['#suffix'] = '</div>';


    // Load dialog settings.
    $editor = editor_load($filter_format->id());
    $file_upload = $editor->getThirdPartySettings('editor_file');
    $max_filesize = min(Bytes::toInt($file_upload['max_size']), file_upload_max_size());

    $existing_file = isset($file_element['data-entity-uuid']) ? \Drupal::entityManager()->loadEntityByUuid('file', $file_element['data-entity-uuid']) : NULL;
    $fid = $existing_file ? $existing_file->id() : NULL;

    $form['fid'] = array(
      '#title' => $this->t('File'),
      '#type' => 'managed_file',
      '#upload_location' => $file_upload['scheme'] . '://' . $file_upload['directory'],
      '#default_value' => $fid ? array($fid) : NULL,
      '#upload_validators' => array(
        'file_validate_extensions' => !empty($file_upload['extensions']) ? $file_upload['extensions'] : array('txt'),
        'file_validate_size' => array($max_filesize),
      ),
      '#required' => TRUE,
    );

    $form['attributes']['href'] = array(
      '#title' => $this->t('URL'),
      '#type' => 'textfield',
      '#default_value' => isset($file_element['href']) ? $file_element['href'] : '',
      '#maxlength' => 2048,
      '#required' => TRUE,
    );

    if ($file_upload['status']) {
      $form['attributes']['href']['#access'] = FALSE;
      $form['attributes']['href']['#required'] = FALSE;
    }
    else {
      $form['fid']['#access'] = FALSE;
      $form['fid']['#required'] = FALSE;
    }

    $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;
  }
Example #8
0
 /**
  * Verifies unicorn editor configuration.
  *
  * @param string $format_id
  *   The format machine name.
  * @param string $foo
  *   The expected value of the foo setting.
  */
 protected function verifyUnicornEditorConfiguration($format_id, $foo = 'bar')
 {
     $editor = editor_load($format_id);
     $settings = $editor->getSettings();
     $this->assertIdentical($editor->getEditor(), 'unicorn', 'The text editor is configured correctly.');
     $this->assertIdentical($settings['foo'], $foo, 'The text editor settings are stored correctly.');
     $this->assertIdentical($settings['ponies too'], true, 'The text editor defaults are retrieved correctly.');
     $this->assertIdentical($settings['rainbows'], true, 'The text editor defaults added by hook_editor_settings_defaults() are retrieved correctly.');
     $this->assertIdentical($settings['sparkles'], false, 'The text editor defaults modified by hook_editor_settings_defaults_alter() are retrieved correctly.');
     $this->drupalGet('admin/config/content/formats/manage/' . $format_id);
     $select = $this->xpath('//select[@name="editor[editor]"]');
     $select_is_disabled = $this->xpath('//select[@name="editor[editor]" and @disabled="disabled"]');
     $options = $this->xpath('//select[@name="editor[editor]"]/option');
     $this->assertTrue(count($select) === 1, 'The Text Editor select exists.');
     $this->assertTrue(count($select_is_disabled) === 0, 'The Text Editor select is not disabled.');
     $this->assertTrue(count($options) === 2, 'The Text Editor select has two options.');
     $this->assertTrue((string) $options[1]['selected'] === 'selected', 'Option 2 ("Unicorn Editor") is selected.');
 }
 /**
  * {@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)
 {
     // The default values are set directly from \Drupal::request()->request,
     // provided by the editor plugin opening the dialog.
     if (!($image_element = $form_state->get('image_element'))) {
         $user_input = $form_state->getUserInput();
         $image_element = isset($user_input['editor_object']) ? $user_input['editor_object'] : [];
         $form_state->set('image_element', $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->format);
     // 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-editor-file-uuid']) ? entity_load_by_uuid('file', $image_element['data-editor-file-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><em>(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);
     $form['dimensions'] = array('#type' => 'fieldset', '#title' => $this->t('Image size'), '#attributes' => array('class' => array('container-inline', 'fieldgroup', 'form-composite')));
     $form['dimensions']['width'] = array('#title' => $this->t('Width'), '#title_display' => 'invisible', '#type' => 'number', '#default_value' => isset($image_element['width']) ? $image_element['width'] : '', '#size' => 8, '#maxlength' => 8, '#min' => 1, '#max' => 99999, '#placeholder' => $this->t('width'), '#field_suffix' => ' × ', '#parents' => array('attributes', 'width'));
     $form['dimensions']['height'] = array('#title' => $this->t('Height'), '#title_display' => 'invisible', '#type' => 'number', '#default_value' => isset($image_element['height']) ? $image_element['height'] : '', '#size' => 8, '#maxlength' => 8, '#min' => 1, '#max' => 99999, '#placeholder' => $this->t('height'), '#field_suffix' => $this->t('pixels'), '#parents' => array('attributes', 'height'));
     // 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'), '#submit' => array(), '#ajax' => array('callback' => '::submitForm', 'event' => 'click'));
     return $form;
 }