19declare(strict_types=1);
41use ILIAS\UI\Implementation\Component\ComponentHelper;
103 case ($component instanceof
F\
Section):
109 case ($component instanceof
F\
Link):
112 case ($component instanceof
F\
Group):
113 return $default_renderer->render($component->getInputs());
115 case ($component instanceof
F\
Text):
118 case ($component instanceof
F\
Numeric):
124 case ($component instanceof
F\
Tag):
130 case ($component instanceof
F\
Select):
134 return $this->renderMarkdownField($component, $default_renderer);
137 return $this->renderTextareaField($component, $default_renderer);
139 case ($component instanceof
F\
Radio):
148 case ($component instanceof
F\
Image):
151 case ($component instanceof
F\
File):
154 case ($component instanceof
F\
Url):
157 case ($component instanceof
F\
Hidden):
163 case ($component instanceof
F\
Rating):
181 ?
string $id_for_label =
null,
182 ?
string $dependant_group_html =
null
186 $tpl->setVariable(
"LABEL", $label);
187 $tpl->setVariable(
"INPUT", $input_html);
189 $tpl->setVariable(
"INPUT_NAME", $component->getName());
193 $tpl->setVariable(
"BINDING_ID", $binding_id);
197 $tpl->setCurrentBlock(
'for');
198 $tpl->setVariable(
"ID", $id_for_label);
199 $tpl->parseCurrentBlock();
201 $tpl->touchBlock(
'tabindex');
206 $tpl->setVariable(
"BYLINE", $byline);
211 $tpl->setCurrentBlock(
'required');
212 $tpl->setVariable(
"REQUIRED_ARIA", $this->
txt(
'required_field'));
213 $tpl->parseCurrentBlock();
217 $tpl->touchBlock(
"disabled");
220 $error = $component->getError();
223 $tpl->setVariable(
"ERROR_LABEL", $this->
txt(
"ui_error"));
224 $tpl->setVariable(
"ERROR_ID", $error_id);
225 $tpl->setVariable(
"ERROR",
$error);
227 $tpl->setVariable(
"ERROR_FOR_ID", $id_for_label);
231 if ($dependant_group_html) {
232 $tpl->setVariable(
"DEPENDANT_GROUP", $dependant_group_html);
239 $name = $component->getName();
246 $id = $this->bindJavaScript($component) ?? $this->createId();
262 if (!is_null($escape)) {
263 $value = $escape($value);
265 if (isset($value) && $value !==
'') {
272 return function ($v) {
276 return htmlspecialchars((
string) $v, ENT_QUOTES,
'utf-8',
false);
282 return function ($v) {
286 return htmlentities((
string) $v, ENT_QUOTES,
'utf-8',
false);
292 $input_html = $default_renderer->render($component->getInputs());
293 return $this->wrapInFormContext(
295 $component->getLabel(),
302 $tpl = $this->getTemplate(
"tpl.text.html",
true,
true);
303 $this->applyName($component, $tpl);
305 if ($component->getMaxLength()) {
306 $tpl->setVariable(
"MAX_LENGTH", $component->getMaxLength());
309 $this->applyValue($component, $tpl, $this->escapeSpecialChars());
311 $label_id = $this->createId();
312 $tpl->setVariable(
'ID', $label_id);
313 return $this->wrapInFormContext($component, $component->getLabel(), $tpl->get(), $label_id);
318 $tpl = $this->getTemplate(
"tpl.numeric.html",
true,
true);
319 $this->applyName($component, $tpl);
320 $this->applyValue($component, $tpl, $this->escapeSpecialChars());
322 $tpl->setVariable(
"STEPSIZE", $component->getStepSize());
324 $label_id = $this->createId();
325 $tpl->setVariable(
'ID', $label_id);
326 return $this->wrapInFormContext($component, $component->getLabel(), $tpl->get(), $label_id);
331 $tpl = $this->getTemplate(
"tpl.checkbox.html",
true,
true);
332 $this->applyName($component, $tpl);
334 if ($component->getValue()) {
335 $tpl->touchBlock(
"value");
338 $label_id = $this->createId();
339 $tpl->setVariable(
'ID', $label_id);
340 return $this->wrapInFormContext($component, $component->getLabel(), $tpl->get(), $label_id);
345 $tpl = $this->getTemplate(
"tpl.optionalgroup_label.html",
true,
true);
346 $tpl->setVariable(
'LABEL', $component->getLabel());
347 $tpl->setVariable(
"NAME", $component->getName());
348 if ($component->getValue()) {
349 $tpl->setVariable(
"CHECKED",
'checked="checked"');
352 $label_id = $this->createId();
353 $tpl->setVariable(
'ID', $label_id);
355 $label = $tpl->get();
356 $input_html = $default_renderer->render($component->getInputs());
358 return $this->wrapInFormContext($component, $label, $input_html, $label_id);
364 if ($component->getValue() !==
null) {
365 list($value, ) = $component->getValue();
369 foreach ($component->getInputs() as $key => $group) {
370 $tpl = $this->getTemplate(
"tpl.switchablegroup_label.html",
true,
true);
371 $tpl->setVariable(
'LABEL', $group->getLabel());
372 $tpl->setVariable(
"NAME", $component->getName());
373 $tpl->setVariable(
"VALUE", $key);
375 $label_id = $this->createId();
376 $tpl->setVariable(
'ID', $label_id);
378 if ($key == $value) {
379 $tpl->setVariable(
"CHECKED",
'checked="checked"');
382 $input_html .= $this->wrapInFormContext(
385 $default_renderer->render($group),
391 return $this->wrapInFormContext(
393 $component->getLabel(),
400 $tpl = $this->getTemplate(
"tpl.tag_input.html",
true,
true);
401 $this->applyName($component, $tpl);
403 $configuration = $component->getConfiguration();
404 $value = $component->getValue();
409 return [
'value' => rawurlencode($v),
'display' => $v];
415 $autocomplete_endpoint =
'undefined';
416 $autocomplete_token =
'undefined';
417 if ($component->getAsyncAutocompleteEndpoint() !==
null) {
418 $autocomplete_endpoint = $component->getAsyncAutocompleteEndpoint()
419 ->renderObject([$component->getAsyncAutocompleteToken()]);
420 $autocomplete_token = $component->getAsyncAutocompleteToken()->render();
423 $component = $component->withAdditionalOnLoadCode(
424 function (
$id) use ($configuration, $value, $autocomplete_endpoint, $autocomplete_token) {
425 $encoded = json_encode($configuration);
426 $value = json_encode($value);
427 return 'il.UI.Input.tagInput.init(document.querySelector('
428 .
"'#{$id} .c-field-tag'), {$encoded}, {$value},"
429 .
" {$autocomplete_endpoint}, "
430 .
" {$autocomplete_token}"
435 if ($component->isDisabled()) {
436 $tpl->setVariable(
"DISABLED",
"disabled");
437 $tpl->setVariable(
"READONLY",
"readonly");
440 $label_id = $this->createId();
441 $tpl->setVariable(
'ID', $label_id);
442 return $this->wrapInFormContext($component, $component->getLabel(), $tpl->get(), $label_id);
447 $tpl = $this->getTemplate(
"tpl.password.html",
true,
true);
448 $this->applyName($component, $tpl);
450 if ($component->getRevelation()) {
451 $component = $component->withResetSignals();
452 $sig_reveal = $component->getRevealSignal();
453 $sig_mask = $component->getMaskSignal();
454 $component = $component->withAdditionalOnLoadCode(
function (
$id) use ($sig_reveal, $sig_mask) {
456 "$(document).on('$sig_reveal', function() {
457 const fieldContainer = document.querySelector('#$id .c-input__field .c-field-password');
458 fieldContainer.classList.add('revealed');
459 fieldContainer.getElementsByTagName('input').item(0).type='text';
461 "$(document).on('$sig_mask', function() {
462 const fieldContainer = document.querySelector('#$id .c-input__field .c-field-password');
463 fieldContainer.classList.remove('revealed');
464 fieldContainer.getElementsByTagName('input').item(0).type='password';
468 $f = $this->getUIFactory();
469 $glyph_reveal =
$f->symbol()->glyph()->eyeopen(
"#")
470 ->withOnClick($sig_reveal);
471 $glyph_mask =
$f->symbol()->glyph()->eyeclosed(
"#")
472 ->withOnClick($sig_mask);
474 $tpl->setVariable(
'PASSWORD_REVEAL', $default_renderer->render($glyph_reveal));
475 $tpl->setVariable(
'PASSWORD_MASK', $default_renderer->render($glyph_mask));
478 $this->applyValue($component, $tpl, $this->escapeSpecialChars());
480 $label_id = $this->createId();
481 $tpl->setVariable(
'ID', $label_id);
482 return $this->wrapInFormContext($component, $component->getLabel(), $tpl->get(), $label_id);
487 $tpl = $this->getTemplate(
"tpl.select.html",
true,
true);
488 $this->applyName($component, $tpl);
490 $value = $component->getValue();
492 $tpl->setCurrentBlock(
"options");
494 $tpl->setVariable(
"SELECTED",
'selected="selected"');
496 if ($component->isRequired() && !$value) {
497 $tpl->setVariable(
"DISABLED_OPTION",
"disabled");
498 $tpl->setVariable(
"HIDDEN",
"hidden");
501 if (!($value && $component->isRequired())) {
502 $tpl->setVariable(
"VALUE",
null);
503 $tpl->setVariable(
"VALUE_STR", $component->isRequired() ? $this->txt(
'ui_select_dropdown_label') :
'-');
504 $tpl->parseCurrentBlock();
507 foreach ($component->getOptions() as $option_key => $option_value) {
508 $tpl->setCurrentBlock(
"options");
509 if ($value == $option_key) {
510 $tpl->setVariable(
"SELECTED",
'selected="selected"');
512 $tpl->setVariable(
"VALUE", $option_key);
513 $tpl->setVariable(
"VALUE_STR", $option_value);
514 $tpl->parseCurrentBlock();
517 $label_id = $this->createId();
518 $tpl->setVariable(
'ID', $label_id);
519 return $this->wrapInFormContext($component, $component->getLabel(), $tpl->get(), $label_id);
522 protected function renderMarkdownField(
F\
Markdown $component, RendererInterface $default_renderer): string
524 [$textarea_tpl, $component] = $this->getPreparedTextareaTemplate($component);
527 $component = $component->withAdditionalOnLoadCode(
528 static function (
$id) use ($component):
string {
530 il.UI.Input.markdown.init(
531 document.querySelector('#$id .c-input__field textarea')?.id,
532 '{$component->getMarkdownRenderer()->getAsyncUrl()}',
533 '{$component->getMarkdownRenderer()->getParameterName()}'
539 $textarea_id = $this->createId();
540 $textarea_tpl->setVariable(
'ID', $textarea_id);
542 $markdown_tpl = $this->getTemplate(
"tpl.markdown.html",
true,
true);
543 $markdown_tpl->setVariable(
'TEXTAREA', $textarea_tpl->get());
545 $markdown_tpl->setVariable(
547 $component->getMarkdownRenderer()->render(
548 $this->htmlEntities()($component->getValue() ??
'')
552 $markdown_tpl->setVariable(
554 $default_renderer->render(
555 $this->getUIFactory()->viewControl()->mode([
556 $this->txt(
'ui_md_input_edit') =>
'#',
557 $this->txt(
'ui_md_input_view') =>
'#',
563 $markdown_actions_glyphs = [
564 'ACTION_HEADING' => $this->getUIFactory()->symbol()->glyph()->header(),
565 'ACTION_LINK' => $this->getUIFactory()->symbol()->glyph()->link(),
566 'ACTION_BOLD' => $this->getUIFactory()->symbol()->glyph()->bold(),
567 'ACTION_ITALIC' => $this->getUIFactory()->symbol()->glyph()->italic(),
568 'ACTION_ORDERED_LIST' => $this->getUIFactory()->symbol()->glyph()->numberedlist(),
569 'ACTION_UNORDERED_LIST' => $this->getUIFactory()->symbol()->glyph()->bulletlist()
572 foreach ($markdown_actions_glyphs as $tpl_variable => $glyph) {
573 if ($component->isDisabled()) {
574 $glyph = $glyph->withUnavailableAction();
577 $action = $this->getUIFactory()->button()->standard(
'',
'#')->withSymbol($glyph);
579 if ($component->isDisabled()) {
580 $action = $action->withUnavailableAction();
583 $markdown_tpl->setVariable($tpl_variable, $default_renderer->render($action));
586 return $this->wrapInFormContext($component, $component->getLabel(), $markdown_tpl->get());
589 protected function renderTextareaField(
F\Textarea $component, RendererInterface $default_renderer): string
591 [$tpl, $component] = $this->getPreparedTextareaTemplate($component);
594 $component = $component->withAdditionalOnLoadCode(
595 static fn(
$id) =>
"il.UI.Input.textarea.init(document.querySelector('#$id .c-input__field textarea')?.id);",
598 $label_id = $this->createId();
599 $tpl->setVariable(
'ID', $label_id);
600 return $this->wrapInFormContext($component, $component->getLabel(), $tpl->get(), $label_id);
608 $tpl = $this->getTemplate(
"tpl.textarea.html",
true,
true);
610 if (0 < $component->getMaxLimit()) {
611 $tpl->setVariable(
'REMAINDER_TEXT', $this->txt(
'ui_chars_remaining'));
612 $tpl->setVariable(
'REMAINDER', $component->getMaxLimit() - strlen($component->getValue() ??
''));
613 $tpl->setVariable(
'MAX_LIMIT', $component->getMaxLimit());
616 if (
null !== $component->getMinLimit()) {
617 $tpl->setVariable(
'MIN_LIMIT', $component->getMinLimit());
620 [$mustache_variable_html, $component] = $this->renderMustacheVariables($component);
621 $tpl->setVariable(
'MUSTACHE_VARIABLES_HTML', $mustache_variable_html);
623 $this->applyName($component, $tpl);
627 $this->mustacheVariableEntities()
629 return [$tpl, $component];
639 return [
'', $component];
642 $template = $this->getTemplate(
'tpl.mustache_variables.html',
true,
true);
643 $template->setVariable(
'MUSTACHE_VARIABLE_USAGE_INFO', $this->txt(
'ui_mustache_variables_usage_info'));
651 $template->setCurrentBlock(
'with_mustache_variable_definition');
652 $template->setVariable(
'VARIABLE_NAME', $variable_name);
653 $template->setVariable(
'VARIABLE_DESCRIPTION', $description);
654 $template->parseCurrentBlock();
658 $enriched_component = $component->withAdditionalOnLoadCode(
static fn(
$id) =>
"
659 il.UI.Input.mustacheVariables.init(
660 il.UI.Input.textarea.get(document.querySelector('#$id .c-input__field textarea')?.id) ??
661 il.UI.Input.markdown.get(document.querySelector('#$id .c-input__field textarea')?.id),
662 document.getElementById('$id'),
666 return [$template->get(), $enriched_component];
671 $tpl = $this->getTemplate(
"tpl.radio.html",
true,
true);
672 $id = $this->createId();
674 foreach ($component->getOptions() as $value => $label) {
676 if ($component->hasOptionFilter()) {
677 $tpl->touchBlock(
'is_filter_option');
680 $opt_id =
$id .
'_' . $value .
'_opt';
682 $tpl->setCurrentBlock(
'optionblock');
683 $tpl->setVariable(
"NAME", $component->getName());
684 $tpl->setVariable(
"OPTIONID", $opt_id);
685 $tpl->setVariable(
"VALUE", $value);
686 $tpl->setVariable(
"LABEL", $label);
688 if ($component->getValue() !==
null && $component->getValue() == $value) {
689 $tpl->setVariable(
"CHECKED",
'checked="checked"');
691 if ($component->isDisabled()) {
692 $tpl->setVariable(
"DISABLED",
'disabled="disabled"');
695 $byline = $component->getBylineFor((
string) $value);
696 if (!empty($byline)) {
697 $tpl->setVariable(
"BYLINE", $byline);
700 $tpl->parseCurrentBlock();
703 if ($component->hasOptionFilter()) {
705 $tpl->touchBlock(
"has_option_filter");
706 $field_html = $tpl->get();
707 [$field_html, $component] = $this->renderOptionFilter($field_html, $component, $default_renderer);
709 $field_html = $tpl->get();
712 return $this->wrapInFormContext($component, $component->getLabel(), $field_html);
717 $tpl = $this->getTemplate(
"tpl.multiselect.html",
true,
true);
719 $options = $component->getOptions();
721 $value = $component->getValue();
722 $name = $this->applyName($component, $tpl);
723 foreach (
$options as $opt_value => $opt_label) {
725 if ($component->hasOptionFilter()) {
726 $tpl->touchBlock(
'is_filter_option');
729 $tpl->setCurrentBlock(
"option");
730 $tpl->setVariable(
"NAME", $name);
731 $tpl->setVariable(
"VALUE", $opt_value);
732 $tpl->setVariable(
"LABEL", $opt_label);
734 if ($value && in_array($opt_value, $value)) {
735 $tpl->setVariable(
"CHECKED",
'checked="checked"');
738 $tpl->parseCurrentBlock();
741 $tpl->touchBlock(
"no_options");
744 if ($component->hasOptionFilter()) {
746 $tpl->touchBlock(
"has_option_filter");
747 $field_html = $tpl->get();
748 [$field_html, $component] = $this->renderOptionFilter($field_html, $component, $default_renderer);
750 $field_html = $tpl->get();
753 return $this->wrapInFormContext($component, $component->getLabel(), $field_html);
758 list($component, $tpl) = $this->internalRenderDateTimeField($component, $default_renderer);
759 $label_id = $this->createId();
760 $tpl->setVariable(
'ID', $label_id);
761 return $this->wrapInFormContext($component, $component->getLabel(), $tpl->get(), $label_id);
769 $tpl = $this->getTemplate(
"tpl.datetime.html",
true,
true);
770 $this->applyName($component, $tpl);
772 if ($component->getTimeOnly() ===
true) {
773 $format = $component::TIME_FORMAT;
774 $dt_type = self::TYPE_TIME;
776 $dt_type = self::TYPE_DATE;
777 $format = $this->getTransformedDateFormat(
778 $component->getFormat(),
779 self::DATEPICKER_FORMAT_MAPPING
782 if ($component->getUseTime() ===
true) {
783 $format .=
' ' . $component::TIME_FORMAT;
784 $dt_type = self::TYPE_DATETIME;
788 $tpl->setVariable(
"DTTYPE", $dt_type);
790 $min_max_format = self::DATE_DATEPICKER_MINMAX_FORMAT;
791 if ($dt_type === self::TYPE_DATETIME) {
792 $min_max_format = self::DATETIME_DATEPICKER_MINMAX_FORMAT;
795 $min_date = $component->getMinValue();
796 if (!is_null($min_date)) {
797 $tpl->setVariable(
"MIN_DATE", date_format($min_date, $min_max_format));
799 $max_date = $component->getMaxValue();
800 if (!is_null($max_date)) {
801 $tpl->setVariable(
"MAX_DATE", date_format($max_date, $min_max_format));
804 $this->applyValue($component, $tpl,
function (?
string $value) use ($dt_type) {
805 if ($value !==
null) {
806 $value = new \DateTimeImmutable($value);
807 return $value->format(match ($dt_type) {
808 self::TYPE_DATETIME => self::HTML5_NATIVE_DATETIME_FORMAT,
809 self::TYPE_DATE => self::HTML5_NATIVE_DATE_FORMAT,
810 self::TYPE_TIME => self::HTML5_NATIVE_TIME_FORMAT,
815 return [$component, $tpl];
820 $inputs = $component->getInputs();
823 list($input, $tpl) = $this->internalRenderDateTimeField($input, $default_renderer);
825 $from_input_id = $this->createId();
826 $tpl->setVariable(
'ID', $from_input_id);
827 $input_html = $this->wrapInFormContext($input, $input->getLabel(), $tpl->get(), $from_input_id);
830 ->withAdditionalPickerconfig([
'useCurrent' =>
false]);
831 list($input, $tpl) = $this->internalRenderDateTimeField($input, $default_renderer);
832 $until_input_id = $this->createId();
833 $tpl->setVariable(
'ID', $until_input_id);
834 $input_html .= $this->wrapInFormContext($input, $input->getLabel(), $tpl->get(), $until_input_id);
836 $tpl = $this->getTemplate(
"tpl.duration.html",
true,
true);
837 $tpl->setVariable(
'DURATION', $input_html);
838 return $this->wrapInFormContext($component, $component->getLabel(), $tpl->get());
843 $inputs_html = $default_renderer->render($section->getInputs());
845 $headline_tpl = $this->getTemplate(
"tpl.headlines.html",
true,
true);
846 $headline_tpl->setVariable(
"HEADLINE", $section->getLabel());
847 $nesting_level = $section->getNestingLevel() + 2;
848 if ($nesting_level > 6) {
851 $headline_tpl->setVariable(
"LEVEL", $nesting_level);
853 $headline_html = $headline_tpl->get();
855 return $this->wrapInFormContext($section, $headline_html, $inputs_html);
860 $tpl = $this->getTemplate(
"tpl.url.html",
true,
true);
861 $this->applyName($component, $tpl);
862 $this->applyValue($component, $tpl, $this->escapeSpecialChars());
864 $label_id = $this->createId();
865 $tpl->setVariable(
'ID', $label_id);
866 return $this->wrapInFormContext($component, $component->getLabel(), $tpl->get(), $label_id);
871 return $this->renderFileField($input, $default_renderer);
876 $template = $this->getTemplate(
'tpl.file.html',
true,
true);
877 foreach ($input->getGeneratedDynamicInputs() as $metadata_input) {
879 if (
null !== (
$data = $metadata_input->getValue())) {
880 $file_id = (!$input->hasMetadataInputs()) ?
$data :
$data[0] ??
null;
882 if (
null !== $file_id) {
883 $file_info = $input->getUploadHandler()->getInfoResult($file_id);
887 $template = $this->renderFilePreview(
896 $file_preview_template = $this->getTemplate(
'tpl.file.html',
true,
true);
897 $file_preview_template = $this->renderFilePreview(
899 $input->getTemplateForDynamicInputs(),
902 $file_preview_template
905 $template->setVariable(
'FILE_PREVIEW_TEMPLATE', $file_preview_template->get(
'block_file_preview'));
907 $this->setHelpBlockForFileField($template, $input);
909 $input = $this->initClientsideFileInput($input);
912 $template->setVariable(
'ACTION_BUTTON', $default_renderer->render(
913 $this->getUIFactory()->button()->shy(
914 $input->getMaxFiles() <= 1
915 ? $this->txt(
'select_file_from_computer')
916 : $this->txt(
'select_files_from_computer'),
921 return $this->wrapInFormContext(
930 $template = $this->getTemplate(
'tpl.hidden.html',
true,
true);
931 $this->applyName($input, $template);
932 $this->applyValue($input, $template, $this->escapeSpecialChars());
933 if ($input->isDisabled()) {
934 $template->setVariable(
"DISABLED",
'disabled="disabled"');
936 $this->bindJSandApplyId($input, $template);
937 return $template->get();
945 parent::registerResources($registry);
946 $registry->
register(
'assets/css/tagify.css');
947 $registry->
register(
'assets/js/tagInput.js');
949 $registry->
register(
'assets/js/dropzone.min.js');
950 $registry->
register(
'assets/js/dropzone.js');
951 $registry->
register(
'assets/js/input.js');
952 $registry->
register(
'assets/js/core.js');
953 $registry->
register(
'assets/js/file.js');
955 $registry->
register(
'assets/js/drilldown.min.js');
956 $registry->
register(
'assets/js/input.factory.min.js');
966 foreach ($input->getTriggeredSignals() as $s) {
968 "signal_id" => $s->getSignal()->getId(),
969 "event" => $s->getEvent(),
970 "options" => $s->getSignal()->getOptions()
973 if ($signals !==
null) {
974 $signals = json_encode($signals);
976 $input = $input->withAdditionalOnLoadCode(
function (
$id) use ($signals) {
977 $code =
"il.UI.input.setSignalsForId('$id', $signals);";
981 $input = $input->withAdditionalOnLoadCode($input->getUpdateOnLoadCode());
997 foreach ($origin->toArray() as $element) {
998 if (array_key_exists($element, $mapping)) {
999 $ret .= $mapping[$element];
1010 RendererInterface $default_renderer,
1014 $template->setCurrentBlock(
'block_file_preview');
1015 $template->
setVariable(
'REMOVAL_GLYPH', $default_renderer->render(
1016 $this->getUIFactory()->symbol()->glyph()->close()->withAction(
"#")
1019 if (
null !== $file_info) {
1029 if ($file_input->hasMetadataInputs()) {
1030 $template->
setVariable(
'EXPAND_GLYPH', $default_renderer->render(
1031 $this->getUIFactory()->symbol()->glyph()->expand()->withAction(
"#")
1033 $template->
setVariable(
'COLLAPSE_GLYPH', $default_renderer->render(
1034 $this->getUIFactory()->symbol()->glyph()->collapse()->withAction(
"#")
1038 $template->
setVariable(
'METADATA_INPUTS', $default_renderer->render($metadata_input));
1048 function (
$id) use ($input) {
1049 $current_file_count = count($input->getGeneratedDynamicInputs());
1050 $translations = json_encode($input->getTranslations());
1051 $is_disabled = ($input->isDisabled()) ?
'true' :
'false';
1052 $php_upload_limit = $this->getUploadLimitResolver()->getPhpUploadLimitInBytes();
1053 $should_upload_be_chunked = ($input->getMaxFileSize() > $php_upload_limit) ?
'true' :
'false';
1054 $chunk_size = (
int) floor($php_upload_limit * self::FILE_UPLOAD_CHUNK_SIZE_FACTOR);
1056 $(document).ready(function () {
1057 il.UI.Input.File.init(
1059 '{$input->getUploadHandler()->getUploadURL()}',
1060 '{$input->getUploadHandler()->getFileRemovalURL()}',
1061 '{$input->getUploadHandler()->getFileIdentifierParameterName()}',
1062 $current_file_count,
1063 {$input->getMaxFiles()},
1064 {$input->getMaxFileSize()},
1065 '{$this->prepareDropzoneJsMimeTypes($input->getAcceptedMimeTypes())}',
1068 $should_upload_be_chunked,
1084 $mime_type_string =
'';
1085 foreach ($mime_types as $index => $mime_type) {
1086 $mime_type_string .= (isset($mime_types[$index + 1])) ?
"$mime_type," : $mime_type;
1089 return $mime_type_string;
1094 $tpl = $this->getTemplate(
"tpl.color_select.html",
true,
true);
1095 $this->applyName($component, $tpl);
1096 $tpl->setVariable(
'VALUE', $component->getValue());
1098 $label_id = $this->createId();
1099 $tpl->setVariable(
'ID', $label_id);
1100 return $this->wrapInFormContext($component, $component->getLabel(), $tpl->get(), $label_id);
1105 $tpl = $this->getTemplate(
"tpl.rating.html",
true,
true);
1106 $id = $this->createId();
1107 $aria_description_id =
$id .
'_desc';
1108 $tpl->setVariable(
'DESCRIPTION_SRC_ID', $aria_description_id);
1110 $option_count = count(FiveStarRatingScale::cases()) - 1;
1112 foreach (range($option_count, 1, -1) as $option) {
1113 $tpl->setCurrentBlock(
'scaleoption');
1114 $tpl->setVariable(
'ARIALABEL', $this->txt($option .
'stars'));
1115 $tpl->setVariable(
'OPT_VALUE', (
string) $option);
1116 $tpl->setVariable(
'OPT_ID',
$id .
'-' . $option);
1117 $tpl->setVariable(
'NAME', $component->getName());
1118 $tpl->setVariable(
'DESCRIPTION_ID', $aria_description_id);
1121 $tpl->setVariable(
"SELECTED",
' checked="checked"');
1123 if ($component->isDisabled()) {
1124 $tpl->setVariable(
"DISABLED",
'disabled="disabled"');
1126 $tpl->parseCurrentBlock();
1129 if (!$component->isRequired()) {
1130 $tpl->setVariable(
'NEUTRAL_ID',
$id .
'-0');
1131 $tpl->setVariable(
'NEUTRAL_NAME', $component->getName());
1132 $tpl->setVariable(
'NEUTRAL_LABEL', $this->txt(
'reset_stars'));
1133 $tpl->setVariable(
'NEUTRAL_DESCRIPTION_ID', $aria_description_id);
1135 if ($component->getValue() === FiveStarRatingScale::NONE || is_null($component->getValue())) {
1136 $tpl->setVariable(
'NEUTRAL_SELECTED',
' checked="checked"');
1140 if ($txt = $component->getAdditionalText()) {
1141 $tpl->setVariable(
'TEXT', $txt);
1144 if ($component->isDisabled()) {
1145 $tpl->touchBlock(
'disabled');
1147 if ($average = $component->getCurrentAverage()) {
1148 $average_title = sprintf($this->txt(
'rating_average'), $average);
1149 $tpl->setVariable(
'AVERAGE_VALUE', $average_title);
1150 $tpl->setVariable(
'AVERAGE_VALUE_PERCENT', $average / $option_count * self::CENTUM);
1153 return $this->wrapInFormContext($component, $component->getLabel(), $tpl->get());
1158 $template = $this->prepareTreeSelectTemplate($component, $default_renderer);
1160 if ($component->canSelectChildNodes()) {
1161 $select_child_nodes =
'true';
1163 $select_child_nodes =
'false';
1166 $enriched_component = $component->withAdditionalOnLoadCode(
1167 static fn(
$id) =>
"il.UI.Input.treeSelect.initTreeMultiSelect('$id', $select_child_nodes);"
1170 $id = $this->bindJSandApplyId($enriched_component, $template);
1172 return $this->wrapInFormContext($component, $component->getLabel(), $template->
get(),
$id);
1177 $template = $this->prepareTreeSelectTemplate($component, $default_renderer);
1179 $enriched_component = $component->withAdditionalOnLoadCode(
1180 static fn(
$id) =>
"il.UI.Input.treeSelect.initTreeSelect('$id');"
1183 $id = $this->bindJSandApplyId($enriched_component, $template);
1185 return $this->wrapInFormContext($component, $component->getLabel(), $template->
get(),
$id);
1188 protected function prepareTreeSelectTemplate(
1190 RendererInterface $default_renderer,
1192 $template = $this->getTemplate(
'tpl.tree_select.html',
true,
true);
1198 $template->
setVariable(
'SELECT_LABEL', $this->txt(
'select'));
1199 $template->
setVariable(
'CLOSE_LABEL', $this->txt(
'close'));
1202 $template->
setVariable(
'INPUT_TEMPLATE', $default_renderer->render(
1205 $template->
setVariable(
'BREADCRUMB_TEMPLATE', $default_renderer->render(
1206 $this->getUIFactory()->breadcrumbs([$this->getUIFactory()->link()->standard(
'label',
'#')])
1208 $template->
setVariable(
'BREADCRUMBS', $default_renderer->render(
1209 $this->getUIFactory()->breadcrumbs([])
1216 $this->getUIFactory()->input()->field()->node(),
1217 $this->getUIFactory()->symbol()->icon(),
1221 $lockstep_iterator = $this->iterateGeneratorsInLockstep($leaf_generator, $dynamic_inputs_generator);
1222 $sync_node_id_whitelst = [];
1224 foreach ($lockstep_iterator as [$leaf, $dynamic_input]) {
1227 $this->checkArgInstanceOf(
'leaf', $leaf, Node\Leaf::class);
1229 $value_template = $this->getTemplate(
'tpl.tree_select.html',
true,
true);
1230 $value_template->setCurrentBlock(
'with_value_template');
1231 $value_template->setVariable(
'NODE_ID', (
string) ($leaf->getId()));
1232 $value_template->setVariable(
'NODE_NAME', $leaf->getName());
1233 $value_template->setVariable(
'INPUT_TEMPLATE', $default_renderer->render($dynamic_input));
1234 $value_template->setVariable(
'UNSELECT_NODE_LABEL', sprintf($this->txt(
'unselect_node'), $leaf->getName()));
1235 $value_template->parseCurrentBlock();
1238 $template->
setVariable(
'VALUE', $value_template->get(
'with_value_template'));
1241 foreach ($leaf->getFullPath() as $node_id) {
1243 $sync_node_id_whitelst[$node_id] = $node_id;
1247 $node_factory = $this->getUIFactory()->input()->field()->node();
1250 $this->getUIFactory()->
symbol()->icon(),
1251 array_values($sync_node_id_whitelst),
1256 foreach ($node_generator as $node) {
1258 $this->checkArgInstanceOf(
'node', $node,
Component\Input\Field\Node\Node::class);
1262 $template->
setVariable(
'DRILLDOWN', $default_renderer->render(
1263 $this->getUIFactory()->menu()->drilldown($component->
getLabel(), $nodes)
1266 $this->toJS(
'unselect_node');
1267 $this->toJS(
'select_node');
1281 while (
$a->valid() &&
$b->valid()) {
1282 yield [
$a->current(),
$b->current()];
1286 if (
$a->valid() ||
$b->valid()) {
1287 throw new LogicException(
'Generators do not have equal lenghts.');
1296 $template->
setVariable(
'FILE_SIZE_LABEL', $this->txt(
'file_notice'));
1297 $template->
setVariable(
'FILE_SIZE_VALUE',
new DataSize($input->getMaxFileSize(), DataSize::Byte));
1301 $template->
setVariable(
'FILES_LABEL', $this->txt(
'ui_file_upload_max_nr'));
1302 $template->
setVariable(
'FILES_VALUE', $input->getMaxFiles());
1317 $option_filter_template = $this->getTemplate(
"tpl.option_filter.html",
true,
true);
1318 $option_filter_template->setVariable(
'INPUT', $input_html);
1320 $search_input_id = $this->createId();
1321 $search_input_label_id = $this->createId();
1322 $search_input_description_id = $this->createId();
1323 $list_id = $this->createId();
1325 $option_filter_template->setVariable(
'SEARCH_INPUT_ID', $search_input_id);
1326 $option_filter_template->setVariable(
'SEARCH_INPUT_LABEL_ID', $search_input_label_id);
1327 $option_filter_template->setVariable(
'SEARCH_INPUT_DESCRIPTION_ID', $search_input_description_id);
1328 $option_filter_template->setVariable(
'LIST_ID', $list_id);
1330 $no_selection_text = $this->txt(
'ui_field_option_filter_no_selection');
1331 $option_filter_template->setVariable(
'NOTHING_SELECTED', $no_selection_text);
1332 $option_filter_template->setVariable(
'ARIA_FILTERED_RESULTS', $this->txt(
'ui_field_option_filter_filtered_results_aria_label'));
1334 $option_filter_template->setVariable(
'SEARCH_LABEL', $this->txt(
"ui_field_option_filter_search_in"));
1335 $option_filter_template->setVariable(
'SCREEN_READER_HINT', $this->txt(
'ui_field_option_filter_screen_reader_hint'));
1336 $option_filter_template->setVariable(
'NO_MATCH', $this->txt(
'ui_field_option_filter_no_match'));
1337 $option_filter_template->setVariable(
'OPTIONS_SHOWN', $this->txt(
'ui_field_option_filter_options_shown'));
1339 $expand_icon = $default_renderer->render($this->getUIFactory()->
symbol()->glyph()->
expand());
1340 $option_filter_template->setVariable(
'EXPAND_TEXT', $expand_icon . $this->txt(
'ui_field_option_filter_show_all_options'));
1342 $collapse_icon = $default_renderer->render($this->getUIFactory()->
symbol()->glyph()->collapseHorizontal());
1343 $option_filter_template->setVariable(
'COLLAPSE_TEXT', $collapse_icon . $this->txt(
'ui_field_option_filter_show_less'));
1345 $remove_icon = $default_renderer->render($this->getUIFactory()->
symbol()->glyph()->
remove());
1346 $option_filter_template->setVariable(
'CLEAR_SEARCH_BTN', $remove_icon . $this->txt(
'ui_field_option_filter_clear_search'));
1348 $component = $component->withAdditionalOnLoadCode(
1349 static fn(
$id):
string =>
"il.UI.Input.optionFilter.init(document.getElementById('$id'));",
1352 return [$option_filter_template->get(), $component];
1357 return function ($val) {
1358 $val = htmlentities((
string) $val);
1359 return str_replace(
'{{',
'{{', str_replace(
'}}',
'}}', $val));
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
This class provides the data size with additional information to remove the work to calculate the siz...
A Link is the often used combination of a label and an URL.
A password is used as part of credentials for authentication.
The scope of this class is split ilias-conform URI's into components.
FiveStarRatingScale
This is the scale for the Rating Input.
This implements the text input.
This implements the textarea input.
Base class for all component renderers.
cannotHandleComponent(Component $component)
This method MUST be called by derived component renderers, if.
txt(string $id)
Get a text from the language file.
createId()
Get a fresh unique id.
bindJavaScript(JavaScriptBindable $component)
Bind the component to JavaScript.
addTriggererOnLoadCode(Triggerer $triggerer)
Add onload-code for triggerer.
getComponentCanonicalNameAttribute(Component $component)
getTemplate(string $name, bool $purge_unfilled_vars, bool $purge_unused_blocks)
Get template of component this renderer is made for.
Interface FileInfoResult.
Interface to be extended by components that have the possibility to bind to Javascript.
withAdditionalOnLoadCode(Closure $binder)
Add some onload-code to the component instead of replacing the existing one.
getOnLoadCode()
Get the currently bound on load code.
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.
setVariable(string $name, $value)
Set a variable in the current block.
get(?string $block=null)
Get the rendered template or a specific block.
setCurrentBlock(string $name)
Set the block to work on.
parseCurrentBlock()
Parse the block that is currently worked on.
An entity that renders components to a string output.
trait JavaScriptBindable
Trait for components implementing JavaScriptBindable providing standard implementation.
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples