diff --git a/src/Foundation.hs b/src/Foundation.hs index 1e9d7451f..b834b1dab 100644 --- a/src/Foundation.hs +++ b/src/Foundation.hs @@ -1068,8 +1068,8 @@ siteLayout' headingOverride widget = do addScript $ StaticR js_services_utilRegistry_js addScript $ StaticR js_services_httpClient_js addScript $ StaticR js_services_i18n_js - -- addScript $ StaticR js_utils_alerts_js -- JavaScript utils + addScript $ StaticR js_utils_alerts_js addScript $ StaticR js_utils_asidenav_js addScript $ StaticR js_utils_asyncForm_js addScript $ StaticR js_utils_asyncTable_js diff --git a/static/css/utils/alerts.scss b/static/css/utils/alerts.scss index 3256eef96..bd6b55bfd 100644 --- a/static/css/utils/alerts.scss +++ b/static/css/utils/alerts.scss @@ -1,23 +1,3 @@ -/* ALERTS */ -/** - .alert - Regular Info Alert - Disappears automatically after 30 seconds - Disappears after x seconds if explicitly specified via data-decay='x' - Can be told not to disappear with data-decay='0' - - .alert-success - Disappears automatically after 30 seconds - - .alert-warning - Does not disappear - Orange regardless of user's selected theme - - .alert-error - Does not disappear - Red regardless of user's selected theme - - */ .alerts { position: fixed; bottom: 0; diff --git a/static/js/utils/alerts.js b/static/js/utils/alerts.js index b854495a0..8b2ba92fb 100644 --- a/static/js/utils/alerts.js +++ b/static/js/utils/alerts.js @@ -1,68 +1,126 @@ (function() { 'use strict'; - window.utils = window.utils || {}; + /** + * + * Alerts Utility + * makes alerts interactive + * + * Attribute: uw-alerts + * + * Types of alerts: + * [default] + * Regular Info Alert + * Disappears automatically after 30 seconds + * Disappears after x seconds if explicitly specified via data-decay='x' + * Can be told not to disappear with data-decay='0' + * + * [success] + * Currently no special visual appearance + * Disappears automatically after 30 seconds + * + * [warning] + * Will be coloured warning-orange regardless of user's selected theme + * Does not disappear + * + * [error] + * Will be coloured error-red regardless of user's selected theme + * Does not disappear + * + * Example usage: + *
+ *
+ *
+ *
+ *
+ *
+ * This is some information + * + */ - var ALERTS_CLASS = 'alerts'; + var ALERTS_UTIL_NAME = 'alerts'; + var ALERTS_UTIL_SELECTOR = '[uw-alerts]'; + + var ALERTS_INITIALIZED_CLASS = 'alerts--initialized'; var ALERTS_TOGGLER_CLASS = 'alerts__toggler'; var ALERTS_TOGGLER_VISIBLE_CLASS = 'alerts__toggler--visible'; var ALERTS_TOGGLER_APPEAR_DELAY = 120; var ALERT_CLASS = 'alert'; + var ALERT_INITIALIZED_CLASS = 'alert--initialized'; var ALERT_CLOSER_CLASS = 'alert__closer'; var ALERT_INVISIBLE_CLASS = 'alert--invisible'; var ALERT_AUTO_HIDE_DELAY = 10; var ALERT_AUTOCLOSING_MATCHER = '.alert-info, .alert-success'; - var JS_INITIALIZED_CLASS = 'js-initialized'; - - window.utils.alerts = function(alertsEl) { - - if (alertsEl.classList.contains(JS_INITIALIZED_CLASS)) { - return false; - } - - if (!alertsEl || !alertsEl.classList.contains(ALERTS_CLASS)) { - throw new Error('utils.alerts has to be called with alerts element'); - } - + var alertsUtil = function(element) { var togglerCheckRequested = false; + var togglerElement; + var alertElements; - var togglerEl = alertsEl.querySelector('.' + ALERTS_TOGGLER_CLASS); + function init() { + if (!element) { + throw new Error('Alerts util has to be called with an element!'); + } - var alertElements = Array.from(alertsEl.querySelectorAll('.' + ALERT_CLASS)) - .filter(function(alert) { - return !alert.classList.contains(JS_INITIALIZED_CLASS); + if (element.classList.contains(ALERTS_INITIALIZED_CLASS)) { + return false; + } + + togglerElement = element.querySelector('.' + ALERTS_TOGGLER_CLASS); + alertElements = gatherAlertElements(); + + initToggler(); + initAlerts(); + + // mark initialized + element.classList.add(ALERTS_INITIALIZED_CLASS); + + return { + name: ALERTS_UTIL_NAME, + element: element, + destroy: function() {}, + }; + } + + function gatherAlertElements() { + return Array.from(element.querySelectorAll('.' + ALERT_CLASS)).filter(function(alert) { + return !alert.classList.contains(ALERT_INITIALIZED_CLASS); }); + } function initToggler() { - togglerEl.addEventListener('click', function() { + togglerElement.addEventListener('click', function() { alertElements.forEach(function(alertEl) { toggleAlert(alertEl, true); }); - togglerEl.classList.remove(ALERTS_TOGGLER_VISIBLE_CLASS); + togglerElement.classList.remove(ALERTS_TOGGLER_VISIBLE_CLASS); }); - alertsEl.classList.add(JS_INITIALIZED_CLASS); + element.classList.add(ALERTS_INITIALIZED_CLASS); } - function initAlert(alertEl) { + function initAlerts() { + alertElements.forEach(initAlert); + } + + function initAlert(alertElement) { var autoHideDelay = ALERT_AUTO_HIDE_DELAY; - if (alertEl.dataset.decay) { - autoHideDelay = parseInt(alertEl.dataset.decay, 10); + if (alertElement.dataset.decay) { + autoHideDelay = parseInt(alertElement.dataset.decay, 10); } - var closeEl = alertEl.querySelector('.' + ALERT_CLOSER_CLASS); + var closeEl = alertElement.querySelector('.' + ALERT_CLOSER_CLASS); closeEl.addEventListener('click', function() { - toggleAlert(alertEl); + toggleAlert(alertElement); }); - if (autoHideDelay > 0 && alertEl.matches(ALERT_AUTOCLOSING_MATCHER)) { + if (autoHideDelay > 0 && alertElement.matches(ALERT_AUTOCLOSING_MATCHER)) { window.setTimeout(function() { - toggleAlert(alertEl); + toggleAlert(alertElement); }, autoHideDelay * 1000); } - alertEl.classList.add(JS_INITIALIZED_CLASS); + alertElement.classList.add(ALERTS_INITIALIZED_CLASS); } function toggleAlert(alertEl, visible) { @@ -80,17 +138,19 @@ }, true); window.setTimeout(function() { - togglerEl.classList.toggle(ALERTS_TOGGLER_VISIBLE_CLASS, alertsHidden); + togglerElement.classList.toggle(ALERTS_TOGGLER_VISIBLE_CLASS, alertsHidden); togglerCheckRequested = false; }, ALERTS_TOGGLER_APPEAR_DELAY); } - initToggler(); - alertElements.forEach(initAlert); - - return { - scope: alertsEl, - destroy: function() {}, - }; + return init(); }; + + if (UtilRegistry) { + UtilRegistry.register({ + name: ALERTS_UTIL_NAME, + selector: ALERTS_UTIL_SELECTOR, + setup: alertsUtil, + }); + } })(); diff --git a/templates/widgets/alerts/alerts.hamlet b/templates/widgets/alerts/alerts.hamlet index bc034c08e..196890850 100644 --- a/templates/widgets/alerts/alerts.hamlet +++ b/templates/widgets/alerts/alerts.hamlet @@ -1,4 +1,4 @@ -
+
$forall (status, msg) <- mmsgs $with status2 <- bool status "info" (status == "")