import { Utility } from '../../core/utility'; import './alerts.sass'; const ALERTS_INITIALIZED_CLASS = 'alerts--initialized'; const ALERTS_ELEVATED_CLASS = 'alerts--elevated'; const ALERTS_TOGGLER_CLASS = 'alerts__toggler'; const ALERTS_TOGGLER_VISIBLE_CLASS = 'alerts__toggler--visible'; const ALERTS_TOGGLER_APPEAR_DELAY = 120; const ALERT_CLASS = 'alert'; const ALERT_INITIALIZED_CLASS = 'alert--initialized'; const ALERT_CLOSER_CLASS = 'alert__closer'; const ALERT_ICON_CLASS = 'alert__icon'; const ALERT_CONTENT_CLASS = 'alert__content'; const ALERT_INVISIBLE_CLASS = 'alert--invisible'; const ALERT_AUTO_HIDE_DELAY = 10; const ALERT_AUTOCLOSING_MATCHER = '.alert-info, .alert-success'; /* * Dataset-Inputs: * - decay (data-decay): Custom time (in seconds) for this alert to stay visible */ @Utility({ selector: '[uw-alerts]', }) export class Alerts { _togglerCheckRequested = false; _togglerElement; _alertElements; _element; _app; constructor(element, app) { if (!element) { throw new Error('Alerts util has to be called with an element!'); } this._element = element; this._app = app; if (this._element.classList.contains(ALERTS_INITIALIZED_CLASS)) { return false; } this._togglerElement = this._element.querySelector('.' + ALERTS_TOGGLER_CLASS); this._alertElements = this._gatherAlertElements(); if (this._togglerElement) { this._initToggler(); } this._initAlerts(); // register http client interceptor to filter out Alerts Header this._setupHttpInterceptor(); // mark initialized this._element.classList.add(ALERTS_INITIALIZED_CLASS); } destroy() { console.log('TBD: Destroy Alert'); } _gatherAlertElements() { return Array.from(this._element.querySelectorAll('.' + ALERT_CLASS)).filter(function(alert) { return !alert.classList.contains(ALERT_INITIALIZED_CLASS); }); } _initToggler() { this._togglerElement.addEventListener('click', () => { this._alertElements.forEach((alertEl) => this._toggleAlert(alertEl, true)); this._togglerElement.classList.remove(ALERTS_TOGGLER_VISIBLE_CLASS); }); } _initAlerts() { this._alertElements.forEach((alert) => this._initAlert(alert)); } _initAlert(alertElement) { let autoHideDelay = ALERT_AUTO_HIDE_DELAY; if (alertElement.dataset.decay) { autoHideDelay = parseInt(alertElement.dataset.decay, 10); } const closeEl = alertElement.querySelector('.' + ALERT_CLOSER_CLASS); closeEl.addEventListener('click', () => { this._toggleAlert(alertElement); }); if (autoHideDelay > 0 && alertElement.matches(ALERT_AUTOCLOSING_MATCHER)) { window.setTimeout(() => this._toggleAlert(alertElement), autoHideDelay * 1000); } } _toggleAlert(alertEl, visible) { alertEl.classList.toggle(ALERT_INVISIBLE_CLASS, !visible); this._checkToggler(); } _checkToggler() { if (this._togglerCheckRequested) { return; } const alertsHidden = this._alertElements.reduce(function(acc, alert) { return acc && alert.classList.contains(ALERT_INVISIBLE_CLASS); }, true); window.setTimeout(() => { this._togglerElement.classList.toggle(ALERTS_TOGGLER_VISIBLE_CLASS, alertsHidden); this._togglerCheckRequested = false; }, ALERTS_TOGGLER_APPEAR_DELAY); } _setupHttpInterceptor() { this._app.httpClient.addResponseInterceptor(this._responseInterceptor.bind(this)); } _elevateAlerts() { this._element.classList.add(ALERTS_ELEVATED_CLASS); } _responseInterceptor = (response) => { let alerts; for (const header of response.headers) { if (header[0] === 'alerts') { const decodedHeader = decodeURIComponent(header[1]); alerts = JSON.parse(decodedHeader); break; } } if (alerts) { alerts.forEach((alert) => { const alertElement = this._createAlertElement(alert.status, alert.content, alert.icon === null ? undefined : alert.icon); this._element.appendChild(alertElement); this._alertElements.push(alertElement); this._initAlert(alertElement); }); this._elevateAlerts(); } } _createAlertElement(type, content, icon = 'info-circle') { const alertElement = document.createElement('div'); alertElement.classList.add(ALERT_CLASS, 'alert-' + type); const alertCloser = document.createElement('div'); alertCloser.classList.add(ALERT_CLOSER_CLASS); const alertIcon = document.createElement('div'); alertIcon.classList.add(ALERT_ICON_CLASS, 'fas', 'fa-' + icon); const alertContent = document.createElement('div'); alertContent.classList.add(ALERT_CONTENT_CLASS); alertContent.innerHTML = content; alertElement.appendChild(alertCloser); alertElement.appendChild(alertIcon); alertElement.appendChild(alertContent); return alertElement; } }