123 lines
4.8 KiB
JavaScript
123 lines
4.8 KiB
JavaScript
/**
|
|
* BatchOverlay — shared full-screen progress overlay.
|
|
*
|
|
* Usage:
|
|
* BatchOverlay.show(title, total, options)
|
|
* options: { unit: 'documents', color: '#dc3545' }
|
|
*
|
|
* BatchOverlay.update(done, total, currentItem)
|
|
* Advances the bar and ETA. currentItem shown in the sub-line.
|
|
*
|
|
* BatchOverlay.done(message, onClose)
|
|
* Switches to "complete" state — green checkmark + Done button.
|
|
* onClose fires when the user dismisses.
|
|
*
|
|
* BatchOverlay.hide()
|
|
* Force-hides (use for error bail-outs before done is reached).
|
|
*/
|
|
var BatchOverlay = (function () {
|
|
|
|
var _startMs = 0;
|
|
var _onClose = null;
|
|
var _unit = 'items';
|
|
var _color = '#0d6efd';
|
|
var _injected = false;
|
|
|
|
var _HTML = '<div id="bos-wrap" style="display:none;position:fixed;inset:0;z-index:9999;' +
|
|
'background:rgba(0,0,0,0.55);align-items:center;justify-content:center;">' +
|
|
'<div class="card shadow-lg p-4 text-center" style="min-width:380px;max-width:480px;width:90%;">' +
|
|
'<div id="bos-spinner" class="spinner-border mx-auto mb-3" role="status" style="width:2.5rem;height:2.5rem;"></div>' +
|
|
'<div id="bos-icon" class="mx-auto mb-3" style="display:none;font-size:2.5rem;color:#198754;"><i class="ti ti-circle-check"></i></div>' +
|
|
'<div class="fw-semibold fs-6 mb-1" id="bos-title">Processing…</div>' +
|
|
'<div class="text-muted small mb-4" id="bos-sub"></div>' +
|
|
'<div id="bos-pct" style="font-size:3rem;font-weight:700;line-height:1;letter-spacing:-1px;">0%</div>' +
|
|
'<div class="text-muted small mb-3" id="bos-count"></div>' +
|
|
'<div class="progress mb-2" style="height:10px;border-radius:6px;">' +
|
|
'<div id="bos-bar" class="progress-bar progress-bar-striped progress-bar-animated"' +
|
|
' role="progressbar" style="width:0%;border-radius:6px;"' +
|
|
' aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>' +
|
|
'</div>' +
|
|
'<div class="text-muted small" id="bos-eta"> </div>' +
|
|
'<button id="bos-close" class="btn btn-success mt-3" style="display:none;">' +
|
|
'<i class="ti ti-check me-1"></i>Done' +
|
|
'</button>' +
|
|
'</div></div>';
|
|
|
|
function _inject() {
|
|
if (_injected) return;
|
|
$('body').append(_HTML);
|
|
$('#bos-close').on('click', function () {
|
|
_resetState();
|
|
$('#bos-wrap').hide();
|
|
if (_onClose) { _onClose(); _onClose = null; }
|
|
});
|
|
_injected = true;
|
|
}
|
|
|
|
function _resetState() {
|
|
$('#bos-spinner').show().css('color', _color);
|
|
$('#bos-icon').hide();
|
|
$('#bos-pct').css('color', _color);
|
|
$('#bos-bar')
|
|
.addClass('progress-bar-striped progress-bar-animated')
|
|
.removeClass('bg-success')
|
|
.css('background-color', _color)
|
|
.css('width', '0%').attr('aria-valuenow', 0);
|
|
$('#bos-close').hide();
|
|
$('#bos-eta').html(' ');
|
|
}
|
|
|
|
function show(title, total, options) {
|
|
options = options || {};
|
|
_unit = options.unit || 'items';
|
|
_color = options.color || '#0d6efd';
|
|
_onClose = options.onClose || null;
|
|
_startMs = Date.now();
|
|
|
|
_inject();
|
|
_resetState();
|
|
|
|
$('#bos-title').text(title);
|
|
$('#bos-sub').text('Starting…');
|
|
$('#bos-pct').text('0%');
|
|
$('#bos-count').text('0 / ' + total + ' ' + _unit);
|
|
$('#bos-wrap').css('display', 'flex');
|
|
}
|
|
|
|
function update(done, total, currentItem) {
|
|
var pct = Math.round(done / total * 100);
|
|
var elapsed = (Date.now() - _startMs) / 1000;
|
|
var eta = ' ';
|
|
if (done > 0) {
|
|
var remaining = Math.round((elapsed / done) * (total - done));
|
|
eta = remaining > 0 ? ('~' + remaining + 's remaining') : 'almost done…';
|
|
}
|
|
$('#bos-pct').text(pct + '%');
|
|
$('#bos-bar').css('width', pct + '%').attr('aria-valuenow', pct);
|
|
$('#bos-count').text(done + ' / ' + total + ' ' + _unit);
|
|
if (currentItem !== undefined) $('#bos-sub').text('Processing ' + currentItem + '…');
|
|
$('#bos-eta').html(eta);
|
|
}
|
|
|
|
function done(message, onClose) {
|
|
_onClose = onClose || null;
|
|
$('#bos-spinner').hide();
|
|
$('#bos-icon').show();
|
|
$('#bos-pct').text('100%').css('color', '#198754');
|
|
$('#bos-bar')
|
|
.removeClass('progress-bar-striped progress-bar-animated')
|
|
.css('background-color', '').addClass('bg-success')
|
|
.css('width', '100%').attr('aria-valuenow', 100);
|
|
$('#bos-sub').text(message || 'Complete.');
|
|
$('#bos-eta').html(' ');
|
|
$('#bos-close').show();
|
|
}
|
|
|
|
function hide() {
|
|
if (_injected) $('#bos-wrap').hide();
|
|
}
|
|
|
|
return { show: show, update: update, done: done, hide: hide };
|
|
|
|
})();
|