19declare(strict_types=1);
53 if ($component instanceof
MainBar) {
54 return $this->renderMainbar($component, $default_renderer);
56 if ($component instanceof
MetaBar) {
57 return $this->renderMetabar($component, $default_renderer);
59 if ($component instanceof
Footer) {
60 return $this->
renderFooter($component, $default_renderer);
62 if ($component instanceof
ModeInfo) {
73 if (!$slate instanceof
Slate && !$slate instanceof
MainBar) {
77 ->withMainBarTreePosition($pos)
79 function ($num, $slate, $is_tool =
false) use ($pos) {
92 UITemplateWrapper $tpl,
93 RendererInterface $default_renderer
95 $hidden = $component->getInitiallyHiddenToolIds();
98 $is_removeable = array_key_exists($entry_id, $close_buttons);
99 $is_hidden = in_array($entry_id, $hidden);
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);"
108 ->withOnClick($trigger_signal);
110 $tpl->setCurrentBlock(
"tool_removal");
111 $tpl->setVariable(
"REMOVE_TOOL", $default_renderer->render($btn_removetool));
112 $tpl->parseCurrentBlock();
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');";
124 UITemplateWrapper $tpl,
125 RendererInterface $default_renderer
127 $f = $this->getUIFactory();
128 foreach ($entries as $k => $entry) {
133 if ($entry instanceof
Slate) {
135 $mb_id = $entry->getMainBarTreePosition();
136 $is_tool = $block === static::BLOCK_MAINBAR_TOOLS;
138 $js = $this->renderToolEntry($k, $mb_id, $component, $tpl, $default_renderer);
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 ->withHelpTopics(...$entry->getHelpTopics());
148 $pos = array_search($k, array_keys($entries));
149 $mb_id =
'0:' . $pos;
153 $button = $button->withAdditionalOnLoadCode(
154 function (
$id) use ($js, $mb_id, $k, $is_tool):
string {
155 $add_as_tool = $is_tool ?
'true' :
'false';
157 il.UI.maincontrols.mainbar.addPartIdAndEntry('$mb_id', 'triggerer', '$id', $add_as_tool);
158 il.UI.maincontrols.mainbar.addMapping('$k','$mb_id');
162 )->withAriaRole(IBulky::MENUITEM);
164 $tpl->setCurrentBlock($block);
165 $tpl->setVariable(
"BUTTON", $default_renderer->render($button));
166 $tpl->parseCurrentBlock();
169 $entry = $entry->withAriaRole(ISlate::MENU);
171 $tpl->setCurrentBlock(
"slate_item");
172 $tpl->setVariable(
"SLATE", $default_renderer->render($entry));
173 $tpl->parseCurrentBlock();
178 protected function renderMainbar(MainBar $component, RendererInterface $default_renderer): string
180 $f = $this->getUIFactory();
181 $tpl = $this->getTemplate(
"tpl.mainbar.html",
true,
true);
183 $tpl->setVariable(
"ARIA_LABEL", $this->txt(
'mainbar_aria_label'));
184 $more_btn_label = $this->txt(
'mainbar_more_label');
188 $more_slate =
$f->mainControls()->slate()->combined(
190 $f->symbol()->glyph()->more()
192 $more_slate = $more_slate->withAriaRole(ISlate::MENU);
193 $component = $component->withAdditionalEntry(
197 $component = $this->calculateMainBarTreePosition(
"0", $component);
200 static::BLOCK_MAINBAR_ENTRIES => $component->getEntries(),
201 static::BLOCK_MAINBAR_TOOLS => $component->getToolEntries()
204 foreach ($mb_entries as $block => $entries) {
205 $this->renderMainbarEntry(
215 if (count($component->getToolEntries()) > 0) {
216 $btn_tools = $component->getToolsButton()
217 ->withOnClick($component->getToggleToolsSignal());
219 $tpl->setCurrentBlock(
"tools_trigger");
220 $tpl->setVariable(
"BUTTON", $default_renderer->render($btn_tools));
221 $tpl->parseCurrentBlock();
225 $btn_disengage =
$f->button()->bulky(
$f->symbol()->glyph()->collapseHorizontal(
"#"), $this->txt(
'close'),
"#")
226 ->withOnClick($component->getDisengageAllSignal());
227 $tpl->setVariable(
"CLOSE_SLATES", $default_renderer->render($btn_disengage));
230 $id = $this->bindMainbarJS($component);
231 $tpl->setVariable(
'ID',
$id);
236 protected function renderMetabar(MetaBar $component, RendererInterface $default_renderer): string
238 $f = $this->getUIFactory();
239 $tpl = $this->getTemplate(
"tpl.metabar.html",
true,
true);
242 'entry' => $component->getEntryClickSignal(),
243 'close_slates' => $component->getDisengageAllSignal()
245 $entries = $component->getEntries();
247 $more_label = $this->txt(
'show_more');
248 $more_symbol =
$f->symbol()->glyph()->disclosure()
249 ->withCounter(
$f->counter()->novelty(0))
250 ->withCounter(
$f->counter()->status(0));
254 $more_slate =
$f->mainControls()->slate()->combined($more_label, $more_symbol);
255 $more_slate = $more_slate->withAriaRole(ISlate::MENU);
256 $entries[] = $more_slate;
258 $this->renderTriggerButtonsAndSlates(
262 static::BLOCK_METABAR_ENTRIES,
267 $component = $component->withOnLoadCode(
268 function (
$id) use ($signals) {
269 $entry_signal = $signals[
'entry'];
270 $close_slates_signal = $signals[
'close_slates'];
272 il.UI.maincontrols.metabar.init('$id');
273 il.UI.maincontrols.metabar.get('$id').registerSignals(
275 '$close_slates_signal',
277 il.UI.maincontrols.metabar.get('$id').init();
278 window.addEventListener(
280 ()=>{il.UI.maincontrols.metabar.get('$id').init()}
285 $tpl->setVariable(
'ARIA_LABEL', $this->txt(
'metabar_aria_label'));
287 $id = $this->bindJavaScript($component);
288 $tpl->setVariable(
'ID',
$id);
294 $tpl = $this->getTemplate(
"tpl.mode_info.html",
true,
true);
295 $tpl->setVariable(
'MODE_TITLE', $component->
getModeTitle());
298 $action = $base_URI .
'?' . $query;
299 $close = $this->getUIFactory()->symbol()->glyph()->close($action);
300 $tpl->setVariable(
'CLOSE_GLYPH', $default_renderer->render($close));
307 RendererInterface $default_renderer
309 $tpl = $this->getTemplate(
"tpl.system_info.html",
true,
true);
310 $tpl->setVariable(
'HEADLINE', $component->getHeadLine());
311 $tpl->setVariable(
'BODY', $component->getInformationText());
312 $tpl->setVariable(
'DENOTATION', $component->getDenotation());
313 switch ($component->getDenotation()) {
314 case Component\MainControls\SystemInfo::DENOTATION_NEUTRAL:
315 case Component\MainControls\SystemInfo::DENOTATION_IMPORTANT:
316 $tpl->setVariable(
'LIVE',
'aria-live="polite"');
318 case Component\MainControls\SystemInfo::DENOTATION_BREAKING:
319 $tpl->setVariable(
'ROLE',
'role="alert"');
322 if ($component->isDismissable()) {
323 $close = $this->getUIFactory()->symbol()->glyph()->close(
"#");
324 $signal = $component->getCloseSignal();
325 $close = $close->withOnClick($signal);
326 $tpl->setVariable(
'CLOSE_BUTTON', $default_renderer->render($close));
327 $tpl->setVariable(
'CLOSE_URI', (
string) $component->getDismissAction());
328 $component = $component->withAdditionalOnLoadCode(fn(
$id) =>
"$(document).on('$signal', function() { il.UI.maincontrols.system_info.close('$id'); });");
331 $more = $this->getUIFactory()->symbol()->glyph()->more(
"#");
332 $tpl->setVariable(
'MORE_BUTTON', $default_renderer->render($more));
334 $component = $component->withAdditionalOnLoadCode(fn(
$id) =>
"il.UI.maincontrols.system_info.init('$id')");
336 $id = $this->bindJavaScript($component);
337 $tpl->setVariable(
'ID',
$id);
338 $tpl->setVariable(
'ID_HEADLINE',
$id .
"_headline");
339 $tpl->setVariable(
'ID_DESCRIPTION',
$id .
"_description");
346 UITemplateWrapper $tpl,
347 RendererInterface $default_renderer,
351 ?
string $active =
null
353 foreach ($entries as
$id => $entry) {
357 if ($entry instanceof
Slate) {
358 $f = $this->getUIFactory();
359 $secondary_signal = $entry->getToggleSignal();
360 $clickable =
$f->button()->bulky($entry->getSymbol(), $entry->getName(),
'#')
362 ->withOnClick($entry_signal)
363 ->appendOnClick($secondary_signal)
364 ->withAriaRole(IBulky::MENUITEM)
365 ->withHelpTopics(...$entry->getHelpTopics());
368 } elseif ($entry instanceof IBulky) {
370 $clickable = $clickable->withAriaRole(IBulky::MENUITEM);
376 $clickable_html = $default_renderer->render($clickable);
379 $tpl->setCurrentBlock(
"slate_item");
380 $tpl->setVariable(
"SLATE", $default_renderer->render($slate));
381 $tpl->parseCurrentBlock();
384 $tpl->setCurrentBlock($use_block);
385 $tpl->setVariable(
"BUTTON", $clickable_html);
386 $tpl->parseCurrentBlock();
392 $trigger_signals = $this->trigger_signals;
394 $inititally_active = $component->
getActive();
397 function (
$id) use ($component, $trigger_signals, $inititally_active):
string {
401 $js =
"il.UI.maincontrols.mainbar.addTriggerSignal('$disengage_all_signal');";
402 $js .=
"il.UI.maincontrols.mainbar.addTriggerSignal('$tools_toggle_signal');";
404 foreach ($trigger_signals as $signal) {
405 $js .=
"il.UI.maincontrols.mainbar.addTriggerSignal('$signal');";
409 $signal = $component->getEngageToolSignal($k);
410 $js .=
"il.UI.maincontrols.mainbar.addTriggerSignal('$signal');";
414 window.addEventListener('resize', il.UI.maincontrols.mainbar.adjustToScreenSize);
415 il.UI.maincontrols.mainbar.init('$inititally_active');
421 return $this->bindJavaScript($component);
426 if (!$this->isFooterVisible($component)) {
430 $template = $this->getTemplate(
"tpl.footer.html",
true,
true);
433 $permanent_url = $component->getPermanentURL();
434 if (
null !== $permanent_url) {
435 $template->setCurrentBlock(
'with_additional_item');
436 $template->setVariable(
'ITEM_CONTENT', $this->permanentLink((
string) $permanent_url, $default_renderer));
437 $template->parseCurrentBlock();
438 $this->parseFooterSection($template,
'permanent-link', $this->txt(
'footer_permanent_link'));
442 $additional_link_groups = $component->getAdditionalLinkGroups();
443 if ([] !== $additional_link_groups) {
445 foreach ($additional_link_groups as [$title, $actions]) {
446 $link_groups[] = [$this->getUIFactory()->listing()->unordered($actions), $title];
449 $this->parseAdditionalFooterSectionItems(
453 $this->txt(
'footer_link_groups'),
459 $additional_links = $component->getAdditionalLinks();
460 if ([] !== $additional_links) {
461 $links = array_map(
static fn($link) => [$link,
null], $additional_links);
462 $this->parseAdditionalFooterSectionItems(
466 $this->txt(
'footer_links'),
472 $additional_icons = $component->getAdditionalIcons();
473 if ([] !== $additional_icons) {
475 foreach ($additional_icons as [$icon, $action]) {
476 if (
null !== $action) {
477 if ($action instanceof
URI) {
478 $action = (string) $action;
480 $icons[] = $this->getUIFactory()->button()->shy(
'', $action)->withSymbol($icon);
486 $this->parseAdditionalFooterSectionIcons(
490 $this->txt(
'footer_icons'),
496 $additional_texts = $component->getAdditionalTexts();
497 if ([] !== $additional_texts) {
498 $texts = array_map(
static fn($text) => [$text,
null], $additional_texts);
499 $this->parseAdditionalFooterSectionItems(
503 $this->txt(
'footer_texts'),
510 return $template->get() . $default_renderer->render($component->getModals());
518 RendererInterface $default_renderer,
519 string $section_type,
520 string $section_label,
521 array $section_items = [],
523 foreach ($section_items as [$content, $title]) {
525 if (
null !== $title) {
526 $template->
setVariable(
'ITEM_TITLE', $this->convertSpecialCharacters($title));
529 $content = $default_renderer->render($content);
531 $content = $this->convertSpecialCharacters($content);
537 $this->parseFooterSection($template, $section_type, $section_label);
545 RendererInterface $default_renderer,
546 string $section_type,
547 string $section_label,
548 array $section_icons = [],
550 foreach ($section_icons as $icon) {
552 $template->
setVariable(
'ICON', $default_renderer->render($icon));
556 $this->parseFooterSection($template, $section_type, $section_label);
561 string $section_type,
562 string $section_label,
564 $template->setCurrentBlock(
'with_additional_section');
565 $template->
setVariable(
'SECTION_TYPE', $section_type);
566 $template->
setVariable(
'SECTION_LABEL', $section_label);
572 return $component->getPermanentURL() !==
null
573 || !empty($component->getAdditionalLinkGroups())
574 || !empty($component->getAdditionalLinks())
575 || !empty($component->getAdditionalIcons())
576 || !empty($component->getAdditionalTexts());
584 parent::registerResources($registry);
585 $registry->
register(
'assets/js/mainbar.js');
586 $registry->
register(
'assets/js/maincontrols.min.js');
587 $registry->
register(
'assets/js/GS.js');
588 $registry->
register(
'assets/js/system_info.js');
589 $registry->
register(
'assets/js/footer.min.js');
594 $template = $this->getTemplate(
"tpl.permanent-link.html",
true,
true);
596 $code =
function (
string $id) use ($permanent_url):
string {
597 $id = $this->jsonEncode(
$id);
598 $perm_url = $this->jsonEncode((
string) $permanent_url);
600 return "document.getElementById($id).addEventListener('click', e => il.Footer.permalink.copyText($perm_url)
601 .then(() => il.Footer.permalink.showTooltip(e.target.nextElementSibling, 5000)));";
603 $button = $this->getUIFactory()->button()->standard($this->txt(
'copy_perma_link'),
'')->withAdditionalOnLoadCode($code);
606 $template->
setVariable(
'PERMANENT_TOOLTIP', $this->txt(
'perma_link_copied'));
608 return $template->
get();
613 return json_encode($value, JSON_HEX_QUOT | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_THROW_ON_ERROR);
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
The scope of this class is split ilias-conform URI's into components.
renderSystemInfo(Component\MainControls\SystemInfo $component, RendererInterface $default_renderer)
renderToolEntry(string $entry_id, string $mb_id, MainBar $component, UITemplateWrapper $tpl, RendererInterface $default_renderer)
parseAdditionalFooterSectionItems(Template $template, RendererInterface $default_renderer, string $section_type, string $section_label, array $section_items=[],)
const BLOCK_METABAR_ENTRIES
renderModeInfo(ModeInfo $component, RendererInterface $default_renderer)
renderTriggerButtonsAndSlates(UITemplateWrapper $tpl, RendererInterface $default_renderer, Signal $entry_signal, string $block, array $entries, ?string $active=null)
const BLOCK_MAINBAR_TOOLS
renderFooter(I\Footer $component, RendererInterface $default_renderer)
bindMainbarJS(MainBar $component)
parseFooterSection(Template $template, string $section_type, string $section_label,)
calculateMainBarTreePosition($pos, $slate)
renderMainbarEntry(array $entries, string $block, MainBar $component, UITemplateWrapper $tpl, RendererInterface $default_renderer)
parseAdditionalFooterSectionIcons(Template $template, RendererInterface $default_renderer, string $section_type, string $section_label, array $section_icons=[],)
registerResources(ResourceRegistry $registry)
Announce resources this renderer requires.
render(Component\Component $component, RendererInterface $default_renderer)
permanentLink(string $permanent_url, RendererInterface $renderer)
isFooterVisible(I\Footer $component)
const BLOCK_MAINBAR_ENTRIES
Base class for all component renderers.
cannotHandleComponent(Component $component)
This method MUST be called by derived component renderers, if.
withOnLoadCode(Closure $binder)
This describes the MainBar.
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.
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.
setVariable(string $name, $value)
Set a variable in the current block.
get(?string $block=null)
Get the rendered template or a specific block.
setCurrentBlock(string $name)
Set the block to work on.
parseCurrentBlock()
Parse the block that is currently worked on.
An entity that renders components to a string output.