diff --git a/core/core.api.php b/core/core.api.php
index 9c358a6e98..6f539ccbd8 100644
--- a/core/core.api.php
+++ b/core/core.api.php
@@ -413,7 +413,7 @@
* \Drupal\Core\Cache\CacheBackendInterface.
*
* The Cache API is used to store data that takes a long time to compute.
- * Caching can either be permanent or valid only for a certain time span, and
+ * Caching can either be permanent or valid only for a certain timespan, and
* the cache can contain any type of data.
*
* To use the Cache API:
@@ -558,7 +558,7 @@
* This also is the case when you define your own entity types: you'll get the
* exact same cache tag invalidation as any of the built-in entity types, with
* the ability to override any of the default behavior if needed.
- * See \Drupal\Core\Cache\CacheableDependencyInterface::getCacheTags(),
+ * See \Drupal\Core\Cache\CacheableDepenencyInterface::getCacheTags(),
* \Drupal\Core\Entity\EntityTypeInterface::getListCacheTags(),
* \Drupal\Core\Entity\Entity::invalidateTagsOnSave() and
* \Drupal\Core\Entity\Entity::invalidateTagsOnDelete().
@@ -569,7 +569,7 @@
* logged-in user who is viewing a page, the language the page is being rendered
* in, the theme being used, etc. When caching the output of such a calculation,
* you must cache each variation separately, along with information about which
- * variation of the contextual data was used in the calculation. The next time
+ * variation of the contextual data was used in the calculatation. The next time
* the computed data is needed, if the context matches that for an existing
* cached data set, the cached data can be reused; if no context matches, a new
* data set can be calculated and cached for later use.
@@ -2003,12 +2003,12 @@ function hook_data_type_info_alter(&$data_types) {
* Alter cron queue information before cron runs.
*
* Called by \Drupal\Core\Cron to allow modules to alter cron queue settings
- * before any jobs are processed.
+ * before any jobs are processesed.
*
* @param array $queues
* An array of cron queue information.
*
- * @see \Drupal\Core\Queue\QueueWorkerInterface
+ * @see \Drupal\Core\QueueWorker\QueueWorkerInterface
* @see \Drupal\Core\Annotation\QueueWorker
* @see \Drupal\Core\Cron
*/
diff --git a/core/core.libraries.yml b/core/core.libraries.yml
index 0b9d87b29c..5eb4a1fbbe 100644
--- a/core/core.libraries.yml
+++ b/core/core.libraries.yml
@@ -233,6 +233,14 @@ drupal.machine-name:
- core/drupalSettings
- core/drupal.form
+drupal.message:
+ version: VERSION
+ js:
+ misc/message.js: {}
+ dependencies:
+ - core/drupal
+ - core/drupal.announce
+
drupal.progress:
version: VERSION
js:
diff --git a/core/core.services.yml b/core/core.services.yml
index ced39ccd59..b5cd022294 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -1618,10 +1618,7 @@ services:
- { name: service_collector, tag: twig.loader, call: addLoader, required: TRUE }
twig.loader.filesystem:
class: Drupal\Core\Template\Loader\FilesystemLoader
- # We use '.' instead of '@app.root' as the path for non-namespaced template
- # files so that they match the relative paths of templates loaded via the
- # theme registry or via Twig namespaces.
- arguments: ['.', '@module_handler', '@theme_handler']
+ arguments: ['@app.root', '@module_handler', '@theme_handler']
tags:
- { name: twig.loader, priority: 100 }
twig.loader.theme_registry:
diff --git a/core/lib/Drupal/Core/Config/ConfigInstaller.php b/core/lib/Drupal/Core/Config/ConfigInstaller.php
index 24d735b99d..d7788161cb 100644
--- a/core/lib/Drupal/Core/Config/ConfigInstaller.php
+++ b/core/lib/Drupal/Core/Config/ConfigInstaller.php
@@ -315,11 +315,10 @@ protected function createConfiguration($collection, array $config_to_create) {
$entity_storage = $this->configManager
->getEntityManager()
->getStorage($entity_type);
-
- $id = $entity_storage->getIDFromConfigName($name, $entity_storage->getEntityType()->getConfigPrefix());
// It is possible that secondary writes can occur during configuration
// creation. Updates of such configuration are allowed.
if ($this->getActiveStorages($collection)->exists($name)) {
+ $id = $entity_storage->getIDFromConfigName($name, $entity_storage->getEntityType()->getConfigPrefix());
$entity = $entity_storage->load($id);
$entity = $entity_storage->updateFromStorageRecord($entity, $new_config->get());
}
@@ -328,9 +327,6 @@ protected function createConfiguration($collection, array $config_to_create) {
}
if ($entity->isInstallable()) {
$entity->trustData()->save();
- if ($id !== $entity->id()) {
- trigger_error(sprintf('The configuration name "%s" does not match the ID "%s"', $name, $entity->id()), E_USER_WARNING);
- }
}
}
else {
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php
index 5cbe365d14..e1b6c1bf5f 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php
@@ -272,10 +272,6 @@ public function preSave() {
* {@inheritdoc}
*/
public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
- // An associative array keyed by the reference type, target type, and
- // bundle.
- static $recursion_tracker = [];
-
$manager = \Drupal::service('plugin.manager.entity_reference_selection');
// Instead of calling $manager->getSelectionHandler($field_definition)
@@ -304,25 +300,9 @@ public static function generateSampleValue(FieldDefinitionInterface $field_defin
// Attempt to create a sample entity, avoiding recursion.
$entity_storage = \Drupal::entityTypeManager()->getStorage($options['target_type']);
- if ($entity_storage instanceof ContentEntityStorageInterface) {
+ if ($options['target_type'] !== $field_definition->getTargetEntityTypeId() && $entity_storage instanceof ContentEntityStorageInterface) {
$bundle = static::getRandomBundle($entity_type, $options['handler_settings']);
-
- // Track the generated entity by reference type, target type, and bundle.
- $key = $field_definition->getTargetEntityTypeId() . ':' . $options['target_type'] . ':' . $bundle;
-
- // If entity generation was attempted but did not finish, do not continue.
- if (isset($recursion_tracker[$key])) {
- return [];
- }
-
- // Mark this as an attempt at generation.
- $recursion_tracker[$key] = TRUE;
-
- // Mark the sample entity as being a preview.
- $values['entity'] = $entity_storage->createWithSampleValues($bundle, ['in_preview' => TRUE]);
-
- // Remove the indicator once the entity is successfully generated.
- unset($recursion_tracker[$key]);
+ $values['entity'] = $entity_storage->createWithSampleValues($bundle);
return $values;
}
}
diff --git a/core/lib/Drupal/Core/Render/Element/StatusMessages.php b/core/lib/Drupal/Core/Render/Element/StatusMessages.php
index 578d28ffbe..a64d34c73a 100644
--- a/core/lib/Drupal/Core/Render/Element/StatusMessages.php
+++ b/core/lib/Drupal/Core/Render/Element/StatusMessages.php
@@ -84,7 +84,7 @@ public static function renderMessages($type = NULL) {
if ($messages) {
// Render the messages.
- $render = [
+ $render[] = [
'#theme' => 'status_messages',
// @todo Improve when https://www.drupal.org/node/2278383 lands.
'#message_list' => $messages,
@@ -95,6 +95,10 @@ public static function renderMessages($type = NULL) {
],
];
}
+ $render[] = [
+ '#markup' => '
',
+ ];
+
return $render;
}
diff --git a/core/lib/Drupal/Core/Render/Renderer.php b/core/lib/Drupal/Core/Render/Renderer.php
index 1c36184430..5e1b8d1b8d 100644
--- a/core/lib/Drupal/Core/Render/Renderer.php
+++ b/core/lib/Drupal/Core/Render/Renderer.php
@@ -380,7 +380,7 @@ protected function doRender(&$elements, $is_root_call = FALSE) {
}
// All render elements support #markup and #plain_text.
- if (isset($elements['#markup']) || isset($elements['#plain_text'])) {
+ if (!empty($elements['#markup']) || !empty($elements['#plain_text'])) {
$elements = $this->ensureMarkupIsSafe($elements);
}
@@ -744,7 +744,11 @@ protected function xssFilterAdminIfUnsafe($string) {
* @see \Drupal\Component\Utility\Xss::filterAdmin()
*/
protected function ensureMarkupIsSafe(array $elements) {
- if (isset($elements['#plain_text'])) {
+ if (empty($elements['#markup']) && empty($elements['#plain_text'])) {
+ return $elements;
+ }
+
+ if (!empty($elements['#plain_text'])) {
$elements['#markup'] = Markup::create(Html::escape($elements['#plain_text']));
}
elseif (!($elements['#markup'] instanceof MarkupInterface)) {
diff --git a/core/lib/Drupal/Core/Routing/RequestFormatRouteFilter.php b/core/lib/Drupal/Core/Routing/RequestFormatRouteFilter.php
index 8d14dd52cf..dbfb801b78 100644
--- a/core/lib/Drupal/Core/Routing/RequestFormatRouteFilter.php
+++ b/core/lib/Drupal/Core/Routing/RequestFormatRouteFilter.php
@@ -4,7 +4,6 @@
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException;
-use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
/**
@@ -18,14 +17,7 @@ class RequestFormatRouteFilter implements FilterInterface {
public function filter(RouteCollection $collection, Request $request) {
// Determine the request format.
$default_format = static::getDefaultFormat($collection);
- // If the request does not specify a format then use the default.
- if (is_null($request->getRequestFormat(NULL))) {
- $format = $default_format;
- $request->setRequestFormat($default_format);
- }
- else {
- $format = $request->getRequestFormat($default_format);
- }
+ $format = $request->getRequestFormat($default_format);
$routes_with_requirement = [];
$routes_without_requirement = [];
@@ -68,9 +60,7 @@ public function filter(RouteCollection $collection, Request $request) {
*
* By default, use 'html' as the default format. But when there's only a
* single route match, and that route specifies a '_format' requirement
- * listing a single format, then use that as the default format. Also, if
- * there are multiple routes which all require the same single format then
- * use it.
+ * listing a single format, then use that as the default format.
*
* @param \Symfony\Component\Routing\RouteCollection $collection
* The route collection to filter.
@@ -79,20 +69,15 @@ public function filter(RouteCollection $collection, Request $request) {
* The default format.
*/
protected static function getDefaultFormat(RouteCollection $collection) {
- // Get the set of formats across all routes in the collection.
- $all_formats = array_reduce($collection->all(), function (array $carry, Route $route) {
- // Routes without a '_format' requirement are assumed to require HTML.
- $route_formats = !$route->hasRequirement('_format')
- ? ['html']
- : explode('|', $route->getRequirement('_format'));
- return array_merge($carry, $route_formats);
- }, []);
- $formats = array_unique(array_filter($all_formats));
-
- // The default format is 'html' unless ALL routes require the same format.
- return count($formats) === 1
- ? reset($formats)
- : 'html';
+ $default_format = 'html';
+ if ($collection->count() === 1) {
+ $only_route = $collection->getIterator()->current();
+ $required_format = $only_route->getRequirement('_format');
+ if (strpos($required_format, '|') === FALSE) {
+ $default_format = $required_format;
+ }
+ }
+ return $default_format;
}
}
diff --git a/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php b/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php
index f246cce462..e3864610f4 100644
--- a/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php
+++ b/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php
@@ -46,9 +46,7 @@ public function handle(Request $request, $type = self::MASTER_REQUEST, $catch =
}
// Determine the request format using the negotiator.
- if ($requested_format = $this->getContentType($request)) {
- $request->setRequestFormat($requested_format);
- }
+ $request->setRequestFormat($this->getContentType($request));
return $this->app->handle($request, $type, $catch);
}
@@ -90,8 +88,8 @@ protected function getContentType(Request $request) {
return $request->query->get('_format');
}
- // No format was specified in the request.
- return NULL;
+ // Do HTML last so that it always wins.
+ return 'html';
}
}
diff --git a/core/misc/dropbutton/dropbutton.es6.js b/core/misc/dropbutton/dropbutton.es6.js
index e654673ec1..73ff363feb 100644
--- a/core/misc/dropbutton/dropbutton.es6.js
+++ b/core/misc/dropbutton/dropbutton.es6.js
@@ -214,7 +214,7 @@
* @param {object} options
* Options object.
* @param {string} [options.title]
- * The button text.
+ * The HTML anchor title attribute and text for the inner span element.
*
* @return {string}
* A string representing a DOM fragment.
diff --git a/core/misc/message.es6.js b/core/misc/message.es6.js
new file mode 100644
index 0000000000..26581ad853
--- /dev/null
+++ b/core/misc/message.es6.js
@@ -0,0 +1,240 @@
+/**
+ * @file
+ * Message API.
+ */
+((Drupal) => {
+ /**
+ * @typedef {object} Drupal.Message~messageDefinition
+ */
+
+ /**
+ * Constructs a new instance of the Drupal.Message object.
+ *
+ * This provides a uniform interface for adding and removing messages to a
+ * specific location on the page.
+ *
+ * @param {HTMLElement} messageWrapper
+ * The zone where to add messages. If no element is provided an attempt is
+ * made to determine a default location.
+ *
+ * @return {Drupal.Message~messageDefinition}
+ * Object to add and remove messages.
+ */
+
+ Drupal.Message = class {
+ constructor(messageWrapper = null) {
+ this.messageWrapper = messageWrapper;
+ }
+
+ /**
+ * Attempt to determine the default location for
+ * inserting JavaScript messages or create one if needed.
+ *
+ * @return {HTMLElement}
+ * The default destination for JavaScript messages.
+ */
+ static defaultWrapper() {
+ let wrapper = document.querySelector('[data-drupal-messages]');
+ if (!wrapper) {
+ wrapper = document.querySelector('[data-drupal-messages-fallback]');
+ wrapper.removeAttribute('data-drupal-messages-fallback');
+ wrapper.setAttribute('data-drupal-messages', '');
+ wrapper.removeAttribute('class');
+ }
+ return wrapper.innerHTML === '' ? Drupal.Message.messageInternalWrapper(wrapper) : wrapper.firstElementChild;
+ }
+
+ /**
+ * Provide an object containing the available message types.
+ *
+ * @return {Object}
+ * An object containing message type strings.
+ */
+ static getMessageTypeLabels() {
+ return {
+ status: Drupal.t('Status message'),
+ error: Drupal.t('Error message'),
+ warning: Drupal.t('Warning message'),
+ };
+ }
+
+ /**
+ * Sequentially adds a message to the message area.
+ *
+ * @name Drupal.Message~messageDefinition.add
+ *
+ * @param {string} message
+ * The message to display
+ * @param {object} [options]
+ * The context of the message, used for removing messages again.
+ * @param {string} [options.id]
+ * The message ID, it can be a simple value: `'filevalidationerror'`
+ * or several values separated by a space: `'mymodule formvalidation'`
+ * which can be used as a sort of tag for message deletion.
+ * @param {string} [options.type=status]
+ * Message type, can be either 'status', 'error' or 'warning'.
+ * @param {string} [options.announce]
+ * Screen-reader version of the message if necessary. To prevent a message
+ * being sent to Drupal.announce() this should be `''`.
+ * @param {string} [options.priority]
+ * Priority of the message for Drupal.announce().
+ *
+ * @return {string}
+ * ID of message.
+ */
+ add(message, options = {}) {
+ if (!this.messageWrapper) {
+ this.messageWrapper = Drupal.Message.defaultWrapper();
+ }
+ if (!options.hasOwnProperty('type')) {
+ options.type = 'status';
+ }
+
+ if (typeof message !== 'string') {
+ throw new Error('Message must be a string.');
+ }
+
+ // Send message to screen reader.
+ Drupal.Message.announce(message, options);
+ /**
+ * Use the provided index for the message or generate a unique key to
+ * allow message deletion.
+ */
+ options.id = options.id ?
+ String(options.id) :
+ `${options.type}-${Math.random().toFixed(15).replace('0.', '')}`;
+
+ // Throw an error if an unexpected message type is used.
+ if (!(Drupal.Message.getMessageTypeLabels().hasOwnProperty(options.type))) {
+ throw new Error(`The message type, ${options.type}, is not present in Drupal.Message.getMessageTypeLabels().`);
+ }
+
+ this.messageWrapper.appendChild(Drupal.theme('message', { text: message }, options));
+
+ return options.id;
+ }
+
+ /**
+ * Select a message based on id.
+ *
+ * @name Drupal.Message~messageDefinition.select
+ *
+ * @param {string} id
+ * The message id to delete from the area.
+ *
+ * @return {Element}
+ * Element found.
+ */
+ select(id) {
+ return this.messageWrapper.querySelector(`[data-drupal-message-id^="${id}"]`);
+ }
+
+ /**
+ * Removes messages from the message area.
+ *
+ * @name Drupal.Message~messageDefinition.remove
+ *
+ * @param {string} id
+ * Index of the message to remove, as returned by
+ * {@link Drupal.Message~messageDefinition.add}.
+ *
+ * @return {number}
+ * Number of removed messages.
+ */
+ remove(id) {
+ return this.messageWrapper.removeChild(this.select(id));
+ }
+
+ /**
+ * Removes all messages from the message area.
+ *
+ * @name Drupal.Message~messageDefinition.clear
+ */
+ clear() {
+ Array.prototype.forEach.call(this.messageWrapper.querySelectorAll('[data-drupal-message-id]'), (message) => {
+ this.messageWrapper.removeChild(message);
+ });
+ }
+
+ /**
+ * Helper to call Drupal.announce() with the right parameters.
+ *
+ * @param {string} message
+ * Displayed message.
+ * @param {object} options
+ * Additional data.
+ * @param {string} [options.announce]
+ * Screen-reader version of the message if necessary. To prevent a message
+ * being sent to Drupal.announce() this should be `''`.
+ * @param {string} [options.priority]
+ * Priority of the message for Drupal.announce().
+ * @param {string} [options.type]
+ * Message type, can be either 'status', 'error' or 'warning'.
+ */
+ static announce(message, options) {
+ if (!options.priority && (options.type === 'warning' || options.type === 'error')) {
+ options.priority = 'assertive';
+ }
+ /**
+ * If screen reader message is not disabled announce screen reader
+ * specific text or fallback to the displayed message.
+ */
+ if (options.announce !== '') {
+ Drupal.announce(options.announce || message, options.priority);
+ }
+ }
+
+ /**
+ * Function for creating the internal message wrapper element.
+ *
+ * @param {HTMLElement} messageWrapper
+ * The message wrapper.
+ *
+ * @return {HTMLElement}
+ * The internal wrapper DOM element.
+ */
+ static messageInternalWrapper(messageWrapper) {
+ const innerWrapper = document.createElement('div');
+ innerWrapper.setAttribute('class', 'messages__wrapper');
+ messageWrapper.insertAdjacentElement('afterbegin', innerWrapper);
+ return innerWrapper;
+ }
+ };
+
+ /**
+ * Theme function for a message.
+ *
+ * @param {object} message
+ * The message object.
+ * @param {string} message.text
+ * The message text.
+ * @param {object} options
+ * The message context.
+ * @param {string} options.type
+ * The message type.
+ * @param {string} options.id
+ * ID of the message, for reference.
+ *
+ * @return {HTMLElement}
+ * A DOM Node.
+ */
+ Drupal.theme.message = ({ text }, options) => {
+ const messagesTypes = Drupal.Message.getMessageTypeLabels();
+ const messageWraper = document.createElement('div');
+ const messageText = document.createElement('h2');
+ messageText.setAttribute('class', 'visually-hidden');
+
+ messageWraper.setAttribute('class', `messages messages--${options.type}`);
+ messageWraper.setAttribute('role', options.type === 'error' ? 'alert' : 'status');
+ messageWraper.setAttribute('data-drupal-message-id', options.id);
+ messageWraper.setAttribute('data-drupal-message-type', options.type);
+
+ messageWraper.setAttribute('aria-label', messagesTypes[options.type]);
+ messageText.innerHTML = messagesTypes[options.type];
+
+ messageWraper.innerHTML = ` ${text}`;
+ messageWraper.insertAdjacentElement('afterbegin', messageText);
+
+ return messageWraper;
+ };
+})(Drupal);
diff --git a/core/misc/message.js b/core/misc/message.js
new file mode 100644
index 0000000000..34664e3be4
--- /dev/null
+++ b/core/misc/message.js
@@ -0,0 +1,135 @@
+/**
+* DO NOT EDIT THIS FILE.
+* See the following change record for more information,
+* https://www.drupal.org/node/2815083
+* @preserve
+**/
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+(function (Drupal) {
+
+ Drupal.Message = function () {
+ function _class() {
+ var messageWrapper = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
+
+ _classCallCheck(this, _class);
+
+ this.messageWrapper = messageWrapper;
+ }
+
+ _createClass(_class, [{
+ key: 'add',
+ value: function add(message) {
+ var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+
+ if (!this.messageWrapper) {
+ this.messageWrapper = Drupal.Message.defaultWrapper();
+ }
+ if (!options.hasOwnProperty('type')) {
+ options.type = 'status';
+ }
+
+ if (typeof message !== 'string') {
+ throw new Error('Message must be a string.');
+ }
+
+ Drupal.Message.announce(message, options);
+
+ options.id = options.id ? String(options.id) : options.type + '-' + Math.random().toFixed(15).replace('0.', '');
+
+ if (!Drupal.Message.getMessageTypeLabels().hasOwnProperty(options.type)) {
+ throw new Error('The message type, ' + options.type + ', is not present in Drupal.Message.getMessageTypeLabels().');
+ }
+
+ this.messageWrapper.appendChild(Drupal.theme('message', { text: message }, options));
+
+ return options.id;
+ }
+ }, {
+ key: 'select',
+ value: function select(id) {
+ return this.messageWrapper.querySelector('[data-drupal-message-id^="' + id + '"]');
+ }
+ }, {
+ key: 'remove',
+ value: function remove(id) {
+ return this.messageWrapper.removeChild(this.select(id));
+ }
+ }, {
+ key: 'clear',
+ value: function clear() {
+ var _this = this;
+
+ Array.prototype.forEach.call(this.messageWrapper.querySelectorAll('[data-drupal-message-id]'), function (message) {
+ _this.messageWrapper.removeChild(message);
+ });
+ }
+ }], [{
+ key: 'defaultWrapper',
+ value: function defaultWrapper() {
+ var wrapper = document.querySelector('[data-drupal-messages]');
+ if (!wrapper) {
+ wrapper = document.querySelector('[data-drupal-messages-fallback]');
+ wrapper.removeAttribute('data-drupal-messages-fallback');
+ wrapper.setAttribute('data-drupal-messages', '');
+ wrapper.removeAttribute('class');
+ }
+ return wrapper.innerHTML === '' ? Drupal.Message.messageInternalWrapper(wrapper) : wrapper.firstElementChild;
+ }
+ }, {
+ key: 'getMessageTypeLabels',
+ value: function getMessageTypeLabels() {
+ return {
+ status: Drupal.t('Status message'),
+ error: Drupal.t('Error message'),
+ warning: Drupal.t('Warning message')
+ };
+ }
+ }, {
+ key: 'announce',
+ value: function announce(message, options) {
+ if (!options.priority && (options.type === 'warning' || options.type === 'error')) {
+ options.priority = 'assertive';
+ }
+
+ if (options.announce !== '') {
+ Drupal.announce(options.announce || message, options.priority);
+ }
+ }
+ }, {
+ key: 'messageInternalWrapper',
+ value: function messageInternalWrapper(messageWrapper) {
+ var innerWrapper = document.createElement('div');
+ innerWrapper.setAttribute('class', 'messages__wrapper');
+ messageWrapper.insertAdjacentElement('afterbegin', innerWrapper);
+ return innerWrapper;
+ }
+ }]);
+
+ return _class;
+ }();
+
+ Drupal.theme.message = function (_ref, options) {
+ var text = _ref.text;
+
+ var messagesTypes = Drupal.Message.getMessageTypeLabels();
+ var messageWraper = document.createElement('div');
+ var messageText = document.createElement('h2');
+ messageText.setAttribute('class', 'visually-hidden');
+
+ messageWraper.setAttribute('class', 'messages messages--' + options.type);
+ messageWraper.setAttribute('role', options.type === 'error' ? 'alert' : 'status');
+ messageWraper.setAttribute('data-drupal-message-id', options.id);
+ messageWraper.setAttribute('data-drupal-message-type', options.type);
+
+ messageWraper.setAttribute('aria-label', messagesTypes[options.type]);
+ messageText.innerHTML = messagesTypes[options.type];
+
+ messageWraper.innerHTML = ' ' + text;
+ messageWraper.insertAdjacentElement('afterbegin', messageText);
+
+ return messageWraper;
+ };
+})(Drupal);
\ No newline at end of file
diff --git a/core/modules/big_pipe/tests/modules/big_pipe_test/src/BigPipePlaceholderTestCases.php b/core/modules/big_pipe/tests/modules/big_pipe_test/src/BigPipePlaceholderTestCases.php
index f274356139..962bde55f1 100644
--- a/core/modules/big_pipe/tests/modules/big_pipe_test/src/BigPipePlaceholderTestCases.php
+++ b/core/modules/big_pipe/tests/modules/big_pipe_test/src/BigPipePlaceholderTestCases.php
@@ -88,11 +88,11 @@ public static function cases(ContainerInterface $container = NULL, AccountInterf
'command' => 'insert',
'method' => 'replaceWith',
'selector' => '[data-big-pipe-placeholder-id="callback=Drupal%5CCore%5CRender%5CElement%5CStatusMessages%3A%3ArenderMessages&args%5B0%5D&token=_HAdUpwWmet0TOTe2PSiJuMntExoshbm1kh2wQzzzAA"]',
- 'data' => ' ' . "\n" . '
Status message
' . "\n" . ' Hello from BigPipe!' . "\n" . ' ' . "\n ",
+ 'data' => '' . "\n" . '
' . "\n" . '
Status message
' . "\n" . ' Hello from BigPipe!' . "\n" . ' ' . "\n" . '
' . "\n",
'settings' => NULL,
],
];
- $status_messages->embeddedHtmlResponse = '' . "\n" . '
Status message
' . "\n" . ' Hello from BigPipe!' . "\n" . ' ' . "\n \n";
+ $status_messages->embeddedHtmlResponse = '' . "\n" . '
' . "\n" . '
Status message
' . "\n" . ' Hello from BigPipe!' . "\n" . ' ' . "\n" . '
' . "\n";
}
// 2. Real-world example of HTML attribute value placeholder: form action.
diff --git a/core/modules/comment/comment.install b/core/modules/comment/comment.install
index 82b578b489..c244fe4ce8 100644
--- a/core/modules/comment/comment.install
+++ b/core/modules/comment/comment.install
@@ -5,7 +5,6 @@
* Install, update and uninstall functions for the Comment module.
*/
-use Drupal\comment\Entity\Comment;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\StringTranslation\PluralTranslatableMarkup;
use Drupal\Core\StringTranslation\TranslatableMarkup;
@@ -196,14 +195,3 @@ function comment_update_8400() {
$entity_definition_update_manager = \Drupal::service('entity.definition_update_manager');
$entity_definition_update_manager->updateFieldStorageDefinition($entity_definition_update_manager->getFieldStorageDefinition('status', 'comment'));
}
-
-/**
- * Configure the comment hostname base field to use a default value callback.
- */
-function comment_update_8600() {
- $entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager();
- /** @var \Drupal\Core\Field\BaseFieldDefinition $field_storage_definition */
- $field_storage_definition = $entity_definition_update_manager->getFieldStorageDefinition('hostname', 'comment');
- $field_storage_definition->setDefaultValueCallback(Comment::class . '::getDefaultHostname');
- $entity_definition_update_manager->updateFieldStorageDefinition($field_storage_definition);
-}
diff --git a/core/modules/comment/src/Entity/Comment.php b/core/modules/comment/src/Entity/Comment.php
index e0745d3da0..5f5a611565 100644
--- a/core/modules/comment/src/Entity/Comment.php
+++ b/core/modules/comment/src/Entity/Comment.php
@@ -143,6 +143,10 @@ public function preSave(EntityStorageInterface $storage) {
$this->threadLock = $lock_name;
}
$this->setThread($thread);
+ if (!$this->getHostname()) {
+ // Ensure a client host from the current request.
+ $this->setHostname(\Drupal::request()->getClientIP());
+ }
}
// The entity fields for name and mail have no meaning if the user is not
// Anonymous. Set them to NULL to make it clearer that they are not used.
@@ -287,8 +291,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
->setLabel(t('Hostname'))
->setDescription(t("The comment author's hostname."))
->setTranslatable(TRUE)
- ->setSetting('max_length', 128)
- ->setDefaultValueCallback(static::class . '::getDefaultHostname');
+ ->setSetting('max_length', 128);
$fields['created'] = BaseFieldDefinition::create('created')
->setLabel(t('Created'))
@@ -569,14 +572,4 @@ public static function getDefaultStatus() {
return \Drupal::currentUser()->hasPermission('skip comment approval') ? CommentInterface::PUBLISHED : CommentInterface::NOT_PUBLISHED;
}
- /**
- * Returns the default value for entity hostname base field.
- *
- * @return string
- * The client host name.
- */
- public static function getDefaultHostname() {
- return \Drupal::request()->getClientIP();
- }
-
}
diff --git a/core/modules/comment/tests/src/Functional/Update/CommentHostnameUpdateTest.php b/core/modules/comment/tests/src/Functional/Update/CommentHostnameUpdateTest.php
deleted file mode 100644
index 7d75b6e6dd..0000000000
--- a/core/modules/comment/tests/src/Functional/Update/CommentHostnameUpdateTest.php
+++ /dev/null
@@ -1,45 +0,0 @@
-databaseDumpFiles = [
- __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8-rc1.bare.standard.php.gz',
- ];
- }
-
- /**
- * Tests comment_update_8600().
- *
- * @see comment_update_8600
- */
- public function testCommentUpdate8600() {
- /** @var \Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface $manager */
- $manager = $this->container->get('entity.definition_update_manager');
-
- /** @var \Drupal\Core\Field\BaseFieldDefinition $definition */
- $definition = $manager->getFieldStorageDefinition('hostname', 'comment');
- // Check that 'hostname' base field doesn't have a default value callback.
- $this->assertNull($definition->getDefaultValueCallback());
-
- $this->runUpdates();
-
- $definition = $manager->getFieldStorageDefinition('hostname', 'comment');
- // Check that 'hostname' base field default value callback was set.
- $this->assertEquals(Comment::class . '::getDefaultHostname', $definition->getDefaultValueCallback());
- }
-
-}
diff --git a/core/modules/comment/tests/src/Kernel/CommentHostnameTest.php b/core/modules/comment/tests/src/Kernel/CommentHostnameTest.php
deleted file mode 100644
index dc4f37b63f..0000000000
--- a/core/modules/comment/tests/src/Kernel/CommentHostnameTest.php
+++ /dev/null
@@ -1,46 +0,0 @@
- '203.0.113.1']);
- /** @var \Symfony\Component\HttpFoundation\RequestStack $stack */
- $stack = $this->container->get('request_stack');
- $stack->push($request);
-
- CommentType::create([
- 'id' => 'foo',
- 'target_entity_type_id' => 'entity_test',
- ])->save();
- $comment = Comment::create(['comment_type' => 'foo']);
-
- // Check that the hostname was set correctly.
- $this->assertEquals('203.0.113.1', $comment->getHostname());
- }
-
-}
diff --git a/core/modules/config/tests/config_test/config/install/config_test.dynamic.isinstallable.yml b/core/modules/config/tests/config_test/config/install/config_test.dynamic.isinstallable.default.yml
similarity index 100%
rename from core/modules/config/tests/config_test/config/install/config_test.dynamic.isinstallable.yml
rename to core/modules/config/tests/config_test/config/install/config_test.dynamic.isinstallable.default.yml
diff --git a/core/modules/config/tests/config_test_id_mismatch/config/install/config_test.dynamic.no_id_match.yml b/core/modules/config/tests/config_test_id_mismatch/config/install/config_test.dynamic.no_id_match.yml
deleted file mode 100644
index 879a53b5b9..0000000000
--- a/core/modules/config/tests/config_test_id_mismatch/config/install/config_test.dynamic.no_id_match.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-id: does_not_match
-label: Default
-weight: 0
-protected_property: Default
-langcode: en
diff --git a/core/modules/config/tests/config_test_id_mismatch/config_test_id_mismatch.info.yml b/core/modules/config/tests/config_test_id_mismatch/config_test_id_mismatch.info.yml
deleted file mode 100644
index 7cd2e0926a..0000000000
--- a/core/modules/config/tests/config_test_id_mismatch/config_test_id_mismatch.info.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-name: 'Configuration test ID mismatch'
-type: module
-package: Testing
-version: VERSION
-core: 8.x
-dependencies:
- - drupal:config_test
diff --git a/core/modules/field/tests/src/Kernel/EntityReference/EntityReferenceItemTest.php b/core/modules/field/tests/src/Kernel/EntityReference/EntityReferenceItemTest.php
index 627fdba5dc..c9446c7453 100644
--- a/core/modules/field/tests/src/Kernel/EntityReference/EntityReferenceItemTest.php
+++ b/core/modules/field/tests/src/Kernel/EntityReference/EntityReferenceItemTest.php
@@ -3,7 +3,6 @@
namespace Drupal\Tests\field\Kernel\EntityReference;
use Drupal\comment\Entity\Comment;
-use Drupal\comment\Entity\CommentType;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FieldItemInterface;
@@ -15,7 +14,6 @@
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
-use Drupal\node\Entity\NodeType;
use Drupal\node\NodeInterface;
use Drupal\taxonomy\TermInterface;
use Drupal\Tests\field\Kernel\FieldKernelTestBase;
@@ -91,14 +89,6 @@ protected function setUp() {
]);
$this->term->save();
- NodeType::create([
- 'type' => $this->randomMachineName(),
- ])->save();
- CommentType::create([
- 'id' => $this->randomMachineName(),
- 'target_entity_type_id' => 'node',
- ])->save();
-
$this->entityStringId = EntityTestStringId::create([
'id' => $this->randomMachineName(),
]);
@@ -112,7 +102,6 @@ protected function setUp() {
$this->createEntityReferenceField('entity_test', 'entity_test', 'field_test_user', 'Test user entity reference', 'user');
$this->createEntityReferenceField('entity_test', 'entity_test', 'field_test_comment', 'Test comment entity reference', 'comment');
$this->createEntityReferenceField('entity_test', 'entity_test', 'field_test_file', 'Test file entity reference', 'file');
- $this->createEntityReferenceField('entity_test_string_id', 'entity_test_string_id', 'field_test_entity_test', 'Test content entity reference with string ID', 'entity_test');
}
/**
@@ -222,19 +211,6 @@ public function testGenerateSampleValue() {
$this->entityValidateAndSave($entity);
}
- /**
- * Tests the ::generateSampleValue() method when it has a circular reference.
- */
- public function testGenerateSampleValueCircularReference() {
- // Delete the existing entity.
- $this->entityStringId->delete();
-
- $entity_storage = \Drupal::entityTypeManager()->getStorage('entity_test');
- $entity = $entity_storage->createWithSampleValues('entity_test');
- $this->assertInstanceOf(EntityTestStringId::class, $entity->field_test_entity_test_string_id->entity);
- $this->assertInstanceOf(EntityTest::class, $entity->field_test_entity_test_string_id->entity->field_test_entity_test->entity);
- }
-
/**
* Tests referencing content entities with string IDs.
*/
diff --git a/core/modules/layout_builder/tests/modules/layout_builder_views_test/config/install/views.view.test_block_view.yml b/core/modules/layout_builder/tests/modules/layout_builder_views_test/config/install/views.view.test_block_view.yml
deleted file mode 100644
index c666e89d68..0000000000
--- a/core/modules/layout_builder/tests/modules/layout_builder_views_test/config/install/views.view.test_block_view.yml
+++ /dev/null
@@ -1,177 +0,0 @@
-langcode: en
-status: true
-dependencies:
- module:
- - node
- - user
-id: test_block_view
-label: 'Test Block View'
-module: views
-description: ''
-tag: ''
-base_table: node_field_data
-base_field: nid
-core: 8.x
-display:
- default:
- display_plugin: default
- id: default
- display_title: Master
- position: 0
- display_options:
- access:
- type: perm
- options:
- perm: 'access content'
- cache:
- type: tag
- options: { }
- query:
- type: views_query
- options:
- disable_sql_rewrite: false
- distinct: false
- replica: false
- query_comment: ''
- query_tags: { }
- exposed_form:
- type: basic
- options:
- submit_button: Apply
- reset_button: false
- reset_button_label: Reset
- exposed_sorts_label: 'Sort by'
- expose_sort_order: true
- sort_asc_label: Asc
- sort_desc_label: Desc
- pager:
- type: some
- options:
- items_per_page: 5
- offset: 0
- style:
- type: default
- row:
- type: fields
- fields:
- title:
- id: title
- table: node_field_data
- field: title
- settings:
- link_to_entity: true
- plugin_id: field
- relationship: none
- group_type: group
- admin_label: ''
- label: ''
- exclude: false
- alter:
- alter_text: false
- text: ''
- make_link: false
- path: ''
- absolute: false
- external: false
- replace_spaces: false
- path_case: none
- trim_whitespace: false
- alt: ''
- rel: ''
- link_class: ''
- prefix: ''
- suffix: ''
- target: ''
- nl2br: false
- max_length: 0
- word_boundary: true
- ellipsis: true
- more_link: false
- more_link_text: ''
- more_link_path: ''
- strip_tags: false
- trim: false
- preserve_tags: ''
- html: false
- element_type: ''
- element_class: ''
- element_label_type: ''
- element_label_class: ''
- element_label_colon: true
- element_wrapper_type: ''
- element_wrapper_class: ''
- element_default_classes: true
- empty: ''
- hide_empty: false
- empty_zero: false
- hide_alter_empty: true
- click_sort_column: value
- type: string
- group_column: value
- group_columns: { }
- group_rows: true
- delta_limit: 0
- delta_offset: 0
- delta_reversed: false
- delta_first_last: false
- multi_type: separator
- separator: ', '
- field_api_classes: false
- filters:
- status:
- value: '1'
- table: node_field_data
- field: status
- plugin_id: boolean
- entity_type: node
- entity_field: status
- id: status
- expose:
- operator: ''
- group: 1
- sorts:
- created:
- id: created
- table: node_field_data
- field: created
- order: DESC
- entity_type: node
- entity_field: created
- plugin_id: date
- relationship: none
- group_type: group
- admin_label: ''
- exposed: false
- expose:
- label: ''
- granularity: second
- title: 'Test Block View'
- header: { }
- footer: { }
- empty: { }
- relationships: { }
- arguments: { }
- display_extenders: { }
- cache_metadata:
- max-age: -1
- contexts:
- - 'languages:language_content'
- - 'languages:language_interface'
- - 'user.node_grants:view'
- - user.permissions
- tags: { }
- block_1:
- display_plugin: block
- id: block_1
- display_title: Block
- position: 1
- display_options:
- display_extenders: { }
- cache_metadata:
- max-age: -1
- contexts:
- - 'languages:language_content'
- - 'languages:language_interface'
- - 'user.node_grants:view'
- - user.permissions
- tags: { }
diff --git a/core/modules/layout_builder/tests/modules/layout_builder_views_test/layout_builder_views_test.info.yml b/core/modules/layout_builder/tests/modules/layout_builder_views_test/layout_builder_views_test.info.yml
deleted file mode 100644
index b471a0a636..0000000000
--- a/core/modules/layout_builder/tests/modules/layout_builder_views_test/layout_builder_views_test.info.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-name: 'Layout Builder Views Test'
-type: module
-description: 'Support module for testing.'
-package: Testing
-version: VERSION
-core: 8.x
-dependencies:
- - views
diff --git a/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php b/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php
index 40c0503cea..b99c273f55 100644
--- a/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php
+++ b/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php
@@ -2,9 +2,7 @@
namespace Drupal\Tests\layout_builder\Functional;
-use Drupal\node\Entity\Node;
use Drupal\Tests\BrowserTestBase;
-use Drupal\views\Entity\View;
/**
* Tests the Layout Builder UI.
@@ -17,9 +15,7 @@ class LayoutBuilderTest extends BrowserTestBase {
* {@inheritdoc}
*/
public static $modules = [
- 'views',
'layout_builder',
- 'layout_builder_views_test',
'layout_test',
'block',
'node',
@@ -353,40 +349,4 @@ public function testLayoutBuilderChooseBlocksAlter() {
$assert_session->linkNotExists('Sticky at top of lists');
}
- /**
- * Tests that deleting a View block used in Layout Builder works.
- */
- public function testDeletedView() {
- $assert_session = $this->assertSession();
- $page = $this->getSession()->getPage();
-
- $this->drupalLogin($this->drupalCreateUser([
- 'configure any layout',
- 'administer node display',
- ]));
-
- $field_ui_prefix = 'admin/structure/types/manage/bundle_with_section_field';
- // Enable overrides.
- $this->drupalPostForm("$field_ui_prefix/display/default", ['layout[allow_custom]' => TRUE], 'Save');
- $this->drupalGet('node/1');
-
- $assert_session->linkExists('Layout');
- $this->clickLink('Layout');
- $this->clickLink('Add Block');
- $this->clickLink('Test Block View');
- $page->pressButton('Add Block');
-
- $assert_session->pageTextContains('Test Block View');
- $assert_session->elementExists('css', '.block-views-blocktest-block-view-block-1');
- $this->clickLink('Save Layout');
- $assert_session->pageTextContains('Test Block View');
- $assert_session->elementExists('css', '.block-views-blocktest-block-view-block-1');
-
- View::load('test_block_view')->delete();
- $this->drupalGet('node/1');
- // Node can be loaded after deleting the View.
- $assert_session->pageTextContains(Node::load(1)->getTitle());
- $assert_session->pageTextNotContains('Test Block View');
- }
-
}
diff --git a/core/modules/rest/tests/modules/rest_test/rest_test.services.yml b/core/modules/rest/tests/modules/rest_test/rest_test.services.yml
index 85b418a6c6..d316cf6072 100644
--- a/core/modules/rest/tests/modules/rest_test/rest_test.services.yml
+++ b/core/modules/rest/tests/modules/rest_test/rest_test.services.yml
@@ -12,7 +12,3 @@ services:
public: false
tags:
- { name: page_cache_request_policy }
- rest_test.encoder.foobar:
- class: Drupal\serialization\Encoder\JsonEncoder
- tags:
- - { name: encoder, format: foobar }
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php
index b5d7fbb7d4..2ab45273d5 100644
--- a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php
+++ b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php
@@ -156,22 +156,12 @@
/**
* Provides an entity resource.
- *
- * @param bool $single_format
- * Provisions a single-format entity REST resource. Defaults to FALSE.
*/
- protected function provisionEntityResource($single_format = FALSE) {
- if ($existing = $this->resourceConfigStorage->load(static::$resourceConfigId)) {
- $existing->delete();
- }
-
- $format = $single_format
- ? [static::$format]
- : [static::$format, 'foobar'];
+ protected function provisionEntityResource() {
// It's possible to not have any authentication providers enabled, when
// testing public (anonymous) usage of a REST resource.
$auth = isset(static::$auth) ? [static::$auth] : [];
- $this->provisionResource($format, $auth);
+ $this->provisionResource([static::$format], $auth);
}
/**
@@ -444,6 +434,20 @@ public function testGet() {
}
$this->provisionEntityResource();
+ // Simulate the developer again forgetting the ?_format query string.
+ $url->setOption('query', []);
+
+ // DX: 406 when ?_format is missing, except when requesting a canonical HTML
+ // route.
+ $response = $this->request('GET', $url, $request_options);
+ if ($has_canonical_url && (!static::$auth || static::$auth === 'cookie')) {
+ $this->assertSame(403, $response->getStatusCode());
+ }
+ else {
+ $this->assert406Response($response);
+ }
+
+ $url->setOption('query', ['_format' => static::$format]);
// DX: forgetting authentication: authentication provider-specific error
// response.
@@ -468,44 +472,10 @@ public function testGet() {
unset($request_options[RequestOptions::HEADERS]['REST-test-auth-global']);
$request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions('GET'));
- // First: single format. Drupal will automatically pick the only format.
- $this->provisionEntityResource(TRUE);
- $expected_403_cacheability = $this->getExpectedUnauthorizedAccessCacheability();
- // DX: 403 because unauthorized single-format route, ?_format is omittable.
- $url->setOption('query', []);
- $response = $this->request('GET', $url, $request_options);
- if ($has_canonical_url) {
- $this->assertSame(403, $response->getStatusCode());
- $this->assertSame(['text/html; charset=UTF-8'], $response->getHeader('Content-Type'));
- }
- else {
- $this->assertResourceErrorResponse(403, FALSE, $response, $expected_403_cacheability->getCacheTags(), $expected_403_cacheability->getCacheContexts(), static::$auth ? FALSE : 'MISS', 'MISS');
- }
- $this->assertSame(static::$auth ? [] : ['MISS'], $response->getHeader('X-Drupal-Cache'));
- // DX: 403 because unauthorized.
- $url->setOption('query', ['_format' => static::$format]);
- $response = $this->request('GET', $url, $request_options);
- $this->assertResourceErrorResponse(403, FALSE, $response, $expected_403_cacheability->getCacheTags(), $expected_403_cacheability->getCacheContexts(), static::$auth ? FALSE : 'MISS', $has_canonical_url ? 'MISS' : 'HIT');
-
- // Then, what we'll use for the remainder of the test: multiple formats.
- $this->provisionEntityResource();
- // DX: 406 because despite unauthorized, ?_format is not omittable.
- $url->setOption('query', []);
- $response = $this->request('GET', $url, $request_options);
- if ($has_canonical_url) {
- $this->assertSame(403, $response->getStatusCode());
- $this->assertSame(['HIT'], $response->getHeader('X-Drupal-Dynamic-Cache'));
- }
- else {
- $this->assertSame(406, $response->getStatusCode());
- $this->assertSame(['UNCACHEABLE'], $response->getHeader('X-Drupal-Dynamic-Cache'));
- }
- $this->assertSame(['text/html; charset=UTF-8'], $response->getHeader('Content-Type'));
- $this->assertSame(static::$auth ? [] : ['MISS'], $response->getHeader('X-Drupal-Cache'));
- // DX: 403 because unauthorized.
- $url->setOption('query', ['_format' => static::$format]);
+ // DX: 403 when unauthorized.
$response = $this->request('GET', $url, $request_options);
- $this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('GET'), $response, $expected_403_cacheability->getCacheTags(), $expected_403_cacheability->getCacheContexts(), static::$auth ? FALSE : 'MISS', 'HIT');
+ $expected_403_cacheability = $this->getExpectedUnauthorizedAccessCacheability();
+ $this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('GET'), $response, $expected_403_cacheability->getCacheTags(), $expected_403_cacheability->getCacheContexts(), static::$auth ? FALSE : 'MISS', 'MISS');
$this->assertArrayNotHasKey('Link', $response->getHeaders());
$this->setUpAuthorization('GET');
diff --git a/core/modules/system/src/Tests/JsMessageTestCases.php b/core/modules/system/src/Tests/JsMessageTestCases.php
new file mode 100644
index 0000000000..05e1040dd3
--- /dev/null
+++ b/core/modules/system/src/Tests/JsMessageTestCases.php
@@ -0,0 +1,32 @@
+
{% for type, messages in message_list %}
{% if type == 'error' %}
{% endif %}
- {% if status_headings[type] %}
-
{{ status_headings[type] }}
- {% endif %}
- {% if messages|length > 1 %}
-
- {% for message in messages %}
- - {{ message }}
- {% endfor %}
-
- {% else %}
- {{ messages|first }}
- {% endif %}
+ {% if status_headings[type] %}
+
{{ status_headings[type] }}
+ {% endif %}
+ {% if messages|length > 1 %}
+
+ {% for message in messages %}
+ - {{ message }}
+ {% endfor %}
+
+ {% else %}
+ {{ messages|first }}
+ {% endif %}
{% if type == 'error' %}
{% endif %}
{% endfor %}
+
diff --git a/core/modules/system/tests/modules/default_format_test/default_format_test.info.yml b/core/modules/system/tests/modules/default_format_test/default_format_test.info.yml
deleted file mode 100644
index 0a02a0688a..0000000000
--- a/core/modules/system/tests/modules/default_format_test/default_format_test.info.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-name: 'Default format test'
-type: module
-description: 'Support module for testing default route format.'
-package: Testing
-version: VERSION
-core: 8.x
diff --git a/core/modules/system/tests/modules/default_format_test/default_format_test.routing.yml b/core/modules/system/tests/modules/default_format_test/default_format_test.routing.yml
deleted file mode 100644
index 368dcb1946..0000000000
--- a/core/modules/system/tests/modules/default_format_test/default_format_test.routing.yml
+++ /dev/null
@@ -1,28 +0,0 @@
-default_format_test.machine:
- path: '/default_format_test/machine'
- defaults:
- # Same controller + method!
- _controller: '\Drupal\default_format_test\DefaultFormatTestController::content'
- requirements:
- _access: 'TRUE'
- _format: 'json'
-
-default_format_test.human:
- path: '/default_format_test/human'
- defaults:
- # Same controller + method!
- _controller: '\Drupal\default_format_test\DefaultFormatTestController::content'
- requirements:
- _access: 'TRUE'
- _format: 'html'
-
-# Route definition identical to default_format_test.machine, only different name.
-# @see \Drupal\FunctionalTests\Routing\DefaultFormatTest::testMultiple
-default_format_test.machine.alias:
- path: '/default_format_test/machine'
- defaults:
- # Same controller + method!
- _controller: '\Drupal\default_format_test\DefaultFormatTestController::content'
- requirements:
- _access: 'TRUE'
- _format: 'json'
diff --git a/core/modules/system/tests/modules/default_format_test/src/DefaultFormatTestController.php b/core/modules/system/tests/modules/default_format_test/src/DefaultFormatTestController.php
deleted file mode 100644
index 6e52eea342..0000000000
--- a/core/modules/system/tests/modules/default_format_test/src/DefaultFormatTestController.php
+++ /dev/null
@@ -1,15 +0,0 @@
-getRequestFormat();
- return new CacheableResponse('format:' . $format, 200, ['Content-Type' => $request->getMimeType($format)]);
- }
-
-}
diff --git a/core/modules/system/tests/modules/js_message_test/js/js_message_test.es6.js b/core/modules/system/tests/modules/js_message_test/js/js_message_test.es6.js
new file mode 100644
index 0000000000..2eb41a21c9
--- /dev/null
+++ b/core/modules/system/tests/modules/js_message_test/js/js_message_test.es6.js
@@ -0,0 +1,92 @@
+/**
+ * @file
+ * Testing behavior for JSMessageTest.
+ */
+
+(($, { behaviors }, { testMessages }) => {
+ // Message types
+ const indexes = {};
+ testMessages.types.forEach((type) => {
+ indexes[type] = [];
+ });
+
+ // Message storage.
+ const messageObjects = {
+ default: {
+ zone: new Drupal.Message(),
+ indexes,
+ },
+ multiple: [],
+ };
+
+ testMessages.selectors
+ .filter(Boolean)
+ .forEach((selector) => {
+ messageObjects[selector] = {
+ zone: new Drupal.Message(document.querySelector(selector)),
+ indexes,
+ };
+ });
+
+ /**
+ * @type {Drupal~behavior}
+ *
+ * @prop {Drupal~behaviorAttach} attach
+ * Add click listeners that show and remove links with context and type.
+ */
+ behaviors.js_message_test = {
+ attach() {
+ $('[data-drupal-messages-area]').once('messages-details').on('click', '[data-action]', (e) => {
+ const $target = $(e.currentTarget);
+ const type = $target.attr('data-type');
+ const area = $target.closest('[data-drupal-messages-area]').attr('data-drupal-messages-area') || 'default';
+ const message = messageObjects[area].zone;
+ const action = $target.attr('data-action');
+
+ if (action === 'add') {
+ messageObjects[area].indexes[type].push(
+ message.add(`This is a message of the type, ${type}. You be the the judge of its importance.`, { type }),
+ );
+ }
+ else if (action === 'remove') {
+ message.remove(messageObjects[area].indexes[type].pop());
+ }
+ });
+ $('[data-action="add-multiple"]').once('add-multiple').on('click', () => {
+ /**
+ * Add several of different types to make sure message type doesn't
+ * cause issues in the API.
+ */
+ [0, 1, 2, 3, 4, 5].forEach((i) => {
+ messageObjects.multiple.push(
+ messageObjects.default.zone.add(
+ `This is message number ${i} of the type, ${testMessages.types[i % testMessages.types.length]}. You be the the judge of its importance.`,
+ { type: testMessages.types[i % testMessages.types.length] },
+ ),
+ );
+ });
+ });
+ $('[data-action="remove-multiple"]').once('remove-multiple').on('click', () => {
+ messageObjects.multiple
+ .forEach(messageIndex => messageObjects.default.zone.remove(messageIndex));
+ messageObjects.multiple = [];
+ });
+ $('[data-action="add-multiple-error"]').once('add-multiple-error').on('click', () => {
+ // Use the same number of elements to facilitate things on the PHP side.
+ [0, 1, 2, 3, 4, 5].forEach(i => messageObjects.default.zone.add(`Msg-${i}`, { type: 'error' }));
+ messageObjects.default.zone.add(`Msg-${testMessages.types.length * 2}`, { type: 'status' });
+ });
+ $('[data-action="remove-type"]').once('remove-type').on('click', () => {
+ Array.prototype.map
+ .call(document.querySelectorAll('[data-drupal-message-id^="error"]'), element => element.getAttribute('data-drupal-message-id'))
+ .forEach(id => messageObjects.default.zone.remove(id));
+ });
+ $('[data-action="clear-all"]').once('clear-all').on('click', () => {
+ messageObjects.default.zone.clear();
+ });
+ $('[data-action="id-no-status"]').once('id-no-status').on('click', () => {
+ messageObjects.default.zone.add('Msg-id-no-status', { id: 'my-special-id' });
+ });
+ },
+ };
+})(jQuery, Drupal, drupalSettings);
diff --git a/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
new file mode 100644
index 0000000000..5f48c826ac
--- /dev/null
+++ b/core/modules/system/tests/modules/js_message_test/js/js_message_test.js
@@ -0,0 +1,79 @@
+/**
+* DO NOT EDIT THIS FILE.
+* See the following change record for more information,
+* https://www.drupal.org/node/2815083
+* @preserve
+**/
+
+(function ($, _ref, _ref2) {
+ var behaviors = _ref.behaviors;
+ var testMessages = _ref2.testMessages;
+
+ var indexes = {};
+ testMessages.types.forEach(function (type) {
+ indexes[type] = [];
+ });
+
+ var messageObjects = {
+ default: {
+ zone: new Drupal.Message(),
+ indexes: indexes
+ },
+ multiple: []
+ };
+
+ testMessages.selectors.filter(Boolean).forEach(function (selector) {
+ messageObjects[selector] = {
+ zone: new Drupal.Message(document.querySelector(selector)),
+ indexes: indexes
+ };
+ });
+
+ behaviors.js_message_test = {
+ attach: function attach() {
+ $('[data-drupal-messages-area]').once('messages-details').on('click', '[data-action]', function (e) {
+ var $target = $(e.currentTarget);
+ var type = $target.attr('data-type');
+ var area = $target.closest('[data-drupal-messages-area]').attr('data-drupal-messages-area') || 'default';
+ var message = messageObjects[area].zone;
+ var action = $target.attr('data-action');
+
+ if (action === 'add') {
+ messageObjects[area].indexes[type].push(message.add('This is a message of the type, ' + type + '. You be the the judge of its importance.', { type: type }));
+ } else if (action === 'remove') {
+ message.remove(messageObjects[area].indexes[type].pop());
+ }
+ });
+ $('[data-action="add-multiple"]').once('add-multiple').on('click', function () {
+ [0, 1, 2, 3, 4, 5].forEach(function (i) {
+ messageObjects.multiple.push(messageObjects.default.zone.add('This is message number ' + i + ' of the type, ' + testMessages.types[i % testMessages.types.length] + '. You be the the judge of its importance.', { type: testMessages.types[i % testMessages.types.length] }));
+ });
+ });
+ $('[data-action="remove-multiple"]').once('remove-multiple').on('click', function () {
+ messageObjects.multiple.forEach(function (messageIndex) {
+ return messageObjects.default.zone.remove(messageIndex);
+ });
+ messageObjects.multiple = [];
+ });
+ $('[data-action="add-multiple-error"]').once('add-multiple-error').on('click', function () {
+ [0, 1, 2, 3, 4, 5].forEach(function (i) {
+ return messageObjects.default.zone.add('Msg-' + i, { type: 'error' });
+ });
+ messageObjects.default.zone.add('Msg-' + testMessages.types.length * 2, { type: 'status' });
+ });
+ $('[data-action="remove-type"]').once('remove-type').on('click', function () {
+ Array.prototype.map.call(document.querySelectorAll('[data-drupal-message-id^="error"]'), function (element) {
+ return element.getAttribute('data-drupal-message-id');
+ }).forEach(function (id) {
+ return messageObjects.default.zone.remove(id);
+ });
+ });
+ $('[data-action="clear-all"]').once('clear-all').on('click', function () {
+ messageObjects.default.zone.clear();
+ });
+ $('[data-action="id-no-status"]').once('id-no-status').on('click', function () {
+ messageObjects.default.zone.add('Msg-id-no-status', { id: 'my-special-id' });
+ });
+ }
+ };
+})(jQuery, Drupal, drupalSettings);
\ No newline at end of file
diff --git a/core/modules/system/tests/modules/js_message_test/js_message_test.info.yml b/core/modules/system/tests/modules/js_message_test/js_message_test.info.yml
new file mode 100644
index 0000000000..e8bc73b065
--- /dev/null
+++ b/core/modules/system/tests/modules/js_message_test/js_message_test.info.yml
@@ -0,0 +1,6 @@
+name: 'JS Message test module'
+type: module
+description: 'Module for the JSMessageTest test.'
+package: Testing
+version: VERSION
+core: 8.x
diff --git a/core/modules/system/tests/modules/js_message_test/js_message_test.libraries.yml b/core/modules/system/tests/modules/js_message_test/js_message_test.libraries.yml
new file mode 100644
index 0000000000..57501a9ce0
--- /dev/null
+++ b/core/modules/system/tests/modules/js_message_test/js_message_test.libraries.yml
@@ -0,0 +1,8 @@
+show_message:
+ version: VERSION
+ js:
+ js/js_message_test.js: {}
+ dependencies:
+ - core/drupalSettings
+ - core/drupal.message
+ - core/jquery.once
diff --git a/core/modules/system/tests/modules/js_message_test/js_message_test.routing.yml b/core/modules/system/tests/modules/js_message_test/js_message_test.routing.yml
new file mode 100644
index 0000000000..4c325e8461
--- /dev/null
+++ b/core/modules/system/tests/modules/js_message_test/js_message_test.routing.yml
@@ -0,0 +1,7 @@
+js_message_test.links:
+ path: '/js_message_test_link'
+ defaults:
+ _controller: '\Drupal\js_message_test\Controller\JSMessageTestController::messageLinks'
+ _title: 'JsMessageLinks'
+ requirements:
+ _access: 'TRUE'
diff --git a/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
new file mode 100644
index 0000000000..57d38284f7
--- /dev/null
+++ b/core/modules/system/tests/modules/js_message_test/src/Controller/JSMessageTestController.php
@@ -0,0 +1,139 @@
+ 'details',
+ '#open' => TRUE,
+ '#title' => "Message area: $messagesSelector",
+ '#attributes' => [
+ 'data-drupal-messages-area' => $messagesSelector,
+ ],
+ ];
+ foreach (JsMessageTestCases::getTypes() as $type) {
+ $buttons[$messagesSelector]["add-$type"] = [
+ '#type' => 'html_tag',
+ '#tag' => 'button',
+ '#value' => "Add $type",
+ '#attributes' => [
+ 'type' => 'button',
+ 'id' => "add-$messagesSelector-$type",
+ 'data-type' => $type,
+ 'data-action' => 'add',
+ ],
+ ];
+ $buttons[$messagesSelector]["remove-$type"] = [
+ '#type' => 'html_tag',
+ '#tag' => 'button',
+ '#value' => "Remove $type",
+ '#attributes' => [
+ 'type' => 'button',
+ 'id' => "remove-$messagesSelector-$type",
+ 'data-type' => $type,
+ 'data-action' => 'remove',
+ ],
+ ];
+ }
+ }
+ // Add alternative message area.
+ $buttons[JsMessageTestCases::getMessagesSelectors()[1]]['messages-other-area'] = [
+ '#type' => 'html_tag',
+ '#tag' => 'div',
+ '#attributes' => [
+ 'data-drupal-messages-other' => TRUE,
+ ],
+ ];
+ $buttons['add-multiple'] = [
+ '#type' => 'html_tag',
+ '#tag' => 'button',
+ '#value' => "Add multiple",
+ '#attributes' => [
+ 'type' => 'button',
+ 'id' => 'add-multiple',
+ 'data-action' => 'add-multiple',
+ ],
+ ];
+ $buttons['remove-multiple'] = [
+ '#type' => 'html_tag',
+ '#tag' => 'button',
+ '#value' => "Remove multiple",
+ '#attributes' => [
+ 'type' => 'button',
+ 'id' => 'remove-multiple',
+ 'data-action' => 'remove-multiple',
+ ],
+ ];
+ $buttons['add-multiple-error'] = [
+ '#type' => 'html_tag',
+ '#tag' => 'button',
+ '#value' => "Add multiple 'error' and one 'status'",
+ '#attributes' => [
+ 'type' => 'button',
+ 'id' => 'add-multiple-error',
+ 'data-action' => 'add-multiple-error',
+ ],
+ ];
+ $buttons['remove-type'] = [
+ '#type' => 'html_tag',
+ '#tag' => 'button',
+ '#value' => "Remove 'error' type",
+ '#attributes' => [
+ 'type' => 'button',
+ 'id' => 'remove-type',
+ 'data-action' => 'remove-type',
+ ],
+ ];
+ $buttons['clear-all'] = [
+ '#type' => 'html_tag',
+ '#tag' => 'button',
+ '#value' => "Clear all",
+ '#attributes' => [
+ 'type' => 'button',
+ 'id' => 'clear-all',
+ 'data-action' => 'clear-all',
+ ],
+ ];
+
+ $buttons['id-no-status'] = [
+ '#type' => 'html_tag',
+ '#tag' => 'button',
+ '#value' => "Id no status",
+ '#attributes' => [
+ 'type' => 'button',
+ 'id' => 'id-no-status',
+ 'data-action' => 'id-no-status',
+ ],
+ ];
+
+ return $buttons + [
+ '#attached' => [
+ 'library' => [
+ 'js_message_test/show_message',
+ ],
+ 'drupalSettings' => [
+ 'testMessages' => [
+ 'selectors' => JsMessageTestCases::getMessagesSelectors(),
+ 'types' => JsMessageTestCases::getTypes(),
+ ],
+ ],
+ ],
+ ];
+ }
+
+}
diff --git a/core/modules/system/tests/themes/test_messages/templates/status-messages.html.twig b/core/modules/system/tests/themes/test_messages/templates/status-messages.html.twig
new file mode 100644
index 0000000000..42f105d3df
--- /dev/null
+++ b/core/modules/system/tests/themes/test_messages/templates/status-messages.html.twig
@@ -0,0 +1,41 @@
+{#
+/**
+ * @file
+ * Test templates file with extra messages div.
+ */
+#}
+
+{% block messages %}
+{% for type, messages in message_list %}
+ {%
+ set classes = [
+ 'messages',
+ 'messages--' ~ type,
+ ]
+ %}
+
+ {% if type == 'error' %}
+
+ {% endif %}
+ {% if status_headings[type] %}
+
{{ status_headings[type] }}
+ {% endif %}
+ {% if messages|length > 1 %}
+
+ {% for message in messages %}
+ - {{ message }}
+ {% endfor %}
+
+ {% else %}
+ {{ messages|first }}
+ {% endif %}
+ {% if type == 'error' %}
+
+ {% endif %}
+
+ {# Remove type specific classes. #}
+ {% set attributes = attributes.removeClass(classes) %}
+{% endfor %}
+{% endblock messages %}
+
+
diff --git a/core/modules/system/tests/themes/test_messages/test_messages.info.yml b/core/modules/system/tests/themes/test_messages/test_messages.info.yml
new file mode 100644
index 0000000000..ea88438d98
--- /dev/null
+++ b/core/modules/system/tests/themes/test_messages/test_messages.info.yml
@@ -0,0 +1,6 @@
+name: 'Theme test messages'
+type: theme
+description: 'Test theme which provides another div for messages.'
+version: VERSION
+core: 8.x
+base theme: classy
diff --git a/core/modules/taxonomy/tests/src/Functional/Views/TaxonomyDefaultArgumentTest.php b/core/modules/taxonomy/tests/src/Functional/Views/TaxonomyDefaultArgumentTest.php
index d2eb21625d..82646c03c0 100644
--- a/core/modules/taxonomy/tests/src/Functional/Views/TaxonomyDefaultArgumentTest.php
+++ b/core/modules/taxonomy/tests/src/Functional/Views/TaxonomyDefaultArgumentTest.php
@@ -2,6 +2,11 @@
namespace Drupal\Tests\taxonomy\Functional\Views;
+use Drupal\field\Entity\FieldConfig;
+use Drupal\views\Views;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+
/**
* Tests the representative node relationship for terms.
*
@@ -16,6 +21,73 @@ class TaxonomyDefaultArgumentTest extends TaxonomyTestBase {
*/
public static $testViews = ['taxonomy_default_argument_test'];
+ /**
+ * Tests the relationship.
+ */
+ public function testNodePath() {
+ $view = Views::getView('taxonomy_default_argument_test');
+
+ $request = Request::create($this->nodes[0]->url());
+ $request->server->set('SCRIPT_NAME', $GLOBALS['base_path'] . 'index.php');
+ $request->server->set('SCRIPT_FILENAME', 'index.php');
+
+ $response = $this->container->get('http_kernel')
+ ->handle($request, HttpKernelInterface::SUB_REQUEST);
+ $view->setRequest($request);
+ $view->setResponse($response);
+
+ $view->initHandlers();
+ $expected = implode(',', [$this->term1->id(), $this->term2->id()]);
+ $this->assertEqual($expected, $view->argument['tid']->getDefaultArgument());
+ $view->destroy();
+ }
+
+ public function testNodePathWithViewSelection() {
+ // Change the term entity reference field to use a view as selection plugin.
+ \Drupal::service('module_installer')->install(['entity_reference_test']);
+
+ $field_name = 'field_' . $this->vocabulary->id();
+ $field = FieldConfig::loadByName('node', 'article', $field_name);
+ $field->setSetting('handler', 'views');
+ $field->setSetting('handler_settings', [
+ 'view' => [
+ 'view_name' => 'test_entity_reference',
+ 'display_name' => 'entity_reference_1',
+ ],
+ ]);
+ $field->save();
+
+ $view = Views::getView('taxonomy_default_argument_test');
+
+ $request = Request::create($this->nodes[0]->url());
+ $request->server->set('SCRIPT_NAME', $GLOBALS['base_path'] . 'index.php');
+ $request->server->set('SCRIPT_FILENAME', 'index.php');
+
+ $response = $this->container->get('http_kernel')->handle($request, HttpKernelInterface::SUB_REQUEST);
+ $view->setRequest($request);
+ $view->setResponse($response);
+
+ $view->initHandlers();
+ $expected = implode(',', [$this->term1->id(), $this->term2->id()]);
+ $this->assertEqual($expected, $view->argument['tid']->getDefaultArgument());
+ }
+
+ public function testTermPath() {
+ $view = Views::getView('taxonomy_default_argument_test');
+
+ $request = Request::create($this->term1->url());
+ $request->server->set('SCRIPT_NAME', $GLOBALS['base_path'] . 'index.php');
+ $request->server->set('SCRIPT_FILENAME', 'index.php');
+
+ $response = $this->container->get('http_kernel')->handle($request, HttpKernelInterface::SUB_REQUEST);
+ $view->setRequest($request);
+ $view->setResponse($response);
+ $view->initHandlers();
+
+ $expected = $this->term1->id();
+ $this->assertEqual($expected, $view->argument['tid']->getDefaultArgument());
+ }
+
/**
* Tests escaping of page title when the taxonomy plugin provides it.
*/
diff --git a/core/modules/taxonomy/tests/src/Kernel/Views/TaxonomyDefaultArgumentTest.php b/core/modules/taxonomy/tests/src/Kernel/Views/TaxonomyDefaultArgumentTest.php
deleted file mode 100644
index 3b9ba26d87..0000000000
--- a/core/modules/taxonomy/tests/src/Kernel/Views/TaxonomyDefaultArgumentTest.php
+++ /dev/null
@@ -1,93 +0,0 @@
-server->set('SCRIPT_NAME', $GLOBALS['base_path'] . 'index.php');
- $request->server->set('SCRIPT_FILENAME', 'index.php');
-
- $response = $this->container->get('http_kernel')
- ->handle($request, HttpKernelInterface::SUB_REQUEST);
-
- $view->setRequest($request);
- $view->setResponse($response);
- $view->initHandlers();
-
- return $view;
- }
-
- /**
- * Tests the relationship.
- */
- public function testNodePath() {
- $view = $this->initViewWithRequest($this->nodes[0]->url());
-
- $expected = implode(',', [$this->term1->id(), $this->term2->id()]);
- $this->assertEqual($expected, $view->argument['tid']->getDefaultArgument());
- $view->destroy();
- }
-
- public function testNodePathWithViewSelection() {
- // Change the term entity reference field to use a view as selection plugin.
- \Drupal::service('module_installer')->install(['entity_reference_test']);
-
- $field_name = 'field_' . $this->vocabulary->id();
- $field = FieldConfig::loadByName('node', 'article', $field_name);
- $field->setSetting('handler', 'views');
- $field->setSetting('handler_settings', [
- 'view' => [
- 'view_name' => 'test_entity_reference',
- 'display_name' => 'entity_reference_1',
- ],
- ]);
- $field->save();
-
- $view = $this->initViewWithRequest($this->nodes[0]->url());
-
- $expected = implode(',', [$this->term1->id(), $this->term2->id()]);
- $this->assertEqual($expected, $view->argument['tid']->getDefaultArgument());
- }
-
- public function testTermPath() {
- $view = $this->initViewWithRequest($this->term1->url());
-
- $expected = $this->term1->id();
- $this->assertEqual($expected, $view->argument['tid']->getDefaultArgument());
- }
-
-}
diff --git a/core/modules/taxonomy/tests/src/Kernel/Views/TaxonomyTestBase.php b/core/modules/taxonomy/tests/src/Kernel/Views/TaxonomyTestBase.php
deleted file mode 100644
index a9f4c474be..0000000000
--- a/core/modules/taxonomy/tests/src/Kernel/Views/TaxonomyTestBase.php
+++ /dev/null
@@ -1,184 +0,0 @@
-installConfig(['node', 'filter']);
- $this->installEntitySchema('user');
- $this->installEntitySchema('taxonomy_term');
- $this->mockStandardInstall();
-
- if ($import_test_views) {
- ViewTestData::createTestViews(get_class($this), ['taxonomy_test_views']);
- }
-
- $this->term1 = $this->createTerm();
- $this->term2 = $this->createTerm();
-
- $node = [];
- $node['type'] = 'article';
- $node['field_views_testing_tags'][]['target_id'] = $this->term1->id();
- $node['field_views_testing_tags'][]['target_id'] = $this->term2->id();
- $this->nodes[] = $this->drupalCreateNode($node);
- $this->nodes[] = $this->drupalCreateNode($node);
- }
-
- /**
- * Provides a workaround for the inability to use the standard profile.
- *
- * @see https://www.drupal.org/node/1708692
- */
- protected function mockStandardInstall() {
- $this->drupalCreateContentType([
- 'type' => 'article',
- ]);
-
- // Create the vocabulary for the tag field.
- $this->vocabulary = Vocabulary::create([
- 'name' => 'Views testing tags',
- 'vid' => 'views_testing_tags',
- ]);
- $this->vocabulary->save();
- $field_name = 'field_' . $this->vocabulary->id();
-
- $handler_settings = [
- 'target_bundles' => [
- $this->vocabulary->id() => $this->vocabulary->id(),
- ],
- 'auto_create' => TRUE,
- ];
-
- $this->installEntitySchema('node');
- $this->createEntityReferenceField('node', 'article', $field_name, 'Tags', 'taxonomy_term', 'default', $handler_settings, FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
- $entity_type_manager = $this->container->get('entity_type.manager');
- $entity_type_manager
- ->getStorage('entity_form_display')
- ->load('node.article.default')
- ->setComponent($field_name, [
- 'type' => 'entity_reference_autocomplete_tags',
- 'weight' => -4,
- ])
- ->save();
-
- $view_modes = [
- 'default',
- 'teaser',
- ];
- foreach ($view_modes as $view_mode) {
- $entity_type_manager
- ->getStorage('entity_view_display')
- ->load("node.article.{$view_mode}")
- ->setComponent($field_name, [
- 'type' => 'entity_reference_label',
- 'weight' => 10,
- ])
- ->save();
- }
- }
-
- /**
- * Creates and returns a taxonomy term.
- *
- * @param array $settings
- * (optional) An array of values to override the following default
- * properties of the term:
- * - name: A random string.
- * - description: A random string.
- * - format: First available text format.
- * - vid: Vocabulary ID of self::$vocabulary object.
- * - langcode: LANGCODE_NOT_SPECIFIED.
- * Defaults to an empty array.
- *
- * @return \Drupal\taxonomy\Entity\Term
- * The created taxonomy term.
- */
- protected function createTerm(array $settings = []) {
- $filter_formats = filter_formats();
- $format = array_pop($filter_formats);
- $settings += [
- 'name' => $this->randomMachineName(),
- 'description' => $this->randomMachineName(),
- // Use the first available text format.
- 'format' => $format->id(),
- 'vid' => $this->vocabulary->id(),
- 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
- ];
- $term = Term::create($settings);
- $term->save();
- return $term;
- }
-
-}
diff --git a/core/modules/tour/tests/src/Unit/Plugin/tour/tip/TipPluginTextTest.php b/core/modules/tour/tests/src/Unit/Plugin/tour/tip/TipPluginTextTest.php
index 65a6d51457..29ea50e468 100644
--- a/core/modules/tour/tests/src/Unit/Plugin/tour/tip/TipPluginTextTest.php
+++ b/core/modules/tour/tests/src/Unit/Plugin/tour/tip/TipPluginTextTest.php
@@ -15,13 +15,10 @@ class TipPluginTextTest extends UnitTestCase {
* Tests that getAriaId returns unique id per plugin instance.
*
* @see \Drupal\tour\Plugin\tour\tip\TipPluginText::getAriaId()
- * @runTestsInSeparateProcesses
- * This test calls \Drupal\Component\Utility\Html::getUniqueId() which uses a
- * static list. Run this test in a separate process to prevent side effects.
*/
public function testGetAriaId() {
- $id_instance_one = 'one';
- $id_instance_two = 'two';
+ $id_instance_one = $this->getRandomGenerator()->word(4, TRUE);
+ $id_instance_two = $this->getRandomGenerator()->word(4, TRUE);
$config_instance_one = [
'id' => $id_instance_one,
];
diff --git a/core/modules/views/src/Plugin/views/display/Block.php b/core/modules/views/src/Plugin/views/display/Block.php
index e210ee3231..5e833d752a 100644
--- a/core/modules/views/src/Plugin/views/display/Block.php
+++ b/core/modules/views/src/Plugin/views/display/Block.php
@@ -2,8 +2,6 @@
namespace Drupal\views\Plugin\views\display;
-use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
-use Drupal\Core\Block\BlockManagerInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Plugin\Block\ViewsBlock;
@@ -44,13 +42,6 @@ class Block extends DisplayPluginBase {
*/
protected $entityManager;
- /**
- * The block manager.
- *
- * @var \Drupal\Core\Block\BlockManagerInterface
- */
- protected $blockManager;
-
/**
* Constructs a new Block instance.
*
@@ -62,14 +53,11 @@ class Block extends DisplayPluginBase {
* The plugin implementation definition.
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
- * @param \Drupal\Core\Block\BlockManagerInterface $block_manager
- * The block manager.
*/
- public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager, BlockManagerInterface $block_manager) {
+ public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityManager = $entity_manager;
- $this->blockManager = $block_manager;
}
/**
@@ -80,8 +68,7 @@ public static function create(ContainerInterface $container, array $configuratio
$configuration,
$plugin_id,
$plugin_definition,
- $container->get('entity.manager'),
- $container->get('plugin.manager.block')
+ $container->get('entity.manager')
);
}
@@ -377,9 +364,6 @@ public function remove() {
$block->delete();
}
}
- if ($this->blockManager instanceof CachedDiscoveryInterface) {
- $this->blockManager->clearCachedDefinitions();
- }
}
}
diff --git a/core/modules/views_ui/tests/src/Functional/UITestBase.php b/core/modules/views_ui/tests/src/Functional/UITestBase.php
index db85773714..684b91f89d 100644
--- a/core/modules/views_ui/tests/src/Functional/UITestBase.php
+++ b/core/modules/views_ui/tests/src/Functional/UITestBase.php
@@ -76,8 +76,8 @@ protected function drupalGet($path, array $options = [], array $headers = []) {
$url = $this->buildUrl($path, $options);
// Ensure that each nojs page is accessible via ajax as well.
- if (strpos($url, '/nojs/') !== FALSE) {
- $url = preg_replace('|/nojs/|', '/ajax/', $url, 1);
+ if (strpos($url, 'nojs') !== FALSE) {
+ $url = str_replace('nojs', 'ajax', $url);
$result = $this->drupalGet($url, $options);
$this->assertSession()->statusCodeEquals(200);
$this->assertEquals('application/json', $this->getSession()->getResponseHeader('Content-Type'));
diff --git a/core/profiles/demo_umami/themes/umami/templates/components/messages/status-messages.html.twig b/core/profiles/demo_umami/themes/umami/templates/components/messages/status-messages.html.twig
index a5094701b4..1a65511a3d 100644
--- a/core/profiles/demo_umami/themes/umami/templates/components/messages/status-messages.html.twig
+++ b/core/profiles/demo_umami/themes/umami/templates/components/messages/status-messages.html.twig
@@ -19,6 +19,7 @@
* - class: HTML classes.
*/
#}
+
{% block messages %}
{% for type, messages in message_list %}
{%
@@ -53,3 +54,4 @@
{% set attributes = attributes.removeClass(classes) %}
{% endfor %}
{% endblock messages %}
+
diff --git a/core/tests/Drupal/FunctionalJavascriptTests/Core/JsMessageTest.php b/core/tests/Drupal/FunctionalJavascriptTests/Core/JsMessageTest.php
new file mode 100644
index 0000000000..14b4e8b625
--- /dev/null
+++ b/core/tests/Drupal/FunctionalJavascriptTests/Core/JsMessageTest.php
@@ -0,0 +1,119 @@
+install(['test_messages']);
+ $theme_config = \Drupal::configFactory()->getEditable('system.theme');
+ $theme_config->set('default', 'test_messages');
+ $theme_config->save();
+ }
+
+ /**
+ * Test click on links to show messages and remove messages.
+ */
+ public function testAddRemoveMessages() {
+ $web_assert = $this->assertSession();
+ $this->drupalGet('js_message_test_link');
+
+ $current_messages = [];
+ foreach (JsMessageTestCases::getMessagesSelectors() as $messagesSelector) {
+ $web_assert->elementExists('css', $messagesSelector);
+ foreach (JsMessageTestCases::getTypes() as $type) {
+ $this->click('[id="add-' . $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, "This is a message of the type, $type. You be the the judge of its importance.");
+ $current_messages[$selector] = ucfirst($type) . " message This is a message of the type, $type. You be the the judge of its importance.";
+ $this->assertCurrentMessages($current_messages, $messagesSelector);
+ }
+ // Remove messages 1 by 1 and confirm the messages are expected.
+ foreach (JsMessageTestCases::getTypes() as $type) {
+ $this->click('[id="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, $messagesSelector);
+ }
+ }
+
+ $messagesSelector = JsMessageTestCases::getMessagesSelectors()[0];
+ $current_messages = [];
+ $types = JsMessageTestCases::getTypes();
+ $nb_messages = count($types) * 2;
+ for ($i = 0; $i < $nb_messages; $i++) {
+ $current_messages[] = ucfirst($types[$i % count($types)]) . " message This is message number $i of the type, {$types[$i % count($types)]}. You be the the judge of its importance.";
+ }
+ // Test adding multiple messages at once.
+ // @see processMessages()
+ $this->click('[id="add-multiple"]');
+ $this->assertCurrentMessages($current_messages, $messagesSelector);
+ $this->click('[id="remove-multiple"]');
+ $this->assertCurrentMessages([], $messagesSelector);
+
+ $current_messages = [];
+ for ($i = 0; $i < $nb_messages; $i++) {
+ $current_messages[] = "Error message Msg-$i";
+ }
+ // The last message is of a different type and shouldn't get cleared.
+ $last_message = 'Status message Msg-' . count($current_messages);
+ $current_messages[] = $last_message;
+ $this->click('[id="add-multiple-error"]');
+ $this->assertCurrentMessages($current_messages, $messagesSelector);
+ $this->click('[id="remove-type"]');
+ $this->assertCurrentMessages([$last_message], $messagesSelector);
+ $this->click('[id="clear-all"]');
+ $this->assertCurrentMessages([], $messagesSelector);
+
+ // Confirm that when adding a message with an "id" specified but no status
+ // that it receives the default status.
+ $this->click('[id="id-no-status"]');
+ $no_status_msg = 'Status message Msg-id-no-status';
+ $this->assertCurrentMessages([$no_status_msg], $messagesSelector);
+ $web_assert->elementTextContains('css', "$messagesSelector .messages--status[data-drupal-message-id=\"my-special-id\"]", $no_status_msg);
+
+ }
+
+ /**
+ * Asserts that currently shown messages match expected messages.
+ *
+ * @param array $expected_messages
+ * Expected messages.
+ * @param string $messagesSelector
+ * The css selector for the containing messages element.
+ */
+ protected function assertCurrentMessages(array $expected_messages, $messagesSelector) {
+ $expected_messages = array_values($expected_messages);
+ $current_messages = [];
+ if ($message_divs = $this->getSession()->getPage()->findAll('css', "$messagesSelector .messages")) {
+ foreach ($message_divs as $message_div) {
+ /** @var \Behat\Mink\Element\NodeElement $message_div */
+ $current_messages[] = $message_div->getText();
+ }
+ }
+ $this->assertEquals($expected_messages, $current_messages);
+ }
+
+}
diff --git a/core/tests/Drupal/FunctionalTests/Routing/DefaultFormatTest.php b/core/tests/Drupal/FunctionalTests/Routing/DefaultFormatTest.php
deleted file mode 100644
index bf695d658b..0000000000
--- a/core/tests/Drupal/FunctionalTests/Routing/DefaultFormatTest.php
+++ /dev/null
@@ -1,32 +0,0 @@
-drupalGet('/default_format_test/human');
- $this->assertSame('format:html', $this->getSession()->getPage()->getContent());
- $this->assertSame('MISS', $this->drupalGetHeader('X-Drupal-Cache'));
-
- $this->drupalGet('/default_format_test/machine');
- $this->assertSame('format:json', $this->getSession()->getPage()->getContent());
- $this->assertSame('MISS', $this->drupalGetHeader('X-Drupal-Cache'));
- }
-
- public function testMultipleRoutesWithSameSingleFormat() {
- $this->drupalGet('/default_format_test/machine');
- $this->assertSame('format:json', $this->getSession()->getPage()->getContent());
- }
-
-}
diff --git a/core/tests/Drupal/KernelTests/Core/Config/ConfigInstallTest.php b/core/tests/Drupal/KernelTests/Core/Config/ConfigInstallTest.php
index 5efd20bbb1..9e473c29ff 100644
--- a/core/tests/Drupal/KernelTests/Core/Config/ConfigInstallTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Config/ConfigInstallTest.php
@@ -253,14 +253,6 @@ public function testLanguage() {
);
}
- /**
- * Tests installing configuration where the filename and ID do not match.
- */
- public function testIdMisMatch() {
- $this->setExpectedException(\PHPUnit_Framework_Error_Warning::class, 'The configuration name "config_test.dynamic.no_id_match" does not match the ID "does_not_match"');
- $this->installModules(['config_test_id_mismatch']);
- }
-
/**
* Installs a module.
*
diff --git a/core/tests/Drupal/KernelTests/Core/Theme/TwigEnvironmentTest.php b/core/tests/Drupal/KernelTests/Core/Theme/TwigEnvironmentTest.php
index c95b0545b9..c1be007b16 100644
--- a/core/tests/Drupal/KernelTests/Core/Theme/TwigEnvironmentTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Theme/TwigEnvironmentTest.php
@@ -111,35 +111,6 @@ public function testTemplateNotFoundException() {
}
}
- /**
- * Ensures that templates resolve to the same class name and cache file.
- */
- public function testTemplateClassname() {
- /** @var \Drupal\Core\Template\TwigEnvironment $environment */
- $environment = \Drupal::service('twig');
-
- // Test using an include template path.
- $name_include = 'container.html.twig';
- $class_include = $environment->getTemplateClass($name_include);
- $key_include = $environment->getCache()->generateKey($name_include, $class_include);
-
- // Test using a namespaced template path.
- $name_namespaced = '@system/container.html.twig';
- $class_namespaced = $environment->getTemplateClass($name_namespaced);
- $key_namespaced = $environment->getCache()->generateKey($name_namespaced, $class_namespaced);
-
- // Test using a direct filesystem template path.
- $name_direct = 'core/modules/system/templates/container.html.twig';
- $class_direct = $environment->getTemplateClass($name_direct);
- $key_direct = $environment->getCache()->generateKey($name_direct, $class_direct);
-
- // All three should be equal for both cases.
- $this->assertEqual($class_include, $class_namespaced);
- $this->assertEqual($class_namespaced, $class_direct);
- $this->assertEqual($key_include, $key_namespaced);
- $this->assertEqual($key_namespaced, $key_direct);
- }
-
/**
* Ensures that cacheFilename() varies by extensions + deployment identifier.
*/
diff --git a/core/tests/Drupal/Tests/Core/Render/RendererTest.php b/core/tests/Drupal/Tests/Core/Render/RendererTest.php
index 54037c57e9..adfc890cb0 100644
--- a/core/tests/Drupal/Tests/Core/Render/RendererTest.php
+++ b/core/tests/Drupal/Tests/Core/Render/RendererTest.php
@@ -89,26 +89,6 @@ public function providerTestRenderBasic() {
['#markup' => 'foo'],
'foo',
];
- // Basic #markup based renderable array with value '0'.
- $data[] = [
- ['#markup' => '0'],
- '0',
- ];
- // Basic #markup based renderable array with value 0.
- $data[] = [
- ['#markup' => 0],
- '0',
- ];
- // Basic #markup based renderable array with value ''.
- $data[] = [
- ['#markup' => ''],
- '',
- ];
- // Basic #markup based renderable array with value NULL.
- $data[] = [
- ['#markup' => NULL],
- '',
- ];
// Basic #plain_text based renderable array.
$data[] = [
['#plain_text' => 'foo'],
@@ -124,26 +104,6 @@ public function providerTestRenderBasic() {
['#plain_text' => Markup::create('foo')],
'<em>foo</em>',
];
- // #plain_text based renderable array with value '0'.
- $data[] = [
- ['#plain_text' => '0'],
- '0',
- ];
- // #plain_text based renderable array with value 0.
- $data[] = [
- ['#plain_text' => 0],
- '0',
- ];
- // #plain_text based renderable array with value ''.
- $data[] = [
- ['#plain_text' => ''],
- '',
- ];
- // #plain_text based renderable array with value NULL.
- $data[] = [
- ['#plain_text' => NULL],
- '',
- ];
// Renderable child element.
$data[] = [
['child' => ['#markup' => 'bar']],
diff --git a/core/tests/Drupal/Tests/Core/StackMiddleware/NegotiationMiddlewareTest.php b/core/tests/Drupal/Tests/Core/StackMiddleware/NegotiationMiddlewareTest.php
index 7b5217d4c5..10d2df8b8b 100644
--- a/core/tests/Drupal/Tests/Core/StackMiddleware/NegotiationMiddlewareTest.php
+++ b/core/tests/Drupal/Tests/Core/StackMiddleware/NegotiationMiddlewareTest.php
@@ -68,10 +68,10 @@ public function testFormatViaQueryParameter() {
*
* @covers ::getContentType
*/
- public function testUnknowContentTypeReturnsNull() {
+ public function testUnknowContentTypeReturnsHtmlByDefault() {
$request = new Request();
- $this->assertNull($this->contentNegotiation->getContentType($request));
+ $this->assertSame('html', $this->contentNegotiation->getContentType($request));
}
/**
@@ -83,7 +83,7 @@ public function testUnknowContentTypeButAjaxRequest() {
$request = new Request();
$request->headers->set('X-Requested-With', 'XMLHttpRequest');
- $this->assertNull($this->contentNegotiation->getContentType($request));
+ $this->assertSame('html', $this->contentNegotiation->getContentType($request));
}
/**
@@ -98,7 +98,7 @@ public function testHandle() {
$request->setFormat()->shouldNotBeCalled();
// Request format will be set with default format.
- $request->setRequestFormat()->shouldNotBeCalled();
+ $request->setRequestFormat('html')->shouldBeCalled();
// Some getContentType calls we don't really care about but have to mock.
$request_data = $this->prophesize(ParameterBag::class);
@@ -127,7 +127,7 @@ public function testSetFormat() {
$request->setFormat('david', 'geeky/david')->shouldBeCalled();
// Some calls we don't care about.
- $request->setRequestFormat()->shouldNotBeCalled();
+ $request->setRequestFormat('html')->shouldBeCalled();
$request_data = $this->prophesize(ParameterBag::class);
$request_data->get('ajax_iframe_upload', FALSE)->shouldBeCalled();
$request_mock = $request->reveal();
diff --git a/core/themes/bartik/css/components/messages.css b/core/themes/bartik/css/components/messages.css
index 15a550d0b9..7018da3a00 100644
--- a/core/themes/bartik/css/components/messages.css
+++ b/core/themes/bartik/css/components/messages.css
@@ -4,10 +4,15 @@
*/
.messages__wrapper {
- padding: 20px 0 5px 8px;
+ padding: 0 0 0 8px;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
- margin: 8px 0;
}
[dir="rtl"] .messages__wrapper {
- padding: 20px 8px 5px 0;
+ padding: 0 8px 0 0;
+}
+.messages:first-child {
+ margin-top: 28px;
+}
+.messages:last-child {
+ margin-bottom: 13px;
}
diff --git a/core/themes/classy/templates/misc/status-messages.html.twig b/core/themes/classy/templates/misc/status-messages.html.twig
index 2115b76f53..7dda6c040c 100644
--- a/core/themes/classy/templates/misc/status-messages.html.twig
+++ b/core/themes/classy/templates/misc/status-messages.html.twig
@@ -19,6 +19,7 @@
* - class: HTML classes.
*/
#}
+
{% block messages %}
{% for type, messages in message_list %}
{%
@@ -51,3 +52,4 @@
{% set attributes = attributes.removeClass(classes) %}
{% endfor %}
{% endblock messages %}
+
diff --git a/core/themes/stable/templates/misc/status-messages.html.twig b/core/themes/stable/templates/misc/status-messages.html.twig
index 41d3fbd318..969631d2d0 100644
--- a/core/themes/stable/templates/misc/status-messages.html.twig
+++ b/core/themes/stable/templates/misc/status-messages.html.twig
@@ -19,6 +19,7 @@
* - class: HTML classes.
*/
#}
+
{% for type, messages in message_list %}
{% if type == 'error' %}
@@ -41,3 +42,4 @@
{% endif %}
{% endfor %}
+