[BUGFIX] Registration of multiple additional view models
[Packages/TYPO3.CMS.git] / typo3 / sysext / form / Documentation / Concepts / FormEditor / Index.rst
1 .. include:: ../../Includes.txt
2
3
4 .. _concepts-formeditor:
5
6 Form editor
7 ===========
8
9
10 .. _concepts-formeditor-general:
11
12 What does it do?
13 ----------------
14
15 The ``form editor`` is a powerful graphical user interface which allows the
16 backend editor to create ``form definitions`` without writing a single line
17 of code. Those ``form definitions`` will be used by the frontend process to
18 render beautiful forms.
19
20 The ``form editor`` is a modular interface which consists of several
21 components:
22
23 - Stage: central visual component of the ``form editor`` which displays the
24   form elements in an abstract view and a frontend preview
25 - Tree: displays the structure of the form as a tree
26 - Inspector: context specific toolbar which handles the visual display of
27   form element options and allows editing those
28 - Core: includes core functionalities of the ``form editor``
29 - ViewModel: defines and steers the visual display
30 - Mediator: delegates events of the components
31 - Modals: processes modals
32 - FormEditor: provides API functions
33 - Helper: helper functions which mainly allow the manipulation of DOM
34   elements
35
36 Generally speaking, the ``Modals``, ``Inspector``, and ``Stage`` components
37 can be adapted through configuration. Especially the ``Inspector`` component
38 is modular and extremely flexible. As an integrator, you can reuse so-called
39 ``inspector editors``. Those elements are input fields of different types
40 which allow the backend editor to alter all of the available form element
41 options.
42
43 .. figure:: ../../Images/javascript_module_interaction.png
44    :alt: JavaScript module interaction
45
46    JavaScript module interaction
47
48 There is a general ``form editor`` configuration which can be found below
49 the following configuration path:
50
51 .. code-block:: yaml
52
53    TYPO3:
54      CMS:
55        Form:
56          prototypes:
57            standard:
58              formEditor:
59
60 Furthermore, you are able to configure the ``form editor`` regarding its
61 different aspects. The configuration can be found below the following
62 configuration paths:
63
64 .. code-block:: yaml
65
66    TYPO3:
67      CMS:
68        Form:
69          prototypes:
70            standard:
71              formElementsDefinition:
72                <formElementTypeIdentifier>:
73                  formEditor:
74              finishersDefinition:
75                <finisherIdentifier>
76                  formEditor:
77              validatorsDefinition:
78                <validatorIdentifier>
79                  formEditor:
80
81
82 .. _concepts-formeditor-stage:
83
84 Stage
85 -----
86
87 The ``Stage`` is the central visual component of the form editor which
88 displays the form elements in two different modes:
89
90 - abstract view: all form elements of a ``Page`` are presented in an
91   abstract way,
92 - frontend preview: renders the form like it will (nearly) be displayed in
93   the frontend ('nearly' since you have to make sure that your frontend CSS
94   is also loaded in the backend in order to get the exact preview).
95
96 Per default, the frontend templates of EXT:form are based on Twitter
97 Bootstrap. Since the backend of TYPO3 CMS also depends on this CSS framework,
98 the corresponding CSS files are already loaded in the backend context.
99 Nevertheless, certain parts of the CSS were overridden and extended in order
100 to meet the specific needs of the TYPO3 backend. Thus, the frontend preview
101 in the backend could differ compared to the "real" frontend.
102
103 If your frontend preview requires loading additional CSS or a CSS framework
104 then go ahead and configure a specific ``prototype`` accordingly.
105
106 Beside the frontend templates, there are also templates for the abstract
107 view, i.e. you can customize the rendering of the abstract view for each
108 form element. If you have created your own form elements, in most cases you
109 will fall back to the already existing Fluid templates. But remember, you
110 are always able to create you own Fluid templated and adapt the abstract view
111 till it suits your needs.
112
113 For more information, read the following chapter: ':ref:`Common abstract view form element templates<apireference-formeditor-stage-commonabstractformelementtemplates>`'.
114
115
116 .. _concepts-formeditor-inspector:
117
118 Inspector
119 ---------
120
121 The ``Inspector`` component is situated on the right side of the ``form
122 editor``. It is a modular, extremely flexible, and context specific toolbar
123 which depends on the chosen form element. The ``Inspector`` allows editing
124 the form element's options with the help of so-called ``inspector editors``.
125 For the most parts, the interface can be easily customized by writing
126 YAML configuration. For each form element you can define which properties
127 are available and in which way they can be edited.
128
129 In addition to the editable form element properties (like ``properties.placeholder``)
130 there are so-called ``property collections`` which can be written by the
131 ``form editor`` as well. Their definition is stored on the hierarchical
132 level of a form element. Right now, there are the following ``property
133 collections``:
134
135 - validators
136 - finishers
137
138 ``Property collections`` also make use of ``inspector editors`` in order to
139 configure them properly. Due to this, we can do a lot of cool stuff. Imagine
140 we have got a validator "Number range" with two validator options called
141 "Minimum" and "Maximum". Additionally, we have got two form elements "Age
142 spouse" and "Age infant". For both form elements the validator is available
143 but for the form element "Age child" the validator option "Minimum" is not
144 editable and the option "Maximum" is pre-filled with a certain value.
145
146
147 .. _concepts-formeditor-basicjavascriptconcepts:
148
149 Basic JavaScript concepts
150 -------------------------
151
152 The form framework was designed to be as extendible as possible. Sooner or
153 later, you want to customize the components of the ``form editor`` using
154 JavaScript. This is especially true if you want to create your own
155 ``inspector editors``. In order to achieve this, you can implement your own
156 JavaScript modules. Those modules will include the required algorithms for
157 the ``inspector editors`` and the ``abstract view`` as well as your own
158 event listing.
159
160
161 .. _concepts-formeditor-basicjavascriptconcepts-registercustomjavascriptmodules:
162
163 Register custom JavaScript modules
164 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
165
166 The following YAML configuration registers an additional JavaScript module.
167
168 .. code-block:: yaml
169
170    TYPO3:
171      CMS:
172        Form:
173          prototypes:
174            standard:
175              formEditor:
176                dynamicRequireJsModules:
177                  additionalViewModelModules:
178                    10: 'TYPO3/CMS/MySitePackage/Backend/FormEditor/ViewModel'
179
180 According to the example shown above, the JavaScript files have to be stored
181 within the folder ``my_site_package/Resources/Public/JavaScript/Backend/FormEditor/ViewModel.js``.
182 In the TYPO3 backend JavaScript files are loaded via RequireJS which depends
183 on a certain convention. The name of the module starts with **TYPO3/CMS**/MySitePackage/Backend/FormEditor/ViewModel
184 followed by your extension key TYPO3/CMS/**MySitePackage**/Backend/FormEditor/ViewModel.
185 Thus, you have to ensure that the module is stored within a subfolder of ``my_site_package/Resources/Public/JavaScript/``.
186 The part TYPO3/CMS/MySitePackage/**Backend/FormEditor**/ViewModel tells you
187 that your files have to be stored in my_site_package/Resources/Public/JavaScript/**Backend/FormEditor**/.
188 The last section TYPO3/CMS/MySitePackage/Backend/FormEditor/**ViewModel**
189 states the name of the JavaScript file without the file extension (.js).
190
191 Check out the following base template which shows you the recommended way
192 for setting up your own module.
193
194 .. code-block:: javascript
195
196    /**
197     * Module: TYPO3/CMS/MySitePackage/Backend/FormEditor/ViewModel
198     */
199    define(['jquery',
200            'TYPO3/CMS/Form/Backend/FormEditor/Helper'
201            ], function($, Helper) {
202            'use strict';
203
204        return (function($, Helper) {
205
206            /**
207             * @private
208             *
209             * @var object
210             */
211            var _formEditorApp = null;
212
213            /**
214             * @private
215             *
216             * @return object
217             */
218            function getFormEditorApp() {
219                return _formEditorApp;
220            };
221
222            /**
223             * @private
224             *
225             * @return object
226             */
227            function getPublisherSubscriber() {
228                return getFormEditorApp().getPublisherSubscriber();
229            };
230
231            /**
232             * @private
233             *
234             * @return object
235             */
236            function getUtility() {
237                return getFormEditorApp().getUtility();
238            };
239
240            /**
241             * @private
242             *
243             * @param object
244             * @return object
245             */
246            function getHelper() {
247                return Helper;
248            };
249
250            /**
251             * @private
252             *
253             * @return object
254             */
255            function getCurrentlySelectedFormElement() {
256                return getFormEditorApp().getCurrentlySelectedFormElement();
257            };
258
259            /**
260             * @private
261             *
262             * @param mixed test
263             * @param string message
264             * @param int messageCode
265             * @return void
266             */
267            function assert(test, message, messageCode) {
268                return getFormEditorApp().assert(test, message, messageCode);
269            };
270
271            /**
272             * @private
273             *
274             * @return void
275             * @throws 1491643380
276             */
277            function _helperSetup() {
278                assert('function' === $.type(Helper.bootstrap),
279                    'The view model helper does not implement the method "bootstrap"',
280                    1491643380
281                );
282                Helper.bootstrap(getFormEditorApp());
283            };
284
285            /**
286             * @private
287             *
288             * @return void
289             */
290            function _subscribeEvents() {
291                getPublisherSubscriber().subscribe('some/eventName/you/want/to/handle', function(topic, args) {
292                    myCustomCode();
293                });
294            };
295
296            /**
297             * @private
298             *
299             * @return void
300             */
301            function myCustomCode() {
302            };
303
304            /**
305             * @public
306             *
307             * @param object formEditorApp
308             * @return void
309             */
310            function bootstrap(formEditorApp) {
311                _formEditorApp = formEditorApp;
312                _helperSetup();
313                _subscribeEvents();
314            };
315
316            /**
317             * Publish the public methods.
318             * Implements the "Revealing Module Pattern".
319             */
320            return {
321                bootstrap: bootstrap
322            };
323        })($, Helper);
324    });
325
326
327 .. _concepts-formeditor-basicjavascriptconcepts-events:
328
329 Events
330 ^^^^^^
331
332 The event handling of EXT:form is based on the ``Publish/Subscribe Pattern``.
333 To learn more about this terrific pattern, check out this website: https://addyosmani.com/resources/essentialjsdesignpatterns/book/.
334 Please not that the processing sequence of the subscribers cannot be
335 influenced. Furthermore, there is no information flow between the
336 subscribers. All events have to be arranged asynchronously.
337
338 For more information, head to the API reference and read the section about
339 ':ref:`Events<concepts-formeditor-basicjavascriptconcepts-events>`'.
340
341
342 .. _concepts-formeditor-basicjavascriptconcepts-formelementmodel:
343
344 FormElement model
345 ^^^^^^^^^^^^^^^^^
346
347 Within the JavaScript code, each form element is represented by a
348 `FormElement model``. This model can be seen as a copy of the ``form
349 definition'' enriched by some additional data. The following example shows
350 you a ``form definition`` and the debug output of the corresponding
351 ``FormElement model``.
352
353 .. code-block:: yaml
354
355    identifier: javascript-form-element-model
356    label: 'JavaScript FormElement model'
357    type: Form
358    finishers:
359      -
360        identifier: EmailToReceiver
361        options:
362          subject: 'Your message: {subject}'
363          recipientAddress: your.company@example.com
364          recipientName: 'Your Company name'
365          senderAddress: '{email}'
366          senderName: '{name}'
367          replyToAddress: ''
368          carbonCopyAddress: ''
369          blindCarbonCopyAddress: ''
370          format: html
371          attachUploads: 'true'
372          translation:
373            language: ''
374    renderables:
375      -
376        identifier: page-1
377        label: 'Contact Form'
378        type: Page
379        renderables:
380          -
381            identifier: name
382            label: Name
383            type: Text
384            properties:
385              fluidAdditionalAttributes:
386                placeholder: Name
387            defaultValue: ''
388            validators:
389              -
390                identifier: NotEmpty
391
392
393 .. code-block:: javascript
394
395    {
396      "identifier": "javascript-form-element-model",
397      "label": "JavaScript FormElement model",
398      "type": "Form",
399      "prototypeName": "standard",
400      "__parentRenderable": null,
401      "__identifierPath": "example-form",
402      "finishers": [
403        {
404          "identifier": "EmailToReceiver",
405          "options": {
406            "subject": "Your message: {subject}",
407            "recipientAddress": "your.company@example.com",
408            "recipientName": "Your Company name",
409            "senderAddress": "{email}",
410            "senderName": "{name}",
411            "replyToAddress": "",
412            "carbonCopyAddress": "",
413            "blindCarbonCopyAddress": "",
414            "format": "html",
415            "attachUploads": true,
416            "translation": {
417              "language": ""
418            }
419          }
420        }
421      ],
422      "renderables": [
423        {
424          "identifier": "page-1",
425          "label": "Contact Form",
426          "type": "Page",
427          "__parentRenderable": "example-form (filtered)",
428          "__identifierPath": "example-form/page-1",
429          "renderables": [
430            {
431              "identifier": "name",
432              "defaultValue": "",
433              "label": "Name",
434              "type": "Text",
435              "properties": {
436                "fluidAdditionalAttributes": {
437                  "placeholder": "Name"
438                }
439              },
440              "__parentRenderable": "example-form/page-1 (filtered)",
441              "__identifierPath": "example-form/page-1/name",
442              "validators": [
443                {
444                  "identifier": "NotEmpty"
445                }
446              ]
447            }
448          ]
449        }
450      ]
451    }
452
453 For each form element which has child elements, you will find a property
454 called ``renderables``. Those ``renderables`` are arrays whose elements
455 consists of ``FormElement models`` of the particular child elements.
456
457 As previously mentioned, the ``FormElement model`` is a conglomerate of the
458 data of the ``form definition`` and some additional information:
459
460 - __parentRenderable
461 - __identifierPath
462
463 The following methods can be utilized in order to access the data of a
464 ``FormElement model``:
465
466 - get()
467 - set()
468 - unset()
469 - on()
470 - off()
471 - getObjectData()
472 - toString()
473 - clone()
474
475 For more information, head to the API reference and read the section about
476 the ':ref:`FormElement model<apireference-formeditor-basicjavascriptconcepts-formelementmodel>`'.
477
478
479 .. _concepts-formeditor-translation-formeditor:
480
481 Translation of form editor
482 --------------------------
483
484 All option values which reside below the following configuration keys can be
485 translated:
486
487 .. code-block:: yaml
488
489    TYPO3:
490      CMS:
491        Form:
492          prototypes:
493            standard:
494              formEditor:
495              formElementsDefinition:
496                <formElementTypeIdentifier>:
497                  formEditor:
498              finishersDefinition:
499                <finisherIdentifier>
500                  formEditor:
501              validatorsDefinition:
502                <validatorIdentifier>
503                  formEditor:
504
505 The translation files of the ``form editor`` are loaded as follows:
506
507 .. code-block:: yaml
508
509    TYPO3:
510      CMS:
511        Form:
512          prototypes:
513            standard:
514              formEditor:
515                translationFile:
516                  # translation files for the form editor
517                  10: 'EXT:form/Resources/Private/Language/Database.xlf'
518                  20: 'EXT:my_site_package/Resources/Private/Language/Database.xlf'
519
520 The process searches for each option value within all of the defined
521 translation files. If a translation is found, the translated option value
522 will be used in preference.
523
524 Imagine, the following is defined for an option value:
525
526 .. code-block:: yaml
527
528    ...
529    label: 'formEditor.elements.Form.editor.finishers.label'
530    ...
531
532 First of all, the process searches for the translation key ``formEditor.elements.Form.editor.finishers.label``
533 within the file ``20: 'EXT:my_site_package/Resources/Private/Language/Database.xlf'``
534 and after it inside the file ``10: 'EXT:form/Resources/Private/Language/Database.xlf'``.
535 If nothing is found, the option value will be displayed unmodified.
536
537 Due to compatibility issues, the setting ``translationFile`` is not defined
538 as an array in the default configuration. To load your own translation files,
539 you should define an array containing 'EXT:form/Resources/Private/Language/Database.xlf'
540 as first entry (key ``10``) followed by your own file (key ``20``) as
541 displayed in the example above.