diff --git a/.mokogitea/workflows/issue-branch.yml b/.mokogitea/workflows/issue-branch.yml index 12a4b11f..63d7fe71 100644 --- a/.mokogitea/workflows/issue-branch.yml +++ b/.mokogitea/workflows/issue-branch.yml @@ -4,8 +4,8 @@ # # FILE INFORMATION # DEFGROUP: MokoGitea.Workflow -# INGROUP: MokoCLI.Automation -# VERSION: 01.00.00 +# INGROUP: mokocli.Automation +# VERSION: 02.63.11 # BRIEF: Auto-create feature branch when an issue is opened name: "Universal: Issue Branch" diff --git a/SECURITY.md b/SECURITY.md index 02864e8f..a4aa3c27 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -23,7 +23,7 @@ DEFGROUP: Template-Joomla INGROUP: Template-Joomla.Documentation REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Joomla PATH: /SECURITY.md -VERSION: 02.63.00 +VERSION: 02.63.11 BRIEF: Security vulnerability reporting and handling policy --> diff --git a/source/packages/MokoSuiteClient b/source/packages/MokoSuiteClient index 81b2453e..050b05d6 160000 --- a/source/packages/MokoSuiteClient +++ b/source/packages/MokoSuiteClient @@ -1 +1 @@ -Subproject commit 81b2453e758754ac63e439d61b05f23f4783afea +Subproject commit 050b05d6efae146a7dc002d434a90cfaf7ba827d diff --git a/source/packages/com_mokosuitebackup/language/en-GB/com_mokosuitebackup.ini b/source/packages/com_mokosuitebackup/language/en-GB/com_mokosuitebackup.ini index 4d4bb101..fa663c7f 100644 --- a/source/packages/com_mokosuitebackup/language/en-GB/com_mokosuitebackup.ini +++ b/source/packages/com_mokosuitebackup/language/en-GB/com_mokosuitebackup.ini @@ -350,6 +350,13 @@ COM_MOKOJOOMBACKUP_RUNBACKUP_BACK_TO_DASHBOARD="Back to dashboard" COM_MOKOJOOMBACKUP_RUNBACKUP_VIEW_RECORD="View backup record" COM_MOKOJOOMBACKUP_RUNBACKUP_LEAVE_WARNING="A backup is in progress. Leaving now will cancel it." COM_MOKOJOOMBACKUP_RUNBACKUP_AUTOCONTINUE="Automatically continue the update when the backup finishes" +COM_MOKOJOOMBACKUP_RUNBACKUP_DONT_CLOSE="Please do not close this window or switch to another window until the backup finishes." +COM_MOKOJOOMBACKUP_RUNBACKUP_UPDATE_RUNNING="Backup complete. The update is now running — please wait and do not close this window…" +COM_MOKOJOOMBACKUP_RUNBACKUP_CANCEL="Cancel backup" +COM_MOKOJOOMBACKUP_RUNBACKUP_CANCEL_CONFIRM1="Cancel the backup that is in progress?" +COM_MOKOJOOMBACKUP_RUNBACKUP_CANCEL_CONFIRM2="Are you sure? The backup will be stopped and the update will NOT continue." +COM_MOKOJOOMBACKUP_RUNBACKUP_CANCELLING="Cancelling…" +COM_MOKOJOOMBACKUP_RUNBACKUP_FAILED_NO_UPDATE="Backup failed — the update was not started. Retry the backup, or go back without updating." COM_MOKOJOOMBACKUP_RUNBACKUP_CONTINUE_UPDATE="Continue the update" COM_MOKOJOOMBACKUP_CONFIG_CLEANUP="Cleanup Defaults" diff --git a/source/packages/com_mokosuitebackup/language/en-US/com_mokosuitebackup.ini b/source/packages/com_mokosuitebackup/language/en-US/com_mokosuitebackup.ini index 7f32636b..61f2219d 100644 --- a/source/packages/com_mokosuitebackup/language/en-US/com_mokosuitebackup.ini +++ b/source/packages/com_mokosuitebackup/language/en-US/com_mokosuitebackup.ini @@ -72,6 +72,13 @@ COM_MOKOJOOMBACKUP_RUNBACKUP_BACK_TO_DASHBOARD="Back to dashboard" COM_MOKOJOOMBACKUP_RUNBACKUP_VIEW_RECORD="View backup record" COM_MOKOJOOMBACKUP_RUNBACKUP_LEAVE_WARNING="A backup is in progress. Leaving now will cancel it." COM_MOKOJOOMBACKUP_RUNBACKUP_AUTOCONTINUE="Automatically continue the update when the backup finishes" +COM_MOKOJOOMBACKUP_RUNBACKUP_DONT_CLOSE="Please do not close this window or switch to another window until the backup finishes." +COM_MOKOJOOMBACKUP_RUNBACKUP_UPDATE_RUNNING="Backup complete. The update is now running — please wait and do not close this window…" +COM_MOKOJOOMBACKUP_RUNBACKUP_CANCEL="Cancel backup" +COM_MOKOJOOMBACKUP_RUNBACKUP_CANCEL_CONFIRM1="Cancel the backup that is in progress?" +COM_MOKOJOOMBACKUP_RUNBACKUP_CANCEL_CONFIRM2="Are you sure? The backup will be stopped and the update will NOT continue." +COM_MOKOJOOMBACKUP_RUNBACKUP_CANCELLING="Cancelling…" +COM_MOKOJOOMBACKUP_RUNBACKUP_FAILED_NO_UPDATE="Backup failed — the update was not started. Retry the backup, or go back without updating." COM_MOKOJOOMBACKUP_RUNBACKUP_CONTINUE_UPDATE="Continue the update" COM_MOKOJOOMBACKUP_CONFIG_CLEANUP="Cleanup Defaults" diff --git a/source/packages/com_mokosuitebackup/mokosuitebackup.xml b/source/packages/com_mokosuitebackup/mokosuitebackup.xml index 3810b08e..ba5cb28b 100644 --- a/source/packages/com_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/com_mokosuitebackup/mokosuitebackup.xml @@ -17,7 +17,7 @@ display label there. --> MokoSuiteBackup - 02.63.00 + 02.63.11 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/02.62.04.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.62.04.sql new file mode 100644 index 00000000..0a0a0e65 --- /dev/null +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.62.04.sql @@ -0,0 +1 @@ +/* 02.62.04 — no schema changes */ diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/02.62.05.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.62.05.sql new file mode 100644 index 00000000..539344ce --- /dev/null +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.62.05.sql @@ -0,0 +1 @@ +/* 02.62.05 — no schema changes */ diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/02.63.01.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.63.01.sql new file mode 100644 index 00000000..6dafb481 --- /dev/null +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.63.01.sql @@ -0,0 +1 @@ +/* 02.63.01 — no schema changes */ diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/02.63.02.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.63.02.sql new file mode 100644 index 00000000..e65aa85e --- /dev/null +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.63.02.sql @@ -0,0 +1 @@ +/* 02.63.02 — no schema changes */ diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/02.63.05.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.63.05.sql new file mode 100644 index 00000000..bc575e1c --- /dev/null +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.63.05.sql @@ -0,0 +1 @@ +/* 02.63.05 — no schema changes */ diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/02.63.06.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.63.06.sql new file mode 100644 index 00000000..7bee5460 --- /dev/null +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.63.06.sql @@ -0,0 +1 @@ +/* 02.63.06 — no schema changes */ diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/02.63.07.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.63.07.sql new file mode 100644 index 00000000..7d7e154f --- /dev/null +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.63.07.sql @@ -0,0 +1 @@ +/* 02.63.07 — no schema changes */ diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/02.63.09.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.63.09.sql new file mode 100644 index 00000000..788cbe28 --- /dev/null +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.63.09.sql @@ -0,0 +1 @@ +/* 02.63.09 — no schema changes */ diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/02.63.10.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.63.10.sql new file mode 100644 index 00000000..39025eb1 --- /dev/null +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.63.10.sql @@ -0,0 +1 @@ +/* 02.63.10 — no schema changes */ diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/02.63.11.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.63.11.sql new file mode 100644 index 00000000..a03acbd5 --- /dev/null +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.63.11.sql @@ -0,0 +1 @@ +/* 02.63.11 — no schema changes */ diff --git a/source/packages/com_mokosuitebackup/tmpl/runbackup/default.php b/source/packages/com_mokosuitebackup/tmpl/runbackup/default.php index 6b2f0a3d..7fb1e458 100644 --- a/source/packages/com_mokosuitebackup/tmpl/runbackup/default.php +++ b/source/packages/com_mokosuitebackup/tmpl/runbackup/default.php @@ -87,6 +87,10 @@ $config = [ 'viewRecord' => Text::_('COM_MOKOJOOMBACKUP_RUNBACKUP_VIEW_RECORD'), 'leaveWarn' => Text::_('COM_MOKOJOOMBACKUP_RUNBACKUP_LEAVE_WARNING'), 'continueUpdate' => Text::_('COM_MOKOJOOMBACKUP_RUNBACKUP_CONTINUE_UPDATE'), + 'cancelConfirm1' => Text::_('COM_MOKOJOOMBACKUP_RUNBACKUP_CANCEL_CONFIRM1'), + 'cancelConfirm2' => Text::_('COM_MOKOJOOMBACKUP_RUNBACKUP_CANCEL_CONFIRM2'), + 'cancelling' => Text::_('COM_MOKOJOOMBACKUP_RUNBACKUP_CANCELLING'), + 'failedNoUpdate' => Text::_('COM_MOKOJOOMBACKUP_RUNBACKUP_FAILED_NO_UPDATE'), ], ]; @@ -120,6 +124,11 @@ $this->getDocument()->addStyleSheet(Uri::root(true) . '/media/com_mokosuitebacku
+ +
@@ -132,10 +141,17 @@ $this->getDocument()->addStyleSheet(Uri::root(true) . '/media/com_mokosuitebacku
- +
+ + +
+ +
@@ -152,6 +168,7 @@ $this->getDocument()->addStyleSheet(Uri::root(true) . '/media/com_mokosuitebacku var CFG = ; var L = CFG.labels || {}; var running = false; + var cancelled = false; var lastRecordId = 0; var el = { @@ -159,6 +176,7 @@ $this->getDocument()->addStyleSheet(Uri::root(true) . '/media/com_mokosuitebacku track: document.querySelector('.msb-rb-progress'), phase: document.getElementById('msb-rb-phase'), status: document.getElementById('msb-rb-status'), + warn: document.getElementById('msb-rb-warn'), title: document.getElementById('msb-rb-title'), actions: document.getElementById('msb-rb-actions'), retry: document.getElementById('msb-rb-retry'), @@ -166,9 +184,38 @@ $this->getDocument()->addStyleSheet(Uri::root(true) . '/media/com_mokosuitebacku continue: document.getElementById('msb-rb-continue'), dashboard: document.getElementById('msb-rb-dashboard'), autocontinue: document.getElementById('msb-rb-autocontinue'), - autocontinueWrap: document.getElementById('msb-rb-autocontinue-wrap') + autocontinueWrap: document.getElementById('msb-rb-autocontinue-wrap'), + cancel: document.getElementById('msb-rb-cancel'), + cancelWrap: document.getElementById('msb-rb-cancel-wrap') }; + function hideCancel() { if (el.cancelWrap) { el.cancelWrap.classList.add('d-none'); } } + + /* Cancel the running backup — requires DOUBLE confirmation. Stops the step + loop, tells the server to cancel the record, and leaves to the dashboard + WITHOUT continuing any pending update. */ + if (el.cancel) { + el.cancel.addEventListener('click', function () { + if (!running || cancelled) { return; } + if (!window.confirm(L.cancelConfirm1 || 'Cancel the backup that is in progress?')) { return; } + if (!window.confirm(L.cancelConfirm2 || 'Are you sure? The backup will be stopped and the update will NOT continue.')) { return; } + + cancelled = true; + running = false; /* also disarms the leave-warning */ + el.cancel.disabled = true; + if (el.warn) { el.warn.classList.add('d-none'); } + setStatus(L.cancelling || 'Cancelling…'); + + var go = function () { window.location.href = CFG.dashboardUrl; }; + /* Best-effort server-side cancel of the record, then leave. */ + if (lastRecordId > 0) { + post({ task: 'ajax.cancelBackup', id: lastRecordId }).then(go, go); + } else { + go(); + } + }); + } + function setBar(pct, striped) { pct = Math.max(0, Math.min(100, parseInt(pct, 10) || 0)); el.bar.style.width = pct + '%'; @@ -204,6 +251,8 @@ $this->getDocument()->addStyleSheet(Uri::root(true) . '/media/com_mokosuitebacku el.bar.classList.add('is-success'); setBar(100, false); el.title.textContent = L.complete || 'Backup complete'; + if (el.warn) { el.warn.classList.add('d-none'); } + hideCancel(); /* Set the one-shot skip flag for THIS action so the following server-side onExtensionBefore(Update|Uninstall) backup is skipped once @@ -254,30 +303,34 @@ $this->getDocument()->addStyleSheet(Uri::root(true) . '/media/com_mokosuitebacku running = false; el.bar.classList.remove('is-animated'); el.bar.classList.add('is-danger'); + if (el.warn) { el.warn.classList.add('d-none'); } el.title.textContent = L.failed || 'Backup failed'; - setStatus(message || 'Backup failed'); + /* Pre-update/uninstall flow: the backup failed, so the update must NOT + run. We deliberately do NOT offer a "continue without backup" option + here — the only ways forward are to retry the backup or go back. */ + setStatus(CFG.returnUrl ? (L.failedNoUpdate || 'Backup failed — the update was not started. Retry the backup, or go back without updating.') : (message || 'Backup failed')); + hideCancel(); showActions(); el.retry.textContent = L.retry || 'Retry'; el.retry.classList.remove('d-none'); el.retry.onclick = function () { el.retry.classList.add('d-none'); - el.continue.classList.add('d-none'); el.bar.classList.remove('is-danger'); el.bar.classList.add('is-animated'); run(); }; - if (CFG.returnUrl) { - showBtn(el.continue, L.continue || 'Continue without backup', CFG.returnUrl); - } showBtn(el.dashboard, L.dashboard || 'Back to dashboard', CFG.dashboardUrl); } async function run() { if (running) { return; } running = true; + cancelled = false; el.actions.classList.add('d-none'); + if (el.cancelWrap) { el.cancelWrap.classList.remove('d-none'); } + if (el.cancel) { el.cancel.disabled = false; } setBar(0, true); setPhase(''); setStatus(L.starting || 'Starting backup…'); @@ -295,7 +348,7 @@ $this->getDocument()->addStyleSheet(Uri::root(true) . '/media/com_mokosuitebacku if (init.record_id) { lastRecordId = init.record_id; } var done = false; - while (!done) { + while (!done && !cancelled) { var step = await post({ task: 'ajax.step', session_id: init.session_id }); if (!step || step.error) { @@ -309,16 +362,27 @@ $this->getDocument()->addStyleSheet(Uri::root(true) . '/media/com_mokosuitebacku done = step.done || false; } + /* User cancelled mid-flight — the click handler already stops the + loop and navigates away, so do not fall through to completion. */ + if (cancelled) { return; } + running = false; await onComplete(); } catch (err) { + if (cancelled) { return; } onError(err && err.message ? err.message : String(err)); } } - /* Warn before leaving while a backup is mid-flight. */ + /* Warn before closing/leaving the window while a backup is mid-flight. + Return the message too — some browsers need it, others show a generic + prompt, but any non-empty value triggers the confirmation dialog. */ window.addEventListener('beforeunload', function (e) { - if (running) { e.preventDefault(); e.returnValue = L.leaveWarn || ''; } + if (!running) { return undefined; } + var msg = L.leaveWarn || 'A backup is in progress. Leaving now will cancel it.'; + e.preventDefault(); + e.returnValue = msg; + return msg; }); if (CFG.autostart) { diff --git a/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml b/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml index 635e02ce..280471a7 100644 --- a/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml +++ b/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml @@ -8,7 +8,7 @@ --> Module - MokoSuiteBackup - cPanel - 02.63.00 + 02.63.11 2026-06-23 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml index 37f84e85..db6cd99e 100644 --- a/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Action Log - MokoSuiteBackup - 02.63.00 + 02.63.11 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml index 84bba0bb..9486c862 100644 --- a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Console - MokoSuiteBackup - 02.63.00 + 02.63.11 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml index 846f70b7..228a6777 100644 --- a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Content - MokoSuiteBackup - 02.63.00 + 02.63.11 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml index 16e56133..9b41d94d 100644 --- a/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml @@ -1,7 +1,7 @@ Quick Icon - MokoSuiteBackup - 02.63.00 + 02.63.11 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_system_mokosuitebackup/language/en-GB/plg_system_mokosuitebackup.ini b/source/packages/plg_system_mokosuitebackup/language/en-GB/plg_system_mokosuitebackup.ini index a465eb30..7cc78952 100644 --- a/source/packages/plg_system_mokosuitebackup/language/en-GB/plg_system_mokosuitebackup.ini +++ b/source/packages/plg_system_mokosuitebackup/language/en-GB/plg_system_mokosuitebackup.ini @@ -14,3 +14,4 @@ PLG_SYSTEM_MOKOJOOMBACKUP_BACKING_UP="Backing up…" PLG_SYSTEM_MOKOJOOMBACKUP_BACKUP_COMPLETE="Backup complete — safe to update." PLG_SYSTEM_MOKOJOOMBACKUP_BACKUP_FAILED="Backup failed" PLG_SYSTEM_MOKOJOOMBACKUP_BACKUP_STARTING="Starting backup…" +PLG_SYSTEM_MOKOSUITEBACKUP_UPDATE_RUNNING="Backup complete. The update is now running — please wait and do not close this window…" diff --git a/source/packages/plg_system_mokosuitebackup/language/en-US/plg_system_mokosuitebackup.ini b/source/packages/plg_system_mokosuitebackup/language/en-US/plg_system_mokosuitebackup.ini index 03a35287..12552aea 100644 --- a/source/packages/plg_system_mokosuitebackup/language/en-US/plg_system_mokosuitebackup.ini +++ b/source/packages/plg_system_mokosuitebackup/language/en-US/plg_system_mokosuitebackup.ini @@ -14,3 +14,4 @@ PLG_SYSTEM_MOKOJOOMBACKUP_BACKING_UP="Backing up…" PLG_SYSTEM_MOKOJOOMBACKUP_BACKUP_COMPLETE="Backup complete — safe to update." PLG_SYSTEM_MOKOJOOMBACKUP_BACKUP_FAILED="Backup failed" PLG_SYSTEM_MOKOJOOMBACKUP_BACKUP_STARTING="Starting backup…" +PLG_SYSTEM_MOKOSUITEBACKUP_UPDATE_RUNNING="Backup complete. The update is now running — please wait and do not close this window…" diff --git a/source/packages/plg_system_mokosuitebackup/media/js/installer-backup.js b/source/packages/plg_system_mokosuitebackup/media/js/installer-backup.js index e3f5ac4a..ea20bef0 100644 --- a/source/packages/plg_system_mokosuitebackup/media/js/installer-backup.js +++ b/source/packages/plg_system_mokosuitebackup/media/js/installer-backup.js @@ -101,6 +101,31 @@ window.location.href = target; }, true); + /* Full-screen "update is running" overlay shown while the re-fired update + POST processes, so the user knows it is working and not to close/switch. */ + function showUpdateOverlay() { + if (document.getElementById('msb-update-overlay')) { return; } + + var o = document.createElement('div'); + o.id = 'msb-update-overlay'; + o.setAttribute('role', 'status'); + o.style.cssText = 'position:fixed;inset:0;z-index:2147483647;background:#000;color:#fff;' + + 'display:flex;flex-direction:column;align-items:center;justify-content:center;' + + 'text-align:center;padding:2rem;font-size:1.15rem;font-weight:600;'; + + var spin = document.createElement('span'); + spin.className = 'spinner-border mb-3'; + spin.setAttribute('aria-hidden', 'true'); + + var msg = document.createElement('div'); + msg.textContent = (cfg && cfg.updateRunningText) + || 'Backup complete. The update is now running — please wait and do not close this window…'; + + o.appendChild(spin); + o.appendChild(msg); + document.body.appendChild(o); + } + /* On return from the backup screen: restore the selection and re-fire. */ function resume() { var params = new URLSearchParams(window.location.search); @@ -131,20 +156,40 @@ if (box) { box.checked = true; } }); - /* Joomla's list-check reads boxchecked — set it so the re-fire passes. */ + /* Restore boxchecked AND fire its `change` event. Joomla's toolbar web + component (joomla-toolbar-button) keeps a list-selection button + DISABLED until boxchecked changes via a change event — setting the + value alone leaves the button disabled, so executeTask() would no-op + and the update never submits (it just returns to the list). */ var bc = form.querySelector('input[name="boxchecked"]'); - if (bc) { bc.value = (data.cids || []).length; } + if (bc) { + bc.value = (data.cids || []).length; + bc.dispatchEvent(new Event('change', { bubbles: true })); + } } window.__msbResuming = true; - var btn = document.querySelector('[task="' + data.task + '"]'); + /* Show a full-screen "update is running" overlay so the user gets clear + feedback that the update is proceeding while the re-fired POST runs. + It persists until the page navigates away (the update finishes and + redirects), matching the black full-screen backup screen. */ + showUpdateOverlay(); - if (btn) { - window.setTimeout(function () { btn.click(); }, 300); - } else if (window.Joomla && typeof Joomla.submitbutton === 'function') { - Joomla.submitbutton(data.task); - } + /* Re-fire the toolbar action. The `task` attribute is on the OUTER + , but its click handler is bound to the INNER +