ILIAS  trunk Revision v12.0_alpha-377-g3641b37b9db
Renderer.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
25use ILIAS\UI\Renderer as RendererInterface;
32
34{
38 public function render(Component\Component $component, RendererInterface $default_renderer): string
39 {
40 if ($component instanceof Component\Triggerer) {
41 $component = $this->addTriggererOnLoadCode($component);
42 }
43 if ($component instanceof Component\Button\Close) {
44 return $this->renderClose($component);
45 } elseif ($component instanceof Component\Button\Minimize) {
46 return $this->renderMinimize($component);
47 } elseif ($component instanceof Component\Button\Toggle) {
48 return $this->renderToggle($component);
49 } elseif ($component instanceof Component\Button\Month) {
50 return $this->renderMonth($component);
51 } elseif ($component instanceof Component\Button\Button) {
52 return $this->renderButton($component, $default_renderer);
53 }
54 $this->cannotHandleComponent($component);
55 }
56
57 protected function renderButton(Component\Button\Button $component, RendererInterface $default_renderer): string
58 {
59 $tpl_name = "";
60 if ($component instanceof Component\Button\Primary) {
61 $tpl_name = "tpl.primary.html";
62 }
63 if ($component instanceof Component\Button\Standard) {
64 $tpl_name = "tpl.standard.html";
65 }
66 if ($component instanceof Component\Button\Shy) {
67 $tpl_name = "tpl.shy.html";
68 }
69 if ($component instanceof Component\Button\Tag) {
70 $tpl_name = "tpl.tag.html";
71 }
72 if ($component instanceof Component\Button\Bulky) {
73 $tpl_name = "tpl.bulky.html";
74 }
75
76 $tpl = $this->getTemplate($tpl_name, true, true);
77
78 $action = $component->getAction();
79 // The action is always put in the data-action attribute to have it available
80 // on the client side, even if it is not available on rendering.
81 if (is_string($action)) {
82 $tpl->setCurrentBlock("with_data_action");
83 $tpl->setVariable("ACTION", $action);
84 $tpl->parseCurrentBlock();
85 }
86
87 $tpl->setVariable("LABEL", $component->getLabel());
88 $symbol = $component->getSymbol();
89 if ($symbol !== null) {
90 if ($component->getLabel() !== '') {
91 $symbol = $symbol->withLabel('');
92 }
93 $tpl->setVariable("SYMBOL", $default_renderer->render($symbol));
94 }
95
96 if ($component->isActive()) {
97 // The actions might also be a list of signals, these will be appended by
98 // bindJavascript in maybeRenderId.
99 if (is_string($action) && $action != "") {
100 $component = $component->withAdditionalOnLoadCode(function ($id) use ($action) {
101 $action = str_replace("&amp;", "&", $action);
102
103 return "$('#$id').on('click', function(event) {
104 window.location = '$action';
105 return false;
106 });";
107 });
108 }
109
110 if ($component instanceof Component\Button\LoadingAnimationOnClick && $component->hasLoadingAnimationOnClick()) {
111 $component = $component->withAdditionalOnLoadCode(fn($id) => "$('#$id').click(function(e) { il.UI.button.activateLoadingAnimation('$id')});");
112 }
113 } else {
114 $tpl->touchBlock("disabled");
115 }
116 $aria_label = $component->getAriaLabel();
117 if ($aria_label != null) {
118 $tpl->setCurrentBlock("with_aria_label");
119 $tpl->setVariable("ARIA_LABEL", $aria_label);
120 $tpl->parseCurrentBlock();
121 }
122
123 if ($component instanceof Component\Button\Engageable
124 && $component->isEngageable()
125 ) {
126 if ($component->isEngaged()) {
127 $tpl->touchBlock("engaged");
128 $aria_pressed = 'true';
129 } else {
130 $aria_pressed = 'false';
131 }
132
133 //Note that Bulky Buttons need to handle aria_pressed seperatly due to possible aria_role conflicts
134 if (!($component instanceof Bulky)) {
135 $tpl->setCurrentBlock("with_aria_pressed");
136 $tpl->setVariable("ARIA_PRESSED", $aria_pressed);
137 $tpl->parseCurrentBlock();
138 }
139 }
140
141 $tooltip_embedding = $this->getTooltipRenderer()->maybeGetTooltipEmbedding(...$component->getHelpTopics());
142 if ($tooltip_embedding) {
143 $component = $component->withAdditionalOnLoadCode($tooltip_embedding[1]);
144 }
145
146 $this->maybeRenderId($component, $tpl);
147
148 if ($component instanceof Component\Button\Tag) {
149 $this->additionalRenderTag($component, $tpl);
150 }
151
152 if ($component instanceof Component\Button\Bulky) {
153 $this->additionalRenderBulky($component, $default_renderer, $tpl);
154 }
155
156 if (!$tooltip_embedding) {
157 return $tpl->get();
158 }
159
160 $tooltip_id = $this->createId();
161 $tpl->setCurrentBlock("with_aria_describedby");
162 $tpl->setVariable("ARIA_DESCRIBED_BY", $tooltip_id);
163 $tpl->parseCurrentBlock();
164
165 return $tooltip_embedding[0]($tooltip_id, $tpl->get());
166 }
167
171 public function registerResources(ResourceRegistry $registry): void
172 {
173 parent::registerResources($registry);
174 $registry->register('assets/js/button.js');
175 $registry->register("./assets/js/moment-with-locales.min.js");
176 }
177
178 protected function renderClose(Component\Button\Close $component): string
179 {
180 $tpl = $this->getTemplate("tpl.close.html", true, true);
181 // This is required as the rendering seems to only create any output at all
182 // if any var was set or block was touched.
183 $tpl->setVariable("FORCE_RENDERING", "");
184 $tpl->setVariable("ARIA_LABEL", $this->txt("close"));
185 $this->maybeRenderId($component, $tpl);
186 return $tpl->get();
187 }
188
189 protected function renderMinimize(Component\Button\Minimize $component): string
190 {
191 $tpl = $this->getTemplate("tpl.minimize.html", true, true);
192 $tpl->setVariable("ARIA_LABEL", $this->txt("minimize"));
193 $this->maybeRenderId($component, $tpl);
194 return $tpl->get();
195 }
196
197 protected function renderToggle(Component\Button\Toggle $component): string
198 {
199 $tpl = $this->getTemplate("tpl.toggle.html", true, true);
200
201 $on_action = $component->getActionOn();
202 $off_action = $component->getActionOff();
203
204 $on_url = (is_string($on_action))
205 ? $on_action
206 : "";
207
208 $off_url = (is_string($off_action))
209 ? $off_action
210 : "";
211
212 $signals = [];
213
214 foreach ($component->getTriggeredSignals() as $s) {
215 $signals[] = [
216 "signal_id" => $s->getSignal()->getId(),
217 "event" => $s->getEvent(),
218 "options" => $s->getSignal()->getOptions()
219 ];
220 }
221
222 $signals = json_encode($signals);
223
224 $button_status = 'off';
225 if ($component->isEngaged()) {
226 $button_status = 'on';
227 }
228
229 if ($component->isActive()) {
230 $component = $component->withAdditionalOnLoadCode(
231 fn($id) =>
232 "$('#$id').on('click', function(event) {
233 il.UI.button.handleToggleClick(event, '$id', '$on_url', '$off_url', $signals);
234 return false; // stop event propagation
235 });"
236 );
237 $tpl->setCurrentBlock("with_on_off_label");
238 $tpl->setVariable("ON_LABEL", $this->txt("toggle_on"));
239 $tpl->setVariable("OFF_LABEL", $this->txt("toggle_off"));
240 $tpl->parseCurrentBlock();
241 } else {
242 $tpl->touchBlock("disabled");
243 $button_status = 'unavailable';
244 }
245
246 $tpl->touchBlock($button_status);
247
248 $label = $component->getLabel();
249 if (!empty($label)) {
250 $tpl->setCurrentBlock("with_label");
251 $tpl->setVariable("LABEL", $label);
252 $tpl->parseCurrentBlock();
253 }
254 $aria_label = $component->getAriaLabel();
255 if ($aria_label != null) {
256 $tpl->setCurrentBlock("with_aria_label");
257 $tpl->setVariable("ARIA_LABEL", $aria_label);
258 $tpl->parseCurrentBlock();
259 }
260
261 $tooltip_embedding = $this->getTooltipRenderer()->maybeGetTooltipEmbedding(...$component->getHelpTopics());
262 if ($tooltip_embedding) {
263 $component = $component->withAdditionalOnLoadCode($tooltip_embedding[1]);
264 $tooltip_id = $this->createId();
265 $tpl->setCurrentBlock("with_aria_describedby");
266 $tpl->setVariable("ARIA_DESCRIBED_BY", $tooltip_id);
267 $tpl->parseCurrentBlock();
268
269 $this->maybeRenderId($component, $tpl);
270 return $tooltip_embedding[0]($tooltip_id, $tpl->get());
271 }
272
273 $this->maybeRenderId($component, $tpl);
274 return $tpl->get();
275 }
276
277 protected function maybeRenderId(Component\JavaScriptBindable $component, Template $tpl): void
278 {
279 $id = $this->bindJavaScript($component);
280 if ($id !== null) {
281 $tpl->setCurrentBlock("with_id");
282 $tpl->setVariable("ID", $id);
283 $tpl->parseCurrentBlock();
284 }
285 }
286
287 protected function renderMonth(Component\Button\Month $component): string
288 {
289 $tpl = $this->getTemplate("tpl.month.html", true, true);
290
291 $component = $component->withAdditionalOnLoadCode(fn($id) => "il.UI.button.initMonth('$id');");
292 $id = $this->bindJavaScript($component);
293 $tpl->setVariable("ID", $id);
294
295 $def = $component->getDefault();
296 $value = implode('-', array_reverse(explode("-", $def)));
297 $tpl->setVariable("DEFAULT", $value);
298
299 return $tpl->get();
300 }
301
302 protected function additionalRenderTag(Component\Button\Tag $component, Template $tpl): void
303 {
304 $tpl->touchBlock('rel_' . $component->getRelevance());
305
306 $classes = trim(join(' ', $component->getClasses()));
307 if ($classes !== '') {
308 $tpl->setVariable("CLASSES", $classes);
309 }
310
311 $bgcol = $component->getBackgroundColor();
312 if ($bgcol) {
313 $tpl->setVariable("BGCOL", $bgcol->asHex());
314 }
315 $forecol = $component->getForegroundColor();
316 if ($forecol) {
317 $tpl->setVariable("FORECOL", $forecol->asHex());
318 }
319 }
320
321 protected function additionalRenderBulky(
322 Component\Button\Button $component,
323 RendererInterface $default_renderer,
324 Template $tpl
325 ): void {
326 $aria_role = $component->getAriaRole();
327 if ($aria_role != null) {
328 $tpl->setCurrentBlock("with_aria_role");
329 $tpl->setVariable("ARIA_ROLE", $aria_role);
330 $tpl->parseCurrentBlock();
331 }
332 if ($component->isEngageable()) {
333 if ($aria_role == Bulky::MENUITEM) {
334 $tpl->touchBlock("with_aria_haspopup");
335 } else {
336 //Note that aria-role='menuitems MUST-NOT have Aria-pressed to true;
337 $tpl->setCurrentBlock("with_aria_pressed");
338 if ($component->isEngaged()) {
339 $tpl->setVariable("ARIA_PRESSED", "true");
340 } else {
341 $tpl->setVariable("ARIA_PRESSED", "false");
342 }
343 $tpl->parseCurrentBlock();
344 }
345 }
346 }
347}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
additionalRenderBulky(Component\Button\Button $component, RendererInterface $default_renderer, Template $tpl)
Definition: Renderer.php:321
renderToggle(Component\Button\Toggle $component)
Definition: Renderer.php:197
render(Component\Component $component, RendererInterface $default_renderer)
Definition: Renderer.php:38
additionalRenderTag(Component\Button\Tag $component, Template $tpl)
Definition: Renderer.php:302
renderClose(Component\Button\Close $component)
Definition: Renderer.php:178
maybeRenderId(Component\JavaScriptBindable $component, Template $tpl)
Definition: Renderer.php:277
registerResources(ResourceRegistry $registry)
Announce resources this renderer requires.
Definition: Renderer.php:171
renderMonth(Component\Button\Month $component)
Definition: Renderer.php:287
renderButton(Component\Button\Button $component, RendererInterface $default_renderer)
Definition: Renderer.php:57
renderMinimize(Component\Button\Minimize $component)
Definition: Renderer.php:189
cannotHandleComponent(Component $component)
This method MUST be called by derived component renderers, if.
bindJavaScript(JavaScriptBindable $component)
Bind the component to JavaScript.
addTriggererOnLoadCode(Triggerer $triggerer)
Add onload-code for triggerer.
getTemplate(string $name, bool $purge_unfilled_vars, bool $purge_unused_blocks)
Get template of component this renderer is made for.
This class is supposed to unify rendering of tooltips over all components and should also be usable b...
Engageable Components have an "engaged" state and will be displayed accordingly.
Definition: Engageable.php:29
isEngageable()
Returns whether the button is stateful or not.
Interface for buttons with loading animation on click.
hasLoadingAnimationOnClick()
Return whether loading animation has been activated.
Interface to be extended by components that have the possibility to bind to Javascript.
This describes how an icon could be modified during construction of UI.
Definition: Icon.php:29
This describes a symbol.
Definition: Symbol.php:30
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
setVariable(string $name, $value)
Set a variable in the current block.
setCurrentBlock(string $name)
Set the block to work on.
touchBlock(string $name)
Touch a block without working further on it.
parseCurrentBlock()
Parse the block that is currently worked on.
An entity that renders components to a string output.
Definition: Renderer.php:31
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...
Definition: Bulky.php:21