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 
28 
30 {
34  public function render(Component\Component $component, RendererInterface $default_renderer): string
35  {
36  $this->checkComponent($component);
37 
38  if ($component instanceof Component\Button\Close) {
39  return $this->renderClose($component);
40  } elseif ($component instanceof Component\Button\Minimize) {
41  return $this->renderMinimize($component);
42  } elseif ($component instanceof Component\Button\Toggle) {
43  return $this->renderToggle($component);
44  } elseif ($component instanceof Component\Button\Month) {
45  return $this->renderMonth($component);
46  } else {
50  return $this->renderButton($component, $default_renderer);
51  }
52  }
53 
54  protected function renderButton(Component\Button\Button $component, RendererInterface $default_renderer): string
55  {
56  $tpl_name = "";
57  if ($component instanceof Component\Button\Primary) {
58  $tpl_name = "tpl.primary.html";
59  }
60  if ($component instanceof Component\Button\Standard) {
61  $tpl_name = "tpl.standard.html";
62  }
63  if ($component instanceof Component\Button\Shy) {
64  $tpl_name = "tpl.shy.html";
65  }
66  if ($component instanceof Component\Button\Tag) {
67  $tpl_name = "tpl.tag.html";
68  }
69  if ($component instanceof Component\Button\Bulky) {
70  $tpl_name = "tpl.bulky.html";
71  }
72 
73  $tpl = $this->getTemplate($tpl_name, true, true);
74 
75  $action = $component->getAction();
76  // The action is always put in the data-action attribute to have it available
77  // on the client side, even if it is not available on rendering.
78  if (is_string($action)) {
79  $tpl->setCurrentBlock("with_data_action");
80  $tpl->setVariable("ACTION", $action);
81  $tpl->parseCurrentBlock();
82  }
83 
84  $label = $component->getLabel();
85  if ($label !== null) {
86  $tpl->setVariable("LABEL", $component->getLabel());
87  }
88  if ($component->isActive()) {
89  // The actions might also be a list of signals, these will be appended by
90  // bindJavascript in maybeRenderId.
91  if (is_string($action) && $action != "") {
92  $component = $component->withAdditionalOnLoadCode(function ($id) use ($action) {
93  $action = str_replace("&amp;", "&", $action);
94 
95  return "$('#$id').on('click', function(event) {
96  window.location = '$action';
97  return false;
98  });";
99  });
100  }
101 
102  if ($component instanceof Component\Button\LoadingAnimationOnClick && $component->hasLoadingAnimationOnClick()) {
103  $component = $component->withAdditionalOnLoadCode(fn ($id) => "$('#$id').click(function(e) { il.UI.button.activateLoadingAnimation('$id')});");
104  }
105  } else {
106  $tpl->touchBlock("disabled");
107  }
108  $aria_label = $component->getAriaLabel();
109  if ($aria_label != null) {
110  $tpl->setCurrentBlock("with_aria_label");
111  $tpl->setVariable("ARIA_LABEL", $aria_label);
112  $tpl->parseCurrentBlock();
113  }
114 
115  if ($component instanceof Component\Button\Engageable
116  && $component->isEngageable()
117  ) {
118  if ($component->isEngaged()) {
119  $tpl->touchBlock("engaged");
120  $aria_pressed = 'true';
121  } else {
122  $aria_pressed = 'false';
123  }
124 
125  //Note that Bulky Buttons need to handle aria_pressed seperatly due to possible aria_role conflicts
126  if (!($component instanceof Bulky)) {
127  $tpl->setCurrentBlock("with_aria_pressed");
128  $tpl->setVariable("ARIA_PRESSED", $aria_pressed);
129  $tpl->parseCurrentBlock();
130  }
131  }
132 
133  $this->maybeRenderId($component, $tpl);
134 
135  if ($component instanceof Component\Button\Tag) {
136  $this->additionalRenderTag($component, $tpl);
137  }
138 
139  if ($component instanceof Component\Button\Bulky) {
140  $this->additionalRenderBulky($component, $default_renderer, $tpl);
141  }
142 
143  return $tpl->get();
144  }
145 
149  public function registerResources(ResourceRegistry $registry): void
150  {
151  parent::registerResources($registry);
152  $registry->register('./src/UI/templates/js/Button/button.js');
153  $registry->register("./node_modules/moment/min/moment-with-locales.min.js");
154  $registry->register("./node_modules/eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js");
155  }
156 
157  protected function renderClose(Component\Button\Close $component): string
158  {
159  $tpl = $this->getTemplate("tpl.close.html", true, true);
160  // This is required as the rendering seems to only create any output at all
161  // if any var was set or block was touched.
162  $tpl->setVariable("FORCE_RENDERING", "");
163  $tpl->setVariable("ARIA_LABEL", $this->txt("close"));
164  $this->maybeRenderId($component, $tpl);
165  return $tpl->get();
166  }
167 
168  protected function renderMinimize(Component\Button\Minimize $component): string
169  {
170  $tpl = $this->getTemplate("tpl.minimize.html", true, true);
171  $tpl->setVariable("ARIA_LABEL", $this->txt("minimize"));
172  $this->maybeRenderId($component, $tpl);
173  return $tpl->get();
174  }
175 
176  protected function renderToggle(Component\Button\Toggle $component): string
177  {
178  $tpl = $this->getTemplate("tpl.toggle.html", true, true);
179 
180  $on_action = $component->getActionOn();
181  $off_action = $component->getActionOff();
182 
183  $on_url = (is_string($on_action))
184  ? $on_action
185  : "";
186 
187  $off_url = (is_string($off_action))
188  ? $off_action
189  : "";
190 
191  $signals = [];
192 
193  foreach ($component->getTriggeredSignals() as $s) {
194  $signals[] = [
195  "signal_id" => $s->getSignal()->getId(),
196  "event" => $s->getEvent(),
197  "options" => $s->getSignal()->getOptions()
198  ];
199  }
200 
201  $signals = json_encode($signals);
202 
203  $button_status = 'off';
204  if ($component->isEngaged()) {
205  $button_status = 'on';
206  }
207 
208  if ($component->isActive()) {
209  $component = $component->withAdditionalOnLoadCode(fn ($id) => "$('#$id').on('click', function(event) {
210  il.UI.button.handleToggleClick(event, '$id', '$on_url', '$off_url', $signals);
211  return false; // stop event propagation
212  });");
213  $tpl->setCurrentBlock("with_on_off_label");
214  $tpl->setVariable("ON_LABEL", $this->txt("toggle_on"));
215  $tpl->setVariable("OFF_LABEL", $this->txt("toggle_off"));
216  $tpl->parseCurrentBlock();
217  } else {
218  $tpl->touchBlock("disabled");
219  $button_status = 'unavailable';
220  }
221 
222  $tpl->touchBlock($button_status);
223 
224  $label = $component->getLabel();
225  if (!empty($label)) {
226  $tpl->setCurrentBlock("with_label");
227  $tpl->setVariable("LABEL", $label);
228  $tpl->parseCurrentBlock();
229  }
230  $aria_label = $component->getAriaLabel();
231  if ($aria_label != null) {
232  $tpl->setCurrentBlock("with_aria_label");
233  $tpl->setVariable("ARIA_LABEL", $aria_label);
234  $tpl->parseCurrentBlock();
235  }
236  $this->maybeRenderId($component, $tpl);
237  return $tpl->get();
238  }
239 
240  protected function maybeRenderId(Component\JavaScriptBindable $component, Template $tpl): void
241  {
242  $id = $this->bindJavaScript($component);
243  if ($id !== null) {
244  $tpl->setCurrentBlock("with_id");
245  $tpl->setVariable("ID", $id);
246  $tpl->parseCurrentBlock();
247  }
248  }
249 
250  protected function renderMonth(Component\Button\Month $component): string
251  {
252  $def = $component->getDefault();
253 
254  for ($i = 1; $i <= 12; $i++) {
255  $this->toJS(array("month_" . str_pad((string) $i, 2, "0", STR_PAD_LEFT) . "_short"));
256  }
257 
258  $tpl = $this->getTemplate("tpl.month.html", true, true);
259 
260  $month = explode("-", $def);
261  $tpl->setVariable("DEFAULT_LABEL", $this->txt("month_" . str_pad($month[0], 2, "0", STR_PAD_LEFT) . "_short") . " " . $month[1]);
262  $tpl->setVariable("DEF_DATE", $month[0] . "/1/" . $month[1]);
263  // see https://github.com/moment/moment/tree/develop/locale
264  $lang_key = in_array($this->getLangKey(), array("ar", "bg", "cs", "da", "de", "el", "en", "es", "et", "fa", "fr", "hu", "it",
265  "ja", "ka", "lt", "nl", "pl", "pt", "ro", "ru", "sk", "sq", "sr", "tr", "uk", "vi", "zh"))
266  ? $this->getLangKey()
267  : "en";
268  if ($lang_key == "zh") {
269  $lang_key = "zh-cn";
270  }
271  $tpl->setVariable("LANG", $lang_key);
272 
273  $component = $component->withAdditionalOnLoadCode(fn ($id) => "il.UI.button.initMonth('$id');");
274  $id = $this->bindJavaScript($component);
275 
276  $tpl->setVariable("ID", $id);
277 
278  return $tpl->get();
279  }
280 
281  protected function additionalRenderTag(Component\Button\Tag $component, Template $tpl): void
282  {
283  $tpl->touchBlock('rel_' . $component->getRelevance());
284 
285  $classes = trim(join(' ', $component->getClasses()));
286  if ($classes !== '') {
287  $tpl->setVariable("CLASSES", $classes);
288  }
289 
290  $bgcol = $component->getBackgroundColor();
291  if ($bgcol) {
292  $tpl->setVariable("BGCOL", $bgcol->asHex());
293  }
294  $forecol = $component->getForegroundColor();
295  if ($forecol) {
296  $tpl->setVariable("FORECOL", $forecol->asHex());
297  }
298  }
299 
300  protected function additionalRenderBulky(
301  Component\Button\Button $component,
302  RendererInterface $default_renderer,
303  Template $tpl
304  ): void {
305  $renderer = $default_renderer->withAdditionalContext($component);
306  $tpl->setVariable("ICON_OR_GLYPH", $renderer->render($component->getIconOrGlyph()));
307  $label = $component->getLabel();
308  if ($label !== null) {
309  $tpl->setVariable("LABEL", $label);
310  }
311 
312  $aria_role = $component->getAriaRole();
313  if ($aria_role != null) {
314  $tpl->setCurrentBlock("with_aria_role");
315  $tpl->setVariable("ARIA_ROLE", $aria_role);
316  $tpl->parseCurrentBlock();
317  }
318  if ($component->isEngageable()) {
319  if ($aria_role == Bulky::MENUITEM) {
320  $tpl->touchBlock("with_aria_haspopup");
321  } else {
322  //Note that aria-role='menuitems MUST-NOT have Aria-pressed to true;
323  $tpl->setCurrentBlock("with_aria_pressed");
324  if ($component->isEngaged()) {
325  $tpl->setVariable("ARIA_PRESSED", "true");
326  } else {
327  $tpl->setVariable("ARIA_PRESSED", "false");
328  }
329  $tpl->parseCurrentBlock();
330  }
331  }
332  }
333 
337  protected function getComponentInterfaceName(): array
338  {
339  return array(Component\Button\Primary::class
340  , Component\Button\Standard::class
341  , Component\Button\Close::class
342  , Component\Button\Minimize::class
343  , Component\Button\Shy::class
344  , Component\Button\Month::class
345  , Component\Button\Tag::class
346  , Component\Button\Bulky::class
347  , Component\Button\Toggle::class
348  );
349  }
350 }
Registry for resources required by rendered output like Javascript or CSS.
checkComponent(Component $component)
Check if a given component fits this renderer and throw if that is not the case. ...
renderMinimize(Component\Button\Minimize $component)
Definition: Renderer.php:168
renderMonth(Component\Button\Month $component)
Definition: Renderer.php:250
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.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Definition: Bulky.php:21
toJS($key)
Add language var to client side (il.Language)
setCurrentBlock(string $name)
Set the block to work on.
setVariable(string $name, $value)
Set a variable in the current block.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Definition: Bulky.php:21
registerResources(ResourceRegistry $registry)
Announce resources this renderer requires.
Definition: Renderer.php:149
getTemplate(string $name, bool $purge_unfilled_vars, bool $purge_unused_blocks)
Get template of component this renderer is made for.
renderToggle(Component\Button\Toggle $component)
Definition: Renderer.php:176
additionalRenderTag(Component\Button\Tag $component, Template $tpl)
Definition: Renderer.php:281
renderButton(Component\Button\Button $component, RendererInterface $default_renderer)
Definition: Renderer.php:54
register(string $name)
Add a dependency.
renderClose(Component\Button\Close $component)
Definition: Renderer.php:157
parseCurrentBlock()
Parse the block that is currently worked on.
render(Component $component, Renderer $default_renderer)
Render the component if possible and delegate additional rendering to the default_renderer.
touchBlock(string $name)
Touch a block without working further on it.
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
additionalRenderBulky(Component\Button\Button $component, RendererInterface $default_renderer, Template $tpl)
Definition: Renderer.php:300
maybeRenderId(Component\JavaScriptBindable $component, Template $tpl)
Definition: Renderer.php:240
if($DIC->http() ->request() ->getMethod()=="GET" &&isset($DIC->http() ->request() ->getQueryParams()['tex'])) $tpl
Definition: latex.php:41
$i
Definition: metadata.php:41
bindJavaScript(JavaScriptBindable $component)
Bind the component to JavaScript.