/**
* @defgroup js_classes_notification
*/
/**
* @file js/classes/notification/NotificationHelper.js
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class NotificationHelper
* @ingroup js_classes_notification
*
* @brief Class that perform notification helper actions.
*/
(function($) {
/** @type {Object} */
$.pkp.classes.notification = $.pkp.classes.notification || {};
/**
* @constructor
*/
$.pkp.classes.notification.NotificationHelper = function() {
};
//
// Public static helper methods
//
/**
* Decides which notification will be used: in place or general.
* This method finds all notification widgets that are inside of the
* handled element of the controller that is handling the current
* notify user event (page or modal). We need to make sure that all
* notifications will be shown inside the same widget where the notify
* user was triggered. Beyond that, we also need to make sure that,
* inside some widgets (tabs and accordions, for example) we use the
* right notification controller.
* To do this, the notification element must follow these rules:
*
* 1 - the notification element must not have a hidden parent, although
* it can be hidden itself.
*
* 2 - the notification element first widget parent also needs to contain
* the element that triggered the notify user event.
*
* 3 - if the notification element is inside an accordion container, it
* will only notify user from events that have the trigger element also
* inside the accordion container.
*
* At the final, if this method find and select more than one
* notification element, we get the closest comparing to the element
* that triggered the event. If it don't find any visible element, it
* bubbles up the event so the site handler can show general
* notifications.
*
* @param {$.pkp.classes.Handler} handler The widget handler that is
* handling the notify user event.
* @param {HTMLElement|Object} triggerElement The element that triggered the
* notify user event.
*/
$.pkp.classes.notification.NotificationHelper.redirectNotifyUserEvent =
function(handler, triggerElement) {
// Get the selector for a notification element.
var $notificationSelector = '.pkp_notification',
$handledElement,
trivialAlreadyHandled,
$pageNotificationElements,
possibleNotificationWidgets,
i, length,
notificationsData,
$accordionContainer,
$element,
$elementParents, parentHandler,
j, parentsLength, $elementParentWidget;
// Sometimes the notification handler will bubble up
// the notifyUser event when in place notifications are
// not visible because of scrolling. When this happens, the
// trigger element will not be an element, but the notifications
// data that were shown by the in place but no visible. In those
// cases, just bubble up again the event until it gets the right
// handler (the site handler).
if (triggerElement !== undefined && triggerElement.content !== undefined) {
notificationsData = triggerElement;
handler.getHtmlElement().parent().trigger(
'notifyUser', [notificationsData]);
return; // no need to do any other event redirection.
}
// Get the html element of the handler.
$handledElement = handler.getHtmlElement();
// If the trigger element is inside a grid, let the site
// handler show TRIVIAL notifications.
trivialAlreadyHandled = false;
if (!(handler instanceof $.pkp.controllers.SiteHandler)) {
if (triggerElement !== undefined &&
$(triggerElement).parents('.pkp_controllers_grid').length > 0) {
$handledElement.parent().trigger('notifyUser');
trivialAlreadyHandled = true;
}
}
// Find all notification elements inside the handled element.
$pageNotificationElements = $($notificationSelector, $handledElement);
// Create a variable to store all possible notification widgets
// that can notify this event.
possibleNotificationWidgets = [];
for (i = 0, length = $pageNotificationElements.length; i < length; i++) {
$element = $($pageNotificationElements[i]);
// If it is inside a hidden parent, get next element.
if ($element.parents(':hidden').length > 0) {
continue;
}
// Find its parent widget.
// FIXME If we use a class to identify pkp widgets, we can avoid
// this code duplication from the get handler method in Handler class,
// unnecessary access to the element data and unnecessary loop.
$elementParents = $element.parents();
for (j = 0, parentsLength = $elementParents.length;
j < parentsLength; j++) {
parentHandler = $($elementParents[j]).data('pkp.handler');
if ((parentHandler instanceof $.pkp.classes.Handler)) {
$elementParentWidget = $($elementParents[j]);
break;
}
}
// If the element that triggered the event is inside of
// this widget or is the widget...
if (triggerElement !== undefined &&
($elementParentWidget.has(triggerElement[0]).length ||
$elementParentWidget[0] === triggerElement[0])) {
// If it is inside an accordion container, and this accordion container
// doesn't also contain the element that triggered the event, get other
// element.
if ($element.parents('.ui-accordion:first').length > 0) {
$accordionContainer = $element.parents('.ui-accordion:first');
if (!$accordionContainer.has(triggerElement[0])) {
continue;
}
}
// This notification element is able to notify this event.
possibleNotificationWidgets.push($element);
}
}
// Check if we found a notification element.
if (possibleNotificationWidgets.length) {
// Trigger all in place notification widgets found, from the
// closest to the element that triggered the action to the top.
for (i = possibleNotificationWidgets.length - 1; i > -1; i--) {
// Show in place notification to user.
possibleNotificationWidgets[i].triggerHandler('notifyUser');
}
} else {
if (!trivialAlreadyHandled) {
// Bubble up the notify user event so the site can handle the
// general notification.
handler.getHtmlElement().parent().trigger('notifyUser');
}
}
};
}(jQuery));
|