From d6f82eee8523d5affa4ac1befe9c725c28837525 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Mon, 1 Mar 2021 15:28:35 +0100 Subject: [PATCH 01/15] opened 4.0-dev --- composer.json | 2 +- readme.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 3b0d626f..44a49262 100644 --- a/composer.json +++ b/composer.json @@ -47,7 +47,7 @@ }, "extra": { "branch-alias": { - "dev-master": "3.2-dev" + "dev-master": "4.0-dev" } } } diff --git a/readme.md b/readme.md index 630329ee..45ffe251 100644 --- a/readme.md +++ b/readme.md @@ -2,8 +2,8 @@ Nette Forms: greatly facilitates web forms ========================================== [![Downloads this Month](https://img.shields.io/packagist/dm/nette/forms.svg)](https://packagist.org/packages/nette/forms) -[![Tests](https://github.com/nette/forms/actions/workflows/tests.yml/badge.svg?branch=v3.2)](https://github.com/nette/forms/actions) -[![Coverage Status](https://coveralls.io/repos/github/nette/forms/badge.svg?branch=v3.2)](https://coveralls.io/github/nette/forms?branch=v3.2) +[![Tests](https://github.com/nette/forms/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/nette/forms/actions) +[![Coverage Status](https://coveralls.io/repos/github/nette/forms/badge.svg?branch=master)](https://coveralls.io/github/nette/forms?branch=master) [![Latest Stable Version](https://poser.pugx.org/nette/forms/v/stable)](https://github.com/nette/forms/releases) [![License](https://img.shields.io/badge/license-New%20BSD-blue.svg)](https://github.com/nette/forms/blob/master/license.md) From 9830003f9106f05a0b1cd9a54492042ac666eac0 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Wed, 8 Nov 2023 22:43:19 +0100 Subject: [PATCH 02/15] removed support for Latte 2 --- composer.json | 4 +- src/Bridges/FormsLatte/FormMacros.php | 330 ------------------ src/Bridges/FormsLatte/Runtime.php | 2 +- tests/Forms.Latte2/FormMacros.button.phpt | 35 -- tests/Forms.Latte2/FormMacros.error.phpt | 55 --- .../FormMacros.formContainer.phpt | 55 --- tests/Forms.Latte2/FormMacros.forms.phpt | 61 ---- tests/Forms.Latte2/FormMacros.get.phpt | 36 -- .../expected/FormMacros.button.html | 9 - .../expected/FormMacros.button.php | 30 -- .../expected/FormMacros.formContainer.html | 41 --- .../expected/FormMacros.formContainer.php | 101 ------ .../expected/FormMacros.forms.html | 118 ------- .../expected/FormMacros.forms.php | 297 ---------------- .../Forms.Latte2/expected/FormMacros.get.html | 5 - .../Forms.Latte2/expected/FormMacros.get.php | 19 - .../Forms.Latte2/templates/forms.button.latte | 9 - .../templates/forms.formContainer.latte | 48 --- tests/Forms.Latte2/templates/forms.get.latte | 4 - tests/Forms.Latte2/templates/forms.latte | 86 ----- tests/Forms.Latte3/forms.button.phpt | 4 - tests/Forms.Latte3/forms.error.phpt | 4 - tests/Forms.Latte3/forms.formContainer.phpt | 4 - tests/Forms.Latte3/forms.get.phpt | 4 - tests/Forms.Latte3/forms.phpt | 4 - tests/Forms.Latte3/n-name.form.phpt | 4 - tests/Forms.Latte3/n-name.input.phpt | 4 - tests/Forms.Latte3/{input}.phpt | 4 - tests/Forms.Latte3/{label}.phpt | 4 - 29 files changed, 3 insertions(+), 1378 deletions(-) delete mode 100644 src/Bridges/FormsLatte/FormMacros.php delete mode 100644 tests/Forms.Latte2/FormMacros.button.phpt delete mode 100644 tests/Forms.Latte2/FormMacros.error.phpt delete mode 100644 tests/Forms.Latte2/FormMacros.formContainer.phpt delete mode 100644 tests/Forms.Latte2/FormMacros.forms.phpt delete mode 100644 tests/Forms.Latte2/FormMacros.get.phpt delete mode 100644 tests/Forms.Latte2/expected/FormMacros.button.html delete mode 100644 tests/Forms.Latte2/expected/FormMacros.button.php delete mode 100644 tests/Forms.Latte2/expected/FormMacros.formContainer.html delete mode 100644 tests/Forms.Latte2/expected/FormMacros.formContainer.php delete mode 100644 tests/Forms.Latte2/expected/FormMacros.forms.html delete mode 100644 tests/Forms.Latte2/expected/FormMacros.forms.php delete mode 100644 tests/Forms.Latte2/expected/FormMacros.get.html delete mode 100644 tests/Forms.Latte2/expected/FormMacros.get.php delete mode 100644 tests/Forms.Latte2/templates/forms.button.latte delete mode 100644 tests/Forms.Latte2/templates/forms.formContainer.latte delete mode 100644 tests/Forms.Latte2/templates/forms.get.latte delete mode 100644 tests/Forms.Latte2/templates/forms.latte diff --git a/composer.json b/composer.json index 44a49262..87327889 100644 --- a/composer.json +++ b/composer.json @@ -24,12 +24,12 @@ "nette/application": "^3.0", "nette/di": "^3.0", "nette/tester": "^2.5.2", - "latte/latte": "^2.10.2 || ^3.0.12", + "latte/latte": "^3.0.12", "tracy/tracy": "^2.9", "phpstan/phpstan-nette": "^2.0@stable" }, "conflict": { - "latte/latte": ">=3.0.0 <3.0.12 || >=3.2" + "latte/latte": "<3.0.12 || >=3.2" }, "suggest": { "ext-intl": "to use date/time controls" diff --git a/src/Bridges/FormsLatte/FormMacros.php b/src/Bridges/FormsLatte/FormMacros.php deleted file mode 100644 index 18c889ad..00000000 --- a/src/Bridges/FormsLatte/FormMacros.php +++ /dev/null @@ -1,330 +0,0 @@ -addMacro('form', [$me, 'macroForm'], 'echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(array_pop($this->global->formsStack));'); - $me->addMacro('formContext', [$me, 'macroFormContext'], 'array_pop($this->global->formsStack);'); - $me->addMacro('formContainer', [$me, 'macroFormContainer'], 'array_pop($this->global->formsStack); $formContainer = end($this->global->formsStack)'); - $me->addMacro('label', [$me, 'macroLabel'], [$me, 'macroLabelEnd'], null, self::AUTO_EMPTY); - $me->addMacro('input', [$me, 'macroInput']); - $me->addMacro('name', [$me, 'macroName'], [$me, 'macroNameEnd'], [$me, 'macroNameAttr']); - $me->addMacro('inputError', [$me, 'macroInputError']); - $me->addMacro('formPrint', [$me, 'macroFormPrint']); - $me->addMacro('formClassPrint', [$me, 'macroFormPrint']); - } - - - /********************* macros ****************d*g**/ - - - /** - * {form ...} - */ - public function macroForm(MacroNode $node, PhpWriter $writer) - { - if ($node->modifiers) { - throw new CompileException('Modifiers are not allowed in ' . $node->getNotation()); - } - - if ($node->prefix) { - throw new CompileException('Did you mean
?'); - } - - $name = $node->tokenizer->fetchWord(); - if ($name == null) { // null or false - throw new CompileException('Missing form name in ' . $node->getNotation()); - } - - $node->replaced = true; - $node->tokenizer->reset(); - return $writer->write( - '$form = $this->global->formsStack[] = ' - . ($name[0] === '$' - ? 'is_object($ʟ_tmp = %node.word) ? $ʟ_tmp : $this->global->uiControl[$ʟ_tmp]' - : '$this->global->uiControl[%node.word]') - . ';' - . 'Nette\Bridges\FormsLatte\Runtime::initializeForm($form);' - . 'echo Nette\Bridges\FormsLatte\Runtime::renderFormBegin($form, %node.array)' - . " /* line $node->startLine */;", - ); - } - - - /** - * {formContext ...} - */ - public function macroFormContext(MacroNode $node, PhpWriter $writer) - { - if ($node->modifiers) { - throw new CompileException('Modifiers are not allowed in ' . $node->getNotation()); - } - - if ($node->prefix) { - throw new CompileException('Did you mean ?'); - } - - $name = $node->tokenizer->fetchWord(); - if ($name == null) { // null or false - throw new CompileException('Missing form name in ' . $node->getNotation()); - } - - $node->tokenizer->reset(); - return $writer->write( - '$form = $this->global->formsStack[] = ' - . ($name[0] === '$' - ? 'is_object($ʟ_tmp = %node.word) ? $ʟ_tmp : $this->global->uiControl[$ʟ_tmp]' - : '$this->global->uiControl[%node.word]') - . " /* line $node->startLine */;", - ); - } - - - /** - * {formContainer ...} - */ - public function macroFormContainer(MacroNode $node, PhpWriter $writer) - { - if ($node->modifiers) { - throw new CompileException('Modifiers are not allowed in ' . $node->getNotation()); - } - - $name = $node->tokenizer->fetchWord(); - if ($name == null) { // null or false - throw new CompileException('Missing name in ' . $node->getNotation()); - } - - $node->tokenizer->reset(); - return $writer->write( - '$this->global->formsStack[] = $formContainer = ' - . ($name[0] === '$' - ? 'is_object($ʟ_tmp = %node.word) ? $ʟ_tmp : end($this->global->formsStack)[$ʟ_tmp]' - : 'end($this->global->formsStack)[%node.word]') - . " /* line $node->startLine */;", - ); - } - - - /** - * {label ...} - */ - public function macroLabel(MacroNode $node, PhpWriter $writer) - { - if ($node->modifiers) { - throw new CompileException('Modifiers are not allowed in ' . $node->getNotation()); - } - - $words = $node->tokenizer->fetchWords(); - if (!$words) { - throw new CompileException('Missing name in ' . $node->getNotation()); - } - - $node->replaced = true; - $name = array_shift($words); - return $writer->write( - ($name[0] === '$' - ? '$ʟ_input = is_object($ʟ_tmp = %0.word) ? $ʟ_tmp : end($this->global->formsStack)[$ʟ_tmp]; if ($ʟ_label = $ʟ_input' - : 'if ($ʟ_label = end($this->global->formsStack)[%0.word]' - ) - . '->%1.raw) echo $ʟ_label' - . ($node->tokenizer->isNext() ? '->addAttributes(%node.array)' : ''), - $name, - $words ? ('getLabelPart(' . implode(', ', array_map([$writer, 'formatWord'], $words)) . ')') : 'getLabel()', - ); - } - - - /** - * {/label} - */ - public function macroLabelEnd(MacroNode $node, PhpWriter $writer) - { - if ($node->content != null) { - $node->openingCode = rtrim($node->openingCode, '?> ') . '->startTag() ?>'; - return $writer->write('if ($ʟ_label) echo $ʟ_label->endTag()'); - } - } - - - /** - * {input ...} - */ - public function macroInput(MacroNode $node, PhpWriter $writer) - { - if ($node->modifiers) { - throw new CompileException('Modifiers are not allowed in ' . $node->getNotation()); - } - - $words = $node->tokenizer->fetchWords(); - if (!$words) { - throw new CompileException('Missing name in ' . $node->getNotation()); - } - - $node->replaced = true; - $name = array_shift($words); - return $writer->write( - ($name[0] === '$' - ? '$ʟ_input = $_input = is_object($ʟ_tmp = %word) ? $ʟ_tmp : end($this->global->formsStack)[$ʟ_tmp]; echo $ʟ_input' - : 'echo end($this->global->formsStack)[%word]') - . '->%raw' - . ($node->tokenizer->isNext() ? '->addAttributes(%node.array)' : '') - . " /* line $node->startLine */;", - $name, - $words ? 'getControlPart(' . implode(', ', array_map([$writer, 'formatWord'], $words)) . ')' : 'getControl()', - ); - } - - - /** - * , , - - - -
- - - - - - - - -
- - - - - - - - - - - - - - -
- - - -
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - -
- -
- - -
- -
- - - - - - - - - - - - - - - \ No newline at end of file diff --git a/tests/Forms.Latte2/expected/FormMacros.forms.php b/tests/Forms.Latte2/expected/FormMacros.forms.php deleted file mode 100644 index dda07804..00000000 --- a/tests/Forms.Latte2/expected/FormMacros.forms.php +++ /dev/null @@ -1,297 +0,0 @@ -global->formsStack[] = $this->global->uiControl["myForm"]; - Nette\Bridges\FormsLatte\Runtime::initializeForm($form); - echo Nette\Bridges\FormsLatte\Runtime::renderFormBegin($form, ['id' => 'myForm', 'class'=>"ajax"]) /* line 1 */; - echo "\n"; - $iterations = 0; - foreach (['id', 'username', 'select', 'area', 'send'] as $name) /* line 2 */ { - echo ' '; - $ʟ_input = is_object($ʟ_tmp = $name) ? $ʟ_tmp : end($this->global->formsStack)[$ʟ_tmp]; - if ($ʟ_label = $ʟ_input->getLabel()) echo $ʟ_label; - echo ' - '; - $ʟ_input = $_input = is_object($ʟ_tmp = $name) ? $ʟ_tmp : end($this->global->formsStack)[$ʟ_tmp]; - echo $ʟ_input->getControl()->addAttributes(['title' => 'Hello', 'size' => 10]) /* line 4 */; - echo ' - '; - echo LR\Filters::escapeHtmlText($ʟ_input->getError()) /* line 5 */; - echo ' - '; - $ʟ_input = is_object($ʟ_tmp = $name) ? $ʟ_tmp : end($this->global->formsStack)[$ʟ_tmp]; - echo LR\Filters::escapeHtmlText($ʟ_input->getError()) /* line 6 */; - echo ' - -
- - '; - $ʟ_input = is_object($ʟ_tmp = $form[$name]) ? $ʟ_tmp : end($this->global->formsStack)[$ʟ_tmp]; - if ($ʟ_label = $ʟ_input->getLabel()) echo $ʟ_label->addAttributes(['title' => 'hello'])->startTag(); - echo ' '; - $ʟ_input = $_input = is_object($ʟ_tmp = $form[$name]) ? $ʟ_tmp : end($this->global->formsStack)[$ʟ_tmp]; - echo $ʟ_input->getControl()->addAttributes(['title' => 'Hello', 'size' => 10]) /* line 10 */; - echo ' '; - if ($ʟ_label) echo $ʟ_label->endTag(); - echo ' - '; - $ʟ_input = is_object($ʟ_tmp = $form[$name]) ? $ʟ_tmp : end($this->global->formsStack)[$ʟ_tmp]; - echo LR\Filters::escapeHtmlText($ʟ_input->getError()) /* line 11 */; - echo "\n"; - $iterations++; - } - echo ' - '; - $ʟ_input = is_object($ʟ_tmp = $form['username']) ? $ʟ_tmp : end($this->global->formsStack)[$ʟ_tmp]; - if ($ʟ_label = $ʟ_input->getLabel()) echo $ʟ_label; - echo ' - - - global->formsStack)["username"]; - echo $ʟ_input->getControlPart()->addAttributes(['value' => null, 'type' => null, 'class' => null])->attributes() /* line 17 */; - echo '> - - global->formsStack)[$ʟ_tmp]; - echo $ʟ_input->getLabelPart()->attributes() /* line 19 */; - echo '> - global->formsStack)[$ʟ_tmp]; - echo $ʟ_input->getLabelPart()->attributes() /* line 20 */; - echo '>'; - echo $ʟ_input->getLabelPart()->getHtml() /* line 20 */; - echo ' - global->formsStack)[$ʟ_tmp]; - echo $ʟ_input->getControlPart()->attributes() /* line 21 */; - echo '> - - '; - if ($ʟ_label = end($this->global->formsStack)["my"]->getLabel()) echo $ʟ_label; - echo end($this->global->formsStack)["my"]->getControl() /* line 23 */; - echo "\n"; - echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(array_pop($this->global->formsStack)); - echo ' - - -'; - $form = $this->global->formsStack[] = $this->global->uiControl["myForm"]; - Nette\Bridges\FormsLatte\Runtime::initializeForm($form); - echo Nette\Bridges\FormsLatte\Runtime::renderFormBegin($form, []) /* line 27 */; - echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(array_pop($this->global->formsStack)); - echo ' - -'; - $form = $this->global->formsStack[] = $this->global->uiControl["myForm"]; - Nette\Bridges\FormsLatte\Runtime::initializeForm($form); - echo Nette\Bridges\FormsLatte\Runtime::renderFormBegin($form, []) /* line 29 */; - echo "\n"; - $iterations = 0; - foreach ($form['sex']->items as $key => $label) /* line 31 */ { - echo ' '; - if ($ʟ_label = end($this->global->formsStack)["sex"]->getLabelPart($key)) echo $ʟ_label->startTag(); - echo ' '; - echo end($this->global->formsStack)["sex"]->getControlPart($key) /* line 32 */; - echo ' '; - echo LR\Filters::escapeHtmlText($label) /* line 32 */; - if ($ʟ_label) echo $ʟ_label->endTag(); - echo ' - -'; - $iterations++; - } - echo 'global->formsStack)["sex"]; - echo $ʟ_input->getLabelPart()->attributes() /* line 35 */; - echo '> -global->formsStack)["sex"]; - echo $ʟ_input->getLabelPart()->attributes() /* line 36 */; - echo '>'; - echo $ʟ_input->getLabelPart()->getHtml() /* line 36 */; - echo ' - - - -'; - if ($ʟ_label = end($this->global->formsStack)["checkbox"]->getLabelPart("")) echo $ʟ_label->startTag(); - echo ' '; - echo end($this->global->formsStack)["checkbox"]->getControlPart("") /* line 41 */; - echo ' Label'; - if ($ʟ_label) echo $ʟ_label->endTag(); - echo ' - - -global->formsStack)["checkbox"]; - echo $ʟ_input->getLabelPart("")->attributes() /* line 44 */; - echo '>'; - echo $ʟ_input->getLabelPart()->getHtml() /* line 44 */; - echo ' - - - -'; - $iterations = 0; - foreach ($form['checklist']->items as $key => $label) /* line 49 */ { - echo ' '; - if ($ʟ_label = end($this->global->formsStack)["checklist"]->getLabelPart($key)) echo $ʟ_label->startTag(); - echo ' '; - echo end($this->global->formsStack)["checklist"]->getControlPart($key) /* line 50 */; - echo ' '; - echo LR\Filters::escapeHtmlText($label) /* line 50 */; - if ($ʟ_label) echo $ʟ_label->endTag(); - echo ' - global->formsStack)["checklist"]; - echo $ʟ_input->getLabelPart($key)->attributes() /* line 51 */; - echo '> global->formsStack)["checklist"]; - echo $ʟ_input->getControlPart($key)->addAttributes(['title' => null])->attributes() /* line 51 */; - echo '> -'; - $iterations++; - } - echo 'global->formsStack)["checklist"]; - echo $ʟ_input->getLabelPart()->attributes() /* line 53 */; - echo '> -global->formsStack)["checklist"]; - echo $ʟ_input->getLabelPart()->attributes() /* line 54 */; - echo '>'; - echo $ʟ_input->getLabelPart()->getHtml() /* line 54 */; - echo ' - - - -'; - $form = $this->global->formsStack[] = $this->global->uiControl["myForm"] /* line 58 */; - Nette\Bridges\FormsLatte\Runtime::initializeForm($form); - if (1) /* line 58 */ { - echo '
global->formsStack), ['id' => null, 'class' => null], false); - echo '> - global->formsStack)["username"]; - echo $ʟ_input->getControlPart()->attributes() /* line 59 */; - echo '> -'; - echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(array_pop($this->global->formsStack), false) /* line 58 */; - echo ' -'; - } - echo ' - -'; - $form = $this->global->formsStack[] = $this->global->uiControl["myForm"] /* line 63 */; - Nette\Bridges\FormsLatte\Runtime::initializeForm($form); - echo 'global->formsStack), ['class' => null], false); - echo '> - global->formsStack)["username"]; - echo $ʟ_input->getControlPart()->addAttributes(['class' => null])->attributes() /* line 64 */; - echo ($ʟ_tmp = array_filter(['nclass'])) ? ' class="' . LR\Filters::escapeHtmlAttr(implode(" ", array_unique($ʟ_tmp))) . '"' : "" /* line 64 */; - echo '> -'; - echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(array_pop($this->global->formsStack), false) /* line 63 */; - echo ' - - -'; - $form = $this->global->formsStack[] = is_object($ʟ_tmp = $this->global->uiControl['myForm']) ? $ʟ_tmp : $this->global->uiControl[$ʟ_tmp] /* line 68 */; - Nette\Bridges\FormsLatte\Runtime::initializeForm($form); - echo 'global->formsStack), [], false); - echo '> - global->formsStack)["username"]; - echo $ʟ_input->getControlPart()->attributes() /* line 69 */; - echo '> -'; - echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(array_pop($this->global->formsStack), false) /* line 68 */; - echo ' - - -global->formsStack)["select"]; - echo $ʟ_input->getControlPart()->attributes() /* line 73 */; - echo '>'; - echo $ʟ_input->getControl()->getHtml() /* line 73 */; - echo ' - - - - - -global->formsStack)["select"]; - echo $ʟ_input->getControlPart()->attributes() /* line 79 */; - echo '>'; - echo $ʟ_input->getControl()->getHtml() /* line 79 */; - echo ' -'; - echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(array_pop($this->global->formsStack)); - echo ' - - -'; - $form = $this->global->formsStack[] = $this->global->uiControl["myForm"] /* line 83 */; - echo 'global->formsStack)["sex"]; - echo $ʟ_input->getLabelPart()->attributes() /* line 84 */; - echo '>'; - echo $ʟ_input->getLabelPart()->getHtml() /* line 84 */; - echo ' -global->formsStack)["username"]; - echo $ʟ_input->getControlPart()->attributes() /* line 85 */; - echo '> -'; - array_pop($this->global->formsStack); -%A% diff --git a/tests/Forms.Latte2/expected/FormMacros.get.html b/tests/Forms.Latte2/expected/FormMacros.get.html deleted file mode 100644 index e3728281..00000000 --- a/tests/Forms.Latte2/expected/FormMacros.get.html +++ /dev/null @@ -1,5 +0,0 @@ -
- - -
-
\ No newline at end of file diff --git a/tests/Forms.Latte2/expected/FormMacros.get.php b/tests/Forms.Latte2/expected/FormMacros.get.php deleted file mode 100644 index ae17372c..00000000 --- a/tests/Forms.Latte2/expected/FormMacros.get.php +++ /dev/null @@ -1,19 +0,0 @@ -global->formsStack[] = $this->global->uiControl["myForm"]; - Nette\Bridges\FormsLatte\Runtime::initializeForm($form); - echo Nette\Bridges\FormsLatte\Runtime::renderFormBegin($form, []) /* line 1 */; - echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(array_pop($this->global->formsStack)); - echo ' - -'; - $form = $this->global->formsStack[] = $this->global->uiControl["myForm"] /* line 3 */; - Nette\Bridges\FormsLatte\Runtime::initializeForm($form); - echo 'global->formsStack), [], false); - echo '> -'; - echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(array_pop($this->global->formsStack), false) /* line 3 */; - echo ' -'; -%A% diff --git a/tests/Forms.Latte2/templates/forms.button.latte b/tests/Forms.Latte2/templates/forms.button.latte deleted file mode 100644 index 8e9969b3..00000000 --- a/tests/Forms.Latte2/templates/forms.button.latte +++ /dev/null @@ -1,9 +0,0 @@ -
- - - - -
global)->getControlPart())->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('send')->getControlPart())->attributes() /* line %d% */; echo '> global)->getControlPart())->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('send')->getControlPart())->attributes() /* line %d% */; echo '>'; echo LR\%a%::escape%a%($ʟ_elem->value) /* line %d% */; echo ' '; - echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(end($this->global->formsStack), false) /* line %d% */; + echo $this->global->forms->renderFormEnd(false) /* line %d% */; echo ' '; - array_pop($this->global->formsStack); + $this->global->forms->end(); %A% diff --git a/tests/Forms.Latte3/expected/forms.formContainer.php b/tests/Forms.Latte3/expected/forms.formContainer.php index 893cc8e3..6bd65b4e 100644 --- a/tests/Forms.Latte3/expected/forms.formContainer.php +++ b/tests/Forms.Latte3/expected/forms.formContainer.php @@ -1,46 +1,45 @@ global->formsStack[] = $this->global->uiControl['myForm'] /* line %d% */; - Nette\Bridges\FormsLatte\Runtime::initializeForm($form); - echo Nette\Bridges\FormsLatte\Runtime::renderFormBegin($form, []) /* line %d% */; + $this->global->forms->begin($form = $this->global->uiControl['myForm']) /* line %d% */; + echo $this->global->forms->renderFormBegin([]) /* line %d% */; echo ' '; - $this->global->formsStack[] = $formContainer = Nette\Bridges\FormsLatte\Runtime::item('cont1', $this->global) /* line %d% */; + $this->global->forms->begin($formContainer = $this->global->forms->item('cont1')) /* line %d% */; echo ' '; - array_pop($this->global->formsStack); - $formContainer = end($this->global->formsStack); + $this->global->forms->end(); + $formContainer = $this->global->forms->current(); - $this->global->formsStack[] = $formContainer = Nette\Bridges\FormsLatte\Runtime::item('items', $this->global) /* line %d% */; + $this->global->forms->begin($formContainer = $this->global->forms->item('items')) /* line %d% */; echo ' '; - array_pop($this->global->formsStack); - $formContainer = end($this->global->formsStack); + $this->global->forms->end(); + $formContainer = $this->global->forms->current(); echo '
'; - echo ($ʟ_label = Nette\Bridges\FormsLatte\Runtime::item('input1', $this->global)->getLabel()) /* line %d% */; + echo ($ʟ_label = $this->global->forms->item('input1')->getLabel()) /* line %d% */; echo ' '; - echo Nette\Bridges\FormsLatte\Runtime::item('input1', $this->global)->getControl() /* line %d% */; + echo $this->global->forms->item('input1')->getControl() /* line %d% */; echo '
'; - echo ($ʟ_label = Nette\Bridges\FormsLatte\Runtime::item('input2', $this->global)->getLabel()) /* line %d% */; + echo ($ʟ_label = $this->global->forms->item('input2')->getLabel()) /* line %d% */; echo ' '; - echo Nette\Bridges\FormsLatte\Runtime::item('input2', $this->global)->getControl() /* line %d% */; + echo $this->global->forms->item('input2')->getControl() /* line %d% */; echo '
'; - echo ($ʟ_label = Nette\Bridges\FormsLatte\Runtime::item('input3', $this->global)->getLabel()) /* line %d% */; + echo ($ʟ_label = $this->global->forms->item('input3')->getLabel()) /* line %d% */; echo ' '; - echo Nette\Bridges\FormsLatte\Runtime::item('input3', $this->global)->getControl() /* line %d% */; + echo $this->global->forms->item('input3')->getControl() /* line %d% */; echo '
Checkboxes '; - $this->global->formsStack[] = $formContainer = Nette\Bridges\FormsLatte\Runtime::item('cont2', $this->global) /* line %d% */; + $this->global->forms->begin($formContainer = $this->global->forms->item('cont2')) /* line %d% */; echo '
    '; foreach ($formContainer->controls as $name => $field) /* line %d% */ { echo '
  1. '; - echo Nette\Bridges\FormsLatte\Runtime::item($field, $this->global)->getControl() /* line %d% */; + echo $this->global->forms->item($field)->getControl() /* line %d% */; echo '
  2. '; @@ -48,24 +47,24 @@ echo '
