Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -298,17 +298,31 @@ protected function getConstraintForRequirement(): ?Constraint
*/
public function getUpdateOnLoadCode(): Closure
{
return fn($id) => "var combinedDuration = function() {
var options = [];
$('#$id').find('input').each(function() {
options.push($(this).val());
});
return options.join(' - ');
}
$('#$id').on('input', function(event) {
il.UI.input.onFieldUpdate(event, '$id', combinedDuration());
});
il.UI.input.onFieldUpdate(event, '$id', combinedDuration());";
return static fn($id) => <<<JS
(function () {
function formatDateTimeValue(value) {
const date = new Date(value);
if (value.includes('T')) {
return date.toLocaleString([], { dateStyle: 'short', timeStyle: 'short' });
}
return date.toLocaleDateString();
}
function reduceDateTimeInputs(inputs) {
return Array
.from(dateTimeInputs)
.map((input) => (input.value) ? formatDateTimeValue(input.value) : '')
.join(' - ');
}
const durationField = document.getElementById('$id');
const dateTimeInputs = durationField.querySelectorAll('.c-field-datetime');
dateTimeInputs.forEach((input) => {
input.addEventListener('input', (event) => {
il.UI.input.onFieldUpdate(event, '$id', reduceDateTimeInputs(dateTimeInputs));
});
});
il.UI.input.onFieldUpdate(undefined, '$id', reduceDateTimeInputs(dateTimeInputs));
})();
JS;
}

public function withLabels(string $start_label, string $end_label): C\Input\Field\Duration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,14 @@ protected function wrapInFilterContext(
return false; // stop event propagation
});");

$tpl->setVariable("UI_COMPONENT_NAME", $this->getComponentCanonicalNameAttribute($component));
$tpl->setVariable("INPUT_NAME", $component->getName());

if ($component->getOnLoadCode() !== null) {
$binding_id = $this->bindJavaScript($component) ?? $this->createId();
$tpl->setVariable("BINDING_ID", $binding_id);
}

