ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
Renderer.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
22 
30 use ILIAS\Data\URI;
32 
34 {
38  public function render(Component\Component $component, RendererInterface $default_renderer): string
39  {
40  $this->checkComponent($component);
41  if ($component instanceof Component\Table\Presentation) {
42  return $this->renderPresentationTable($component, $default_renderer);
43  }
44  if ($component instanceof Component\Table\PresentationRow) {
45  return $this->renderPresentationRow($component, $default_renderer);
46  }
47  if ($component instanceof Component\Table\Ordering) {
48  return $this->renderOrderingTable($component, $default_renderer);
49  }
50  if ($component instanceof Component\Table\OrderingRow) {
51  return $this->renderOrderingRow($component, $default_renderer);
52  }
53  if ($component instanceof Component\Table\Data) {
54  return $this->renderDataTable($component, $default_renderer);
55  }
56  if ($component instanceof Component\Table\DataRow) {
57  return $this->renderDataRow($component, $default_renderer);
58  }
59  throw new \LogicException(self::class . " cannot render component '" . get_class($component) . "'.");
60  }
61 
62  protected function renderPresentationTable(
63  Component\Table\Presentation $component,
64  RendererInterface $default_renderer
65  ): string {
66  $tpl = $this->getTemplate("tpl.presentationtable.html", true, true);
67  $tpl->setVariable("TITLE", $component->getTitle());
68  $expcollapsebtns = [];
69  if ($sig_ta = $component->getExpandCollapseAllSignal()) {
70  $sig_ta_expand = clone $sig_ta;
71  $sig_ta_expand->addOption('expand', true);
72  $expcollapsebtns[] = $this->getUIFactory()->button()
73  ->standard($this->txt('presentation_table_expand'), '')
74  ->withOnClick($sig_ta_expand);
75  $sig_ta_collapse = clone $sig_ta;
76  $sig_ta_collapse->addOption('expand', false);
77  $expcollapsebtns[] = $this->getUIFactory()->button()
78  ->standard($this->txt('presentation_table_collapse'), '')
79  ->withOnClick($sig_ta_collapse);
80  $component = $component->withAdditionalOnLoadCode(
81  static fn($id) => "
82  il.UI.table.presentation.init('{$id}');
83  $(document).on('$sig_ta', function(event, signal_data) { il.UI.table.presentation.get('$id').expandAll(signal_data); return false; });
84  "
85  );
86  }
87 
88  $tpl->setVariable("EXPANDCOLLAPSEALL", $default_renderer->render($expcollapsebtns));
89 
90  $vcs = $component->getViewControls();
91  if ($vcs) {
92  $tpl->setVariable("VC", $default_renderer->render($vcs));
93  }
94 
95  $id = $this->bindJavaScript($component);
96  $tpl->setVariable("ID", $id);
97 
98  $row_mapping = $component->getRowMapping();
99  $data = $component->getData();
100  $component_id = $id;
101 
102  if (empty($data)) {
103  $this->renderEmptyPresentationRow($tpl, $default_renderer, $this->txt('ui_table_no_records'));
104  return $tpl->get();
105  }
106 
107  foreach ($data as $record) {
108  $row = $row_mapping(
109  new PresentationRow($component->getSignalGenerator(), $component_id),
110  $record,
111  $this->getUIFactory(),
112  $component->getEnvironment()
113  );
114 
115  $tpl->setCurrentBlock("row");
116  $tpl->setVariable("ROW", $default_renderer->render($row));
117  $tpl->parseCurrentBlock();
118  }
119 
120  return $tpl->get();
121  }
122 
123  protected function renderPresentationRow(
124  Component\Table\PresentationRow $component,
125  RendererInterface $default_renderer
126  ): string {
127  $f = $this->getUIFactory();
128  $tpl = $this->getTemplate("tpl.presentationrow.html", true, true);
129 
130  $component = $this->registerSignals($component->withResetSignals());
131  $sig_show = $component->getShowSignal();
132  $sig_hide = $component->getCloseSignal();
133  $sig_toggle = $component->getToggleSignal();
134  $id = $this->bindJavaScript($component);
135 
136  $expander = $f->symbol()->glyph()->expand("#")
137  ->withOnClick($sig_show);
138  $collapser = $f->symbol()->glyph()->collapse("#")
139  ->withOnClick($sig_hide);
140  $shy_expander = $f->button()->shy($this->txt("presentation_table_more"), "#")
141  ->withOnClick($sig_show);
142 
143  $tpl->setVariable("ID", $id);
144  $tpl->setVariable("EXPANDER", $default_renderer->render($expander));
145  $tpl->setVariable("COLLAPSER", $default_renderer->render($collapser));
146  $tpl->setVariable("SHY_EXPANDER", $default_renderer->render($shy_expander));
147 
148  if ($symbol = $component->getLeadingSymbol()) {
149  $tpl->setVariable("SYMBOL", $default_renderer->render($symbol));
150  }
151  $tpl->setVariable("HEADLINE", $component->getHeadline());
152  $tpl->setVariable("TOGGLE_SIGNAL", $sig_toggle);
153  $subheadline = $component->getSubheadline();
154  if ($subheadline) {
155  $tpl->setVariable("SUBHEADLINE", $subheadline);
156  }
157 
158  foreach ($component->getImportantFields() as $label => $value) {
159  $tpl->setCurrentBlock("important_field");
160  if (is_string($label)) {
161  $tpl->setVariable("IMPORTANT_FIELD_LABEL", $label);
162  }
163  $tpl->setVariable("IMPORTANT_FIELD_VALUE", $value);
164  $tpl->parseCurrentBlock();
165  }
166 
167  $tpl->setVariable("DESCLIST", $default_renderer->render($component->getContent()));
168 
169  $further_fields_headline = $component->getFurtherFieldsHeadline();
170  $further_fields = $component->getFurtherFields();
171 
172  if (count($further_fields) > 0) {
173  $tpl->touchBlock("has_further_fields");
174 
175  if ($further_fields_headline) {
176  $tpl->setVariable("FURTHER_FIELDS_HEADLINE", $further_fields_headline);
177  }
178 
179  foreach ($further_fields as $label => $value) {
180  $tpl->setCurrentBlock("further_field");
181  if (is_string($label)) {
182  $tpl->setVariable("FIELD_LABEL", $label);
183  }
184  $tpl->setVariable("FIELD_VALUE", $value);
185  $tpl->parseCurrentBlock();
186  }
187  }
188 
189  $action = $component->getAction();
190  if (!is_null($action)) {
191  $tpl->setCurrentBlock("button");
192  $tpl->setVariable("BUTTON", $default_renderer->render($action));
193  $tpl->parseCurrentBlock();
194  }
195 
196  return $tpl->get();
197  }
198 
199  public function renderDataTable(Component\Table\Data $component, RendererInterface $default_renderer): string
200  {
201  $tpl = $this->getTemplate("tpl.datatable.html", true, true);
202 
203  $opt_action_id = Action::OPT_ACTIONID;
204  $opt_row_id = Action::OPT_ROWID;
205  $component = $component
206  ->withAdditionalOnLoadCode(
207  static fn($id): string =>
208  "il.UI.table.data.init('{$id}','{$opt_action_id}','{$opt_row_id}');"
209  )
210  ->withAdditionalOnLoadCode($this->getAsyncActionHandler($component->getAsyncActionSignal()))
211  ->withAdditionalOnLoadCode($this->getMultiActionHandler($component->getMultiActionSignal()))
212  ->withAdditionalOnLoadCode($this->getSelectionHandler($component->getSelectionSignal()));
213 
214  $actions = [];
215  foreach ($component->getAllActions() as $action_id => $action) {
216  $component = $component->withAdditionalOnLoadCode($this->getActionRegistration((string) $action_id, $action));
217  if ($action->isAsync()) {
218  $signal = clone $component->getAsyncActionSignal();
219  $signal->addOption(Action::OPT_ACTIONID, $action_id);
220  $action = $action->withSignalTarget($signal);
221  }
222  $actions[$action_id] = $action;
223  }
224  $component = $component->withActions($actions);
225 
226  if ($component->hasMultiActions()) {
227  $component = $component->withAdditionalOnLoadCode(
228  static fn($id): string => "il.UI.table.data.get('{$id}').selectAll(false);"
229  );
230  }
231 
232  [$component, $view_controls] = $component->applyViewControls(
233  $component->getFilter() ?? [],
234  $component->getAdditionalParameters()
235  );
236 
237  $tpl->setVariable('VIEW_CONTROLS', $default_renderer->render($view_controls));
238 
239  $rows = $component->getDataRetrieval()->getRows(
240  $component->getRowBuilder(),
241  array_keys($component->getVisibleColumns()),
242  $component->getRange(),
243  $component->getOrder(),
244  $component->getFilter(),
245  $component->getAdditionalParameters()
246  );
247 
248  $id = $this->bindJavaScript($component);
249  $tpl->setVariable('ID', $id);
250  $tpl->setVariable('TITLE', $component->getTitle());
251  $tpl->setVariable('COL_COUNT', (string) $component->getColumnCount());
252 
253  $sortation_signal = null;
254  // if the generator is empty, and thus invalid, we render an empty row.
255  if (!$rows->valid()) {
256  $this->renderFullWidthDataCell($component, $tpl, $this->txt('ui_table_no_records'));
257  } else {
258  $this->appendTableRows($tpl, $rows, $default_renderer);
259 
260  if ($component->hasMultiActions()) {
261  $multi_actions = $component->getMultiActions();
262  $modal = $this->buildMultiActionsAllObjectsModal($multi_actions, $id);
263  $multi_actions_dropdown = $this->buildMultiActionsDropdown(
264  $multi_actions,
265  $component->getMultiActionSignal(),
266  $modal->getShowSignal()
267  );
268  $total_number_of_cols = count($component->getVisibleColumns()) + 2; // + selection column and action dropdown column
269  $tpl->setVariable('COLUMN_COUNT', (string) $total_number_of_cols);
270  $tpl->setVariable('MULTI_ACTION_TRIGGERER', $default_renderer->render($multi_actions_dropdown));
271  $tpl->setVariable('MULTI_ACTION_ALL_MODAL', $default_renderer->render($modal));
272  }
273 
274  $sortation_signal = null;
275  $sortation_view_control = array_filter(
276  $view_controls->getInputs(),
277  static fn($i): bool => $i instanceof Component\Input\ViewControl\Sortation
278  );
279  if ($sortation_view_control) {
280  $sortation_signal = array_shift($sortation_view_control)->getInternalSignal();
281  $sortation_signal->addOption('parent_container', $id);
282  }
283  }
284 
285  $this->renderTableHeader($default_renderer, $component, $tpl, $sortation_signal);
286  return $tpl->get();
287  }
288 
289  protected function renderTableHeader(
290  RendererInterface $default_renderer,
291  Component\Table\Data $component,
292  Template $tpl,
293  ?Component\Signal $sortation_signal
294  ): void {
295  $order = $component->getOrder();
296  $glyph_factory = $this->getUIFactory()->symbol()->glyph();
297  $sort_col = key($order->get());
298  $sort_direction = current($order->get());
299  $columns = $component->getVisibleColumns();
300 
301  foreach ($columns as $col_id => $col) {
302  $param_sort_direction = Order::ASC;
303  $col_title = $col->getTitle();
304  if ($col_id === $sort_col) {
305  if ($sort_direction === Order::ASC) {
306  $sortation = $this->txt('order_option_generic_ascending');
307  $sortation_glyph = $glyph_factory->sortAscending("#");
308  $param_sort_direction = Order::DESC;
309  }
310  if ($sort_direction === Order::DESC) {
311  $sortation = $this->txt('order_option_generic_descending');
312  $sortation_glyph = $glyph_factory->sortDescending("#");
313  }
314  }
315 
316  $tpl->setCurrentBlock('header_cell');
317  $tpl->setVariable('COL_INDEX', (string) $col->getIndex());
318 
319  if ($col->isSortable() && ! is_null($sortation_signal)) {
320  $sort_signal = clone $sortation_signal;
321  $sort_signal->addOption('value', "$col_id:$param_sort_direction");
322  $col_title = $default_renderer->render(
323  $this->getUIFactory()->button()->shy($col_title, $sort_signal)
324  );
325 
326  if ($col_id === $sort_col) {
327  $sortation_glyph = $default_renderer->render($sortation_glyph->withOnClick($sort_signal));
328  $tpl->setVariable('COL_SORTATION', $sortation);
329  $tpl->setVariable('COL_SORTATION_GLYPH', $sortation_glyph);
330  }
331  }
332 
333  $tpl->setVariable('COL_TITLE', $col_title);
334  $tpl->setVariable('COL_TYPE', strtolower($col->getType()));
335  $tpl->parseCurrentBlock();
336  }
337 
338  if ($component->hasSingleActions()) {
339  $tpl->setVariable('COL_INDEX_ACTION', (string) count($columns));
340  $tpl->setVariable('COL_TITLE_ACTION', $this->txt('actions'));
341 
342  }
343 
344  if ($component->hasMultiActions()) {
345  $signal = $component->getSelectionSignal();
346  $sig_all = clone $signal;
347  $sig_all->addOption('select', true);
348  $select_all = $glyph_factory->add()->withOnClick($sig_all);
349  $signal->addOption('select', false);
350  $select_none = $glyph_factory->close()->withOnClick($signal);
351  $tpl->setVariable('SELECTION_CONTROL_SELECT', $default_renderer->render($select_all));
352  $tpl->setVariable('SELECTION_CONTROL_DESELECT', $default_renderer->render($select_none));
353  }
354  }
355 
360  protected function renderFullWidthDataCell(Component\Table\Data $component, Template $tpl, string $content): void
361  {
362  $cell_tpl = $this->getTemplate('tpl.datacell.html', true, true);
363  $cell_tpl->setCurrentBlock('cell');
364  $cell_tpl->setVariable('CELL_CONTENT', $content);
365  $cell_tpl->setVariable('COL_SPAN', count($component->getVisibleColumns()));
366  $cell_tpl->setVariable('COL_TYPE', 'full-width');
367  $cell_tpl->setVariable('COL_INDEX', '1');
368  $cell_tpl->parseCurrentBlock();
369 
370  $tpl->setCurrentBlock('row');
371  $tpl->setVariable('ALTERNATION', 'even');
372  $tpl->setVariable('CELLS', $cell_tpl->get());
373  $tpl->parseCurrentBlock();
374  }
375 
376  protected function registerActions(Component\Table\Table $component): Component\Table\Table
377  {
378  $opt_action_id = Action::OPT_ACTIONID;
379  $opt_row_id = Action::OPT_ROWID;
380 
381  $component = $component
382  ->withAdditionalOnLoadCode(
383  static fn($id): string =>
384  "il.UI.table.data.init('{$id}','{$opt_action_id}','{$opt_row_id}');"
385  )
386  ->withAdditionalOnLoadCode($this->getAsyncActionHandler($component->getAsyncActionSignal()))
387  ->withAdditionalOnLoadCode($this->getMultiActionHandler($component->getMultiActionSignal()))
388  ->withAdditionalOnLoadCode($this->getSelectionHandler($component->getSelectionSignal()));
389 
390  $actions = [];
391  foreach ($component->getAllActions() as $action_id => $action) {
392  $component = $component->withAdditionalOnLoadCode($this->getActionRegistration((string) $action_id, $action));
393  if ($action->isAsync()) {
394  $signal = clone $component->getAsyncActionSignal();
395  $signal->addOption(Action::OPT_ACTIONID, $action_id);
396  $action = $action->withSignalTarget($signal);
397  }
398  $actions[$action_id] = $action;
399  }
400  $component = $component->withActions($actions);
401 
402  if ($component->hasMultiActions()) {
403  $component = $component->withAdditionalOnLoadCode(
404  static fn($id): string => "il.UI.table.data.get('{$id}').selectAll(false);"
405  );
406  }
407 
408  return $component;
409  }
410 
411  protected function renderActionsHeader(
412  RendererInterface $default_renderer,
413  Component\Table\Table $component,
414  Template $tpl
415  ): void {
416  if ($component->hasSingleActions()) {
417  $tpl->setVariable('COL_INDEX_ACTION', (string) count($component->getColumns()));
418  $tpl->setVariable('COL_TITLE_ACTION', $this->txt('actions'));
419  }
420 
421  if ($component->hasMultiActions()) {
422  $glyph_factory = $this->getUIFactory()->symbol()->glyph();
423  $signal = $component->getSelectionSignal();
424  $sig_all = clone $signal;
425  $sig_all->addOption('select', true);
426  $select_all = $glyph_factory->add()->withOnClick($sig_all);
427  $signal->addOption('select', false);
428  $select_none = $glyph_factory->close()->withOnClick($signal);
429  $tpl->setVariable('SELECTION_CONTROL_SELECT', $default_renderer->render($select_all));
430  $tpl->setVariable('SELECTION_CONTROL_DESELECT', $default_renderer->render($select_none));
431  }
432  }
433 
434  protected function appendTableRows(
435  Template $tpl,
436  \Generator|array $rows,
437  RendererInterface $default_renderer
438  ): void {
439  $alternate = 'even';
440  foreach ($rows as $row) {
441  $row_contents = $default_renderer->render($row);
442  $alternate = ($alternate === 'odd') ? 'even' : 'odd';
443  $tpl->setCurrentBlock('row');
444  $tpl->setVariable('ALTERNATION', $alternate);
445  $tpl->setVariable('CELLS', $row_contents);
446  $tpl->parseCurrentBlock();
447  }
448  }
449 
450  protected function renderEmptyPresentationRow(Template $tpl, RendererInterface $default_renderer, string $content): void
451  {
452  $row_tpl = $this->getTemplate('tpl.presentationrow_empty.html', true, true);
453  $row_tpl->setVariable('CONTENT', $content);
454  $tpl->setVariable('ROW', $row_tpl->get());
455  }
456 
461  array $actions,
462  string $table_id
463  ): \ILIAS\UI\Component\Modal\RoundTrip {
464  $f = $this->getUIFactory();
465 
466  $msg = $f->messageBox()->confirmation($this->txt('datatable_multiactionmodal_msg'));
467 
468  $select = $f->input()->field()->select(
469  $this->txt('datatable_multiactionmodal_actionlabel'),
470  array_map(
471  static fn($action): string => $action->getLabel(),
472  $actions
473  ),
474  ""
475  )->withRequired(true);
476  $submit = $f->button()->primary($this->txt('datatable_multiactionmodal_apply'), '')
477  ->withOnLoadCode(
478  static fn($id): string => "$('#{$id}').click(function() { il.UI.table.data.get('{$table_id}').doActionForAll(this); return false; });"
479  );
480  $modal = $f->modal()
481  ->roundtrip($this->txt('datatable_multiactionmodal_title'), [$msg, $select])
482  ->withActionButtons([$submit]);
483  return $modal;
484  }
485 
489  protected function buildMultiActionsDropdown(
490  array $actions,
491  Component\Signal $action_signal,
492  Component\Signal $modal_signal,
494  if ($actions === []) {
495  return null;
496  }
497  $f = $this->getUIFactory();
498  $glyph = $f->symbol()->glyph()->bulletlist();
499  $buttons = [];
500  $all_obj_buttons = [];
501  foreach ($actions as $action_id => $act) {
502  $signal = clone $action_signal;
503  $signal->addOption(Action::OPT_ACTIONID, $action_id);
504  $buttons[] = $f->button()->shy($act->getLabel(), $signal);
505  }
506 
507  $buttons[] = $f->divider()->horizontal();
508  $buttons[] = $f->button()->shy($this->txt('datatable_multiactionmodal_listentry'), '#')->withOnClick($modal_signal);
509 
510  return $f->dropdown()->standard($buttons)->withLabel($this->txt('datatable_multiaction_label'));
511  }
512 
513  protected function getAsyncActionHandler(Component\Signal $action_signal): \Closure
514  {
515  return static function ($id) use ($action_signal): string {
516  return "
517  $(document).on('{$action_signal}', function(event, signal_data) {
518  il.UI.table.data.get('{$id}').doSingleAction(signal_data);
519  return false;
520  });";
521  };
522  }
523  protected function getMultiActionHandler(Component\Signal $action_signal): \Closure
524  {
525  return static function ($id) use ($action_signal): string {
526  return "
527  $(document).on('{$action_signal}', function(event, signal_data) {
528  il.UI.table.data.get('{$id}').doMultiAction(signal_data);
529  return false;
530  });";
531  };
532  }
533 
534  protected function getSelectionHandler(Component\Signal $selection_signal): \Closure
535  {
536  return static function ($id) use ($selection_signal): string {
537  return "
538  $(document).on('{$selection_signal}', function(event, signal_data) {
539  il.UI.table.data.get('{$id}').selectAll(signal_data.options.select);
540  return false;
541  });
542  ";
543  };
544  }
545 
546  protected function getActionRegistration(
547  string $action_id,
548  Action $action
549  ): \Closure {
550  $async = $action->isAsync() ? 'true' : 'false';
551  $url_builder_js = $action->getURLBuilderJS();
552  $tokens_js = $action->getURLBuilderTokensJS();
553 
554  return static function ($id) use ($action_id, $async, $url_builder_js, $tokens_js): string {
555  return "
556  il.UI.table.data.get('{$id}').registerAction('{$action_id}', {$async}, {$url_builder_js}, {$tokens_js});
557  ";
558  };
559  }
560 
561  public function renderDataRow(Component\Table\DataRow $component, RendererInterface $default_renderer): string
562  {
563  $cell_tpl = $this->getTemplate("tpl.datacell.html", true, true);
564  $cols = $component->getColumns();
565 
566  foreach ($cols as $col_id => $column) {
567  if ($column->isHighlighted()) {
568  $cell_tpl->touchBlock('highlighted');
569  }
570  $cell_tpl->setCurrentBlock('cell');
571  $cell_tpl->setVariable('COL_TYPE', strtolower($column->getType()));
572  $cell_tpl->setVariable('COL_INDEX', $column->getIndex());
573  $cell_content = $component->getCellContent($col_id);
574  if ($cell_content instanceof Component\Component) {
575  $cell_content = $default_renderer->render($cell_content);
576  }
577  $cell_tpl->setVariable('CELL_CONTENT', $cell_content);
578  $cell_tpl->setVariable('CELL_COL_TITLE', $component->getColumns()[$col_id]->getTitle());
579  $cell_tpl->parseCurrentBlock();
580  }
581 
582  if ($component->tableHasMultiActions()) {
583  $cell_tpl->setVariable('ROW_ID', $component->getId());
584  }
585  if ($component->tableHasSingleActions()) {
586  $row_actions_dropdown = $this->getSingleActionsForRow(
587  $component->getId(),
588  $component->getActions()
589  );
590  $cell_tpl->setVariable('ACTION_CONTENT', $default_renderer->render($row_actions_dropdown));
591  }
592 
593  return $cell_tpl->get();
594  }
595 
596  public function renderOrderingRow(Component\Table\OrderingRow $component, RendererInterface $default_renderer): string
597  {
598  $cell_tpl = $this->getTemplate("tpl.orderingcell.html", true, true);
599  $this->fillCells($component, $cell_tpl, $default_renderer);
600 
601  if ($component->isOrderingDisabled()) {
602  return $cell_tpl->get();
603  }
604 
605  $namesource = new class () implements NameSource {
606  public function getNewName(): string
607  {
608  return '';
609  }
610  public function getNewDedicatedName(string $dedicated_name): string
611  {
612  return $dedicated_name;
613  }
614  };
615 
616  $input = $this->getUIFactory()->input()->field()->numeric('order')
617  ->withDedicatedName($component->getId())
618  ->withNameFrom($namesource)
619  ->withValue($component->getPosition() * 10);
620  $cell_tpl->setVariable('ORDER_INPUT', $default_renderer->render($input));
621 
622  return $cell_tpl->get();
623  }
624 
625  protected function fillCells(
626  Component\Table\DataRow $row,
627  Template $cell_tpl,
628  RendererInterface $default_renderer
629  ) {
630  $cols = $row->getColumns();
631  foreach ($cols as $col_id => $column) {
632  if ($column->isHighlighted()) {
633  $cell_tpl->touchBlock('highlighted');
634  }
635  $cell_tpl->setCurrentBlock('cell');
636  $cell_tpl->setVariable('COL_TYPE', strtolower($column->getType()));
637  $cell_tpl->setVariable('COL_INDEX', $column->getIndex());
638  $cell_content = $row->getCellContent($col_id);
639  if ($cell_content instanceof Component\Component) {
640  $cell_content = $default_renderer->render($cell_content);
641  }
642  $cell_tpl->setVariable('CELL_CONTENT', $cell_content);
643  $cell_tpl->setVariable('CELL_COL_TITLE', $row->getColumns()[$col_id]->getTitle());
644  $cell_tpl->parseCurrentBlock();
645  }
646 
647  if ($row->tableHasMultiActions()) {
648  $cell_tpl->setVariable('ROW_ID', $row->getId());
649  }
650  if ($row->tableHasSingleActions()) {
651  $row_actions_dropdown = $this->getSingleActionsForRow(
652  $row->getId(),
653  $row->getActions()
654  );
655  $cell_tpl->setVariable('ACTION_CONTENT', $default_renderer->render($row_actions_dropdown));
656  }
657  }
658 
662  protected function getSingleActionsForRow(string $row_id, array $actions): \ILIAS\UI\Component\Dropdown\Standard
663  {
664  $f = $this->getUIFactory();
665  $buttons = [];
666  foreach ($actions as $act) {
667  $act = $act->withRowId($row_id);
668  $target = $act->getTarget();
669  if ($target instanceof URI) {
670  $target = (string) $target;
671  }
672  $buttons[] = $f->button()->shy($act->getLabel(), $target);
673  }
674  return $f->dropdown()->standard($buttons);
675  }
676 
677  public function renderOrderingTable(Component\Table\Ordering $component, RendererInterface $default_renderer): string
678  {
679  $tpl = $this->getTemplate("tpl.orderingtable.html", true, true);
680  $component = $this->registerActions($component);
681 
682  [$component, $view_controls] = $component->applyViewControls();
683 
684  $rows = $component->getDataBinding()->getRows(
685  $component->getRowBuilder(),
686  array_keys($component->getVisibleColumns()),
687  );
688 
689 
690  if (!$component->isOrderingDisabled()) {
691  $component = $component->withAdditionalOnLoadCode(
692  static fn($id): string => "il.UI.table.ordering.init('{$id}');"
693  );
694  }
695 
696  $tableid = $this->bindJavaScript($component) ?? $this->createId();
697  $total_number_of_cols = count($component->getVisibleColumns());
698 
699  if (!$component->isOrderingDisabled()) {
700  $total_number_of_cols = $total_number_of_cols + 1;
701  $submit = $this->getUIFactory()->button()->standard($this->txt('sorting_save'), "")
702  ->withOnLoadCode(static fn($id) => "document.getElementById('$id').addEventListener('click',
703  function() {document.querySelector('#$tableid form.c-table-ordering__form').submit();return false;});");
704 
705  $tpl->setVariable('FORM_BUTTONS', $default_renderer->render($submit));
706  $tpl->setVariable('POS_INPUT_TITLE', $this->txt('table_posinput_col_title'));
707  }
708 
709  $tpl->setVariable('ID', $tableid);
710  $tpl->setVariable('TARGET_URL', $component->getTargetURL() ? $component->getTargetURL()->__toString() : '#');
711  $tpl->setVariable('TITLE', $component->getTitle());
712  $tpl->setVariable('COL_COUNT', (string) $component->getColumnCount());
713  $tpl->setVariable('VIEW_CONTROLS', $default_renderer->render($view_controls));
714 
715  $columns = $component->getVisibleColumns();
716  foreach ($columns as $col_id => $col) {
717  $col_title = $col->getTitle();
718  $tpl->setCurrentBlock('header_cell');
719  $tpl->setVariable('COL_INDEX', (string) $col->getIndex());
720  $tpl->setVariable('COL_TITLE', $col_title);
721  $tpl->setVariable('COL_TYPE', strtolower($col->getType()));
722  $tpl->parseCurrentBlock();
723  }
724 
725  $rows = iterator_to_array($rows);
726  $r = [];
727  foreach ($rows as $idx => $row) {
728  $r[] = $row
729  ->withPosition($idx + 1)
730  ->withOrderingDisabled($component->isOrderingDisabled());
731  }
732 
733  $this->renderActionsHeader($default_renderer, $component, $tpl);
734  $this->appendTableRows($tpl, $r, $default_renderer);
735 
736  if ($component->hasMultiActions()) {
737  $total_number_of_cols = $total_number_of_cols + 2;
738  $multi_actions = $component->getMultiActions();
739  $modal = $this->buildMultiActionsAllObjectsModal($multi_actions, $tableid);
740  $multi_actions_dropdown = $this->buildMultiActionsDropdown(
741  $multi_actions,
742  $component->getMultiActionSignal(),
743  $modal->getShowSignal()
744  );
745  $tpl->setVariable('MULTI_ACTION_TRIGGERER', $default_renderer->render($multi_actions_dropdown));
746  $tpl->setVariable('MULTI_ACTION_ALL_MODAL', $default_renderer->render($modal));
747  }
748 
749  $tpl->setVariable('COLUMN_COUNT', (string) $total_number_of_cols);
750  return $tpl->get();
751  }
752 
753 
757  public function registerResources(ResourceRegistry $registry): void
758  {
759  parent::registerResources($registry);
760  $registry->register('./src/UI/templates/js/Table/dist/table.min.js');
761  $registry->register('./src/UI/templates/js/Modal/modal.js');
762  }
763 
765  {
766  $show = $component->getShowSignal();
767  $close = $component->getCloseSignal();
768  $toggle = $component->getToggleSignal();
769  $table_id = $component->getTableId();
770  return $component->withAdditionalOnLoadCode(
771  static fn($id): string =>
772  "$(document).on('$show', function() { il.UI.table.presentation.get('$table_id').expandRow('$id'); return false; });" .
773  "$(document).on('$close', function() { il.UI.table.presentation.get('$table_id').collapseRow('$id'); return false; });" .
774  "$(document).on('$toggle', function() { il.UI.table.presentation.get('$table_id').toggleRow('$id'); return false; });"
775  );
776  }
777 
781  protected function getComponentInterfaceName(): array
782  {
783  return [
784  Component\Table\PresentationRow::class,
785  Component\Table\Presentation::class,
786  Component\Table\Data::class,
787  Component\Table\DataRow::class,
788  Component\Table\OrderingRow::class,
789  Component\Table\Ordering::class
790  ];
791  }
792 }
Registry for resources required by rendered output like Javascript or CSS.
button(string $caption, string $cmd)
checkComponent(Component $component)
Check if a given component fits this renderer and throw if that is not the case. ...
registerSignals(Component\Table\PresentationRow $component)
Definition: Renderer.php:764
renderPresentationTable(Component\Table\Presentation $component, RendererInterface $default_renderer)
Definition: Renderer.php:62
Class ChatMainBarProvider .
renderTableHeader(RendererInterface $default_renderer, Component\Table\Data $component, Template $tpl, ?Component\Signal $sortation_signal)
Definition: Renderer.php:289
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getActionRegistration(string $action_id, Action $action)
Definition: Renderer.php:546
txt(string $id)
Get a text from the language file.
registerResources(ResourceRegistry $registry)
Announce resources this renderer requires.
Definition: Renderer.php:757
setCurrentBlock(string $name)
Set the block to work on.
This describes commonalities between all types of Dropdowns.
Definition: Dropdown.php:34
buildMultiActionsAllObjectsModal(array $actions, string $table_id)
Definition: Renderer.php:460
setVariable(string $name, $value)
Set a variable in the current block.
render(Component\Component $component, RendererInterface $default_renderer)
Definition: Renderer.php:38
renderPresentationRow(Component\Table\PresentationRow $component, RendererInterface $default_renderer)
Definition: Renderer.php:123
getSingleActionsForRow(string $row_id, array $actions)
Definition: Renderer.php:662
getAsyncActionHandler(Component\Signal $action_signal)
Definition: Renderer.php:513
registerActions(Component\Table\Table $component)
Definition: Renderer.php:376
renderDataTable(Component\Table\Data $component, RendererInterface $default_renderer)
Definition: Renderer.php:199
renderFullWidthDataCell(Component\Table\Data $component, Template $tpl, string $content)
Renders a full-width cell with a single message within, indication there is no data to display...
Definition: Renderer.php:360
getTemplate(string $name, bool $purge_unfilled_vars, bool $purge_unused_blocks)
Get template of component this renderer is made for.
renderDataRow(Component\Table\DataRow $component, RendererInterface $default_renderer)
Definition: Renderer.php:561
The scope of this class is split ilias-conform URI&#39;s into components.
Definition: URI.php:18
fillCells(Component\Table\DataRow $row, Template $cell_tpl, RendererInterface $default_renderer)
Definition: Renderer.php:625
register(string $name)
Add a dependency.
getSelectionHandler(Component\Signal $selection_signal)
Definition: Renderer.php:534
renderOrderingTable(Component\Table\Ordering $component, RendererInterface $default_renderer)
Definition: Renderer.php:677
parseCurrentBlock()
Parse the block that is currently worked on.
appendTableRows(Template $tpl, \Generator|array $rows, RendererInterface $default_renderer)
Definition: Renderer.php:434
withNameFrom(NameSource $source, ?string $parent_name=null)
touchBlock(string $name)
Touch a block without working further on it.
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
Describes a source for input names.
Definition: NameSource.php:26
const DESC
Definition: Order.php:15
renderEmptyPresentationRow(Template $tpl, RendererInterface $default_renderer, string $content)
Definition: Renderer.php:450
getMultiActionHandler(Component\Signal $action_signal)
Definition: Renderer.php:523
renderActionsHeader(RendererInterface $default_renderer, Component\Table\Table $component, Template $tpl)
Definition: Renderer.php:411
renderOrderingRow(Component\Table\OrderingRow $component, RendererInterface $default_renderer)
Definition: Renderer.php:596
buildMultiActionsDropdown(array $actions, Component\Signal $action_signal, Component\Signal $modal_signal,)
Definition: Renderer.php:489
$r
bindJavaScript(JavaScriptBindable $component)
Bind the component to JavaScript.