ILIAS  release_8 Revision v8.24
Renderer.php
Go to the documentation of this file.
1<?php
2
3declare(strict_types=1);
4
22
24use ILIAS\UI\Renderer as RendererInterface;
29use LogicException;
30
36{
37 public const MODE_ROLE = "group";
38
39 public function render(Component\Component $component, RendererInterface $default_renderer): string
40 {
41 $this->checkComponent($component);
42
43 if ($component instanceof Component\ViewControl\Mode) {
44 return $this->renderMode($component, $default_renderer);
45 }
46 if ($component instanceof Component\ViewControl\Section) {
47 return $this->renderSection($component, $default_renderer);
48 }
49 if ($component instanceof Component\ViewControl\Sortation) {
50 return $this->renderSortation($component, $default_renderer);
51 }
52 if ($component instanceof Component\ViewControl\Pagination) {
53 return $this->renderPagination($component, $default_renderer);
54 }
55 throw new LogicException("Component '{$component->getCanonicalName()}' isn't supported by this renderer.");
56 }
57
58 protected function renderMode(Component\ViewControl\Mode $component, RendererInterface $default_renderer): string
59 {
60 $f = $this->getUIFactory();
61
62 $tpl = $this->getTemplate("tpl.mode.html", true, true);
63
64 $activate_first_item = false;
65 $active = $component->getActive();
66 if ($active == "") {
67 $activate_first_item = true;
68 }
69
70 foreach ($component->getLabelledActions() as $label => $action) {
71 $tpl->setVariable("ARIA", $this->txt($component->getAriaLabel()));
72 $tpl->setVariable("ROLE", self::MODE_ROLE);
73
74 $tpl->setCurrentBlock("view_control");
75
76 //At this point we don't have a specific text for the button aria label.
77 // component->getAriaLabel gets the main view control aria label.
78 $button = $f->button()->standard($label, $action)->withAriaLabel($label);
79 if ($activate_first_item) {
80 $button = $button->withEngagedState(true);
81 $activate_first_item = false;
82 } elseif ($active == $label) {
83 $button = $button->withEngagedState(true);
84 } else {
85 $button = $button->withEngagedState(false);
86 }
87 $tpl->setVariable("BUTTON", $default_renderer->render($button));
88 $tpl->parseCurrentBlock();
89 }
90
91 return $tpl->get();
92 }
93
94 protected function renderSection(
95 Component\ViewControl\Section $component,
96 RendererInterface $default_renderer
97 ): string {
98 $tpl = $this->getTemplate("tpl.section.html", true, true);
99
100 // render middle button
101 $tpl->setVariable("BUTTON", $default_renderer->render($component->getSelectorButton()));
102
103 // previous button
104 $this->renderSectionButton($component->getPreviousActions(), $tpl, "prev");
105
106 // next button
107 $this->renderSectionButton($component->getNextActions(), $tpl, "next");
108
109 return $tpl->get();
110 }
111
112 protected function renderSectionButton(Component\Button\Button $component, Template $tpl, string $type): void
113 {
114 $uptype = strtoupper($type);
115
116 $action = $component->getAction();
117 $tpl->setVariable($uptype . "_ACTION", $action);
118 $label = ($type == "next")
119 ? $this->txt("next")
120 : $this->txt("previous");
121 $tpl->setVariable($uptype . "_LABEL", $label);
122 if ($component->isActive()) {
123 $tpl->setCurrentBlock($type . "_with_href");
124 $tpl->setVariable($uptype . "_HREF", $action);
125 $tpl->parseCurrentBlock();
126 } else {
127 $tpl->touchBlock($type . "_disabled");
128 }
129 $this->renderId($component, $tpl, $type . "_with_id", $uptype . "_ID");
130 }
131
132 protected function renderSortation(
134 RendererInterface $default_renderer
135 ): string {
136 $f = $this->getUIFactory();
137
138 $tpl = $this->getTemplate("tpl.sortation.html", true, true);
139
140 $component = $component->withResetSignals();
141 $triggeredSignals = $component->getTriggeredSignals();
142 if ($triggeredSignals) {
143 $internal_signal = $component->getSelectSignal();
144 $signal = $triggeredSignals[0]->getSignal();
145
146 $component = $component->withAdditionalOnLoadCode(fn ($id) => "$(document).on('$internal_signal', function(event, signalData) {
147 il.UI.viewcontrol.sortation.onInternalSelect(event, signalData, '$signal', '$id');
148 return false;
149 })");
150 }
151
152 $this->renderId($component, $tpl, "id", "ID");
153
154 //setup entries
155 $options = $component->getOptions();
156 $init_label = $component->getLabel();
157 $items = array();
158 foreach ($options as $val => $label) {
159 if ($triggeredSignals) {
160 $shy = $f->button()->shy($label, $val)->withOnClick($internal_signal);
161 } else {
162 $url = $component->getTargetURL() ?? '';
163 $url .= (strpos($url, '?') === false) ? '?' : '&';
164 $url .= $component->getParameterName() . '=' . $val;
165 $shy = $f->button()->shy($label, $url);
166 }
167 $items[] = $shy;
168 }
169
170 $dd = $f->dropdown()->standard($items)
171 ->withLabel($init_label);
172
173 $tpl->setVariable('SORTATION_DROPDOWN', $default_renderer->render($dd));
174 return $tpl->get();
175 }
176
177 protected function renderPagination(
178 Component\ViewControl\Pagination $component,
179 RendererInterface $default_renderer
180 ): string {
181 $tpl = $this->getTemplate("tpl.pagination.html", true, true);
182
186 $component = $component->withResetSignals();
187 $triggeredSignals = $component->getTriggeredSignals();
188 if ($triggeredSignals) {
189 $internal_signal = $component->getInternalSignal();
190 $signal = $triggeredSignals[0]->getSignal();
191 $component = $component->withOnLoadCode(fn ($id) => "$(document).on('$internal_signal', function(event, signalData) {
192 il.UI.viewcontrol.pagination.onInternalSelect(event, signalData, '$signal', '$id');
193 return false;
194 })");
195
196 $id = $this->bindJavaScript($component);
197 $tpl->setVariable('ID', $id);
198 }
199
200 $range = $this->getPaginationRange($component);
201 $chunk_options = array();
202 foreach ($range as $entry) {
203 $shy = $this->getPaginationShyButton($entry, $component);
204 if ($entry === $component->getCurrentPage()) {
205 $shy = $shy->withEngagedState(true);
206 }
207 $chunk_options[] = $shy;
208 }
209
210 if ($component->getDropdownAt() == null ||
211 $component->getDropdownAt() > $component->getNumberOfPages()) {
212 foreach ($chunk_options as $entry) {
213 $tpl->setCurrentBlock("entry");
214 $tpl->setVariable('BUTTON', $default_renderer->render($entry));
215 $tpl->parseCurrentBlock();
216 }
217 } else {
218 //if threshold is reached, render as dropdown
219 $f = $this->getUIFactory();
220
221 $dd_label_template = $component->getDropdownLabel();
222 if ($dd_label_template === $component->getDefaultDropdownLabel()) {
223 $dd_label_template = $this->txt($dd_label_template);
224 }
225 $dd_label = sprintf(
226 $dd_label_template,
227 $component->getCurrentPage() + 1,
228 $component->getNumberOfPages()
229 );
230
231 $dd = $f->dropdown()->standard($chunk_options)->withLabel($dd_label);
232 $tpl->setCurrentBlock("entry");
233 $tpl->setVariable('BUTTON', $default_renderer->render($dd));
234 $tpl->parseCurrentBlock();
235 }
236
237 if ($component->getMaxPaginationButtons()) {
238 $this->setPaginationFirstLast($component, $range, $default_renderer, $tpl);
239 }
240
241 $this->setPaginationBrowseControls($component, $default_renderer, $tpl);
242 return $tpl->get();
243 }
244
250 protected function getPaginationRange(Component\ViewControl\Pagination $component): array
251 {
252 if (!$component->getMaxPaginationButtons()) {
253 $start = 0;
254 $stop = max($component->getNumberOfPages() - 1, 0);
255 } else {
256 //current page should be in the middle, so start is half the amount of max entries:
257 $start = (int) ($component->getCurrentPage() - floor($component->getMaxPaginationButtons() / 2));
258 $start = max($start, 0); //0, if negative
259 //stop is (calculated) start plus number of entries:
260 $stop = $start + $component->getMaxPaginationButtons() - 1;
261 //if stop exceeds max pages, recalculate both:
262 if ($stop > $component->getNumberOfPages() - 1) {
263 $stop = max($component->getNumberOfPages() - 1, 0); //0, if negative
264 $start = $stop - $component->getMaxPaginationButtons();
265 $start = max($start, 0); //0, if negative
266 }
267 }
268 return range($start, $stop);
269 }
270
271 protected function getPaginationShyButton(
272 int $val,
274 string $label = ''
275 ): Shy {
276 $f = $this->getUIFactory();
277
278 if ($label === '') {
279 $label = (string) ($val + 1);
280 }
281
282 if ($component->getTriggeredSignals()) {
283 $shy = $f->button()->shy($label, (string) $val)->withOnClick($component->getInternalSignal());
284 } else {
285 $url = $component->getTargetURL() ?? '';
286 if (strpos($url, '?') === false) {
287 $url .= '?' . $component->getParameterName() . '=' . $val;
288 } else {
289 $base = substr($url, 0, strpos($url, '?') + 1);
290 $query = parse_url($url, PHP_URL_QUERY);
291 parse_str($query, $params);
292 $params[$component->getParameterName()] = $val;
293 $url = $base . http_build_query($params);
294 }
295 $shy = $f->button()->shy($label, $url);
296 }
297 return $shy;
298 }
299
303 protected function setPaginationBrowseControls(
305 RendererInterface $default_renderer,
307 ): void {
308 $prev = max(0, $component->getCurrentPage() - 1);
309 $next = $component->getCurrentPage() + 1;
310
311 $f = $this->getUIFactory();
312
313 if ($component->getTriggeredSignals()) {
314 $back = $f->symbol()->glyph()->back('')->withOnClick($component->getInternalSignal());
315 $forward = $f->symbol()->glyph()->next('')->withOnClick($component->getInternalSignal());
316 } else {
317 $url = $component->getTargetURL() ?? '';
318 if (strpos($url, '?') === false) {
319 $url_prev = $url . '?' . $component->getParameterName() . '=' . $prev;
320 $url_next = $url . '?' . $component->getParameterName() . '=' . $next;
321 } else {
322 $base = substr($url, 0, strpos($url, '?') + 1);
323 $query = parse_url($url, PHP_URL_QUERY);
324 parse_str($query, $params);
325
326 $params[$component->getParameterName()] = $prev;
327 $url_prev = $base . http_build_query($params);
328 $params[$component->getParameterName()] = $next;
329 $url_next = $base . http_build_query($params);
330 }
331
332 $back = $f->symbol()->glyph()->back($url_prev);
333 $forward = $f->symbol()->glyph()->next($url_next);
334 }
335
336 if ($component->getCurrentPage() === 0) {
337 $back = $back->withUnavailableAction();
338 }
339 if ($component->getCurrentPage() >= $component->getNumberOfPages() - 1) {
340 $forward = $forward->withUnavailableAction();
341 }
342
343 $tpl->setVariable('PREVIOUS', $default_renderer->render($back));
344 $tpl->setVariable('NEXT', $default_renderer->render($forward));
345 }
346
352 protected function setPaginationFirstLast(
354 array $range,
355 RendererInterface $default_renderer,
357 ): void {
358 if (!in_array(0, $range)) {
359 $shy = $this->getPaginationShyButton(0, $component);
360 $tpl->setVariable('FIRST', $default_renderer->render($shy));
361 }
362 $last = max($component->getNumberOfPages() - 1, 0);
363 if (!in_array($last, $range)) {
364 $shy = $this->getPaginationShyButton($component->getNumberOfPages() - 1, $component);
365 $tpl->setVariable('LAST', $default_renderer->render($shy));
366 }
367 }
368
372 public function registerResources(ResourceRegistry $registry): void
373 {
374 parent::registerResources($registry);
375 $registry->register('./src/UI/templates/js/ViewControl/sortation.js');
376 $registry->register('./src/UI/templates/js/ViewControl/pagination.js');
377 }
378
379 protected function renderId(
380 Component\JavaScriptBindable $component,
382 string $block,
383 string $template_var
384 ): void {
385 $id = $this->bindJavaScript($component);
386 if (!$id) {
387 $id = $this->createId();
388 }
389 $tpl->setCurrentBlock($block);
390 $tpl->setVariable($template_var, $id);
391 $tpl->parseCurrentBlock();
392 }
393
397 protected function getComponentInterfaceName(): array
398 {
399 return array(
400 Component\ViewControl\Mode::class,
401 Component\ViewControl\Section::class,
402 Component\ViewControl\Sortation::class,
403 Component\ViewControl\Pagination::class
404 );
405 }
406}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
renderMode(Component\ViewControl\Mode $component, RendererInterface $default_renderer)
Definition: Renderer.php:58
registerResources(ResourceRegistry $registry)
Announce resources this renderer requires.
Definition: Renderer.php:372
setPaginationBrowseControls(Component\ViewControl\Pagination $component, RendererInterface $default_renderer, Template $tpl)
Add back/next-glyphs to the template for left/right browsing in pagination.
Definition: Renderer.php:303
getComponentInterfaceName()
Get the name of the component-interface this renderer is supposed to render.ATTENTION: Fully qualifie...
Definition: Renderer.php:397
renderSortation(Component\ViewControl\Sortation $component, RendererInterface $default_renderer)
Definition: Renderer.php:132
getPaginationRange(Component\ViewControl\Pagination $component)
Get the range of pagination-buttons to show.
Definition: Renderer.php:250
renderSectionButton(Component\Button\Button $component, Template $tpl, string $type)
Definition: Renderer.php:112
renderSection(Component\ViewControl\Section $component, RendererInterface $default_renderer)
Definition: Renderer.php:94
getPaginationShyButton(int $val, Component\ViewControl\Pagination $component, string $label='')
Definition: Renderer.php:271
setPaginationFirstLast(Component\ViewControl\Pagination $component, array $range, RendererInterface $default_renderer, Template $tpl)
Add quick-access to first/last pages in pagination.
Definition: Renderer.php:352
renderId(Component\JavaScriptBindable $component, Template $tpl, string $block, string $template_var)
Definition: Renderer.php:379
render(Component\Component $component, RendererInterface $default_renderer)
Definition: Renderer.php:39
checkComponent(Component $component)
Check if a given component fits this renderer and throw \LogicError if that is not the case.
getTemplate(string $name, bool $purge_unfilled_vars, bool $purge_unused_blocks)
Get template of component this renderer is made for.
return true
if(!file_exists(getcwd() . '/ilias.ini.php'))
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Definition: confirmReg.php:20
Interface to be extended by components that have the possibility to bind to Javascript.
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
if(! $DIC->user() ->getId()||!ilLTIConsumerAccess::hasCustomProviderCreationAccess()) $params
Definition: ltiregstart.php:33
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Definition: Bulky.php:21
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
$base
Definition: index.php:4
$query
$type
$url