gl-website-deployer/admin/phpMyAdmin/js/dist/error_report.js
2024-11-19 08:02:04 +01:00

285 lines
9.0 KiB
JavaScript

/* global TraceKit */ // js/vendor/tracekit.js
/**
* general function, usually for data manipulation pages
*
*/
var ErrorReport = {
/**
* @var {object}, stores the last exception info
*/
lastException: null,
/**
* @var object stores the Error Report Data to prevent unnecessary data fetching
*/
errorReportData: null,
/**
* @var object maintains unique keys already used
*/
keyDict: {},
/**
* handles thrown error exceptions based on user preferences
*
* @param {object} data
* @param {any} exception
* @return {void}
*/
errorDataHandler: function (data, exception) {
if (data.success !== true) {
Functions.ajaxShowMessage(data.error, false);
return;
}
if (data.report_setting === 'ask') {
ErrorReport.showErrorNotification();
} else if (data.report_setting === 'always') {
var reportData = ErrorReport.getReportData(exception);
var postData = $.extend(reportData, {
'send_error_report': true,
'automatic': true
});
$.post('index.php?route=/error-report', postData, function (data) {
if (data.success === false) {
// in the case of an error, show the error message returned.
Functions.ajaxShowMessage(data.error, false);
} else {
Functions.ajaxShowMessage(data.message, false);
}
});
}
},
errorHandler: function (exception) {
// issue: 14359
if (JSON.stringify(ErrorReport.lastException) === JSON.stringify(exception)) {
return;
}
if (exception.name === null || typeof exception.name === 'undefined') {
exception.name = ErrorReport.extractExceptionName(exception);
}
ErrorReport.lastException = exception;
if (ErrorReport.errorReportData === null) {
$.post('index.php?route=/error-report', {
'ajax_request': true,
'server': CommonParams.get('server'),
'get_settings': true,
'exception_type': 'js'
}, function (data) {
ErrorReport.errorReportData = data;
ErrorReport.errorDataHandler(data, exception);
});
} else {
ErrorReport.errorDataHandler(ErrorReport.errorReportData, exception);
}
},
/**
* Shows the modal dialog previewing the report
*
* @param exception object error report info
*
* @return {void}
*/
showReportDialog: function (exception) {
const reportData = ErrorReport.getReportData(exception);
const sendErrorReport = function () {
const postData = $.extend(reportData, {
'send_error_report': true,
'description': $('#errorReportDescription').val(),
'always_send': $('#errorReportAlwaysSendCheckbox')[0].checked
});
$.post('index.php?route=/error-report', postData, function (data) {
if (data.success === false) {
Functions.ajaxShowMessage(data.error, false);
} else {
Functions.ajaxShowMessage(data.message, 3000);
}
});
$('#errorReportModal').modal('hide');
};
$.post('index.php?route=/error-report', reportData).done(function (data) {
// Delete the modal to refresh it in case the user changed SendErrorReports value
if (document.getElementById('errorReportModal') !== null) {
$('#errorReportModal').remove();
}
$('body').append($(data.report_modal));
const $errorReportModal = $('#errorReportModal');
$errorReportModal.on('show.bs.modal', function () {
// Prevents multiple onClick events
$('#errorReportModalConfirm').off('click', sendErrorReport);
$('#errorReportModalConfirm').on('click', sendErrorReport);
$('#errorReportModal .modal-body').html(data.message);
});
$errorReportModal.modal('show');
});
},
/**
* Shows the small notification that asks for user permission
*
* @return {void}
*/
showErrorNotification: function () {
var key = Math.random().toString(36).substring(2, 12);
while (key in ErrorReport.keyDict) {
key = Math.random().toString(36).substring(2, 12);
}
ErrorReport.keyDict[key] = 1;
var $div = $('<div class="alert alert-danger" role="alert" id="error_notification_' + key + '"></div>').append(Functions.getImage('s_error') + Messages.strErrorOccurred);
var $buttons = $('<div class="float-end"></div>');
var buttonHtml = '<button class="btn btn-primary" id="show_error_report_' + key + '">';
buttonHtml += Messages.strShowReportDetails;
buttonHtml += '</button>';
var settingsUrl = 'index.php?route=/preferences/features&server=' + CommonParams.get('server');
buttonHtml += '<a class="ajax" href="' + settingsUrl + '">';
buttonHtml += Functions.getImage('s_cog', Messages.strChangeReportSettings);
buttonHtml += '</a>';
buttonHtml += '<a href="#" id="ignore_error_' + key + '" data-notification-id="' + key + '">';
buttonHtml += Functions.getImage('b_close', Messages.strIgnore);
buttonHtml += '</a>';
$buttons.html(buttonHtml);
$div.append($buttons);
// eslint-disable-next-line compat/compat
$div.appendTo(document.body);
$(document).on('click', '#show_error_report_' + key, ErrorReport.createReportDialog);
$(document).on('click', '#ignore_error_' + key, ErrorReport.removeErrorNotification);
},
/**
* Removes the notification if it was displayed before
*
* @param {Event} e
* @return {void}
*/
removeErrorNotification: function (e) {
if (e) {
// don't remove the hash fragment by navigating to #
e.preventDefault();
}
$('#error_notification_' + $(this).data('notification-id')).fadeOut(function () {
$(this).remove();
});
},
/**
* Extracts Exception name from message if it exists
*
* @param exception
* @return {string}
*/
extractExceptionName: function (exception) {
if (exception.message === null || typeof exception.message === 'undefined') {
return '';
}
var reg = /([a-zA-Z]+):/;
var regexResult = reg.exec(exception.message);
if (regexResult && regexResult.length === 2) {
return regexResult[1];
}
return '';
},
/**
* Shows the modal dialog previewing the report
*
* @return {void}
*/
createReportDialog: function () {
ErrorReport.removeErrorNotification();
ErrorReport.showReportDialog(ErrorReport.lastException);
},
/**
* Returns the report data to send to the server
*
* @param exception object exception info
*
* @return {object}
*/
getReportData: function (exception) {
if (exception && exception.stack && exception.stack.length) {
for (var i = 0; i < exception.stack.length; i++) {
var stack = exception.stack[i];
if (stack.context && stack.context.length) {
for (var j = 0; j < stack.context.length; j++) {
if (stack.context[j].length > 80) {
stack.context[j] = stack.context[j].substring(-1, 75) + '//...';
}
}
}
}
}
var reportData = {
'server': CommonParams.get('server'),
'ajax_request': true,
'exception': exception,
'url': window.location.href,
'exception_type': 'js'
};
if (AJAX.scriptHandler.scripts.length > 0) {
reportData.scripts = AJAX.scriptHandler.scripts.map(function (script) {
return script;
});
}
return reportData;
},
/**
* Wraps given function in error reporting code and returns wrapped function
*
* @param {Function} func function to be wrapped
*
* @return {Function}
*/
wrapFunction: function (func) {
if (!func.wrapped) {
var newFunc = function () {
try {
return func.apply(this, arguments);
} catch (x) {
TraceKit.report(x);
}
};
newFunc.wrapped = true;
// Set guid of wrapped function same as original function, so it can be removed
// See bug#4146 (problem with jquery draggable and sortable)
newFunc.guid = func.guid = func.guid || newFunc.guid || jQuery.guid++;
return newFunc;
} else {
return func;
}
},
/**
* Automatically wraps the callback in AJAX.registerOnload
*
* @return {void}
*/
wrapAjaxOnloadCallback: function () {
var oldOnload = AJAX.registerOnload;
AJAX.registerOnload = function (file, func) {
var wrappedFunction = ErrorReport.wrapFunction(func);
oldOnload.call(this, file, wrappedFunction);
};
},
/**
* Automatically wraps the callback in $.fn.on
*
* @return {void}
*/
wrapJqueryOnCallback: function () {
var oldOn = $.fn.on;
$.fn.on = function () {
for (var i = 1; i <= 3; i++) {
if (typeof arguments[i] === 'function') {
arguments[i] = ErrorReport.wrapFunction(arguments[i]);
break;
}
}
return oldOn.apply(this, arguments);
};
},
/**
* Wraps the callback in AJAX.registerOnload automatically
*
* @return {void}
*/
setUpErrorReporting: function () {
ErrorReport.wrapAjaxOnloadCallback();
ErrorReport.wrapJqueryOnCallback();
}
};
AJAX.registerOnload('error_report.js', function () {
TraceKit.report.subscribe(ErrorReport.errorHandler);
ErrorReport.setUpErrorReporting();
});