diff --git a/core/modules/ckeditor/js/plugins/drupalimage/plugin.js b/core/modules/ckeditor/js/plugins/drupalimage/plugin.js old mode 100644 new mode 100755 index 0025664..8bfe9bb --- a/core/modules/ckeditor/js/plugins/drupalimage/plugin.js +++ b/core/modules/ckeditor/js/plugins/drupalimage/plugin.js @@ -60,7 +60,11 @@ element: 'img', attributes: { src: '', - alt: '' + alt: '', + width: '', + height: '', + 'data-entity-type': '', + 'data-entity-uuid': '' } }); @@ -99,7 +103,7 @@ data['data-entity-type'] = element.attributes['data-entity-type']; // Parse the data-entity-uuid attribute. data['data-entity-uuid'] = element.attributes['data-entity-uuid']; - + return element; }; diff --git a/core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.js b/core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.js old mode 100644 new mode 100755 index d1d666c..c6105f9 --- a/core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.js +++ b/core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.js @@ -58,8 +58,7 @@ requiredContent.attributes['data-align'] = ''; requiredContent.attributes['data-caption'] = ''; widgetDefinition.requiredContent = new CKEDITOR.style(requiredContent); - widgetDefinition.allowedContent.img.attributes['!data-align'] = true; - widgetDefinition.allowedContent.img.attributes['!data-caption'] = true; + widgetDefinition.allowedContent.img.attributes += ',!data-align,!data-caption'; // Override allowedContent setting for the 'caption' nested editable. // This must match what caption_filter enforces. @@ -72,7 +71,10 @@ // data-caption attributes. var originalDowncast = widgetDefinition.downcast; widgetDefinition.downcast = function (element) { - var img = findElementByName(element, 'img'); + var img = originalDowncast.call(this, element); + if (!img) { + img = findElementByName(element, 'img'); + } originalDowncast.call(this, img); var caption = this.editables.caption; diff --git a/core/modules/ckeditor/js/plugins/drupallink/plugin.js b/core/modules/ckeditor/js/plugins/drupallink/plugin.js old mode 100644 new mode 100755 diff --git a/core/modules/image/css/image.admin.css b/core/modules/image/css/image.admin.css old mode 100644 new mode 100755 index 9f9878a..1acb185 --- a/core/modules/image/css/image.admin.css +++ b/core/modules/image/css/image.admin.css @@ -16,6 +16,7 @@ .image-style-preview .preview-image { margin: auto; position: relative; + display: block; } .image-style-preview .preview-image .width { border: 1px solid #666; diff --git a/core/modules/image/image.module b/core/modules/image/image.module old mode 100644 new mode 100755 index 7f8314a..baa0817 --- a/core/modules/image/image.module +++ b/core/modules/image/image.module @@ -4,14 +4,17 @@ * @file * Exposes global functionality for creating image styles. */ - +use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\Core\Form\FormStateInterface; use Drupal\file\Entity\File; use Drupal\field\FieldStorageConfigInterface; use Drupal\field\FieldConfigInterface; use Drupal\image\Entity\ImageStyle; + + /** * Image style constant for user presets in the database. * @@ -483,3 +486,106 @@ function image_field_config_delete(FieldConfigInterface $field) { \Drupal::service('file.usage')->delete($file, 'image', 'default_image', $field->uuid()); } } + + +/** + * Implements hook_form_FORM_ID_alter() for EditorImageDialog. + * + * Alters the image dialog form for text editor, to allow the user to select an + * image style. + * + * @see \Drupal\editor\Form\EditorImageDialog::buildForm() + */ +function image_form_editor_image_dialog_alter(&$form, FormStateInterface $form_state) { + + $filter_format = $form_state->getBuildInfo()['args'][0]; + $filters = $filter_format->filters()->getAll(); + + $image_element = $form_state->getStorage()['image_element']; + + // When image style functionality is available, disallow the user from + // specifying the dimensions manually, only allow image styles to be picked. + if (isset($filters['filter_imagestyle']) && $filters['filter_imagestyle']->status) { + // Hide the default width/height form items. + $form['dimensions']['#access'] = FALSE; + + $image_options = image_style_options(FALSE); + $image_options_keys = array_keys($image_options); + $form['image_style'] = array( + '#type' => 'item', + '#field_prefix' => '
', + '#field_suffix' => '
', + ); + $form['image_style']['selection'] = array( + '#title' => t('Image style'), + '#type' => 'select', + '#default_value' => isset($image_element['data-image-style']) ? $image_element['data-image-style'] : $image_options_keys[0], + '#options' => $image_options, + '#required' => TRUE, + '#wrapper_attributes' => array('class' => array('container-inline')), + '#attributes' => array('class' => array('container-inline')), + '#parents' => array('attributes', 'data-image-style'), + ); + $form['image_style']['preview_toggle'] = array( + '#type' => 'checkbox', + '#title' => t('Show preview'), + ); + $image_styles = entity_load_multiple('image_style'); + foreach ($image_styles as $id => $image_style) { + $preview_arguments = array( + '#theme' => 'image_style_preview', + '#style' => $image_style, + ); + $form['image_style']['preview_' . $id] = array( + '#type' => 'fieldset', + '#title' => t('Preview of %image-style image style', array('%image-style' => $image_style->label())), + '#markup' => drupal_render($preview_arguments), + '#states' => array( + 'visible' => array( + ':input[name="image_style[preview_toggle]"]' => array('checked' => TRUE), + ':input[name="attributes[data-image-style]"]' => array('value' => $id), + ), + ), + ); + } + $form['#attached']['css'][drupal_get_path('module', 'image') . '/css/image.admin.css'] = array(); + + $form['actions']['save_modal']['#validate'][] = 'image_form_editor_image_dialog_validate'; + } +} + +/** + * Form validation handler for EditorImageDialog. + * + * Ensures the image shown in the text editor matches the chosen image style. + * + * @see \Drupal\editor\Form\EditorImageDialog::buildForm() + * @see \Drupal\editor\Form\EditorImageDialog::validateForm() + * @see image_form_editor_image_dialog_alter() + */ +function image_form_editor_image_dialog_validate(array &$form, FormStateInterface &$form_state) { + $attributes = $form_state->getValue('attributes'); + if (!empty($form_state->getValue('fid')[0])) { + $image_style = entity_load('image_style', $attributes['data-image-style']); + $file = file_load($form_state->getValue('fid')[0]); + $uri = $file->getFileUri(); + + // Set the 'src' attribute to the image style URL. FilterImageStyle will + // look at the 'data-editor-file-uuid' attribute, not the 'src' attribute to + // render the appropriate output. + $attributes['src'] = $image_style->buildUrl($uri); + + // Set the 'width' and 'height' attributes to the image style's transformed + // dimensions. + $image = \Drupal::service('image.factory')->get($uri); + if ($image->isValid()) { + $dimensions = array( + 'width' => $image->getWidth(), + 'height' => $image->getHeight() + ); + $image_style->transformDimensions($dimensions, $attributes['src']); + $attributes['width'] = $dimensions['width']; + $attributes['height'] = $dimensions['height']; + } + } +} \ No newline at end of file diff --git a/core/modules/responsive_image/responsive_image.module b/core/modules/responsive_image/responsive_image.module old mode 100644 new mode 100755 index 7df1da8..20e1919 --- a/core/modules/responsive_image/responsive_image.module +++ b/core/modules/responsive_image/responsive_image.module @@ -11,6 +11,8 @@ use Drupal\responsive_image\Entity\ResponsiveImageStyle; use Drupal\Core\Image\ImageInterface; use Drupal\breakpoint\BreakpointInterface; +use Drupal\Core\Form\FormStateInterface; +use Drupal\file\Entity\File; /** * The machine name for the empty image breakpoint image style option. @@ -510,3 +512,172 @@ function responsive_image_library_info_alter(array &$libraries, $module) { $libraries['drupal.ajax']['dependencies'][] = 'responsive_image/ajax'; } } + + +/** + * Implements hook_form_FORM_ID_alter() for EditorImageDialog. + * + * Alters the image dialog form for text editor, to allow the user to select a + * responsive image style. + * + * @see \Drupal\editor\Form\EditorImageDialog::buildForm() + */ +function responsive_image_form_editor_image_dialog_alter(&$form, FormStateInterface $form_state) { + + $filter_format = $form_state->getBuildInfo()['args'][0]; + $filters = $filter_format->filters()->getAll(); + + $image_element = $form_state->getStorage()['image_element']; + + // When responsive image functionality is available, disallow the user from + // specifying the dimensions manually, and from selecting an image style, only + // allowing a responsive image style to be selected. + if (isset($filters['filter_responsive_image_style']) && $filters['filter_responsive_image_style']->status) { + + // Hide the default width/height form items. + $form['dimensions']['#access'] = FALSE; + + // Remove the image style selection, if it exists; it does not make sense to + // use FilterImageStyle when already using FilterPictureMapping! + if (isset($form['image_style'])) { + unset($form['image_style']); + // Remove its #validate callback as well. + $validators = &$form['actions']['save_modal']['#validate']; + $index = array_search('image_form_editor_image_dialog_validate', $validators); + if ($index !== FALSE) { + unset($validators[$index]); + } + } + + $form['responsive_image_style'] = array( + '#type' => 'item', + ); + $responsive_image_options = array(); + $responsive_image_styles = entity_load_multiple('responsive_image_style'); + if ($responsive_image_styles && !empty($responsive_image_styles)) { + foreach ($responsive_image_styles as $responsive_image_style_id => $responsive_image_style) { + if ($responsive_image_style->hasImageStyleMappings()) { + $responsive_image_options[$responsive_image_style_id] = $responsive_image_style->label(); + } + } + } + + $form['responsive_image_style']['selection'] = array( + '#title' => t('Responsive image style'), + '#type' => 'select', + '#default_value' => isset($image_element['data-responsive-image-style']) ? $image_element['data-responsive-image-style'] : key($responsive_image_options), + '#options' => $responsive_image_options, + '#required' => TRUE, + '#wrapper_attributes' => array('class' => array('container-inline')), + '#attributes' => array('class' => array('container-inline')), + '#parents' => array('attributes', 'data-responsive-image-style'), + ); + $form['responsive_image_style']['preview_toggle'] = array( + '#type' => 'checkbox', + '#title' => t('Show preview'), + ); + foreach ($responsive_image_styles as $responsive_image_style_id => $responsive_image_style) { + if ($responsive_image_style->hasImageStyleMappings()) { + $form['responsive_image_style']['preview_' . $responsive_image_style_id] = array( + '#type' => 'fieldset', + '#title' => t('Preview of %responsive-image-style responsive image style', array('%responsive-image-style' => $responsive_image_style->label())), + '#states' => array( + 'visible' => array( + ':input[name="responsive_image_style[preview_toggle]"]' => array('checked' => TRUE), + ':input[name="attributes[data-responsive-image-style]"]' => array('value' => $responsive_image_style_id), + ), + ), + ); + + $preview_arguments = array( + '#theme' => 'responsive_image', + '#uri' => \Drupal::config('image.settings')->get('preview_image'), + '#responsive_image_style_id' => $responsive_image_style_id, + ); + $form['responsive_image_style']['preview_' . $responsive_image_style_id] = array( + '#type' => 'item', + '#markup' => drupal_render($preview_arguments), + '#states' => array( + 'visible' => array( + ':input[name="responsive_image_style[preview_toggle]"]' => array('checked' => TRUE), + ':input[name="attributes[data-responsive-image-style]"]' => array('value' => $responsive_image_style_id), + ), + ), + ); + } + } + + $form['actions']['save_modal']['#validate'][] = 'responsive_image_form_editor_image_dialog_validate'; + } +} + +/** + * Form validation handler for EditorImageDialog. + * + * Ensures the image shown in the text editor matches the chosen picture mapping + * at the smallest breakpoint. + * + * @see \Drupal\editor\Form\EditorImageDialog::buildForm() + * @see \Drupal\editor\Form\EditorImageDialog::validateForm() + * @see picture_form_editor_image_dialog_alter() + */ +function responsive_image_form_editor_image_dialog_validate(array &$form, FormStateInterface $form_state) { + $attributes = &$form_state->getValue('attributes'); + if (!empty($form_state->getValue('fid')[0])) { + $responsive_image_style = entity_load('responsive_image_style', $attributes['data-responsive-image-style']); + $file = File::load($form_state->getValue('fid')[0]); + $uri = $file->getFileUri(); + // Set up original file information. + $image = \Drupal::service('image.factory')->get($uri); + if ($image->isValid()) { + $dimensions = [ + 'width' => $image->getWidth(), + 'height' => $image->getHeight(), + ]; + } + else { + // @todo: what if the image is not valid? + $dimensions = [ + 'width' => 1000, + 'height' => 1000, + ]; + } + + // Select the first (i.e. smallest) breakpoint and the 1x multiplier. We + // choose to show the image in the editor as if it were being viewed in the + // narrowest viewport, so that when the user starts to edit this content + // again on a mobile device, it will work fine. + $breakpoint_machine_names = array_keys($responsive_image_style->getKeyedImageStyleMappings()); + $image_style_mapping = $responsive_image_style->getKeyedImageStyleMappings()[$breakpoint_machine_names[0]]; + switch ($image_style_mapping['image_mapping_type']) { + case 'sizes': + // More than one image style can be mapped. Use the smallest one. + $transformed_dimensions = $dimensions; + foreach ($image_style_mapping['image_mapping']['sizes_image_styles'] as $mapped_image_style) { + $new_dimensions = responsive_image_get_image_dimensions($mapped_image_style, $dimensions, $uri); + if (!$transformed_dimensions || $transformed_dimensions['width'] >= $new_dimensions['width']) { + $image_style_name = $mapped_image_style; + $transformed_dimensions = $new_dimensions; + } + } + break; + + case 'image_style': + $image_style_name = $image_style_mapping['image_mapping']; + $transformed_dimensions = responsive_image_get_image_dimensions($image_style_name, $dimensions, $uri); + break; + } + + // Set the 'src' attribute to the image style URL. FilterImageStyle will + // look at the 'data-editor-file-uuid' attribute, not the 'src' attribute to + // render the appropriate output. + $attributes['src'] = _responsive_image_image_style_url($image_style_name, $uri); + + // Set the 'width' and 'height' attributes to the image style's transformed + // dimensions. + if ($image->isValid()) { + $attributes['width'] = $transformed_dimensions['width']; + $attributes['height'] = $transformed_dimensions['height']; + } + } +} \ No newline at end of file diff --git a/core/modules/system/css/components/container-inline.module.css b/core/modules/system/css/components/container-inline.module.css old mode 100644 new mode 100755 index b68da65..8083ff0 --- a/core/modules/system/css/components/container-inline.module.css +++ b/core/modules/system/css/components/container-inline.module.css @@ -11,3 +11,7 @@ .container-inline .details-wrapper { display: block; } +/* Allow items inside inline items to render themselves as blocks. */ +.container-inline .container-block { + display: block; +} \ No newline at end of file diff --git a/core/modules/system/system.install b/core/modules/system/system.install old mode 100644 new mode 100755 index 44212b1..e5e8ee7 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -1644,5 +1644,27 @@ function system_update_8014() { } /** + * Add allowed attributes to existing html filters. + */ +function system_update_8012() { + $config_factory = \Drupal::configFactory(); + foreach ($config_factory->listAll('filter.format') as $name) { + $config = $config_factory->getEditable($name); + if (!$config->get('filters.filter_imagestyle.status')) { + continue; + } + $allowed_html = $config->get('filters.filter_html.settings.allowed_html'); + $matches = []; + if (!empty($allowed_html) && preg_match('/]*)>/', $allowed_html, $matches)) { + $new_attributes = array_filter(explode(' ', $matches[1])); + $new_attributes[] = 'data-image-style'; + $allowed_html = preg_replace('/]*)>/', '', $allowed_html); + $config->set('filters.filter_html.settings.allowed_html', $allowed_html); + $config->save(); + } + } +} + +/** * @} End of "addtogroup updates-8.0.0-rc". */ diff --git a/core/profiles/standard/config/install/filter.format.basic_html.yml b/core/profiles/standard/config/install/filter.format.basic_html.yml old mode 100644 new mode 100755 index 92224c2..63d649a --- a/core/profiles/standard/config/install/filter.format.basic_html.yml +++ b/core/profiles/standard/config/install/filter.format.basic_html.yml @@ -15,7 +15,7 @@ filters: status: true weight: -10 settings: - allowed_html: '