first commit
This commit is contained in:
@@ -0,0 +1,256 @@
|
||||
/**
|
||||
* @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(messageWrapper = null) {
|
||||
if (!messageWrapper) {
|
||||
this.messageWrapper = Drupal.Message.defaultWrapper();
|
||||
} else {
|
||||
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.classList.remove('hidden');
|
||||
}
|
||||
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.
|
||||
* @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 emptry 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';
|
||||
}
|
||||
|
||||
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 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().`,
|
||||
);
|
||||
}
|
||||
|
||||
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 }, { 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('data-drupal-message-id', id);
|
||||
messageWrapper.setAttribute('data-drupal-message-type', type);
|
||||
|
||||
messageWrapper.setAttribute('aria-label', messagesTypes[type]);
|
||||
|
||||
messageWrapper.innerHTML = `${text}`;
|
||||
|
||||
return messageWrapper;
|
||||
};
|
||||
})(Drupal);
|
||||
Reference in New Issue
Block a user