| Server IP : 85.158.181.41 / Your IP : 216.73.217.12 Web Server : Apache System : Linux cloud9-vm129 6.1.178+1-ph #ph SMP PREEMPT_DYNAMIC Wed Jul 29 09:00:54 UTC 2026 x86_64 User : moncbefd ( 1024) PHP Version : 7.3.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /home/moncbefd/www.moneta.at/admin/javascript/engine/controllers/layouts/main/header/ |
Upload File : |
/* --------------------------------------------------------------
info_box.js 2016-11-10
Gambio GmbH
http://www.gambio.de
Copyright (c) 2016 Gambio GmbH
Released under the GNU General Public License (Version 2)
[http://www.gnu.org/licenses/gpl-2.0.html]
--------------------------------------------------------------
*/
/**
* Infobox Controller
*
* Handles the functionality of the info box component of the admin layout pages.
*/
gx.controllers.module(
'info_box',
[
'loading_spinner',
`${gx.source}/libs/info_box`
],
function (data) {
'use strict';
// --------------------------------------------------------------------
// VARIABLES
// --------------------------------------------------------------------
// Module element, which represents the info box.
const $this = $(this);
// Notification counter icon element.
const $counter = $this.find('.notification-count');
// Module default parameters.
const defaults = {
// Popover steady time.
closeDelay: 5000,
// Roll on/out animation duration.
animationDuration: 600,
// Default open mode on links.
linkOpenMode: '_self'
};
// Module options.
const options = $.extend(true, {}, defaults, data);
// Shortcut to info box library.
const library = jse.libs.info_box;
// Shortcut to spinner library.
const spinner = jse.libs.loading_spinner;
// Shortcut to language text service.
const translator = jse.core.lang;
// CSS classes.
const classes = {
// Active state of the message list container (for the roll in/out animation).
containerVisible: 'visible',
// Hidden message item.
hidden: 'hidden'
};
// Selector strings.
const selectors = {
// Message list container.
container: '.popover.message-list-container',
// Message list container arrow.
arrow: '.arrow',
// Message list.
list: '.popover-content',
// Message list visibility checkbox.
checkbox: '.visibility-checkbox',
// Message item.
item: '.message',
// Hidden message item.
hiddenItem: '[data-status="hidden"]',
// Message item button.
itemButton: '.message-button',
// Message item action (remove, hide, etc.).
itemAction: '.action-icon'
};
// Module object.
const module = {};
// Indicates whether the roll animation is still running.
let isAnimating = false;
// Indicates whether the message item list container is shown for a certain duration
// Happens on new messages after a silent refresh.
let isShownWithCloseDelay = false;
// --------------------------------------------------------------------
// FUNCTIONS
// --------------------------------------------------------------------
/**
* Returns a space-separated CSS class name by replacing the periods with spaces.
*
* @param className CSS class.
*
* @return {String} Class name without periods.
*/
function _getClassNameWithoutPeriods(className) {
return className.split('.').join(' ');
}
/**
* Returns the markup for the popover template.
*
* @return {String} Generated HTML string.
*/
function _getPopoverMarkup() {
return `
<div class="${_getClassNameWithoutPeriods(selectors.container)}" role="tooltip">
<div class="${_getClassNameWithoutPeriods(selectors.arrow)}"></div>
<div class="popover-title"></div>
<div class="${_getClassNameWithoutPeriods(selectors.list)}"></div>
</div>
`;
}
/**
* Returns the generated markup for a message item.
*
* @param {Object} message Message item.
*
* @return {jQuery} Markup as jQuery object.
*/
function _getMessageItemMarkup(message) {
// Is the message an admin action success message?
const isSuccessMessage = message.identifier
&& message.identifier.includes(library.SUCCESS_MSG_IDENTIFIER_PREFIX);
// Is the message hideable but not removable?
const isHideableMessage = !isSuccessMessage
&& message.visibility && message.visibility === library.VISIBILITY_HIDEABLE;
// Is the message always visible?
const isAlwaysOnMessage = !isSuccessMessage
&& message.visibility && message.visibility === library.VISIBILITY_ALWAYS_ON;
// Message item markup.
const markup = `
<div
class="message ${message.type} ${isSuccessMessage ? 'admin-action-success' : ''}"
data-status="${message.status}"
data-id="${message.id}"
data-visibility="${message.visibility}"
data-identifier="${message.identifier}"
>
<div class="action-icons">
<span class="${_getClassNameWithoutPeriods(selectors.itemAction)} do-hide fa fa-minus"></span>
<span class="${_getClassNameWithoutPeriods(selectors.itemAction)} do-remove fa fa-times"></span>
</div>
<div class="headline">
${message.headline}
</div>
<div class="content">
${message.message}
</div>
<a class="btn ${_getClassNameWithoutPeriods(selectors.itemButton)}" href="${message.buttonLink}">
${message.buttonLabel}
</a>
</div>
`;
// Markup as jQuery object for manipulation purposes.
const $markup = $(markup);
// Remove button from markup, if no button label is defined.
if (!message.buttonLabel) {
$markup.find(selectors.itemButton).remove();
}
// Show remove/hide button, depending on the visibility value and kind of message.
if (isAlwaysOnMessage) {
$markup.find(`${selectors.itemAction}`).remove();
} else if (isHideableMessage) {
$markup.find(`${selectors.itemAction} do-remove`).remove();
} else if (isSuccessMessage) {
$markup.find(`${selectors.itemAction} do-hide`).remove();
}
return $markup;
}
/**
* Returns the markup for the message items visibility checkbox.
*
* @return {String} Generated HTML string.
*/
function _getVisibilityCheckboxMarkup() {
return `
<div class="visibility-checkbox-container">
<input type="checkbox" class="${_getClassNameWithoutPeriods(selectors.checkbox)}">
<label class="visibility-checkbox-label">${translator.translate('SHOW_ALL', 'admin_info_boxes')}</label>
</div>
`;
}
/**
* Marks each visible message item as read.
*/
function _markMessageItemsAsRead() {
// Message items.
const $messageList = $(selectors.container).find(selectors.item);
// Iterate over each message and mark as read.
$messageList.each((index, element) => {
// Current iteration element.
const $message = $(element);
// Message data.
const data = $message.data();
// Indicate, if the message is declared as hidden.
const isHidden = $message.hasClass(library.STATUS_HIDDEN);
// Delete by ID if existent.
if (!isHidden && data.id) {
library.setStatus(data.id, library.STATUS_READ);
$message.data('status', library.STATUS_READ);
}
// Delete success messages.
if (data.identifier && data.identifier.includes(library.SUCCESS_MSG_IDENTIFIER_PREFIX)) {
library.deleteByIdentifier(data.identifier);
}
});
}
/**
* Sets the message item amount in the notification icon.
*
* Admin action success messages will be excluded.
*
* @param {Array} messages Message items.
*/
function _setMessageCounter(messages) {
// Hidden CSS class.
const hiddenClass = 'hidden';
// Message item count.
let count = 0;
// Iterate over each message item and check message identifier.
if (messages.length) {
messages.forEach(message => count =
message.identifier.includes(library.SUCCESS_MSG_IDENTIFIER_PREFIX) ? count : ++count)
}
// The notification count will be hidden, if there are no messages.
if (count) {
$counter
.removeClass(hiddenClass)
.text(count);
} else {
$counter.addClass(hiddenClass);
}
}
/**
* Handles the click event on the info box action button.
*/
function _onClick() {
_toggleContainer(!$(selectors.container).length);
}
/**
* Toggles the message list container (popover) with an animation.
*
* @param {Boolean} doShow Show the message list container?
*/
function _toggleContainer(doShow) {
// Exit immediately when the animation process is still running.
if (isAnimating) {
return;
}
// Indicate animation process.
isAnimating = true;
// Switch animation process indicator to false after animation duration.
setTimeout(() => isAnimating = false, options.animationDuration);
if (doShow) {
// Perform message item list container roll in animation.
$this.popover('show');
} else {
// Perform message item list container roll out animation and then hide.
$(selectors.container).removeClass(classes.containerVisible);
setTimeout(() => $this.popover('hide'), options.animationDuration);
}
}
/**
* Handles the popover (message container) 'shown' event by getting the messages from the server
* and displaying them in the container.
*/
function _onPopoverShown() {
// Message list container.
const $container = $(selectors.container);
// Indicate container visibility.
$container
.addClass(classes.containerVisible)
.css({top: $container.height() * -1});
// Fix container and arrow position.
_fixPositions();
// Enable loading state.
_toggleLoading(true);
// Retrieve messages from server and show them in the container and mark them as read.
library.getMessages().then(messages => {
// Disable loading state.
_toggleLoading(false);
// Put messages into message list.
_putMessagesIntoContainer(messages);
// Hide hidden message items and show only the success message item if exists.
_reviseMessageItemList();
// Set notification count.
_setMessageCounter(messages);
// Mark visible message items as read.
_markMessageItemsAsRead();
});
// Attach event handlers to popover.
$container
.off('click change')
.on('click', selectors.itemButton, _onMessageItemButtonClick)
.on('click', selectors.itemAction, _onMessageItemActionClick)
.on('change', selectors.checkbox, _onVisibilityCheckboxChange);
}
/**
* Toggles the hidden message items.
*
* @param {Boolean} doShow Show the hidden message items?
*/
function _toggleHiddenMessageItems(doShow) {
// Message list container.
const $container = $(selectors.container);
// Hidden message items.
const $hiddenMessageItems = $container.find(selectors.item).filter(selectors.hiddenItem);
// Toggle visibility.
if (doShow) {
$hiddenMessageItems.removeClass(classes.hidden);
} else {
$hiddenMessageItems.addClass(classes.hidden);
}
}
/**
* Revises the message item list by hiding message items declared as hidden.
*
* Additionally, if an admin action success message item is found it will be solely displayed.
*/
function _reviseMessageItemList() {
// Message list container.
const $container = $(selectors.container);
// Message list.
const $messageList = $container.find(selectors.list);
// Message items.
const $messageItems = $messageList.find(selectors.item);
// Hidden message items.
const $hiddenMessageItems = $messageItems.filter(selectors.hiddenItem);
// Admin action success message items.
const $successMessageItems = $messageItems.filter(`[data-identifier*=${library.SUCCESS_MSG_IDENTIFIER_PREFIX}]`);
// Hide messages declared as hidden and add visibility checkbox.
if ($hiddenMessageItems.length) {
_toggleHiddenMessageItems(false);
$messageList.append(_getVisibilityCheckboxMarkup());
}
// Remove all other messages (including duplicate success messages) if a success message is present.
if ($successMessageItems.length) {
$messageItems
.not($successMessageItems.first())
.hide();
}
}
/**
* Fills the message list with message items.
*
* @param {Array} messages Message items.
*/
function _putMessagesIntoContainer(messages) {
// Message list container.
const $container = $(selectors.container);
// Message list.
const $messageList = $container.find(selectors.list);
// Array containing all generated message item markups.
const messageItemsMarkups = [];
// Clear message list.
$messageList.empty();
// Show messages.
if (messages.length) {
// Iterate over each message item and generate markups.
for (const message of messages) {
// Generate markup.
const $markup = _getMessageItemMarkup(message);
// Add markup to array.
messageItemsMarkups.push($markup);
}
} else {
// Generate markup for the missing entries info message item.
const $noEntriesMessageItemMarkup = _getMessageItemMarkup({
message: translator.translate('NO_MESSAGES', 'admin_info_boxes'),
visibility: library.VISIBILITY_ALWAYS_ON,
status: library.STATUS_READ,
headline: '',
type: '',
id: '',
identifier: ''
});
// Add markup to array.
messageItemsMarkups.push($noEntriesMessageItemMarkup);
}
// Put render messages.
messageItemsMarkups.forEach(element => $messageList.append(element));
// Fade the message items in smoothly.
$messageList
.children()
.each((index, element) => $(element).hide().fadeIn());
}
/**
* Handles the click event to a message item button by opening the link.
*/
function _onMessageItemButtonClick(event) {
// Prevent default behavior.
event.preventDefault();
event.stopPropagation();
// Link value from button.
const href = $(this).attr('href');
// Check if we need to perform a special action.
const $message = $(this).parents('.message');
switch ($message.data('identifier')) {
case 'clear_cache':
$.get(href).done(response => {
library.addSuccessMessage(response);
});
break;
default:
// Open link if exists.
if (href && href.trim().length) {
window.open(href, options.linkOpenMode);
}
}
}
/**
* Handles the click event to a message item action.
*/
function _onMessageItemActionClick() {
// Clicked element.
const $element = $(this);
// Check if the clicked target indicates a message removal.
const doRemove = $element.hasClass('do-remove');
// ID of the message taken from the message item element.
const id = $element.parents(selectors.item).data('id');
// Delete/hide message depending on the clicked target.
if (doRemove) {
_deleteMessage(id);
} else {
_hideMessage(id);
}
}
/**
* Handles click event on the entire document.
*
* @param {jQuery.Event} event Triggered event.
*/
function _onWindowClick(event) {
// Clicked target.
const $target = $(event.target);
// Message list item container.
const $container = $(selectors.container);
// Conditions.
const isClickedOnButton = $this.has($target).length || $this.is($target).length;
const isContainerShown = $container.length;
const isClickedOutsideOfPopover = !$container.has($target).length;
// Only hide container, if clicked target is not within the container area.
if (isClickedOutsideOfPopover && isContainerShown && !isClickedOnButton && !isShownWithCloseDelay) {
_toggleContainer(false);
}
}
/**
* Fixes the container and arrow positions.
*/
function _fixPositions() {
// Offset correction values.
const ARROW_OFFSET = 240;
const POPOVER_OFFSET = 250;
// Message list container (popover).
const $container = $(selectors.container);
// Arrow.
const $arrow = $container.find(selectors.arrow);
// Fix the offset for the affected elements, if popover is open.
if ($container.length) {
const arrowOffset = $container.offset().left + ARROW_OFFSET;
const popoverOffset = $this.offset().left - POPOVER_OFFSET + ($this.width() / 2);
$arrow.offset({left: arrowOffset});
$container.offset({left: popoverOffset});
}
}
/**
* Handles the visibility checkbox change event.
*/
function _onVisibilityCheckboxChange() {
// Indicates whether the checkbox is checked.
const isCheckboxChecked = $(this).is(':checked');
// Toggle hidden messages and mark shown messages as read.
_toggleHiddenMessageItems(isCheckboxChecked);
_markMessageItemsAsRead();
}
/**
* Deletes a message item and refreshes the message item list.
*
* @param {Number} id Message ID.
*/
function _deleteMessage(id) {
library
.deleteById(id)
.then(_refresh);
}
/**
* Hides a message item and refreshes the message item list.
*
* @param {Number} id Message ID.
*/
function _hideMessage(id) {
library
.setStatus(id, library.STATUS_HIDDEN)
.then(_refresh);
}
/**
* Refreshes the message item list.
*/
function _refresh() {
// Message list container.
const $container = $(selectors.container);
// Show loading spinner on the message container.
const $spinner = spinner.show($container, 9999);
// Refresh list.
_onPopoverShown();
// Hide loading spinner.
spinner.hide($spinner);
}
/**
* Retrieves the messages and displays the popover if there are new messages.
*/
function _refreshSilently() {
// Retrieve messages from server and update the notification count.
// Popover will we displayed if there is a new message.
library.getMessages().then(messages => {
// Set notification count.
_setMessageCounter(messages);
// Iterate over messages and try to find a message item declared as new.
// If found, the container will be opened.
for (const message of messages) {
if (message.status === library.STATUS_NEW) {
// Exit immediately when the animation process is still running
// or if the message list item container is already shown with a defined duration.
if (isAnimating || isShownWithCloseDelay) {
return;
}
// Open message item list container.
_toggleContainer(true);
// Indicate delayed closing.
isShownWithCloseDelay = true;
// Hide container and indicate delayed closing finish.
setTimeout(() => {
_toggleContainer(false);
isShownWithCloseDelay = false;
}, options.closeDelay);
break;
}
}
});
}
/**
* Toggles the loading state.
*
* @param {Boolean} isLoading Is the load process running?
*/
function _toggleLoading(isLoading) {
// Loading message class.
const loadingMessageClass = '.loading';
// Message item list container.
const $messageList = $(selectors.container).find(selectors.list);
// Loading message element.
const $loadingMessage = $messageList.find(loadingMessageClass);
// Loading message markup.
const markup = `
<div class="${_getClassNameWithoutPeriods(loadingMessageClass)}">
${translator.translate('LOADING', 'admin_info_boxes')}
</div>
`;
// Remove existing loading message.
$loadingMessage.remove();
// Add new loading message if parameter is true.
if (isLoading) {
$messageList.append($(markup))
}
}
// --------------------------------------------------------------------
// INITIALIZATION
// --------------------------------------------------------------------
// Module initialize function.
module.init = done => {
// Initialize popover plugin and attach event handlers.
$this
.popover({
animation: false,
placement: 'bottom',
content: ' ',
trigger: 'manual',
template: _getPopoverMarkup()
})
.on('click', _onClick)
.on('shown.bs.popover', _onPopoverShown)
.on('show:popover', () => _toggleContainer(true))
.on('refresh:messages', _refreshSilently);
// Attach event listeners to the window.
$(window)
.on('resize', _fixPositions)
.on('click', _onWindowClick);
// Initial message check.
_refreshSilently();
// Finish initialization.
done();
};
// Return data to module engine.
return module;
});