first commit
This commit is contained in:
@@ -0,0 +1,312 @@
|
||||
/**
|
||||
* @file js/controllers/NotificationHandler.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 NotificationHandler
|
||||
* @ingroup js_controllers
|
||||
*
|
||||
* @brief Handle in place notifications.
|
||||
*/
|
||||
(function($) {
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*
|
||||
* @extends $.pkp.classes.Handler
|
||||
*
|
||||
* @param {jQueryObject} $notificationElement The html notification element.
|
||||
* @param {Object} options Notification options.
|
||||
*/
|
||||
$.pkp.controllers.NotificationHandler =
|
||||
function($notificationElement, options) {
|
||||
this.parent($notificationElement, options);
|
||||
|
||||
this.options_ = options;
|
||||
|
||||
this.bind('notifyUser', this.fetchNotificationHandler_);
|
||||
|
||||
// Hide the notification element.
|
||||
this.getHtmlElement().hide();
|
||||
|
||||
// Trigger the notify user event without bubbling up.
|
||||
this.getHtmlElement().triggerHandler('notifyUser');
|
||||
|
||||
if (this.options_.refreshOn) {
|
||||
this.bindGlobal(this.options_.refreshOn, this.fetchNotificationHandler_);
|
||||
}
|
||||
};
|
||||
$.pkp.classes.Helper.inherits(
|
||||
$.pkp.controllers.NotificationHandler,
|
||||
$.pkp.classes.Handler);
|
||||
|
||||
|
||||
//
|
||||
// Private properties.
|
||||
//
|
||||
/**
|
||||
* The options to fetch a notification.
|
||||
* @private
|
||||
* @type {Object?}
|
||||
*/
|
||||
$.pkp.controllers.NotificationHandler.prototype.options_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* Time to hide trivial inplace notifications.
|
||||
* @private
|
||||
* @type {number?}
|
||||
*/
|
||||
$.pkp.controllers.NotificationHandler.prototype.trivialTimer_ = null;
|
||||
|
||||
|
||||
//
|
||||
// Private methods.
|
||||
//
|
||||
/**
|
||||
* Handler to fetch the notification data.
|
||||
* @private
|
||||
*/
|
||||
$.pkp.controllers.NotificationHandler.prototype.fetchNotificationHandler_ =
|
||||
function() {
|
||||
|
||||
var requestOptions = {};
|
||||
requestOptions.requestOptions = this.options_.requestOptions;
|
||||
|
||||
// Avoid race conditions with other notification controllers.
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: this.options_.fetchNotificationUrl,
|
||||
data: requestOptions,
|
||||
success: this.callbackWrapper(this.showNotificationResponseHandler_),
|
||||
dataType: 'json',
|
||||
async: false
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Callback to show the notification data in place.
|
||||
*
|
||||
* @param {Object} ajaxContext The AJAX request context.
|
||||
* @param {Object} jsonData A parsed JSON response object.
|
||||
* @private
|
||||
*/
|
||||
$.pkp.controllers.NotificationHandler.prototype.
|
||||
showNotificationResponseHandler_ = function(ajaxContext, jsonData) {
|
||||
// Delete any existing trivial notification timer.
|
||||
clearTimeout(this.trivialTimer_);
|
||||
|
||||
var $notificationElement = this.getHtmlElement(),
|
||||
workingJsonData = this.handleJson(jsonData),
|
||||
inPlaceNotificationsData, newNotificationsData,
|
||||
trivialNotificationsId, notificationId, i;
|
||||
|
||||
if (workingJsonData === false) {
|
||||
return;
|
||||
}
|
||||
if (workingJsonData.content.inPlace) {
|
||||
inPlaceNotificationsData = this.concatenateNotifications_(
|
||||
workingJsonData.content.inPlace);
|
||||
newNotificationsData = this.removeAlreadyShownNotifications_(
|
||||
/** @type {Object} */ (workingJsonData));
|
||||
|
||||
this.unbindPartial($notificationElement);
|
||||
$notificationElement.html(inPlaceNotificationsData);
|
||||
|
||||
// We need to show the notification element now so the
|
||||
// visibility test can be executed.
|
||||
$notificationElement.show();
|
||||
|
||||
trivialNotificationsId = this.getTrivialNotifications_(
|
||||
workingJsonData.content.inPlace);
|
||||
|
||||
if (!(this.visibleWithoutScrolling_()) && newNotificationsData) {
|
||||
// In place notification is not visible. Let parent widgets
|
||||
// show the notification data.
|
||||
$notificationElement.parent().
|
||||
trigger('notifyUser', [newNotificationsData]);
|
||||
|
||||
// Remove in place trivial notifications.
|
||||
for (i in trivialNotificationsId) {
|
||||
notificationId = trivialNotificationsId[i];
|
||||
$notificationElement =
|
||||
$('#pkp_notification_' + notificationId,
|
||||
this.getHtmlElement());
|
||||
this.unbindPartial($notificationElement);
|
||||
$notificationElement.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// After visibility test and possible trivial notifications
|
||||
// removal, we need to test if the in place notification widget
|
||||
// shows any notification. If not, hide it.
|
||||
if ($notificationElement.children().length === 0) {
|
||||
$notificationElement.hide();
|
||||
} else {
|
||||
// Add a timer to any trivial notifications
|
||||
// inside this widget.
|
||||
this.addTimerToNotifications(trivialNotificationsId);
|
||||
}
|
||||
|
||||
} else {
|
||||
this.unbindPartial(this.getHtmlElement());
|
||||
this.getHtmlElement().empty();
|
||||
this.getHtmlElement().hide();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check if the notification is inside the window are visible.
|
||||
* @return {boolean} True iff the notification is visible.
|
||||
* @private
|
||||
*/
|
||||
$.pkp.controllers.NotificationHandler.prototype.
|
||||
visibleWithoutScrolling_ = function() {
|
||||
var $notificationElement = this.getHtmlElement(),
|
||||
notificationTop = $notificationElement.offset().top,
|
||||
notificationMiddle = notificationTop + this.getHtmlElement().height() / 2,
|
||||
windowScrollTop = $(window).scrollTop(),
|
||||
windowBottom = windowScrollTop + $(window).height(),
|
||||
// Consider modals and its own scroll functionality.
|
||||
$parentModalContentWrapper = $notificationElement
|
||||
.parents('.ui-dialog-content'),
|
||||
modalContentTop, modalContentBottom;
|
||||
|
||||
if ($parentModalContentWrapper.length > 0) {
|
||||
modalContentTop = $parentModalContentWrapper.offset().top;
|
||||
modalContentBottom = modalContentTop +
|
||||
$parentModalContentWrapper.height();
|
||||
if (notificationMiddle < modalContentTop ||
|
||||
notificationMiddle > modalContentBottom) {
|
||||
// The element is outside of the modal content wrapper area.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the element is inside of the visible window area.
|
||||
if (notificationMiddle < windowScrollTop ||
|
||||
notificationMiddle > windowBottom) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Remove notification data from object that is already on page.
|
||||
* @param {Object} notificationsData The notification data to perform
|
||||
* the deletion on.
|
||||
* @return {Object|boolean} Notification data after deletion.
|
||||
* @private
|
||||
*/
|
||||
$.pkp.controllers.NotificationHandler.prototype.
|
||||
removeAlreadyShownNotifications_ = function(notificationsData) {
|
||||
|
||||
var workingNotificationsData = /** @type {{ content: {
|
||||
inPlace: Array, general: Array} }} */
|
||||
(notificationsData),
|
||||
emptyObject = true,
|
||||
levelId, notificationId, element;
|
||||
for (levelId in workingNotificationsData.content.inPlace) {
|
||||
for (notificationId in
|
||||
workingNotificationsData.content.inPlace[levelId]) {
|
||||
element = $('#pkp_notification_' + notificationId);
|
||||
if (element.length > 0) {
|
||||
delete workingNotificationsData.content.
|
||||
inPlace[levelId][notificationId];
|
||||
delete workingNotificationsData.content.
|
||||
general[levelId][notificationId];
|
||||
} else {
|
||||
emptyObject = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (emptyObject) {
|
||||
return false;
|
||||
} else {
|
||||
return workingNotificationsData;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Concatenate notification data in a string variable.
|
||||
* @param {Object} notificationsData The notification data to assemble
|
||||
* the concatenation from.
|
||||
* @return {string} The concatenated notification data.
|
||||
* @private
|
||||
*/
|
||||
$.pkp.controllers.NotificationHandler.prototype.
|
||||
concatenateNotifications_ = function(notificationsData) {
|
||||
var returner = '', levelId, notificationId;
|
||||
for (levelId in notificationsData) {
|
||||
for (notificationId in notificationsData[levelId]) {
|
||||
// Concatenate all notifications.
|
||||
returner += notificationsData[levelId][notificationId];
|
||||
}
|
||||
}
|
||||
|
||||
return returner;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get all trivial notifications id inside the passed notifications.
|
||||
* @param {Object} notificationsData The data returned from the fetch
|
||||
* notification request.
|
||||
* @return {Array} The trivial notifications id.
|
||||
* @private
|
||||
*/
|
||||
$.pkp.controllers.NotificationHandler.prototype.
|
||||
getTrivialNotifications_ = function(notificationsData) {
|
||||
|
||||
var trivialNotificationsId = [], levelId, notificationId;
|
||||
for (levelId in notificationsData) {
|
||||
if (levelId == 1) { // Trivial level.
|
||||
for (notificationId in notificationsData[levelId]) {
|
||||
trivialNotificationsId.push(notificationId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return trivialNotificationsId;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Add a timer for passed notifications to hide them after a time.
|
||||
* @param {Object} notificationsId Array with the notifications id
|
||||
* that will receive the timer.
|
||||
*/
|
||||
$.pkp.controllers.NotificationHandler.prototype.
|
||||
addTimerToNotifications = function(notificationsId) {
|
||||
|
||||
var self, removeNotification;
|
||||
|
||||
self = this; // remember "this" reference for later use in callback
|
||||
|
||||
removeNotification = function() {
|
||||
var $notification = $(this);
|
||||
self.unbindPartial($notification);
|
||||
$notification.remove();
|
||||
};
|
||||
|
||||
if (notificationsId.length) {
|
||||
this.trivialTimer_ = setTimeout(function() {
|
||||
var notificationId, $notification;
|
||||
for (notificationId in notificationsId) {
|
||||
$notification = $('#pkp_notification_' +
|
||||
notificationsId[notificationId]);
|
||||
$notification.fadeOut(400, removeNotification);
|
||||
}
|
||||
}, 6000);
|
||||
}
|
||||
};
|
||||
|
||||
}(jQuery));
|
||||
Reference in New Issue
Block a user