417 lines
15 KiB
JavaScript
417 lines
15 KiB
JavaScript
// SA. ENV-834
|
|
var contentLockerReloadUrl = "";
|
|
|
|
var timer;
|
|
var intervalId;
|
|
var siteRoot = location.protocol + '//' + location.host;
|
|
var dtLastActivity;
|
|
var saveButton;
|
|
var deleteButton;
|
|
var editButton;
|
|
var canEnabledDelBtn;
|
|
var errorPlaceholder;
|
|
var checking;
|
|
var updating;
|
|
var dataIsEdited;
|
|
var severity = {
|
|
info: 0,
|
|
warning: 1,
|
|
error: 2,
|
|
critical: 3,
|
|
};
|
|
|
|
var dataEditedText = "Sorry, this {entity} is being edited by {username}. Please, try to <a href='" + contentLockerReloadUrl + "'>refresh</a> the page a little bit later.";
|
|
var dataExpiredText = "Sorry, this {entity} has been changed since your last visit. Please, <a href='" + contentLockerReloadUrl + "'>refresh</a> the page to get actual version.";
|
|
var timedInactivityText = "Sorry, you have exceeded the period of inactivity and we cannot save your changes now. Please reload the page to try edit this object again.";
|
|
var UserFinishedEditing = "{entity} is now available for editing. <a href='" + contentLockerReloadUrl + "'>Refresh</a> the page to load latest changes and start editing";
|
|
var serverErrorText = "Server is not responding";
|
|
var timeoutLockWarning = "Exclusive lock will be released in {_X_} seconds because of inactivity.";
|
|
//var dataEditedPopover = "{entity} is being edited by {username}. Please, try again later.";
|
|
var dataEditedPopover = "This {entity} is currently being updated by {username}. Please attempt your edit again later."
|
|
var serverError404Text = "It seems like the connection to the server was lost and server considered you left the edit page.";
|
|
var serverError401Text = "You are not authorized to edit the {entity}. Please, <a href='" + siteRoot + "/Account/Login'>sign in</a> and try to edit the {entity} again";
|
|
|
|
|
|
// call it when click on the link before redirect to locked page
|
|
function CheckLock(buttonId, tableId, fieldId) {
|
|
var contentLockerRequest = {
|
|
'tableId': tableId,
|
|
'fieldId': fieldId
|
|
};
|
|
var result = false;
|
|
|
|
$.ajax({
|
|
type: "post",
|
|
url: siteRoot + "/ContentLockerApi/IsLock",
|
|
data: contentLockerRequest,
|
|
async: false,
|
|
error: function (response) {
|
|
ShowPopover(buttonId, serverErrorText);
|
|
result = false;
|
|
},
|
|
success: function (response) {
|
|
if (response.Status == true) {
|
|
ShowPopover(buttonId, dataEditedPopover.replace(/\{username\}/g, response.LockedBy).replace(/\{entity\}/g, response.EntityTitle));
|
|
result = false;
|
|
}
|
|
else {
|
|
result = true;
|
|
}
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
function CheckingLocks(tableId, fieldId, externalReferencesCount, editButtonId, deleteButtonId, erorPlaceholderId) {
|
|
checking = true;
|
|
deleteButton = deleteButtonId;
|
|
editButton = editButtonId;
|
|
errorPlaceholder = erorPlaceholderId;
|
|
dataIsEdited = false;
|
|
if (externalReferencesCount > 0) {
|
|
canEnabledDelBtn = false;
|
|
}
|
|
else {
|
|
canEnabledDelBtn = true;
|
|
}
|
|
|
|
var contentLockerRequest = {
|
|
'tableId': tableId,
|
|
'fieldId': fieldId
|
|
};
|
|
IsLock(contentLockerRequest);
|
|
}
|
|
// call it on the edit page to lock the object
|
|
function StartEdit(tableId, fieldId, deleteButtonId, saveButtonId, erorPlaceholderId, timestamp) {
|
|
|
|
updating = true;
|
|
errorPlaceholder = erorPlaceholderId;
|
|
deleteButton = deleteButtonId;
|
|
saveButton = saveButtonId;
|
|
|
|
var contentLockerRequest = {
|
|
'tableId': tableId,
|
|
'fieldId': fieldId,
|
|
'timestamp': timestamp
|
|
};
|
|
$('#danger').hide();
|
|
AddLock(contentLockerRequest);
|
|
$(window).on('unload', function () {
|
|
RemoveLock(contentLockerRequest.tableId, contentLockerRequest.fieldId);
|
|
});
|
|
|
|
$("#lnkLogout").click(function () {
|
|
RemoveLock(contentLockerRequest.tableId, contentLockerRequest.fieldId);
|
|
});
|
|
}
|
|
// call it on the details (always) and edit page (if content is locked by someone else)
|
|
function IsLock(contentLockerRequest) {
|
|
if (!checking)
|
|
return;
|
|
var canGoOn = true;
|
|
$.ajax({
|
|
type: "post",
|
|
url: siteRoot + "/ContentLockerApi/IsLock",
|
|
data: contentLockerRequest,
|
|
error: function (response) {
|
|
$(editButton).addClass("disabled");
|
|
LockTabElements();
|
|
$(deleteButton).addClass("disabled");
|
|
RemoveErrorMessage();
|
|
if (response.status != null) {
|
|
if (response.status == 401) {
|
|
ShowErrorMessage({ errorText: serverError401Text.replace(/\{entity\}/g, response.EntityTitle) });
|
|
}
|
|
else {
|
|
ShowErrorMessage();
|
|
}
|
|
} else {
|
|
ShowErrorMessage();
|
|
}
|
|
},
|
|
success: function (response) {
|
|
if (response == null || response.Status == null) {
|
|
$(editButton).addClass("disabled");
|
|
LockTabElements();
|
|
$(deleteButton).addClass("disabled");
|
|
RemoveErrorMessage();
|
|
ShowErrorMessage();
|
|
} else {
|
|
if (response.Status == true) {
|
|
$(editButton).addClass("disabled");
|
|
LockTabElements();
|
|
$(deleteButton).addClass("disabled");
|
|
ShowErrorMessage({ errorText: dataEditedText.replace(/\{username\}/g, response.LockedBy).replace(/\{entity\}/g, response.EntityTitle), enabledReloadLink: false });
|
|
dataIsEdited = true;
|
|
} else {
|
|
if (dataIsEdited) {
|
|
RemoveErrorMessage();
|
|
canGoOn = false;
|
|
ShowErrorMessage({ errorText: UserFinishedEditing.replace(/\{entity\}/g, response.EntityTitle, false) });
|
|
}
|
|
dataIsEdited = false;
|
|
}
|
|
if (canGoOn) {
|
|
setTimeout(IsLock, _isLockCheckIntervalMs, contentLockerRequest);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
// call it to send lock ajax request to the server
|
|
function AddLock(contentLockerRequest) {
|
|
contentLockerReloadUrl = document.location.href;
|
|
var hashPos = contentLockerReloadUrl.indexOf('#');
|
|
|
|
if (hashPos > 0)
|
|
contentLockerReloadUrl = contentLockerReloadUrl.substr(0, hashPos);
|
|
|
|
$.ajax({
|
|
type: "post",
|
|
url: siteRoot + "/ContentLockerApi/AddLock",
|
|
data: contentLockerRequest,
|
|
error: function (response) {
|
|
$(saveButton).addClass("disabled");
|
|
LockTabElements();
|
|
$(deleteButton).addClass("disabled");
|
|
ShowErrorMessage();
|
|
},
|
|
success: function (response) {
|
|
if (response == null || response.Status == null) {
|
|
$(saveButton).addClass("disabled");
|
|
LockTabElements();
|
|
$(deleteButton).addClass("disabled");
|
|
ShowErrorMessage();
|
|
} else {
|
|
if (response.Status == true) {
|
|
$(saveButton).removeClass("disabled");
|
|
UnlockTabElements();
|
|
$(deleteButton).removeClass("disabled");
|
|
RemoveErrorMessage();
|
|
|
|
dtLastActivity = new Date().getTime();
|
|
setTimeout(UpdateLock, _isLockCheckIntervalMs, contentLockerRequest);
|
|
} else {
|
|
var errorMessage = '';
|
|
if (response.Code == 2) { // expired
|
|
errorMessage = dataExpiredText.replace(/\{username\}/g, response.LockedBy).replace(/\{entity\}/g, response.EntityTitle);
|
|
} else { // blocked by other person
|
|
errorMessage = dataEditedText.replace(/\{username\}/g, response.LockedBy).replace(/\{entity\}/g, response.EntityTitle);
|
|
}
|
|
$(saveButton).addClass("disabled");
|
|
LockTabElements();
|
|
$(deleteButton).addClass("disabled");
|
|
ShowErrorMessage({ errorText: errorMessage, enabledReloadLink: false });
|
|
CheckingLocks(contentLockerRequest.tableId, contentLockerRequest.fieldId, 0, saveButton, deleteButton, errorPlaceholder);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
// automatically called every X seconds to extend locked period
|
|
function UpdateLock(contentLockerRequest) {
|
|
if (!updating)
|
|
return;
|
|
$.ajax({
|
|
type: "post",
|
|
url: siteRoot + "/ContentLockerApi/UpdateLock",
|
|
data: contentLockerRequest,
|
|
error: function (returnval) {
|
|
$(saveButton).addClass("disabled");
|
|
LockTabElements();
|
|
$(deleteButton).addClass("disabled");
|
|
ShowErrorMessage();
|
|
},
|
|
success: function (returnval) {
|
|
if (returnval == true) {
|
|
var _currentDate = new Date().getTime();
|
|
var _criticalThreshold = dtLastActivity + _periodOfInactivity * 1000;
|
|
var _warningThreshold = _criticalThreshold - _warningInterval * 1000;
|
|
if (_currentDate >= _warningThreshold && _currentDate < _criticalThreshold) {
|
|
setTimeout(UpdateLock, _isLockCheckIntervalMs, contentLockerRequest);
|
|
setWarningMessage(_criticalThreshold);
|
|
}
|
|
else if (_currentDate < _criticalThreshold) {
|
|
setTimeout(UpdateLock, _isLockCheckIntervalMs, contentLockerRequest);
|
|
dropWarningMessage();
|
|
} else {
|
|
$(saveButton).addClass("disabled");
|
|
LockTabElements();
|
|
$(deleteButton).addClass("disabled");
|
|
ShowErrorMessage({ errorText: timedInactivityText });
|
|
RemoveLock(contentLockerRequest.tableId, contentLockerRequest.fieldId);
|
|
}
|
|
} else {
|
|
$(saveButton).addClass("disabled");
|
|
LockTabElements();
|
|
$(deleteButton).addClass("disabled");
|
|
ShowErrorMessage();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
function setWarningMessage(criticalThreshold) {
|
|
if (intervalId) {
|
|
return;
|
|
}
|
|
|
|
var func = function () {
|
|
var timeLockInterval = (Math.ceil((criticalThreshold - new Date().getTime()) / 1000));
|
|
if (timeLockInterval > 0) {
|
|
ShowErrorMessage({
|
|
errorText: timeoutLockWarning.replace(/\{_X_\}/g, timeLockInterval),
|
|
enabledReloadLink: false,
|
|
className: 'alert alert-warning',
|
|
severity: severity.warning,
|
|
});
|
|
}
|
|
};
|
|
intervalId = setInterval(func, 1000);
|
|
};
|
|
function dropWarningMessage() {
|
|
if (intervalId) {
|
|
clearInterval(intervalId);
|
|
intervalId = undefined;
|
|
}
|
|
RemoveErrorMessage();
|
|
};
|
|
// call it if user leave the edit page or no activity for a long time
|
|
function RemoveLock(tableId, fieldId) {
|
|
var contentLockerRequest = {
|
|
'tableId': tableId,
|
|
'fieldId': fieldId
|
|
};
|
|
|
|
$.ajax({
|
|
type: "post",
|
|
async: false,
|
|
url: siteRoot + "/ContentLockerApi/RemoveLock",
|
|
data: contentLockerRequest
|
|
});
|
|
}
|
|
|
|
// reset timer of inactivity
|
|
function ResetInactivePeriod() {
|
|
dtLastActivity = new Date().getTime();
|
|
}
|
|
|
|
function ShowErrorMessage(settings) {
|
|
// declare default settings for the message
|
|
var _default = {
|
|
errorText: serverErrorText,
|
|
enabledReloadLink: true,
|
|
className: 'alert alert-danger',
|
|
severity: severity.critical,
|
|
};
|
|
// copy all from settings
|
|
var _settings = $.extend({}, _default, settings || {});
|
|
// check if there is element with lower severity and remove it
|
|
var _severity = $('#' + errorPlaceholder).find('div').data('severity');
|
|
if (_severity < _settings.severity) {
|
|
dropWarningMessage();
|
|
}
|
|
|
|
if (document.getElementById(errorPlaceholder).childElementCount == 0) {
|
|
var alertMsg = document.createElement('div');
|
|
alertMsg.className = _settings.className;
|
|
alertMsg.setAttribute('data-severity', _settings.severity);
|
|
|
|
var erormsg = document.createElement('span');
|
|
$(erormsg).html(_settings.errorText);
|
|
|
|
alertMsg.appendChild(erormsg);
|
|
|
|
if (_settings.enabledReloadLink) {
|
|
var linkPlaceholder = document.createElement('span');
|
|
$(linkPlaceholder).css('float', 'right');
|
|
|
|
var link = document.createElement('a');
|
|
link.href = 'javascript:reloadPage()';
|
|
$(link).text("Reload");
|
|
|
|
linkPlaceholder.appendChild(link);
|
|
alertMsg.appendChild(linkPlaceholder);
|
|
}
|
|
document.getElementById(errorPlaceholder).appendChild(alertMsg);
|
|
}
|
|
else if (_severity === _settings.severity) {
|
|
// just replace error text if messages are with the same severity
|
|
$('#' + errorPlaceholder).find('div > span').html(_settings.errorText);
|
|
}
|
|
}
|
|
|
|
// SA. ENV-815
|
|
function reloadPage() {
|
|
document.location.href = contentLockerReloadUrl;
|
|
}
|
|
|
|
function RemoveErrorMessage() {
|
|
var erorRootElement = document.getElementById(errorPlaceholder)
|
|
if (erorRootElement.childElementCount > 0) {
|
|
while (erorRootElement.hasChildNodes()) {
|
|
erorRootElement.removeChild(erorRootElement.lastChild);
|
|
}
|
|
}
|
|
}
|
|
|
|
function ShowPopover(buttonId, message) {
|
|
var btn = null,
|
|
title = '<strong>Not allowed</strong><button type="button" class="close">×</button>';
|
|
// if element with id=buttonId was not found
|
|
if (typeof (buttonId) === 'string')
|
|
btn = $('#' + buttonId);
|
|
else if (typeof (buttonId) === 'object')
|
|
btn = $(buttonId);
|
|
if (btn == null || btn.length == 0)
|
|
return;
|
|
btn.popover({
|
|
html: 'true',
|
|
title: title,
|
|
trigger: 'manual',
|
|
content: message,
|
|
template: '<div class="popover" style="min-width: 250px;"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
|
|
});
|
|
btn.popover('show');
|
|
|
|
// need to fix bug when popover title parameter didn't work when button had title attribute
|
|
btn.data('bs.popover').$tip.find('.popover-title').html(title);
|
|
var originalTitle = btn.data('original-title');
|
|
if (originalTitle) {
|
|
btn.attr('title', originalTitle);
|
|
btn.removeAttr('data-original-title');
|
|
}
|
|
|
|
btn.data('bs.popover').$tip.find('.popover-title').find('button.close').on('click', function (event) {
|
|
btn.popover('destroy');
|
|
if (!event)
|
|
event = window.event;
|
|
event.stopPropagation();
|
|
});
|
|
}
|
|
|
|
function LockTabElements() {
|
|
var lockableElements = document.getElementsByClassName('lockable');
|
|
for (var i = 0; i < lockableElements.length; ++i) {
|
|
var item = lockableElements[i];
|
|
$(item).addClass("disabled");
|
|
}
|
|
}
|
|
|
|
function UnlockTabElements() {
|
|
var lockableElements = document.getElementsByClassName('lockable');
|
|
for (var i = 0; i < lockableElements.length; ++i) {
|
|
var item = lockableElements[i];
|
|
$(item).removeClass("disabled");
|
|
}
|
|
}
|
|
|
|
function StopChecking() {
|
|
checking = false;
|
|
}
|
|
|
|
function StopEdit() {
|
|
updating = false;
|
|
}
|
|
|
|
|
|
|