From 44deb5a1dbebd1047006191633f57d14b18c3ebf Mon Sep 17 00:00:00 2001 From: Fabian Helfer Date: Fri, 9 Jan 2026 08:59:38 +0100 Subject: [PATCH] [Improvement] UI: Adds onloadCode to ViewControl Mode --- .../UI/src/Component/ViewControl/Mode.php | 17 +++++ .../Component/ViewControl/Mode.php | 72 +++++++++++++++++++ .../Component/ViewControl/Renderer.php | 3 + 3 files changed, 92 insertions(+) diff --git a/components/ILIAS/UI/src/Component/ViewControl/Mode.php b/components/ILIAS/UI/src/Component/ViewControl/Mode.php index 77d4bb054be2..d3a96303dd08 100755 --- a/components/ILIAS/UI/src/Component/ViewControl/Mode.php +++ b/components/ILIAS/UI/src/Component/ViewControl/Mode.php @@ -21,6 +21,8 @@ namespace ILIAS\UI\Component\ViewControl; use ILIAS\UI\Component\Component; +use ILIAS\UI\Component\JavaScriptBindable; +use Closure; /** * This describes a Mode Control @@ -52,4 +54,19 @@ public function getLabelledActions(): array; * Get the aria-label on the ViewControl */ public function getAriaLabel(): string; + + public function withOnLoadCodeForAction(string $label, Closure $binder): static; + public function withAdditionalOnLoadCodeForAction(string $label, Closure $binder): static; + + /** + * @param array $label_binder_map + */ + public function withOnLoadCodeForActions(array $label_binder_map): static; + + /** + * @param array $label_binder_map + */ + public function withAdditionalOnLoadCodeForActions(array $label_binder_map): static; + + public function getOnLoadCodeForAction(string $label): ?Closure; } diff --git a/components/ILIAS/UI/src/Implementation/Component/ViewControl/Mode.php b/components/ILIAS/UI/src/Implementation/Component/ViewControl/Mode.php index 5c5ece9c2c99..1fed14102a66 100755 --- a/components/ILIAS/UI/src/Implementation/Component/ViewControl/Mode.php +++ b/components/ILIAS/UI/src/Implementation/Component/ViewControl/Mode.php @@ -22,6 +22,10 @@ use ILIAS\UI\Component as C; use ILIAS\UI\Implementation\Component\ComponentHelper; +use Closure; +use ILIAS\UI\Implementation\Component\JavaScriptBindable; +use ReflectionFunction; +use InvalidArgumentException; class Mode implements C\ViewControl\Mode { @@ -30,6 +34,8 @@ class Mode implements C\ViewControl\Mode protected array $labeled_actions; protected string $aria_label; protected ?string $active = null; + /** @var Closure[] */ + private array $on_load_code_binder_by_label = []; public function __construct($labelled_actions, string $aria_label) { @@ -58,4 +64,70 @@ public function getAriaLabel(): string { return $this->aria_label; } + + public function withOnLoadCodeForAction(string $label, Closure $binder): static + { + $this->checkLabelExists($label); + $this->checkBinder($binder); + $clone = clone $this; + $clone->on_load_code_binder_by_label[$label] = $binder; + return $clone; + } + + public function withAdditionalOnLoadCodeForAction(string $label, Closure $binder): static + { + $current_binder = $this->getOnLoadCodeForAction($label); + if ($current_binder === null) { + return $this->withOnLoadCodeForAction($label, $binder); + } + + $this->checkLabelExists($label); + $this->checkBinder($binder); + return $this->withOnLoadCodeForAction($label, static fn($id) => $binder($id) . "\n" . $current_binder($id)); + } + + public function getOnLoadCodeForAction(string $label): ?Closure + { + return $this->on_load_code_binder_by_label[$label] ?? null; + } + + /** + * @throws \InvalidArgumentException if closure does not take one argument + */ + private function checkBinder(Closure $binder): void + { + $refl = new ReflectionFunction($binder); + $args = array_map(static fn($arg) => $arg->name, $refl->getParameters()); + if (array("id") !== $args) { + throw new InvalidArgumentException('Expected closure "$binder" to have exactly one argument "$id".'); + } + } + + /** + * @throws InvalidArgumentException if the label does not exist + */ + private function checkLabelExists(string $label): void + { + if (!array_key_exists($label, $this->labeled_actions)) { + throw new InvalidArgumentException("Label '$label' does not exist in Mode control."); + } + } + + public function withOnLoadCodeForActions(array $label_binder_map): static + { + $clone = clone $this; + foreach ($label_binder_map as $label => $binder) { + $clone = $clone->withOnLoadCodeForAction($label, $binder); + } + return $clone; + } + + public function withAdditionalOnLoadCodeForActions(array $label_binder_map): static + { + $clone = clone $this; + foreach ($label_binder_map as $label => $binder) { + $clone = $clone->withAdditionalOnLoadCodeForAction($label, $binder); + } + return $clone; + } } diff --git a/components/ILIAS/UI/src/Implementation/Component/ViewControl/Renderer.php b/components/ILIAS/UI/src/Implementation/Component/ViewControl/Renderer.php index 55d0e7a6f646..f10854f2d768 100644 --- a/components/ILIAS/UI/src/Implementation/Component/ViewControl/Renderer.php +++ b/components/ILIAS/UI/src/Implementation/Component/ViewControl/Renderer.php @@ -74,6 +74,9 @@ protected function renderMode(Component\ViewControl\Mode $component, RendererInt $tpl->setCurrentBlock("view_control"); $button = $f->button()->standard($label, $action); + if ($action = $component->getOnLoadCodeForAction($label)) { + $button = $button->withOnLoadCode($action); + } if ($activate_first_item) { $button = $button->withEngagedState(true); $activate_first_item = false;