ILIAS  release_7 Revision v7.30-3-g800a261c036
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
8use ILIAS\UI\Renderer as RendererInterface;
10
16{
17 public const MODE_ROLE = "group";
18
23 public function render(Component\Component $component, RendererInterface $default_renderer)
24 {
25 $this->checkComponent($component);
26
27 if ($component instanceof Component\ViewControl\Mode) {
28 return $this->renderMode($component, $default_renderer);
29 }
30 if ($component instanceof Component\ViewControl\Section) {
31 return $this->renderSection($component, $default_renderer);
32 }
33 if ($component instanceof Component\ViewControl\Sortation) {
34 return $this->renderSortation($component, $default_renderer);
35 }
36 if ($component instanceof Component\ViewControl\Pagination) {
37 return $this->renderPagination($component, $default_renderer);
38 }
39 }
40
41 protected function renderMode(Component\ViewControl\Mode $component, RendererInterface $default_renderer)
42 {
43 $f = $this->getUIFactory();
44
45 $tpl = $this->getTemplate("tpl.mode.html", true, true);
46
47 $active = $component->getActive();
48 if ($active == "") {
49 $activate_first_item = true;
50 }
51
52 foreach ($component->getLabelledActions() as $label => $action) {
53 $tpl->setVariable("ARIA", $this->txt($component->getAriaLabel()));
54 $tpl->setVariable("ROLE", self::MODE_ROLE);
55
56 $tpl->setCurrentBlock("view_control");
57
58 //At this point we don't have an specific text for the button aria label. component->getAriaLabel gets the main viewcontrol aria label.
59 $button = $f->button()->standard($label, $action)->withAriaLabel($label);
60 if ($activate_first_item) {
61 $button = $button->withEngagedState(true);
62 $activate_first_item = false;
63 } elseif ($active == $label) {
64 $button = $button->withEngagedState(true);
65 } else {
66 $button = $button->withEngagedState(false);
67 }
68 $tpl->setVariable("BUTTON", $default_renderer->render($button));
69 $tpl->parseCurrentBlock();
70 }
71
72 return $tpl->get();
73 }
74
75 protected function renderSection(Component\ViewControl\Section $component, RendererInterface $default_renderer)
76 {
77 $tpl = $this->getTemplate("tpl.section.html", true, true);
78
79 // render middle button
80 $tpl->setVariable("BUTTON", $default_renderer->render($component->getSelectorButton()));
81
82 // previous button
83 $this->renderSectionButton($component->getPreviousActions(), $tpl, "prev");
84
85 // next button
86 $this->renderSectionButton($component->getNextActions(), $tpl, "next");
87
88 return $tpl->get();
89 }
90
96 protected function renderSectionButton(Component\Button\Button $component, $tpl, $type)
97 {
98 $uptype = strtoupper($type);
99
100 $action = $component->getAction();
101 $tpl->setVariable($uptype . "_ACTION", $action);
102 $label = ($type == "next")
103 ? $this->txt("next")
104 : $this->txt("previous");
105 $tpl->setVariable($uptype . "_LABEL", $label);
106 if ($component->isActive()) {
107 $tpl->setCurrentBlock($type . "_with_href");
108 $tpl->setVariable($uptype . "_HREF", $action);
109 $tpl->parseCurrentBlock();
110 } else {
111 $tpl->touchBlock($type . "_disabled");
112 }
113 $this->renderId($component, $tpl, $type . "_with_id", $uptype . "_ID");
114 }
115
116
117 protected function renderSortation(Component\ViewControl\Sortation $component, RendererInterface $default_renderer)
118 {
119 $f = $this->getUIFactory();
120
121 $tpl = $this->getTemplate("tpl.sortation.html", true, true);
122
123 $component = $component->withResetSignals();
124 $triggeredSignals = $component->getTriggeredSignals();
125 if ($triggeredSignals) {
126 $internal_signal = $component->getSelectSignal();
127 $signal = $triggeredSignals[0]->getSignal();
128
129 $component = $component->withAdditionalOnLoadCode(function ($id) use ($internal_signal, $signal) {
130 return "$(document).on('{$internal_signal}', function(event, signalData) {
131 il.UI.viewcontrol.sortation.onInternalSelect(event, signalData, '{$signal}', '{$id}');
132 return false;
133 })";
134 });
135 }
136
137 $this->renderId($component, $tpl, "id", "ID");
138
139 //setup entries
140 $options = $component->getOptions();
141 $init_label = $component->getLabel();
142 $items = array();
143 foreach ($options as $val => $label) {
144 if ($triggeredSignals) {
145 $shy = $f->button()->shy($label, $val)->withOnClick($internal_signal);
146 } else {
147 $url = $component->getTargetURL();
148 $url .= (strpos($url, '?') === false) ? '?' : '&';
149 $url .= $component->getParameterName() . '=' . $val;
150 $shy = $f->button()->shy($label, $url);
151 }
152 $items[] = $shy;
153 }
154
155 $dd = $f->dropdown()->standard($items)
156 ->withLabel($init_label);
157
158 $tpl->setVariable('SORTATION_DROPDOWN', $default_renderer->render($dd));
159 return $tpl->get();
160 }
161
162
163
164 protected function renderPagination(Component\ViewControl\Pagination $component, RendererInterface $default_renderer)
165 {
166 $tpl = $this->getTemplate("tpl.pagination.html", true, true);
167
171 $component = $component->withResetSignals();
172 $triggeredSignals = $component->getTriggeredSignals();
173 if ($triggeredSignals) {
174 $internal_signal = $component->getInternalSignal();
175 $signal = $triggeredSignals[0]->getSignal();
176 $component = $component->withOnLoadCode(function ($id) use ($internal_signal, $signal) {
177 return "$(document).on('{$internal_signal}', function(event, signalData) {
178 il.UI.viewcontrol.pagination.onInternalSelect(event, signalData, '{$signal}', '{$id}');
179 return false;
180 })";
181 });
182
183 $id = $this->bindJavaScript($component);
184 $tpl->setVariable('ID', $id);
185 }
186
187 $range = $this->getPaginationRange($component);
188 $chunk_options = array();
189 foreach ($range as $entry) {
190 $shy = $this->getPaginationShyButton($entry, $component);
191 if ((int) $entry === $component->getCurrentPage()) {
192 $shy = $shy->withEngagedState(true);
193 }
194 $chunk_options[] = $shy;
195 }
196
197 if ($component->getDropdownAt() == null ||
198 $component->getDropdownAt() > $component->getNumberOfPages()) {
199 foreach ($chunk_options as $entry) {
200 $tpl->setCurrentBlock("entry");
201 $tpl->setVariable('BUTTON', $default_renderer->render($entry));
202 $tpl->parseCurrentBlock();
203 }
204 } else {
205 //if threshold is reached, render as dropdown
206 $f = $this->getUIFactory();
207
208 $dd_label_template = $component->getDropdownLabel();
209 if ($dd_label_template === $component->getDefaultDropdownLabel()) {
210 $dd_label_template = $this->txt($dd_label_template);
211 }
212 $dd_label = sprintf(
213 $dd_label_template,
214 $component->getCurrentPage() + 1,
215 $component->getNumberOfPages()
216 );
217
218 $dd = $f->dropdown()->standard($chunk_options)->withLabel($dd_label);
219 $tpl->setCurrentBlock("entry");
220 $tpl->setVariable('BUTTON', $default_renderer->render($dd));
221 $tpl->parseCurrentBlock();
222 }
223
224 if ($component->getMaxPaginationButtons()) {
225 $this->setPaginationFirstLast($component, $range, $default_renderer, $tpl);
226 }
227
228 $this->setPaginationBrowseControls($component, $default_renderer, $tpl);
229 return $tpl->get();
230 }
231
239 protected function getPaginationRange(Component\ViewControl\Pagination $component)
240 {
241 if (!$component->getMaxPaginationButtons()) {
242 $start = 0;
243 $stop = max($component->getNumberOfPages() - 1, 0);
244 } else {
245 //current page should be in the middle, so start is half the amount of max entries:
246 $start = (int) ($component->getCurrentPage() - floor($component->getMaxPaginationButtons() / 2));
247 $start = max($start, 0); //0, if negative
248 //stop is (calculated) start plus number of entries:
249 $stop = $start + $component->getMaxPaginationButtons() - 1;
250 //if stop exceeds max pages, recalculate both:
251 if ($stop > $component->getNumberOfPages() - 1) {
252 $stop = max($component->getNumberOfPages() - 1, 0); //0, if negative
253 $start = $stop - $component->getMaxPaginationButtons();
254 $start = max($start, 0); //0, if negative
255 }
256 }
257 return range($start, $stop);
258 }
259
260
268 protected function getPaginationShyButton($val, Component\ViewControl\Pagination $component, $label = '')
269 {
270 $f = $this->getUIFactory();
271
272 if ($label === '') {
273 $label = (string) ((int) $val + 1);
274 }
275
276 if ($component->getTriggeredSignals()) {
277 $shy = $f->button()->shy($label, (string) $val)->withOnClick($component->getInternalSignal());
278 } else {
279 $url = $component->getTargetURL();
280 if (strpos($url, '?') === false) {
281 $url .= '?' . $component->getParameterName() . '=' . $val;
282 } else {
283 $base = substr($url, 0, strpos($url, '?') + 1);
284 $query = parse_url($url, PHP_URL_QUERY);
285 parse_str($query, $params);
286 $params[$component->getParameterName()] = $val;
287 $url = $base . http_build_query($params);
288 }
289 $shy = $f->button()->shy($label, $url);
290 }
291 return $shy;
292 }
293
303 protected function setPaginationBrowseControls(Component\ViewControl\Pagination $component, RendererInterface $default_renderer, $tpl)
304 {
305 $prev = max(0, $component->getCurrentPage() - 1);
306 $next = $component->getCurrentPage() + 1;
307
308 $f = $this->getUIFactory();
309
310 if ($component->getTriggeredSignals()) {
311 $back = $f->symbol()->glyph()->back('')->withOnClick($component->getInternalSignal());
312 $forward = $f->symbol()->glyph()->next('')->withOnClick($component->getInternalSignal());
313 } else {
314 $url = $component->getTargetURL();
315 if (strpos($url, '?') === false) {
316 $url_prev = $url . '?' . $component->getParameterName() . '=' . $prev;
317 $url_next = $url . '?' . $component->getParameterName() . '=' . $next;
318 } else {
319 $base = substr($url, 0, strpos($url, '?') + 1);
320 $query = parse_url($url, PHP_URL_QUERY);
321 parse_str($query, $params);
322
323 $params[$component->getParameterName()] = $prev;
324 $url_prev = $base . http_build_query($params);
325 $params[$component->getParameterName()] = $next;
326 $url_next = $base . http_build_query($params);
327 }
328
329 $back = $f->symbol()->glyph()->back($url_prev);
330 $forward = $f->symbol()->glyph()->next($url_next);
331 }
332
333 if ($component->getCurrentPage() === 0) {
334 $back = $back->withUnavailableAction();
335 }
336 if ($component->getCurrentPage() >= $component->getNumberOfPages() - 1) {
337 $forward = $forward->withUnavailableAction();
338 }
339
340 $tpl->setVariable('PREVIOUS', $default_renderer->render($back));
341 $tpl->setVariable('NEXT', $default_renderer->render($forward));
342 }
343
354 protected function setPaginationFirstLast(Component\ViewControl\Pagination $component, $range, RendererInterface $default_renderer, $tpl)
355 {
356 if (!in_array(0, $range)) {
357 $shy = $this->getPaginationShyButton(0, $component);
358 $tpl->setVariable('FIRST', $default_renderer->render($shy));
359 }
360 $last = max($component->getNumberOfPages() - 1, 0);
361 if (!in_array($last, $range)) {
362 $shy = $this->getPaginationShyButton($component->getNumberOfPages() - 1, $component);
363 $tpl->setVariable('LAST', $default_renderer->render($shy));
364 }
365 }
366
367
371 public function registerResources(\ILIAS\UI\Implementation\Render\ResourceRegistry $registry)
372 {
373 parent::registerResources($registry);
374 $registry->register('./src/UI/templates/js/ViewControl/sortation.js');
375 $registry->register('./src/UI/templates/js/ViewControl/pagination.js');
376 }
377
378
379 protected function renderId(Component\JavaScriptBindable $component, $tpl, $block, $template_var)
380 {
381 $id = $this->bindJavaScript($component);
382 if (!$id) {
383 $id = $this->createId();
384 }
385 $tpl->setCurrentBlock($block);
386 $tpl->setVariable($template_var, $id);
387 $tpl->parseCurrentBlock();
388 }
389
393 protected function getComponentInterfaceName()
394 {
395 return array(
396 Component\ViewControl\Mode::class,
397 Component\ViewControl\Section::class,
398 Component\ViewControl\Sortation::class,
399 Component\ViewControl\Pagination::class
400 );
401 }
402}
An exception for terminatinating execution or to throw for unit testing.
renderMode(Component\ViewControl\Mode $component, RendererInterface $default_renderer)
Definition: Renderer.php:41
getComponentInterfaceName()
Get the name of the component-interface this renderer is supposed to render.ATTENTION: Fully qualifie...
Definition: Renderer.php:393
renderSortation(Component\ViewControl\Sortation $component, RendererInterface $default_renderer)
Definition: Renderer.php:117
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:303
renderSectionButton(Component\Button\Button $component, $tpl, $type)
Definition: Renderer.php:96
getPaginationShyButton($val, Component\ViewControl\Pagination $component, $label='')
Definition: Renderer.php:268
renderId(Component\JavaScriptBindable $component, $tpl, $block, $template_var)
Definition: Renderer.php:379
getPaginationRange(Component\ViewControl\Pagination $component)
Get the range of pagination-buttons to show.
Definition: Renderer.php:239
registerResources(\ILIAS\UI\Implementation\Render\ResourceRegistry $registry)
Definition: Renderer.php:371
renderSection(Component\ViewControl\Section $component, RendererInterface $default_renderer)
Definition: Renderer.php:75
render(Component\Component $component, RendererInterface $default_renderer)
Definition: Renderer.php:23
setPaginationFirstLast(Component\ViewControl\Pagination $component, $range, RendererInterface $default_renderer, $tpl)
Add quick-access to first/last pages in pagination.
Definition: Renderer.php:354
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.
A component is the most general form of an entity in the UI.
Definition: Component.php:14
Interface to be extended by components that have the possibility to bind to Javascript.
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
trait JavaScriptBindable
Trait for components implementing JavaScriptBindable providing standard implementation.
Class ChatMainBarProvider \MainMenu\Provider.
Class Factory.
$base
Definition: index.php:4
$query
$type
$url