server/settings/js/users/deleteHandler.js
Vincent Petry 0d9f24a0ef Add timeout to user and group deletion notification
Added timeout in DeleteHandler to auto-delete after a delay.

Fixed issue where OC.Notification.hide() was called twice in a row when
deleting multiple entries, causing the second notification to disappear.
Fixed issue where "undo" click event handler was registered multiple
times when calling setNotifications() twice.
Added JS unit tests for the DeleteHandler class.

Refix undo users, groups feature

Timeout is now cleared in cancel().

Fixed click handler name for "undo" to be able to work with multiple
DeleteHandler instances (in our case one for users and one for groups)
so that there is no conflict.
2014-09-15 14:04:44 +02:00

210 lines
5.8 KiB
JavaScript

/**
* Copyright (c) 2014, Arthur Schiwon <blizzz@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or later.
* See the COPYING-README file.
*/
/**
* takes care of deleting things represented by an ID
*
* @class
* @param {string} endpoint the corresponding ajax PHP script. Currently limited
* to settings - ajax path.
* @param {string} paramID the by the script expected parameter name holding the
* ID of the object to delete
* @param {markCallback} markCallback function to be called after successfully
* marking the object for deletion.
* @param {removeCallback} removeCallback the function to be called after
* successful delete.
*/
function DeleteHandler(endpoint, paramID, markCallback, removeCallback) {
this.oidToDelete = false;
this.canceled = false;
this.ajaxEndpoint = endpoint;
this.ajaxParamID = paramID;
this.markCallback = markCallback;
this.removeCallback = removeCallback;
this.undoCallback = false;
this.notifier = false;
this.notificationDataID = false;
this.notificationMessage = false;
this.notificationPlaceholder = '%oid';
}
/**
* Number of milliseconds after which the operation is performed.
*/
DeleteHandler.TIMEOUT_MS = 7000;
/**
* Timer after which the action will be performed anyway.
*/
DeleteHandler.prototype._timeout = null;
/**
* The function to be called after successfully marking the object for deletion
* @callback markCallback
* @param {string} oid the ID of the specific user or group
*/
/**
* The function to be called after successful delete. The id of the object will
* be passed as argument. Unsuccessful operations will display an error using
* OC.dialogs, no callback is fired.
* @callback removeCallback
* @param {string} oid the ID of the specific user or group
*/
/**
* This callback is fired after "undo" was clicked so the consumer can update
* the web interface
* @callback undoCallback
* @param {string} oid the ID of the specific user or group
*/
/**
* enabled the notification system. Required for undo UI.
*
* @param {object} notifier Usually OC.Notification
* @param {string} dataID an identifier for the notifier, e.g. 'deleteuser'
* @param {string} message the message that should be shown upon delete. %oid
* will be replaced with the affected id of the item to be deleted
* @param {undoCallback} undoCallback called after "undo" was clicked
*/
DeleteHandler.prototype.setNotification = function(notifier, dataID, message, undoCallback) {
this.notifier = notifier;
this.notificationDataID = dataID;
this.notificationMessage = message;
this.undoCallback = undoCallback;
var dh = this;
$('#notification')
.off('click.deleteHandler_' + dataID)
.on('click.deleteHandler_' + dataID, '.undo', function () {
if ($('#notification').data(dh.notificationDataID)) {
var oid = dh.oidToDelete;
dh.cancel();
if(typeof dh.undoCallback !== 'undefined') {
dh.undoCallback(oid);
}
}
dh.notifier.hide();
});
};
/**
* shows the Undo Notification (if configured)
*/
DeleteHandler.prototype.showNotification = function() {
if(this.notifier !== false) {
if(!this.notifier.isHidden()) {
this.hideNotification();
}
$('#notification').data(this.notificationDataID, true);
var msg = this.notificationMessage.replace(
this.notificationPlaceholder, escapeHTML(this.oidToDelete));
this.notifier.showHtml(msg);
}
};
/**
* hides the Undo Notification
*/
DeleteHandler.prototype.hideNotification = function() {
if(this.notifier !== false) {
$('#notification').removeData(this.notificationDataID);
this.notifier.hide();
}
};
/**
* initializes the delete operation for a given object id
*
* @param {string} oid the object id
*/
DeleteHandler.prototype.mark = function(oid) {
if(this.oidToDelete !== false) {
// passing true to avoid hiding the notification
// twice and causing the second notification
// to disappear immediately
this.deleteEntry(true);
}
this.oidToDelete = oid;
this.canceled = false;
this.markCallback(oid);
this.showNotification();
if (this._timeout) {
clearTimeout(this._timeout);
this._timeout = null;
}
if (DeleteHandler.TIMEOUT_MS > 0) {
this._timeout = window.setTimeout(
_.bind(this.deleteEntry, this),
DeleteHandler.TIMEOUT_MS
);
}
};
/**
* cancels a delete operation
*/
DeleteHandler.prototype.cancel = function() {
if (this._timeout) {
clearTimeout(this._timeout);
this._timeout = null;
}
this.canceled = true;
this.oidToDelete = false;
};
/**
* executes a delete operation. Requires that the operation has been
* initialized by mark(). On error, it will show a message via
* OC.dialogs.alert. On success, a callback is fired so that the client can
* update the web interface accordingly.
*
* @param {boolean} [keepNotification] true to keep the notification, false to hide
* it, defaults to false
*/
DeleteHandler.prototype.deleteEntry = function(keepNotification) {
if(this.canceled || this.oidToDelete === false) {
return false;
}
var dh = this;
if(!keepNotification && $('#notification').data(this.notificationDataID) === true) {
dh.hideNotification();
}
if (this._timeout) {
clearTimeout(this._timeout);
this._timeout = null;
}
var payload = {};
payload[dh.ajaxParamID] = dh.oidToDelete;
$.ajax({
type: 'POST',
url: OC.filePath('settings', 'ajax', dh.ajaxEndpoint),
// FIXME: do not use synchronous ajax calls as they block the browser !
async: false,
data: payload,
success: function (result) {
if (result.status === 'success') {
// Remove undo option, & remove user from table
//TODO: following line
dh.removeCallback(dh.oidToDelete);
dh.canceled = true;
} else {
OC.dialogs.alert(result.data.message, t('settings', 'Unable to delete {objName}', {objName: escapeHTML(dh.oidToDelete)}));
dh.undoCallback(dh.oidToDelete);
}
}
});
};