// SPDX-FileCopyrightText: 2022 Felix Hamann ,Gregor Kleen ,Sarah Vaupel // // SPDX-License-Identifier: AGPL-3.0-or-later import { Utility } from '../../core/utility'; import { EventManager, EventWrapper, EVENT_TYPE } from '../../lib/event-manager/event-manager'; 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; _eventManager; _boundResponseInterceptor; constructor(element, app) { if (!element) { throw new Error('Alerts util has to be called with an element!'); } this._element = element; this._app = app; this._eventManager = new EventManager(); this._boundResponseInterceptor = this._responseInterceptor.bind(this); if (this._element.classList.contains(ALERTS_INITIALIZED_CLASS)) { return false; } this._togglerElement = this._element.querySelector('.' + ALERTS_TOGGLER_CLASS); this._alertElements = this._gatherAlertElements(); // mark initialized this._element.classList.add(ALERTS_INITIALIZED_CLASS); } start() { if (this._togglerElement) { this._initToggler(); } this._initAlerts(); // register http client interceptor to filter out Alerts Header this._setupHttpInterceptor(); } destroy() { this._eventManager.cleanUp(); this._app.httpClient.removeResponseInterceptor(this._boundResponseInterceptor); if(this._alertElements) { this._alertElements.forEach(element => element.remove()); } if(this._element.classList.contains(ALERTS_INITIALIZED_CLASS)) this._element.classList.remove(ALERTS_INITIALIZED_CLASS); } _gatherAlertElements() { return Array.from(this._element.querySelectorAll('.' + ALERT_CLASS)).filter(function(alert) { return !alert.classList.contains(ALERT_INITIALIZED_CLASS); }); } _initToggler() { let clickListenerToggler = new EventWrapper(EVENT_TYPE.CLICK, () => { this._alertElements.forEach((alertEl) => this._toggleAlert(alertEl, true)); this._togglerElement.classList.remove(ALERTS_TOGGLER_VISIBLE_CLASS); }, this._togglerElement); this._eventManager.registerNewListener(clickListenerToggler); } _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); const closeAlertEvent = new EventWrapper(EVENT_TYPE.CLICK, (() => { this._toggleAlert(alertElement); }).bind(this), closeEl); this._eventManager.registerNewListener(closeAlertEvent); 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._boundResponseInterceptor); } _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 = 'notification-info') { 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, 'ico-' + 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; } }