core/includes/entity.api.php | 12 ++ core/modules/ckeditor/ckeditor.module | 2 - .../ckeditor/js/ckeditor.drupalimage.admin.js | 9 +- .../ckeditor/js/plugins/drupalimage/plugin.js | 6 - .../ckeditor/Plugin/CKEditorPlugin/DrupalImage.php | 112 +++--------- .../modules/editor/config/schema/editor.schema.yml | 26 +++ core/modules/editor/editor.admin.inc | 131 ++++++++++++++ core/modules/editor/editor.module | 188 +++++++++++++++++++- .../lib/Drupal/editor/Form/EditorImageDialog.php | 25 ++- .../Drupal/editor/Plugin/Core/Entity/Editor.php | 9 +- .../text/Plugin/field/widget/TextareaWidget.php | 3 - .../modules/text/lib/Drupal/text/TextProcessed.php | 41 +---- .../lib/Drupal/views/Plugin/views/area/Text.php | 2 +- .../Plugin/views/exposed_form/InputRequired.php | 2 +- .../standard/config/editor.editor.basic_html.yml | 8 + .../standard/config/editor.editor.full_html.yml | 8 + 16 files changed, 413 insertions(+), 171 deletions(-) diff --git a/core/includes/entity.api.php b/core/includes/entity.api.php index 8b97b74..6018c2e 100644 --- a/core/includes/entity.api.php +++ b/core/includes/entity.api.php @@ -315,6 +315,18 @@ function hook_entity_delete(Drupal\Core\Entity\EntityInterface $entity) { } /** + * Respond to entity revision deletion. + * + * This hook runs after the entity type-specific revision delete hook. + * + * @param Drupal\Core\Entity\EntityInterface $entity + * The entity object for the entity revision that has been deleted. + */ +function hook_entity_revision_delete(Drupal\Core\Entity\EntityInterface $entity) { + // @todo: code example +} + +/** * Alter or execute an Drupal\Core\Entity\Query\EntityQueryInterface. * * @param \Drupal\Core\Entity\Query\QueryInterface $query diff --git a/core/modules/ckeditor/ckeditor.module b/core/modules/ckeditor/ckeditor.module index c03facb..8b587c7 100644 --- a/core/modules/ckeditor/ckeditor.module +++ b/core/modules/ckeditor/ckeditor.module @@ -81,8 +81,6 @@ function ckeditor_library_info() { array('system', 'jquery.once'), array('system', 'drupal.vertical-tabs'), array('system', 'drupalSettings'), - // @todo D8 formUpdated event should be debounced already. - array('system', 'drupal.debounce'), ), ); $libraries['ckeditor'] = array( diff --git a/core/modules/ckeditor/js/ckeditor.drupalimage.admin.js b/core/modules/ckeditor/js/ckeditor.drupalimage.admin.js index 01d01c7..da0d7e8 100644 --- a/core/modules/ckeditor/js/ckeditor.drupalimage.admin.js +++ b/core/modules/ckeditor/js/ckeditor.drupalimage.admin.js @@ -38,10 +38,11 @@ Drupal.behaviors.ckeditorDrupalImageSettings = { Drupal.behaviors.ckeditorDrupalImageSettingsSummary = { attach: function () { $('#edit-editor-settings-plugins-drupalimage').drupalSetSummary(function (context) { - var $maxFileSize = $('input[name="editor[settings][plugins][drupalimage][max_size]"]'); - var $maxWidth = $('input[name="editor[settings][plugins][drupalimage][max_dimensions][width]"]'); - var $maxHeight = $('input[name="editor[settings][plugins][drupalimage][max_dimensions][height]"]'); - var $scheme = $('input[name="editor[settings][plugins][drupalimage][scheme]"]:checked'); + var root = 'input[name="editor[settings][plugins][drupalimage][image_upload]'; + var $maxFileSize = $(root + '[max_size]"]'); + var $maxWidth = $(root + '[max_dimensions][width]"]'); + var $maxHeight = $(root + '[max_dimensions][height]"]'); + var $scheme = $(root + '[scheme]"]:checked'); var maxFileSize = $maxFileSize.val() ? $maxFileSize.val() : $maxFileSize.attr('placeholder'); var maxDimensions = ($maxWidth.val() && $maxHeight.val()) ? '(' + $maxWidth.val() + 'x' + $maxHeight.val() + ')' : ''; diff --git a/core/modules/ckeditor/js/plugins/drupalimage/plugin.js b/core/modules/ckeditor/js/plugins/drupalimage/plugin.js index 5daf892..ecd6788 100644 --- a/core/modules/ckeditor/js/plugins/drupalimage/plugin.js +++ b/core/modules/ckeditor/js/plugins/drupalimage/plugin.js @@ -72,12 +72,6 @@ CKEDITOR.plugins.add('drupalimage', { dialogClass: 'editor-image-dialog' }; - // Add upload-image field based on the textarea's "data-image-uploads" - // attribute. - if (editor.element.$.attributes['data-editor-uploads']) { - existingValues['uploadsEnabled'] = 1; - } - // Open the dialog for the edit form. Drupal.ckeditor.openDialog(editor, Drupal.url('editor/dialog/image/' + editor.config.drupal.format), existingValues, saveCallback, dialogSettings); } diff --git a/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/CKEditorPlugin/DrupalImage.php b/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/CKEditorPlugin/DrupalImage.php index e3f73a7..db84e20 100644 --- a/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/CKEditorPlugin/DrupalImage.php +++ b/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/CKEditorPlugin/DrupalImage.php @@ -64,105 +64,33 @@ public function getButtons() { /** * {@inheritdoc} + * + * @see \Drupal\editor\Form\EditorImageDialog + * @see editor_image_upload_settings_form() */ public function settingsForm(array $form, array &$form_state, Editor $editor) { - // Defaults. - $editor->settings['image_upload'] = isset($editor->settings['image_upload']) ? $editor->settings['image_upload'] : array(); - $editor->settings['image_upload'] += array( - 'scheme' => file_default_scheme(), - 'directory' => 'inline-images', - 'max_size' => '', - 'max_dimensions' => array('width' => '', 'height' => ''), - ); - - // Validate all settings as a group. - $form['#element_validate'] = array( - array($this, 'validateImageUploadValues'), - ); - $form['#attached'] = array( - 'library' => array(array('ckeditor', 'drupal.ckeditor.drupalimage.admin')), - ); - - $default_max_size = format_size(file_upload_max_size()); - $form['max_size'] = array( - '#type' => 'textfield', - '#default_value' => $editor->settings['image_upload']['max_size'], - '#title' => t('Maximum file size'), - '#description' => t('If this is left empty, then the file size will be limited by the PHP maximum upload size of @size', array('@size' => $default_max_size)), - '#maxlength' => 20, - '#size' => 10, - '#placeholder' => $default_max_size, - ); - - $form['max_dimensions'] = array( - '#type' => 'item', - '#title' => t('Maximum dimensions'), - '#field_prefix' => '
', - '#field_suffix' => '
', - '#description' => t('Images larger than these dimensions will be scaled down.'), - ); - $form['max_dimensions']['width'] = array( - '#title' => t('Width'), - '#title_display' => 'invisible', - '#type' => 'number', - '#default_value' => $editor->settings['image_upload']['max_dimensions']['width'], - '#size' => 8, - '#maxlength' => 8, - '#min' => 1, - '#max' => 99999, - '#placeholder' => 'width', - '#field_suffix' => ' x ', - ); - $form['max_dimensions']['height'] = array( - '#title' => t('Height'), - '#title_display' => 'invisible', - '#type' => 'number', - '#default_value' => $editor->settings['image_upload']['max_dimensions']['height'], - '#size' => 8, - '#maxlength' => 8, - '#min' => 1, - '#max' => 99999, - '#placeholder' => 'height', - '#field_suffix' => 'pixels', - ); - - // Any visible, writable wrapper can potentially be used for uploads, - // including a remote file system that integrates with a CDN. - $stream_wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_WRITE_VISIBLE); - foreach ($stream_wrappers as $scheme => $info) { - $options[$scheme] = $info['description']; - } - - $config = config('system.file'); - if (!empty($options)) { - $form['scheme'] = array( - '#type' => 'radios', - '#title' => t('File storage scheme'), - '#default_value' => $editor->settings['image_upload']['scheme'], - '#options' => $options, - '#access' => count($options) > 1, - ); - } - - foreach ($stream_wrappers as $scheme => $info) { - $form['scheme'][$scheme]['#attributes']['data-label'] = t('Storage: @name', array('@name' => $info['name'])); - } - - $form['directory'] = array( - '#type' => 'textfield', - '#default_value' => $editor->settings['image_upload']['directory'], - '#title' => t('Upload directory'), - '#description' => t('A directory relative to Drupal\'s files directory where upload images will be stored.'), + form_load_include($form_state, 'inc', 'editor', 'editor.admin'); + $form['image_upload'] = editor_image_upload_settings_form($editor); + $form['image_upload']['#attached']['library'][] = array('ckeditor', 'drupal.ckeditor.drupalimage.admin'); + $form['image_upload']['#element_validate'] = array( + array($this, 'validateImageUploadSettings'), ); return $form; } - function validateImageUploadValues(array $element, array &$form_state) { - $settings = &$form_state['values']['editor']['settings']['plugins']['drupalimage']; - - // Save the settings at the editor level, not the plugin. - $form_state['values']['editor']['settings']['image_upload'] = $settings; + /** + * #element_validate handler for the "image_upload" element in settingsForm(). + * + * Moves the text editor's image upload settings from the DrupalImage plugin's + * own settings into $editor->image_upload. + * + * @see \Drupal\editor\Form\EditorImageDialog + * @see editor_image_upload_settings_form() + */ + function validateImageUploadSettings(array $element, array &$form_state) { + $settings = &$form_state['values']['editor']['settings']['plugins']['drupalimage']['image_upload']; + $form_state['editor']->image_upload = $settings; unset($form_state['values']['editor']['settings']['plugins']['drupalimage']); } diff --git a/core/modules/editor/config/schema/editor.schema.yml b/core/modules/editor/config/schema/editor.schema.yml index 6654b88..4e2c985 100644 --- a/core/modules/editor/config/schema/editor.schema.yml +++ b/core/modules/editor/config/schema/editor.schema.yml @@ -12,6 +12,32 @@ editor.editor.*: label: 'Text editor' settings: type: editor.settings.[%parent.editor] + image_upload: + type: mapping + label: 'Image upload settings' + mapping: + status: + type: boolean + label: 'Status' + scheme: + type: string + label: 'File storage' + directory: + type: string + label: 'Upload directory' + max_size: + type: string + label: 'Maximum file size' + max_dimensions: + type: mapping + label: 'Maximum dimensions' + mapping: + width: + type: integer + label: 'Maximum width' + height: + type: integer + label: 'Maximum height' status: type: boolean label: 'Status' diff --git a/core/modules/editor/editor.admin.inc b/core/modules/editor/editor.admin.inc new file mode 100644 index 0000000..329f686 --- /dev/null +++ b/core/modules/editor/editor.admin.inc @@ -0,0 +1,131 @@ +image_upload = isset($editor->image_upload) ? $editor->image_upload : array(); + $editor->image_upload += array( + 'status' => FALSE, + 'scheme' => file_default_scheme(), + 'directory' => 'inline-images', + 'max_size' => '', + 'max_dimensions' => array('width' => '', 'height' => ''), + ); + + $form['status'] = array( + '#type' => 'checkbox', + '#title' => t('Enable image uploads'), + '#default_value' => $editor->image_upload['status'], + '#attributes' => array( + 'data-editor-image-upload' => 'status', + ), + ); + $show_if_image_uploads_enabled = array( + 'visible' => array( + ':input[data-editor-image-upload="status"]' => array('checked' => TRUE), + ), + ); + + // Any visible, writable wrapper can potentially be used for uploads, + // including a remote file system that integrates with a CDN. + $stream_wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_WRITE_VISIBLE); + foreach ($stream_wrappers as $scheme => $info) { + $options[$scheme] = $info['description']; + } + if (!empty($options)) { + $form['scheme'] = array( + '#type' => 'radios', + '#title' => t('File storage'), + '#default_value' => $editor->image_upload['scheme'], + '#options' => $options, + '#states' => $show_if_image_uploads_enabled, + '#access' => count($options) > 1, + ); + } + // Set data- attributes with human-readable names for all possible stream + // wrappers, so that drupal.ckeditor.drupalimage.admin's summary rendering + // can use that. + foreach ($stream_wrappers as $scheme => $info) { + $form['scheme'][$scheme]['#attributes']['data-label'] = t('Storage: @name', array('@name' => $info['name'])); + } + + $form['directory'] = array( + '#type' => 'textfield', + '#default_value' => $editor->image_upload['directory'], + '#title' => t('Upload directory'), + '#description' => t('A directory relative to Drupal\'s files directory where uploaded images will be stored.'), + '#states' => $show_if_image_uploads_enabled, + ); + + $default_max_size = format_size(file_upload_max_size()); + $form['max_size'] = array( + '#type' => 'textfield', + '#default_value' => $editor->image_upload['max_size'], + '#title' => t('Maximum file size'), + '#description' => t('If this is left empty, then the file size will be limited by the PHP maximum upload size of @size.', array('@size' => $default_max_size)), + '#maxlength' => 20, + '#size' => 10, + '#placeholder' => $default_max_size, + '#states' => $show_if_image_uploads_enabled, + ); + + $form['max_dimensions'] = array( + '#type' => 'item', + '#title' => t('Maximum dimensions'), + '#field_prefix' => '
', + '#field_suffix' => '
', + '#description' => t('Images larger than these dimensions will be scaled down.'), + '#states' => $show_if_image_uploads_enabled, + ); + $form['max_dimensions']['width'] = array( + '#title' => t('Width'), + '#title_display' => 'invisible', + '#type' => 'number', + '#default_value' => $editor->image_upload['max_dimensions']['width'], + '#size' => 8, + '#maxlength' => 8, + '#min' => 1, + '#max' => 99999, + '#placeholder' => 'width', + '#field_suffix' => ' x ', + '#states' => $show_if_image_uploads_enabled, + ); + $form['max_dimensions']['height'] = array( + '#title' => t('Height'), + '#title_display' => 'invisible', + '#type' => 'number', + '#default_value' => $editor->image_upload['max_dimensions']['height'], + '#size' => 8, + '#maxlength' => 8, + '#min' => 1, + '#max' => 99999, + '#placeholder' => 'height', + '#field_suffix' => 'pixels', + '#states' => $show_if_image_uploads_enabled, + ); + + return $form; +} diff --git a/core/modules/editor/editor.module b/core/modules/editor/editor.module index eb97e0f..c8d5e33 100644 --- a/core/modules/editor/editor.module +++ b/core/modules/editor/editor.module @@ -8,7 +8,7 @@ use Drupal\file\Plugin\Core\Entity\File; use Drupal\editor\Plugin\Core\Entity\Editor; use Drupal\Component\Utility\NestedArray; -use Drupal\system\SystemConfigFormBase; +use Drupal\Core\Entity\EntityInterface; /** * Implements hook_help(). @@ -56,7 +56,6 @@ function editor_menu_alter(&$items) { */ function editor_element_info() { $type['text_format'] = array( - '#editor_uploads' => FALSE, '#pre_render' => array('editor_pre_render_format'), ); return $type; @@ -377,11 +376,6 @@ function editor_pre_render_format($element) { $element['format']['format']['#attributes']['data-editor-for'] = $field_id; } - // Set a data attribute if uploads are enabled. - if ($element['#editor_uploads']) { - $element['value']['#attributes']['data-editor-uploads'] = 'true'; - } - // Attach Text Editor module's (this module) library. $element['#attached']['library'][] = array('editor', 'drupal.editor'); @@ -391,3 +385,183 @@ function editor_pre_render_format($element) { return $element; } + +/** + * Implements hook_entity_insert(). + */ +function editor_entity_insert(EntityInterface $entity) { + $referenced_files_by_field = _editor_get_file_uuids_by_field($entity); + foreach ($referenced_files_by_field as $field => $uuids) { + _editor_record_file_usage($uuids, $entity); + } +} + +/** + * Implements hook_entity_update(). + */ +function editor_entity_update(EntityInterface $entity) { + // On new revisions, all files are considered to be a new usage and no + // deletion of previous file usages are necessary. + if (!empty($entity->original) && $entity->getRevisionId() != $entity->original->getRevisionId()) { + $referenced_files = _editor_get_file_uuids_by_field($entity); + _editor_record_file_usage($referenced_files, $entity); + } + // On modified revisions, detect which file references have been added (and + // record their usage) and which ones have been removed (delete their usage). + // File references that existed both in the previous version of the revision + // and in the new one don't need their usage to be updated. + else { + $original_uuids_by_field = _editor_get_file_uuids_by_field($entity->original); + $uuids_by_field = _editor_get_file_uuids_by_field($entity); + + // Detect file usages that should be incremented. + foreach ($uuids_by_field as $field => $uuids) { + $added_files = array_diff($uuids_by_field[$field], $original_uuids_by_field); + _editor_record_file_usage($added_files, $entity); + } + + // Detect file usages that should be decremented. + foreach ($original_uuids_by_field as $field => $uuids) { + $removed_files = array_diff($original_uuids_by_field[$field], $uuids_by_field); + _editor_delete_file_usage($removed_files, $entity, 1); + } + } +} + +/** + * Implements hook_entity_delete(). + */ +function editor_entity_delete(EntityInterface $entity) { + $referenced_files_by_field = _editor_get_file_uuids_by_field($entity); + foreach ($referenced_files_by_field as $field => $uuids) { + _editor_delete_file_usage($uuids, $entity, 0); + } +} + +/** + * Implements hook_entity_revision_delete(). + */ +function editor_entity_revision_delete(EntityInterface $entity) { + $referenced_files_by_field = _editor_get_file_uuids_by_field($entity); + foreach ($referenced_files_by_field as $field => $uuids) { + _editor_delete_file_usage($uuids, $entity, 1); + } +} + +/** + * Records file usage of files referenced by processed text fields. + * + * Every referenced file that does not yet have the FILE_STATUS_PERMANENT state, + * will be given that state. + * + * @param array $uuids + * An array of file entity UUIDs. + * @param EntityInterface $entity + * An entity whose fields to inspect for file references. + */ +function _editor_record_file_usage(array $uuids, EntityInterface $entity) { + foreach ($uuids as $uuid) { + $file = entity_load_by_uuid('file', $uuid); + if ($file->status !== FILE_STATUS_PERMANENT) { + $file->status = FILE_STATUS_PERMANENT; + $file->save(); + } + file_usage()->add($file, 'editor', $entity->entityType(), $entity->id()); + } +} + +/** + * Deletes file usage of files referenced by processed text fields. + * + * @param array $uuids + * An array of file entity UUIDs. + * @param EntityInterface $entity + * An entity whose fields to inspect for file references. + * @param $count + * The number of references to delete. Should be 1 when deleting a single + * revision and 0 when deleting an entity entirely. + * + * @see Drupal\file\FileUsage\FileUsageInterface::delete() + */ +function _editor_delete_file_usage(array $uuids, EntityInterface $entity, $count) { + foreach ($uuids as $uuid) { + $file = entity_load_by_uuid('file', $uuid); + file_usage()->delete($file, 'editor', $entity->entityType(), $entity->id(), $count); + } +} + +/** + * Finds all files referenced (data-editor-file-uuid) by processed text fields. + * + * @param EntityInterface $entity + * An entity whose fields to analyze. + * + * @return array + * An array of file entity UUIDs. + */ +function _editor_get_file_uuids_by_field(EntityInterface $entity) { + $uuids = array(); + + $processed_text_fields = _editor_get_processed_text_fields($entity); + foreach ($processed_text_fields as $processed_text_field) { + $text = $entity->get($processed_text_field)->value; + $uuids[$processed_text_field] = _editor_parse_file_uuids($text); + } + return $uuids; +} + +/** + * Determines the text fields on an entity that have text processing enabled. + * + * @param EntityInterface $entity + * An entity whose fields to analyze. + * + * @return array + * The names of the fields on this entity that have text processing enabled. + */ +function _editor_get_processed_text_fields(EntityInterface $entity) { + $text_field_types = array( + 'field_item:text', + 'field_item:text_long', + 'field_item:text_with_summary' + ); + + $properties = $entity->getPropertyDefinitions(); + if (empty($properties)) { + return array(); + } + + // Find all fields of one of the text field types. + $fields = array_keys(array_filter($properties, function ($definition) use ($text_field_types) { + return in_array($definition['type'], $text_field_types); + })); + if (empty($fields)) { + return array(); + } + + // Only return fields that have text processing enabled. + return array_filter($fields, function ($field) use ($entity) { + $instance = field_info_instance($entity->entityType(), $field, $entity->bundle()); + return $instance->getFieldSetting('text_processing') === '1'; + }); +} + +/** + * Parse an HTML snippet for any data-editor-file-uuid attributes. + * + * @param string $text + * The partial (X)HTML snippet to load. Invalid markup will be corrected on + * import. + * + * @return array + * An array of all found UUIDs. + */ +function _editor_parse_file_uuids($text) { + $dom = filter_dom_load($text); + $xpath = new \DOMXPath($dom); + $uuids = array(); + foreach ($xpath->query('//*[@data-editor-file-uuid]') as $node) { + $uuids[] = $node->getAttribute('data-editor-file-uuid'); + } + return $uuids; +} diff --git a/core/modules/editor/lib/Drupal/editor/Form/EditorImageDialog.php b/core/modules/editor/lib/Drupal/editor/Form/EditorImageDialog.php index 8d44118..7398207 100644 --- a/core/modules/editor/lib/Drupal/editor/Form/EditorImageDialog.php +++ b/core/modules/editor/lib/Drupal/editor/Form/EditorImageDialog.php @@ -47,21 +47,21 @@ public function buildForm(array $form, array &$form_state, FilterFormat $filter_ $editor = editor_load($filter_format->format); // Construct strings to use in the upload validators. - if (!empty($editor->settings['image_upload']['dimensions'])) { - $max_dimensions = $editor->settings['image_upload']['dimensions']['max_width'] . 'x' . $editor->settings['image_upload']['dimensions']['max_height']; + if (!empty($editor->image_upload['dimensions'])) { + $max_dimensions = $editor->image_upload['dimensions']['max_width'] . 'x' . $editor->image_upload['dimensions']['max_height']; } else { $max_dimensions = 0; } - $max_filesize = min(parse_size($editor->settings['image_upload']['max_size']), file_upload_max_size()); + $max_filesize = min(parse_size($editor->image_upload['max_size']), file_upload_max_size()); - $existing_file = isset($input['data-file-uuid']) ? entity_load_by_uuid('file', $input['data-file-uuid']) : NULL; + $existing_file = isset($input['data-editor-file-uuid']) ? entity_load_by_uuid('file', $input['data-editor-file-uuid']) : NULL; $fid = $existing_file ? $existing_file->id() : NULL; $form['fid'] = array( '#title' => t('Image'), '#type' => 'managed_file', - '#upload_location' => $editor->settings['image_upload']['scheme'] . '://' .$editor->settings['image_upload']['directory'], + '#upload_location' => $editor->image_upload['scheme'] . '://' .$editor->image_upload['directory'], '#default_value' => $fid ? array($fid) : NULL, '#upload_validators' => array( 'file_validate_extensions' => array('gif png jpg jpeg'), @@ -79,14 +79,10 @@ public function buildForm(array $form, array &$form_state, FilterFormat $filter_ '#required' => TRUE, ); - // If the editor has uploads enabled and the field was requested, show - // an upload field. Otherwise only a plain "src" field is shown. - $uploads_enabled = !empty($form_state['uploads_enabled']) || !empty($input['uploadsEnabled']); - if ($uploads_enabled && !empty($editor->settings['image_upload'])) { + // If the editor has image uploads enabled, show a managed_file form item, + // otherwise show a (file URL) text form item. + if ($editor->image_upload['status'] === '1') { $form['attributes']['src']['#access'] = FALSE; - // Set a flag in form state so the upload field stays accessible during - // the validation and submit handling. - $form_state['uploads_enabled'] = TRUE; } else { $form['fid']['#access'] = FALSE; @@ -160,13 +156,14 @@ public function validateForm(array &$form, array &$form_state) { public function submitForm(array &$form, array &$form_state) { $response = new AjaxResponse(); - // Convert any uploaded files from the FID values to data-uuid attributes. + // Convert any uploaded files from the FID values to data-editor-file-uuid + // attributes. if (!empty($form_state['values']['fid'][0])) { $file = file_load($form_state['values']['fid'][0]); $uri = $file->getFileUri(); $stream = file_stream_wrapper_get_instance_by_uri($uri); $form_state['values']['attributes']['src'] = str_replace($_SERVER['DOCUMENT_ROOT'], '', $stream->realpath()); - $form_state['values']['attributes']['data-file-uuid'] = $file->uuid(); + $form_state['values']['attributes']['data-editor-file-uuid'] = $file->uuid(); } if (form_get_errors()) { diff --git a/core/modules/editor/lib/Drupal/editor/Plugin/Core/Entity/Editor.php b/core/modules/editor/lib/Drupal/editor/Plugin/Core/Entity/Editor.php index 710b991..48e4a77 100644 --- a/core/modules/editor/lib/Drupal/editor/Plugin/Core/Entity/Editor.php +++ b/core/modules/editor/lib/Drupal/editor/Plugin/Core/Entity/Editor.php @@ -47,13 +47,20 @@ class Editor extends ConfigEntityBase implements EditorInterface { public $editor; /** - * The array of settings for the text editor. + * The array of text editor plugin-specific settings for the text editor. * * @var array */ public $settings = array(); /** + * The array of image upload settings for the text editor. + * + * @var array + */ + public $image_upload = array(); + + /** * Overrides Drupal\Core\Entity\Entity::id(). */ public function id() { diff --git a/core/modules/text/lib/Drupal/text/Plugin/field/widget/TextareaWidget.php b/core/modules/text/lib/Drupal/text/Plugin/field/widget/TextareaWidget.php index 6dd9330..298ce8d 100644 --- a/core/modules/text/lib/Drupal/text/Plugin/field/widget/TextareaWidget.php +++ b/core/modules/text/lib/Drupal/text/Plugin/field/widget/TextareaWidget.php @@ -81,9 +81,6 @@ public function formElement(FieldInterface $items, $delta, array $element, $lang $element['#type'] = 'text_format'; $element['#format'] = $items[$delta]->format; $element['#base_type'] = $main_widget['#type']; - if (module_exists('editor')) { - $element['#editor_uploads'] = TRUE; - } } else { $element['value'] = $main_widget; diff --git a/core/modules/text/lib/Drupal/text/TextProcessed.php b/core/modules/text/lib/Drupal/text/TextProcessed.php index 82a4c2d..352420d 100644 --- a/core/modules/text/lib/Drupal/text/TextProcessed.php +++ b/core/modules/text/lib/Drupal/text/TextProcessed.php @@ -82,50 +82,11 @@ public function getValue($langcode = NULL) { * Implements \Drupal\Core\TypedData\TypedDataInterface::setValue(). */ public function setValue($value, $notify = TRUE) { - - // @todo: We don't have enough context here to adequately determine if files - // have been removed from an current revision. Likewise we don't have the - // ability to decrement a usage when a revision is deleted. Switch to using - // hooks for hook_entity_insert/update/delete/revision_delete()? - if (isset($value) && module_exists('editor')) { - // Parse the value for any file usages and increment/decrement them as - // needed. - $field = $this->parent->getParent(); - $entity = $field->getParent(); - $instance = field_info_instance($entity->entityType(), $field->getName(), $entity->bundle()); - - $uuids = parseFileUuids($value); - $xpath = new \DOMXPath($dom); - foreach ($xpath->query('//*[@data-file-uuid]') as $node) { - $file_uuid = $node->getAttribute('data-file-uuid'); - $file = entity_load_by_uuid('file', $file_uuid); - if ($file->status !== FILE_STATUS_PERMANENT) { - $file->status = FILE_STATUS_PERMANENT; - $file->save(); - } - file_usage()->add($file, 'file', $entity->entityType(), $entity->id()); - } - + if (isset($value)) { // @todo This is triggered from DatabaseStorageController::invokeFieldMethod() // in the case of case of non-NG entity types. // throw new ReadOnlyException('Unable to set a computed property.'); } } - /** - * Parse text for any data-file-uuid attributes. - * - * @param string $value - * The string of data being saved in this field. - * @return array - * An array of all found UUIDs. - */ - protected function parseFileUuids($value) { - $dom = filter_dom_load($value); - $xpath = new \DOMXPath($dom); - $uuids = array(); - foreach ($xpath->query('//*[@data-file-uuid]') as $node) { - $uuids[] = $node->getAttribute('data-file-uuid'); - } - } } diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/area/Text.php b/core/modules/views/lib/Drupal/views/Plugin/views/area/Text.php index 645e10d..71124a2 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/area/Text.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/area/Text.php @@ -39,7 +39,7 @@ public function buildOptionsForm(&$form, &$form_state) { '#default_value' => $this->options['content'], '#rows' => 6, '#format' => isset($this->options['format']) ? $this->options['format'] : filter_default_format(), - '#wysiwyg' => FALSE, + '#editor' => FALSE, ); } diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/exposed_form/InputRequired.php b/core/modules/views/lib/Drupal/views/Plugin/views/exposed_form/InputRequired.php index 5a94674..ec35078 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/exposed_form/InputRequired.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/exposed_form/InputRequired.php @@ -41,7 +41,7 @@ public function buildOptionsForm(&$form, &$form_state) { '#description' => t('Text to display instead of results until the user selects and applies an exposed filter.'), '#default_value' => $this->options['text_input_required'], '#format' => isset($this->options['text_input_required_format']) ? $this->options['text_input_required_format'] : filter_default_format(), - '#wysiwyg' => FALSE, + '#editor' => FALSE, ); } diff --git a/core/profiles/standard/config/editor.editor.basic_html.yml b/core/profiles/standard/config/editor.editor.basic_html.yml index cf4a600..e340685 100644 --- a/core/profiles/standard/config/editor.editor.basic_html.yml +++ b/core/profiles/standard/config/editor.editor.basic_html.yml @@ -20,5 +20,13 @@ settings: plugins: stylescombo: styles: '' +image_upload: + status: '1' + scheme: public + directory: inline-images + max_size: '' + max_dimensions: + width: '' + height: '' status: '1' langcode: und diff --git a/core/profiles/standard/config/editor.editor.full_html.yml b/core/profiles/standard/config/editor.editor.full_html.yml index c0111f9..eb01c1c 100644 --- a/core/profiles/standard/config/editor.editor.full_html.yml +++ b/core/profiles/standard/config/editor.editor.full_html.yml @@ -30,5 +30,13 @@ settings: plugins: stylescombo: styles: '' +image_upload: + status: '1' + scheme: public + directory: inline-images + max_size: '' + max_dimensions: + width: '' + height: '' status: '1' langcode: und