summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Carver2018-12-05 23:43:40 (GMT)
committerMark Carver2018-12-05 23:43:40 (GMT)
commitd33fe477180da110fc07c111d5b02b91172b810c (patch)
tree7d838c8c9b7eee74975bf9a5b5e7dad6b4052f8d
parent2e53e0db69fc7812c311b60998e6145d527fb8ff (diff)
Issue #3018412 by markcarver: Add support for JavaScript Message API8.x-3.16
-rw-r--r--bootstrap.info.yml2
-rw-r--r--bootstrap.libraries.yml4
-rw-r--r--js/misc/message.js181
-rw-r--r--templates/system/status-messages.html.twig60
4 files changed, 223 insertions, 24 deletions
diff --git a/bootstrap.info.yml b/bootstrap.info.yml
index 4e4c30a..90d0ca8 100644
--- a/bootstrap.info.yml
+++ b/bootstrap.info.yml
@@ -31,6 +31,8 @@ libraries-extend:
- bootstrap/drupal.dialog.ajax
core/drupal.form:
- bootstrap/drupal.form
+ core/drupal.message:
+ - bootstrap/drupal.message
core/drupal.progress:
- bootstrap/drupal.progress
core/drupal.states:
diff --git a/bootstrap.libraries.yml b/bootstrap.libraries.yml
index f51ce5b..9640b63 100644
--- a/bootstrap.libraries.yml
+++ b/bootstrap.libraries.yml
@@ -101,6 +101,10 @@ drupal.form:
dependencies:
- bootstrap/theme
+drupal.message:
+ js:
+ js/misc/message.js: {}
+
drupal.progress:
js:
js/misc/progress.js: {}
diff --git a/js/misc/message.js b/js/misc/message.js
new file mode 100644
index 0000000..845553e
--- /dev/null
+++ b/js/misc/message.js
@@ -0,0 +1,181 @@
+/**
+ * @file
+ * message.js
+ */
+(function ($, Drupal) {
+
+ /**
+ * Retrieves the classes for a specific message type.
+ *
+ * @param {String} type
+ * The type of message.
+ *
+ * @return {String}
+ * The classes to add, space separated.
+ */
+ Drupal.Message.getMessageTypeClass = function (type) {
+ var classes = this.getMessageTypeClasses();
+ return 'alert alert-' + (classes[type] || 'success');
+ };
+
+ /**
+ * Helper function to map Drupal types to Bootstrap classes.
+ *
+ * @return {Object<String, String>}
+ * A map of classes, keyed by message type.
+ */
+ Drupal.Message.getMessageTypeClasses = function () {
+ return {
+ status: 'success',
+ error: 'danger',
+ warning: 'warning',
+ info: 'info',
+ };
+ };
+
+ /**
+ * Retrieves a label for a specific message type.
+ *
+ * @param {String} type
+ * The type of message.
+ *
+ * @return {String}
+ * The message type label.
+ */
+ Drupal.Message.getMessageTypeLabel = function (type) {
+ var labels = this.getMessageTypeLabels();
+ return labels[type];
+ };
+
+ /**
+ * @inheritDoc
+ */
+ Drupal.Message.getMessageTypeLabels = function () {
+ return {
+ status: Drupal.t('Status message'),
+ error: Drupal.t('Error message'),
+ warning: Drupal.t('Warning message'),
+ info: Drupal.t('Informative message'),
+ };
+ };
+
+ /**
+ * Retrieves the aria-role for a specific message type.
+ *
+ * @param {String} type
+ * The type of message.
+ *
+ * @return {String}
+ * The message type role.
+ */
+ Drupal.Message.getMessageTypeRole = function (type) {
+ var labels = this.getMessageTypeRoles();
+ return labels[type];
+ };
+
+ /**
+ * Map of the message type aria-role values.
+ *
+ * @return {Object<String, String>}
+ * A map of roles, keyed by message type.
+ */
+ Drupal.Message.getMessageTypeRoles = function () {
+ return {
+ status: 'status',
+ error: 'alert',
+ warning: 'alert',
+ info: 'status',
+ };
+ };
+
+ /**
+ * @inheritDoc
+ */
+ Drupal.theme.message = function (message, options) {
+ options = options || {};
+ var wrapper = Drupal.theme('messageWrapper', options.id || (new Date()).getTime(), options.type || 'status');
+
+ if (options.dismissible === void 0 || !!options.dismissible) {
+ wrapper.classList.add('alert-dismissible');
+ wrapper.appendChild(Drupal.theme('messageClose'));
+ }
+
+ wrapper.appendChild(Drupal.theme('messageContents', message && message.text));
+
+ return wrapper;
+ };
+
+ /**
+ * Themes the message container.
+ *
+ * @param {String} id
+ * The message identifier.
+ * @param {String} type
+ * The type of message.
+ *
+ * @return {HTMLElement}
+ * A constructed HTMLElement.
+ */
+ Drupal.theme.messageWrapper = function (id, type) {
+ var wrapper = document.createElement('div');
+ var label = Drupal.Message.getMessageTypeLabel(type);
+ wrapper.setAttribute('class', Drupal.Message.getMessageTypeClass(type));
+ wrapper.setAttribute('role', Drupal.Message.getMessageTypeRole(type));
+ wrapper.setAttribute('aria-label', label);
+ wrapper.setAttribute('data-drupal-message-id', id);
+ wrapper.setAttribute('data-drupal-message-type', type);
+ if (label) {
+ wrapper.appendChild(Drupal.theme('messageLabel', label));
+ }
+ return wrapper;
+ };
+
+ /**
+ * Themes the message close button.
+ *
+ * @return {HTMLElement}
+ * A constructed HTMLElement.
+ */
+ Drupal.theme.messageClose = function () {
+ var element = document.createElement('button');
+ element.setAttribute('class', 'close');
+ element.setAttribute('type', 'button');
+ element.setAttribute('role', 'button');
+ element.setAttribute('data-dismiss', 'alert');
+ element.setAttribute('aria-label', Drupal.t('Close'));
+ element.innerHTML = '<span aria-hidden="true">&times;</span>';
+ return element;
+ };
+
+ /**
+ * Themes the message container.
+ *
+ * @param {String} label
+ * The message label.
+ *
+ * @return {HTMLElement}
+ * A constructed HTMLElement.
+ */
+ Drupal.theme.messageLabel = function (label) {
+ var element = document.createElement('h2');
+ element.setAttribute('class', 'sr-only');
+ element.innerHTML = label;
+ return element;
+ };
+
+ /**
+ * Themes the message contents.
+ *
+ * @param {String} html
+ * The message identifier.
+ *
+ * @return {HTMLElement}
+ * A constructed HTMLElement.
+ */
+ Drupal.theme.messageContents = function (html) {
+ var element = document.createElement('p');
+ element.innerHTML = '' + html;
+ return element;
+ }
+
+})(window.jQuery, window.Drupal);
diff --git a/templates/system/status-messages.html.twig b/templates/system/status-messages.html.twig
index 7a2295a..19f88b8 100644
--- a/templates/system/status-messages.html.twig
+++ b/templates/system/status-messages.html.twig
@@ -44,28 +44,40 @@
'info': 'info',
}
%}
-{% for type, messages in message_list %}
- {%
- set message_classes = [
- 'alert',
- 'alert-' ~ status_classes[type],
- 'alert-dismissible',
- ]
- %}
- {# Reset the attribute classes and then add the message specific classes. #}
- <div{{ attributes.setAttribute('class', classes).addClass(message_classes).setAttribute('role', 'alert') }}>
- <button type="button" role="button" class="close" data-dismiss="alert" aria-label="{{ 'Close'|t }}"><span aria-hidden="true">&times;</span></button>
- {% if status_headings[type] %}
- <h4 class="sr-only">{{ status_headings[type] }}</h4>
- {% endif %}
- {% if messages|length > 1 %}
- <ul class="item-list item-list--messages">
- {% for message in messages %}
- <li class="item item--message">{{ message }}</li>
- {% endfor %}
- </ul>
- {% else %}
- {{ messages|first }}
- {% endif %}
+{%
+ set status_roles = {
+ 'status': 'status',
+ 'error': 'alert',
+ 'warning': 'alert',
+ 'info': 'status',
+ }
+%}
+<div data-drupal-messages>
+ <div class="messages__wrapper">
+ {% for type, messages in message_list %}
+ {%
+ set message_classes = [
+ 'alert',
+ 'alert-' ~ status_classes[type],
+ 'alert-dismissible',
+ ]
+ %}
+ {# Reset the attribute classes and then add the message specific classes. #}
+ <div{{ attributes.setAttribute('class', classes).addClass(message_classes).setAttribute('role', status_roles[type]).setAttribute('aria-label', status_headings[type]) }}>
+ <button type="button" role="button" class="close" data-dismiss="alert" aria-label="{{ 'Close'|t }}"><span aria-hidden="true">&times;</span></button>
+ {% if status_headings[type] %}
+ <h2 class="sr-only">{{ status_headings[type] }}</h2>
+ {% endif %}
+ {% if messages|length > 1 %}
+ <ul class="item-list item-list--messages">
+ {% for message in messages %}
+ <li class="item item--message">{{ message }}</li>
+ {% endfor %}
+ </ul>
+ {% else %}
+ <p>{{ messages|first }}</p>
+ {% endif %}
+ </div>
+ {% endfor %}
</div>
-{% endfor %}
+</div>