diff --git a/core/modules/ckeditor/js/plugins/drupalimage/plugin.js b/core/modules/ckeditor/js/plugins/drupalimage/plugin.js index f752f81fa4cf6fd7be97e09ba5435338505f63cc..51a0bc5ea2d78ebcc3c2680e3bd81df28e37f48b 100644 --- a/core/modules/ckeditor/js/plugins/drupalimage/plugin.js +++ b/core/modules/ckeditor/js/plugins/drupalimage/plugin.js @@ -3,8 +3,8 @@ * Drupal Image plugin. * * This alters the existing CKEditor image2 widget plugin to: - * - require a data-editor-file-uuid attribute (which Drupal uses to track where - * images are being used) + * - require a data-entity-type and a data-entity-uuid attribute (which Drupal + * uses to track where images are being used) * - use a Drupal-native dialog (that is in fact just an alterable Drupal form * like any other) instead of CKEditor's own dialogs. * @see \Drupal\editor\Form\EditorImageDialog @@ -18,7 +18,7 @@ beforeInit: function (editor) { // Override the image2 widget definition to require and handle the - // additional data-editor-file-uuid attribute. + // additional data-entity-type and data-entity-uuid attributes. editor.on('widgetDefinition', function (event) { var widgetDefinition = event.data; if (widgetDefinition.name !== 'image') { @@ -26,8 +26,8 @@ } // Override requiredContent & allowedContent. - widgetDefinition.requiredContent = 'img[alt,src,width,height,data-editor-file-uuid]'; - widgetDefinition.allowedContent.img.attributes += ',!data-editor-file-uuid'; + widgetDefinition.requiredContent = 'img[alt,src,width,height,data-entity-type,data-entity-uuid]'; + widgetDefinition.allowedContent.img.attributes += ',!data-entity-type,!data-entity-uuid'; // We don't allow
,
,
or

in our downcast. delete widgetDefinition.allowedContent.figure; delete widgetDefinition.allowedContent.figcaption; @@ -40,14 +40,14 @@ // Override downcast(): since we only accept in our upcast method, // the element is already correct. We only need to update the element's - // data-editor-file-uuid attribute. + // data-entity-uuid attribute. widgetDefinition.downcast = function (element) { - element.attributes['data-editor-file-uuid'] = this.data['data-editor-file-uuid']; + element.attributes['data-entity-uuid'] = this.data['data-entity-uuid']; }; // We want to upcast elements to a DOM structure required by the // image2 widget; we only accept an tag, and that tag MAY - // have a data-editor-file-uuid attribute. + // have a data-entity-type and a data-entity-uuid attribute. widgetDefinition.upcast = function (element, data) { if (element.name !== 'img') { return; @@ -57,8 +57,10 @@ return; } - // Parse the data-editor-file-uuid attribute. - data['data-editor-file-uuid'] = element.attributes['data-editor-file-uuid']; + // Parse the data-entity-type attribute. + 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; }; @@ -71,7 +73,8 @@ 'alt': 'alt', 'width': 'width', 'height': 'height', - 'data-editor-file-uuid': 'data-editor-file-uuid' + 'data-entity-type': 'data-entity-type', + 'data-entity-uuid': 'data-entity-uuid' }; // Protected; transforms widget's data object to the format used by the @@ -175,8 +178,8 @@ // Register the "editdrupalimage" command, which essentially just replaces // the "image" command's CKEditor dialog with a Drupal-native dialog. editor.addCommand('editdrupalimage', { - allowedContent: 'img[alt,!src,width,height,!data-editor-file-uuid]', - requiredContent: 'img[alt,src,width,height,data-editor-file-uuid]', + allowedContent: 'img[alt,!src,width,height,!data-entity-type,!data-entity-uuid]', + requiredContent: 'img[alt,src,width,height,data-entity-type,data-entity-uuid]', modes: { wysiwyg: 1 }, canUndo: true, exec: function (editor, data) { diff --git a/core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.js b/core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.js index b49fa001bf4437d33429f4aebefdf5ed8495e9a5..50a4a4d072d3272e6b8c0088e70ba20188c95c97 100644 --- a/core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.js +++ b/core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.js @@ -48,7 +48,7 @@ }, true); // Override requiredContent & allowedContent. - widgetDefinition.requiredContent = 'img[alt,src,width,height,data-editor-file-uuid,data-align,data-caption]'; + widgetDefinition.requiredContent = 'img[alt,src,width,height,data-entity-type,data-entity-uuid,data-align,data-caption]'; widgetDefinition.allowedContent.img.attributes += ',data-align,data-caption'; // Override allowedContent setting for the 'caption' nested editable. @@ -58,8 +58,8 @@ widgetDefinition.editables.caption.allowedContent = 'a[!href]; em strong cite code br'; // Override downcast(): ensure we *only* output , but also ensure - // we include the data-editor-file-uuid, data-align and data-caption - // attributes. + // we include the data-entity-type, data-entity-uuid, data-align and + // data-caption attributes. widgetDefinition.downcast = function (element) { // Find an image element in the one being downcasted (can be itself). var img = findElementByName(element, 'img'); @@ -79,7 +79,8 @@ attrs['data-align'] = this.data.align; } } - attrs['data-editor-file-uuid'] = this.data['data-editor-file-uuid']; + attrs['data-entity-type'] = this.data['data-entity-type']; + attrs['data-entity-uuid'] = this.data['data-entity-uuid']; return img; }; @@ -91,7 +92,7 @@ // -

