[TASK] Streamline EXT:form code 72/51972/21
authorBenni Mack <benni@typo3.org>
Tue, 7 Mar 2017 07:45:35 +0000 (08:45 +0100)
committerChristian Kuhn <lolli@schwarzbu.ch>
Fri, 17 Mar 2017 13:01:39 +0000 (14:01 +0100)
* Register "formvh:" as global namespace, simplifying the templates
* Remove formvh:be.pageRenderer and add the missing files to EXT:fluid
* Migrate callbacks to signal slots and deprecate the callbacks
* Fix plain mail viewhelper, and deprecated it as it can be done in
  Fluid directly
* Code cleanup (fix indention, unused variables etc.)
* Deprecate custom checkbox VH because the fluid bug is gone
* Change tx_form view properties to ".0" instead of ".5" to be in line
  with FSC
* Streamline fluid VH additionalAttributes usage; add compatibility for
  previous configuration; Add BE form editor auto migration
* Fix small JavaScript bugs
* Fix small configuration bugs

Resolves: #80301
Resolves: #80287
Releases: master
Change-Id: Icf68b8a9a6876805af7bf273735d3d30984136ed
Reviewed-on: https://review.typo3.org/51972
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Ralf Zimmermann <ralf.zimmermann@tritum.de>
Tested-by: Ralf Zimmermann <ralf.zimmermann@tritum.de>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
66 files changed:
typo3/sysext/core/Documentation/Changelog/master/Important-80301-ExtFormCleanupAndCallbackMigration.rst [new file with mode: 0644]
typo3/sysext/fluid/Classes/ViewHelpers/Be/PageRendererViewHelper.php
typo3/sysext/form/Classes/Controller/FormEditorController.php
typo3/sysext/form/Classes/Controller/FormManagerController.php
typo3/sysext/form/Classes/Domain/Factory/AbstractFormFactory.php
typo3/sysext/form/Classes/Domain/Model/FormElements/AbstractFormElement.php
typo3/sysext/form/Classes/Domain/Model/FormElements/AbstractSection.php
typo3/sysext/form/Classes/Domain/Model/FormElements/AdvancedPassword.php
typo3/sysext/form/Classes/Domain/Model/FormElements/DatePicker.php
typo3/sysext/form/Classes/Domain/Model/FormElements/FileUpload.php
typo3/sysext/form/Classes/Domain/Model/FormElements/FormElementInterface.php
typo3/sysext/form/Classes/Domain/Model/FormElements/Section.php
typo3/sysext/form/Classes/Domain/Model/FormElements/UnknownFormElement.php
typo3/sysext/form/Classes/Domain/Model/Renderable/AbstractRenderable.php
typo3/sysext/form/Classes/Domain/Model/Renderable/RenderableInterface.php
typo3/sysext/form/Classes/Domain/Model/Renderable/RootRenderableInterface.php
typo3/sysext/form/Classes/Domain/Renderer/FluidFormRenderer.php
typo3/sysext/form/Classes/Domain/Renderer/RendererInterface.php
typo3/sysext/form/Classes/Domain/Runtime/FormRuntime.php
typo3/sysext/form/Classes/Hooks/FormElementsOnSubmitHooks.php [new file with mode: 0644]
typo3/sysext/form/Classes/Hooks/FormPagePreviewRenderer.php
typo3/sysext/form/Classes/Mvc/Property/PropertyMappingConfiguration.php [new file with mode: 0644]
typo3/sysext/form/Classes/Service/TranslationService.php
typo3/sysext/form/Classes/ViewHelpers/Be/PageRendererViewHelper.php [deleted file]
typo3/sysext/form/Classes/ViewHelpers/Form/CheckboxViewHelper.php
typo3/sysext/form/Classes/ViewHelpers/PlainTextMailViewHelper.php
typo3/sysext/form/Classes/ViewHelpers/RenderRenderableViewHelper.php
typo3/sysext/form/Classes/ViewHelpers/TranslateElementPropertyViewHelper.php
typo3/sysext/form/Configuration/PageTS/modWizards.ts
typo3/sysext/form/Configuration/TypoScript/setup.txt
typo3/sysext/form/Configuration/Yaml/BaseSetup.yaml
typo3/sysext/form/Configuration/Yaml/FormEditorSetup.yaml
typo3/sysext/form/Resources/Private/Backend/Layouts/FormEditor.html
typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Yaml/NewForms/SimpleContactForm.yaml
typo3/sysext/form/Resources/Private/Frontend/Partials/AdvancedPassword.html
typo3/sysext/form/Resources/Private/Frontend/Partials/Checkbox.html
typo3/sysext/form/Resources/Private/Frontend/Partials/ContentElement.html
typo3/sysext/form/Resources/Private/Frontend/Partials/DatePicker.html
typo3/sysext/form/Resources/Private/Frontend/Partials/Field/Field.html
typo3/sysext/form/Resources/Private/Frontend/Partials/Field/Required.html
typo3/sysext/form/Resources/Private/Frontend/Partials/Fieldset.html
typo3/sysext/form/Resources/Private/Frontend/Partials/FileUpload.html
typo3/sysext/form/Resources/Private/Frontend/Partials/Hidden.html
typo3/sysext/form/Resources/Private/Frontend/Partials/ImageUpload.html
typo3/sysext/form/Resources/Private/Frontend/Partials/MultiCheckbox.html
typo3/sysext/form/Resources/Private/Frontend/Partials/MultiSelect.html
typo3/sysext/form/Resources/Private/Frontend/Partials/Page.html
typo3/sysext/form/Resources/Private/Frontend/Partials/Password.html
typo3/sysext/form/Resources/Private/Frontend/Partials/RadioButton.html
typo3/sysext/form/Resources/Private/Frontend/Partials/SingleSelect.html
typo3/sysext/form/Resources/Private/Frontend/Partials/StaticText.html
typo3/sysext/form/Resources/Private/Frontend/Partials/SummaryPage.html
typo3/sysext/form/Resources/Private/Frontend/Partials/Text.html
typo3/sysext/form/Resources/Private/Frontend/Partials/Textarea.html
typo3/sysext/form/Resources/Private/Frontend/Partials/UnknownElement.html
typo3/sysext/form/Resources/Private/Frontend/Templates/Finishers/Email/Html.html
typo3/sysext/form/Resources/Private/Frontend/Templates/Finishers/Email/Plaintext.html
typo3/sysext/form/Resources/Private/Frontend/Templates/Form.html
typo3/sysext/form/Resources/Private/Frontend/Templates/Render.html
typo3/sysext/form/Resources/Private/Language/Database.xlf
typo3/sysext/form/Resources/Public/Images/hidden.svg [new file with mode: 0644]
typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/Core.js
typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/InspectorComponent.js
typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/ViewModel.js
typo3/sysext/form/ext_localconf.php
typo3/sysext/form/ext_tables.php

diff --git a/typo3/sysext/core/Documentation/Changelog/master/Important-80301-ExtFormCleanupAndCallbackMigration.rst b/typo3/sysext/core/Documentation/Changelog/master/Important-80301-ExtFormCleanupAndCallbackMigration.rst
new file mode 100644 (file)
index 0000000..bca2cc5
--- /dev/null
@@ -0,0 +1,264 @@
+.. include:: ../../Includes.txt
+
+===========================================================
+Important: #80301 - EXT:form - Cleanup / callback migration
+===========================================================
+
+See :issue:`80301`
+
+Description
+===========
+
+The callback 'onBuildingFinished' is deprecated and will be removed in TYPO3 v9.
+--------------------------------------------------------------------------------
+
+Use the new signal slot 'onBuildingFinished' instead.
+
+Connect to the signal:
+
+.. code-block:: php
+
+    \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class)->connect(
+        \TYPO3\CMS\Form\Domain\Runtime\FormRuntime::class,
+        'onBuildingFinished',
+        \VENDOR\YourNamespace\YourClass::class,
+        'onBuildingFinished'
+    );
+
+Use the signal:
+
+.. code-block:: php
+
+    /**
+     * @param \TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface $renderable
+     * @return void
+     */
+    public function onBuildingFinished(\TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface $renderable)
+    {
+    }
+
+
+This signal will be dispatched for each renderable.
+
+
+The callback 'beforeRendering' is deprecated and will be removed in TYPO3 v9.
+-----------------------------------------------------------------------------
+
+Use the new signal slot 'beforeRendering' instead.
+
+Connect to the signal:
+
+.. code-block:: php
+
+    \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class)->connect(
+        \TYPO3\CMS\Form\Domain\Runtime\FormRuntime::class,
+        'beforeRendering',
+        \VENDOR\YourNamespace\YourClass::class,
+        'beforeRendering'
+    );
+
+Use the signal:
+
+.. code-block:: php
+
+    /**
+     * @param \TYPO3\CMS\Form\Domain\Runtime\FormRuntime $formRuntime
+     * @param \TYPO3\CMS\Form\Domain\Model\Renderable\RootRenderableInterface $renderable
+     * @return void
+     */
+    public function beforeRendering(\TYPO3\CMS\Form\Domain\Runtime\FormRuntime $formRuntime, \TYPO3\CMS\Form\Domain\Model\Renderable\RootRenderableInterface $renderable)
+    {
+    }
+
+
+This signal will be dispatched for each renderable.
+
+
+The callback 'onSubmit' is deprecated and will be removed in TYPO3 v9.
+----------------------------------------------------------------------
+
+Use the new signal slot 'onSubmit' instead.
+
+Connect to the signal:
+
+.. code-block:: php
+
+    \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class)->connect(
+        \TYPO3\CMS\Form\Domain\Runtime\FormRuntime::class,
+        'onSubmit',
+        \VENDOR\YourNamespace\YourClass::class,
+        'onSubmit'
+    );
+
+Use the signal:
+
+.. code-block:: php
+
+    /**
+     * @param \TYPO3\CMS\Form\Domain\Runtime\FormRuntime $formRuntime
+     * @param \TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface $renderable
+     * @param mixed &$elementValue submitted value of the element *before post processing*
+     * @param array $requestArguments submitted raw request values
+     * @return void
+     */
+    public function onSubmit(\TYPO3\CMS\Form\Domain\Runtime\FormRuntime $formRuntime, \TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface $renderable, &$elementValue, array $requestArguments = [])
+    {
+    }
+
+
+This signal will be dispatched for each renderable.
+
+
+The callback 'initializeFormElement' dispatches the 'initializeFormElement' signal.
+-----------------------------------------------------------------------------------
+
+Connect to the signal:
+
+.. code-block:: php
+
+    \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class)->connect(
+        \TYPO3\CMS\Form\Domain\Model\Renderable\AbstractRenderable::class,
+        'initializeFormElement',
+        \VENDOR\YourNamespace\YourClass::class,
+        'initializeFormElement'
+    );
+
+Use the signal:
+
+.. code-block:: php
+
+    /**
+     * @param \TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface $renderable
+     * @return void
+     */
+    public function initializeFormElement(\TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface $renderable)
+    {
+    }
+
+
+This enables you to override the 'initializeFormElement' method within your custom implementation class.
+If you do not call the parents 'initializeFormElement' then no signal will be thrown.
+Furthermore, you can connect to the signal and initialize the generic form elements without defining a
+custom implementaion to access the 'initializeFormElement' method.
+You only need a class which connects to this signal. Then detect the form element you wish to initialize.
+This saves you a lot of configuration!
+
+
+The form manager dispatches the 'beforeFormCreate' signal.
+----------------------------------------------------------
+
+Connect to the signal:
+
+.. code-block:: php
+
+    \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class)->connect(
+        \TYPO3\CMS\Form\Controller\FormManagerController::class,
+        'beforeFormCreate',
+        \VENDOR\YourNamespace\YourClass::class,
+        'beforeFormCreate'
+    );
+
+Use the signal:
+
+.. code-block:: php
+
+    /**
+     * @string $formPersistenceIdentifier
+     * @array $formDefinition
+     * @return void
+     */
+    public function beforeFormCreate(string $formPersistenceIdentifier, array &$formDefinition)
+    {
+    }
+
+
+The form manager dispatches the 'beforeFormDuplicate' signal.
+-------------------------------------------------------------
+
+Connect to the signal:
+
+.. code-block:: php
+
+    \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class)->connect(
+        \TYPO3\CMS\Form\Controller\FormManagerController::class,
+        'beforeFormDuplicate',
+        \VENDOR\YourNamespace\YourClass::class,
+        'beforeFormDuplicate'
+    );
+
+Use the signal:
+
+.. code-block:: php
+
+    /**
+     * @string $formPersistenceIdentifier
+     * @array $formDefinition
+     * @return void
+     */
+    public function beforeFormDuplicate(string $formPersistenceIdentifier, array &$formDefinition)
+    {
+    }
+
+
+The form manager dispatches the 'beforeFormDelete' signal.
+----------------------------------------------------------
+
+Connect to the signal:
+
+.. code-block:: php
+
+    \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class)->connect(
+        \TYPO3\CMS\Form\Controller\FormManagerController::class,
+        'beforeFormDelete',
+        \VENDOR\YourNamespace\YourClass::class,
+        'beforeFormDelete'
+    );
+
+Use the signal:
+
+.. code-block:: php
+
+    /**
+     * @string $formPersistenceIdentifier
+     * @return void
+     */
+    public function beforeFormDelete(string $formPersistenceIdentifier)
+    {
+    }
+
+The form editor dispatches the 'beforeFormSave' signal.
+-------------------------------------------------------
+
+Connect to the signal:
+
+.. code-block:: php
+
+    \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class)->connect(
+        \TYPO3\CMS\Form\Controller\FormEditorController::class,
+        'beforeFormSave',
+        \VENDOR\YourNamespace\YourClass::class,
+        'beforeFormSave'
+    );
+
+Use the signal:
+
+.. code-block:: php
+
+    /**
+     * @string $formPersistenceIdentifier
+     * @array $formDefinition
+     * @return void
+     */
+    public function beforeFormSave(string $formPersistenceIdentifier, array &$formDefinition)
+    {
+    }
+
+
+New form element property: properties.fluidAdditionalAttributes
+---------------------------------------------------------------
+
+To deal with fluid ViewHelpers 'additionalAttributes' it is necessary to introduce a new configuration scope "properties.fluidAdditionalAttributes" for each form element.
+This configuration property will be used to fill the fluid ViewHelper property "additionalAttributes".
+
+
+.. index:: Frontend, Backend, ext:form
index 5781273..2036f1b 100644 (file)
@@ -67,6 +67,7 @@ class PageRendererViewHelper extends AbstractViewHelper
         $this->registerArgument('addJsInlineLabels', 'array', 'Custom labels to add to JavaScript inline labels');
         $this->registerArgument('includeRequireJsModules', 'array', 'List of RequireJS modules to be loaded');
         $this->registerArgument('jQueryNamespace', 'string', 'Store the jQuery object in a specific namespace. This option will be removed in TYPO3 v9');
