diff options
Diffstat (limited to 'core/misc/message.js')
-rw-r--r-- | core/misc/message.js | 221 |
1 files changed, 178 insertions, 43 deletions
diff --git a/core/misc/message.js b/core/misc/message.js index fd899e0ceba..9db487cd908 100644 --- a/core/misc/message.js +++ b/core/misc/message.js @@ -1,15 +1,27 @@ /** -* DO NOT EDIT THIS FILE. -* See the following change record for more information, -* https://www.drupal.org/node/2815083 -* @preserve -**/ - -(Drupal => { + * @file + * Message API. + */ +((Drupal) => { + /** + * @typedef {class} Drupal.Message~messageDefinition + */ + + /** + * Constructs a new instance of the Drupal.Message class. + * + * 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} + * Class to add and remove messages. + */ Drupal.Message = class { - constructor() { - let messageWrapper = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; - + constructor(messageWrapper = null) { if (!messageWrapper) { this.messageWrapper = Drupal.Message.defaultWrapper(); } else { @@ -17,30 +29,65 @@ } } + /** + * 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.classList.remove('hidden'); } - - return wrapper.innerHTML === '' ? Drupal.Message.messageInternalWrapper(wrapper) : wrapper.firstElementChild; + 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') + warning: Drupal.t('Warning message'), }; } - add(message) { - let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - + /** + * 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. + * @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 an explicit selector for a message. + * @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 an empty string. + * @param {string} [options.priority] + * Priority of the message for Drupal.announce(). + * + * @return {string} + * ID of message. + */ + add(message, options = {}) { if (!options.hasOwnProperty('type')) { options.type = 'status'; } @@ -49,71 +96,159 @@ throw new Error('Message must be a string.'); } + // Send message to screen reader. Drupal.Message.announce(message, options); - options.id = options.id ? String(options.id) : `${options.type}-${Math.random().toFixed(15).replace('0.', '')}`; - + /** + * Use the provided index for the message or generate a pseudo-random 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)) { - const { - type - } = options; - throw new Error(`The message type, ${type}, is not present in Drupal.Message.getMessageTypeLabels().`); + const { type } = options; + throw new Error( + `The message type, ${type}, is not present in Drupal.Message.getMessageTypeLabels().`, + ); } - this.messageWrapper.appendChild(Drupal.theme('message', { - text: message - }, options)); + 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}"]`); + 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); - }); + 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')) { + 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; } - }; - Drupal.theme.message = (_ref, _ref2) => { - let { - text - } = _ref; - let { - type, - id - } = _ref2; + /** + * 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 }, { type, id }) => { const messagesTypes = Drupal.Message.getMessageTypeLabels(); const messageWrapper = document.createElement('div'); + messageWrapper.setAttribute('class', `messages messages--${type}`); - messageWrapper.setAttribute('role', type === 'error' || type === 'warning' ? 'alert' : 'status'); + messageWrapper.setAttribute( + 'role', + type === 'error' || type === 'warning' ? 'alert' : 'status', + ); messageWrapper.setAttribute('data-drupal-message-id', id); messageWrapper.setAttribute('data-drupal-message-type', type); + messageWrapper.setAttribute('aria-label', messagesTypes[type]); + messageWrapper.innerHTML = `${text}`; + return messageWrapper; }; -})(Drupal);
\ No newline at end of file +})(Drupal); |