This repository has been archived on 2024-10-24. You can view files and clone it, but cannot push or open issues or pull requests.
fradrive-old/frontend/src/utils/alerts/alerts.js
2024-05-23 01:24:44 +00:00

195 lines
5.8 KiB
JavaScript

// SPDX-FileCopyrightText: 2022 Felix Hamann <felix.hamann@campus.lmu.de>,Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>
//
// 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;
}
}