TYPO3 v15 dev-main snapshot ()

This commit is contained in:
2026-08-10 22:31:24 +02:00
commit aad9daaefd
1506 changed files with 94005 additions and 0 deletions
@@ -0,0 +1,579 @@
.. include:: /Includes.rst.txt
.. _concepts-formeditor:
Form editor
===========
.. _concepts-formeditor-general:
What does it do?
----------------
The ``form editor`` is a powerful graphical user interface in the TYPO3 backend
which allows editors to create ``form definitions`` without writing a single line
of code. These ``form definitions`` are used by the frontend process to
render beautiful forms.
The ``form editor`` is a modular interface which consists of the following
components:
- Stage: main visual component of the backend ``form editor`` where displaying
form elements in an abstract view or a frontend preview (in the middle of the ``form editor``)
- Tree: displays the structure of the form as a tree (on the left)
- Inspector: context specific toolbar which displays
form element options and where options can be edited (on the right)
- Core: core functionality of the ``form editor``
- ViewModel: defines and controls the visual display
- Mediator: delegates component events
- Modals: processes modals
- FormEditor: provides API functions
- Helper: helper functions for the manipulation of DOM elements
The ``Modals``, ``Inspector``, and ``Stage`` components
can be modified by configuration. The ``Inspector`` component
is modular and extremely flexible. Integrators can add
``inspector editors`` (input fields of different types)
to allow backend editors to alter form element
options.
The diagram below shows Javascript module interaction between the form editor and the
core, viewmodel and mediator.
.. figure:: ../../Images/javascript_module_interaction.png
:alt: JavaScript module interaction
JavaScript module interaction
The ``form editor`` configuration is under the following configuration path:
.. code-block:: yaml
prototypes:
standard:
formEditor:
Here you can configure different aspects of the ``form editor`` under the following
configuration paths:
.. code-block:: yaml
prototypes:
standard:
formElementsDefinition:
<formElementTypeIdentifier>:
formEditor:
finishersDefinition:
<finisherIdentifier>
formEditor:
validatorsDefinition:
<validatorIdentifier>
formEditor:
.. _concepts-formeditor-components-in-detail:
Form editor components in detail
--------------------------------
.. _concepts-formeditor-stage:
Stage
^^^^^
The ``Stage`` is the central visual component of the form editor and it
can display form elements in two different modes:
- abstract view: all the form elements on a ``Page`` (a step) presented in an
abstract way,
- frontend preview: renders the form as it will be displayed in
the frontend (to render the form exactly the same as in the frontend, make sure
your frontend CSS is loaded in the backend)
By default, the frontend templates of :t3ext:`form` are based on `Bootstrap`_.
Since the backend of TYPO3 CMS also depends on `Bootstrap`_,
the corresponding CSS files will already loaded in the backend.
Nevertheless, some CSS is overridden and extended in order
to meet the specific needs of the TYPO3 backend, meaning frontend preview
(in the backend) could differ compared to the "real" frontend.
If your frontend preview requires additional CSS or a CSS framework
then go ahead and configure a specific ``prototype`` accordingly.
Beside the frontend templates, there are also templates for the abstract
view, i.e. you can customize the rendering of the abstract view for each
form element. If you have created your own form elements, in most cases you
will fall back to the already existing Fluid templates. But remember, you
are always able to create your own Fluid templates and adapt the abstract view
to suit your needs.
For more information, read the following chapter: ':ref:`Common abstract view form element templates<apireference-formeditor-stage-commonabstractformelementtemplates>`'.
.. _Bootstrap: https://getbootstrap.com/
.. _concepts-formeditor-inspector:
Inspector
^^^^^^^^^
The ``Inspector`` is on the right side of the ``form editor``. It is a modular,
flexible, and context-specific toolbar
and depends on which form element is currently selected. The ``Inspector``
is where you can edit form element options using ``inspector editors``.
The interface is easily customized by YAML configuration. You can define form element
properties and how they can be edited.
You can edit form element properties (like ``properties.placeholder``)
as well as ``property collections``. They are defined at the form element level
in the YAML configuration file. There are two types of ``property collections``:
- validators
- finishers
``Property collections`` are also configured by ``inspector editors`` and this
allows you to do some cool stuff. Imagine that you have a "Number range" validator with
two validator options "Minimum" and "Maximum" and two form elements, "Age
spouse" and "Age infant". You could set the validator for both form elements,
but make "Minimum" non-editable and pre-fill "Maximum" with a value for the "Age
infant" form element only and not the "Age spouse" form element.
.. _concepts-formeditor-translation-formeditor:
Translation of the form editor
------------------------------
All option values below the following configuration keys can be translated:
.. code-block:: yaml
prototypes:
standard:
formEditor:
formElementsDefinition:
<formElementTypeIdentifier>:
formEditor:
finishersDefinition:
<finisherIdentifier>
formEditor:
validatorsDefinition:
<validatorIdentifier>
formEditor:
The ``form editor`` translation files are loaded as follows:
.. code-block:: yaml
prototypes:
standard:
formEditor:
translationFiles:
# custom translation file
20: 'EXT:my_site_package/Resources/Private/Language/Database.xlf'
Option values are searched for in the defined
translation files. If a translation is found, the translated option value
will be used.
As an example, if the following option is defined:
.. code-block:: yaml
...
label: 'formEditor.elements.Form.editor.finishers.label'
...
The translation key ``formEditor.elements.Form.editor.finishers.label``
is first searched for in the file
``20: 'EXT:my_site_package/Resources/Private/Language/Database.xlf'``
and then in the file ``10: 'EXT:form/Resources/Private/Language/Database.xlf'``
(loaded by default by EXT:form). If nothing is found, the option value will be
displayed unmodified.
.. _concepts-formeditor-customization-formeditor:
Customization of the form editor
--------------------------------
The form editor can be customized by YAML
configuration in the configuration. The configuration is not stored in one central configuration
file. Instead, configuration is defined for each form element (see
`EXT:form/form/Configuration/Yaml/FormElements/`). In addition,
the :yaml:`Form` element itself (see `EXT:form/Configuration/Yaml/FormElements/Form.yaml`)
has some basic configuration.
A common customization is to remove form elements from the form
editor. Unlike other TYPO3 modules, the form editor cannot be configured
using backend user groups and `Access Lists` - it can only be done by YAML configuration.
Quite often, integrators tend to unset form elements as shown below.
In this example, the :yaml:`AdvancedPassword` form element is completely removed from
the form framework. Integrators and developers will no longer be able to use
the :yaml:`AdvancedPassword` element in their YAML form definitions or via API.
.. code-block:: yaml
:linenos:
:emphasize-lines: 4
prototypes:
standard:
formElementsDefinition:
AdvancedPassword: null
The correct way is to unset the :ref:`group property <prototypes.prototypeIdentifier.formelementsdefinition.formelementtypeidentifier.formeditor.group>`.
This property defines which group in the ``form editor`` "new Element"
modal the form element should belong in. Unsetting this property will remove the
form element safely from the form editor:
.. code-block:: yaml
:linenos:
:emphasize-lines: 6
prototypes:
standard:
formElementsDefinition:
AdvancedPassword:
formEditor:
group: null
.. _concepts-formeditor-extending:
Extending the form editor
-------------------------
Learn :ref:`here <concepts-finishers-customfinisherimplementations-extend-gui>`
how to make finishers configurable in the backend form editor.
.. _concepts-formeditor-basicjavascriptconcepts:
Basic JavaScript concepts
-------------------------
The form framework was designed to be as extendable as possible. Sooner or
later, you will want to customize ``form editor`` components using
JavaScript. This is especially true if you want to create your own
``inspector editors``. In order to achieve this, you can implement your own
JavaScript modules. Those modules will include the required algorithms for
the ``inspector editors`` and the ``abstract view`` as well as your own
events.
.. _concepts-formeditor-basicjavascriptconcepts-registercustomjavascriptmodules:
Register custom JavaScript modules
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can use the following configuration YAML to register your JavaScript module.
.. code-block:: yaml
prototypes:
standard:
formEditor:
dynamicJavaScriptModules:
additionalViewModelModules:
10: '@my-vendor/my-site-package/backend/form-editor/view-model.js'
.. code-block:: php
# Configuration/JavaScriptModules.php
<?php
return [
'dependencies' => ['form'],
'imports' => [
'@myvendor/my-site-package/' => 'EXT:my_site_package/Resources/Public/JavaScript/',
],
];
In the configuration above, the JavaScript files have to be in the folder
``my_site_package/Resources/Public/JavaScript/backend/form-editor/view-model.js``.
The following example module is a template you can use containing the recommended setup.
.. code-block:: javascript
/**
* Module: @my-vendor/my-site-package/backend/form-editor/view-model.js
*/
import * as Helper from '@typo3/form/backend/form-editor/helper.js'
/**
* @private
*
* @var object
*/
let _formEditorApp = null;
/**
* @private
*
* @return object
*/
function getFormEditorApp() {
return _formEditorApp;
};
/**
* @private
*
* @return object
*/
function getPublisherSubscriber() {
return getFormEditorApp().getPublisherSubscriber();
};
/**
* @private
*
* @return object
*/
function getUtility() {
return getFormEditorApp().getUtility();
};
/**
* @private
*
* @param object
* @return object
*/
function getHelper() {
return Helper;
};
/**
* @private
*
* @return object
*/
function getCurrentlySelectedFormElement() {
return getFormEditorApp().getCurrentlySelectedFormElement();
};
/**
* @private
*
* @param mixed test
* @param string message
* @param int messageCode
* @return void
*/
function assert(test, message, messageCode) {
return getFormEditorApp().assert(test, message, messageCode);
};
/**
* @private
*
* @return void
* @throws 1491643380
*/
function _helperSetup() {
assert('function' === typeof Helper.bootstrap,
'The view model helper does not implement the method "bootstrap"',
1491643380
);
Helper.bootstrap(getFormEditorApp());
};
/**
* @private
*
* @return void
*/
function _subscribeEvents() {
getPublisherSubscriber().subscribe('some/eventName/you/want/to/handle', function(topic, args) {
myCustomCode();
});
};
/**
* @private
*
* @return void
*/
function myCustomCode() {
};
/**
* @public
*
* @param object formEditorApp
* @return void
*/
export function bootstrap(formEditorApp) {
_formEditorApp = formEditorApp;
_helperSetup();
_subscribeEvents();
};
.. _concepts-formeditor-basicjavascriptconcepts-events:
Events
^^^^^^
Event handling in :t3ext:`form` is based on the ``Publish/Subscribe Pattern``.
To learn more about this terrific pattern, see: https://addyosmani.com/resources/essentialjsdesignpatterns/book/.
Please note that the processing sequence of the subscribers cannot be
influenced. Furthermore, there is no information flow between the
subscribers. All events are asynchronous.
For more information, head to the API reference and read the section about
':ref:`Events<concepts-formeditor-basicjavascriptconcepts-events>`'.
.. _concepts-formeditor-basicjavascriptconcepts-formelementmodel:
FormElement model
^^^^^^^^^^^^^^^^^
In the JavaScript code, each form element is represented by a
``FormElement model``. This model can be seen as a copy of the ``form definition``
enriched with some additional data. The following example shows
you a ``form definition`` and, below it, the debug output of ``FormElement model``.
.. code-block:: yaml
identifier: javascript-form-element-model
label: 'JavaScript FormElement model'
type: Form
finishers:
-
identifier: EmailToReceiver
options:
subject: 'Your message: {subject}'
recipients:
your.company@example.com: 'Your Company name'
ceo@example.com: 'CEO'
senderAddress: '{email}'
senderName: '{name}'
replyToRecipients:
replyTo.company@example.com: 'Your Company name'
carbonCopyRecipients:
cc.company@example.com: 'Your Company name'
blindCarbonCopyRecipients:
bcc.company@example.com: 'Your Company name'
addHtmlPart: true
attachUploads: 'true'
translation:
language: ''
title: ''
renderables:
-
identifier: page-1
label: 'Contact Form'
type: Page
renderables:
-
identifier: name
label: Name
type: Text
properties:
fluidAdditionalAttributes:
placeholder: Name
defaultValue: ''
validators:
-
identifier: NotEmpty
.. code-block:: javascript
{
"identifier": "javascript-form-element-model",
"label": "JavaScript FormElement model",
"type": "Form",
"prototypeName": "standard",
"__parentRenderable": null,
"__identifierPath": "example-form",
"finishers": [
{
"identifier": "EmailToReceiver",
"options": {
"subject": "Your message: {subject}",
"recipients": {
"your.company@example.com": "Your Company name",
"ceo@example.com": "CEO"
},
"senderAddress": "{email}",
"senderName": "{name}",
"replyToRecipients": {
"replyTo.company@example.com": "Your Company name"
},
"carbonCopyRecipients": {
"cc.company@example.com": "Your Company name"
},
"blindCarbonCopyRecipients": {
"bcc.company@example.com": "Your Company name"
},
"addHtmlPart": true,
"attachUploads": true,
"translation": {
"language": ""
},
"title": ""
}
}
],
"renderables": [
{
"identifier": "page-1",
"label": "Contact Form",
"type": "Page",
"__parentRenderable": "example-form (filtered)",
"__identifierPath": "example-form/page-1",
"renderables": [
{
"identifier": "name",
"defaultValue": "",
"label": "Name",
"type": "Text",
"properties": {
"fluidAdditionalAttributes": {
"placeholder": "Name"
}
},
"__parentRenderable": "example-form/page-1 (filtered)",
"__identifierPath": "example-form/page-1/name",
"validators": [
{
"identifier": "NotEmpty"
}
]
}
]
}
]
}
For each form element which has child elements, there is a property
called ``renderables``. ``renderables`` are arrays of ``FormElement models``
of child elements.
The ``FormElement model`` is therefore a combination of the
of ``form definition`` data and some additional information:
- __parentRenderable
- __identifierPath
The following methods can be used to access ``FormElement model`` data:
- get()
- set()
- unset()
- on()
- off()
- getObjectData()
- toString()
- clone()
Head to the API reference to read more about
the :ref:`FormElement model<apireference-formeditor-basicjavascriptconcepts-formelementmodel>`.