From ae47646b3b4ed01f2b2258ff8f4377957b95f602 Mon Sep 17 00:00:00 2001 From: Artur Kyryliuk Date: Sat, 29 Aug 2026 21:00:26 +0200 Subject: [PATCH] fix(manager): stop an unknown template id from looping on an empty alert Opening ?a=16 with an id that has no record produced an alert box with no text, and then reloaded the same URL for as long as the tab was open. Two causes, one symptom: * Controllers\Template::parameterData() passed a literal English sentence to alertAndQuit(), whose second argument defaults to $lexicon = true. getLexicon() returns '' for a key it does not know, so the message was empty. Chunk, Snippet, Plugin and MoveDocument all pass false here for a literal; Template was the one that did not. * webAlertAndQuit() falls back to history.back(-1) when it is given no URL. On a page that alerts as soon as it is opened, going back lands on the request that raised the alert, which alerts again. Chrome suppresses repeat dialogs after the first, so it runs silently. alertAndQuit() takes a $url now and passes it through, and an unknown lexicon key falls back to the string it was given, so no alert can be blank again. Template sends the user to its own Cancel target. Also fixes the stylesheet the alert page loads for itself: $path already ends in '/', so appending '/css/styles.min.css' asked for media/style/default//css/styles.min.css. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01MXdDGZnGP6vGt9zTDG5o3n --- core/src/Controllers/Template.php | 11 ++++++++++- core/src/Core.php | 4 ++-- core/src/ManagerTheme.php | 15 ++++++++++++--- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/core/src/Controllers/Template.php b/core/src/Controllers/Template.php index d450d4290a..eda892c152 100644 --- a/core/src/Controllers/Template.php +++ b/core/src/Controllers/Template.php @@ -159,7 +159,16 @@ protected function parameterData() if ($id > 0) { if (!$data->exists) { - $this->managerTheme->alertAndQuit('No database record has been found for this template.'); + // false: the message is the message, not a lexicon key - and a + // key that does not exist used to resolve to '', so this alert + // was empty. The URL is the page's own Cancel target: without + // one the alert falls back to history.back(-1), straight into + // the request that raised it. + $this->managerTheme->alertAndQuit( + 'No database record has been found for this template.', + false, + 'index.php?a=76&tab=0' + ); } $_SESSION['itemname'] = $data->templatename; diff --git a/core/src/Core.php b/core/src/Core.php index 1d2061e943..d937b554ac 100644 --- a/core/src/Core.php +++ b/core/src/Core.php @@ -3610,8 +3610,8 @@ public function webAlertAndQuit($msg, $url = '') $style = ''; if (IN_MANAGER_MODE) { $path = 'media/style/' . $this->getConfig('manager_theme') . '/'; - if (is_file(EVO_MANAGER_PATH . $path . '/css/styles.min.css')) { - $file_name = '/css/styles.min.css'; + if (is_file(EVO_MANAGER_PATH . $path . 'css/styles.min.css')) { + $file_name = 'css/styles.min.css'; } else { $file_name = 'style.css'; } diff --git a/core/src/ManagerTheme.php b/core/src/ManagerTheme.php index 25e6799b2b..f37a509758 100644 --- a/core/src/ManagerTheme.php +++ b/core/src/ManagerTheme.php @@ -838,12 +838,21 @@ public function getCore(): CoreInterface /** * @inheritdoc */ - public function alertAndQuit(string $message, $lexicon = true): void + /** + * @param string $message a lexicon key, or the message itself when $lexicon is false + * @param bool $lexicon whether $message is a key to look up + * @param string $url where to send the user after the alert. Empty means + * history.back(-1), which on a page that alerts as soon + * as it is opened returns to the page that alerts - a + * loop the user cannot leave. Pass a destination + * whenever the alert ends the page. + */ + public function alertAndQuit(string $message, $lexicon = true, string $url = ''): void { if ($lexicon) { - $message = $this->getLexicon($message); + $message = $this->getLexicon($message, $message); } - $this->getCore()->webAlertAndQuit($message); + $this->getCore()->webAlertAndQuit($message, $url); } public function isLoadDatePicker(): bool