+        $this->registerArgument('addInlineSettings', 'array', 'Adds Javascript Inline Setting');
     }
 
     /**
@@ -84,6 +85,7 @@ class PageRendererViewHelper extends AbstractViewHelper
         $addJsInlineLabels = $this->arguments['addJsInlineLabels'];
         $includeRequireJsModules = $this->arguments['includeRequireJsModules'];
         $jQueryNamespace = $this->arguments['jQueryNamespace'];
+        $addInlineSettings = $this->arguments['addInlineSettings'];
 
         if ($pageTitle) {
             $this->pageRenderer->setTitle($pageTitle);
@@ -129,6 +131,11 @@ class PageRendererViewHelper extends AbstractViewHelper
                 $this->pageRenderer->loadRequireJsModule($addRequireJsFile);
             }
         }
+
+        if (is_array($addInlineSettings) && count($addInlineSettings) > 0) {
+            $this->pageRenderer->addInlineSettingArray(null, $addInlineSettings);
+        }
+
         // Add inline language labels
         if (is_array($addJsInlineLabels) && count($addJsInlineLabels) > 0) {
             $extensionKey = $this->controllerContext->getRequest()->getControllerExtensionKey();
index efdf27d..c1a1a18 100644 (file)
@@ -22,6 +22,7 @@ use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Utility\ArrayUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 use TYPO3\CMS\Fluid\View\TemplateView;
 use TYPO3\CMS\Form\Domain\Configuration\ConfigurationService;
 use TYPO3\CMS\Form\Domain\Exception\RenderingException;
@@ -142,6 +143,15 @@ class FormEditorController extends AbstractBackendController
     {
         $formDefinition = ArrayUtility::stripTagsFromValuesRecursive($formDefinition);
         $formDefinition = $this->convertJsonArrayToAssociativeArray($formDefinition);
+
+        $this->objectManager
+            ->get(Dispatcher::class)
+            ->dispatch(
+                self::class,
+                'beforeFormSave',
+                [$formPersistenceIdentifier, &$formDefinition]
+            );
+
         $this->formPersistenceManager->save($formPersistenceIdentifier, $formDefinition);
         return '';
     }
index eeaa426..edfc07a 100644 (file)
@@ -28,6 +28,7 @@ use TYPO3\CMS\Core\Page\PageRenderer;
 use TYPO3\CMS\Core\Utility\ArrayUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Mvc\View\JsonView;
+use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 use TYPO3\CMS\Form\Exception as FormException;
 use TYPO3\CMS\Form\Service\TranslationService;
 use TYPO3\CMS\Lang\LanguageService;
@@ -107,6 +108,15 @@ class FormManagerController extends AbstractBackendController
         $form['prototypeName'] = $prototypeName;
 
         $formPersistenceIdentifier = $this->formPersistenceManager->getUniquePersistenceIdentifier($form['identifier'], $savePath);
+
+        $this->objectManager
+            ->get(Dispatcher::class)
+            ->dispatch(
+                self::class,
+                'beforeFormCreate',
+                [$formPersistenceIdentifier, &$form]
+            );
+
         $this->formPersistenceManager->save($formPersistenceIdentifier, $form);
 
         return $this->controllerContext->getUriBuilder()->uriFor('index', ['formPersistenceIdentifier' => $formPersistenceIdentifier], 'FormEditor');
@@ -128,6 +138,15 @@ class FormManagerController extends AbstractBackendController
         $formToDuplicate['identifier'] = $this->formPersistenceManager->getUniqueIdentifier($this->convertFormNameToIdentifier($formName));
 
         $formPersistenceIdentifier = $this->formPersistenceManager->getUniquePersistenceIdentifier($formToDuplicate['identifier'], $savePath);
+
+        $this->objectManager
+            ->get(Dispatcher::class)
+            ->dispatch(
+                self::class,
+                'beforeFormDuplicate',
+                [$formPersistenceIdentifier, &$formToDuplicate]
+            );
+
         $this->formPersistenceManager->save($formPersistenceIdentifier, $formToDuplicate);
 
         return $this->controllerContext->getUriBuilder()->uriFor('index', ['formPersistenceIdentifier' => $formPersistenceIdentifier], 'FormEditor');
@@ -162,6 +181,14 @@ class FormManagerController extends AbstractBackendController
     public function deleteAction(string $formPersistenceIdentifier)
     {
         if (empty($this->getReferences($formPersistenceIdentifier))) {
+            $this->objectManager
+                ->get(Dispatcher::class)
+                ->dispatch(
+                    self::class,
+                    'beforeFormDelete',
+                    [$formPersistenceIdentifier]
+                );
+
             $this->formPersistenceManager->delete($formPersistenceIdentifier);
         } else {
             $this->addFlashMessage(
index 3cf96b1..2ac4939 100644 (file)
@@ -17,7 +17,11 @@ namespace TYPO3\CMS\Form\Domain\Factory;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 use TYPO3\CMS\Form\Domain\Model\FormDefinition;
+use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
 
 /**
  * Base class for custom *Form Factories*. A Form Factory is responsible for building
@@ -51,8 +55,8 @@ use TYPO3\CMS\Form\Domain\Model\FormDefinition;
 abstract class AbstractFormFactory implements FormFactoryInterface
 {
     /**
-     * Helper to be called by every AbstractFormFactory after everything has been built to trigger the "onBuildingFinished"
-     * template method on all form elements.
+     * Helper to be called by every AbstractFormFactory after everything has been built to dispatch the "onBuildingFinished"
+     * signal on all form elements.
      *
      * @param FormDefinition $form
      * @return void
@@ -61,7 +65,16 @@ abstract class AbstractFormFactory implements FormFactoryInterface
     protected function triggerFormBuildingFinished(FormDefinition $form)
     {
         foreach ($form->getRenderablesRecursively() as $renderable) {
+            GeneralUtility::deprecationLog('EXT:form - calls for "onBuildingFinished" are deprecated since TYPO3 v8 and will be removed in TYPO3 v9');
             $renderable->onBuildingFinished();
+
+            GeneralUtility::makeInstance(ObjectManager::class)
+                ->get(Dispatcher::class)
+                ->dispatch(
+                    FormRuntime::class,
+                    'onBuildingFinished',
+                    [$renderable]
+                );
         }
     }
 }
index bd61d44..63a493f 100644 (file)
@@ -17,6 +17,9 @@ namespace TYPO3\CMS\Form\Domain\Model\FormElements;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 use TYPO3\CMS\Extbase\Validation\Validator\NotEmptyValidator;
 use TYPO3\CMS\Form\Domain\Exception\IdentifierNotValidException;
 use TYPO3\CMS\Form\Domain\Model\Renderable\AbstractRenderable;
@@ -74,6 +77,13 @@ abstract class AbstractFormElement extends AbstractRenderable implements FormEle
      */
     public function initializeFormElement()
     {
+        GeneralUtility::makeInstance(ObjectManager::class)
+            ->get(Dispatcher::class)
+            ->dispatch(
+                AbstractRenderable::class,
+                'initializeFormElement',
+                [$this]
+            );
     }
 
     /**
@@ -163,8 +173,10 @@ abstract class AbstractFormElement extends AbstractRenderable implements FormEle
      * @param array $requestArguments submitted raw request values
      * @return void
      * @api
+     * @deprecated since TYPO3 v8, will be removed in TYPO3 v9
      */
     public function onSubmit(FormRuntime $formRuntime, &$elementValue, array $requestArguments = [])
     {
+        GeneralUtility::logDeprecatedFunction();
     }
 }
index b00f276..312f582 100644 (file)
@@ -200,8 +200,10 @@ abstract class AbstractSection extends AbstractCompositeRenderable
      * @param array $requestArguments submitted raw request values
      * @return void
      * @api
+     * @deprecated since TYPO3 v8, will be removed in TYPO3 v9
      */
     public function onSubmit(FormRuntime $formRuntime, &$elementValue, array $requestArguments = [])
     {
+        GeneralUtility::logDeprecatedFunction();
     }
 }
index 95bd7bf..fb94c6e 100644 (file)
@@ -18,14 +18,13 @@ namespace TYPO3\CMS\Form\Domain\Model\FormElements;
  */
 
 use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Extbase\Error\Error;
-use TYPO3\CMS\Extbase\Object\ObjectManager;
 use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
 
 /**
  * A password with confirmation form element
  *
  * Scope: frontend
+ * @deprecated since TYPO3 v8, will be removed in TYPO3 v9
  */
 class AdvancedPassword extends AbstractFormElement
 {
@@ -40,16 +39,10 @@ class AdvancedPassword extends AbstractFormElement
      * @return void
      * @see FormRuntime::mapAndValidate()
      * @internal
+     * @deprecated since TYPO3 v8, will be removed in TYPO3 v9
      */
     public function onSubmit(FormRuntime $formRuntime, &$elementValue, array $requestArguments = [])
     {
-        if ($elementValue['password'] !== $elementValue['confirmation']) {
-            $processingRule = $this->getRootForm()->getProcessingRule($this->getIdentifier());
-            $processingRule->getProcessingMessages()->addError(
-                GeneralUtility::makeInstance(ObjectManager::class)
-                    ->get(Error::class, 'Password doesn\'t match confirmation', 1334768052)
-            );
-        }
-        $elementValue = $elementValue['password'];
+        GeneralUtility::logDeprecatedFunction();
     }
 }
index 1cd6038..3dc273c 100644 (file)
@@ -32,5 +32,6 @@ class DatePicker extends AbstractFormElement
     public function initializeFormElement()
     {
         $this->setDataType('DateTime');
+        parent::initializeFormElement();
     }
 }
index 0bfe713..f5885e3 100644 (file)
@@ -15,12 +15,7 @@ namespace TYPO3\CMS\Form\Domain\Model\FormElements;
  * The TYPO3 project - inspiring people to share!
  */
 
