diff -u b/core/misc/message.js b/core/misc/message.js --- b/core/misc/message.js +++ b/core/misc/message.js @@ -70,33 +70,28 @@ * * @name Drupal.message~messageDefinition.remove * - * @param {string|number} [messageIndex] + * @param {Number|String|Array.} [messages] * Index of the message to remove, as returned by - * {@link Drupal.message~messageDefinition.add} or a number - * corresponding to the CSS index of the element. + * {@link Drupal.message~messageDefinition.add}, a number + * corresponding to the CSS index of the element, or an + * array containing a combination of the previous two types. * * @return {number} * Number of removed messages. */ - function messageRemove(messageIndex) { - var removeSelector = '[data-drupal-message]'; + function messageRemove(messages) { + var messagesToRemove = messages instanceof Array ? messages : [messages]; + messagesToRemove.forEach(function (messageIndex) { + var removeSelector = typeof messageIndex === 'string' ? + // If it's a string, select corresponding message. + '[data-drupal-message="' + messageIndex + '"]' : + // If the index is numeric remove the element based on the DOM index. + '[data-drupal-message]:nth-child(' + messageIndex + ')'; + var remove = this.element.querySelector(removeSelector); + this.element.removeChild(remove); + }.bind(this)); - // If it's a string, select corresponding message. - if (typeof messageIndex === 'string') { - removeSelector = '[data-drupal-message="' + messageIndex + '"]'; - } - // If the index is numeric remove the element based on the DOM index. - else if (typeof messageIndex === 'number') { - removeSelector = '[data-drupal-message]:nth-child(' + messageIndex + ')'; - } - - var remove = this.element.querySelectorAll(removeSelector); - var length = remove.length; - for (var i = 0; i < length; i += 1) { - this.element.removeChild(remove[i]); - } - - return length; + return messagesToRemove.length; } return { diff -u b/core/modules/system/src/Tests/JsMessageTestCases.php b/core/modules/system/src/Tests/JsMessageTestCases.php --- b/core/modules/system/src/Tests/JsMessageTestCases.php +++ b/core/modules/system/src/Tests/JsMessageTestCases.php @@ -8,16 +8,6 @@ class JsMessageTestCases { /** - * Gets the test contexts. - * - * @return string[] - * The test contexts. - */ - public static function getContexts() { - return ['context1', 'context2']; - } - - /** * Gets the test types. * * @return string[] diff -u b/core/modules/system/tests/modules/js_message_test/js/js_message_test.js b/core/modules/system/tests/modules/js_message_test/js/js_message_test.js --- b/core/modules/system/tests/modules/js_message_test/js/js_message_test.js +++ b/core/modules/system/tests/modules/js_message_test/js/js_message_test.js @@ -3,7 +3,7 @@ * Testing behavior for JSMessageTest. */ -(function ($, message) { +(function ($) { 'use strict'; @@ -18,31 +18,47 @@ - var message = Drupal.message(); - var messageIndex; - var messageList = []; + var messageObjects = {}; + var messageIndexes = {}; + $('.show-link').once('show-msg').on('click', function (e) { + e.preventDefault(); var type = e.currentTarget.getAttribute('data-type'); - messageIndex = message.add('Msg-' + type, type); + messageIndexes[type] = getMessageObject(e).add('Msg-' + type, type); }); $('.remove-link').once('remove-msg').on('click', function (e) { e.preventDefault(); var type = e.currentTarget.getAttribute('data-type'); - message.remove(messageIndex); + getMessageObject(e).remove(messageIndexes[type]); }); $('.show-multiple').once('show-msg').on('click', function (e) { e.preventDefault(); for (var i = 0; i < 10; i++) { - messageList.push(message.add('Msg-' + i, 'status')); + messageIndexes[i] = getMessageObject(e).add('Msg-' + i, 'status'); } }); $('.remove-multiple').once('remove-msg').on('click', function (e) { e.preventDefault(); for (var i = 0; i < 10; i++) { - message.remove(messageList[i]); + getMessageObject(e).remove(messageIndexes[i]); } - messageList = []; }); + + /** + * Gets message object for the click event. + * + * @param {jQuery.Event} e + * The click event. + * @return {Drupal.message~messageDefinition} + * The message object for correct div. + */ + function getMessageObject(e) { + var divSelector = e.currentTarget.getAttribute('data-selector'); + if (!messageObjects.hasOwnProperty(divSelector)) { + messageObjects[divSelector] = Drupal.message(document.querySelector(divSelector)); + } + return messageObjects[divSelector]; + } } }; -})(jQuery, Drupal.message); +})(jQuery); diff -u b/core/modules/system/tests/modules/js_message_test/src/Controller/JSMessageTestController.php b/core/modules/system/tests/modules/js_message_test/src/Controller/JSMessageTestController.php --- b/core/modules/system/tests/modules/js_message_test/src/Controller/JSMessageTestController.php +++ b/core/modules/system/tests/modules/js_message_test/src/Controller/JSMessageTestController.php @@ -19,41 +19,36 @@ public function messageLinks() { $links = []; foreach (JsMessageTestCases::getMessagesSelectors() as $messagesSelector) { - foreach (JsMessageTestCases::getContexts() as $context) { - foreach (JsMessageTestCases::getTypes() as $type) { - $links["show-$messagesSelector-$context-$type"] = [ - 'title' => "Show-$messagesSelector-$context-$type", - 'url' => Url::fromRoute('js_message_test.links'), - 'attributes' => [ - 'id' => "show-$messagesSelector-$context-$type", - 'data-context' => $context, - 'data-type' => $type, - 'data-selector' => $messagesSelector, - 'class' => ['show-link'], - ], - ]; - $links["remove-$messagesSelector-$context-$type"] = [ - 'title' => "Remove-$messagesSelector-$context-$type", - 'url' => Url::fromRoute('js_message_test.links'), - 'attributes' => [ - 'id' => "remove-$messagesSelector-$context-$type", - 'data-context' => $context, - 'data-type' => $type, - 'data-selector' => $messagesSelector, - 'class' => ['remove-link'], - ], - ]; - } - $links["remove-$context"] = [ - 'title' => "Remove-$context-all", + foreach (JsMessageTestCases::getTypes() as $type) { + $links["show-$messagesSelector-$type"] = [ + 'title' => "Show-$messagesSelector-$type", 'url' => Url::fromRoute('js_message_test.links'), 'attributes' => [ - 'id' => "remove-$context", - 'data-context' => $context, + 'id' => "show-$messagesSelector-$type", + 'data-type' => $type, + 'data-selector' => $messagesSelector, + 'class' => ['show-link'], + ], + ]; + $links["remove-$messagesSelector-$type"] = [ + 'title' => "Remove-$messagesSelector-$type", + 'url' => Url::fromRoute('js_message_test.links'), + 'attributes' => [ + 'id' => "remove-$messagesSelector-$type", + 'data-type' => $type, + 'data-selector' => $messagesSelector, 'class' => ['remove-link'], ], ]; } + $links["remove"] = [ + 'title' => "Remove-all", + 'url' => Url::fromRoute('js_message_test.links'), + 'attributes' => [ + 'id' => "remove", + 'class' => ['remove-link'], + ], + ]; } $links['show-multi'] = [ diff -u b/core/tests/Drupal/FunctionalJavascriptTests/Core/JsMessageTest.php b/core/tests/Drupal/FunctionalJavascriptTests/Core/JsMessageTest.php --- b/core/tests/Drupal/FunctionalJavascriptTests/Core/JsMessageTest.php +++ b/core/tests/Drupal/FunctionalJavascriptTests/Core/JsMessageTest.php @@ -17,6 +17,9 @@ */ public static $modules = ['js_message_test']; + /** + * {@inheritdoc} + */ protected function setUp() { parent::setUp(); @@ -27,7 +30,6 @@ $theme_config->save(); } - /** * Test click on links to show messages and remove messages. */ @@ -35,49 +37,31 @@ $web_assert = $this->assertSession(); $this->drupalGet('js_message_test_link'); + $current_messages = []; foreach (JsMessageTestCases::getMessagesSelectors() as $messagesSelector) { $web_assert->elementExists('css', $messagesSelector); - foreach (JsMessageTestCases ::getContexts() as $context) { - foreach (JsMessageTestCases::getTypes() as $type) { - $this->clickLink("Show-$messagesSelector-$context-$type"); - $selector = "$messagesSelector .messages.messages--$type.js-messages.js-messages-context--$context"; - $msg_element = $web_assert->waitForElementVisible('css', $selector); - $this->assertNotEmpty($msg_element, "Message element visible: $selector"); - $web_assert->elementContains('css', $selector, "Msg-$context-$type"); - // Click all remove links except the one that will remove the message. - $this->clickAllRemoveLinksExcept($context, $type, $messagesSelector); - // Confirm the message was not removed. - $web_assert->elementContains('css', $selector, "Msg-$context-$type"); - // Click the remove links that should remove the message. - $this->clickLink("Remove-$messagesSelector-$context-$type"); - $web_assert->elementNotExists('css', $selector); - } + foreach (JsMessageTestCases::getTypes() as $type) { + $this->clickLink("Show-$messagesSelector-$type"); + $selector = "$messagesSelector .messages.messages--$type"; + $msg_element = $web_assert->waitForElementVisible('css', $selector); + $this->assertNotEmpty($msg_element, "Message element visible: $selector"); + $web_assert->elementContains('css', $selector, "Msg-$type"); + $current_messages[$selector] = "Msg-$type"; + $this->assertCurrentMessages($current_messages); + } + // Remove messages 1 by 1 and confirm the messages are expected. + foreach (JsMessageTestCases::getTypes() as $type) { + $this->clickLink("Remove-$messagesSelector-$type"); + $selector = "$messagesSelector .messages.messages--$type"; + // The message for this selector should not be on the page. + unset($current_messages[$selector]); + $this->assertCurrentMessages($current_messages); } - // Test removing all messages of a specific context. - $this->clickLink("Show-$messagesSelector-context1-error"); - $this->clickLink("Show-$messagesSelector-context2-error"); - $this->clickLink("Show-$messagesSelector-context1-warning"); - $this->clickLink("Show-$messagesSelector-context2-warning"); - $this->waitForMessageElement('warning', 'context2'); - $this->assertCurrentMessages([ - 'Msg-context1-error', - 'Msg-context2-error', - 'Msg-context1-warning', - 'Msg-context2-warning', - ]); - $this->clickLink('Remove-context1-all'); - $web_assert->assertWaitOnAjaxRequest(); - $this->assertCurrentMessages([ - 'Msg-context2-error', - 'Msg-context2-warning', - ]); - $this->clickLink('Remove-context2-all'); - $this->assertCurrentMessages([]); } + // Test adding multiple messages at once. // @see processMessages() $this->clickLink('Show Multiple'); - $this->waitForMessageElement('status', 'context-9'); $current_messages = []; for ($i = 0; $i < 10; $i++) { @@ -86,27 +70,6 @@ $this->assertCurrentMessages($current_messages); $this->clickLink('Remove Multiple'); $this->assertCurrentMessages([]); - - - - } - - /** - * Clicks all remove message links except for combination specified. - * - * @param string $exclude_context - * The message context to exclude. - * @param string $exclude_type - * The message type to exclude. - */ - protected function clickAllRemoveLinksExcept($exclude_context, $exclude_type, $messagesSelector) { - foreach (JsMessageTestCases::getContexts() as $context) { - foreach (JsMessageTestCases::getTypes() as $type) { - if ($context !== $exclude_context || $type !== $exclude_type) { - $this->clickLink("Remove-$messagesSelector-$context-$type"); - } - } - } } /** @@ -116,6 +79,7 @@ * Expected messages. */ protected function assertCurrentMessages(array $expected_messages) { + $expected_messages = array_values($expected_messages); $current_messages = []; if ($message_divs = $this->getSession()->getPage()->findAll('css', '.messages')) { foreach ($message_divs as $message_div) { @@ -128,15 +92,2 @@ - /** - * Waits for an element message to be visible. - * - * @param string $type - * The type of the message. - * @param string $context - * The context of the message. - */ - protected function waitForMessageElement($type, $context) { - $last_msg_element = $this->assertSession()->waitForElementVisible('css', ".messages.messages--$type.js-messages.js-messages-context--$context"); - $this->assertNotEmpty($last_msg_element, "Message element visible."); - } - } only in patch2: unchanged: --- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php @@ -1094,8 +1094,7 @@ public function __clone() { // Ensure that the following properties are actually cloned by // overwriting the original references with ones pointing to copies of - // them: enforceIsNew, newRevision, loadedRevisionId, fields, entityKeys and - // translatableEntityKeys. + // them: enforceIsNew, newRevision, loadedRevisionId and fields. $enforce_is_new = $this->enforceIsNew; $this->enforceIsNew = &$enforce_is_new; @@ -1108,12 +1107,6 @@ public function __clone() { $fields = $this->fields; $this->fields = &$fields; - $entity_keys = $this->entityKeys; - $this->entityKeys = &$entity_keys; - - $translatable_entity_keys = $this->translatableEntityKeys; - $this->translatableEntityKeys = &$translatable_entity_keys; - foreach ($this->fields as $name => $values) { $this->fields[$name] = []; // Untranslatable fields may have multiple references for the same field only in patch2: unchanged: --- a/core/modules/language/src/LanguageNegotiatorInterface.php +++ b/core/modules/language/src/LanguageNegotiatorInterface.php @@ -91,6 +91,7 @@ * } * } * } + * ?> * @endcode * * For more information, see only in patch2: unchanged: --- a/core/modules/user/src/Tests/UserTimeZoneTest.php +++ b/core/modules/user/src/Tests/UserTimeZoneTest.php @@ -28,15 +28,8 @@ public function testUserTimeZone() { ->set('timezone.user.configurable', 1) ->set('timezone.default', 'America/Los_Angeles') ->save(); - - // Load the 'medium' date format, which is the default for node creation - // time, and override it. Since we are testing time zones with Daylight - // Saving Time, and need to future proof against changes to the zoneinfo - // database, we choose the 'I' format placeholder instead of a - // human-readable zone name. With 'I', a 1 means the date is in DST, and 0 - // if not. DateFormat::load('medium') - ->setPattern('Y-m-d H:i I') + ->setPattern('Y-m-d H:i T') ->save(); // Create a user account and login. @@ -56,11 +49,11 @@ public function testUserTimeZone() { // Confirm date format and time zone. $this->drupalGet('node/' . $node1->id()); - $this->assertText('2007-03-09 21:00 0', 'Date should be PST.'); + $this->assertText('2007-03-09 21:00 PST', 'Date should be PST.'); $this->drupalGet('node/' . $node2->id()); - $this->assertText('2007-03-11 01:00 0', 'Date should be PST.'); + $this->assertText('2007-03-11 01:00 PST', 'Date should be PST.'); $this->drupalGet('node/' . $node3->id()); - $this->assertText('2007-03-20 21:00 1', 'Date should be PDT.'); + $this->assertText('2007-03-20 21:00 PDT', 'Date should be PDT.'); // Change user time zone to Santiago time. $edit = []; @@ -71,25 +64,25 @@ public function testUserTimeZone() { // Confirm date format and time zone. $this->drupalGet('node/' . $node1->id()); - $this->assertText('2007-03-10 02:00 1', 'Date should be Chile summer time; five hours ahead of PST.'); + $this->assertText('2007-03-10 02:00 CLST', 'Date should be Chile summer time; five hours ahead of PST.'); $this->drupalGet('node/' . $node2->id()); - $this->assertText('2007-03-11 05:00 0', 'Date should be Chile time; four hours ahead of PST'); + $this->assertText('2007-03-11 05:00 CLT', 'Date should be Chile time; four hours ahead of PST'); $this->drupalGet('node/' . $node3->id()); - $this->assertText('2007-03-21 00:00 0', 'Date should be Chile time; three hours ahead of PDT.'); + $this->assertText('2007-03-21 00:00 CLT', 'Date should be Chile time; three hours ahead of PDT.'); // Ensure that anonymous users also use the default timezone. $this->drupalLogout(); $this->drupalGet('node/' . $node1->id()); - $this->assertText('2007-03-09 21:00 0', 'Date should be PST.'); + $this->assertText('2007-03-09 21:00 PST', 'Date should be PST.'); $this->drupalGet('node/' . $node2->id()); - $this->assertText('2007-03-11 01:00 0', 'Date should be PST.'); + $this->assertText('2007-03-11 01:00 PST', 'Date should be PST.'); $this->drupalGet('node/' . $node3->id()); - $this->assertText('2007-03-20 21:00 1', 'Date should be PDT.'); + $this->assertText('2007-03-20 21:00 PDT', 'Date should be PDT.'); // Format a date without accessing the current user at all and // ensure that it uses the default timezone. $this->drupalGet('/system-test/date'); - $this->assertText('2016-01-13 08:29 0', 'Date should be PST.'); + $this->assertText('2016-01-13 08:29 PST', 'Date should be PST.'); } } only in patch2: unchanged: --- a/core/tests/Drupal/KernelTests/Core/Entity/ContentEntityCloneTest.php +++ b/core/tests/Drupal/KernelTests/Core/Entity/ContentEntityCloneTest.php @@ -179,44 +179,4 @@ public function testNewRevisionOnCloneEntityTranslation() { $this->assertFalse($entity_translation->isNewRevision()); } - /** - * Tests modifications on entity keys of a cloned entity object. - */ - public function testEntityKeysModifications() { - // Create a test entity with a translation, which will internally trigger - // entity cloning for the new translation and create references for some of - // the entity properties. - $entity = EntityTestMulRev::create([ - 'name' => 'original-name', - 'uuid' => 'original-uuid', - 'language' => 'en', - ]); - $entity->addTranslation('de'); - $entity->save(); - - // Clone the entity. - $clone = clone $entity; - - // Alter a non-translatable and a translatable entity key fields of the - // cloned entity and assert that retrieving the value through the entity - // keys local cache will be different for the cloned and the original - // entity. - // We first have to call the ::uuid() and ::label() method on the original - // entity as it is going to cache the field values into the $entityKeys and - // $translatableEntityKeys properties of the entity object and we want to - // check that the cloned and the original entity aren't sharing the same - // reference to those local cache properties. - $uuid_field_name = $entity->getEntityType()->getKey('uuid'); - $this->assertFalse($entity->getFieldDefinition($uuid_field_name)->isTranslatable()); - $clone->$uuid_field_name->value = 'clone-uuid'; - $this->assertEquals('original-uuid', $entity->uuid()); - $this->assertEquals('clone-uuid', $clone->uuid()); - - $label_field_name = $entity->getEntityType()->getKey('label'); - $this->assertTrue($entity->getFieldDefinition($label_field_name)->isTranslatable()); - $clone->$label_field_name->value = 'clone-name'; - $this->assertEquals('original-name', $entity->label()); - $this->assertEquals('clone-name', $clone->label()); - } - }