$tpl->setCurrentBlock("addon_left");
$tpl->setVariable("LABEL", $component->getLabel());
if ($id_pointing_to_input) {
Expand All @@ -158,7 +166,7 @@ protected function wrapInFilterContext(
$tpl->parseCurrentBlock();
$tpl->setCurrentBlock("filter_field");
if ($component->isComplex()) {
$tpl->setVariable("FILTER_FIELD", $this->renderProxyField($input_html, $default_renderer));
$tpl->setVariable("FILTER_FIELD", $this->renderProxyField($component, $input_html, $default_renderer));
} else {
$tpl->setVariable("FILTER_FIELD", $input_html);
}
Expand All @@ -176,6 +184,7 @@ protected function maybeDisable(FormInput $component, Template $tpl): void
}

protected function renderProxyField(
FormInput $component,
string $input_html,
RendererInterface $default_renderer
): string {
Expand Down Expand Up @@ -207,7 +216,6 @@ protected function renderDurationField(F\Duration $component, RendererInterface
$input_html .= $default_renderer->render($input);

$tpl = $this->getTemplate("tpl.duration.html", true, true);
$id = $this->bindJSandApplyId($component, $tpl);
$tpl->setVariable('DURATION', $input_html);

return $this->wrapInFormContext($component, $component->getLabel(), $tpl->get());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,21 +96,25 @@ protected function getConstraintForRequirement(): ?Constraint
*/
public function getUpdateOnLoadCode(): Closure
{
return fn($id) => "(function() {
var checkedBoxes = function() {
var options = [];
$('#$id').find('li').each(function() {
if ($(this).find('input').prop('checked')) {
options.push($(this).find('span').text());
}
});
return options.join(', ');
}
$('#$id').on('input', function(event) {
il.UI.input.onFieldUpdate(event, '$id', checkedBoxes());
});
il.UI.input.onFieldUpdate(event, '$id', checkedBoxes());
})();";
return static fn($id) => <<<JS
(function () {
function reduceMultiSelectCheckboxInputs(inputs) {
return Array
.from(inputs)
.filter((input) => input.checked)
.map((input) => input.parentElement.querySelector('.c-field-multiselect__label-text')?.textContent ?? '')
.join(', ');
}
const multiSelectField = document.getElementById('$id');
const multiSelectCheckboxInputs = multiSelectField.querySelectorAll('.c-field-multiselect input[type="checkbox"]');
multiSelectCheckboxInputs.forEach((input) => {
input.addEventListener('input', (event) => {
il.UI.input.onFieldUpdate(event, '$id', reduceMultiSelectCheckboxInputs(multiSelectCheckboxInputs));
});
});
il.UI.input.onFieldUpdate(undefined, '$id', reduceMultiSelectCheckboxInputs(multiSelectCheckboxInputs));
})();
JS;
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

declare(strict_types=1);

namespace ILIAS\UI\examples\Input\Container\Filter\Standard;

/**
* ---
* description: >
* Example showing a Filter Container and Filter Inputs with additional JavaScript on-load-code
* attached to them.
*
* expected output: >
* ILIAS shows the rendered Filter Component with several Filter Inputs. When opening the browser
* console, for each of the Filter Input, as well as the Filter Container, a log entry that refers
* to their ID will be visible.
* ---
*/
function with_additional_on_load_code(): string
{
global $DIC;

$factory = $DIC->ui()->factory();
$renderer = $DIC->ui()->renderer();

$pseudo_load_code = static fn($name) => static fn($id) => "console.log('Loaded $name with ID: ' + '$id');";

$pseudo_options = [
'A' => 'Option A',
'B' => 'Option B',
'C' => 'Option C',
];

$filter_inputs = [
$factory->input()->field()->multiSelect('multi-select', $pseudo_options)->withAdditionalOnLoadCode($pseudo_load_code('multi-select')),
$factory->input()->field()->select('single-select', $pseudo_options)->withAdditionalOnLoadCode($pseudo_load_code('single-select')),
$factory->input()->field()->duration('duration')->withAdditionalOnLoadCode($pseudo_load_code('duration')),
$factory->input()->field()->dateTime('datetime')->withAdditionalOnLoadCode($pseudo_load_code('datetime')),
$factory->input()->field()->numeric('numeric')->withAdditionalOnLoadCode($pseudo_load_code('numeric')),
$factory->input()->field()->text('text')->withAdditionalOnLoadCode($pseudo_load_code('text')),
];

$filter = $factory->input()->container()->filter()->standard(
'#',
'#',
'#',
'#',
'#',
'#',
$filter_inputs,
array_map(static fn() => true, $filter_inputs),
true,
true,
)->withAdditionalOnLoadCode($pseudo_load_code('filter'));

return $renderer->render($filter);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div class="col-md-6 col-lg-4 il-popover-container">
<div class="input-group">
<div data-il-ui-component="{UI_COMPONENT_NAME}" data-il-ui-input-name="{INPUT_NAME}"<!-- BEGIN binding --> id="{BINDING_ID}"<!-- END binding --> class="input-group">
<!-- BEGIN addon_left -->
<label <!-- BEGIN for -->for="{ID}" <!-- END for --> class="input-group-addon leftaddon">{LABEL}</label>
<!-- END addon_left -->
Expand Down
5 changes: 5 additions & 0 deletions components/ILIAS/UI/tests/Base.php
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,11 @@ public function normalizeHTML(string $html): string
return trim(str_replace(["\n", "\r"], "", $html));
}

/**
* @deprecated please try not to use this method anymore. It relies on DOMDocument, which DOES NOT
* support HTML5 and will trigger warnings for such elements and COULD add self-closing
* tags ( <... />) automatically, which produces false-positives.
*/
public function assertHTMLEquals(string $expected_html_as_string, string $html_as_string): void
{
$html = new DOMDocument();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public function testRenderTextWithFilterContext(): void

$expected = $this->brutallyTrimHTML('
<div class="col-md-6 col-lg-4 il-popover-container">
<div class="input-group">
<div data-il-ui-component="text-field-input" data-il-ui-input-name="" class="input-group">
<label for="id_1" class="input-group-addon leftaddon">label</label>
<input id="id_1" type="text" class="c-field-text" />
<span class="input-group-addon rightaddon">
Expand All @@ -147,8 +147,7 @@ public function testRenderNumericWithFilterContext(): void
$html = $this->brutallyTrimHTML($fr->render($numeric));

$expected = $this->brutallyTrimHTML('
<div class="col-md-6 col-lg-4 il-popover-container">
<div class="input-group">
<div class="col-md-6 col-lg-4 il-popover-container"><div data-il-ui-component="numeric-field-input" data-il-ui-input-name="" class="input-group">
<label for="id_1" class="input-group-addon leftaddon">label</label>
<input id="id_1" type="number" class="c-field-number" />
<span class="input-group-addon rightaddon">
Expand All @@ -173,8 +172,7 @@ public function testRenderSelectWithFilterContext(): void
$html = $this->brutallyTrimHTML($fr->render($select));

$expected = $this->brutallyTrimHTML('
<div class="col-md-6 col-lg-4 il-popover-container">
<div class="input-group">
<div class="col-md-6 col-lg-4 il-popover-container"><div data-il-ui-component="select-field-input" data-il-ui-input-name="" class="input-group">
<label for="id_1" class="input-group-addon leftaddon">label</label>
<select id="id_1">
<option selected="selected" value="">-</option>
Expand Down Expand Up @@ -202,8 +200,7 @@ public function testRenderMultiSelectWithFilterContext(): void
$html = $this->brutallyTrimHTML($fr->render($multi));

$expected = $this->brutallyTrimHTML('
<div class="col-md-6 col-lg-4 il-popover-container">
<div class="input-group">
<div class="col-md-6 col-lg-4 il-popover-container"><div data-il-ui-component="multi-select-field-input" data-il-ui-input-name="" class="input-group">
<label class="input-group-addon leftaddon">label</label>
<span role="button" tabindex="0" class="form-control il-filter-field" id="id_3" data-placement="bottom"></span>
<div class="il-standard-popover-content" style="display:none;" id="id_1"></div>
Expand All @@ -213,7 +210,6 @@ public function testRenderMultiSelectWithFilterContext(): void
</a>
</span>
</div>
{POPOVER}
</div>
');
$this->assertHTMLEquals($expected, $html);
Expand All @@ -229,8 +225,7 @@ public function testRenderDateTimeWithFilterContext(): void
$html = $this->brutallyTrimHTML($fr->render($datetime));

$expected = $this->brutallyTrimHTML('
<div class="col-md-6 col-lg-4 il-popover-container">
<div class="input-group">
<div class="col-md-6 col-lg-4 il-popover-container"><div data-il-ui-component="date-time-field-input" data-il-ui-input-name="" class="input-group">
<label for="id_1" class="input-group-addon leftaddon">label</label>
<div class="c-input-group">
<input id="id_1" type="date" class="c-field-datetime" />
Expand Down Expand Up @@ -283,18 +278,16 @@ public function testRenderDurationWithFilterContext(): void


$expected = $this->brutallyTrimHTML('
<div class="col-md-6 col-lg-4 il-popover-container">
<div class="input-group">
<div class="col-md-6 col-lg-4 il-popover-container"><div data-il-ui-component="duration-field-input" data-il-ui-input-name="" class="input-group">
<label class="input-group-addon leftaddon">label</label>
<span role="button" tabindex="0" class="form-control il-filter-field" id="id_7" data-placement="bottom"></span>
<div class="il-standard-popover-content" style="display:none;" id="id_5"></div>
<span role="button" tabindex="0" class="form-control il-filter-field" id="id_6" data-placement="bottom"></span>
<div class="il-standard-popover-content" style="display:none;" id="id_4"></div>
<span class="input-group-addon rightaddon">
<a class="glyph" href="" aria-label="remove" id="id_8">
<a class="glyph" href="" aria-label="remove" id="id_7">
<span class="glyphicon glyphicon-minus-sign" aria-hidden="true"></span>
</a>
</span>
</div>
{POPOVER}
</div>
');
$this->assertHTMLEquals($expected, $html);
Expand Down
Loading