From 5afce50d7706a9514c65be88051da03948096ddb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20D=C3=ADaz?= Date: Thu, 4 Jun 2026 11:57:33 +0200 Subject: [PATCH] [FIX] LTI: Keep embedded targets in iframe --- .../classes/Screen/LtiViewLayoutProvider.php | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/components/ILIAS/LTIProvider/classes/Screen/LtiViewLayoutProvider.php b/components/ILIAS/LTIProvider/classes/Screen/LtiViewLayoutProvider.php index efc6caf9419a..9daad5f60c50 100644 --- a/components/ILIAS/LTIProvider/classes/Screen/LtiViewLayoutProvider.php +++ b/components/ILIAS/LTIProvider/classes/Screen/LtiViewLayoutProvider.php @@ -59,6 +59,7 @@ public function isInterestedInContexts(): ContextCollection public function getPageBuilderDecorator(CalledContexts $screen_context_stack): ?PageBuilderModification { $this->globalScreen()->layout()->meta()->addCss('./components/ILIAS/LTIProvider/templates/default/lti.css'); + $this->disableTopFrameTargets(); $is_exit_mode = $this->isLTIExitMode($screen_context_stack); $external_css = ($is_exit_mode) ? '' : $this->dic["lti"]->getExternalCss(); if ($external_css !== '') { @@ -81,6 +82,32 @@ function (PagePartProvider $parts): Page { ->withHighPriority(); } + private function disableTopFrameTargets(): void + { + $this->dic->ui()->mainTemplate()->addOnLoadCode(<<<'JS' +(function () { + if (window.self === window.top) { + return; + } + var update = function (root) { + root.querySelectorAll('a[target="_top"], form[target="_top"]').forEach(function (element) { + element.setAttribute('target', '_self'); + }); + }; + update(document); + new MutationObserver(function (mutations) { + mutations.forEach(function (mutation) { + mutation.addedNodes.forEach(function (node) { + if (node.nodeType === Node.ELEMENT_NODE) { + update(node); + } + }); + }); + }).observe(document.body, {childList: true, subtree: true}); +}()); +JS); + } + protected function isLTIExitMode(CalledContexts $screen_context_stack): bool { $data_collection = $screen_context_stack->current()->getAdditionalData();