-use TYPO3\CMS\Core\Resource\ResourceFactory;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Core\Utility\PathUtility;
-use TYPO3\CMS\Extbase\Object\ObjectManager;
-use TYPO3\CMS\Form\Mvc\Property\TypeConverter\UploadedFileReferenceConverter;
-use TYPO3\CMS\Form\Mvc\Validation\MimeTypeValidator;
 
 /**
  * A generic file upload form element
@@ -37,73 +32,16 @@ class FileUpload extends AbstractFormElement
     public function initializeFormElement()
     {
         $this->setDataType('TYPO3\CMS\Extbase\Domain\Model\FileReference');
+        parent::initializeFormElement();
     }
 
     /**
-     * Set the property mapping configuration for the file upload element.
-     * * Add the UploadedFileReferenceConverter to convert an uploaded file to an
-     *   FileReference.
-     * * Add the MimeTypeValidator to the UploadedFileReferenceConverter to
-     *   delete non valid filetypes directly.
-     * * Setup the storage:
-     *   If the property "saveToFileMount" exist for this element it will be used.
-     *   If this file mount or the property "saveToFileMount" does not exist
-     *   the folder in which the form definition lies (persistence identifier) will be used.
-     *   If the form is generated programmatically and therefore no
-     *   persistence identifier exist the default storage "1:/user_upload/" will be used.
-     *
      * @return void
      * @internal
-     * @todo: could we find a not so ugly solution for that?
+     * @deprecated since TYPO3 v8, will be removed in TYPO3 v9
      */
     public function onBuildingFinished()
     {
-        /** @var \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration $propertyMappingConfiguration */
-        $propertyMappingConfiguration = $this->getRootForm()->getProcessingRule($this->getIdentifier())->getPropertyMappingConfiguration();
-
-        $mimeTypeValidator = GeneralUtility::makeInstance(ObjectManager::class)
-            ->get(MimeTypeValidator::class, ['allowedMimeTypes' => $this->properties['allowedMimeTypes']]);
-        $uploadConfiguration = [
-            UploadedFileReferenceConverter::CONFIGURATION_FILE_VALIDATORS => [$mimeTypeValidator],
-            UploadedFileReferenceConverter::CONFIGURATION_UPLOAD_CONFLICT_MODE => 'rename',
-        ];
-
-        $saveToFileMountIdentifier = (isset($this->properties['saveToFileMount'])) ? $this->properties['saveToFileMount'] : null;
-        if ($this->checkSaveFileMountAccess($saveToFileMountIdentifier)) {
-            $uploadConfiguration[UploadedFileReferenceConverter::CONFIGURATION_UPLOAD_FOLDER] = $saveToFileMountIdentifier;
-        } else {
-            $persistenceIdentifier = $this->getRootForm()->getPersistenceIdentifier();
-            if (!empty($persistenceIdentifier)) {
-                $pathinfo = PathUtility::pathinfo($persistenceIdentifier);
-                $saveToFileMountIdentifier  = $pathinfo['dirname'];
-                if ($this->checkSaveFileMountAccess($saveToFileMountIdentifier)) {
-                    $uploadConfiguration[UploadedFileReferenceConverter::CONFIGURATION_UPLOAD_FOLDER] = $saveToFileMountIdentifier;
-                }
-            }
-        }
-
-        $propertyMappingConfiguration->setTypeConverterOptions(UploadedFileReferenceConverter::class, $uploadConfiguration);
-    }
-
-    /**
-     * @param string $saveToFileMountIdentifier
-     * @return bool
-     * @internal
-     */
-    protected function checkSaveFileMountAccess(string $saveToFileMountIdentifier): bool
-    {
-        if (empty($saveToFileMountIdentifier)) {
-            return false;
-        }
-
-        $resourceFactory = GeneralUtility::makeInstance(ObjectManager::class)
-            ->get(ResourceFactory::class);
-
-        try {
-            $resourceFactory->getFolderObjectFromCombinedIdentifier($saveToFileMountIdentifier);
-            return true;
-        } catch (\InvalidArgumentException $e) {
-            return false;
-        }
+        GeneralUtility::logDeprecatedFunction();
     }
 }
index 4f475aa..80b43e6 100644 (file)
@@ -144,6 +144,7 @@ interface FormElementInterface extends RenderableInterface
      * @return void
      * @see FormRuntime::mapAndValidate()
      * @api
+     * @deprecated since TYPO3 v8, will be removed in TYPO3 v9
      */
     public function onSubmit(FormRuntime $formRuntime, &$elementValue, array $requestArguments = []);
 }
index 5b7772e..0b6b140 100644 (file)
@@ -17,8 +17,12 @@ namespace TYPO3\CMS\Form\Domain\Model\FormElements;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 use TYPO3\CMS\Extbase\Validation\Validator\NotEmptyValidator;
 use TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface;
+use TYPO3\CMS\Form\Domain\Model\Renderable\AbstractRenderable;
 
 /**
  * A Section, being part of a bigger Page
@@ -47,6 +51,13 @@ class Section extends AbstractSection implements FormElementInterface
      */
     public function initializeFormElement()
     {
+        GeneralUtility::makeInstance(ObjectManager::class)
+            ->get(Dispatcher::class)
+            ->dispatch(
+                AbstractRenderable::class,
+                'initializeFormElement',
+                [$this]
+            );
     }
 
     /**
index ff29362..ed1c3d9 100644 (file)
@@ -17,6 +17,9 @@ namespace TYPO3\CMS\Form\Domain\Model\FormElements;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 use TYPO3\CMS\Form\Domain\Exception\IdentifierNotValidException;
 use TYPO3\CMS\Form\Domain\Model\Renderable\AbstractRenderable;
 use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
@@ -47,6 +50,21 @@ class UnknownFormElement extends AbstractRenderable implements FormElementInterf
     }
 
     /**
+     * @return void
+     * @api
+     */
+    public function initializeFormElement()
+    {
+        GeneralUtility::makeInstance(ObjectManager::class)
+            ->get(Dispatcher::class)
+            ->dispatch(
+                AbstractRenderable::class,
+                'initializeFormElement',
+                [$this]
+            );
+    }
+
+    /**
      * Returns a unique identifier of this element.
      * While element identifiers are only unique within one form,
      * this includes the identifier of the form itself, making it "globally" unique
@@ -74,16 +92,6 @@ class UnknownFormElement extends AbstractRenderable implements FormElementInterf
     }
 
     /**
-     * Not used in this implementation
-     *
-     * @return void
-     * @internal
-     */
-    public function initializeFormElement()
-    {
-    }
-
-    /**
      * @return mixed the default value for this Form Element
      * @internal
      */
@@ -141,8 +149,10 @@ class UnknownFormElement extends AbstractRenderable implements FormElementInterf
      * @return void
      * @see FormRuntime::mapAndValidate()
      * @internal
+     * @deprecated since TYPO3 v8, will be removed in TYPO3 v9
      */
     public function onSubmit(FormRuntime $formRuntime, &$elementValue, array $requestArguments = [])
     {
+        GeneralUtility::logDeprecatedFunction();
     }
 }
