Files

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">&nbsp;</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('&nbsp;');
}
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 = '&nbsp;';
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('&nbsp;');
$('#bos-close').show();
}
function hide() {
if (_injected) $('#bos-wrap').hide();
}
return { show: show, update: update, done: done, hide: hide };
})();