'; - array_pop($this->global->formsStack); - $formContainer = end($this->global->formsStack); + $this->global->forms->end(); + $formContainer = $this->global->forms->current(); echo '
'; - echo ($ʟ_label = Nette\Bridges\FormsLatte\Runtime::item('input7', $this->global)->getLabel()) /* line %d% */; + echo ($ʟ_label = $this->global->forms->item('input7')->getLabel()) /* line %d% */; echo ' '; - echo Nette\Bridges\FormsLatte\Runtime::item('input7', $this->global)->getControl() /* line %d% */; + echo $this->global->forms->item('input7')->getControl() /* line %d% */; echo '
Items @@ -73,12 +72,12 @@ $items = [1, 2, 3] /* line %d% */; foreach ($items as $item) /* line %d% */ { if (!isset($formContainer[$item])) /* line %d% */ continue; - $this->global->formsStack[] = $formContainer = Nette\Bridges\FormsLatte\Runtime::item($item, $this->global) /* line %d% */; + $this->global->forms->begin($formContainer = $this->global->forms->item($item)) /* line %d% */; echo ' '; - echo Nette\Bridges\FormsLatte\Runtime::item('input', $this->global)->getControl() /* line %d% */; + echo $this->global->forms->item('input')->getControl() /* line %d% */; echo "\n"; - array_pop($this->global->formsStack); - $formContainer = end($this->global->formsStack); + $this->global->forms->end(); + $formContainer = $this->global->forms->current(); } @@ -86,18 +85,19 @@ echo '
'; - echo ($ʟ_label = Nette\Bridges\FormsLatte\Runtime::item('input8', $this->global)->getLabel()) /* line %d% */; + echo ($ʟ_label = $this->global->forms->item('input8')->getLabel()) /* line %d% */; echo ' '; - echo Nette\Bridges\FormsLatte\Runtime::item('input8', $this->global)->getControl() /* line %d% */; + echo $this->global->forms->item('input8')->getControl() /* line %d% */; echo '
'; - echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(array_pop($this->global->formsStack)) /* line %d% */; -%A% + echo $this->global->forms->renderFormEnd() /* line %d% */; + $this->global->forms->end(); +%A% \ No newline at end of file diff --git a/tests/Forms.Latte3/expected/forms.get.php b/tests/Forms.Latte3/expected/forms.get.php index 25af74d4..0fd2c1ed 100644 --- a/tests/Forms.Latte3/expected/forms.get.php +++ b/tests/Forms.Latte3/expected/forms.get.php @@ -1,21 +1,20 @@ global->formsStack[] = $this->global->uiControl['myForm'] /* line %d% */; - Nette\Bridges\FormsLatte\Runtime::initializeForm($form); - echo Nette\Bridges\FormsLatte\Runtime::renderFormBegin($form, []) /* line %d% */; - echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(array_pop($this->global->formsStack)) /* line %d% */; + $this->global->forms->begin($form = $this->global->uiControl['myForm']) /* line %d% */; + echo $this->global->forms->renderFormBegin([]) /* line %d% */; + echo $this->global->forms->renderFormEnd() /* line %d% */; + $this->global->forms->end(); echo ' '; - $form = $this->global->formsStack[] = $this->global->uiControl['myForm'] /* line %d% */; - Nette\Bridges\FormsLatte\Runtime::initializeForm($form); + $this->global->forms->begin($form = $this->global->uiControl['myForm']) /* line %d% */; echo 'global->formsStack), [], false) /* line %d% */; + echo $this->global->forms->renderFormBegin([], false) /* line %d% */; echo '> '; - echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(end($this->global->formsStack), false) /* line %d% */; + echo $this->global->forms->renderFormEnd(false) /* line %d% */; echo ' '; - array_pop($this->global->formsStack); -%A% + $this->global->forms->end(); +%A% \ No newline at end of file diff --git a/tests/Forms.Latte3/expected/forms.php b/tests/Forms.Latte3/expected/forms.php index 55e8d735..9ebde5a3 100644 --- a/tests/Forms.Latte3/expected/forms.php +++ b/tests/Forms.Latte3/expected/forms.php @@ -1,97 +1,96 @@ global->formsStack[] = $this->global->uiControl['myForm'] /* line %d% */; - Nette\Bridges\FormsLatte\Runtime::initializeForm($form); - echo Nette\Bridges\FormsLatte\Runtime::renderFormBegin($form, ['id' => 'myForm', 'class' => 'ajax']) /* line %d% */; + $this->global->forms->begin($form = $this->global->uiControl['myForm']) /* line %d% */; + echo $this->global->forms->renderFormBegin(['id' => 'myForm', 'class' => 'ajax']) /* line %d% */; echo "\n"; foreach (['id', 'username', 'select', 'area', 'send'] as $name) /* line %d% */ { echo ' '; - echo ($ʟ_label = Nette\Bridges\FormsLatte\Runtime::item($name, $this->global)->getLabel()) /* line %d% */; + echo ($ʟ_label = $this->global->forms->item($name)->getLabel()) /* line %d% */; echo ' '; - echo Nette\Bridges\FormsLatte\Runtime::item($name, $this->global)->getControl()->addAttributes(['title' => 'Hello', 'size' => 10]) /* line %d% */; + echo $this->global->forms->item($name)->getControl()->addAttributes(['title' => 'Hello', 'size' => 10]) /* line %d% */; echo ' '; - echo LR\%a%::escape%a%(Nette\Bridges\FormsLatte\Runtime::item($name, $this->global)->getError()) /* line %d% */; + echo LR\Filters::escapeHtmlText($this->global->forms->item($name)->getError()) /* line %d% */; echo '
'; - echo ($ʟ_label = Nette\Bridges\FormsLatte\Runtime::item($form[$name], $this->global)->getLabel())?->addAttributes(['title' => 'hello'])?->startTag() /* line %d% */; + echo ($ʟ_label = $this->global->forms->item($form[$name])->getLabel())?->addAttributes(['title' => 'hello'])?->startTag() /* line %d% */; echo ' '; - echo Nette\Bridges\FormsLatte\Runtime::item($form[$name], $this->global)->getControl()->addAttributes(['title' => 'Hello', 'size' => 10]) /* line %d% */; + echo $this->global->forms->item($form[$name])->getControl()->addAttributes(['title' => 'Hello', 'size' => 10]) /* line %d% */; echo ' '; echo $ʟ_label?->endTag() /* line %d% */; echo ' '; - echo LR\%a%::escape%a%(Nette\Bridges\FormsLatte\Runtime::item($form[$name], $this->global)->getError()) /* line %d% */; + echo LR\Filters::escapeHtmlText($this->global->forms->item($form[$name])->getError()) /* line %d% */; echo "\n"; } echo ' '; - echo ($ʟ_label = Nette\Bridges\FormsLatte\Runtime::item($form['username'], $this->global)->getLabel()) /* line %d% */; + echo ($ʟ_label = $this->global->forms->item($form['username'])->getLabel()) /* line %d% */; echo ' global)->getLabelPart())->addAttributes(['title' => null])->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('username')->getLabelPart())->addAttributes(['title' => null])->attributes() /* line %d% */; echo ' title=hello>Name global)->getControlPart())->addAttributes(['value' => null, 'type' => null, 'class' => null])->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('username')->getControlPart())->addAttributes(['value' => null, 'type' => null, 'class' => null])->attributes() /* line %d% */; echo '> global)->getLabelPart())->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item($form['username'])->getLabelPart())->attributes() /* line %d% */; echo '> global)->getLabelPart())->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item($form['username'])->getLabelPart())->attributes() /* line %d% */; echo '>'; echo $ʟ_elem->getHtml() /* line %d% */; echo ' global)->getControlPart())->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item($form['username'])->getControlPart())->attributes() /* line %d% */; echo '> '; - echo ($ʟ_label = Nette\Bridges\FormsLatte\Runtime::item('my', $this->global)->getLabel()) /* line %d% */; - echo Nette\Bridges\FormsLatte\Runtime::item('my', $this->global)->getControl() /* line %d% */; + echo ($ʟ_label = $this->global->forms->item('my')->getLabel()) /* line %d% */; + echo $this->global->forms->item('my')->getControl() /* line %d% */; echo "\n"; - echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(array_pop($this->global->formsStack)) /* line %d% */; + echo $this->global->forms->renderFormEnd() /* line %d% */; + $this->global->forms->end(); echo ' '; - $form = $this->global->formsStack[] = $this->global->uiControl['myForm'] /* line %d% */; - Nette\Bridges\FormsLatte\Runtime::initializeForm($form); - echo Nette\Bridges\FormsLatte\Runtime::renderFormBegin($form, []) /* line %d% */; - echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(array_pop($this->global->formsStack)) /* line %d% */; + $this->global->forms->begin($form = $this->global->uiControl['myForm']) /* line %d% */; + echo $this->global->forms->renderFormBegin([]) /* line %d% */; + echo $this->global->forms->renderFormEnd() /* line %d% */; + $this->global->forms->end(); echo ' '; - $form = $this->global->formsStack[] = $this->global->uiControl['myForm'] /* line %d% */; - Nette\Bridges\FormsLatte\Runtime::initializeForm($form); - echo Nette\Bridges\FormsLatte\Runtime::renderFormBegin($form, []) /* line %d% */; + $this->global->forms->begin($form = $this->global->uiControl['myForm']) /* line %d% */; + echo $this->global->forms->renderFormBegin([]) /* line %d% */; echo "\n"; foreach ($form['sex']->items as $key => $label) /* line %d% */ { echo ' '; - echo ($ʟ_label = Nette\Bridges\FormsLatte\Runtime::item('sex', $this->global)->getLabelPart($key))?->startTag() /* line %d% */; + echo ($ʟ_label = $this->global->forms->item('sex')->getLabelPart($key))?->startTag() /* line %d% */; echo ' '; - echo Nette\Bridges\FormsLatte\Runtime::item('sex', $this->global)->getControlPart($key) /* line %d% */; + echo $this->global->forms->item('sex')->getControlPart($key) /* line %d% */; echo ' '; echo LR\%a%::escape%a%($label) /* line %d% */; echo $ʟ_label?->endTag() /* line %d% */; echo ' global)->getLabelPart($key))->addAttributes(['title' => null])->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('sex')->getLabelPart($key))->addAttributes(['title' => null])->attributes() /* line %d% */; echo ' title=hello> global)->getControlPart($key))->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('sex')->getControlPart($key))->attributes() /* line %d% */; echo '> global)->getLabelPart($key))->addAttributes(['title' => null])->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('sex')->getLabelPart($key))->addAttributes(['title' => null])->attributes() /* line %d% */; echo ' title=hello>'; echo $ʟ_elem->getHtml() /* line %d% */; echo ' @@ -100,47 +99,47 @@ } echo 'global)->getLabelPart())->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('sex')->getLabelPart())->attributes() /* line %d% */; echo '> global)->getLabelPart())->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('sex')->getLabelPart())->attributes() /* line %d% */; echo '>'; echo $ʟ_elem->getHtml() /* line %d% */; echo ' global)->getLabelPart())->addAttributes(['title' => null])->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('sex')->getLabelPart())->addAttributes(['title' => null])->attributes() /* line %d% */; echo ' title="hello">'; echo $ʟ_elem->getHtml() /* line %d% */; echo ' global)->getControlPart("{$key}"))->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item($form['sex'])->getControlPart("{$key}"))->attributes() /* line %d% */; echo '> '; - echo ($ʟ_label = Nette\Bridges\FormsLatte\Runtime::item('checkbox', $this->global)->getLabelPart(''))?->startTag() /* line %d% */; + echo ($ʟ_label = $this->global->forms->item('checkbox')->getLabelPart(''))?->startTag() /* line %d% */; echo ' '; - echo Nette\Bridges\FormsLatte\Runtime::item('checkbox', $this->global)->getControlPart('') /* line %d% */; + echo $this->global->forms->item('checkbox')->getControlPart('') /* line %d% */; echo ' Label'; echo $ʟ_label?->endTag() /* line %d% */; echo ' global)->getLabelPart(''))->addAttributes(['title' => null])->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('checkbox')->getLabelPart(''))->addAttributes(['title' => null])->attributes() /* line %d% */; echo ' title=hello> global)->getControlPart(''))->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('checkbox')->getControlPart(''))->attributes() /* line %d% */; echo '> global)->getLabelPart())->addAttributes(['title' => null])->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('checkbox')->getLabelPart())->addAttributes(['title' => null])->attributes() /* line %d% */; echo ' title=hello> global)->getControlPart())->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('checkbox')->getControlPart())->attributes() /* line %d% */; echo '> global)->getLabelPart(''))->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('checkbox')->getLabelPart(''))->attributes() /* line %d% */; echo '>'; echo $ʟ_elem->getHtml() /* line %d% */; echo ' global)->getLabelPart())->addAttributes(['title' => null])->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('checkbox')->getLabelPart())->addAttributes(['title' => null])->attributes() /* line %d% */; echo ' title=hello>'; echo $ʟ_elem->getHtml() /* line %d% */; echo ' @@ -149,20 +148,20 @@ '; foreach ($form['checklist']->items as $key => $label) /* line %d% */ { echo ' '; - echo ($ʟ_label = Nette\Bridges\FormsLatte\Runtime::item('checklist', $this->global)->getLabelPart($key))?->startTag() /* line %d% */; + echo ($ʟ_label = $this->global->forms->item('checklist')->getLabelPart($key))?->startTag() /* line %d% */; echo ' '; - echo Nette\Bridges\FormsLatte\Runtime::item('checklist', $this->global)->getControlPart($key) /* line %d% */; + echo $this->global->forms->item('checklist')->getControlPart($key) /* line %d% */; echo ' '; echo LR\%a%::escape%a%($label) /* line %d% */; echo $ʟ_label?->endTag() /* line %d% */; echo ' global)->getLabelPart($key))->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('checklist')->getLabelPart($key))->attributes() /* line %d% */; echo '> global)->getControlPart($key))->addAttributes(['title' => null])->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('checklist')->getControlPart($key))->addAttributes(['title' => null])->attributes() /* line %d% */; echo ' title=hello> global)->getLabelPart($key))->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('checklist')->getLabelPart($key))->attributes() /* line %d% */; echo '>'; echo $ʟ_elem->getHtml() /* line %d% */; echo ' @@ -171,15 +170,15 @@ } echo 'global)->getLabelPart())->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('checklist')->getLabelPart())->attributes() /* line %d% */; echo '> global)->getLabelPart())->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('checklist')->getLabelPart())->attributes() /* line %d% */; echo '>'; echo $ʟ_elem->getHtml() /* line %d% */; echo ' global)->getLabelPart())->addAttributes(['title' => null])->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('checklist')->getLabelPart())->addAttributes(['title' => null])->attributes() /* line %d% */; echo ' title="hello">'; echo $ʟ_elem->getHtml() /* line %d% */; echo ' @@ -187,93 +186,91 @@ '; if (1) /* line %d% */ { - $form = $this->global->formsStack[] = $this->global->uiControl['myForm'] /* line %d% */; - Nette\Bridges\FormsLatte\Runtime::initializeForm($form); + $this->global->forms->begin($form = $this->global->uiControl['myForm']) /* line %d% */; echo 'global->formsStack), ['id' => null, 'class' => null], false) /* line %d% */; + echo $this->global->forms->renderFormBegin(['id' => null, 'class' => null], false) /* line %d% */; echo ' id="myForm" class="ajax"> global)->getControlPart())->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('username')->getControlPart())->attributes() /* line %d% */; echo '> '; - echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(end($this->global->formsStack), false) /* line %d% */; + echo $this->global->forms->renderFormEnd(false) /* line %d% */; echo ' '; - array_pop($this->global->formsStack); + $this->global->forms->end(); } echo ' '; - $form = $this->global->formsStack[] = $this->global->uiControl['myForm'] /* line %d% */; - Nette\Bridges\FormsLatte\Runtime::initializeForm($form); + $this->global->forms->begin($form = $this->global->uiControl['myForm']) /* line %d% */; echo 'global->formsStack), ['class' => null], false) /* line %d% */; + echo $this->global->forms->renderFormBegin(['class' => null], false) /* line %d% */; echo ($ʟ_tmp = array_filter(['nclass'])) ? ' class="' . LR\%a%::escape%a%(implode(" ", array_unique($ʟ_tmp))) . '"' : "" /* line %d% */; echo '> global)->getControlPart())->addAttributes(['class' => null])->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('username')->getControlPart())->addAttributes(['class' => null])->attributes() /* line %d% */; echo ($ʟ_tmp = array_filter(['nclass'])) ? ' class="' . LR\%a%::escape%a%(implode(" ", array_unique($ʟ_tmp))) . '"' : "" /* line %d% */; echo '> '; - echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(end($this->global->formsStack), false) /* line %d% */; + echo $this->global->forms->renderFormEnd(false) /* line %d% */; echo ' '; - array_pop($this->global->formsStack); + $this->global->forms->end(); echo ' '; - $form = $this->global->formsStack[] = is_object($ʟ_tmp = $this->global->uiControl['myForm']) ? $ʟ_tmp : $this->global->uiControl[$ʟ_tmp] /* line %d% */; - Nette\Bridges\FormsLatte\Runtime::initializeForm($form); + $this->global->forms->begin($form = (is_object($ʟ_tmp = $this->global->uiControl['myForm']) ? $ʟ_tmp : $this->global->uiControl[$ʟ_tmp])) /* line %d% */; echo 'global->formsStack), [], false) /* line %d% */; + echo $this->global->forms->renderFormBegin([], false) /* line %d% */; echo '> global)->getControlPart())->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('username')->getControlPart())->attributes() /* line %d% */; echo '> '; - echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(end($this->global->formsStack), false) /* line %d% */; + echo $this->global->forms->renderFormEnd(false) /* line %d% */; echo ' '; - array_pop($this->global->formsStack); + $this->global->forms->end(); echo ' global)->getControlPart())->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('select')->getControlPart())->attributes() /* line %d% */; echo '>'; echo $ʟ_elem->getHtml() /* line %d% */; echo ' global)->getControlPart())->addAttributes(['title' => null])->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('area')->getControlPart())->addAttributes(['title' => null])->attributes() /* line %d% */; %A% echo $ʟ_elem->getHtml() /* line %d% */; echo ' global)->getControlPart())->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('select')->getControlPart())->attributes() /* line %d% */; echo '>'; echo $ʟ_elem->getHtml() /* line %d% */; echo ' '; - echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(array_pop($this->global->formsStack)) /* line %d% */; + echo $this->global->forms->renderFormEnd() /* line %d% */; + $this->global->forms->end(); echo ' '; - $form = $this->global->formsStack[] = $this->global->uiControl['myForm'] /* line %d% */; - Nette\Bridges\FormsLatte\Runtime::initializeForm($form); + $this->global->forms->begin($form = $this->global->uiControl['myForm']) /* line %d% */; echo ' global)->getLabelPart())->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('sex')->getLabelPart())->attributes() /* line %d% */; echo '>'; echo $ʟ_elem->getHtml() /* line %d% */; echo ' global)->getControlPart())->attributes() /* line %d% */; + echo ($ʟ_elem = $this->global->forms->item('username')->getControlPart())->attributes() /* line %d% */; echo '> '; - array_pop($this->global->formsStack) /* line %d% */; + /* line %d% */; + $this->global->forms->end(); %A% diff --git a/tests/Forms.Latte3/n-name.form.phpt b/tests/Forms.Latte3/n-name.form.phpt index 2d23307a..6192700a 100644 --- a/tests/Forms.Latte3/n-name.form.phpt +++ b/tests/Forms.Latte3/n-name.form.phpt @@ -15,14 +15,13 @@ $latte->addExtension(new FormsExtension); Assert::match( <<<'XX' %A% - $form = $this->global->formsStack[] = $this->global->uiControl['foo'] /* line 1 */; - Nette\Bridges\FormsLatte\Runtime::initializeForm($form); + $this->global->forms->begin($form = $this->global->uiControl['foo']) /* line 1 */; echo 'global->formsStack), [], false) /* line 1 */; + echo $this->global->forms->renderFormBegin([], false) /* line 1 */; echo '>'; - echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(end($this->global->formsStack), false) /* line 1 */; + echo $this->global->forms->renderFormEnd(false) /* line 1 */; echo ''; - array_pop($this->global->formsStack); + $this->global->forms->end(); %A% XX, $latte->compile('
'), @@ -32,17 +31,16 @@ Assert::match( Assert::match( <<<'XX' %A% - $form = $this->global->formsStack[] = $this->global->uiControl['foo'] /* line 1 */; - Nette\Bridges\FormsLatte\Runtime::initializeForm($form); + $this->global->forms->begin($form = $this->global->uiControl['foo']) /* line 1 */; $ʟ_tag[0] = ''; if (0) /* line 1 */ { %A% - echo Nette\Bridges\FormsLatte\Runtime::renderFormBegin(end($this->global->formsStack), [], false) /* line 1 */; + echo $this->global->forms->renderFormBegin([], false) /* line 1 */; echo '>'; } - echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(end($this->global->formsStack), false) /* line 1 */; + echo $this->global->forms->renderFormEnd(false) /* line 1 */; echo $ʟ_tag[0]; - array_pop($this->global->formsStack); + $this->global->forms->end(); %A% XX, $latte->compile('
'), diff --git a/tests/Forms.Latte3/n-name.input.phpt b/tests/Forms.Latte3/n-name.input.phpt index b8d5ff76..16484545 100644 --- a/tests/Forms.Latte3/n-name.input.phpt +++ b/tests/Forms.Latte3/n-name.input.phpt @@ -13,12 +13,12 @@ $latte->setLoader(new Latte\Loaders\StringLoader); $latte->addExtension(new FormsExtension); Assert::match( - '%A%echo ($ʟ_elem = Nette\Bridges\FormsLatte\Runtime::item(\'foo\', $this->global)->getControlPart())->attributes() %A%', + '%A%echo ($ʟ_elem = $this->global->forms->item(\'foo\')->getControlPart())->attributes() %A%', $latte->compile(''), ); Assert::match( - '%A%echo ($ʟ_elem = Nette\Bridges\FormsLatte\Runtime::item(\'foo\', $this->global)->getControlPart(\'\'))->attributes() %A%', + '%A%echo ($ʟ_elem = $this->global->forms->item(\'foo\')->getControlPart(\'\'))->attributes() %A%', $latte->compile(''), ); @@ -29,11 +29,11 @@ Assert::exception( ); Assert::match( - '%A%echo ($ʟ_elem = Nette\Bridges\FormsLatte\Runtime::item(\'foo\', $this->global)->getControlPart(\'x\'))->attributes() %A%', + '%A%echo ($ʟ_elem = $this->global->forms->item(\'foo\')->getControlPart(\'x\'))->attributes() %A%', $latte->compile(''), ); Assert::match( - '%A%echo ($ʟ_elem = Nette\Bridges\FormsLatte\Runtime::item(\'foo\', $this->global)->getControlPart(\'x\'))->attributes() %A%', + '%A%echo ($ʟ_elem = $this->global->forms->item(\'foo\')->getControlPart(\'x\'))->attributes() %A%', $latte->compile(''), ); diff --git a/tests/Forms.Latte3/{input}.phpt b/tests/Forms.Latte3/{input}.phpt index e71ef81c..02b23622 100644 --- a/tests/Forms.Latte3/{input}.phpt +++ b/tests/Forms.Latte3/{input}.phpt @@ -13,22 +13,22 @@ $latte->setLoader(new Latte\Loaders\StringLoader); $latte->addExtension(new FormsExtension); Assert::match( - '%A%echo Nette\Bridges\FormsLatte\Runtime::item(\'foo\', $this->global)->getControl() %A%', + '%A%echo $this->global->forms->item(\'foo\')->getControl() %A%', $latte->compile('{input foo}'), ); Assert::match( - '%A%echo Nette\Bridges\FormsLatte\Runtime::item(\'foo\', $this->global)->getControl()->addAttributes([\'class\' => \'foo\']) %A%', + '%A%echo $this->global->forms->item(\'foo\')->getControl()->addAttributes([\'class\' => \'foo\']) %A%', $latte->compile('{input foo class => foo}'), ); Assert::match( - '%A%echo Nette\Bridges\FormsLatte\Runtime::item(\'foo\', $this->global)->getControl()->addAttributes([\'class\' => \'foo\']) %A%', + '%A%echo $this->global->forms->item(\'foo\')->getControl()->addAttributes([\'class\' => \'foo\']) %A%', $latte->compile('{input foo, class => foo}'), ); Assert::match( - '%A%echo Nette\Bridges\FormsLatte\Runtime::item(\'foo\', $this->global)->getControlPart(\'\') %A%', + '%A%echo $this->global->forms->item(\'foo\')->getControlPart(\'\') %A%', $latte->compile('{input foo:}'), ); @@ -39,31 +39,31 @@ Assert::exception( ); Assert::match( - '%A%echo Nette\Bridges\FormsLatte\Runtime::item(\'foo\', $this->global)->getControlPart(\'\') %A%', + '%A%echo $this->global->forms->item(\'foo\')->getControlPart(\'\') %A%', $latte->compile('{input foo:,}'), ); Assert::match( - '%A%echo Nette\Bridges\FormsLatte\Runtime::item(\'foo\', $this->global)->getControlPart(\'\')->addAttributes([\'class\' => \'foo\']) %A%', + '%A%echo $this->global->forms->item(\'foo\')->getControlPart(\'\')->addAttributes([\'class\' => \'foo\']) %A%', $latte->compile('{input foo:, class => foo}'), ); Assert::match( - '%A%echo Nette\Bridges\FormsLatte\Runtime::item(\'foo\', $this->global)->getControlPart(\'x\') %A%', + '%A%echo $this->global->forms->item(\'foo\')->getControlPart(\'x\') %A%', $latte->compile('{input foo:x}'), ); Assert::match( - '%A%echo Nette\Bridges\FormsLatte\Runtime::item(\'foo\', $this->global)->getControlPart(\'x\')->addAttributes([\'class\' => \'foo\']) %A%', + '%A%echo $this->global->forms->item(\'foo\')->getControlPart(\'x\')->addAttributes([\'class\' => \'foo\']) %A%', $latte->compile('{input foo:x, class => foo}'), ); Assert::match( - '%A%echo Nette\Bridges\FormsLatte\Runtime::item(\'foo\', $this->global)->getControlPart(\'x\') %A%', + '%A%echo $this->global->forms->item(\'foo\')->getControlPart(\'x\') %A%', $latte->compile('{input "foo":"x"}'), ); Assert::match( - '%A%echo Nette\Bridges\FormsLatte\Runtime::item(\'foo\', $this->global)->getControlPart(\'x\') %A%', + '%A%echo $this->global->forms->item(\'foo\')->getControlPart(\'x\') %A%', $latte->compile('{input "foo" : "x"}'), ); diff --git a/tests/Forms.Latte3/{label}.phpt b/tests/Forms.Latte3/{label}.phpt index d2860420..b09ceca0 100644 --- a/tests/Forms.Latte3/{label}.phpt +++ b/tests/Forms.Latte3/{label}.phpt @@ -13,22 +13,22 @@ $latte->setLoader(new Latte\Loaders\StringLoader); $latte->addExtension(new FormsExtension); Assert::match( - '%A%echo ($ʟ_label = Nette\Bridges\FormsLatte\Runtime::item(\'foo\', $this->global)->getLabel()) %A%', + '%A%echo ($ʟ_label = $this->global->forms->item(\'foo\')->getLabel()) %A%', $latte->compile('{label foo /}'), ); Assert::match( - '%A%echo ($ʟ_label = Nette\Bridges\FormsLatte\Runtime::item(\'foo\', $this->global)->getLabel())?->addAttributes([\'class\' => \'foo\']) %A%', + '%A%echo ($ʟ_label = $this->global->forms->item(\'foo\')->getLabel())?->addAttributes([\'class\' => \'foo\']) %A%', $latte->compile('{label foo class => foo /}'), ); Assert::match( - '%A%echo ($ʟ_label = Nette\Bridges\FormsLatte\Runtime::item(\'foo\', $this->global)->getLabel())?->addAttributes([\'class\' => \'foo\']) %A%', + '%A%echo ($ʟ_label = $this->global->forms->item(\'foo\')->getLabel())?->addAttributes([\'class\' => \'foo\']) %A%', $latte->compile('{label foo, class => foo /}'), ); Assert::match( - '%A%echo ($ʟ_label = Nette\Bridges\FormsLatte\Runtime::item(\'foo\', $this->global)->getLabelPart(\'\')) %A%', + '%A%echo ($ʟ_label = $this->global->forms->item(\'foo\')->getLabelPart(\'\')) %A%', $latte->compile('{label foo: /}'), ); @@ -39,31 +39,31 @@ Assert::exception( ); Assert::match( - '%A%echo ($ʟ_label = Nette\Bridges\FormsLatte\Runtime::item(\'foo\', $this->global)->getLabelPart(\'\')) %A%', + '%A%echo ($ʟ_label = $this->global->forms->item(\'foo\')->getLabelPart(\'\')) %A%', $latte->compile('{label foo:, /}'), ); Assert::match( - '%A%echo ($ʟ_label = Nette\Bridges\FormsLatte\Runtime::item(\'foo\', $this->global)->getLabelPart(\'\'))?->addAttributes([\'class\' => \'foo\']) %A%', + '%A%echo ($ʟ_label = $this->global->forms->item(\'foo\')->getLabelPart(\'\'))?->addAttributes([\'class\' => \'foo\']) %A%', $latte->compile('{label foo:, class => foo /}'), ); Assert::match( - '%A%echo ($ʟ_label = Nette\Bridges\FormsLatte\Runtime::item(\'foo\', $this->global)->getLabelPart(\'x\')) %A%', + '%A%echo ($ʟ_label = $this->global->forms->item(\'foo\')->getLabelPart(\'x\')) %A%', $latte->compile('{label foo:x /}'), ); Assert::match( - '%A%echo ($ʟ_label = Nette\Bridges\FormsLatte\Runtime::item(\'foo\', $this->global)->getLabelPart(\'x\'))?->addAttributes([\'class\' => \'foo\']) %A%', + '%A%echo ($ʟ_label = $this->global->forms->item(\'foo\')->getLabelPart(\'x\'))?->addAttributes([\'class\' => \'foo\']) %A%', $latte->compile('{label foo:x, class => foo /}'), ); Assert::match( - '%A%echo ($ʟ_label = Nette\Bridges\FormsLatte\Runtime::item(\'foo\', $this->global)->getLabelPart(\'x\')) %A%', + '%A%echo ($ʟ_label = $this->global->forms->item(\'foo\')->getLabelPart(\'x\')) %A%', $latte->compile('{label "foo":"x" /}'), ); Assert::match( - '%A%echo ($ʟ_label = Nette\Bridges\FormsLatte\Runtime::item(\'foo\', $this->global)->getLabelPart(\'x\')) %A%', + '%A%echo ($ʟ_label = $this->global->forms->item(\'foo\')->getLabelPart(\'x\')) %A%', $latte->compile('{label "foo" : "x" /}'), ); From eacf7b5df5eeb3f81fcd28e231b56ee4bd89df9b Mon Sep 17 00:00:00 2001 From: David Grudl Date: Mon, 9 Jan 2023 21:57:49 +0100 Subject: [PATCH 04/15] added deprecated notices --- src/Forms/Container.php | 6 +- src/Forms/Controls/Checkbox.php | 3 +- src/Forms/Controls/CsrfProtection.php | 2 +- src/Forms/Controls/SelectBox.php | 2 +- src/Forms/Controls/UploadControl.php | 2 +- src/Forms/Form.php | 68 +++++++++++----------- src/Forms/Rendering/DataClassGenerator.php | 2 +- src/Forms/Rendering/LatteRenderer.php | 2 +- 8 files changed, 45 insertions(+), 42 deletions(-) diff --git a/src/Forms/Container.php b/src/Forms/Container.php index de730b93..af4b26bd 100644 --- a/src/Forms/Container.php +++ b/src/Forms/Container.php @@ -172,9 +172,10 @@ public function getUntrustedValues(string|object|null $returnType = null, ?array } - /** @deprecated use getUntrustedValues() */ + #[\Deprecated('use getUntrustedValues()')] public function getUnsafeValues($returnType, ?array $controls = null) { + trigger_error(__METHOD__ . '() was renamed to getUntrustedValues()', E_USER_DEPRECATED); return $this->getUntrustedValues($returnType, $controls); } @@ -556,9 +557,10 @@ public function addImageButton(string $name, ?string $src = null, ?string $alt = } - /** @deprecated use addImageButton() */ + #[\Deprecated('use addImageButton()')] public function addImage(): Controls\ImageButton { + trigger_error(__METHOD__ . '() was renamed to addImageButton()', E_USER_DEPRECATED); return $this->addImageButton(...func_get_args()); } diff --git a/src/Forms/Controls/Checkbox.php b/src/Forms/Controls/Checkbox.php index 0bbe08f3..ee1bdf2a 100644 --- a/src/Forms/Controls/Checkbox.php +++ b/src/Forms/Controls/Checkbox.php @@ -90,9 +90,10 @@ public function getContainerPrototype(): Html } - /** @deprecated use getContainerPrototype() */ + #[\Deprecated('use getContainerPrototype()')] public function getSeparatorPrototype(): Html { + trigger_error(__METHOD__ . '() was renamed to getContainerPrototype()', E_USER_DEPRECATED); return $this->container; } } diff --git a/src/Forms/Controls/CsrfProtection.php b/src/Forms/Controls/CsrfProtection.php index 00538812..b204e030 100644 --- a/src/Forms/Controls/CsrfProtection.php +++ b/src/Forms/Controls/CsrfProtection.php @@ -22,7 +22,7 @@ class CsrfProtection extends HiddenField { public const Protection = 'Nette\Forms\Controls\CsrfProtection::validateCsrf'; - /** @deprecated use CsrfProtection::Protection */ + #[\Deprecated('use CsrfProtection::Protection')] public const PROTECTION = self::Protection; public ?Nette\Http\Session $session = null; diff --git a/src/Forms/Controls/SelectBox.php b/src/Forms/Controls/SelectBox.php index 17d05fdb..9d19a85a 100644 --- a/src/Forms/Controls/SelectBox.php +++ b/src/Forms/Controls/SelectBox.php @@ -22,7 +22,7 @@ class SelectBox extends ChoiceControl /** validation rule */ public const Valid = ':selectBoxValid'; - /** @deprecated use SelectBox::Valid */ + #[\Deprecated('use SelectBox::Valid')] public const VALID = self::Valid; /** of option / optgroup */ diff --git a/src/Forms/Controls/UploadControl.php b/src/Forms/Controls/UploadControl.php index fdcca95a..250b9473 100644 --- a/src/Forms/Controls/UploadControl.php +++ b/src/Forms/Controls/UploadControl.php @@ -26,7 +26,7 @@ class UploadControl extends BaseControl /** validation rule */ public const Valid = ':uploadControlValid'; - /** @deprecated use UploadControl::Valid */ + #[\Deprecated('use UploadControl::Valid')] public const VALID = self::Valid; private bool $nullable = false; diff --git a/src/Forms/Form.php b/src/Forms/Form.php index c10551d9..cd544494 100644 --- a/src/Forms/Form.php +++ b/src/Forms/Form.php @@ -85,106 +85,106 @@ class Form extends Container implements Nette\HtmlStringable /** @internal protection token ID */ public const ProtectorId = '_token_'; - /** @deprecated use Form::Equal */ + #[\Deprecated('use Form::Equal')] public const EQUAL = self::Equal; - /** @deprecated use Form::IsIn */ + #[\Deprecated('use Form::IsIn')] public const IS_IN = self::IsIn; - /** @deprecated use Form::NotEqual */ + #[\Deprecated('use Form::NotEqual')] public const NOT_EQUAL = self::NotEqual; - /** @deprecated use Form::IsNotIn */ + #[\Deprecated('use Form::IsNotIn')] public const IS_NOT_IN = self::IsNotIn; - /** @deprecated use Form::Filled */ + #[\Deprecated('use Form::Filled')] public const FILLED = self::Filled; - /** @deprecated use Form::Blank */ + #[\Deprecated('use Form::Blank')] public const BLANK = self::Blank; - /** @deprecated use Form::Required */ + #[\Deprecated('use Form::Required')] public const REQUIRED = self::Required; - /** @deprecated use Form::Valid */ + #[\Deprecated('use Form::Valid')] public const VALID = self::Valid; - /** @deprecated use Form::Submitted */ + #[\Deprecated('use Form::Submitted')] public const SUBMITTED = self::Submitted; - /** @deprecated use Form::MinLength */ + #[\Deprecated('use Form::MinLength')] public const MIN_LENGTH = self::MinLength; - /** @deprecated use Form::MaxLength */ + #[\Deprecated('use Form::MaxLength')] public const MAX_LENGTH = self::MaxLength; - /** @deprecated use Form::Length */ + #[\Deprecated('use Form::Length')] public const LENGTH = self::Length; - /** @deprecated use Form::Email */ + #[\Deprecated('use Form::Email')] public const EMAIL = self::Email; - /** @deprecated use Form::Pattern */ + #[\Deprecated('use Form::Pattern')] public const PATTERN = self::Pattern; - /** @deprecated use Form::PatternCI */ + #[\Deprecated('use Form::PatternCI')] public const PATTERN_ICASE = self::PatternInsensitive; - /** @deprecated use Form::Integer */ + #[\Deprecated('use Form::Integer')] public const INTEGER = self::Integer; - /** @deprecated use Form::Numeric */ + #[\Deprecated('use Form::Numeric')] public const NUMERIC = self::Numeric; - /** @deprecated use Form::Float */ + #[\Deprecated('use Form::Float')] public const FLOAT = self::Float; - /** @deprecated use Form::Min */ + #[\Deprecated('use Form::Min')] public const MIN = self::Min; - /** @deprecated use Form::Max */ + #[\Deprecated('use Form::Max')] public const MAX = self::Max; - /** @deprecated use Form::Range */ + #[\Deprecated('use Form::Range')] public const RANGE = self::Range; - /** @deprecated use Form::Count */ + #[\Deprecated('use Form::Count')] public const COUNT = self::Count; - /** @deprecated use Form::MaxFileSize */ + #[\Deprecated('use Form::MaxFileSize')] public const MAX_FILE_SIZE = self::MaxFileSize; - /** @deprecated use Form::MimeType */ + #[\Deprecated('use Form::MimeType')] public const MIME_TYPE = self::MimeType; - /** @deprecated use Form::Image */ + #[\Deprecated('use Form::Image')] public const IMAGE = self::Image; - /** @deprecated use Form::MaxPostSize */ + #[\Deprecated('use Form::MaxPostSize')] public const MAX_POST_SIZE = self::MaxPostSize; - /** @deprecated use Form::Get */ + #[\Deprecated('use Form::Get')] public const GET = self::Get; - /** @deprecated use Form::Post */ + #[\Deprecated('use Form::Post')] public const POST = self::Post; - /** @deprecated use Form::DataText */ + #[\Deprecated('use Form::DataText')] public const DATA_TEXT = self::DataText; - /** @deprecated use Form::DataLine */ + #[\Deprecated('use Form::DataLine')] public const DATA_LINE = self::DataLine; - /** @deprecated use Form::DataFile */ + #[\Deprecated('use Form::DataFile')] public const DATA_FILE = self::DataFile; - /** @deprecated use Form::DataKeys */ + #[\Deprecated('use Form::DataKeys')] public const DATA_KEYS = self::DataKeys; - /** @deprecated use Form::TrackerId */ + #[\Deprecated('use Form::TrackerId')] public const TRACKER_ID = self::TrackerId; - /** @deprecated use Form::ProtectorId */ + #[\Deprecated('use Form::ProtectorId')] public const PROTECTOR_ID = self::ProtectorId; /** diff --git a/src/Forms/Rendering/DataClassGenerator.php b/src/Forms/Rendering/DataClassGenerator.php index a575fea7..3783741f 100644 --- a/src/Forms/Rendering/DataClassGenerator.php +++ b/src/Forms/Rendering/DataClassGenerator.php @@ -24,7 +24,7 @@ final class DataClassGenerator public bool $useSmartObject = true; - /** @deprecated use Nette\Latte\Blueprint::dataClass() */ + #[\Deprecated('use Nette\Latte\Blueprint::dataClass()')] public function generateCode(Form $form, ?string $baseName = null): string { trigger_error(__METHOD__ . '() is deprecated, use ' . Blueprint::class . '::dataClass()', E_USER_DEPRECATED); diff --git a/src/Forms/Rendering/LatteRenderer.php b/src/Forms/Rendering/LatteRenderer.php index 74f8b95f..245b8f10 100644 --- a/src/Forms/Rendering/LatteRenderer.php +++ b/src/Forms/Rendering/LatteRenderer.php @@ -19,7 +19,7 @@ */ final class LatteRenderer { - /** @deprecated use Nette\Latte\Blueprint::latte() */ + #[\Deprecated('use Nette\Latte\Blueprint::latte()')] public function render(Form $form): string { trigger_error(__METHOD__ . '() is deprecated, use ' . Blueprint::class . '::latte()', E_USER_DEPRECATED); From c00cbfff7c2bf64b103c5390664d64dd4d5db77a Mon Sep 17 00:00:00 2001 From: David Grudl Date: Sun, 12 Nov 2023 17:43:25 +0100 Subject: [PATCH 05/15] added type hints (BC break) --- src/Forms/Control.php | 5 ++--- src/Forms/Controls/BaseControl.php | 21 ++++++++------------- src/Forms/Controls/Checkbox.php | 3 +-- src/Forms/Controls/ChoiceControl.php | 6 ++---- src/Forms/Controls/HiddenField.php | 3 +-- src/Forms/Controls/MultiChoiceControl.php | 6 ++---- src/Forms/Controls/MultiSelectBox.php | 3 +-- src/Forms/Controls/SelectBox.php | 3 +-- src/Forms/Controls/TextBase.php | 7 +++---- src/Forms/Controls/TextInput.php | 4 ++-- src/Forms/Controls/UploadControl.php | 7 +++---- src/Forms/Form.php | 4 +--- 12 files changed, 27 insertions(+), 45 deletions(-) diff --git a/src/Forms/Control.php b/src/Forms/Control.php index 9eff4bf7..cd60ccae 100644 --- a/src/Forms/Control.php +++ b/src/Forms/Control.php @@ -18,15 +18,14 @@ interface Control /** * Sets control's value. * @param mixed $value - * @return static */ - function setValue(mixed $value); + function setValue(mixed $value): static; /** * Returns control's value. * @return mixed */ - function getValue(); + function getValue(): mixed; function validate(): void; diff --git a/src/Forms/Controls/BaseControl.php b/src/Forms/Controls/BaseControl.php index d0f7fede..175d2948 100644 --- a/src/Forms/Controls/BaseControl.php +++ b/src/Forms/Controls/BaseControl.php @@ -134,10 +134,9 @@ public function getHtmlName(): string /** * Sets control's value. - * @return static * @internal */ - public function setValue(mixed $value) + public function setValue($value): static { $this->value = $value; return $this; @@ -148,7 +147,7 @@ public function setValue(mixed $value) * Returns control's value. * @return mixed */ - public function getValue() + public function getValue(): mixed { return $this->value; } @@ -166,9 +165,8 @@ public function isFilled(): bool /** * Sets control's default value. - * @return static */ - public function setDefaultValue($value) + public function setDefaultValue($value): static { $form = $this->getForm(throw: false); if ($this->isDisabled() || !$form || !$form->isAnchored() || !$form->isSubmitted()) { @@ -181,9 +179,8 @@ public function setDefaultValue($value) /** * Disables or enables control. - * @return static */ - public function setDisabled(bool $state = true) + public function setDisabled(bool $state = true): static { $this->disabled = $state; if ($state) { @@ -229,9 +226,8 @@ public function isOmitted(): bool /** * Generates control's HTML element. - * @return Html|string */ - public function getControl() + public function getControl(): Html|string { $this->setOption('rendered', true); $el = clone $this->control; @@ -247,9 +243,8 @@ public function getControl() /** * Generates label's HTML element. - * @return Html|string|null */ - public function getLabel(string|Stringable|null $caption = null) + public function getLabel(string|Stringable|null $caption = null): Html|string|null { $label = clone $this->label; $label->for = $this->getHtmlId(); @@ -397,13 +392,13 @@ public function translate($value, ...$parameters): mixed /** * Adds a validation rule. - * @return static */ public function addRule( callable|string $validator, string|Stringable|null $errorMessage = null, mixed $arg = null, - ) { + ): static + { $this->rules->addRule($validator, $errorMessage, $arg); return $this; } diff --git a/src/Forms/Controls/Checkbox.php b/src/Forms/Controls/Checkbox.php index ee1bdf2a..29aff944 100644 --- a/src/Forms/Controls/Checkbox.php +++ b/src/Forms/Controls/Checkbox.php @@ -34,10 +34,9 @@ public function __construct(string|Stringable|null $label = null) /** * Sets control's value. - * @return static * @internal */ - public function setValue($value) + public function setValue($value): static { if (!is_scalar($value) && $value !== null) { throw new Nette\InvalidArgumentException(sprintf("Value must be scalar or null, %s given in field '%s'.", get_debug_type($value), $this->getName())); diff --git a/src/Forms/Controls/ChoiceControl.php b/src/Forms/Controls/ChoiceControl.php index ff291ef3..487fce8b 100644 --- a/src/Forms/Controls/ChoiceControl.php +++ b/src/Forms/Controls/ChoiceControl.php @@ -44,10 +44,9 @@ public function loadHttpData(): void /** * Sets selected item (by key). * @param string|int|\BackedEnum|null $value - * @return static * @internal */ - public function setValue($value) + public function setValue($value): static { if ($value instanceof \BackedEnum) { $value = $value->value; @@ -96,9 +95,8 @@ public function isFilled(): bool /** * Sets items from which to choose. - * @return static */ - public function setItems(array $items, bool $useKeys = true) + public function setItems(array $items, bool $useKeys = true): static { $this->items = $useKeys ? $items : array_combine($items, $items); return $this; diff --git a/src/Forms/Controls/HiddenField.php b/src/Forms/Controls/HiddenField.php index ab6a7010..41baca89 100644 --- a/src/Forms/Controls/HiddenField.php +++ b/src/Forms/Controls/HiddenField.php @@ -40,10 +40,9 @@ public function __construct($persistentValue = null) /** * Sets control's value. - * @return static * @internal */ - public function setValue($value) + public function setValue($value): static { if ($value === null) { $value = ''; diff --git a/src/Forms/Controls/MultiChoiceControl.php b/src/Forms/Controls/MultiChoiceControl.php index aaab133e..71f76871 100644 --- a/src/Forms/Controls/MultiChoiceControl.php +++ b/src/Forms/Controls/MultiChoiceControl.php @@ -42,10 +42,9 @@ public function loadHttpData(): void /** * Sets selected items (by keys). - * @return static * @internal */ - public function setValue($values) + public function setValue($values): static { if (is_scalar($values) || $values === null) { $values = (array) $values; @@ -96,9 +95,8 @@ public function getRawValue(): array /** * Sets items from which to choose. - * @return static */ - public function setItems(array $items, bool $useKeys = true) + public function setItems(array $items, bool $useKeys = true): static { $this->items = $useKeys ? $items : array_combine($items, $items); return $this; diff --git a/src/Forms/Controls/MultiSelectBox.php b/src/Forms/Controls/MultiSelectBox.php index e0832c3e..506c612d 100644 --- a/src/Forms/Controls/MultiSelectBox.php +++ b/src/Forms/Controls/MultiSelectBox.php @@ -32,9 +32,8 @@ public function __construct($label = null, ?array $items = null) /** * Sets options and option groups from which to choose. - * @return static */ - public function setItems(array $items, bool $useKeys = true) + public function setItems(array $items, bool $useKeys = true): static { if (!$useKeys) { $res = []; diff --git a/src/Forms/Controls/SelectBox.php b/src/Forms/Controls/SelectBox.php index 9d19a85a..73ee5bb2 100644 --- a/src/Forms/Controls/SelectBox.php +++ b/src/Forms/Controls/SelectBox.php @@ -64,9 +64,8 @@ public function getPrompt(): string|Stringable|false /** * Sets options and option groups from which to choose. - * @return static */ - public function setItems(array $items, bool $useKeys = true) + public function setItems(array $items, bool $useKeys = true): static { if (!$useKeys) { $res = []; diff --git a/src/Forms/Controls/TextBase.php b/src/Forms/Controls/TextBase.php index 0f351b4b..a8cd1a99 100644 --- a/src/Forms/Controls/TextBase.php +++ b/src/Forms/Controls/TextBase.php @@ -28,10 +28,9 @@ abstract class TextBase extends BaseControl /** * Sets control's value. - * @return static * @internal */ - public function setValue($value) + public function setValue($value): static { if ($value === null) { $value = ''; @@ -126,12 +125,12 @@ protected function getRenderedValue(): ?string } - /** @return static */ public function addRule( callable|string $validator, string|Stringable|null $errorMessage = null, mixed $arg = null, - ) { + ): static + { foreach ($this->getRules() as $rule) { if (!$rule->canExport() && !$rule->branch) { return parent::addRule($validator, $errorMessage, $arg); diff --git a/src/Forms/Controls/TextInput.php b/src/Forms/Controls/TextInput.php index 2dd12ad1..c5bfda4d 100644 --- a/src/Forms/Controls/TextInput.php +++ b/src/Forms/Controls/TextInput.php @@ -62,12 +62,12 @@ public function getControl(): Nette\Utils\Html } - /** @return static */ public function addRule( callable|string $validator, string|Stringable|null $errorMessage = null, mixed $arg = null, - ) { + ): static + { foreach ($this->getRules() as $rule) { if (!$rule->canExport() && !$rule->branch) { return parent::addRule($validator, $errorMessage, $arg); diff --git a/src/Forms/Controls/UploadControl.php b/src/Forms/Controls/UploadControl.php index 250b9473..ce50719b 100644 --- a/src/Forms/Controls/UploadControl.php +++ b/src/Forms/Controls/UploadControl.php @@ -68,10 +68,9 @@ public function getHtmlName(): string /** - * @return static * @internal */ - public function setValue($value) + public function setValue($value): static { return $this; } @@ -122,12 +121,12 @@ public function isOk(): bool } - /** @return static */ public function addRule( callable|string $validator, string|Stringable|null $errorMessage = null, mixed $arg = null, - ) { + ): static + { if ($validator === Form::Image) { $this->control->accept = implode(', ', Forms\Helpers::getSupportedImages()); diff --git a/src/Forms/Form.php b/src/Forms/Form.php index cd544494..27efad23 100644 --- a/src/Forms/Form.php +++ b/src/Forms/Form.php @@ -204,9 +204,7 @@ class Form extends Container implements Nette\HtmlStringable /** @internal used only by standalone form */ public Nette\Http\IRequest $httpRequest; - - /** @var bool */ - protected $crossOrigin = false; + protected bool $crossOrigin = false; private static ?Nette\Http\IRequest $defaultHttpRequest = null; private SubmitterControl|bool $submittedBy = false; private array $httpData; From ba0c765fb01d08954927de09d1eadb766e4fd788 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Sun, 12 Sep 2021 22:25:45 +0200 Subject: [PATCH 06/15] Container: only Control/Container can be added to form (BC break) --- src/Forms/Container.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Forms/Container.php b/src/Forms/Container.php index af4b26bd..2e0994fd 100644 --- a/src/Forms/Container.php +++ b/src/Forms/Container.php @@ -279,6 +279,10 @@ public function addComponent( ?string $insertBefore = null, ): static { + if (!$component instanceof Control && !$component instanceof self) { + throw new Nette\InvalidStateException("Component '$name' of type " . get_debug_type($component) . ' is not intended to be used in the form.'); + } + parent::addComponent($component, $name, $insertBefore); $this->currentGroup?->add($component); return $this; From de92a0dc96e91cd4d27774fd0b5cd193d766885d Mon Sep 17 00:00:00 2001 From: David Grudl Date: Tue, 20 Dec 2022 00:33:10 +0100 Subject: [PATCH 07/15] removed compatibility for old class names --- src/Forms/Control.php | 3 --- src/Forms/FormRenderer.php | 3 --- src/Forms/SubmitterControl.php | 3 --- src/compatibility.php | 37 ---------------------------------- 4 files changed, 46 deletions(-) delete mode 100644 src/compatibility.php diff --git a/src/Forms/Control.php b/src/Forms/Control.php index cd60ccae..0f8b31d8 100644 --- a/src/Forms/Control.php +++ b/src/Forms/Control.php @@ -39,6 +39,3 @@ function getErrors(): array; */ function isOmitted(): bool; } - - -interface_exists(IControl::class); diff --git a/src/Forms/FormRenderer.php b/src/Forms/FormRenderer.php index 8db0b7d3..fdb9eb79 100644 --- a/src/Forms/FormRenderer.php +++ b/src/Forms/FormRenderer.php @@ -20,6 +20,3 @@ interface FormRenderer */ function render(Form $form): string; } - - -interface_exists(IFormRenderer::class); diff --git a/src/Forms/SubmitterControl.php b/src/Forms/SubmitterControl.php index e59f87cd..22874568 100644 --- a/src/Forms/SubmitterControl.php +++ b/src/Forms/SubmitterControl.php @@ -20,6 +20,3 @@ interface SubmitterControl extends Control */ function getValidationScope(): ?array; } - - -interface_exists(ISubmitterControl::class); diff --git a/src/compatibility.php b/src/compatibility.php deleted file mode 100644 index dd9c45ee..00000000 --- a/src/compatibility.php +++ /dev/null @@ -1,37 +0,0 @@ - Date: Thu, 8 Feb 2024 20:25:33 +0100 Subject: [PATCH 08/15] Container::getControls() returns list instead of iterator with names (BC break) --- src/Forms/Container.php | 7 ++++--- tests/Forms/Container.getControls().phpt | 20 +------------------- 2 files changed, 5 insertions(+), 22 deletions(-) diff --git a/src/Forms/Container.php b/src/Forms/Container.php index 2e0994fd..9f61b4ca 100644 --- a/src/Forms/Container.php +++ b/src/Forms/Container.php @@ -290,11 +290,12 @@ public function addComponent( /** - * Iterates over all form controls. + * Retrieves the entire hierarchy of form controls including nested. + * @return list */ - public function getControls(): \Iterator + public function getControls(): array { - return $this->getComponents(true, Control::class); + return array_values(array_filter($this->getComponentTree(), fn($c) => $c instanceof Control)); } diff --git a/tests/Forms/Container.getControls().phpt b/tests/Forms/Container.getControls().phpt index 5c4d2bef..3c605a6e 100644 --- a/tests/Forms/Container.getControls().phpt +++ b/tests/Forms/Container.getControls().phpt @@ -15,22 +15,4 @@ $form->addContainer('cont') ->addText('name'); $controls = $form->getControls(); - -$names = $values = []; -foreach ($controls as $name => $value) { - $names[] = $name; - $values[] = $value; -} - -Assert::same(['name', 'age', 'name'], $names); -Assert::same([$form['name'], $form['age'], $form['cont-name']], $values); - -// again -$names = $values = []; -foreach ($controls as $name => $value) { - $names[] = $name; - $values[] = $value; -} - -Assert::same(['name', 'age', 'name'], $names); -Assert::same([$form['name'], $form['age'], $form['cont-name']], $values); +Assert::same([$form['name'], $form['age'], $form['cont-name']], $controls); From 54db3a1f992d968842d1e7d9f28eb3284d7cc900 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Sat, 27 Apr 2024 16:34:35 +0200 Subject: [PATCH 09/15] Container::setValues() and setDefaults() accepts array|Traversable|stdClass (BC break) --- src/Forms/Container.php | 10 ++++++++-- tests/Forms/Container.values.mapping.phpt | 7 +++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/Forms/Container.php b/src/Forms/Container.php index 9f61b4ca..6e2cd6ac 100644 --- a/src/Forms/Container.php +++ b/src/Forms/Container.php @@ -46,21 +46,27 @@ class Container extends Nette\ComponentModel\Container implements \ArrayAccess /** * Fill-in with default values. + * @param array|\Traversable|\stdClass $values */ - public function setDefaults(array|object $data, bool $erase = false): static + public function setDefaults(array|object $values, bool $erase = false): static { $form = $this->getForm(false); - $this->setValues($data, $erase, $form?->isAnchored() && $form->isSubmitted()); + $this->setValues($values, $erase, $form?->isAnchored() && $form->isSubmitted()); return $this; } /** * Fill-in with values. + * @param array|\Traversable|\stdClass $values * @internal */ public function setValues(array|object $values, bool $erase = false, bool $onlyDisabled = false): static { + if (is_object($values) && !($values instanceof \Traversable || $values instanceof \stdClass)) { + trigger_error(__METHOD__ . ': argument should be array|Traversable|stdClass, ' . get_debug_type($values) . ' given.'); + } + $values = $values instanceof \Traversable ? iterator_to_array($values) : (array) $values; diff --git a/tests/Forms/Container.values.mapping.phpt b/tests/Forms/Container.values.mapping.phpt index 043d6cbc..4e27d179 100644 --- a/tests/Forms/Container.values.mapping.phpt +++ b/tests/Forms/Container.values.mapping.phpt @@ -11,15 +11,14 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -#[AllowDynamicProperties] -class FormData +class FormData extends stdClass { public string $title; public FormFirstLevel $first; } -class FormFirstLevel +class FormFirstLevel extends stdClass { public string $name; public ?int $age = null; @@ -27,7 +26,7 @@ class FormFirstLevel } -class FormSecondLevel +class FormSecondLevel extends stdClass { public string $city; } From 7679210eda3e0a5ef1b78be7b3a8a9eafca23f3b Mon Sep 17 00:00:00 2001 From: David Grudl Date: Mon, 31 Mar 2025 03:14:00 +0200 Subject: [PATCH 10/15] BaseControl::$disabled is bool, added $disabledChoices --- src/Forms/Controls/BaseControl.php | 6 ++---- src/Forms/Controls/CheckboxList.php | 4 ++-- src/Forms/Controls/ChoiceControl.php | 11 ++++++----- src/Forms/Controls/MultiChoiceControl.php | 11 ++++++----- src/Forms/Controls/MultiSelectBox.php | 2 +- src/Forms/Controls/RadioList.php | 4 ++-- src/Forms/Controls/SelectBox.php | 2 +- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Forms/Controls/BaseControl.php b/src/Forms/Controls/BaseControl.php index 175d2948..563c1230 100644 --- a/src/Forms/Controls/BaseControl.php +++ b/src/Forms/Controls/BaseControl.php @@ -45,9 +45,7 @@ abstract class BaseControl extends Nette\ComponentModel\Component implements Con protected mixed $value = null; protected Html $control; protected Html $label; - - /** @var bool|bool[] */ - protected bool|array $disabled = false; + protected bool $disabled = false; /** @var callable[][] extension methods */ private static array $extMethods = []; @@ -198,7 +196,7 @@ public function setDisabled(bool $state = true): static */ public function isDisabled(): bool { - return $this->disabled === true; + return $this->disabled; } diff --git a/src/Forms/Controls/CheckboxList.php b/src/Forms/Controls/CheckboxList.php index cff3f538..2036df77 100644 --- a/src/Forms/Controls/CheckboxList.php +++ b/src/Forms/Controls/CheckboxList.php @@ -60,7 +60,7 @@ public function getControl(): Html array_merge($input->attrs, [ 'id' => null, 'checked?' => $this->value, - 'disabled:' => $this->disabled, + 'disabled:' => $this->disabled ?: $this->disabledChoices, 'required' => null, 'data-nette-rules:' => [array_key_first($items) => $input->attrs['data-nette-rules']], ]), @@ -83,7 +83,7 @@ public function getControlPart($key = null): Html return parent::getControl()->addAttributes([ 'id' => $this->getHtmlId() . '-' . $key, 'checked' => in_array($key, (array) $this->value, strict: true), - 'disabled' => is_array($this->disabled) ? isset($this->disabled[$key]) : $this->disabled, + 'disabled' => $this->disabled || isset($this->disabledChoices[$key]), 'required' => null, 'value' => $key, ]); diff --git a/src/Forms/Controls/ChoiceControl.php b/src/Forms/Controls/ChoiceControl.php index 487fce8b..de84788c 100644 --- a/src/Forms/Controls/ChoiceControl.php +++ b/src/Forms/Controls/ChoiceControl.php @@ -21,6 +21,8 @@ */ abstract class ChoiceControl extends BaseControl { + /** @var bool[] */ + protected array $disabledChoices = []; private bool $checkDefaultValue = true; private array $items = []; @@ -69,7 +71,7 @@ public function setValue($value): static public function getValue(): mixed { return array_key_exists($this->value, $this->items) - && !isset($this->disabled[$this->value]) + && !isset($this->disabledChoices[$this->value]) ? $this->value : null; } @@ -128,12 +130,11 @@ public function getSelectedItem(): mixed public function setDisabled(bool|array $value = true): static { if (!is_array($value)) { + $this->disabledChoices = []; return parent::setDisabled($value); } - - parent::setDisabled(false); - $this->disabled = array_fill_keys($value, value: true); - return $this; + $this->disabledChoices = array_fill_keys($value, value: true); + return parent::setDisabled(false); } diff --git a/src/Forms/Controls/MultiChoiceControl.php b/src/Forms/Controls/MultiChoiceControl.php index 71f76871..1766ef31 100644 --- a/src/Forms/Controls/MultiChoiceControl.php +++ b/src/Forms/Controls/MultiChoiceControl.php @@ -21,6 +21,8 @@ */ abstract class MultiChoiceControl extends BaseControl { + /** @var bool[] */ + protected array $disabledChoices = []; private bool $checkDefaultValue = true; private array $items = []; @@ -119,7 +121,7 @@ public function getSelectedItems(): array { $res = []; foreach ($this->value as $key) { - if (isset($this->items[$key]) && !isset($this->disabled[$key])) { + if (isset($this->items[$key]) && !isset($this->disabledChoices[$key])) { $res[$key] = $this->items[$key]; } } @@ -133,12 +135,11 @@ public function getSelectedItems(): array public function setDisabled(bool|array $value = true): static { if (!is_array($value)) { + $this->disabledChoices = []; return parent::setDisabled($value); } - - parent::setDisabled(false); - $this->disabled = array_fill_keys($value, value: true); - return $this; + $this->disabledChoices = array_fill_keys($value, value: true); + return parent::setDisabled(false); } diff --git a/src/Forms/Controls/MultiSelectBox.php b/src/Forms/Controls/MultiSelectBox.php index 506c612d..08ba8204 100644 --- a/src/Forms/Controls/MultiSelectBox.php +++ b/src/Forms/Controls/MultiSelectBox.php @@ -66,7 +66,7 @@ public function getControl(): Nette\Utils\Html return Nette\Forms\Helpers::createSelectBox( $items, [ - 'disabled:' => is_array($this->disabled) ? $this->disabled : null, + 'disabled:' => $this->disabledChoices, ] + $this->optionAttributes, $this->value, )->addAttributes(parent::getControl()->attrs)->multiple(true); diff --git a/src/Forms/Controls/RadioList.php b/src/Forms/Controls/RadioList.php index e9b3f941..f96f02bd 100644 --- a/src/Forms/Controls/RadioList.php +++ b/src/Forms/Controls/RadioList.php @@ -58,7 +58,7 @@ public function getControl(): Html array_merge($input->attrs, [ 'id:' => $ids, 'checked?' => $this->value, - 'disabled:' => $this->disabled, + 'disabled:' => $this->disabled ?: $this->disabledChoices, 'data-nette-rules:' => [key($items) => $input->attrs['data-nette-rules']], ]), ['for:' => $ids] + $this->itemLabel->attrs, @@ -80,7 +80,7 @@ public function getControlPart($key = null): Html return parent::getControl()->addAttributes([ 'id' => $this->getHtmlId() . '-' . $key, 'checked' => in_array($key, (array) $this->value, strict: true), - 'disabled' => is_array($this->disabled) ? isset($this->disabled[$key]) : $this->disabled, + 'disabled' => $this->disabled || isset($this->disabledChoices[$key]), 'value' => $key, ]); } diff --git a/src/Forms/Controls/SelectBox.php b/src/Forms/Controls/SelectBox.php index 73ee5bb2..19aca80e 100644 --- a/src/Forms/Controls/SelectBox.php +++ b/src/Forms/Controls/SelectBox.php @@ -96,7 +96,7 @@ public function getControl(): Nette\Utils\Html } $attrs = $this->optionAttributes; - $attrs['disabled:'] = is_array($this->disabled) ? $this->disabled : []; + $attrs['disabled:'] = $this->disabledChoices; $selected = $this->value; if ($this->prompt !== false) { From 4c51b1b5f16556fb100c03a1e85a6345bf6eeef4 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Fri, 10 Nov 2023 14:06:48 +0100 Subject: [PATCH 11/15] Latte: {formContext}, {formPrint} & {formClassPrint) are deprecated --- src/Bridges/FormsLatte/Nodes/FormNode.php | 4 +++- src/Bridges/FormsLatte/Nodes/FormPrintNode.php | 5 +++++ tests/Forms.Latte3/expected/forms.html | 6 ------ tests/Forms.Latte3/expected/forms.php | 18 ------------------ tests/Forms.Latte3/templates/forms.latte | 6 ------ 5 files changed, 8 insertions(+), 31 deletions(-) diff --git a/src/Bridges/FormsLatte/Nodes/FormNode.php b/src/Bridges/FormsLatte/Nodes/FormNode.php index a3bf7dc6..612059b1 100644 --- a/src/Bridges/FormsLatte/Nodes/FormNode.php +++ b/src/Bridges/FormsLatte/Nodes/FormNode.php @@ -22,7 +22,6 @@ /** * {form name} ... {/form} - * {formContext ...} */ class FormNode extends StatementNode { @@ -47,6 +46,9 @@ public static function create(Tag $tag): \Generator $tag->parser->stream->tryConsume(','); $node->attributes = $tag->parser->parseArguments(); $node->print = $tag->name === 'form'; + if (!$node->print) { + trigger_error('Tag {formContext} is deprecated', E_USER_DEPRECATED); + } [$node->content, $endTag] = yield; $node->endLine = $endTag?->position; diff --git a/src/Bridges/FormsLatte/Nodes/FormPrintNode.php b/src/Bridges/FormsLatte/Nodes/FormPrintNode.php index 204e541d..f1ff307e 100644 --- a/src/Bridges/FormsLatte/Nodes/FormPrintNode.php +++ b/src/Bridges/FormsLatte/Nodes/FormPrintNode.php @@ -27,6 +27,11 @@ class FormPrintNode extends StatementNode public static function create(Tag $tag): static { + if ($tag->name === 'formPrint') { + trigger_error('Tag {formPrint} is deprecated, use Nette\Forms\Blueprint::latte($form)', E_USER_DEPRECATED); + } else { + trigger_error('Tag {formClassPrint} is deprecated, use Nette\Forms\Blueprint::dataClass($form)', E_USER_DEPRECATED); + } $node = new static; $node->name = $tag->parser->isEnd() ? null diff --git a/tests/Forms.Latte3/expected/forms.html b/tests/Forms.Latte3/expected/forms.html index 8bc00324..ddf573e2 100644 --- a/tests/Forms.Latte3/expected/forms.html +++ b/tests/Forms.Latte3/expected/forms.html @@ -111,9 +111,3 @@ - - - - - - \ No newline at end of file diff --git a/tests/Forms.Latte3/expected/forms.php b/tests/Forms.Latte3/expected/forms.php index 9ebde5a3..10fa0b90 100644 --- a/tests/Forms.Latte3/expected/forms.php +++ b/tests/Forms.Latte3/expected/forms.php @@ -255,22 +255,4 @@ '; echo $this->global->forms->renderFormEnd() /* line %d% */; $this->global->forms->end(); - - echo ' - - -'; - $this->global->forms->begin($form = $this->global->uiControl['myForm']) /* line %d% */; - echo ' -global->forms->item('sex')->getLabelPart())->attributes() /* line %d% */; - echo '>'; - echo $ʟ_elem->getHtml() /* line %d% */; - echo ' -global->forms->item('username')->getControlPart())->attributes() /* line %d% */; - echo '> -'; - /* line %d% */; - $this->global->forms->end(); %A% diff --git a/tests/Forms.Latte3/templates/forms.latte b/tests/Forms.Latte3/templates/forms.latte index 7196558b..91153dcf 100644 --- a/tests/Forms.Latte3/templates/forms.latte +++ b/tests/Forms.Latte3/templates/forms.latte @@ -80,9 +80,3 @@ -{/formContext myForm} From 45bc2c417f453e38289c1311c68863f0041ba4cf Mon Sep 17 00:00:00 2001 From: David Grudl Date: Sun, 11 Feb 2024 18:03:59 +0100 Subject: [PATCH 12/15] added HTML attribute data-nette-error --- src/Forms/Controls/BaseControl.php | 1 + tests/Forms.Latte3/expected/forms.html | 14 +++++++------- tests/Forms/expected/Forms.renderer.1.expect | 8 ++++---- tests/Forms/expected/Forms.renderer.2.expect | 6 +++--- .../Forms/expected/Forms.renderer.translate.expect | 2 +- 5 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/Forms/Controls/BaseControl.php b/src/Forms/Controls/BaseControl.php index 563c1230..2f11408f 100644 --- a/src/Forms/Controls/BaseControl.php +++ b/src/Forms/Controls/BaseControl.php @@ -235,6 +235,7 @@ public function getControl(): Html|string 'required' => $this->isRequired(), 'disabled' => $this->isDisabled(), 'data-nette-rules' => Nette\Forms\Helpers::exportRules($this->rules) ?: null, + 'data-nette-error' => $this->hasErrors(), ]); } diff --git a/tests/Forms.Latte3/expected/forms.html b/tests/Forms.Latte3/expected/forms.html index ddf573e2..30672133 100644 --- a/tests/Forms.Latte3/expected/forms.html +++ b/tests/Forms.Latte3/expected/forms.html @@ -8,12 +8,12 @@ - + error
- + error @@ -43,11 +43,11 @@ - + - + @@ -89,17 +89,17 @@
- +
- +
- +
diff --git a/tests/Forms/expected/Forms.renderer.1.expect b/tests/Forms/expected/Forms.renderer.1.expect index 4f627614..3c17482d 100644 --- a/tests/Forms/expected/Forms.renderer.1.expect +++ b/tests/Forms/expected/Forms.renderer.1.expect @@ -14,7 +14,7 @@ - + Enter your age @@ -54,14 +54,14 @@ - + Enter your shipping address - + Select your country @@ -81,7 +81,7 @@ - + Reenter your password diff --git a/tests/Forms/expected/Forms.renderer.2.expect b/tests/Forms/expected/Forms.renderer.2.expect index 4fbec753..4b4872f5 100644 --- a/tests/Forms/expected/Forms.renderer.2.expect +++ b/tests/Forms/expected/Forms.renderer.2.expect @@ -13,14 +13,14 @@
-
• +
Age must be numeric value
-
+
Please select a valid option.
@@ -73,7 +73,7 @@
-
(at least 3 characters) +
(at least 3 characters) The password is too short: it must be at least 3 characters
diff --git a/tests/Forms/expected/Forms.renderer.translate.expect b/tests/Forms/expected/Forms.renderer.translate.expect index e1230b98..125b4ac4 100644 --- a/tests/Forms/expected/Forms.renderer.translate.expect +++ b/tests/Forms/expected/Forms.renderer.translate.expect @@ -15,7 +15,7 @@ - + WEAK PASSWORD From de1d1e2b8b0e74c8257d6c3d89bd24c88d591610 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Tue, 6 Aug 2024 00:27:12 +0200 Subject: [PATCH 13/15] netteForms: removed distribution files (BC break) --- src/assets/netteForms.js | 563 ----------------------------------- src/assets/netteForms.min.js | 7 - 2 files changed, 570 deletions(-) delete mode 100644 src/assets/netteForms.js delete mode 100644 src/assets/netteForms.min.js diff --git a/src/assets/netteForms.js b/src/assets/netteForms.js deleted file mode 100644 index 60c86de4..00000000 --- a/src/assets/netteForms.js +++ /dev/null @@ -1,563 +0,0 @@ -/*! - * NetteForms - simple form validation. - * - * This file is part of the Nette Framework (https://nette.org) - * Copyright (c) 2004 David Grudl (https://davidgrudl.com) - */ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : - typeof define === 'function' && define.amd ? define(factory) : - (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Nette?.noInit ? (global.Nette = factory()) : (global.Nette = factory()).initOnLoad()); -})(this, (function () { 'use strict'; - - class Validators { - filled(elem, arg, val) { - return val !== '' && val !== false && val !== null - && (!Array.isArray(val) || val.length > 0) - && (!(val instanceof FileList) || val.length > 0); - } - blank(elem, arg, val) { - return !this.filled(elem, arg, val); - } - valid(elem, arg) { - return arg.validateControl(elem, undefined, true); - } - equal(elem, arg, val) { - if (arg === undefined) { - return null; - } - let toString = (val) => { - if (typeof val === 'number' || typeof val === 'string') { - return '' + val; - } - else { - return val === true ? '1' : ''; - } - }; - let vals = Array.isArray(val) ? val : [val]; - let args = Array.isArray(arg) ? arg : [arg]; - loop: for (let a of vals) { - for (let b of args) { - if (toString(a) === toString(b)) { - continue loop; - } - } - return false; - } - return vals.length > 0; - } - notEqual(elem, arg, val) { - return arg === undefined ? null : !this.equal(elem, arg, val); - } - minLength(elem, arg, val) { - val = typeof val === 'number' ? val.toString() : val; - return val.length >= arg; - } - maxLength(elem, arg, val) { - val = typeof val === 'number' ? val.toString() : val; - return val.length <= arg; - } - length(elem, arg, val) { - val = typeof val === 'number' ? val.toString() : val; - arg = Array.isArray(arg) ? arg : [arg, arg]; - return ((arg[0] === null || val.length >= arg[0]) - && (arg[1] === null || val.length <= arg[1])); - } - email(elem, arg, val) { - return (/^("([ !#-[\]-~]|\\[ -~])+"|[-a-z0-9!#$%&'*+/=?^_`{|}~]+(\.[-a-z0-9!#$%&'*+/=?^_`{|}~]+)*)@([0-9a-z\u00C0-\u02FF\u0370-\u1EFF]([-0-9a-z\u00C0-\u02FF\u0370-\u1EFF]{0,61}[0-9a-z\u00C0-\u02FF\u0370-\u1EFF])?\.)+[a-z\u00C0-\u02FF\u0370-\u1EFF]([-0-9a-z\u00C0-\u02FF\u0370-\u1EFF]{0,17}[a-z\u00C0-\u02FF\u0370-\u1EFF])?$/i).test(val); - } - url(elem, arg, val, newValue) { - if (!(/^[a-z\d+.-]+:/).test(val)) { - val = 'https://' + val; - } - if ((/^https?:\/\/((([-_0-9a-z\u00C0-\u02FF\u0370-\u1EFF]+\.)*[0-9a-z\u00C0-\u02FF\u0370-\u1EFF]([-0-9a-z\u00C0-\u02FF\u0370-\u1EFF]{0,61}[0-9a-z\u00C0-\u02FF\u0370-\u1EFF])?\.)?[a-z\u00C0-\u02FF\u0370-\u1EFF]([-0-9a-z\u00C0-\u02FF\u0370-\u1EFF]{0,17}[a-z\u00C0-\u02FF\u0370-\u1EFF])?|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|\[[0-9a-f:]{3,39}\])(:\d{1,5})?(\/\S*)?$/i).test(val)) { - newValue.value = val; - return true; - } - return false; - } - regexp(elem, arg, val) { - let parts = typeof arg === 'string' ? arg.match(/^\/(.*)\/([imu]*)$/) : false; - try { - return parts && (new RegExp(parts[1], parts[2].replace('u', ''))).test(val); - } - catch { - return null; - } - } - pattern(elem, arg, val, newValue, caseInsensitive) { - if (typeof arg !== 'string') { - return null; - } - try { - let regExp; - try { - regExp = new RegExp('^(?:' + arg + ')$', caseInsensitive ? 'ui' : 'u'); - } - catch { - regExp = new RegExp('^(?:' + arg + ')$', caseInsensitive ? 'i' : ''); - } - return val instanceof FileList - ? Array.from(val).every((file) => regExp.test(file.name)) - : regExp.test(val); - } - catch { - return null; - } - } - patternCaseInsensitive(elem, arg, val) { - return this.pattern(elem, arg, val, null, true); - } - numeric(elem, arg, val) { - return (/^[0-9]+$/).test(val); - } - integer(elem, arg, val, newValue) { - if ((/^-?[0-9]+$/).test(val)) { - newValue.value = parseFloat(val); - return true; - } - return false; - } - float(elem, arg, val, newValue) { - val = val.replace(/ +/g, '').replace(/,/g, '.'); - if ((/^-?[0-9]*\.?[0-9]+$/).test(val)) { - newValue.value = parseFloat(val); - return true; - } - return false; - } - min(elem, arg, val) { - if (Number.isFinite(arg)) { - val = parseFloat(val); - } - return val >= arg; - } - max(elem, arg, val) { - if (Number.isFinite(arg)) { - val = parseFloat(val); - } - return val <= arg; - } - range(elem, arg, val) { - if (!Array.isArray(arg)) { - return null; - } - else if (elem.type === 'time' && arg[0] > arg[1]) { - return val >= arg[0] || val <= arg[1]; - } - return (arg[0] === null || this.min(elem, arg[0], val)) - && (arg[1] === null || this.max(elem, arg[1], val)); - } - submitted(elem) { - return elem.form['nette-submittedBy'] === elem; - } - fileSize(elem, arg, val) { - return Array.from(val).every((file) => file.size <= arg); - } - mimeType(elem, args, val) { - let parts = []; - args = Array.isArray(args) ? args : [args]; - args.forEach((arg) => parts.push('^' + arg.replace(/([^\w])/g, '\\$1').replace('\\*', '.*') + '$')); - let re = new RegExp(parts.join('|')); - return Array.from(val).every((file) => !file.type || re.test(file.type)); - } - image(elem, arg, val) { - return this.mimeType(elem, arg ?? ['image/gif', 'image/png', 'image/jpeg', 'image/webp'], val); - } - static(elem, arg) { - return arg; - } - } - - class FormValidator { - formErrors = []; - validators = new Validators; - #preventFiltering = {}; - #formToggles = {}; - #toggleListeners = new WeakMap; - #getFormElement(form, name) { - let res = form.elements.namedItem(name); - return (res instanceof RadioNodeList ? res[0] : res); - } - #expandRadioElement(elem) { - let res = elem.form.elements.namedItem(elem.name); - return (res instanceof RadioNodeList ? Array.from(res) : [res]); - } - /** - * Function to execute when the DOM is fully loaded. - */ - #onDocumentReady(callback) { - if (document.readyState !== 'loading') { - callback.call(this); - } - else { - document.addEventListener('DOMContentLoaded', callback); - } - } - /** - * Returns the value of form element. - */ - getValue(elem) { - if (elem instanceof HTMLInputElement) { - if (elem.type === 'radio') { - return this.#expandRadioElement(elem) - .find((input) => input.checked) - ?.value ?? null; - } - else if (elem.type === 'file') { - return elem.files; - } - else if (elem.type === 'checkbox') { - return elem.name.endsWith('[]') // checkbox list - ? this.#expandRadioElement(elem) - .filter((input) => input.checked) - .map((input) => input.value) - : elem.checked; - } - else { - return elem.value.trim(); - } - } - else if (elem instanceof HTMLSelectElement) { - return elem.multiple - ? Array.from(elem.selectedOptions, (option) => option.value) - : elem.selectedOptions[0]?.value ?? null; - } - else if (elem instanceof HTMLTextAreaElement) { - return elem.value; - } - else if (elem instanceof RadioNodeList) { - return this.getValue(elem[0]); - } - else { - return null; - } - } - /** - * Returns the effective value of form element. - */ - getEffectiveValue(elem, filter = false) { - let val = this.getValue(elem); - if (val === elem.getAttribute('data-nette-empty-value')) { - val = ''; - } - if (filter && this.#preventFiltering[elem.name] === undefined) { - this.#preventFiltering[elem.name] = true; - let ref = { value: val }; - this.validateControl(elem, undefined, true, ref); - val = ref.value; - delete this.#preventFiltering[elem.name]; - } - return val; - } - /** - * Validates form element against given rules. - */ - validateControl(elem, rules, onlyCheck = false, value, emptyOptional) { - rules ??= JSON.parse(elem.getAttribute('data-nette-rules') ?? '[]'); - value ??= { value: this.getEffectiveValue(elem) }; - emptyOptional ??= !this.validateRule(elem, ':filled', null, value); - for (let rule of rules) { - let op = rule.op.match(/(~)?([^?]+)/), curElem = rule.control ? this.#getFormElement(elem.form, rule.control) : elem; - rule.neg = !!op[1]; - rule.op = op[2]; - rule.condition = !!rule.rules; - if (!curElem) { - continue; - } - else if (emptyOptional && !rule.condition && rule.op !== ':filled') { - continue; - } - let success = this.validateRule(curElem, rule.op, rule.arg, elem === curElem ? value : undefined); - if (success === null) { - continue; - } - else if (rule.neg) { - success = !success; - } - if (rule.condition && success) { - if (!this.validateControl(elem, rule.rules, onlyCheck, value, rule.op === ':blank' ? false : emptyOptional)) { - return false; - } - } - else if (!rule.condition && !success) { - if (this.isDisabled(curElem)) { - continue; - } - if (!onlyCheck) { - let arr = Array.isArray(rule.arg) ? rule.arg : [rule.arg], message = rule.msg.replace(/%(value|\d+)/g, (foo, m) => this.getValue(m === 'value' ? curElem : elem.form.elements.namedItem(arr[m].control))); - this.addError(curElem, message); - } - return false; - } - } - return true; - } - /** - * Validates whole form. - */ - validateForm(sender, onlyCheck = false) { - let form = sender.form ?? sender, scope; - this.formErrors = []; - if (sender.getAttribute('formnovalidate') !== null) { - let scopeArr = JSON.parse(sender.getAttribute('data-nette-validation-scope') ?? '[]'); - if (scopeArr.length) { - scope = new RegExp('^(' + scopeArr.join('-|') + '-)'); - } - else { - this.showFormErrors(form, []); - return true; - } - } - for (let elem of form.elements) { - if (elem.willValidate && elem.validity.badInput) { - elem.reportValidity(); - return false; - } - } - for (let elem of form.elements) { - if (elem.getAttribute('data-nette-rules') - && (!scope || elem.name.replace(/]\[|\[|]|$/g, '-').match(scope)) - && !this.isDisabled(elem) - && !this.validateControl(elem, undefined, onlyCheck) - && !this.formErrors.length) { - return false; - } - } - let success = !this.formErrors.length; - this.showFormErrors(form, this.formErrors); - return success; - } - /** - * Check if input is disabled. - */ - isDisabled(elem) { - if (elem.type === 'radio') { - return this.#expandRadioElement(elem) - .every((input) => input.disabled); - } - return elem.disabled; - } - /** - * Adds error message to the queue. - */ - addError(elem, message) { - this.formErrors.push({ - element: elem, - message: message, - }); - } - /** - * Display error messages. - */ - showFormErrors(form, errors) { - let messages = [], focusElem; - for (let error of errors) { - if (messages.indexOf(error.message) < 0) { - messages.push(error.message); - focusElem ??= error.element; - } - } - if (messages.length) { - this.showModal(messages.join('\n'), () => { - focusElem?.focus(); - }); - } - } - /** - * Display modal window. - */ - showModal(message, onclose) { - let dialog = document.createElement('dialog'); - if (!dialog.showModal) { - alert(message); - onclose(); - return; - } - let style = document.createElement('style'); - style.innerText = '.netteFormsModal { text-align: center; margin: auto; border: 2px solid black; padding: 1rem } .netteFormsModal button { padding: .1em 2em }'; - let button = document.createElement('button'); - button.innerText = 'OK'; - button.onclick = () => { - dialog.remove(); - onclose(); - }; - dialog.setAttribute('class', 'netteFormsModal'); - dialog.innerText = message + '\n\n'; - dialog.append(style, button); - document.body.append(dialog); - dialog.showModal(); - } - /** - * Validates single rule. - */ - validateRule(elem, op, arg, value) { - if (elem.validity.badInput) { - return op === ':filled'; - } - value ??= { value: this.getEffectiveValue(elem, true) }; - let method = op.charAt(0) === ':' ? op.substring(1) : op; - method = method.replace('::', '_').replaceAll('\\', ''); - let args = Array.isArray(arg) ? arg : [arg]; - args = args.map((arg) => { - if (arg?.control) { - let control = this.#getFormElement(elem.form, arg.control); - return control === elem ? value.value : this.getEffectiveValue(control, true); - } - return arg; - }); - if (method === 'valid') { - args[0] = this; // todo - } - return this.validators[method] - ? this.validators[method](elem, Array.isArray(arg) ? args : args[0], value.value, value) - : null; - } - /** - * Process all toggles in form. - */ - toggleForm(form, event) { - this.#formToggles = {}; - for (let elem of Array.from(form.elements)) { - if (elem.getAttribute('data-nette-rules')) { - this.toggleControl(elem, undefined, null, !event); - } - } - for (let i in this.#formToggles) { - this.toggle(i, this.#formToggles[i].state, this.#formToggles[i].elem, event); - } - } - /** - * Process toggles on form element. - */ - toggleControl(elem, rules, success = null, firsttime = false, value, emptyOptional) { - rules ??= JSON.parse(elem.getAttribute('data-nette-rules') ?? '[]'); - value ??= { value: this.getEffectiveValue(elem) }; - emptyOptional ??= !this.validateRule(elem, ':filled', null, value); - let has = false, curSuccess; - for (let rule of rules) { - let op = rule.op.match(/(~)?([^?]+)/), curElem = rule.control ? this.#getFormElement(elem.form, rule.control) : elem; - rule.neg = !!op[1]; - rule.op = op[2]; - rule.condition = !!rule.rules; - if (!curElem) { - continue; - } - else if (emptyOptional && !rule.condition && rule.op !== ':filled') { - continue; - } - curSuccess = success; - if (success !== false) { - curSuccess = this.validateRule(curElem, rule.op, rule.arg, elem === curElem ? value : undefined); - if (curSuccess === null) { - continue; - } - else if (rule.neg) { - curSuccess = !curSuccess; - } - if (!rule.condition) { - success = curSuccess; - } - } - if ((rule.condition && this.toggleControl(elem, rule.rules, curSuccess, firsttime, value, rule.op === ':blank' ? false : emptyOptional)) || rule.toggle) { - has = true; - if (firsttime) { - this.#expandRadioElement(curElem) - .filter((el) => !this.#toggleListeners.has(el)) - .forEach((el) => { - el.addEventListener('change', (e) => this.toggleForm(elem.form, e)); - this.#toggleListeners.set(el, null); - }); - } - for (let id in rule.toggle ?? {}) { - this.#formToggles[id] ??= { elem: elem, state: false }; - this.#formToggles[id].state ||= rule.toggle[id] ? !!curSuccess : !curSuccess; - } - } - } - return has; - } - /** - * Displays or hides HTML element. - */ - toggle(selector, visible, srcElement, event) { - if (/^\w[\w.:-]*$/.test(selector)) { // id - selector = '#' + selector; - } - Array.from(document.querySelectorAll(selector)) - .forEach((elem) => elem.hidden = !visible); - } - /** - * Compact checkboxes - */ - compactCheckboxes(form, formData) { - let values = {}; - for (let elem of form.elements) { - if (elem instanceof HTMLInputElement && elem.type === 'checkbox' && elem.name.endsWith('[]') && elem.checked && !elem.disabled) { - formData.delete(elem.name); - values[elem.name] ??= []; - values[elem.name].push(elem.value); - } - } - for (let name in values) { - formData.set(name.substring(0, name.length - 2), values[name].join(',')); - } - } - /** - * Setup handlers. - */ - initForm(form) { - if (form.method === 'get' && form.hasAttribute('data-nette-compact')) { - form.addEventListener('formdata', (e) => this.compactCheckboxes(form, e.formData)); - } - if (!Array.from(form.elements).some((elem) => elem.getAttribute('data-nette-rules'))) { - return; - } - this.toggleForm(form); - if (form.noValidate) { - return; - } - form.noValidate = true; - form.addEventListener('submit', (e) => { - if (!this.validateForm((e.submitter || form))) { - e.stopImmediatePropagation(); - e.preventDefault(); - } - }); - form.addEventListener('reset', () => { - setTimeout(() => this.toggleForm(form)); - }); - } - initOnLoad() { - this.#onDocumentReady(() => { - Array.from(document.forms) - .forEach((form) => this.initForm(form)); - }); - } - } - - let webalizeTable = { \u00e1: 'a', \u00e4: 'a', \u010d: 'c', \u010f: 'd', \u00e9: 'e', \u011b: 'e', \u00ed: 'i', \u013e: 'l', \u0148: 'n', \u00f3: 'o', \u00f4: 'o', \u0159: 'r', \u0161: 's', \u0165: 't', \u00fa: 'u', \u016f: 'u', \u00fd: 'y', \u017e: 'z' }; - /** - * Converts string to web safe characters [a-z0-9-] text. - * @param {string} s - * @return {string} - */ - function webalize(s) { - s = s.toLowerCase(); - let res = ''; - for (let i = 0; i < s.length; i++) { - let ch = webalizeTable[s.charAt(i)]; - res += ch ? ch : s.charAt(i); - } - return res.replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, ''); - } - - var version = "3.5.3"; - - let nette = new FormValidator; - nette.version = version; - nette.webalize = webalize; - - return nette; - -})); diff --git a/src/assets/netteForms.min.js b/src/assets/netteForms.min.js deleted file mode 100644 index 0b1e9f33..00000000 --- a/src/assets/netteForms.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * NetteForms - simple form validation. - * - * This file is part of the Nette Framework (https://nette.org) - * Copyright (c) 2004 David Grudl (https://davidgrudl.com) - */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self,e.Nette?.noInit?e.Nette=t():(e.Nette=t()).initOnLoad())}(this,(function(){"use strict";class e{filled(e,t,r){return""!==r&&!1!==r&&null!==r&&(!Array.isArray(r)||r.length>0)&&(!(r instanceof FileList)||r.length>0)}blank(e,t,r){return!this.filled(e,t,r)}valid(e,t){return t.validateControl(e,void 0,!0)}equal(e,t,r){if(void 0===t)return null;let n=e=>"number"==typeof e||"string"==typeof e?""+e:!0===e?"1":"",l=Array.isArray(r)?r:[r],i=Array.isArray(t)?t:[t];e:for(let e of l){for(let t of i)if(n(e)===n(t))continue e;return!1}return l.length>0}notEqual(e,t,r){return void 0===t?null:!this.equal(e,t,r)}minLength(e,t,r){return(r="number"==typeof r?r.toString():r).length>=t}maxLength(e,t,r){return(r="number"==typeof r?r.toString():r).length<=t}length(e,t,r){return r="number"==typeof r?r.toString():r,(null===(t=Array.isArray(t)?t:[t,t])[0]||r.length>=t[0])&&(null===t[1]||r.length<=t[1])}email(e,t,r){return/^("([ !#-[\]-~]|\\[ -~])+"|[-a-z0-9!#$%&'*+/=?^_`{|}~]+(\.[-a-z0-9!#$%&'*+/=?^_`{|}~]+)*)@([0-9a-z\u00C0-\u02FF\u0370-\u1EFF]([-0-9a-z\u00C0-\u02FF\u0370-\u1EFF]{0,61}[0-9a-z\u00C0-\u02FF\u0370-\u1EFF])?\.)+[a-z\u00C0-\u02FF\u0370-\u1EFF]([-0-9a-z\u00C0-\u02FF\u0370-\u1EFF]{0,17}[a-z\u00C0-\u02FF\u0370-\u1EFF])?$/i.test(r)}url(e,t,r,n){return/^[a-z\d+.-]+:/.test(r)||(r="https://"+r),!!/^https?:\/\/((([-_0-9a-z\u00C0-\u02FF\u0370-\u1EFF]+\.)*[0-9a-z\u00C0-\u02FF\u0370-\u1EFF]([-0-9a-z\u00C0-\u02FF\u0370-\u1EFF]{0,61}[0-9a-z\u00C0-\u02FF\u0370-\u1EFF])?\.)?[a-z\u00C0-\u02FF\u0370-\u1EFF]([-0-9a-z\u00C0-\u02FF\u0370-\u1EFF]{0,17}[a-z\u00C0-\u02FF\u0370-\u1EFF])?|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|\[[0-9a-f:]{3,39}\])(:\d{1,5})?(\/\S*)?$/i.test(r)&&(n.value=r,!0)}regexp(e,t,r){let n="string"==typeof t&&t.match(/^\/(.*)\/([imu]*)$/);try{return n&&new RegExp(n[1],n[2].replace("u","")).test(r)}catch{return null}}pattern(e,t,r,n,l){if("string"!=typeof t)return null;try{let e;try{e=new RegExp("^(?:"+t+")$",l?"ui":"u")}catch{e=new RegExp("^(?:"+t+")$",l?"i":"")}return r instanceof FileList?Array.from(r).every((t=>e.test(t.name))):e.test(r)}catch{return null}}patternCaseInsensitive(e,t,r){return this.pattern(e,t,r,null,!0)}numeric(e,t,r){return/^[0-9]+$/.test(r)}integer(e,t,r,n){return!!/^-?[0-9]+$/.test(r)&&(n.value=parseFloat(r),!0)}float(e,t,r,n){return r=r.replace(/ +/g,"").replace(/,/g,"."),!!/^-?[0-9]*\.?[0-9]+$/.test(r)&&(n.value=parseFloat(r),!0)}min(e,t,r){return Number.isFinite(t)&&(r=parseFloat(r)),r>=t}max(e,t,r){return Number.isFinite(t)&&(r=parseFloat(r)),r<=t}range(e,t,r){return Array.isArray(t)?"time"===e.type&&t[0]>t[1]?r>=t[0]||r<=t[1]:(null===t[0]||this.min(e,t[0],r))&&(null===t[1]||this.max(e,t[1],r)):null}submitted(e){return e.form["nette-submittedBy"]===e}fileSize(e,t,r){return Array.from(r).every((e=>e.size<=t))}mimeType(e,t,r){let n=[];(t=Array.isArray(t)?t:[t]).forEach((e=>n.push("^"+e.replace(/([^\w])/g,"\\$1").replace("\\*",".*")+"$")));let l=new RegExp(n.join("|"));return Array.from(r).every((e=>!e.type||l.test(e.type)))}image(e,t,r){return this.mimeType(e,t??["image/gif","image/png","image/jpeg","image/webp"],r)}static(e,t){return t}}let t={"á":"a","ä":"a","č":"c","ď":"d","é":"e","ě":"e","í":"i","ľ":"l","ň":"n","ó":"o","ô":"o","ř":"r","š":"s","ť":"t","ú":"u","ů":"u","ý":"y","ž":"z"};let r=new class{formErrors=[];validators=new e;#e={};#t={};#r=new WeakMap;#n(e,t){let r=e.elements.namedItem(t);return r instanceof RadioNodeList?r[0]:r}#l(e){let t=e.form.elements.namedItem(e.name);return t instanceof RadioNodeList?Array.from(t):[t]}#i(e){"loading"!==document.readyState?e.call(this):document.addEventListener("DOMContentLoaded",e)}getValue(e){return e instanceof HTMLInputElement?"radio"===e.type?this.#l(e).find((e=>e.checked))?.value??null:"file"===e.type?e.files:"checkbox"===e.type?e.name.endsWith("[]")?this.#l(e).filter((e=>e.checked)).map((e=>e.value)):e.checked:e.value.trim():e instanceof HTMLSelectElement?e.multiple?Array.from(e.selectedOptions,(e=>e.value)):e.selectedOptions[0]?.value??null:e instanceof HTMLTextAreaElement?e.value:e instanceof RadioNodeList?this.getValue(e[0]):null}getEffectiveValue(e,t=!1){let r=this.getValue(e);if(r===e.getAttribute("data-nette-empty-value")&&(r=""),t&&void 0===this.#e[e.name]){this.#e[e.name]=!0;let t={value:r};this.validateControl(e,void 0,!0,t),r=t.value,delete this.#e[e.name]}return r}validateControl(e,t,r=!1,n,l){t??=JSON.parse(e.getAttribute("data-nette-rules")??"[]"),n??={value:this.getEffectiveValue(e)},l??=!this.validateRule(e,":filled",null,n);for(let i of t){let t=i.op.match(/(~)?([^?]+)/),a=i.control?this.#n(e.form,i.control):e;if(i.neg=!!t[1],i.op=t[2],i.condition=!!i.rules,!a)continue;if(l&&!i.condition&&":filled"!==i.op)continue;let o=this.validateRule(a,i.op,i.arg,e===a?n:void 0);if(null!==o)if(i.neg&&(o=!o),i.condition&&o){if(!this.validateControl(e,i.rules,r,n,":blank"!==i.op&&l))return!1}else if(!i.condition&&!o){if(this.isDisabled(a))continue;if(!r){let t=Array.isArray(i.arg)?i.arg:[i.arg],r=i.msg.replace(/%(value|\d+)/g,((r,n)=>this.getValue("value"===n?a:e.form.elements.namedItem(t[n].control))));this.addError(a,r)}return!1}}return!0}validateForm(e,t=!1){let r,n=e.form??e;if(this.formErrors=[],null!==e.getAttribute("formnovalidate")){let t=JSON.parse(e.getAttribute("data-nette-validation-scope")??"[]");if(!t.length)return this.showFormErrors(n,[]),!0;r=new RegExp("^("+t.join("-|")+"-)")}for(let e of n.elements)if(e.willValidate&&e.validity.badInput)return e.reportValidity(),!1;for(let e of n.elements)if(e.getAttribute("data-nette-rules")&&(!r||e.name.replace(/]\[|\[|]|$/g,"-").match(r))&&!this.isDisabled(e)&&!this.validateControl(e,void 0,t)&&!this.formErrors.length)return!1;let l=!this.formErrors.length;return this.showFormErrors(n,this.formErrors),l}isDisabled(e){return"radio"===e.type?this.#l(e).every((e=>e.disabled)):e.disabled}addError(e,t){this.formErrors.push({element:e,message:t})}showFormErrors(e,t){let r,n=[];for(let e of t)n.indexOf(e.message)<0&&(n.push(e.message),r??=e.element);n.length&&this.showModal(n.join("\n"),(()=>{r?.focus()}))}showModal(e,t){let r=document.createElement("dialog");if(!r.showModal)return alert(e),void t();let n=document.createElement("style");n.innerText=".netteFormsModal { text-align: center; margin: auto; border: 2px solid black; padding: 1rem } .netteFormsModal button { padding: .1em 2em }";let l=document.createElement("button");l.innerText="OK",l.onclick=()=>{r.remove(),t()},r.setAttribute("class","netteFormsModal"),r.innerText=e+"\n\n",r.append(n,l),document.body.append(r),r.showModal()}validateRule(e,t,r,n){if(e.validity.badInput)return":filled"===t;n??={value:this.getEffectiveValue(e,!0)};let l=":"===t.charAt(0)?t.substring(1):t;l=l.replace("::","_").replaceAll("\\","");let i=Array.isArray(r)?r:[r];return i=i.map((t=>{if(t?.control){let r=this.#n(e.form,t.control);return r===e?n.value:this.getEffectiveValue(r,!0)}return t})),"valid"===l&&(i[0]=this),this.validators[l]?this.validators[l](e,Array.isArray(r)?i:i[0],n.value,n):null}toggleForm(e,t){this.#t={};for(let r of Array.from(e.elements))r.getAttribute("data-nette-rules")&&this.toggleControl(r,void 0,null,!t);for(let e in this.#t)this.toggle(e,this.#t[e].state,this.#t[e].elem,t)}toggleControl(e,t,r=null,n=!1,l,i){t??=JSON.parse(e.getAttribute("data-nette-rules")??"[]"),l??={value:this.getEffectiveValue(e)},i??=!this.validateRule(e,":filled",null,l);let a,o=!1;for(let s of t){let t=s.op.match(/(~)?([^?]+)/),u=s.control?this.#n(e.form,s.control):e;if(s.neg=!!t[1],s.op=t[2],s.condition=!!s.rules,u&&(!i||s.condition||":filled"===s.op)){if(a=r,!1!==r){if(a=this.validateRule(u,s.op,s.arg,e===u?l:void 0),null===a)continue;s.neg&&(a=!a),s.condition||(r=a)}if(s.condition&&this.toggleControl(e,s.rules,a,n,l,":blank"!==s.op&&i)||s.toggle){o=!0,n&&this.#l(u).filter((e=>!this.#r.has(e))).forEach((t=>{t.addEventListener("change",(t=>this.toggleForm(e.form,t))),this.#r.set(t,null)}));for(let t in s.toggle??{})this.#t[t]??={elem:e,state:!1},this.#t[t].state||=s.toggle[t]?!!a:!a}}}return o}toggle(e,t,r,n){/^\w[\w.:-]*$/.test(e)&&(e="#"+e),Array.from(document.querySelectorAll(e)).forEach((e=>e.hidden=!t))}compactCheckboxes(e,t){let r={};for(let n of e.elements)n instanceof HTMLInputElement&&"checkbox"===n.type&&n.name.endsWith("[]")&&n.checked&&!n.disabled&&(t.delete(n.name),r[n.name]??=[],r[n.name].push(n.value));for(let e in r)t.set(e.substring(0,e.length-2),r[e].join(","))}initForm(e){"get"===e.method&&e.hasAttribute("data-nette-compact")&&e.addEventListener("formdata",(t=>this.compactCheckboxes(e,t.formData))),Array.from(e.elements).some((e=>e.getAttribute("data-nette-rules")))&&(this.toggleForm(e),e.noValidate||(e.noValidate=!0,e.addEventListener("submit",(t=>{this.validateForm(t.submitter||e)||(t.stopImmediatePropagation(),t.preventDefault())})),e.addEventListener("reset",(()=>{setTimeout((()=>this.toggleForm(e)))}))))}initOnLoad(){this.#i((()=>{Array.from(document.forms).forEach((e=>this.initForm(e)))}))}};return r.version="3.5.3",r.webalize=function(e){e=e.toLowerCase();let r="";for(let n=0;n Date: Tue, 6 Aug 2024 01:34:19 +0200 Subject: [PATCH 14/15] netteForms: restructured package, includes UMD and ESM (BC break) --- rollup.config.js | 41 +++++++++++++++++++++++++----- src/assets/{ => dist}/package.json | 12 ++++----- src/assets/index.esm.ts | 7 +++++ src/assets/index.umd.ts | 2 +- tests/netteForms/karma.conf.ts | 2 +- 5 files changed, 48 insertions(+), 16 deletions(-) rename src/assets/{ => dist}/package.json (68%) create mode 100644 src/assets/index.esm.ts diff --git a/rollup.config.js b/rollup.config.js index 8a369754..95ba912a 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -34,21 +34,21 @@ function spaces2tabs() { export default [ - { + { // TODO: consider the possibility of cutting off the UMD versions completely due to collision input: 'src/assets/index.umd.ts', output: [ { format: 'umd', name: 'Nette', - dir: 'src/assets', - entryFileNames: 'netteForms.js', + dir: 'src/assets/dist', + entryFileNames: 'nette-forms.umd.js', generatedCode: 'es2015', }, { format: 'umd', name: 'Nette', - dir: 'src/assets', - entryFileNames: 'netteForms.min.js', + dir: 'src/assets/dist', + entryFileNames: 'nette-forms.umd.min.js', generatedCode: 'es2015', plugins: [ terser(), @@ -65,9 +65,36 @@ export default [ }, { - input: 'src/assets/index.umd.ts', + input: 'src/assets/index.esm.ts', + output: [ + { + format: 'es', + dir: 'src/assets/dist', + entryFileNames: 'nette-forms.esm.js', + generatedCode: 'es2015', + }, + { + format: 'es', + dir: 'src/assets/dist', + entryFileNames: 'nette-forms.esm.min.js', + generatedCode: 'es2015', + plugins: [ + terser(), + ], + }, + ], + plugins: [ + json(), + nodeResolve(), + typescript(), + spaces2tabs(), + ], + }, + + { + input: 'src/assets/index.esm.ts', output: [{ - file: 'src/assets/netteForms.d.ts', + file: 'src/assets/dist/nette-forms.d.ts', format: 'es', }], plugins: [ diff --git a/src/assets/package.json b/src/assets/dist/package.json similarity index 68% rename from src/assets/package.json rename to src/assets/dist/package.json index 9451d82d..3aabed2d 100644 --- a/src/assets/package.json +++ b/src/assets/dist/package.json @@ -1,6 +1,6 @@ { "name": "nette-forms", - "version": "3.5.3", + "version": "4.0.0", "description": "Client side script for Nette Forms Component", "keywords": [ "nette", @@ -10,12 +10,10 @@ "homepage": "https://nette.org", "author": "David Grudl (https://davidgrudl.com)", "license": "BSD-3-Clause", - "main": "src/assets/netteForms.js", - "types": "src/assets/netteForms.d.ts", - "unpkg": "src/assets/netteForms.min.js", - "files": [ - "src/assets" - ], + "main": "nette-forms.umd.js", + "module": "nette-forms.esm.js", + "types": "nette-forms.d.ts", + "unpkg": "nette-forms.umd.min.js", "repository": { "type": "git", "url": "git+https://github.com/nette/forms.git", diff --git a/src/assets/index.esm.ts b/src/assets/index.esm.ts new file mode 100644 index 00000000..5be89db1 --- /dev/null +++ b/src/assets/index.esm.ts @@ -0,0 +1,7 @@ +import { FormValidator } from './formValidator'; + +// TODO +export function initialize() { +} + +export { FormValidator }; diff --git a/src/assets/index.umd.ts b/src/assets/index.umd.ts index 55621a62..1e73639f 100644 --- a/src/assets/index.umd.ts +++ b/src/assets/index.umd.ts @@ -1,6 +1,6 @@ import { FormValidator } from './formValidator'; import { webalize } from './webalize'; -import { version } from './package.json'; +import { version } from './dist/package.json'; type NetteForms = FormValidator & { version: string; webalize: typeof webalize }; let nette = new FormValidator as NetteForms; diff --git a/tests/netteForms/karma.conf.ts b/tests/netteForms/karma.conf.ts index 3712c64d..059cb3d0 100644 --- a/tests/netteForms/karma.conf.ts +++ b/tests/netteForms/karma.conf.ts @@ -4,7 +4,7 @@ module.exports = function (config) { frameworks: ['jasmine'], browsers: ['ChromeHeadless'], files: [ - '../../src/assets/netteForms.js', + '../../src/assets/dist/nette-forms.umd.js', 'spec/*Spec.js', ], autoWatch: false, From ad58e590710387969ae1086e6b462b32e846f05f Mon Sep 17 00:00:00 2001 From: "milos.brecher" Date: Tue, 22 Jul 2025 14:33:33 +0200 Subject: [PATCH 15/15] Support typed autowiring of two parameters in form handlers --- src/Forms/Form.php | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/Forms/Form.php b/src/Forms/Form.php index 27efad23..613b5cc2 100644 --- a/src/Forms/Form.php +++ b/src/Forms/Form.php @@ -522,15 +522,29 @@ private function invokeHandlers(iterable $handlers, $button = null): void $args = []; if ($params) { $type = Helpers::getSingleType($params[0]); - $args[] = match (true) { - !$type => $button ?? $this, - $this instanceof $type => $this, - $button instanceof $type => $button, - default => $this->getValues($type), - }; - if (isset($params[1])) { - $args[] = $this->getValues(Helpers::getSingleType($params[1])); - } + + $autowireByTypes = false; + $valuesAsFirst = in_array($type, ['array', \Nette\Utils\ArrayHash::class, \stdClass::class], true); + if($valuesAsFirst && isset($params[1])){ + $type2 = Helpers::getSingleType($params[1]); + $autowireByTypes = $this instanceof $type2; + } + + if ($autowireByTypes) { + $args[] = $this->getValues($type); + $args[] = $this; + + } else { + $args[] = match (true) { + !$type => $button ?? $this, + $this instanceof $type => $this, + $button instanceof $type => $button, + default => $this->getValues($type), + }; + if (isset($params[1])) { + $args[] = $this->getValues(Helpers::getSingleType($params[1])); + } + } } $handler(...$args);