ILIAS  release_8 Revision v8.24
Renderer.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
32use ILIAS\UI\Implementation\Render\Template as UITemplateWrapper;
33use ILIAS\UI\Renderer as RendererInterface;
36use LogicException;
37
39{
40 public const BLOCK_MAINBAR_ENTRIES = 'trigger_item';
41 public const BLOCK_MAINBAR_TOOLS = 'tool_trigger_item';
42 public const BLOCK_METABAR_ENTRIES = 'meta_element';
43
44 private array $trigger_signals = [];
45
49 public function render(Component\Component $component, RendererInterface $default_renderer): string
50 {
51 $this->checkComponent($component);
52
53 if ($component instanceof MainBar) {
54 return $this->renderMainbar($component, $default_renderer);
55 }
56 if ($component instanceof MetaBar) {
57 return $this->renderMetabar($component, $default_renderer);
58 }
59 if ($component instanceof Footer) {
60 return $this->renderFooter($component, $default_renderer);
61 }
62 if ($component instanceof ModeInfo) {
63 return $this->renderModeInfo($component, $default_renderer);
64 }
65 if ($component instanceof Component\MainControls\SystemInfo) {
66 return $this->renderSystemInfo($component, $default_renderer);
67 }
68 throw new LogicException("Cannot render: " . get_class($component));
69 }
70
71 protected function calculateMainBarTreePosition($pos, $slate)
72 {
73 if (!$slate instanceof Slate && !$slate instanceof MainBar) {
74 return $slate;
75 }
76 return $slate
77 ->withMainBarTreePosition($pos)
78 ->withMappedSubNodes(
79 function ($num, $slate, $is_tool = false) use ($pos) {
80 if ($is_tool) {
81 $pos = 'T';
82 }
83 return $this->calculateMainBarTreePosition("$pos:$num", $slate);
84 }
85 );
86 }
87
88 protected function renderToolEntry(
89 string $entry_id,
90 string $mb_id,
91 MainBar $component,
92 UITemplateWrapper $tpl,
93 RendererInterface $default_renderer
94 ): string {
95 $hidden = $component->getInitiallyHiddenToolIds();
96 $close_buttons = $component->getCloseButtons();
97
98 $is_removeable = array_key_exists($entry_id, $close_buttons);
99 $is_hidden = in_array($entry_id, $hidden);
100
101 if ($is_removeable) {
102 $trigger_signal = $component->getTriggerSignal($mb_id, $component::ENTRY_ACTION_REMOVE);
103 $this->trigger_signals[] = $trigger_signal;
104 $btn_removetool = $close_buttons[$entry_id]
105 ->withAdditionalOnloadCode(
106 fn ($id) => "il.UI.maincontrols.mainbar.addPartIdAndEntry('$mb_id', 'remover', '$id', true);"
107 )
108 ->withOnClick($trigger_signal);
109
110 $tpl->setCurrentBlock("tool_removal");
111 $tpl->setVariable("REMOVE_TOOL", $default_renderer->render($btn_removetool));
112 $tpl->parseCurrentBlock();
113 }
114
115 $is_removeable = $is_removeable ? 'true' : 'false';
116 $is_hidden = $is_hidden ? 'true' : 'false';
117 return "il.UI.maincontrols.mainbar.addToolEntry('$mb_id', $is_removeable, $is_hidden, '$entry_id');";
118 }
119
120 protected function renderMainbarEntry(
121 array $entries,
122 string $block,
123 MainBar $component,
124 UITemplateWrapper $tpl,
125 RendererInterface $default_renderer
126 ): void {
127 $f = $this->getUIFactory();
128 foreach ($entries as $k => $entry) {
129 $button = $entry;
130 $slate = null;
131 $js = '';
132
133 if ($entry instanceof Slate) {
134 $slate = $entry;
135 $mb_id = $entry->getMainBarTreePosition();
136 $is_tool = $block === static::BLOCK_MAINBAR_TOOLS;
137 if ($is_tool) {
138 $js = $this->renderToolEntry($k, $mb_id, $component, $tpl, $default_renderer);
139 }
140
141 $trigger_signal = $component->getTriggerSignal($mb_id, $component::ENTRY_ACTION_TRIGGER);
142 $this->trigger_signals[] = $trigger_signal;
143 $button = $f->button()->bulky($entry->getSymbol(), $entry->getName(), '#')
144 ->withOnClick($trigger_signal);
145 } else {
146 //add Links/Buttons as toplevel entries
147 $pos = array_search($k, array_keys($entries));
148 $mb_id = '0:' . $pos;
149 $is_tool = false;
150 }
151
152 $button = $button->withAdditionalOnLoadCode(
153 function ($id) use ($js, $mb_id, $k, $is_tool): string {
154 $add_as_tool = $is_tool ? 'true' : 'false';
155 $js .= "
156 il.UI.maincontrols.mainbar.addPartIdAndEntry('$mb_id', 'triggerer', '$id', $add_as_tool);
157 il.UI.maincontrols.mainbar.addMapping('$k','$mb_id');
158 ";
159 return $js;
160 }
161 )->withAriaRole(IBulky::MENUITEM);
162
163 $tpl->setCurrentBlock($block);
164 $tpl->setVariable("BUTTON", $default_renderer->render($button));
165 $tpl->parseCurrentBlock();
166
167 if ($slate) {
168 $entry = $entry->withAriaRole(ISlate::MENU);
169
170 $tpl->setCurrentBlock("slate_item");
171 $tpl->setVariable("SLATE", $default_renderer->render($entry));
172 $tpl->parseCurrentBlock();
173 }
174 }
175 }
176
177 protected function renderMainbar(MainBar $component, RendererInterface $default_renderer): string
178 {
179 $f = $this->getUIFactory();
180 $tpl = $this->getTemplate("tpl.mainbar.html", true, true);
181
182 $tpl->setVariable("ARIA_LABEL", $this->txt('mainbar_aria_label'));
183 $more_btn_label = $this->txt('mainbar_more_label');
187 $more_slate = $f->mainControls()->slate()->combined(
188 $more_btn_label,
189 $f->symbol()->glyph()->more()
190 );
191 $more_slate = $more_slate->withAriaRole(ISlate::MENU);
192 $component = $component->withAdditionalEntry(
193 '_mb_more_entry',
194 $more_slate
195 );
196 $component = $this->calculateMainBarTreePosition("0", $component);
197
198 $mb_entries = [
199 static::BLOCK_MAINBAR_ENTRIES => $component->getEntries(),
200 static::BLOCK_MAINBAR_TOOLS => $component->getToolEntries()
201 ];
202
203 foreach ($mb_entries as $block => $entries) {
204 $this->renderMainbarEntry(
205 $entries,
206 $block,
207 $component,
208 $tpl,
209 $default_renderer
210 );
211 }
212
213 //tools-section trigger
214 if (count($component->getToolEntries()) > 0) {
215 $btn_tools = $component->getToolsButton()
216 ->withOnClick($component->getToggleToolsSignal());
217
218 $tpl->setCurrentBlock("tools_trigger");
219 $tpl->setVariable("BUTTON", $default_renderer->render($btn_tools));
220 $tpl->parseCurrentBlock();
221 }
222
223 //disengage all, close slates
224 $btn_disengage = $f->button()->bulky($f->symbol()->glyph()->collapseHorizontal("#"), $this->txt('close'), "#")
225 ->withOnClick($component->getDisengageAllSignal());
226 $tpl->setVariable("CLOSE_SLATES", $default_renderer->render($btn_disengage));
227
228
229 $id = $this->bindMainbarJS($component);
230 $tpl->setVariable('ID', $id);
231
232 return $tpl->get();
233 }
234
235 protected function renderMetabar(MetaBar $component, RendererInterface $default_renderer): string
236 {
237 $f = $this->getUIFactory();
238 $tpl = $this->getTemplate("tpl.metabar.html", true, true);
239 $active = '';
240 $signals = [
241 'entry' => $component->getEntryClickSignal(),
242 'close_slates' => $component->getDisengageAllSignal()
243 ];
244 $entries = $component->getEntries();
245
246 $more_label = $this->txt('show_more');
247 $more_symbol = $f->symbol()->glyph()->disclosure()
248 ->withCounter($f->counter()->novelty(0))
249 ->withCounter($f->counter()->status(0));
253 $more_slate = $f->mainControls()->slate()->combined($more_label, $more_symbol);
254 $more_slate = $more_slate->withAriaRole(ISlate::MENU);
255 $entries[] = $more_slate;
256
257 $this->renderTriggerButtonsAndSlates(
258 $tpl,
259 $default_renderer,
260 $signals['entry'],
261 static::BLOCK_METABAR_ENTRIES,
262 $entries,
263 $active
264 );
265
266 $component = $component->withOnLoadCode(
267 function ($id) use ($signals) {
268 $entry_signal = $signals['entry'];
269 $close_slates_signal = $signals['close_slates'];
270 return "
271 il.UI.maincontrols.metabar.registerSignals(
272 '$id',
273 '$entry_signal',
274 '$close_slates_signal',
275 );
276 il.UI.maincontrols.metabar.init();
277 $(window).resize(il.UI.maincontrols.metabar.init);
278 ";
279 }
280 );
281 $tpl->setVariable('ARIA_LABEL', $this->txt('metabar_aria_label'));
282
283 $id = $this->bindJavaScript($component);
284 $tpl->setVariable('ID', $id);
285 return $tpl->get();
286 }
287
288 protected function renderModeInfo(ModeInfo $component, RendererInterface $default_renderer): string
289 {
290 $tpl = $this->getTemplate("tpl.mode_info.html", true, true);
291 $tpl->setVariable('MODE_TITLE', $component->getModeTitle());
292 $base_URI = $component->getCloseAction()->getBaseURI();
293 $query = $component->getCloseAction()->getQuery();
294 $action = $base_URI . '?' . $query;
295 $close = $this->getUIFactory()->symbol()->glyph()->close($action);
296 $tpl->setVariable('CLOSE_GLYPH', $default_renderer->render($close));
297
298 return $tpl->get();
299 }
300
301 protected function renderSystemInfo(
302 Component\MainControls\SystemInfo $component,
303 RendererInterface $default_renderer
304 ): string {
305 $tpl = $this->getTemplate("tpl.system_info.html", true, true);
306 $tpl->setVariable('HEADLINE', $component->getHeadLine());
307 $tpl->setVariable('BODY', $component->getInformationText());
308 $tpl->setVariable('DENOTATION', $component->getDenotation());
309 switch ($component->getDenotation()) {
310 case Component\MainControls\SystemInfo::DENOTATION_NEUTRAL:
311 case Component\MainControls\SystemInfo::DENOTATION_IMPORTANT:
312 $tpl->setVariable('LIVE', 'aria-live="polite"');
313 break;
314 case Component\MainControls\SystemInfo::DENOTATION_BREAKING:
315 $tpl->setVariable('ROLE', 'role="alert"');
316 break;
317 }
318 if ($component->isDismissable()) {
319 $close = $this->getUIFactory()->symbol()->glyph()->close("#");
320 $signal = $component->getCloseSignal();
321 $close = $close->withOnClick($signal);
322 $tpl->setVariable('CLOSE_BUTTON', $default_renderer->render($close));
323 $tpl->setVariable('CLOSE_URI', (string) $component->getDismissAction());
324 $component = $component->withAdditionalOnLoadCode(fn ($id) => "$(document).on('$signal', function() { il.UI.maincontrols.system_info.close('$id'); });");
325 }
326
327 $more = $this->getUIFactory()->symbol()->glyph()->more("#");
328 $tpl->setVariable('MORE_BUTTON', $default_renderer->render($more));
329
330 $component = $component->withAdditionalOnLoadCode(fn ($id) => "il.UI.maincontrols.system_info.init('$id')");
331
332 $id = $this->bindJavaScript($component);
333 $tpl->setVariable('ID', $id);
334 $tpl->setVariable('ID_HEADLINE', $id . "_headline");
335 $tpl->setVariable('ID_DESCRIPTION', $id . "_description");
336
337 return $tpl->get();
338 }
339
340
342 UITemplateWrapper $tpl,
343 RendererInterface $default_renderer,
344 Signal $entry_signal,
345 string $block,
346 array $entries,
347 string $active = null
348 ): void {
349 foreach ($entries as $id => $entry) {
350 $use_block = $block;
351 $engaged = (string) $id === $active;
352 $slate = null;
353 if ($entry instanceof Slate) {
354 $f = $this->getUIFactory();
355 $secondary_signal = $entry->getToggleSignal();
356 $clickable = $f->button()->bulky($entry->getSymbol(), $entry->getName(), '#')
357 ->withEngagedState($engaged)
358 ->withOnClick($entry_signal)
359 ->appendOnClick($secondary_signal)
360 ->withAriaRole(IBulky::MENUITEM);
361
362 $slate = $entry;
363 } elseif ($entry instanceof IBulky) {
364 $clickable = $entry;
365 $clickable = $clickable->withAriaRole(IBulky::MENUITEM);
366 $slate = null;
367 } else {
368 $clickable = $entry;
369 }
370
371 $clickable_html = $default_renderer->render($clickable);
372
373 if ($slate) {
374 $tpl->setCurrentBlock("slate_item");
375 $tpl->setVariable("SLATE", $default_renderer->render($slate));
376 $tpl->parseCurrentBlock();
377 }
378
379 $tpl->setCurrentBlock($use_block);
380 $tpl->setVariable("BUTTON", $clickable_html);
381 $tpl->parseCurrentBlock();
382 }
383 }
384
385 protected function bindMainbarJS(MainBar $component): ?string
386 {
387 $trigger_signals = $this->trigger_signals;
388
389 $inititally_active = $component->getActive();
390
391 $component = $component->withOnLoadCode(
392 function ($id) use ($component, $trigger_signals, $inititally_active): string {
393 $disengage_all_signal = $component->getDisengageAllSignal();
394 $tools_toggle_signal = $component->getToggleToolsSignal();
395
396 $js = "il.UI.maincontrols.mainbar.addTriggerSignal('$disengage_all_signal');";
397 $js .= "il.UI.maincontrols.mainbar.addTriggerSignal('$tools_toggle_signal');";
398
399 foreach ($trigger_signals as $signal) {
400 $js .= "il.UI.maincontrols.mainbar.addTriggerSignal('$signal');";
401 }
402
403 foreach ($component->getToolEntries() as $k => $tool) {
404 $signal = $component->getEngageToolSignal($k);
405 $js .= "il.UI.maincontrols.mainbar.addTriggerSignal('$signal');";
406 }
407
408 $js .= "
409 window.addEventListener('resize', il.UI.maincontrols.mainbar.adjustToScreenSize);
410 il.UI.maincontrols.mainbar.init('$inititally_active');
411 ";
412 return $js;
413 }
414 );
415
416 return $this->bindJavaScript($component);
417 }
418
419 protected function renderFooter(Footer $component, RendererInterface $default_renderer): string
420 {
421 $tpl = $this->getTemplate("tpl.footer.html", true, true);
422 $links = $component->getLinks();
423 $modalsWithTriggers = $component->getModals();
424 $links = array_merge($links, array_column($modalsWithTriggers, 1));
425
426 if ($links) {
427 $link_list = $this->getUIFactory()->listing()->unordered($links);
428 $tpl->setVariable('LINKS', $default_renderer->render($link_list));
429 }
430
431 if ($modalsWithTriggers !== []) {
432 $tpl->setVariable('MODALS', $default_renderer->render(
433 array_column($modalsWithTriggers, 0)
434 ));
435 }
436
437 $tpl->setVariable('TEXT', $component->getText());
438
439 $perm_url = $component->getPermanentURL();
440 if ($perm_url instanceof URI) {
441 $url = $perm_url->__toString();
442 $link = $this->getUIFactory()
443 ->link()
444 ->standard($this->txt('perma_link'), $url);
445 $tpl->setVariable('PERMANENT', $default_renderer->render($link));
446 }
447 return $tpl->get();
448 }
449
453 public function registerResources(ResourceRegistry $registry): void
454 {
455 parent::registerResources($registry);
456 $registry->register('./src/UI/templates/js/MainControls/dist/mainbar.js');
457 $registry->register('./src/UI/templates/js/MainControls/metabar.js');
458 $registry->register('./src/GlobalScreen/Client/dist/GS.js');
459 $registry->register('./src/UI/templates/js/MainControls/system_info.js');
460 }
461
465 protected function getComponentInterfaceName(): array
466 {
467 return array(
468 MetaBar::class,
469 MainBar::class,
470 Footer::class,
471 ModeInfo::class,
472 Component\MainControls\SystemInfo::class
473 );
474 }
475}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
The scope of this class is split ilias-conform URI's into components.
Definition: URI.php:35
getComponentInterfaceName()
Get the name of the component-interface this renderer is supposed to render.ATTENTION: Fully qualifie...
Definition: Renderer.php:465
renderTriggerButtonsAndSlates(UITemplateWrapper $tpl, RendererInterface $default_renderer, Signal $entry_signal, string $block, array $entries, string $active=null)
Definition: Renderer.php:341
renderSystemInfo(Component\MainControls\SystemInfo $component, RendererInterface $default_renderer)
Definition: Renderer.php:301
renderFooter(Footer $component, RendererInterface $default_renderer)
Definition: Renderer.php:419
renderToolEntry(string $entry_id, string $mb_id, MainBar $component, UITemplateWrapper $tpl, RendererInterface $default_renderer)
Definition: Renderer.php:88
renderModeInfo(ModeInfo $component, RendererInterface $default_renderer)
Definition: Renderer.php:288
renderMainbarEntry(array $entries, string $block, MainBar $component, UITemplateWrapper $tpl, RendererInterface $default_renderer)
Definition: Renderer.php:120
registerResources(ResourceRegistry $registry)
Announce resources this renderer requires.
Definition: Renderer.php:453
render(Component\Component $component, RendererInterface $default_renderer)
Definition: Renderer.php:49
checkComponent(Component $component)
Check if a given component fits this renderer and throw \LogicError if that is not the case.
return true
This describes the Footer.
Definition: Footer.php:33
This describes the MainBar.
Definition: MainBar.php:34
getCloseButtons()
Buttons to close tools; maybe configure with callback.
getToggleToolsSignal()
Signal to toggle the tools-section.
getDisengageAllSignal()
This signal disengages all slates when triggered.
This describes the MetaBar.
Definition: MetaBar.php:33
Registry for resources required by rendered output like Javascript or CSS.
register(string $name)
Add a dependency.
Interface to templating as it is used in the UI framework.
Definition: Template.php:29
An entity that renders components to a string output.
Definition: Renderer.php:31
if($DIC->http() ->request() ->getMethod()=="GET" &&isset($DIC->http() ->request() ->getQueryParams()['tex'])) $tpl
Definition: latex.php:41
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Definition: Factory.php:21
$query
$url