ILIAS  release_8 Revision v8.19
All Data Structures Namespaces Files Functions Variables Modules Pages
Renderer.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
22 
29 use 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(
133  Component\ViewControl\Sortation $component,
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,
273  Component\ViewControl\Pagination $component,
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(
304  Component\ViewControl\Pagination $component,
305  RendererInterface $default_renderer,
306  Template $tpl
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(
353  Component\ViewControl\Pagination $component,
354  array $range,
355  RendererInterface $default_renderer,
356  Template $tpl
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,
381  Template $tpl,
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 }
renderSection(Component\ViewControl\Section $component, RendererInterface $default_renderer)
Definition: Renderer.php:94
Registry for resources required by rendered output like Javascript or CSS.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Definition: Factory.php:21
renderSortation(Component\ViewControl\Sortation $component, RendererInterface $default_renderer)
Definition: Renderer.php:132
checkComponent(Component $component)
Check if a given component fits this renderer and throw if that is not the case. ...
$type
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...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
txt(string $id)
Get a text from the language file.
render(Component\Component $component, RendererInterface $default_renderer)
Definition: Renderer.php:39
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Definition: Bulky.php:21
renderId(Component\JavaScriptBindable $component, Template $tpl, string $block, string $template_var)
Definition: Renderer.php:379
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
setCurrentBlock(string $name)
Set the block to work on.
getPaginationShyButton(int $val, Component\ViewControl\Pagination $component, string $label='')
Definition: Renderer.php:271
setVariable(string $name, $value)
Set a variable in the current block.
getPaginationRange(Component\ViewControl\Pagination $component)
Get the range of pagination-buttons to show.
Definition: Renderer.php:250
renderMode(Component\ViewControl\Mode $component, RendererInterface $default_renderer)
Definition: Renderer.php:58
getTemplate(string $name, bool $purge_unfilled_vars, bool $purge_unused_blocks)
Get template of component this renderer is made for.
$query
register(string $name)
Add a dependency.
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
parseCurrentBlock()
Parse the block that is currently worked on.
touchBlock(string $name)
Touch a block without working further on it.
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
$url
if($DIC->http() ->request() ->getMethod()=="GET" &&isset($DIC->http() ->request() ->getQueryParams()['tex'])) $tpl
Definition: latex.php:41
registerResources(ResourceRegistry $registry)
Announce resources this renderer requires.
Definition: Renderer.php:372
renderSectionButton(Component\Button\Button $component, Template $tpl, string $type)
Definition: Renderer.php:112
$base
Definition: index.php:4
bindJavaScript(JavaScriptBindable $component)
Bind the component to JavaScript.