|
|
|
@@ -497,6 +497,88 @@
|
|
|
|
|
return default_value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var renderBootstrapTableLoadErrorState = function ($table) {
|
|
|
|
|
var $wrapper = $table.closest('.bootstrap-table');
|
|
|
|
|
|
|
|
|
|
if (!$wrapper.length) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var statusCode = parseInt($table.data('bs-table-load-error-status'), 10);
|
|
|
|
|
var statusSuffix = Number.isFinite(statusCode) && statusCode > 0 ? ' (HTTP ' + statusCode + ')' : '';
|
|
|
|
|
|
|
|
|
|
var errorHtml = '<div class="text-danger">'
|
|
|
|
|
+ '<i class="fas fa-triangle-exclamation" aria-hidden="true"></i> '
|
|
|
|
|
+ '{{ trans('general.search_load_error_short') }}' + statusSuffix
|
|
|
|
|
+ '<div class="text-muted" style="margin-top: 4px;">{{ trans('general.search_load_error_help') }}</div>'
|
|
|
|
|
+ '</div>';
|
|
|
|
|
|
|
|
|
|
var $targets = $wrapper.find('.fixed-table-body .no-records-found td, .fixed-table-body .fixed-table-loading');
|
|
|
|
|
|
|
|
|
|
if (!$targets.length) {
|
|
|
|
|
// On initial load errors, bootstrap-table can insert the no-records row
|
|
|
|
|
// after the load-error callback fires. Observe DOM changes briefly and
|
|
|
|
|
// render the error state once the row appears, then disconnect.
|
|
|
|
|
var existingObserver = $table.data('bs-table-load-error-observer');
|
|
|
|
|
if (existingObserver) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var wrapperNode = $wrapper.get(0);
|
|
|
|
|
if (!wrapperNode || typeof MutationObserver === 'undefined') {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var observer = new MutationObserver(function () {
|
|
|
|
|
if ($table.data('bs-table-load-error') !== true) {
|
|
|
|
|
observer.disconnect();
|
|
|
|
|
$table.removeData('bs-table-load-error-observer');
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var $newTargets = $wrapper.find('.fixed-table-body .no-records-found td, .fixed-table-body .fixed-table-loading');
|
|
|
|
|
if ($newTargets.length) {
|
|
|
|
|
observer.disconnect();
|
|
|
|
|
$table.removeData('bs-table-load-error-observer');
|
|
|
|
|
renderBootstrapTableLoadErrorState($table);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
observer.observe(wrapperNode, { childList: true, subtree: true });
|
|
|
|
|
$table.data('bs-table-load-error-observer', observer);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var activeObserver = $table.data('bs-table-load-error-observer');
|
|
|
|
|
if (activeObserver) {
|
|
|
|
|
activeObserver.disconnect();
|
|
|
|
|
$table.removeData('bs-table-load-error-observer');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$targets.html(errorHtml);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var resolveHttpStatusFromLoadErrorArgs = function () {
|
|
|
|
|
for (var i = 0; i < arguments.length; i++) {
|
|
|
|
|
var arg = arguments[i];
|
|
|
|
|
if (!arg) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (typeof arg === 'number' && arg > 0) {
|
|
|
|
|
return arg;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (typeof arg === 'object' && typeof arg.status === 'number' && arg.status > 0) {
|
|
|
|
|
return arg.status;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var initialAdvancedSearchOperator = getStoredAdvancedSearchOperator() || normalizeAdvancedSearchOperator(data_with_default('advanced-search-operator', defaultAdvancedSearchOperator));
|
|
|
|
@@ -607,8 +689,38 @@
|
|
|
|
|
exportOptions: export_options,
|
|
|
|
|
exportTypes: ['xlsx', 'excel', 'csv', 'pdf', 'json', 'xml', 'txt', 'sql', 'doc'],
|
|
|
|
|
onLoadSuccess: function () { // possible 'fixme'? this might be for contents, not for headers?
|
|
|
|
|
// Clear transport/server error state so genuine empty results show normal messaging.
|
|
|
|
|
$(this).data('bs-table-load-error', false);
|
|
|
|
|
$(this).removeData('bs-table-load-error-status');
|
|
|
|
|
var observer = $(this).data('bs-table-load-error-observer');
|
|
|
|
|
if (observer) {
|
|
|
|
|
observer.disconnect();
|
|
|
|
|
$(this).removeData('bs-table-load-error-observer');
|
|
|
|
|
}
|
|
|
|
|
$('[data-tooltip="true"]').tooltip(); // Needed to attach tooltips after ajax call
|
|
|
|
|
},
|
|
|
|
|
onLoadError: function () {
|
|
|
|
|
// Mark this table as failed so formatNoMatches can render an explicit error state
|
|
|
|
|
// instead of the misleading "no records" empty-state message.
|
|
|
|
|
var $table = $(this);
|
|
|
|
|
$table.data('bs-table-load-error', true);
|
|
|
|
|
var statusCode = resolveHttpStatusFromLoadErrorArgs.apply(null, arguments);
|
|
|
|
|
if (statusCode) {
|
|
|
|
|
$table.data('bs-table-load-error-status', statusCode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// On first page load, bootstrap-table may already have rendered the default
|
|
|
|
|
// no-records row. Force-replace that content immediately after the error.
|
|
|
|
|
renderBootstrapTableLoadErrorState($table);
|
|
|
|
|
},
|
|
|
|
|
onPostBody: function () {
|
|
|
|
|
// Keep the error empty-state stable if bootstrap-table re-renders body rows
|
|
|
|
|
// while the current table state is still a transport/server error.
|
|
|
|
|
var $table = $(this);
|
|
|
|
|
if ($table.data('bs-table-load-error') === true) {
|
|
|
|
|
renderBootstrapTableLoadErrorState($table);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
onPostHeader: function () {
|
|
|
|
|
var lookup = {};
|
|
|
|
|
var lookup_initialized = false;
|
|
|
|
@@ -666,11 +778,42 @@
|
|
|
|
|
|
|
|
|
|
},
|
|
|
|
|
formatNoMatches: function () {
|
|
|
|
|
if ($(this).data('bs-table-load-error') === true) {
|
|
|
|
|
var statusCode = parseInt($(this).data('bs-table-load-error-status'), 10);
|
|
|
|
|
var statusSuffix = Number.isFinite(statusCode) && statusCode > 0 ? ' (HTTP ' + statusCode + ')' : '';
|
|
|
|
|
return '<div class="text-danger" style="padding: 8px 0;">'
|
|
|
|
|
+ '<i class="fas fa-triangle-exclamation" aria-hidden="true" style="margin-right: 6px;"></i>'
|
|
|
|
|
+ '{{ trans('general.search_load_error_short') }}' + statusSuffix
|
|
|
|
|
+ '<div class="text-muted" style="margin-top: 4px;">{{ trans('general.search_load_error_help') }}</div>'
|
|
|
|
|
+ '</div>';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return '{{ trans('table.no_matching_records') }}';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Event-driven fallback for initial-load timing/callback-context edge cases.
|
|
|
|
|
// In some bootstrap-table flows, onLoadError can race before the empty row exists
|
|
|
|
|
// or callback context may not be the raw table element. These events are emitted
|
|
|
|
|
// from the table node itself and are reliable across initial load and searches.
|
|
|
|
|
var $currentTable = $(this);
|
|
|
|
|
$currentTable.off('.snipeLoadState').on('load-success.bs.table.snipeLoadState', function () {
|
|
|
|
|
$currentTable.data('bs-table-load-error', false);
|
|
|
|
|
$currentTable.removeData('bs-table-load-error-status');
|
|
|
|
|
}).on('load-error.bs.table.snipeLoadState', function () {
|
|
|
|
|
$currentTable.data('bs-table-load-error', true);
|
|
|
|
|
var statusCode = resolveHttpStatusFromLoadErrorArgs.apply(null, Array.prototype.slice.call(arguments, 1));
|
|
|
|
|
if (statusCode) {
|
|
|
|
|
$currentTable.data('bs-table-load-error-status', statusCode);
|
|
|
|
|
}
|
|
|
|
|
renderBootstrapTableLoadErrorState($currentTable);
|
|
|
|
|
}).on('post-body.bs.table.snipeLoadState', function () {
|
|
|
|
|
if ($currentTable.data('bs-table-load-error') === true) {
|
|
|
|
|
renderBootstrapTableLoadErrorState($currentTable);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var bootstrapTableInstance = $(this).data('bootstrap.table');
|
|
|
|
|
|
|
|
|
|
if (bootstrapTableInstance && typeof bootstrapTableInstance.renderAdvancedSearchTags === 'function') {
|
|
|
|
|