ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
Renderer.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 2017 Jesús López <lopez@leifos.de> Extended GPL, see docs/LICENSE */
3
5
7use ILIAS\UI\Renderer as RendererInterface;
9
15{
16 const MODE_ROLE = "group";
17
22 public function render(Component\Component $component, RendererInterface $default_renderer)
23 {
24 $this->checkComponent($component);
25
26 if ($component instanceof Component\ViewControl\Mode) {
27 return $this->renderMode($component, $default_renderer);
28 }
29 if ($component instanceof Component\ViewControl\Section) {
30 return $this->renderSection($component, $default_renderer);
31 }
32 if ($component instanceof Component\ViewControl\Sortation) {
33 return $this->renderSortation($component, $default_renderer);
34 }
35 if ($component instanceof Component\ViewControl\Pagination) {
36 return $this->renderPagination($component, $default_renderer);
37 }
38 }
39
40 protected function renderMode(Component\ViewControl\Mode $component, RendererInterface $default_renderer)
41 {
42 $f = $this->getUIFactory();
43
44 $tpl = $this->getTemplate("tpl.mode.html", true, true);
45
46 $active = $component->getActive();
47 if ($active == "") {
48 $activate_first_item = true;
49 }
50
51 foreach ($component->getLabelledActions() as $label => $action) {
52 $tpl->setVariable("ARIA", $this->txt($component->getAriaLabel()));
53 $tpl->setVariable("ROLE", self::MODE_ROLE);
54
55 $tpl->setCurrentBlock("view_control");
56
57 //At this point we don't have an specific text for the button aria label. component->getAriaLabel gets the main viewcontrol aria label.
58 if ($activate_first_item) {
59 $tpl->setVariable("BUTTON", $default_renderer->render($f->button()->standard($label, $action)->WithUnavailableAction()->withAriaLabel($label)->withAriaChecked()));
60 $activate_first_item = false;
61 } elseif ($active == $label) {
62 $tpl->setVariable("BUTTON", $default_renderer->render($f->button()->standard($label, $action)->withUnavailableAction()->withAriaLabel($label)->withAriaChecked()));
63 } else {
64 $tpl->setVariable("BUTTON", $default_renderer->render($f->button()->standard($label, $action)->withAriaLabel($label)));
65 }
66 $tpl->parseCurrentBlock();
67 }
68
69 return $tpl->get();
70 }
71
72 protected function renderSection(Component\ViewControl\Section $component, RendererInterface $default_renderer)
73 {
74 $f = $this->getUIFactory();
75
76 $tpl = $this->getTemplate("tpl.section.html", true, true);
77
78 // render middle button
79 $tpl->setVariable("BUTTON", $default_renderer->render($component->getSelectorButton()));
80
81 // previous button
82 $this->renderSectionButton($component->getPreviousActions(), $tpl, "prev");
83
84 // next button
85 $this->renderSectionButton($component->getNextActions(), $tpl, "next");
86
87 return $tpl->get();
88 }
89
95 protected function renderSectionButton(Component\Button\Button $component, $tpl, $type)
96 {
97 $uptype = strtoupper($type);
98
99 $action = $component->getAction();
100 $tpl->setVariable($uptype . "_ACTION", $action);
101 if ($component->isActive()) {
102 $tpl->setCurrentBlock($type . "_with_href");
103 $tpl->setVariable($uptype . "_HREF", $action);
104 $tpl->parseCurrentBlock();
105 } else {
106 $tpl->touchBlock($type . "_disabled");
107 }
108 $this->maybeRenderId($component, $tpl, $type . "_with_id", $uptype . "_ID");
109 }
110
111
112 protected function renderSortation(Component\ViewControl\Sortation $component, RendererInterface $default_renderer)
113 {
114 $f = $this->getUIFactory();
115
116 $tpl = $this->getTemplate("tpl.sortation.html", true, true);
117
118 $component = $component->withResetSignals();
119 $triggeredSignals = $component->getTriggeredSignals();
120 if ($triggeredSignals) {
121 $internal_signal = $component->getSelectSignal();
122 $signal = $triggeredSignals[0]->getSignal();
123 $options = json_encode($signal->getOptions());
124
125 $component = $component->withOnLoadCode(function ($id) use ($internal_signal, $signal) {
126 return "$(document).on('{$internal_signal}', function(event, signalData) {
127 il.UI.viewcontrol.sortation.onInternalSelect(event, signalData, '{$signal}', '{$id}');
128 return false;
129 })";
130 });
131
132 //maybeRenderId does not return id
133 $id = $this->bindJavaScript($component);
134 $tpl->setVariable('ID', $id);
135 }
136
137 //setup entries
138 $options = $component->getOptions();
139 $init_label = $component->getLabel();
140 $items = array();
141 foreach ($options as $val => $label) {
142 if ($triggeredSignals) {
143 $shy = $f->button()->shy($label, $val)->withOnClick($internal_signal);
144 } else {
145 $url = $component->getTargetURL();
146 $url .= (strpos($url, '?') === false) ? '?' : '&';
147 $url .= $component->getParameterName() . '=' . $val;
148 $shy = $f->button()->shy($label, $url);
149 }
150 $items[] = $shy;
151 }
152
153 $dd = $f->dropdown()->standard($items)
154 ->withLabel($init_label);
155
156 $tpl->setVariable('SORTATION_DROPDOWN', $default_renderer->render($dd));
157 return $tpl->get();
158 }
159
160
161
162 protected function renderPagination(Component\ViewControl\Pagination $component, RendererInterface $default_renderer)
163 {
164 $tpl = $this->getTemplate("tpl.pagination.html", true, true);
165
166 $component = $component->withResetSignals();
167 $triggeredSignals = $component->getTriggeredSignals();
168 if ($triggeredSignals) {
169 $internal_signal = $component->getInternalSignal();
170 $signal = $triggeredSignals[0]->getSignal();
171 $component = $component->withOnLoadCode(function ($id) use ($internal_signal, $signal) {
172 return "$(document).on('{$internal_signal}', function(event, signalData) {
173 il.UI.viewcontrol.pagination.onInternalSelect(event, signalData, '{$signal}', '{$id}');
174 return false;
175 })";
176 });
177
178 $id = $this->bindJavaScript($component);
179 $tpl->setVariable('ID', $id);
180 }
181
182 $range = $this->getPaginationRange($component);
183 $chunk_options = array();
184 foreach ($range as $entry) {
185 $shy = $this->getPaginationShyButton($entry, $component);
186 if ((int) $entry === $component->getCurrentPage()) {
187 $shy = $shy->withUnavailableAction();
188 }
189 $chunk_options[] = $shy;
190 }
191
192 if ($component->getDropdownAt() == null ||
193 $component->getDropdownAt() > $component->getNumberOfPages()) {
194 foreach ($chunk_options as $entry) {
195 $tpl->setCurrentBlock("entry");
196 $tpl->setVariable('BUTTON', $default_renderer->render($entry));
197 $tpl->parseCurrentBlock();
198 }
199 } else {
200 //if threshold is reached, render as dropdown
201 $f = $this->getUIFactory();
202 $dd = $f->dropdown()->standard($chunk_options)->withLabel(
203 (string) ($component->getCurrentPage() + 1)
204 );
205 $tpl->setCurrentBlock("entry");
206 $tpl->setVariable('BUTTON', $default_renderer->render($dd));
207 $tpl->parseCurrentBlock();
208 }
209
210 if ($component->getMaxPaginationButtons()) {
211 $this->setPaginationFirstLast($component, $range, $default_renderer, $tpl);
212 }
213
214 $this->setPaginationBrowseControls($component, $default_renderer, $tpl);
215 return $tpl->get();
216 }
217
225 protected function getPaginationRange(Component\ViewControl\Pagination $component)
226 {
227 if (!$component->getMaxPaginationButtons()) {
228 $start = 0;
229 $stop = max($component->getNumberOfPages() - 1, 0);
230 } else {
231 //current page should be in the middle, so start is half the amount of max entries:
232 $start = (int) ($component->getCurrentPage() - floor($component->getMaxPaginationButtons() / 2));
233 $start = max($start, 0); //0, if negative
234 //stop is (calculated) start plus number of entries:
235 $stop = $start + $component->getMaxPaginationButtons() - 1;
236 //if stop exceeds max pages, recalculate both:
237 if ($stop > $component->getNumberOfPages() - 1) {
238 $stop = max($component->getNumberOfPages() - 1, 0); //0, if negative
239 $start = $stop - $component->getMaxPaginationButtons();
240 $start = max($start, 0); //0, if negative
241 }
242 }
243 return range($start, $stop);
244 }
245
246
254 protected function getPaginationShyButton($val, Component\ViewControl\Pagination $component, $label = '')
255 {
256 $f = $this->getUIFactory();
257
258 if ($label === '') {
259 $label = (string) ($val + 1);
260 }
261
262 if ($component->getTriggeredSignals()) {
263 $shy = $f->button()->shy($label, (string) $val)->withOnClick($component->getInternalSignal());
264 } else {
265 $url = $component->getTargetURL();
266 if (strpos($url, '?') === false) {
267 $url .= '?' . $component->getParameterName() . '=' . $val;
268 } else {
269 $base = substr($url, 0, strpos($url, '?') + 1);
270 $query = parse_url($url, PHP_URL_QUERY);
271 parse_str($query, $params);
272 $params[$component->getParameterName()] = $val;
273 $url = $base . http_build_query($params);
274 }
275 $shy = $f->button()->shy($label, $url);
276 }
277 return $shy;
278 }
279
289 protected function setPaginationBrowseControls(Component\ViewControl\Pagination $component, RendererInterface $default_renderer, &$tpl)
290 {
291 $prev = max(0, $component->getCurrentPage() - 1);
292 $next = $component->getCurrentPage() + 1;
293
294 $f = $this->getUIFactory();
295
296 if ($component->getTriggeredSignals()) {
297 $back = $f->glyph()->back('')->withOnClick($component->getInternalSignal());
298 $forward = $f->glyph()->next('')->withOnClick($component->getInternalSignal());
299 } else {
300 $url = $component->getTargetURL();
301 if (strpos($url, '?') === false) {
302 $url_prev = $url . '?' . $component->getParameterName() . '=' . $prev;
303 $url_next = $url . '?' . $component->getParameterName() . '=' . $next;
304 } else {
305 $base = substr($url, 0, strpos($url, '?') + 1);
306 $query = parse_url($url, PHP_URL_QUERY);
307 parse_str($query, $params);
308
309 $params[$component->getParameterName()] = $prev;
310 $url_prev = $base . http_build_query($params);
311 $params[$component->getParameterName()] = $next;
312 $url_next = $base . http_build_query($params);
313 }
314
315 $back = $f->glyph()->back($url_prev);
316 $forward = $f->glyph()->next($url_next);
317 }
318
319 if ($component->getCurrentPage() === 0) {
320 $back = $back->withUnavailableAction();
321 }
322 if ($component->getCurrentPage() >= $component->getNumberOfPages() - 1) {
323 $forward = $forward->withUnavailableAction();
324 }
325
326 $tpl->setVariable('PREVIOUS', $default_renderer->render($back));
327 $tpl->setVariable('NEXT', $default_renderer->render($forward));
328 }
329
340 protected function setPaginationFirstLast(Component\ViewControl\Pagination $component, $range, RendererInterface $default_renderer, &$tpl)
341 {
342 if (!in_array(0, $range)) {
343 $shy = $this->getPaginationShyButton(0, $component);
344 $tpl->setVariable('FIRST', $default_renderer->render($shy));
345 }
346 $last = max($component->getNumberOfPages() - 1, 0);
347 if (!in_array($last, $range)) {
348 $shy = $this->getPaginationShyButton($component->getNumberOfPages() - 1, $component);
349 $tpl->setVariable('LAST', $default_renderer->render($shy));
350 }
351 }
352
353
357 public function registerResources(\ILIAS\UI\Implementation\Render\ResourceRegistry $registry)
358 {
359 parent::registerResources($registry);
360 $registry->register('./src/UI/templates/js/ViewControl/sortation.js');
361 $registry->register('./src/UI/templates/js/ViewControl/pagination.js');
362 }
363
364
365 protected function maybeRenderId(Component\Component $component, $tpl, $block, $template_var)
366 {
367 $id = $this->bindJavaScript($component);
368 if ($id !== null) {
369 $tpl->setCurrentBlock($block);
370 $tpl->setVariable($template_var, $id);
371 $tpl->parseCurrentBlock();
372 }
373 }
374
378 protected function getComponentInterfaceName()
379 {
380 return array(
381 Component\ViewControl\Mode::class,
382 Component\ViewControl\Section::class,
383 Component\ViewControl\Sortation::class,
384 Component\ViewControl\Pagination::class
385 );
386 }
387}
$tpl
Definition: ilias.php:10
An exception for terminatinating execution or to throw for unit testing.
renderMode(Component\ViewControl\Mode $component, RendererInterface $default_renderer)
Definition: Renderer.php:40
renderPagination(Component\ViewControl\Pagination $component, RendererInterface $default_renderer)
Definition: Renderer.php:162
setPaginationFirstLast(Component\ViewControl\Pagination $component, $range, RendererInterface $default_renderer, &$tpl)
Add quick-access to first/last pages in pagination.
Definition: Renderer.php:340
getComponentInterfaceName()
Get the name of the component-interface this renderer is supposed to render.ATTENTION: Fully qualifie...
Definition: Renderer.php:378
renderSortation(Component\ViewControl\Sortation $component, RendererInterface $default_renderer)
Definition: Renderer.php:112
maybeRenderId(Component\Component $component, $tpl, $block, $template_var)
Definition: Renderer.php:365
renderSectionButton(Component\Button\Button $component, $tpl, $type)
Definition: Renderer.php:95
setPaginationBrowseControls(Component\ViewControl\Pagination $component, RendererInterface $default_renderer, &$tpl)
Add back/next-glyphs to the template for left/right browsing in pagination.
Definition: Renderer.php:289
getPaginationShyButton($val, Component\ViewControl\Pagination $component, $label='')
Definition: Renderer.php:254
getPaginationRange(Component\ViewControl\Pagination $component)
Get the range of pagintaion-buttons to show.
Definition: Renderer.php:225
registerResources(\ILIAS\UI\Implementation\Render\ResourceRegistry $registry)
Definition: Renderer.php:357
renderSection(Component\ViewControl\Section $component, RendererInterface $default_renderer)
Definition: Renderer.php:72
render(Component\Component $component, RendererInterface $default_renderer)
@inheritdocs
Definition: Renderer.php:22
getTemplate($name, $purge_unfilled_vars, $purge_unused_blocks)
Get template of component this renderer is made for.
bindJavaScript(JavaScriptBindable $component)
Bind the component to JavaScript.
checkComponent(Component $component)
Check if a given component fits this renderer and throw \LogicError if that is not the case.
$action
if(!array_key_exists('StateId', $_REQUEST)) $id
A component is the most general form of an entity in the UI.
Definition: Component.php:14
An entity that renders components to a string output.
Definition: Renderer.php:15
$base
Definition: index.php:4
Class BaseForm.
Class Factory.
$query
$type
$url
$start
Definition: bench.php:8