1class AlertElement extends HTMLElement { 2 constructor() { 3 super(); 4 5 // Bindings 6 this.close = this.close.bind(this); 7 this.destroyCloseButton = this.destroyCloseButton.bind(this); 8 this.createCloseButton = this.createCloseButton.bind(this); 9 this.onMutation = this.onMutation.bind(this); 10 this.observer = new MutationObserver(this.onMutation); 11 this.observer.observe(this, { 12 attributes: false, 13 childList: true, 14 subtree: true 15 }); 16 17 // Handle the fade in animation 18 this.addEventListener('animationend', event => { 19 if (event.animationName === 'joomla-alert-fade-in' && event.target === this) { 20 this.dispatchEvent(new CustomEvent('joomla.alert.shown')); 21 this.style.removeProperty('animationName'); 22 } 23 }); 24 25 // Handle the fade out animation 26 this.addEventListener('animationend', event => { 27 if (event.animationName === 'joomla-alert-fade-out' && event.target === this) { 28 this.dispatchEvent(new CustomEvent('joomla.alert.closed')); 29 this.remove(); 30 } 31 }); 32 } 33 34 /* Attributes to monitor */ 35 static get observedAttributes() { 36 return ['type', 'role', 'dismiss', 'auto-dismiss', 'close-text']; 37 } 38 get type() { 39 return this.getAttribute('type'); 40 } 41 set type(value) { 42 this.setAttribute('type', value); 43 } 44 get role() { 45 return this.getAttribute('role'); 46 } 47 set role(value) { 48 this.setAttribute('role', value); 49 } 50 get closeText() { 51 return this.getAttribute('close-text'); 52 } 53 set closeText(value) { 54 this.setAttribute('close-text', value); 55 } 56 get dismiss() { 57 return this.getAttribute('dismiss'); 58 } 59 set dismiss(value) { 60 this.setAttribute('dismiss', value); 61 } 62 get autodismiss() { 63 return this.getAttribute('auto-dismiss'); 64 } 65 set autodismiss(value) { 66 this.setAttribute('auto-dismiss', value); 67 } 68 69 /* Lifecycle, element appended to the DOM */ 70 connectedCallback() { 71 this.dispatchEvent(new CustomEvent('joomla.alert.show')); 72 this.style.animationName = 'joomla-alert-fade-in'; 73 74 // Default to info 75 if (!this.type || !['info', 'warning', 'danger', 'success'].includes(this.type)) { 76 this.setAttribute('type', 'info'); 77 } 78 // Default to alert 79 if (!this.role || !['alert', 'alertdialog'].includes(this.role)) { 80 this.setAttribute('role', 'alert'); 81 } 82 83 // Hydrate the button 84 if (this.firstElementChild && this.firstElementChild.tagName === 'BUTTON') { 85 this.button = this.firstElementChild; 86 if (this.button.classList.contains('joomla-alert--close')) { 87 this.button.classList.add('joomla-alert--close'); 88 } 89 if (this.button.innerHTML === '') { 90 this.button.innerHTML = '<span aria-hidden="true">×</span>'; 91 } 92 if (!this.button.hasAttribute('aria-label')) { 93 this.button.setAttribute('aria-label', this.closeText); 94 } 95 } 96 97 // Append button 98 if (this.hasAttribute('dismiss') && !this.button) { 99 this.createCloseButton(); 100 } 101 if (this.hasAttribute('auto-dismiss')) { 102 this.autoDismiss(); 103 } 104 } 105 106 /* Lifecycle, element removed from the DOM */ 107 disconnectedCallback() { 108 if (this.button) { 109 this.button.removeEventListener('click', this.close); 110 } 111 this.observer.disconnect(); 112 } 113 114 /* Respond to attribute changes */ 115 attributeChangedCallback(attr, oldValue, newValue) { 116 switch (attr) { 117 case 'type': 118 if (!newValue || newValue && ['info', 'warning', 'danger', 'success'].indexOf(newValue) === -1) { 119 this.type = 'info'; 120 } 121 break; 122 case 'role': 123 if (!newValue || newValue && ['alert', 'alertdialog'].indexOf(newValue) === -1) { 124 this.role = 'alert'; 125 } 126 break; 127 case 'dismiss': 128 if ((!newValue || newValue === '') && (!oldValue || oldValue === '')) { 129 if (this.button && !this.hasAttribute('dismiss')) { 130 this.destroyCloseButton(); 131 } else if (!this.button && this.hasAttribute('dismiss')) { 132 this.createCloseButton(); 133 } 134 } else if (this.button && newValue === 'false') { 135 this.destroyCloseButton(); 136 } else if (!this.button && newValue !== 'false') { 137 this.createCloseButton(); 138 } 139 break; 140 case 'close-text': 141 if (!newValue || newValue !== oldValue) { 142 if (this.button) { 143 this.button.setAttribute('aria-label', newValue); 144 } 145 } 146 break; 147 case 'auto-dismiss': 148 this.autoDismiss(); 149 break; 150 } 151 } 152 153 /* Observe added elements */ 154 onMutation(mutationsList) { 155 // eslint-disable-next-line no-restricted-syntax 156 for (const mutation of mutationsList) { 157 if (mutation.type === 'childList') { 158 if (mutation.addedNodes.length) { 159 // Make sure that the button is always the first element 160 if (this.button && this.firstElementChild !== this.button) { 161 this.prepend(this.button); 162 } 163 } 164 } 165 } 166 } 167 168 /* Method to close the alert */ 169 close() { 170 this.dispatchEvent(new CustomEvent('joomla.alert.close')); 171 this.style.animationName = 'joomla-alert-fade-out'; 172 } 173 174 /* Method to create the close button */ 175 createCloseButton() { 176 this.button = document.createElement('button'); 177 this.button.setAttribute('type', 'button'); 178 this.button.classList.add('joomla-alert--close'); 179 this.button.innerHTML = '<span aria-hidden="true">×</span>'; 180 this.button.setAttribute('aria-label', this.closeText); 181 this.insertAdjacentElement('afterbegin', this.button); 182 183 /* Add the required listener */ 184 this.button.addEventListener('click', this.close); 185 } 186 187 /* Method to remove the close button */ 188 destroyCloseButton() { 189 if (this.button) { 190 this.button.removeEventListener('click', this.close); 191 this.button.parentNode.removeChild(this.button); 192 this.button = null; 193 } 194 } 195 196 /* Method to auto-dismiss */ 197 autoDismiss() { 198 const timer = parseInt(this.getAttribute('auto-dismiss'), 10); 199 setTimeout(this.close, timer >= 10 ? timer : 3000); 200 } 201} 202if (!customElements.get('joomla-alert')) { 203 customElements.define('joomla-alert', AlertElement); 204} 205 206/** 207 * @copyright (C) 2020 Open Source Matters, Inc. <https://www.joomla.org> 208 * @license GNU General Public License version 2 or later; see LICENSE.txt 209 */ 210 211/** 212 * Returns the container of the Messages 213 * 214 * @param {string|HTMLElement} container The container 215 * 216 * @returns {HTMLElement} 217 */ 218const getMessageContainer = container => { 219 let messageContainer; 220 if (container instanceof HTMLElement) { 221 return container; 222 } 223 if (typeof container === 'undefined' || container && container === '#system-message-container') { 224 messageContainer = document.getElementById('system-message-container'); 225 } else { 226 messageContainer = document.querySelector(container); 227 } 228 return messageContainer; 229}; 230 231/** 232 * Render messages send via JSON 233 * Used by some javascripts such as validate.js 234 * 235 * @param {object}
235 messages JavaScript object containing the messages to render. 236 * Example: 237 * const messages = { 238 * "message": ["This will be a green message", "So will this"], 239 * "error": ["This will be a red message", "So will this"], 240 * "info": ["This will be a blue message", "So will this"], 241 * "notice": ["This will be same as info message", "So will this"], 242 * "warning": ["This will be a orange message", "So will this"], 243 * "my_custom_type": ["This will be same as info message", "So will this"] 244 * }; 245 * @param {string} selector The selector of the container where the message will be rendered 246 * @param {bool} keepOld If we shall discard old messages 247 * @param {int} timeout The milliseconds before the message self destruct 248 * @return void 249 */ 250Joomla.renderMessages = (messages, selector, keepOld, timeout) => { 251 const messageContainer = getMessageContainer(selector); 252 if (typeof keepOld === 'undefined' || keepOld && keepOld === false) { 253 Joomla.removeMessages(messageContainer); 254 } 255 [].slice.call(Object.keys(messages)).forEach(type => { 256 let alertClass = type; 257 258 // Array of messages of this type 259 const typeMessages = messages[type]; 260 const messagesBox = document.createElement('joomla-alert');
261 if (['success', 'info', 'danger', 'warning'].indexOf(type) < 0) { 262 alertClass = type === 'notice' ? 'info' : type; 263 alertClass = type === 'message' ? 'success' : alertClass; 264 alertClass = type === 'error' ? 'danger' : alertClass; 265 alertClass = type === 'warning' ? 'warning' : alertClass; 266 } 267 messagesBox.setAttribute('type', alertClass); 268 messagesBox.setAttribute('close-text', Joomla.Text._('JCLOSE')); 269 messagesBox.setAttribute('dismiss', true); 270 if (timeout && parseInt(timeout, 10) > 0) { 271 messagesBox.setAttribute('auto-dismiss', timeout); 272 } 273 274 // Title 275 const title = Joomla.Text._(type); 276 277 // Skip titles with untranslated strings 278 if (typeof title !== 'undefined') { 279 const titleWrapper = document.createElement('div'); 280 titleWrapper.className = 'alert-heading'; 281 titleWrapper.innerHTML = Joomla.sanitizeHtml(`<span class="${type}"></span><span class="visually-hidden">${Joomla.Text._(type) ? Joomla.Text._(type) : type}</span>`); 282 messagesBox.appendChild(titleWrapper); 283 } 284 285 // Add messages to the message box 286 const messageWrapper = document.createElement('div'); 287 messageWrapper.className = 'alert-wrapper'; 288 typeMessages.forEach(typeMessage => { 289 messageWrapper.innerHTML += Joomla.sanitizeHtml(`<div class="alert-message">${typeMessage}</div>`); 290 }); 291 messagesBox.appendChild(messageWrapper); 292 messageContainer.appendChild(messagesBox); 293 }); 294}; 295 296/** 297 * Remove messages 298 * 299 * @param {element} container The element of the container of the message 300 * to be removed 301 * 302 * @return {void} 303 */ 304Joomla.removeMessages = container => { 305 const messageContainer = getMessageContainer(container); 306 const alerts = [].slice.call(messageContainer.querySelectorAll('joomla-alert')); 307 if (alerts.length) { 308 alerts.forEach(alert => { 309 alert.close(); 310 }); 311 } 312}; 313document.addEventListener('DOMContentLoaded', () => { 314 const messages = Joomla.getOptions('joomla.messages'); 315 if (messages) { 316 Object.keys(messages).map(message => Joomla.renderMessages(messages[message], undefined, true, undefined)); 317 } 318});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.