123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- /**
- * @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);
|