Skip to content

Commit

Permalink
[FIX] UI: align Container\Form context renderers.
Browse files Browse the repository at this point in the history
  • Loading branch information
thibsy committed Nov 15, 2024
1 parent c77704f commit 3dab4e4
Show file tree
Hide file tree
Showing 7 changed files with 41 additions and 115 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,20 +61,4 @@ protected function extractRequestData(ServerRequestInterface $request): InputDat
{
return new PostDataFromServerRequest($request);
}

/**
* @inheritdoc
*/
public function getPromptButtons(): array
{
return [];
}

/**
* @inheritdoc
*/
public function getPromptTitle(): string
{
return '';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@

class FormRendererFactory extends Render\DefaultRendererFactory
{
public const NO_BUTTONS_FORM = [
public const FORM_CONTEXTS_WITHOUT_BUTTONS = [
'StateStatePrompt',
'RoundTripModal',
];

public function getRendererInContext(Component\Component $component, array $contexts): Render\AbstractComponentRenderer
{
$has_context_without_buttons = array_intersect(self::NO_BUTTONS_FORM, $contexts);
$has_context_without_buttons = array_intersect(self::FORM_CONTEXTS_WITHOUT_BUTTONS, $contexts);

if (! empty($has_context_without_buttons)) {
return new NoButtonsContextRenderer(
return new FormWithoutSubmitButtonsContextRenderer(
$this->ui_factory,
$this->tpl_factory,
$this->lng,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,27 @@
use ILIAS\UI\Component;
use LogicException;

class NoButtonsContextRenderer extends AbstractComponentRenderer
class FormWithoutSubmitButtonsContextRenderer extends Renderer
{
/**
* @inheritdoc
*/
public function render(Component\Component $component, RendererInterface $default_renderer): string
{
if (!$component instanceof Form\Form) {
$this->cannotHandleComponent($component);
if ($component instanceof Form\Standard) {
return $this->renderFormWithoutSubmitButtons($component, $default_renderer);
}
return $this->renderNoSubmit($component, $default_renderer);

$this->cannotHandleComponent($component);
}

protected function renderNoSubmit(
Form\Form $component,
protected function renderFormWithoutSubmitButtons(
Form\Standard $component,
RendererInterface $default_renderer
): string {
$tpl = $this->getTemplate("tpl.no_submit.html", true, true);
$tpl = $this->getTemplate("tpl.without_submit_buttons.html", true, true);

$this->maybeAddDedicatedName($component, $tpl);
$this->maybeAddRequired($component, $tpl);
$this->addPostURL($component, $tpl);
$this->maybeAddError($component, $tpl);
Expand Down Expand Up @@ -75,41 +77,4 @@ static function (string $id) use ($component): string {

return $tpl->get();
}

protected function addPostURL(Component\Input\Container\Form\FormWithPostURL $component, Template $tpl): void
{
if ('' !== ($url = $component->getPostURL())) {
$tpl->setCurrentBlock("action");
$tpl->setVariable("URL", $url);
$tpl->parseCurrentBlock();
}
}

protected function maybeAddError(Form\Form $component, Template $tpl): void
{
if (null !== ($error = $component->getError())) {
$tpl->setCurrentBlock("error");
$tpl->setVariable("ERROR", $error);
$tpl->parseCurrentBlock();
}
}

protected function maybeAddRequired(Form\Form $component, Template $tpl): void
{
if ($component->hasRequiredInputs()) {
$tpl->setVariable("TXT_REQUIRED_TOP", $this->txt("required_field"));
$tpl->setVariable("TXT_REQUIRED", $this->txt("required_field"));
}
}

/**
* @inheritdoc
*/
protected function getComponentInterfaceName(): array
{
return [
Component\Input\Container\Form\Standard::class,
FormWithoutSubmitButton::class,
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,14 @@ public function render(Component\Component $component, RendererInterface $defaul
return $this->renderStandard($component, $default_renderer);
}

if ($component instanceof Form\FormWithoutSubmitButton) {
return $this->renderNoSubmit($component, $default_renderer);
}

$this->cannotHandleComponent($component);
}

protected function renderStandard(Form\Standard $component, RendererInterface $default_renderer): string
{
$tpl = $this->getTemplate("tpl.standard.html", true, true);
if ($component->getDedicatedName() !== null) {
$tpl->setVariable("NAME", 'name="' . $component->getDedicatedName() . '"');
}

$this->maybeAddDedicatedName($component, $tpl);
$this->maybeAddRequired($component, $tpl);
$this->addPostURL($component, $tpl);
$this->maybeAddError($component, $tpl);
Expand All @@ -68,39 +62,11 @@ protected function renderStandard(Form\Standard $component, RendererInterface $d
return $tpl->get();
}

protected function renderNoSubmit(Form\FormWithoutSubmitButton $component, RendererInterface $default_renderer): string
protected function maybeAddDedicatedName(Form\Form $component, Template $tpl): void
{
$tpl = $this->getTemplate("tpl.no_submit.html", true, true);

$this->maybeAddRequired($component, $tpl);
$this->addPostURL($component, $tpl);
$this->maybeAddError($component, $tpl);

$tpl->setVariable("INPUTS", $default_renderer->render($component->getInputGroup()));

/** @var $component Form\FormWithoutSubmitButton */
$enriched_component = $component->withAdditionalOnLoadCode(
static function (string $id) use ($component): string {
return "
// @TODO: we need to refactor the signal-management to prevent using jQuery here.
$(document).on('{$component->getSubmitSignal()}', function () {
let form = document.getElementById('$id');
if (!form instanceof HTMLFormElement) {
throw new Error(`Element '$id' is not an instance of HTMLFormElement.`);
}
// @TODO: we should use the triggering button as an emitter here. When doing
// so, please also change file.js processFormSubmissionHook().
form.requestSubmit();
});
";
}
);

$id = $this->bindJavaScript($enriched_component) ?? $this->createId();
$tpl->setVariable("ID", $id);

return $tpl->get();
if ($component->getDedicatedName() !== null) {
$tpl->setVariable("NAME", 'name="' . $component->getDedicatedName() . '"');
}
}

protected function addPostURL(Component\Input\Container\Form\FormWithPostURL $component, Template $tpl): void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,15 @@
use ILIAS\UI\Implementation\Component\Input;
use ILIAS\UI\Implementation\Component\Input\NameSource;
use ILIAS\UI\Implementation\Component\SignalGeneratorInterface;
use ILIAS\UI\Implementation\Component\Prompt\IsPromptContentInternal;
use ILIAS\UI\Component\Signal;
use ILIAS\UI\Implementation\Component\JavaScriptBindable as JavaScriptBindableTrait;
use ILIAS\UI\Component\JavaScriptBindable;

/**
* This implements a standard form.
*/
class Standard extends Form implements C\Input\Container\Form\Standard, JavaScriptBindable
class Standard extends Form implements C\Input\Container\Form\Standard, IsPromptContentInternal, JavaScriptBindable
{
use HasPostURL;
use JavaScriptBindableTrait;
Expand All @@ -55,10 +56,10 @@ public function __construct(
/**
* @inheritDoc
*/
public function withSubmitLabel(string $caption): C\Input\Container\Form\Standard
public function withSubmitLabel(string $label): C\Input\Container\Form\Standard
{
$clone = clone $this;
$clone->submit_caption = $caption;
$clone->submit_caption = $label;
return $clone;
}

Expand All @@ -70,6 +71,16 @@ public function getSubmitLabel(): ?string
return $this->submit_caption;
}

public function getPromptButtons(): array
{
return [];
}

public function getPromptTitle(): string
{
return '';
}

public function getSubmitSignal(): Signal
{
return $this->submit_signal;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
<form id="{ID}" role="form" class="c-form c-form--horizontal" enctype="multipart/form-data"<!-- BEGIN reference_error --> describedby="{ERROR_ID}"<!-- END reference_error --> {NAME}<!-- BEGIN action --> action="{URL}"<!-- END action --> method="post" novalidate="novalidate">
<!-- BEGIN error -->
<div id="{ERROR_ID}" class="c-form__error-msg alert alert-danger">
{ERROR}
</div>
<div class="c-form__error-msg alert alert-danger" id="{ERROR_ID}"><span class="sr-only">{ERROR_LABEL}: </span>{ERROR}</div>
<!-- END error -->

{INPUTS}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public function getNewDedicatedName(string $dedicated_name): string
/**
* @author Thibeau Fuhrer <[email protected]>
*/
class NoSubmitFormTest extends \ILIAS_UI_TestBase
class FormWithoutSubmitButtonsTest extends \ILIAS_UI_TestBase
{
protected SignalGenerator $signal_generator;
protected NameSource $namesource;
Expand Down Expand Up @@ -144,7 +144,8 @@ public function testRenderWithRequiredInputs(): void
public function testRenderWithError(): void
{
$post_url = 'http://ilias.localhost/some_url?param1=foo&param2=bar';
$error_lang_var = 'ui_error_in_group';
$error_lang_var = 'ui_error';
$error_lang_var_in_group = 'ui_error_in_group';

$dummy_input = $this->buildInputFactory()->text('test_label')->withAdditionalTransformation(
$this->refinery->custom()->constraint(
Expand All @@ -171,11 +172,12 @@ static function ($value): bool {
$form = $form->withRequest($request);
$data = $form->getData();

$expected_html =
"<form id=\"id_1\" role=\"form\" class=\"c-form c-form--horizontal\" enctype=\"multipart/form-data\" action=\"$post_url\" method=\"post\" novalidate=\"novalidate\">" .
"<div id=\"\" class=\"c-form__error-msg alert alert-danger\">$error_lang_var</div>" .
$dummy_input->getCanonicalName() .
"</form>";
$expected_html = <<<EOT
<form id="id_2" role="form" class="c-form c-form--horizontal" enctype="multipart/form-data" describedby="id_1" action="$post_url" method="post" novalidate="novalidate">
<div class="c-form__error-msg alert alert-danger" id="id_1"><span class="sr-only">$error_lang_var:</span>$error_lang_var_in_group
</div>{$dummy_input->getCanonicalName()}
</form>
EOT;

$context = $this->createMock(\ILIAS\UI\Component\Modal\RoundTrip::class);
$context->method('getCanonicalName')->willReturn('RoundTripModal');
Expand Down

0 comments on commit 3dab4e4

Please sign in to comment.