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