index 3e83248..4a1eb9f 100644 (file)
@@ -130,6 +130,12 @@ abstract class AbstractRenderable implements RenderableInterface
         }
 
         if (isset($options['properties'])) {
+            if (isset($options['properties']['placeholder'])) {
+                GeneralUtility::deprecationLog('EXT:form - "properties.placeholder" is deprecated since TYPO3 v8 and will be removed in TYPO3 v9. Use "properties.fluidAdditionalAttributes.placeholder."');
+                $options['properties']['fluidAdditionalAttributes']['placeholder'] = $options['properties']['placeholder'];
+                unset($options['properties']['placeholder']);
+            }
+
             foreach ($options['properties'] as $key => $value) {
                 $this->setProperty($key, $value);
             }
@@ -400,9 +406,11 @@ abstract class AbstractRenderable implements RenderableInterface
      * @param FormRuntime $formRuntime
      * @return void
      * @api
+     * @deprecated since TYPO3 v8, will be removed in TYPO3 v9
      */
     public function beforeRendering(FormRuntime $formRuntime)
     {
+        GeneralUtility::logDeprecatedFunction();
     }
 
     /**
@@ -413,6 +421,7 @@ abstract class AbstractRenderable implements RenderableInterface
      *
      * @return void
      * @api
+     * @deprecated since TYPO3 v8, will be removed in TYPO3 v9
      */
     public function onBuildingFinished()
     {
index 1739817..7b185c7 100644 (file)
@@ -81,6 +81,7 @@ interface RenderableInterface extends RootRenderableInterface
      *
      * @return void
      * @api
+     * @deprecated since TYPO3 v8, will be removed in TYPO3 v9
      */
     public function onBuildingFinished();
 
index 6820c48..17bbf08 100644 (file)
@@ -62,6 +62,7 @@ interface RootRenderableInterface
      * @param FormRuntime $formRuntime
      * @return void
      * @api
+     * @deprecated since TYPO3 v8, will be removed in TYPO3 v9
      */
     public function beforeRendering(FormRuntime $formRuntime);
 
index f8c2a10..1d2487e 100644 (file)
@@ -5,6 +5,8 @@ namespace TYPO3\CMS\Form\Domain\Renderer;
 /*
  * This file is part of the TYPO3 CMS project.
  *
+ * It originated from the Neos.Form package (www.neos.io)
+ *
  * It is free software; you can redistribute it and/or modify it under
  * the terms of the GNU General Public License, either version 2
  * of the License, or any later version.
@@ -17,8 +19,10 @@ namespace TYPO3\CMS\Form\Domain\Renderer;
 
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 use TYPO3\CMS\Fluid\View\TemplateView;
 use TYPO3\CMS\Form\Domain\Exception\RenderingException;
+use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
 use TYPO3\CMS\Form\ViewHelpers\RenderRenderableViewHelper;
 
 /**
@@ -124,10 +128,10 @@ class FluidFormRenderer extends AbstractElementRenderer implements RendererInter
     /**
      * Renders the FormDefinition.
      *
-     * This method is expected to invoke the beforeRendering() callback
+     * This method is expected to dispatch the 'beforeRendering' signal
      * on each renderable.
-     * This method invoke the beforeRendering() callback within the 'FormDefinition'.
-     * The callbacks for each other renderables will be triggered from the
+     * This method dispatch the 'beforeRendering' signal initially.
+     * Each other signals will be dispatched from the
      * renderRenderable viewHelper.
      * {@link \TYPO3\CMS\Form\ViewHelpers\RenderRenderableViewHelper::renderStatic()}
      *
@@ -172,9 +176,17 @@ class FluidFormRenderer extends AbstractElementRenderer implements RendererInter
         // from the renderable
         $view->getTemplatePaths()->fillFromConfigurationArray($renderingOptions);
 
-        // Invoke the beforeRendering callback on the renderable
+        GeneralUtility::deprecationLog('EXT:form - calls for "beforeRendering" are deprecated since TYPO3 v8 and will be removed in TYPO3 v9');
         $this->formRuntime->getFormDefinition()->beforeRendering($this->formRuntime);
 
+        GeneralUtility::makeInstance(ObjectManager::class)
+            ->get(Dispatcher::class)
+            ->dispatch(
+                FormRuntime::class,
+                'beforeRendering',
+                [$this->formRuntime, $this->formRuntime->getFormDefinition()]
+            );
+
         return $view->render($this->formRuntime->getTemplateName());
     }
 }
index 142b75f..9e12483 100644 (file)
@@ -39,7 +39,7 @@ interface RendererInterface
     public function setControllerContext(ControllerContext $controllerContext);
 
     /**
-     * Note: This method is expected to invoke the beforeRendering() callback
+     * Note: This method is expected to dispatch the 'beforeRendering' signal
      * on each $renderable
      *
      * @return string the rendered $formRuntime
index fa40a27..25b6e7c 100644 (file)
@@ -27,6 +27,7 @@ use TYPO3\CMS\Extbase\Mvc\Web\Response;
 use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
 use TYPO3\CMS\Extbase\Property\Exception as PropertyException;
 use TYPO3\CMS\Extbase\Reflection\PropertyReflection;
+use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 use TYPO3\CMS\Form\Domain\Exception\RenderingException;
 use TYPO3\CMS\Form\Domain\Finishers\FinisherContext;
 use TYPO3\CMS\Form\Domain\Model\FormDefinition;
@@ -406,15 +407,36 @@ class FormRuntime implements RootRenderableInterface, \ArrayAccess
         };
 
         $value = null;
+
+        GeneralUtility::deprecationLog('EXT:form - calls for "onSubmit" are deprecated since TYPO3 v8 and will be removed in TYPO3 v9');
         $page->onSubmit($this, $value, $requestArguments);
+
+        $this->objectManager
+            ->get(Dispatcher::class)
+            ->dispatch(
+                self::class,
+                'onSubmit',
+                [$this, $page, &$value, $requestArguments]
+            );
+
         foreach ($page->getElementsRecursively() as $element) {
             try {
                 $value = ArrayUtility::getValueByPath($requestArguments, $element->getIdentifier(), '.');
             } catch (\RuntimeException $exception) {
                 $value = null;
             }
+
+            GeneralUtility::deprecationLog('EXT:form - calls for "onSubmit" are deprecated since TYPO3 v8 and will be removed in TYPO3 v9');
             $element->onSubmit($this, $value, $requestArguments);
 
+            $this->objectManager
+                ->get(Dispatcher::class)
+                ->dispatch(
+                    self::class,
+                    'onSubmit',
+                    [$this, $element, &$value, $requestArguments]
+                );
+
             $this->formState->setFormValue($element->getIdentifier(), $value);
             $registerPropertyPaths($element->getIdentifier());
         }
@@ -783,9 +805,11 @@ class FormRuntime implements RootRenderableInterface, \ArrayAccess
      * @param FormRuntime $formRuntime
      * @return void
      * @api
+     * @deprecated since TYPO3 v8, will be removed in TYPO3 v9
      */
     public function beforeRendering(FormRuntime $formRuntime)
     {
+        GeneralUtility::logDeprecatedFunction();
     }
 
     /**
diff --git a/typo3/sysext/form/Classes/Hooks/FormElementsOnSubmitHooks.php b/typo3/sysext/form/Classes/Hooks/FormElementsOnSubmitHooks.php
new file mode 100644 (file)
index 0000000..b90886c
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+namespace TYPO3\CMS\Form\Hooks;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Error\Error;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface;
+use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
+
+/**
+ * Scope: frontend
+ * @internal
+ */
+class FormElementsOnSubmitHooks
+{
+
+    /**
+     * This signal is invoked by the FormRuntime whenever values are mapped and validated
+     * (after a form page was submitted)
+     *
+     * @param FormRuntime $formRuntime
+     * @param RenderableInterface $renderable
+     * @param mixed &$elementValue submitted value of the element *before post processing*
+     * @param array $requestArguments submitted raw request values
+     * @return void
+     * @see FormRuntime::mapAndValidate()
+     * @internal
+     */
+    public function onSubmit(FormRuntime $formRuntime, RenderableInterface $renderable, &$elementValue, array $requestArguments = [])
+    {
+        if ($renderable->getType() === 'AdvancedPassword') {
+            if ($elementValue['password'] !== $elementValue['confirmation']) {
+                $processingRule = $renderable->getRootForm()->getProcessingRule($renderable->getIdentifier());
+                $processingRule->getProcessingMessages()->addError(
+                    GeneralUtility::makeInstance(ObjectManager::class)
+                        ->get(Error::class, 'Password doesn\'t match confirmation', 1334768052)
+                );
+            }
+            $elementValue = $elementValue['password'];
+        }
+    }
+}
index 9aed0b4..aea58a7 100644 (file)
@@ -15,6 +15,7 @@ namespace TYPO3\CMS\Form\Hooks;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Backend\View\PageLayoutViewDrawItemHookInterface;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Object\ObjectManager;
 use TYPO3\CMS\Extbase\Service\FlexFormService;
@@ -24,7 +25,7 @@ use TYPO3\CMS\Lang\LanguageService;
 /**
  * Contains a preview rendering for the page module of CType="form_formframework"
  */
-class FormPagePreviewRenderer implements \TYPO3\CMS\Backend\View\PageLayoutViewDrawItemHookInterface
+class FormPagePreviewRenderer implements PageLayoutViewDrawItemHookInterface
 {
     /**
      * Preprocesses the preview rendering of the content element "form_formframework".
diff --git a/typo3/sysext/form/Classes/Mvc/Property/PropertyMappingConfiguration.php b/typo3/sysext/form/Classes/Mvc/Property/PropertyMappingConfiguration.php
new file mode 100644 (file)
index 0000000..ae43b3c
--- /dev/null
@@ -0,0 +1,103 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Mvc\Property;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Resource\ResourceFactory;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\PathUtility;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Form\Domain\Model\FormElements\FileUpload;
+use TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface;
+use TYPO3\CMS\Form\Mvc\Property\TypeConverter\UploadedFileReferenceConverter;
+use TYPO3\CMS\Form\Mvc\Validation\MimeTypeValidator;
+
+/**
+ * Scope: frontend
+ */
+class PropertyMappingConfiguration
+{
+
+    /**
+     * Set the property mapping configuration for the file upload element.
+     * * Add the UploadedFileReferenceConverter to convert an uploaded file to an
+     *   FileReference.
+     * * Add the MimeTypeValidator to the UploadedFileReferenceConverter to
+     *   delete non valid filetypes directly.
+     * * Setup the storage:
+     *   If the property "saveToFileMount" exist for this element it will be used.
+     *   If this file mount or the property "saveToFileMount" does not exist
+     *   the folder in which the form definition lies (persistence identifier) will be used.
+     *   If the form is generated programmatically and therefore no
+     *   persistence identifier exist the default storage "1:/user_upload/" will be used.
+     *
+     * @param RenderableInterface $renderable
+     * @return void
+     * @internal
+     * @todo: could we find a not so ugly solution for that?
+     */
+    public function setPropertyMappingConfiguration(RenderableInterface $renderable)
+    {
+        if (get_class($renderable) === FileUpload::class) {
+            /** @var \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration $propertyMappingConfiguration */
+            $propertyMappingConfiguration = $renderable->getRootForm()->getProcessingRule($renderable->getIdentifier())->getPropertyMappingConfiguration();
+
+            $mimeTypeValidator = GeneralUtility::makeInstance(ObjectManager::class)
+                ->get(MimeTypeValidator::class, ['allowedMimeTypes' => $renderable->getProperties()['allowedMimeTypes']]);
+            $uploadConfiguration = [
+                UploadedFileReferenceConverter::CONFIGURATION_FILE_VALIDATORS => [$mimeTypeValidator],
+                UploadedFileReferenceConverter::CONFIGURATION_UPLOAD_CONFLICT_MODE => 'rename',
+            ];
+
+            $saveToFileMountIdentifier = (isset($renderable->getProperties()['saveToFileMount'])) ? $renderable->getProperties()['saveToFileMount'] : null;
+            if ($this->checkSaveFileMountAccess($saveToFileMountIdentifier)) {
+                $uploadConfiguration[UploadedFileReferenceConverter::CONFIGURATION_UPLOAD_FOLDER] = $saveToFileMountIdentifier;
+            } else {
+                $persistenceIdentifier = $renderable->getRootForm()->getPersistenceIdentifier();
+                if (!empty($persistenceIdentifier)) {
+                    $pathinfo = PathUtility::pathinfo($persistenceIdentifier);
+                    $saveToFileMountIdentifier  = $pathinfo['dirname'];
+                    if ($this->checkSaveFileMountAccess($saveToFileMountIdentifier)) {
+                        $uploadConfiguration[UploadedFileReferenceConverter::CONFIGURATION_UPLOAD_FOLDER] = $saveToFileMountIdentifier;
+                    }
+                }
+            }
+
+            $propertyMappingConfiguration->setTypeConverterOptions(UploadedFileReferenceConverter::class, $uploadConfiguration);
+        }
+    }
+
+    /**
+     * @param string $saveToFileMountIdentifier
+     * @return bool
+     * @internal
+     */
+    protected function checkSaveFileMountAccess(string $saveToFileMountIdentifier): bool
+    {
+        if (empty($saveToFileMountIdentifier)) {
+            return false;
+        }
+
+        $resourceFactory = GeneralUtility::makeInstance(ObjectManager::class)
+            ->get(ResourceFactory::class);
+
+        try {
+            $resourceFactory->getFolderObjectFromCombinedIdentifier($saveToFileMountIdentifier);
+            return true;
+        } catch (\InvalidArgumentException $e) {
+            return false;
+        }
+    }
+}
index f85c723..dfced35 100644 (file)
@@ -315,6 +315,17 @@ class TranslationService implements SingletonInterface
                 $optionLabel = (empty($translatedValue)) ? $optionLabel : $translatedValue;
             }
             $translatedValue = $defaultValue;
+        } elseif ($property === 'fluidAdditionalAttributes' && is_array($defaultValue)) {
+            foreach ($defaultValue as $propertyName => &$propertyValue) {
+                $translationKeyChain = [
+                    sprintf('%s:%s.element.%s.%s.%s', $translationFile, $formRuntime->getIdentifier(), $element->getIdentifier(), $propertyType, $propertyName),
+                    sprintf('%s:element.%s.%s.%s', $translationFile, $element->getIdentifier(), $propertyType, $propertyName),
+                    sprintf('%s:element.%s.%s.%s', $translationFile, $element->getType(), $propertyType, $propertyName),
+                ];
+                $translatedValue = $this->processTranslationChain($translationKeyChain, $language);
+                $propertyValue = (empty($translatedValue)) ? $propertyValue : $translatedValue;
+            }
+            $translatedValue = $defaultValue;
         } else {
             $translationKeyChain = [
                 sprintf('%s:%s.element.%s.%s.%s', $translationFile, $formRuntime->getIdentifier(), $element->getIdentifier(), $propertyType, $property),
diff --git a/typo3/sysext/form/Classes/ViewHelpers/Be/PageRendererViewHelper.php b/typo3/sysext/form/Classes/ViewHelpers/Be/PageRendererViewHelper.php
deleted file mode 100644 (file)
index 0c32752..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-<?php
-declare(strict_types=1);
-namespace TYPO3\CMS\Form\ViewHelpers\Be;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Fluid\ViewHelpers\Be\PageRendererViewHelper as FluidPageRendererViewHelper;
-
-/**
- * Extends the FluidPageRendererViewHelper
- * Add the additional argument 'addInlineSettings' to add settings to
- * the TYPO3 javascript inline setting
- *
- * Scope: backend
- * @internal
- */
-class PageRendererViewHelper extends FluidPageRendererViewHelper
-{
-
-    /**
-     * Initialize arguments.
-     *
-     * @return void
-     * @internal
-     */
-    public function initializeArguments()
-    {
-        parent::initializeArguments();
-        $this->registerArgument('addInlineSettings', 'array', 'Adds Javascript Inline Setting');
-    }
-
-    /**
-     * @return void
-     * @internal
-     */
-    public function render()
-    {
-        $addInlineSettings = $this->arguments['addInlineSettings'];
-        if (is_array($addInlineSettings) && count($addInlineSettings) > 0) {
-            $this->pageRenderer->addInlineSettingArray(null, $addInlineSettings);
-        }
-
-        parent::render();
-    }
-}
index 400fcba..6b8eba8 100644 (file)
@@ -15,6 +15,7 @@ namespace TYPO3\CMS\Form\ViewHelpers\Form;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Fluid\ViewHelpers\Form\CheckboxViewHelper as FluidCheckboxViewHelper;
 
 /**
@@ -23,6 +24,7 @@ use TYPO3\CMS\Fluid\ViewHelpers\Form\CheckboxViewHelper as FluidCheckboxViewHelp
  *
  * Scope: frontend
  * @api
+ * @deprecated since TYPO3 v8, will be removed in TYPO3 v9
  */
 class CheckboxViewHelper extends FluidCheckboxViewHelper
 {
@@ -32,10 +34,11 @@ class CheckboxViewHelper extends FluidCheckboxViewHelper
      *
      * @return string
      * @api
+     * @deprecated since TYPO3 v8, will be removed in TYPO3 v9
      */
     public function render()
     {
-        $this->arguments['multiple'] = (bool)$this->arguments['multiple'];
+        GeneralUtility::logDeprecatedFunction();
         return parent::render();
     }
 }
index e4a20e1..d63e7c6 100644 (file)
@@ -23,6 +23,7 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
  *
  * Scope: frontend
  * @api
+ * @deprecated since TYPO3 v8, will be removed in TYPO3 v9
  */
 class PlainTextMailViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper
 {
@@ -51,7 +52,6 @@ class PlainTextMailViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractV
     {
         $formValue = $arguments['formValue'];
 
-        $label = $formValue['element']->getLabel();
         $label = TranslateElementPropertyViewHelper::renderStatic(
             ['element' => $formValue['element'], 'property' => 'label'],
             $renderChildrenClosure,
@@ -61,7 +61,7 @@ class PlainTextMailViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractV
         $isMultiValue = $formValue['isMultiValue'];
 
         $label .= ': ';
-        if ($isMultiValue) {
+        if ($isMultiValue && is_array($processedValue)) {
             $output = $label . array_shift($processedValue) . LF;
             $indent = str_repeat(chr(32), (strlen($label)));
             foreach ($processedValue as $multiValue) {
index cadb293..f489582 100644 (file)
@@ -17,6 +17,8 @@ namespace TYPO3\CMS\Form\ViewHelpers;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
 use TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface;
 use TYPO3\CMS\Form\Domain\Model\Renderable\RootRenderableInterface;
@@ -63,48 +65,39 @@ class RenderRenderableViewHelper extends AbstractViewHelper
      */
     public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
     {
+
         /** @var FormRuntime $formRuntime */
         $formRuntime =  $renderingContext
             ->getViewHelperVariableContainer()
             ->get(self::class, 'formRuntime');
 
-        // Invoke the beforeRendering callback on the renderable
+        GeneralUtility::deprecationLog('EXT:form - calls for "beforeRendering" are deprecated since TYPO3 v8 and will be removed in TYPO3 v9');
         $arguments['renderable']->beforeRendering($formRuntime);
 
-        $renderable = $arguments['renderable'];
+        $renderingContext
+            ->getObjectManager()
+            ->get(Dispatcher::class)
+            ->dispatch(
+                FormRuntime::class,
+                'beforeRendering',
+                [$formRuntime, $arguments['renderable']]
+            );
+
         $content = $renderChildrenClosure();
-        if (!empty($content)) {
-            $content = static::renderPreviewMode($content, $renderable, $renderingContext, $formRuntime);
-        }
-        return $content;
-    }
 
-    /**
-     * Wrap every renderable with a span with a identifier path data attribute.
-     *
-     * @param string $content
-     * @param RootRenderableInterface $renderable
-     * @param RenderingContextInterface $renderingContext
-     * @param FormRuntime $formRuntime
-     * @return string
-     * @internal
-     */
-    public static function renderPreviewMode(
-        string $content,
-        RootRenderableInterface $renderable,
-        RenderingContextInterface $renderingContext,
-        FormRuntime $formRuntime
-    ): string {
-        $renderingOptions = $formRuntime->getRenderingOptions();
-        $previewMode = isset($renderingOptions['previewMode']) && $renderingOptions['previewMode'] === true;
-        if ($previewMode) {
-            $path = $renderable->getIdentifier();
-            if ($renderable instanceof RenderableInterface) {
-                while ($renderable = $renderable->getParentRenderable()) {
-                    $path = $renderable->getIdentifier() . '/' . $path;
+        // Wrap every renderable with a span with a identifier path data attribute if previewMode is active
+        if (!empty($content)) {
+            $renderingOptions = $formRuntime->getRenderingOptions();
+            if (isset($renderingOptions['previewMode']) && $renderingOptions['previewMode'] === true) {
+                $renderable = $arguments['renderable'];
+                $path = $renderable->getIdentifier();
+                if ($renderable instanceof RenderableInterface) {
+                    while ($renderable = $renderable->getParentRenderable()) {
+                        $path = $renderable->getIdentifier() . '/' . $path;
+                    }
                 }
+                $content = '<span data-element-identifier-path="' . $path . '">' . $content . '</span>';
             }
-            $content = sprintf('<span data-element-identifier-path="%s">%s</span>', $path, $content);
         }
         return $content;
     }
index a263e05..5932920 100644 (file)
@@ -52,7 +52,7 @@ class TranslateElementPropertyViewHelper extends AbstractViewHelper
      * @param array $arguments
      * @param \Closure $renderChildrenClosure
      * @param RenderingContextInterface $renderingContext
-     * @return string
+     * @return string|array
      * @api
      */
     public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
index 86a9370..edcf2c8 100644 (file)
@@ -1,17 +1,13 @@
-mod.wizards {
-    newContentElement.wizardItems {
-        forms {
-            show :=addToList(formframework)
-            elements {
-                formframework {
-                    iconIdentifier = content-elements-mailform
-                    title = LLL:EXT:backend/Resources/Private/Language/locallang_db_new_content_el.xlf:forms_mail_title
-                    description = LLL:EXT:backend/Resources/Private/Language/locallang_db_new_content_el.xlf:forms_mail_description
-                    tt_content_defValues {
-                        CType = form_formframework
-                    }
-                }
+mod.wizards.newContentElement.wizardItems.forms {
+    show :=addToList(formframework)
+    elements {
+        formframework {
+            iconIdentifier = content-elements-mailform
+            title = LLL:EXT:backend/Resources/Private/Language/locallang_db_new_content_el.xlf:forms_mail_title
+            description = LLL:EXT:backend/Resources/Private/Language/locallang_db_new_content_el.xlf:forms_mail_description
+            tt_content_defValues {
+                CType = form_formframework
             }
         }
     }
-}
\ No newline at end of file
+}
index d3b5354..8ca6165 100644 (file)
@@ -7,9 +7,9 @@ plugin.tx_form {
         #
         # That means: If you want to override the formelement templates
         # then change them within the yaml settings, not here.
-        templateRootPaths.5 = EXT:form/Resources/Private/Frontend/Templates/
-        partialRootPaths.5 = EXT:form/Resources/Private/Frontend/Partials/
-        layoutRootPaths.5 = EXT:form/Resources/Private/Frontend/Layouts/
+        templateRootPaths.0 = EXT:form/Resources/Private/Frontend/Templates/
+        partialRootPaths.0 = EXT:form/Resources/Private/Frontend/Partials/
+        layoutRootPaths.0 = EXT:form/Resources/Private/Frontend/Layouts/
     }
 
     mvc {
index 193b72e..9b80ba9 100644 (file)
@@ -62,6 +62,9 @@ TYPO3:
             AdvancedPassword:
               __inheritances:
                 10: 'TYPO3.CMS.Form.prototypes.standard.formElementsDefinition.Password'
+              # implementationClassName 'TYPO3\CMS\Form\Domain\Model\FormElements\AdvancedPassword'
+              # is deprecated since TYPO3 v8 and will be removed in TYPO3 v9
+              # will be 'TYPO3\CMS\Form\Domain\Model\FormElements\GenericFormElement' in TYPO3 v9
               implementationClassName: 'TYPO3\CMS\Form\Domain\Model\FormElements\AdvancedPassword'
               properties:
                 elementClassAttribute: 'input-medium'
@@ -83,6 +86,10 @@ TYPO3:
                 renderAsHiddenField: false
                 styleAttribute: 'position:absolute; margin:0 0 0 -999em;'
 
+            Hidden:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.formElementMixins.FormElementMixin'
+
             ### FORM ELEMENTS: SELECT ###
             Checkbox:
               __inheritances:
@@ -131,10 +138,6 @@ TYPO3:
               properties:
                 text: ''
 
-            Hidden:
-              __inheritances:
-                10: 'TYPO3.CMS.Form.mixins.formElementMixins.FormElementMixin'
-
             ContentElement:
               __inheritances:
                 10: 'TYPO3.CMS.Form.mixins.formElementMixins.ReadOnlyFormElementMixin'
index b2051b7..73faadb 100644 (file)
@@ -153,7 +153,7 @@ TYPO3:
                 paginationTitle: 'formEditor.pagination.title'
 
                 iconIdentifier: 'content-elements-mailform'
-                predefinedDefaults:
+                predefinedDefaults: []
                 editors:
                   900:
                     identifier: 'finishers'
@@ -303,7 +303,7 @@ TYPO3:
               formEditor:
                 __inheritances:
                   10: 'TYPO3.CMS.Form.mixins.formElementMixins.RemovableFormElementMixin'
-                predefinedDefaults:
+                predefinedDefaults: []
                 label: 'formEditor.elements.Page.label'
                 group: page
                 groupSorting: 100
@@ -316,7 +316,7 @@ TYPO3:
 
             SummaryPage:
               formEditor:
-                predefinedDefaults:
+                predefinedDefaults: []
                 label: 'formEditor.elements.SummaryPage.label'
                 group: page
                 groupSorting: 200
@@ -361,6 +361,22 @@ TYPO3:
                     propertyPath: 'properties.confirmationLabel'
                   500: null
 
+            Hidden:
+              formEditor:
+                label: 'formEditor.elements.Hidden.label'
+                group: input
+                groupSorting: 500
+                iconIdentifier: 't3-form-icon-hidden'
+                predefinedDefaults:
+                  defaultValue: ''
+                editors:
+                  300:
+                    identifier: 'defaultValue'
+                    templateName: 'Inspector-TextEditor'
+                    label: 'formEditor.elements.Hidden.editor.defaultValue.label'
+                    propertyPath: 'defaultValue'
+                  800: null
+
             Textarea:
               formEditor:
                 label: 'formEditor.elements.Textarea.label'
@@ -368,6 +384,7 @@ TYPO3:
                 groupSorting: 200
                 iconIdentifier: 't3-form-icon-textarea'
                 editors:
+                  600: null
                   900:
                     selectOptions:
                       # remove email validator
@@ -487,10 +504,10 @@ TYPO3:
                 editors:
                   200: null
                   300:
-                    identifier: 'staticText'
+                    identifier: 'contentElement'
                     templateName: 'Inspector-Typo3WinBrowserEditor'
-                    label: 'formEditor.elements.StaticText.editor.contentElement.label'
-                    buttonLabel: 'formEditor.elements.StaticText.editor.contentElement.buttonLabel'
+                    label: 'formEditor.elements.ContentElement.editor.contentElement.label'
+                    buttonLabel: 'formEditor.elements.ContentElement.editor.contentElement.buttonLabel'
                     browsableType: tt_content
                     propertyPath: 'properties.contentElementUid'
                     propertyValidatorsMode: 'OR'
@@ -718,7 +735,7 @@ TYPO3:
         formElementMixins:
           BaseFormElementMixin:
             formEditor:
-              predefinedDefaults:
+              predefinedDefaults: []
               editors:
                 100:
                   identifier: 'header'
@@ -787,19 +804,23 @@ TYPO3:
                   templateName: 'Inspector-RequiredValidatorEditor'
                   label: 'formEditor.elements.FormElement.editor.requiredValidator.label'
                   validatorIdentifier: 'NotEmpty'
+                  propertyPath: 'properties.fluidAdditionalAttributes.required'
+                  propertyValue: 'required'
 
           TextMixin:
             formEditor:
               predefinedDefaults:
                 properties:
-                  placeholder: ''
+                  fluidAdditionalAttributes:
+                    placeholder: ''
                 defaultValue: ''
               editors:
                 400:
                   identifier: 'placeholder'
                   templateName: 'Inspector-TextEditor'
                   label: 'formEditor.elements.TextMixin.editor.placeholder.label'
-                  propertyPath: 'properties.placeholder'
+                  propertyPath: 'properties.fluidAdditionalAttributes.placeholder'
+                  compatibilityPropertyPath: 'properties.placeholder'
                 500:
                   identifier: 'defaultValue'
                   templateName: 'Inspector-TextEditor'
index ad02201..adaeb27 100644 (file)
@@ -1,6 +1,4 @@
-{namespace formvh = TYPO3\CMS\Form\ViewHelpers}
-
-<formvh:be.pageRenderer
+<f:be.pageRenderer
     includeCssFiles="{stylesheets}"
     addInlineSettings="{addInlineSettings}"
     includeJsFiles="{0: 'EXT:backend/Resources/Public/JavaScript/jsfunc.tbe_editor.js'}"
@@ -44,4 +42,4 @@
             viewModel
         ).run();
     });
-</script>
\ No newline at end of file
+</script>
index 4e217ea..e6bce2b 100644 (file)
@@ -31,7 +31,8 @@ renderables:
         label: 'Name'
         type: Text
         properties:
-          placeholder: 'Name'
+          fluidAdditionalAttributes:
+            placeholder: 'Name'
         defaultValue: ''
         validators:
           -
@@ -41,7 +42,8 @@ renderables:
         label: 'Subject'
         type: Text
         properties:
-          placeholder: 'Subject'
+          fluidAdditionalAttributes:
+            placeholder: 'Subject'
         defaultValue: ''
         validators:
           -
@@ -51,7 +53,8 @@ renderables:
         label: 'Email'
         type: Text
         properties:
-          placeholder: 'Email address'
+          fluidAdditionalAttributes:
+            placeholder: 'Email address'
         defaultValue: ''
         validators:
           -
@@ -63,7 +66,8 @@ renderables:
         label: 'Message'
         type: Textarea
         properties:
-          placeholder: ''
+          fluidAdditionalAttributes:
+            placeholder: ''
         defaultValue: ''
         validators:
           -
index c56b4b6..7c3d1fe 100644 (file)
@@ -1,4 +1,3 @@
-{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
 <formvh:renderRenderable renderable="{element}">
     <f:render partial="Field/Field" arguments="{element: element}" contentAs="elementContent">
         <div class="form-group">
@@ -7,7 +6,7 @@
                     id="{element.uniqueIdentifier}"
                     class="{element.properties.elementClassAttribute} form-control"
                     errorClass="{element.properties.elementErrorClassAttribute}"
-                    additionalAttributes="{f:if(condition: '{element.required}', then: '{required: \'required\', placeholder: \'{formvh:translateElementProperty(element: element, property: \"placeholder\")}\'}', else: '{placeholder: \'{formvh:translateElementProperty(element: element, property: \"placeholder\")}\'}')}"
+                    additionalAttributes="{formvh:translateElementProperty(element: element, property: 'fluidAdditionalAttributes')}"
             />
             <f:if condition="{formvh:translateElementProperty(element: element, property: 'passwordDescription')}">
                 <span class="help-block">{formvh:translateElementProperty(element: element, property: 'passwordDescription')}</span>
@@ -22,8 +21,8 @@
                     id="{element.uniqueIdentifier}-confirmation"
                     class="{element.properties.confirmationClassAttribute} form-control"
                     errorClass="{element.properties.elementErrorClassAttribute}"
-                    additionalAttributes="{f:if(condition: '{element.required}', then: '{required: \'required\', placeholder: \'{formvh:translateElementProperty(element: element, property: \"placeholder\")}\'}', else: '{placeholder: \'{formvh:translateElementProperty(element: element, property: \"placeholder\")}\'}')}"
+                    additionalAttributes="{formvh:translateElementProperty(element: element, property: 'fluidAdditionalAttributes')}"
             />
         </div>
     </f:render>
-</formvh:renderRenderable>
\ No newline at end of file
+</formvh:renderRenderable>
index 7610cab..13d2697 100644 (file)
@@ -1,4 +1,3 @@
-{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
 <formvh:renderRenderable renderable="{element}">
     <f:render partial="Field/Field" arguments="{element: element}" contentAs="elementContent">
         <div class="form-check">
@@ -9,9 +8,9 @@
                         class="{element.properties.elementClassAttribute}"
                         value="{element.properties.value}"
                         errorClass="{element.properties.elementErrorClassAttribute}"
-                        additionalAttributes="{f:if(condition: '{element.required}', then: '{required: \'required\'}')}"
+                        additionalAttributes="{formvh:translateElementProperty(element: element, property: 'fluidAdditionalAttributes')}"
                 />
             </label>
         </div>
     </f:render>
-</formvh:renderRenderable>
\ No newline at end of file
+</formvh:renderRenderable>
index 7dc9fae..e1908d4 100644 (file)
@@ -1,4 +1,3 @@
-{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
 <formvh:renderRenderable renderable="{element}">
     <f:if condition="{element.rootForm.renderingOptions.previewMode}">
         <f:then>
@@ -21,4 +20,4 @@
             </f:if>
         </f:else>
     </f:if>
-</formvh:renderRenderable>
\ No newline at end of file
+</formvh:renderRenderable>
index eb784f3..8983f9b 100644 (file)
@@ -1,17 +1,15 @@
-{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
 <formvh:renderRenderable renderable="{element}">
     <div class="form-inline">
             <f:render partial="Field/Field" arguments="{element: element}" contentAs="elementContent">
                 <formvh:form.datePicker
                     id="{element.uniqueIdentifier}"
                     property="{element.identifier}"
-                    placeholder="{formvh:translateElementProperty(element: element, property: 'placeholder')}"
                     dateFormat="{element.properties.dateFormat}"
                     initialDate="{element.properties.initialDate}"
                     enableDatePicker="{element.properties.enableDatePicker}"
                     class="{element.properties.elementClassAttribute}"
                     errorClass="{element.properties.elementErrorClassAttribute}"
-                    additionalAttributes="{f:if(condition: '{element.required}', then: '{required: \'required\'}')}"
+                    additionalAttributes="{formvh:translateElementProperty(element: element, property: 'fluidAdditionalAttributes')}"
                     previewMode="{element.rootForm.renderingOptions.previewMode}"
                 />
             </f:render>
@@ -34,7 +32,7 @@
                 <label class="control-label" for="{element.uniqueIdentifier}-time-minute">{formvh:translateElementProperty(element: element, property: 'timeSelectorMinuteLabel')}</label>
                 <div class="{element.properties.containerClassAttribute}">
                     <formvh:form.timePicker
-                            id="{element.uniqueIdentifier}-time"
+                            id="{element.uniqueIdentifier}-time-minute"
                             property="{element.identifier}"
                             initialDate="{element.properties.initialDate}"
                             class="{element.properties.timeSelectorClassAttribute} form-control"
@@ -45,4 +43,4 @@
             </div>
          </f:if>
     </div>
-</formvh:renderRenderable>
\ No newline at end of file
+</formvh:renderRenderable>
index f6bbbac..cd8334c 100644 (file)
@@ -1,4 +1,3 @@
-{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
 <f:form.validationResults for="{element.identifier}">
     <div class="form-group{f:if(condition: '{validationResults.errors.0}', then: ' has-error')}">
         <label class="control-label" for="{element.uniqueIdentifier}">{formvh:translateElementProperty(element: element, property: 'label')}<f:if condition="{element.required}"><f:render partial="Field/Required" /></f:if></label>
index 71ccc55..870fe37 100644 (file)
@@ -1,4 +1,3 @@
-{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
 <formvh:renderRenderable renderable="{element}">
     <fieldset id="{element.uniqueIdentifier}" class="form-group{f:if(condition: element.properties.elementClassAttribute, then: ' {element.properties.elementClassAttribute}')}">
         <f:if condition="{element.label}">
@@ -8,4 +7,4 @@
             <f:render partial="{element.templateName}" arguments="{element: element}" />
         </f:for>
     </fieldset>
-</formvh:renderRenderable>
\ No newline at end of file
+</formvh:renderRenderable>
index d5d719a..a78e2f3 100644 (file)
@@ -1,7 +1,11 @@
-{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
 <formvh:renderRenderable renderable="{element}">
     <f:render partial="Field/Field" arguments="{element: element}" contentAs="elementContent">
-        <formvh:form.uploadedResource property="{element.identifier}" as="resource" additionalAttributes="{f:if(condition: '{element.required}', then: '{required: \'required\'}')}" accept="{element.properties.allowedMimeTypes}">
+        <formvh:form.uploadedResource
+            property="{element.identifier}"
+            as="resource"
+            additionalAttributes="{formvh:translateElementProperty(element: element, property: 'fluidAdditionalAttributes')}"
+            accept="{element.properties.allowedMimeTypes}"
+        >
             <f:if condition="{resource}">
                 <div id="{element.uniqueIdentifier}-preview">
                     {resource.originalResource.originalFile.name}
@@ -9,4 +13,4 @@
             </f:if>
         </formvh:form.uploadedResource>
     </f:render>
-</formvh:renderRenderable>
\ No newline at end of file
+</formvh:renderRenderable>
index 7e46fb0..a5ad24a 100644 (file)
@@ -1,4 +1,7 @@
-{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
 <formvh:renderRenderable renderable="{element}">
-    <f:form.hidden property="{element.identifier}" id="{element.uniqueIdentifier}" />
-</formvh:renderRenderable>
\ No newline at end of file
+    <f:form.hidden
+        property="{element.identifier}"
+        id="{element.uniqueIdentifier}"
+        additionalAttributes="{formvh:translateElementProperty(element: element, property: 'fluidAdditionalAttributes')}"
+    />
+</formvh:renderRenderable>
index 85561c7..c2b4e25 100644 (file)
@@ -1,7 +1,11 @@
-{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
 <formvh:renderRenderable renderable="{element}">
     <f:render partial="Field/Field" arguments="{element: element}" contentAs="elementContent">
-        <formvh:form.uploadedResource property="{element.identifier}" as="image" additionalAttributes="{f:if(condition: '{element.required}', then: '{required: \'required\'}')}" accept="{element.properties.allowedMimeTypes}">
+        <formvh:form.uploadedResource
+            property="{element.identifier}"
+            as="image"
+            additionalAttributes="{formvh:translateElementProperty(element: element, property: 'fluidAdditionalAttributes')}"
+            accept="{element.properties.allowedMimeTypes}"
+        >
             <f:if condition="{image}">
                 <div id="{element.uniqueIdentifier}-preview">
                     <a href="{f:uri.image(image: image, maxWidth: element.properties.imageLinkMaxWidth)}" class="{element.properties.elementClassAttribute}">
@@ -11,4 +15,4 @@
             </f:if>
         </formvh:form.uploadedResource>
     </f:render>
-</formvh:renderRenderable>
\ No newline at end of file
+</formvh:renderRenderable>
index fc55d14..fdb53a6 100644 (file)
@@ -1,16 +1,16 @@
-{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
 <formvh:renderRenderable renderable="{element}">
     <f:render partial="Field/Field" arguments="{element: element}" contentAs="elementContent">
         <div id="{element.uniqueIdentifier}" class="inputs-list">
             <f:for each="{element.properties.options}" as="label" key="value">
                 <div class="form-check">
                     <label class="form-check-label">
-                        <formvh:form.checkbox
+                        <f:form.checkbox
                                 property="{element.identifier}"
                                 multiple="1"
                                 class="{element.properties.elementClassAttribute}"
                                 value="{value}"
                                 errorClass="{element.properties.elementErrorClassAttribute}"
+                                additionalAttributes="{formvh:translateElementProperty(element: element, property: 'fluidAdditionalAttributes')}"
                         />
                         <span>{formvh:translateElementProperty(element: element, property: 'options.{value}')}</span>
                     </label>
index 1eb53fb..6f5557d 100644 (file)
@@ -1,4 +1,3 @@
-{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
 <formvh:renderRenderable renderable="{element}">
     <f:render partial="Field/Field" arguments="{element: element}" contentAs="elementContent">
         <f:form.select
@@ -8,6 +7,7 @@
                 options="{formvh:translateElementProperty(element: element, property: 'options')}"
                 multiple="multiple"
                 errorClass="{element.properties.elementErrorClassAttribute}"
+                additionalAttributes="{formvh:translateElementProperty(element: element, property: 'fluidAdditionalAttributes')}"
         />
     </f:render>
-</formvh:renderRenderable>
\ No newline at end of file
+</formvh:renderRenderable>
index a6360ea..11b7b25 100644 (file)
@@ -1,4 +1,3 @@
-{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
 <formvh:renderRenderable renderable="{page}">
     <f:if condition="{page.label}">
         <h2>{formvh:translateElementProperty(element: page, property: 'label')}</h2>
@@ -6,4 +5,4 @@
     <f:for each="{page.elements}" as="element">
         <f:render partial="{element.templateName}" arguments="{element: element}" />
     </f:for>
-</formvh:renderRenderable>
\ No newline at end of file
+</formvh:renderRenderable>
index 61f6014..60ecab8 100644 (file)
@@ -1,12 +1,11 @@
-{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
 <formvh:renderRenderable renderable="{element}">
     <f:render partial="Field/Field" arguments="{element: element}" contentAs="elementContent">
         <f:form.password
                 property="{element.identifier}"
                 id="{element.uniqueIdentifier}"
                 class="{element.properties.elementClassAttribute} form-control"
-                additionalAttributes="{f:if(condition: '{element.required}', then: '{required: \'required\', placeholder: \'{formvh:translateElementProperty(element: element, property: \"placeholder\")}\'}', else: '{placeholder: \'{formvh:translateElementProperty(element: element, property: \"placeholder\")}\'}')}"
+                additionalAttributes="{formvh:translateElementProperty(element: element, property: 'fluidAdditionalAttributes')}"
                 errorClass="{element.properties.elementErrorClassAttribute}"
         />
     </f:render>
-</formvh:renderRenderable>
\ No newline at end of file
+</formvh:renderRenderable>
index f355f10..46a8d23 100644 (file)
@@ -1,4 +1,3 @@
-{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
 <formvh:renderRenderable renderable="{element}">
     <f:render partial="Field/Field" arguments="{element: element}" contentAs="elementContent">
         <div id="{element.uniqueIdentifier}" class="inputs-list">
@@ -11,7 +10,7 @@
                                     class="{element.properties.elementClassAttribute} form-check-input"
                                     value="{value}"
                                     errorClass="{element.properties.elementErrorClassAttribute}"
-                                    additionalAttributes="{f:if(condition: '{element.required}', then: '{required: \'required\'}')}"
+                                    additionalAttributes="{formvh:translateElementProperty(element: element, property: 'fluidAdditionalAttributes')}"
                             />
                             <span>{formvh:translateElementProperty(element: element, property: 'options.{value}')}</span>
                         </label>
@@ -20,4 +19,4 @@
             </div>
         </div>
     </f:render>
-</formvh:renderRenderable>
\ No newline at end of file
+</formvh:renderRenderable>
index f668ffb..6ff1ad6 100644 (file)
@@ -1,4 +1,3 @@
-{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
 <formvh:renderRenderable renderable="{element}">
     <f:render partial="Field/Field" arguments="{element: element}" contentAs="elementContent">
         <f:form.select
@@ -7,7 +6,7 @@
                 options="{formvh:translateElementProperty(element: element, property: 'options')}"
                 class="{element.properties.elementClassAttribute} form-control"
                 errorClass="{element.properties.elementErrorClassAttribute}"
-                additionalAttributes="{f:if(condition: '{element.required}', then: '{required: \'required\'}')}"
+                additionalAttributes="{formvh:translateElementProperty(element: element, property: 'fluidAdditionalAttributes')}"
         />
     </f:render>
-</formvh:renderRenderable>
\ No newline at end of file
+</formvh:renderRenderable>
index 44676d5..44d42ed 100644 (file)
@@ -1,4 +1,3 @@
-{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
 <formvh:renderRenderable renderable="{element}">
     <div class="clearfix">
         <f:if condition="{element.label}">
@@ -8,4 +7,4 @@
             <p{f:if(condition: element.properties.elementClassAttribute, then: ' class="{element.properties.elementClassAttribute}"')}>{formvh:translateElementProperty(element: element, property: 'text') -> f:format.nl2br()}</p>
         </f:if>
     </div>
-</formvh:renderRenderable>
\ No newline at end of file
+</formvh:renderRenderable>
index 82ba495..b89b34b 100644 (file)
@@ -1,4 +1,3 @@
-{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
 <formvh:renderRenderable renderable="{page}">
     <fieldset class="form-group">
         <f:if condition="{page.label}">
@@ -6,7 +5,7 @@
         </f:if>
         <div class="table-responsive">
             <table class="table">
-                <formvh:renderAllFormValues renderable="{page.rootForm}">
+                <formvh:renderAllFormValues renderable="{page.rootForm}" as="formValue">
                     <tr>
                         <td class="summary-table-first-col">{formvh:translateElementProperty(element: formValue.element, property: 'label')}</td>
                         <td>
@@ -42,4 +41,4 @@
             </table>
         </div>
     </fieldset>
-</formvh:renderRenderable>
\ No newline at end of file
+</formvh:renderRenderable>
index 4141bcc..06b6806 100644 (file)
@@ -1,13 +1,11 @@
-{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
 <formvh:renderRenderable renderable="{element}">
     <f:render partial="Field/Field" arguments="{element: element}" contentAs="elementContent">
         <f:form.textfield
                 property="{element.identifier}"
                 id="{element.uniqueIdentifier}"
                 class="{element.properties.elementClassAttribute} form-control"
-                placeholder="{formvh:translateElementProperty(element: element, property: 'placeholder')}"
                 errorClass="{element.properties.elementErrorClassAttribute}"
-                required="{element.required}"
+                additionalAttributes="{formvh:translateElementProperty(element: element, property: 'fluidAdditionalAttributes')}"
         />
     </f:render>
-</formvh:renderRenderable>
\ No newline at end of file
+</formvh:renderRenderable>
index 7ed587f..11f7231 100644 (file)
@@ -1,4 +1,3 @@
-{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
 <formvh:renderRenderable renderable="{element}">
     <f:render partial="Field/Field" arguments="{element: element}" contentAs="elementContent">
         <f:form.textarea
@@ -8,7 +7,7 @@
                 rows="{element.properties.rows}"
                 cols="{element.properties.cols}"
                 errorClass="{element.properties.elementErrorClassAttribute}"
-                additionalAttributes="{f:if(condition: '{element.required}', then: '{required: \'required\', placeholder: \'{formvh:translateElementProperty(element: element, property: \"placeholder\")}\'}', else: '{placeholder: \'{formvh:translateElementProperty(element: element, property: \"placeholder\")}\'}')}"
+                additionalAttributes="{formvh:translateElementProperty(element: element, property: 'fluidAdditionalAttributes')}"
         />
     </f:render>
-</formvh:renderRenderable>
\ No newline at end of file
+</formvh:renderRenderable>
index d8bc3a7..6a4d07d 100644 (file)
@@ -1,2 +1 @@
-{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
-<formvh:renderRenderable renderable="{element}"> </formvh:renderRenderable>
\ No newline at end of file
+<formvh:renderRenderable renderable="{element}"> </formvh:renderRenderable>
index 0ca28d7..9efd905 100644 (file)
@@ -1,7 +1,4 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-
-{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
-
 <html>
 <head>
     <title></title>
@@ -11,7 +8,7 @@
 
 <body>
     <table width="600" cellpadding="0" cellspacing="0" border="0">
-        <formvh:renderAllFormValues renderable="{form.formDefinition}">
+        <formvh:renderAllFormValues renderable="{form.formDefinition}" as="formValue">
             <tr>
                 <td width="600" valign="top" align="left">{formvh:translateElementProperty(element: formValue.element, property: 'label')}</td>
                 <td width="600" valign="top" align="left">
@@ -45,4 +42,4 @@
         </formvh:renderAllFormValues>
     </table>
 </body>
-</html>
\ No newline at end of file
+</html>
index 436543c..675762c 100644 (file)
@@ -1,3 +1,13 @@
-{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
-
-<formvh:renderAllFormValues renderable="{form.formDefinition}"><formvh:plainTextMail formValue="{formValue}" /></formvh:renderAllFormValues>
\ No newline at end of file
+<formvh:renderAllFormValues renderable="{form.formDefinition}" as="formValue"><f:spaceless>
+    <f:if condition="{formValue.isMultiValue}">
+        <f:then>
+<formvh:translateElementProperty element="{formValue.element}" property="label" />:
+    <f:for each="{formValue.processedValue}" as="singleValue">- {singleValue}
+    </f:for>
+        </f:then>
+        <f:else>
+<formvh:translateElementProperty element="{formValue.element}" property="label" />: <f:if condition="{formValue.processedValue}"><f:then>{formValue.processedValue}</f:then><f:else>-</f:else></f:if>
+        </f:else>
+    </f:if>
+</f:spaceless>
+</formvh:renderAllFormValues>
index 70d0f4d..9d7d8ec 100644 (file)
@@ -1,4 +1,3 @@
-{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
 <formvh:renderRenderable renderable="{form}">
     <formvh:form object="{form}" action="perform" method="post" id="{form.identifier}" section="{form.identifier}" enctype="multipart/form-data">
         <f:render partial="{form.currentPage.templateName}" arguments="{page: form.currentPage}" />
@@ -7,4 +6,4 @@
             <f:render partial="Form/Navigation" arguments="{form: form}" />
         </div>
     </formvh:form>
-</formvh:renderRenderable>
\ No newline at end of file
+</formvh:renderRenderable>
index c207752..96212dc 100644 (file)
@@ -1,5 +1,4 @@
-{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
 <f:flashMessages />
 <f:if condition="{formConfiguration}">
     <formvh:render overrideConfiguration="{formConfiguration}"/>
-</f:if>
\ No newline at end of file
+</f:if>
index 48679d2..a74b7cd 100644 (file)
                 <source>Text</source>
             </trans-unit>
 
+            <trans-unit id="formEditor.elements.Hidden.label" xml:space="preserve">
+                <source>Hidden</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Hidden.editor.defaultValue.label" xml:space="preserve">
+                <source>Value</source>
+            </trans-unit>
+
             <trans-unit id="formEditor.elements.ContentElement.label" xml:space="preserve">
                 <source>Content element</source>
             </trans-unit>
                 <source>No content element selected</source>
             </trans-unit>
 
-            <trans-unit id="formEditor.elements.StaticText.editor.contentElement.label" xml:space="preserve">
+            <trans-unit id="formEditor.elements.ContentElement.editor.contentElement.label" xml:space="preserve">
                 <source>Content element uid</source>
             </trans-unit>
-            <trans-unit id="formEditor.elements.StaticText.editor.contentElement.buttonLabel" xml:space="preserve">
+            <trans-unit id="formEditor.elements.ContentElement.editor.contentElement.buttonLabel" xml:space="preserve">
                 <source>tt_content</source>
             </trans-unit>
 
diff --git a/typo3/sysext/form/Resources/Public/Images/hidden.svg b/typo3/sysext/form/Resources/Public/Images/hidden.svg
new file mode 100644 (file)
index 0000000..db92ec0
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+        viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<path style="fill:#FFFFFF;" d="M1,9.5h3v-3H1V9.5z M5,6.5v3h10v-3H5z"/>
+<path style="fill:#9A9999;" d="M0,10.5h4v-1H1v-3h3v-1H0V10.5z M5,5.5v1h10v3H5v1h11v-5H5z"/>
+<polygon style="fill:#676767;" points="6.5,4.5 6.5,3.5 5,3.5 4,3.5 2.5,3.5 2.5,4.5 4,4.5 4,11.5 2.5,11.5 2.5,12.5 4,12.5 5,12.5 
+       6.5,12.5 6.5,11.5 5,11.5 5,4.5 "/>
+</svg>
index a90b016..742e2cb 100644 (file)
@@ -822,6 +822,40 @@ define(['jquery'], function($) {
                  * @public
                  *
                  * @param string key
+                 * @param bool disablePublishersOnSet
+                 * @return void
+                 * @throws 1489321637
+                 * @throws 1489319753
+                 * @publish mixed
+                 */
+                function unset(key, disablePublishersOnSet) {
+                    var obj, oldValue, parentPropertyData, parentPropertyPath, propertyToRemove;
+                    utility().assert(utility().isNonEmptyString(key), 'Invalid parameter "key"', 1489321637);
+                    disablePublishersOnSet = !!disablePublishersOnSet;
+
+                    oldValue = get(key);
+
+                    if (key.indexOf('.') > 0) {
+                        parentPropertyPath = key.split('.');
+                        propertyToRemove = parentPropertyPath.pop();
+                        parentPropertyPath = parentPropertyPath.join('.');
+                        parentPropertyData = get(parentPropertyPath);
+                        delete parentPropertyData[propertyToRemove];
+                    } else {
+                        assert(false, 'remove toplevel properties is not supported', 1489319753);
+                    }
+
+                    if (!utility().isUndefinedOrNull(_publisherTopics[key]) && !disablePublishersOnSet) {
+                        for (var i = 0, len = _publisherTopics[key].length; i < len; ++i) {
+                            publisherSubscriber().publish(_publisherTopics[key][i], [key, undefined, oldValue, _objectData['__identifierPath']]);
+                        }
+                    }
+                };
+
+                /**
+                 * @public
+                 *
+                 * @param string key
                  * @param string topicName
                  * @return void
                  * @throws 1475361757
@@ -933,6 +967,7 @@ define(['jquery'], function($) {
                 return {
                     get: get,
                     set: set,
+                    unset: unset,
 
                     on: on,
                     off: off,
@@ -1677,7 +1712,7 @@ define(['jquery'], function($) {
              * @throws 1475604050
              */
             function createFormElement(configuration, identifierPathPrefix, parentFormElement, registerPropertyValidators, disablePublishersOnSet) {
-                var currentChildFormElements, collections, formElementTypeDefinition, identifierPath, rawChildFormElements, formElement;
+                var currentChildFormElements, collections, formElementTypeDefinition, identifierPath, rawChildFormElements, formElement, predefinedDefaults;
                 utility().assert('object' === $.type(configuration), 'Invalid parameter "configuration"', 1475375693);
                 utility().assert(utility().isNonEmptyString(configuration['identifier']), '"identifier" must not be empty', 1475436040);
                 utility().assert(utility().isNonEmptyString(configuration['type']), '"type" must not be empty', 1475604050);
@@ -1693,6 +1728,7 @@ define(['jquery'], function($) {
                 delete configuration['renderables'];
 
                 collections = {};
+                predefinedDefaults = formElementTypeDefinition['predefinedDefaults'] || {};
                 for (var collectionName in configuration) {
                     if (!configuration.hasOwnProperty(collectionName)) {
                         continue;
@@ -1700,7 +1736,14 @@ define(['jquery'], function($) {
                     if (utility().isUndefinedOrNull(_repositoryFormEditorDefinitions[collectionName])) {
                         continue;
                     }
-                    collections[collectionName] = configuration[collectionName];
+
+                    predefinedDefaults[collectionName] = predefinedDefaults[collectionName] || {};
+                    collections[collectionName] = $.extend(
+                        predefinedDefaults[collectionName] || {},
+                        configuration[collectionName]
+                    );
+
+                    delete predefinedDefaults[collectionName];
                     delete configuration[collectionName];
                 }
 
index 1987fc6..7bb4513 100644 (file)
@@ -1035,7 +1035,7 @@ define(['jquery',
          * @throws 1475421056
          */
         function renderTextEditor(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
-            var propertyPath, propertyData;
+            var compatibilityPropertyData, compatibilityPropertyPath, propertyData, propertyPath;
             assert(
                 'object' === $.type(editorConfiguration),
                 'Invalid parameter "editorConfiguration"',
@@ -1077,6 +1077,22 @@ define(['jquery',
             );
             propertyData = getCurrentlySelectedFormElement().get(propertyPath);
 
+            if (
+                getUtility().isNonEmptyString(editorConfiguration['compatibilityPropertyPath'])
+                && getUtility().isUndefinedOrNull(propertyData)
+            ) {
+                compatibilityPropertyPath = getFormEditorApp().buildPropertyPath(
+                    editorConfiguration['compatibilityPropertyPath'],
+                    collectionElementIdentifier,
+                    collectionName
+                );
+                compatibilityPropertyData = getCurrentlySelectedFormElement().get(compatibilityPropertyPath);
+
+                getCurrentlySelectedFormElement().set(propertyPath, compatibilityPropertyData, true);
+                getCurrentlySelectedFormElement().unset(compatibilityPropertyPath, true);
+                propertyData = compatibilityPropertyData;
+            }
+
             _validateCollectionElement(propertyPath, editorHtml);
 
             getHelper().getTemplatePropertyDomElement('propertyPath', editorHtml).val(propertyData);
@@ -1084,8 +1100,30 @@ define(['jquery',
             renderFormElementSelectorEditorAddition(editorConfiguration, editorHtml, propertyPath);
 
             getHelper().getTemplatePropertyDomElement('propertyPath', editorHtml).on('keyup paste', function() {
-                getCurrentlySelectedFormElement().set(propertyPath, $(this).val());
+                if (
+                    !!editorConfiguration['doNotSetIfPropertyValueIsEmpty']
+                    && !getUtility().isNonEmptyString($(this).val())
+                ) {
+                    getCurrentlySelectedFormElement().unset(propertyPath);
+                } else {
+                    getCurrentlySelectedFormElement().set(propertyPath, $(this).val());
+                }
                 _validateCollectionElement(propertyPath, editorHtml);
+                if (
+                    !getUtility().isUndefinedOrNull(editorConfiguration['additionalElementPropertyPaths'])
+                    && 'array' === $.type(editorConfiguration['additionalElementPropertyPaths'])
+                ) {
+                    for (var i = 0, len = editorConfiguration['additionalElementPropertyPaths'].length; i < len; ++i) {
+                        if (
+                            !!editorConfiguration['doNotSetIfPropertyValueIsEmpty']
+                            && !getUtility().isNonEmptyString($(this).val())
+                        ) {
+                            getCurrentlySelectedFormElement().unset(editorConfiguration['additionalElementPropertyPaths'][i]);
+                        } else {
+                            getCurrentlySelectedFormElement().set(editorConfiguration['additionalElementPropertyPaths'][i], $(this).val());
+                        }
+                    }
+                }
             });
         };
 
@@ -1507,9 +1545,11 @@ define(['jquery',
          * @throws 1475417094
          * @throws 1475417095
          * @throws 1475417096
+         * @throws 1489319751
+         * @throws 1489319752
          */
         function renderRequiredValidatorEditor(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
-            var validatorIdentifier;
+            var propertyPath, propertyValue, validatorIdentifier;
             assert(
                 'object' === $.type(editorConfiguration),
                 'Invalid parameter "editorConfiguration"',
@@ -1530,12 +1570,27 @@ define(['jquery',
                 'Invalid configuration "label"',
                 1475417096
             );
+            assert(
+                getUtility().isNonEmptyString(editorConfiguration['propertyPath']),
+                'Invalid configuration "propertyPath"',
+                1489319751
+            );
+            assert(
+                getUtility().isNonEmptyString(editorConfiguration['propertyValue']),
+                'Invalid configuration "propertyValue"',
+                1489319752
+            );
 
             validatorIdentifier = editorConfiguration['validatorIdentifier'];
             getHelper().getTemplatePropertyDomElement('label', editorHtml).append(editorConfiguration['label']);
 
+            propertyPath = getFormEditorApp()
+                .buildPropertyPath(editorConfiguration['propertyPath'], collectionElementIdentifier, collectionName);
+            propertyValue = editorConfiguration['propertyValue'];
+
             if (-1 !== getFormEditorApp().getIndexFromPropertyCollectionElement(validatorIdentifier, 'validators')) {
                 $('input[type="checkbox"]', $(editorHtml)).prop('checked', true);
+                getCurrentlySelectedFormElement().set(propertyPath, propertyValue);
             }
 
             $('input[type="checkbox"]', $(editorHtml)).on('change', function() {
@@ -1544,11 +1599,13 @@ define(['jquery',
                         'view/inspector/collectionElement/new/selected',
                         [validatorIdentifier, 'validators']
                     );
+                    getCurrentlySelectedFormElement().set(propertyPath, propertyValue);
                 } else {
                     getPublisherSubscriber().publish(
                         'view/inspector/removeCollectionElement/perform',
                         [validatorIdentifier, 'validators']
-                    );                 
+                    );
+                    getCurrentlySelectedFormElement().unset(propertyPath);
                 }
             });
         };
index 0efb0cc..00e36e2 100644 (file)
@@ -1200,7 +1200,24 @@ define(['jquery',
          * @publish view/collectionElement/removed
          */
         function removePropertyCollectionElement(collectionElementIdentifier, collectionName, formElement, disablePublishersOnSet) {
+            var collectionElementConfiguration;
+
             getFormEditorApp().removePropertyCollectionElement(collectionElementIdentifier, collectionName, formElement);
+
+            collectionElementConfiguration = getFormEditorApp().getPropertyCollectionElementConfiguration(
+                collectionElementIdentifier,
+                collectionName
+            );
+            if ('array' === $.type(collectionElementConfiguration['editors'])) {
+                for (var i = 0, len1 = collectionElementConfiguration['editors'].length; i < len1; ++i) {
+                    if ('array' === $.type(collectionElementConfiguration['editors'][i]['additionalElementPropertyPaths'])) {
+                        for (var j = 0, len2 = collectionElementConfiguration['editors'][i]['additionalElementPropertyPaths'].length; j < len2; ++j) {
+                            getCurrentlySelectedFormElement().unset(collectionElementConfiguration['editors'][i]['additionalElementPropertyPaths'][j], true);
+                        }
+                    }
+                }
+            }
+
             if (!!!disablePublishersOnSet) {
                 getPublisherSubscriber().publish('view/collectionElement/removed', [
                     collectionElementIdentifier,
index f008f51..45c13bd 100644 (file)
@@ -2,70 +2,92 @@
 defined('TYPO3_MODE') or die();
 
 call_user_func(function () {
-    // Register FE plugin
-    \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
-        'TYPO3.CMS.Form',
-        'Formframework',
-        ['FormFrontend' => 'render, perform'],
-        ['FormFrontend' => 'perform'],
-        \TYPO3\CMS\Extbase\Utility\ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT
-    );
+    if (TYPO3_MODE === 'BE') {
+        // Hook to enrich tt_content form flex element with finisher settings and form list drop down
+        $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][\TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools::class]['flexParsing'][
+            \TYPO3\CMS\Form\Hooks\DataStructureIdentifierHook::class
+        ] = \TYPO3\CMS\Form\Hooks\DataStructureIdentifierHook::class;
 
-    // Add new content element wizard entry
-    \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPageTSConfig(
-        '<INCLUDE_TYPOSCRIPT: source="FILE:EXT:form/Configuration/PageTS/modWizards.ts">'
-    );
+        // Hook to count used forms elements in tt_content
+        $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser']['formPersistenceIdentifier'] =
+            \TYPO3\CMS\Form\Hooks\SoftReferenceParserHook::class;
 
-    // FE file upload processing
-    \TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerTypeConverter(
-        \TYPO3\CMS\Form\Mvc\Property\TypeConverter\UploadedFileReferenceConverter::class
-    );
+        // Register for hook to show preview of tt_content element of CType="form_formframework" in page module
+        $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/class.tx_cms_layout.php']['tt_content_drawItem']['form_formframework'] =
+            \TYPO3\CMS\Form\Hooks\FormPagePreviewRenderer::class;
 
-    // Hook to enrich tt_content form flex element with finisher settings and form list drop down
-    $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][\TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools::class]['flexParsing'][
-        \TYPO3\CMS\Form\Hooks\DataStructureIdentifierHook::class
-    ] = \TYPO3\CMS\Form\Hooks\DataStructureIdentifierHook::class;
+        // Add a bunch of icons to icon registry
+        $iconIdentifiers = [
+            'advanced-password',
+            'checkbox',
+            'content-element',
+            'date-picker',
+            'duplicate',
+            'fieldset',
+            'file-upload',
+            'finisher',
+            'form-element-selector',
+            'hidden',
+            'image-upload',
+            'insert-after',
+            'insert-in',
+            'multi-checkbox',
+            'multi-select',
+            'page',
+            'password',
+            'radio-button',
+            'single-select',
+            'static-text',
+            'summary-page',
+            'text',
+            'textarea',
+            'validator'
+        ];
+        $iconRegistry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Imaging\IconRegistry::class);
+        foreach ($iconIdentifiers as $iconIdentifier) {
+            $iconRegistry->registerIcon(
+                't3-form-icon-' . $iconIdentifier,
+                \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class,
+                ['source' => 'EXT:form/Resources/Public/Images/' . $iconIdentifier . '.svg']
+            );
+        }
 
-    // Hook to count used forms elements in tt_content
-    $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser']['formPersistenceIdentifier'] =
-        \TYPO3\CMS\Form\Hooks\SoftReferenceParserHook::class;
+        // Add new content element wizard entry
+        \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPageTSConfig(
+            '<INCLUDE_TYPOSCRIPT: source="FILE:EXT:form/Configuration/PageTS/modWizards.ts">'
+        );
+    }
 
-    // Register for hook to show preview of tt_content element of CType="form_formframework" in page module
-    $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/class.tx_cms_layout.php']['tt_content_drawItem']['form_formframework'] =
-        \TYPO3\CMS\Form\Hooks\FormPagePreviewRenderer::class;
+    if (TYPO3_MODE === 'FE') {
+        \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class)->connect(
+            \TYPO3\CMS\Form\Domain\Runtime\FormRuntime::class,
+            'onSubmit',
+            \TYPO3\CMS\Form\Hooks\FormElementsOnSubmitHooks::class,
+            'onSubmit'
+        );
 
-    // Add a bunch of icons to icon registry
-    $iconIdentifiers = [
-        'advanced-password',
-        'checkbox',
-        'content-element',
-        'date-picker',
-        'duplicate',
-        'fieldset',
-        'file-upload',
-        'finisher',
-        'form-element-selector',
-        'image-upload',
-        'insert-after',
-        'insert-in',
-        'multi-checkbox',
-        'multi-select',
-        'page',
-        'password',
-        'radio-button',
-        'single-select',
-        'static-text',
-        'summary-page',
-        'text',
-        'textarea',
-        'validator'
-    ];
-    $iconRegistry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Imaging\IconRegistry::class);
-    foreach ($iconIdentifiers as $iconIdentifier) {
-        $iconRegistry->registerIcon(
-            't3-form-icon-' . $iconIdentifier,
-            \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class,
-            ['source' => 'EXT:form/Resources/Public/Images/' . $iconIdentifier . '.svg']
+        // FE file upload processing
+        \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class)->connect(
+            \TYPO3\CMS\Form\Domain\Runtime\FormRuntime::class,
+            'onBuildingFinished',
+            \TYPO3\CMS\Form\Mvc\Property\PropertyMappingConfiguration::class,
+            'setPropertyMappingConfiguration'
+        );
+
+        \TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerTypeConverter(
+            \TYPO3\CMS\Form\Mvc\Property\TypeConverter\UploadedFileReferenceConverter::class
         );
     }
+
+    // Register "formvh:" namespace
+    $GLOBALS['TYPO3_CONF_VARS']['SYS']['fluid']['namespaces']['formvh'][] = 'TYPO3\\CMS\\Form\\ViewHelpers';
+
+    // Register FE plugin
+    \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
+        'TYPO3.CMS.Form',
+        'Formframework',
+        ['FormFrontend' => 'render, perform'],
+        ['FormFrontend' => 'perform'],
+        \TYPO3\CMS\Extbase\Utility\ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT
+    );
 });
index c036107..aae73d7 100644 (file)
@@ -1,21 +1,25 @@
 <?php
 defined('TYPO3_MODE') or die();
 
-// Register the backend module Web->Forms
-\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerModule(
-    'TYPO3.CMS.Form',
-    'web',
-    'formbuilder',
-    '',
-    [
-        'FormManager' => 'index, show, create, duplicate, references, delete',
-        'FormEditor' => 'index, saveForm, renderFormPage, renderRenderableOptions',
-    ],
-    [
-        'access' => 'user,group',
-        'icon' => 'EXT:form/Resources/Public/Icons/Extension.png',
-        'labels' => 'LLL:EXT:form/Resources/Private/Language/locallang_module.xlf',
-        'navigationComponentId' => '',
-        'inheritNavigationComponentFromMainModule' => false
-    ]
-);
+call_user_func(function () {
+    if (TYPO3_MODE === 'BE') {
+        // Register the backend module Web->Forms
+        \TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerModule(
+            'TYPO3.CMS.Form',
+            'web',
+            'formbuilder',
+            '',
+            [
+                'FormManager' => 'index, show, create, duplicate, references, delete',
+                'FormEditor' => 'index, saveForm, renderFormPage, renderRenderableOptions',
+            ],
+            [
+                'access' => 'user,group',
+                'icon' => 'EXT:form/Resources/Public/Icons/Extension.png',
+                'labels' => 'LLL:EXT:form/Resources/Private/Language/locallang_module.xlf',
+                'navigationComponentId' => '',
+                'inheritNavigationComponentFromMainModule' => false
+            ]
+        );
+    }
+});