tag (captioned image). // We take the same attributes into account as downcast() does. widgetDefinition.upcast = function (element, data) { - if (element.name !== 'img' || !element.attributes['data-editor-file-uuid']) { + if (element.name !== 'img' || !element.attributes['data-entity-type'] || !element.attributes['data-entity-uuid']) { return; } // Don't initialize on pasted fake objects. @@ -112,8 +113,10 @@ data.align = attrs['data-align']; delete attrs['data-align']; } - data['data-editor-file-uuid' ] = attrs['data-editor-file-uuid']; - delete attrs['data-editor-file-uuid']; + data['data-entity-type' ] = attrs['data-entity-type']; + delete attrs['data-entity-type']; + data['data-entity-uuid' ] = attrs['data-entity-uuid']; + delete attrs['data-entity-uuid']; if (captionFilterEnabled) { // Unwrap from

wrapper created by HTML parser for a captioned diff --git a/core/modules/editor/editor.module b/core/modules/editor/editor.module index cc1a23883a4ae5b9c0d19e2f76270f554acb3dc5..0c33fd27161ca9e22b5e2be1c6e66d7838aa07a7 100644 --- a/core/modules/editor/editor.module +++ b/core/modules/editor/editor.module @@ -441,7 +441,7 @@ function _editor_delete_file_usage(array $uuids, EntityInterface $entity, $count } /** - * Finds all files referenced (data-editor-file-uuid) by formatted text fields. + * Finds all files referenced (data-entity-uuid) by formatted text fields. * * @param EntityInterface $entity * An entity whose fields to analyze. @@ -482,7 +482,7 @@ function _editor_get_formatted_text_fields(FieldableEntityInterface $entity) { } /** - * Parse an HTML snippet for any data-editor-file-uuid attributes. + * Parse an HTML snippet for any linked file with data-entity-uuid attributes. * * @param string $text * The partial (X)HTML snippet to load. Invalid markup will be corrected on @@ -495,8 +495,8 @@ function _editor_parse_file_uuids($text) { $dom = Html::load($text); $xpath = new \DOMXPath($dom); $uuids = array(); - foreach ($xpath->query('//*[@data-editor-file-uuid]') as $node) { - $uuids[] = $node->getAttribute('data-editor-file-uuid'); + foreach ($xpath->query('//*[@data-entity-type="file" and @data-entity-uuid]') as $node) { + $uuids[] = $node->getAttribute('data-entity-uuid'); } return $uuids; } diff --git a/core/modules/editor/src/Form/EditorImageDialog.php b/core/modules/editor/src/Form/EditorImageDialog.php index 34eed26f42ecbfca3a69957129f147e6c3967960..d124ab117a2f813efc116e216369692fab27ba53 100644 --- a/core/modules/editor/src/Form/EditorImageDialog.php +++ b/core/modules/editor/src/Form/EditorImageDialog.php @@ -60,7 +60,7 @@ public function buildForm(array $form, FormStateInterface $form_state, FilterFor } $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; + $existing_file = isset($image_element['data-entity-uuid']) ? entity_load_by_uuid('file', $image_element['data-entity-uuid']) : NULL; $fid = $existing_file ? $existing_file->id() : NULL; $form['fid'] = array( @@ -204,8 +204,8 @@ public function buildForm(array $form, FormStateInterface $form_state, FilterFor public function submitForm(array &$form, FormStateInterface $form_state) { $response = new AjaxResponse(); - // Convert any uploaded files from the FID values to data-editor-file-uuid - // attributes. + // 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 = file_load($fid); @@ -214,7 +214,8 @@ public function submitForm(array &$form, FormStateInterface $form_state) { // 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-editor-file-uuid'), $file->uuid()); + $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 diff --git a/core/modules/editor/src/Plugin/Filter/EditorFileReference.php b/core/modules/editor/src/Plugin/Filter/EditorFileReference.php index 5315b78c4cd72ac07a5b8a22c5162d88472e18c5..41161abc3d218cf08a54fb75f6be7e137cefd3ba 100644 --- a/core/modules/editor/src/Plugin/Filter/EditorFileReference.php +++ b/core/modules/editor/src/Plugin/Filter/EditorFileReference.php @@ -70,12 +70,12 @@ static public function create(ContainerInterface $container, array $configuratio public function process($text, $langcode) { $result = new FilterProcessResult($text); - if (stristr($text, 'data-editor-file-uuid') !== FALSE) { + if (stristr($text, 'data-entity-type="file"') !== FALSE) { $dom = Html::load($text); $xpath = new \DOMXPath($dom); $processed_uuids = array(); - foreach ($xpath->query('//*[@data-editor-file-uuid]') as $node) { - $uuid = $node->getAttribute('data-editor-file-uuid'); + foreach ($xpath->query('//*[@data-entity-type="file" and @data-entity-uuid]') as $node) { + $uuid = $node->getAttribute('data-entity-uuid'); // Only process the first occurrence of each file UUID. if (!isset($processed_uuids[$uuid])) { $processed_uuids[$uuid] = TRUE; diff --git a/core/modules/editor/src/Tests/EditorFileReferenceFilterTest.php b/core/modules/editor/src/Tests/EditorFileReferenceFilterTest.php index bda9b2ef9370df6521e6681e1c8e00229737a169..87809ef512cba1382ac2cf8bf3041663ec40a1fc 100644 --- a/core/modules/editor/src/Tests/EditorFileReferenceFilterTest.php +++ b/core/modules/editor/src/Tests/EditorFileReferenceFilterTest.php @@ -68,45 +68,50 @@ function testEditorFileReferenceFilter() { $uuid_2 = $image_2->uuid(); $cache_tag_2 = ['file:' . $id_2]; - $this->pass('No data-editor-file-uuid attribute.'); + $this->pass('No data-entity-type and no data-entity-uuid attribute.'); $input = ''; $output = $test($input); $this->assertIdentical($input, $output->getProcessedText()); - $this->pass('One data-editor-file-uuid attribute.'); - $input = ''; + $this->pass('A non-file data-entity-type attribute value.'); + $input = ''; + $output = $test($input); + $this->assertIdentical($input, $output->getProcessedText()); + + $this->pass('One data-entity-uuid attribute.'); + $input = ''; $output = $test($input); $this->assertIdentical($input, $output->getProcessedText()); $this->assertEqual($cache_tag, $output->getCacheTags()); - $this->pass('One data-editor-file-uuid attribute with odd capitalization.'); - $input = ''; + $this->pass('One data-entity-uuid attribute with odd capitalization.'); + $input = ''; $output = $test($input); $this->assertIdentical($input, $output->getProcessedText()); $this->assertEqual($cache_tag, $output->getCacheTags()); - $this->pass('One data-editor-file-uuid attribute on a non-image tag.'); - $input = '

Hello, world!

'; - // Test handling of an invalid data- attribute. - $body_value .= ''; + $body_value = '

Hello, world!

'; + // Test handling of an invalid data-entity-uuid attribute. + $body_value .= ''; + // Test handling of an invalid data-entity-type attribute. + $body_value .= ''; // Test handling of a non-existing UUID. - $body_value .= ''; + $body_value .= ''; // Test editor_entity_insert(): increment. $this->createUser(); $node = entity_create('node', array( @@ -90,16 +92,31 @@ public function testEditorEntityHooks() { $this->assertIdentical(array('editor' => array('node' => array(1 => '3'))), $file_usage->listUsage($image), 'The image has 3 usages.'); // Test hook_entity_update(): decrement, by modifying the last revision: - // remove the data- attribute from the body field. + // remove the data-entity-type attribute from the body field. $body = $node->get('body')->first()->get('value'); $original_value = $body->getValue(); - $new_value = str_replace('data-editor-file-uuid', 'data-editor-file-uuid-modified', $original_value); + $new_value = str_replace('data-entity-type', 'data-entity-type-modified', $original_value); + $body->setValue($new_value); + $node->save(); + $this->assertIdentical(array('editor' => array('node' => array(1 => '2'))), $file_usage->listUsage($image), 'The image has 2 usages.'); + + // Test editor_entity_update(): increment again by creating a new revision: + // read the data- attributes to the body field. + $node->setNewRevision(TRUE); + $node->get('body')->first()->get('value')->setValue($original_value); + $node->save(); + $this->assertIdentical(array('editor' => array('node' => array(1 => '3'))), $file_usage->listUsage($image), 'The image has 3 usages.'); + + // Test hook_entity_update(): decrement, by modifying the last revision: + // remove the data-entity-uuid attribute from the body field. + $body = $node->get('body')->first()->get('value'); + $new_value = str_replace('data-entity-uuid', 'data-entity-uuid-modified', $original_value); $body->setValue($new_value); $node->save(); $this->assertIdentical(array('editor' => array('node' => array(1 => '2'))), $file_usage->listUsage($image), 'The image has 2 usages.'); // Test hook_entity_update(): increment, by modifying the last revision: - // readd the data- attribute to the body field. + // read the data- attributes to the body field. $node->get('body')->first()->get('value')->setValue($original_value); $node->save(); $this->assertIdentical(array('editor' => array('node' => array(1 => '3'))), $file_usage->listUsage($image), 'The image has 3 usages.');