`. E.g.:
* Static: `form = Person`
* Dynamic 1: `form = {{form:SE}}` (the left `form` is a keyword for QFQ, the right `form` is a variable name)
* Dynamic 2: `form = {{SELECT f.name FROM Form AS f WHERE f.id=...}}` (the left `form` is a keyword for QFQ, the right `form` is a variable name)
* With the `Dynamic` option, it's easily possible to use one Typo3 page and display different forms on that specific
page.
* If a form is edited using the JSON form editor then a backup of the previous version is saved. See :ref:`formAsFile`.
Form process order
------------------
Depending on `form load / save` or `record delete`, different tasks are performed. Processing is divided into:
* Native FormElements like: `input`, `select list`, `checkbox`, `radio`, ....
* `upload` elements are categorized as native FormElement, but will be processed later.
* `pill`, `fieldset` and `subrecord` elements are only processed during form load, they do not impact `save` or `delete`.
* Action FormElement like `before...`, `after...`, `sendmail` ...
Each FormElement has an order.
Native FormElements which 'name':
* corresponds to a column in the form primary table: are grouped together in one insert or update query.
* do not correspond to a column in the primary table: needs an explicit defined Action FormElement to be handled.
FormElement processing order:
.. image:: Images/FormProcess.png
.. _record_locking:
Record locking
--------------
Support for record locking is given with mode:
* *exclusive*: user can't force a write.
* Including a timeout (default 15 mins recordLockTimeoutSeconds in :ref:`configuration`) for maximum lock time.
* *advisory*: user is only warned, but allowed to overwrite.
* *none*: no bookkeeping about locks.
Details:
* For 'new' records (r=0) there is no locking at all.
* The record locking protection is based on the `tablename` and the `record id`. Different `Forms`, with the same primary table,
will be protected by record locking.
* Action-`FormElements` updating non primary table records are not
protected by 'record locking': the QFQ record locking is *NOT 100%*.
* The 'record locking' mode will be specified per `Form`. If there are multiple Forms with different modes, and there is
already a lock for a `tablename` / `record id` pair, the most restrictive will be applied.
* A user opens a form: starting with the first change of content, a record lock will be acquired in the background. If
the lock is denied (e.g. another user already owns a lock on the record) an alert is shown. This means: the lock timeout
counts from the first change, not from the last modification on the form.
* If a timeout expires, the lock becomes invalid. During the next change in a form, the lock is acquired again.
* A lock is assigned to a record of a table. Multiple forms, with the same primary table, uses the same lock for a given record.
* If a user tries to delete a record and another user already owns a lock on that record, the delete action is denied.
* If there are different locking modes in multiple forms, the most restricting mode applies for the current lock.
* If the same user opens the same recording in different tabs or browsers, the user has the possibility to skip a lock.
Exclusive
^^^^^^^^^
An existing lock on a record forbids any write action on that record. Exception: locks owned by the same user might be overwritten.
Advisory
^^^^^^^^
An existing lock on a record informs the user that another user is currently working on that record. Nevertheless,
writing is allowed.
None
^^^^
No locking at all.
.. _comment-space-character:
Comment- and space-character
----------------------------
The following applies to the fields `Form.parameter` and `FormElement.parameter`:
* Lines will be trimmed - leading and trailing spaces will be removed.
* If a leading and/or trailing space is needed, escape it: \\ hello world \\ > ' hello world '.
* Lines starting with a '#' are treated as a comment and will not be parsed. Such lines are treated as 'empty lines'.
* The comment sign can be escaped with \\ .
.. _form-main:
Form Settings
-------------
+-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
| Name | Description |
+=========================+====================================================================================================================================================+
|Name | Unique and speaking name of the *Form*. Form will be identified by this name. Use only '[a-zA-Z0-9._+-]'. _`form-name` |
+-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
|Title | Title, shown on/above the form. _`form-title` |
+-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
|Note | Personal editor notes. _`form-note` |
+-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
|Table | Primary table of the form. _`form-tablename` |
+-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
|Primary Key | Primary key of the indicated table. Only needed if != 'id'. _`form-primary-key` |
+-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
|Required Parameter NEW | Name of required SIP parameter to create a new record (r=0), separated by comma. '#' as comment delimiter. See :ref:`form-requiredParameter` |
+-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
|Required Parameter EDIT | Name of required SIP parameter to edit an existing record (r>0), separated by comma. '#' as comment delimiter. See :ref:`form-requiredParameter` |
+-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
|Permit New | 'sip, logged_in, logged_out, always, never' (Default: sip): See :ref:`form-permitNewEdit` |
+-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
|Permit Edit | 'sip, logged_in, logged_out, always, never' (Default: sip): See :ref:`form-permitNewEdit` |
+-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
|Permit REST | See :ref:`restApi` |
+-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
|Escape Type Default | See :ref:`variable-escape`. |
+-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
|Show button | 'new, delete, close, save' (Default: 'new,delete,close,save'): Shown named buttons in the upper right corner of the form. |
| | See :ref:`form-showButton` |
+-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
|Forward Mode | 'auto | close | no | url | url-skip-history | url-sip | url-sip-skip-history' (Default: auto): See :ref:`form-forward`. |
+-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
|Forward (Mode) Page | a) URL / Typo3 page slug or b) Forward Mode (via '{{...}}') or combination of a) & b). See :ref:`form-forward`. |
+-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
|labelAlign | Label align (default/left/center/right)/ Default: 'default' (defined by Config). _`form-label-align` |
+-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
|Parameter | Misc additional parameters. See :ref:`form-parameter`. |
+-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
|BS Label Columns | The bootstrap grid system is based on 12 columns. The sum of *bsLabelColumns*, |
+-------------------------+ *bsInputColumns* and *bsNoteColumns* should be 12. These values here are the base values |
|BS Input Columns | for all *FormElements*. Exceptions per *FormElement* can be specified per *FormElement*. |
+-------------------------+ Default: label=col-md-3, input=col-md-6, note=col-md-3. See :ref:`form-layout`. |
|BS Note Columns | |
+-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
|multiMode | NOT IMPLEMENTED - 'none, horizontal, vertical' (Default 'none') |
+-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
|multiSql | NOT IMPLEMENTED - Optional. SQL Query which selects all records to edit. |
+-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
|multiDetailForm | NOT IMPLEMENTED - Optional. Form to open, if a record is selected to edit (double click on record line) |
+-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
|multiDetailFormParameter | NOT IMPLEMENTED - Optional. Translated Parameter submitted to detail form (like subrecord parameter) |
+-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
|multiFormWrap | By default (if empty) wraps the form in a HTML table. Alternative is to use CSS grid. See :ref:`multi-form-grid`. |
+-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
|multiFormCellWrap | By default (if empty) wraps each input in ``. If 'multiFormWrap' is given but `multiFormCellWrap` is empty, than the default is ``. |
| | See :ref:`multi-form-grid`. |
+-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
.. _`form-permitNewEdit`:
permitNew & permitEdit
^^^^^^^^^^^^^^^^^^^^^^
Depending on `r`, the following access permission will be taken:
* `r=0` - permitNew
* `r>0` - permitEdit
+------------+---------------------------------------------------------------------------------------------------+
| Option | Description |
+============+===================================================================================================+
| sip | The parameter 'form' and 'r' must be supplied via SIP or hard coded in the QFQ tt_content record. |
+------------+---------------------------------------------------------------------------------------------------+
| logged_in | The form will only be shown if the current User is logged in as a FE User |
+------------+---------------------------------------------------------------------------------------------------+
| logged_out | The form will only be shown if the current User is *not* logged in as a FE User |
+------------+---------------------------------------------------------------------------------------------------+
| always | No access restriction, the form will always be shown |
+------------+---------------------------------------------------------------------------------------------------+
| never | The form will never be shown |
+------------+---------------------------------------------------------------------------------------------------+
* `sip`
* is *always* the preferred way. With 'sip' it's not necessary to differ between logged in or not, cause the SIP
only exist and is only valid, if it's created via QFQ/report earlier. This means 'creating' the SIP implies
'access granted'. The grant will be revoked when the QFQ session is destroyed - this happens when a user logs out or
the web browser is closed.
* `logged_in` / `logged_out`: for forms which might be displayed without a SIP, but maybe on a protected or even
unprotected page. *The option is probably not often used.*
* `always`: such a form is always allowed to be loaded.
* `permitNew=always`: Public accessible forms (e.g. for registration) will allow users to fill and save
the form.
* `permitEdit=always`: Public accessible forms will allow users to update existing data. This
is dangerous, cause the URL parameter (recordId) 'r' might be changed by the user (URL manipulating) and therefore
the user might see and/or change data from other users. *The option is probably not often used.*
* `never`: such a form is not allowed to be loaded.
* `permitNew=never`: Public accessible forms. It's not possible to create new records.
* `permitEdit=none`: Public accessible forms. It's not possible to update records.
.. _`form-requiredParameter`:
Required Parameter New|Edit
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Comma separated list of variable names. On form load, an error message will be shown in case of missing parameters.
The parameters must be given by SIP.
The list of required parameter has to be defined for `New` (r=0, create a new record) and for `Edit` (r>0, edit existing
record).
Optional a comment might be attached after the parameter definition.
E.g.: ::
New: grId, pId # Always specify a person, grId2
Edit: pId
.. _`form-showButton`:
showButton
^^^^^^^^^^
Display or hide the button `new`, `delete`, `close`, `save`.
* *new*: Creates a new record. If the form needs any special parameter via SIP or Client (=browser), hide this 'new' button - the necessary parameter are not provided.
* *delete*: This either deletes the current record only, or (if defined via action *FormElement* 'beforeDelete' ) any specified subrecords.
* *close*: Close the current form. If there are changes, a popup opens and ask to save / close / cancel. The last page from the history will be shown.
* *save*: Save the form.
* Default: show all buttons.
.. _`form-forward`:
Forward: Save / Close
^^^^^^^^^^^^^^^^^^^^^
Forward (=forwardMode)
""""""""""""""""""""""
After the user presses *Save*, *Close*, *Delete* or *New*, different actions are possible where the browser redirects to.
* `auto` (default) - the QFQ browser Javascript logic, decides to stay on the page or to force a redirection
to a previous page. The decision depends on:
* *Close* goes back (feels like close) to the previous page. Note: if there is no history, QFQ won't close the tab,
instead a message is shown.
* *Save* stays on the current page.
* `close` - goes back (feels like close) to the previous page. Note: if there is no history, QFQ won't close the tab,
instead a message is shown.
* `no` - no change, the browser remains on the current side. Close does not close the page. It just triggers a save if
there are modified data.
* `url` - the browser redirects to the URL or T3 page named in `Forward URL / Page`. Independent if the user presses `save` or `close`.
* `url-skip-history` - same as `url`, but the current location won't saved in the browser history.
* `url-sip` - like `url`, but any given parameter will be SIP encoded. Only useful if `url` points to current web instance.
* `url-sip-skip-history` - like `url-sip`, but skips the Browser history.
Only with `Forward` == `url` | `url-skip-history`, the definition of `Forward URL / Page` becomes active.
Forward URL / Page (=forwardPage)
"""""""""""""""""""""""""""""""""
Format: [ ] or [|]
* ``:
* `http://www.example.com/index.html?a=123#bottom`
* `website.html?a=123#bottom`
* `&a=123#bottom, ?id=&a=123#bottom`
* `{{SELECT ...}}`
* `|`
* `` - Valid keywords are as above: `auto|close|no|url|url-skip-history|url-sip|url-sip-skip-history`
Specifying the mode in `forwardPage` overwrites `formMode` (but only if `formMode` is `url...`).
Also regular QFQ statements like {{var}} or {{SELECT ...}} are possible in `forwardPage`. This is useful to dynamically
redirect to different targets, depending on user input or any other dependencies.
If a forwardMode 'url...' is specified and there is no `forwardPage`, QFQ falls down to `auto` mode.
On a form, the user might click 'save' or 'save,close' or 'close' (with modified data this leads to 'save,close').
The CLIENT `submit_reason` shows the user action:
* `{{submit_reason:CE:alnumx}}` = `save` or `save,close`
Example forwardPage
^^^^^^^^^^^^^^^^^^^
* `{{SELECT IF('{{formModeGlobal:S}}'='requiredOff', 'no', 'auto') }}`
* `{{SELECT IF('{{submit_reason:CE:alnumx}}'='save', 'no', 'url'), '|http://example.com' }}`
Type: combined dynamic mode & URL/page
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Syntax: `forwardPage=|`
* `forwardPage={{SELECT IF(a.url='','no','url'), '|', a.url FROM Address AS a }}`
.. _form-parameter:
Form.parameter
^^^^^^^^^^^^^^
* The following parameter are optional.
* Each parameter has to be on a single line.
* If a parameter is defined multiple time, the last one is the final one.
* Comment lines have to start with ``#``.
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| Name | Type | Description |
+=============================+========+==========================================================================================================+
| dbIndex | int | Database credential index, given via :ref:`config-qfq-php` to let the current `Form` |
| | | operate on the database. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| bsColumns | string | Wrap the whole form in '. See :ref:`bs-custom-field-width`. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| maxVisiblePill | int | Show pills upto as button, all further in a drop-down menu. Eg.: maxVisiblePill=3. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| class | string | HTML div with given class, surrounding the whole form. Eg.: class=container-fluid. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| classTitle | string | CSS class inside of the `title` div. Default 'qfq-form-title'. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| classPill | string | HTML div with given class, surrounding the `pill` title line. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| classBody | string | HTML div with given class, surrounding all *FormElement*. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| extraDeleteForm | string | Name of a form which specifies how to delete the primary record and optional slave records. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| data-pattern-error | string | Pattern violation: Text for error message used for all FormElements of current form. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| data-required-error | string | Required violation: Text for error message used for all FormElements of current form. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| data-match-error | string | Match violation: Text for error message used for all FormElements of current form. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| data-error | string | If none specific is defined: Text for error message used for all FormElements of current form. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| buttonOnChangeClass | string | Color for save button after user modified some content or current form. E.g.: 'btn-info alert-info'. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| ldapServer | string | FQDN Ldap Server. E.g.: directory.example.com. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| ldapBaseDn | string | E.g.: `ou=Addressbook,dc=example,dc=com`. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| ldapAttributes | string | List of attributes to fill STORE_LDAP with. E.g.: cn, email. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| ldapSearch | string | E.g.: `(mail={{email::alnumx:l}})` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| ldapTimeLimit | int | Maximum time to wait for an answer of the LDAP Server. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| typeAheadLdap | | Enable LDAP as 'Typeahead' data source. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| typeAheadLdapSearch | string | Regular LDAP search expression. E.g.: `(|(cn=*?*)(mail=*?*))` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| typeAheadLdapValuePrintf | string | Value formatting of LDAP result, per entry. E.g.: `'%s / %s / %s', mail, room number, telephone number` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| typeAheadLdapIdPrintf | string | Key formatting of LDAP result, per entry. E.g.: `'%s', mail` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| typeAheadLdapSearchPerToken | | Split search value in token and OR-combine every search with the individual tokens. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| typeAheadLimit | int | Maximum number of entries. The limit is applied to the server (LDAP or SQL) and the Client. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| typeAheadMinLength | int | Minimum number of characters which have to typed to start the search. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| mode | string | The value `readonly` will activate a global readonly mode of the form - the user can't change any data. |
| | | See :ref:`form-mode-global` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| activateFirstRequiredTab | digit | 0: off, 1: (default) - with formModeGlobal=requiredOffButMark bring pill to front on save. |
| | | See :ref:`form-mode-global` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| enterAsSubmit | digit | 0: off, 1: Pressing *enter* in a form means *save* and *close*. Takes default from :ref:`configuration`. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| submitButtonText | string | Show a save button at the bottom of the form, with . See :ref:`submitButtonText`. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| saveButtonActive | | 0: off, 1: Make the 'save'-button active on *Form* load (instead of waiting for the first user change). |
| | | The save button is still 'gray' (record not dirty), but the user can click 'save'. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| saveButtonText | string | Overwrite default from :ref:`configuration` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| saveButtonTooltip | string | Overwrite default from :ref:`configuration` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| saveButtonClass | string | Overwrite default from :ref:`configuration` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| saveButtonGlyphIcon | string | Overwrite default from :ref:`configuration` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| closeButtonText | string | Overwrite default from :ref:`configuration` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| closeButtonTooltip | string | Overwrite default from :ref:`configuration` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| closeButtonClass | string | Overwrite default from :ref:`configuration` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| closeButtonGlyphIcon | string | Overwrite default from :ref:`configuration` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| deleteButtonText | string | Overwrite default from :ref:`configuration` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| deleteButtonTooltip | string | Overwrite default from :ref:`configuration` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| deleteButtonClass | string | Overwrite default from :ref:`configuration` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| deleteButtonGlyphIcon | string | Overwrite default from :ref:`configuration` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| newButtonText | string | Overwrite default from :ref:`configuration` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| newButtonTooltip | string | Overwrite default from :ref:`configuration` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| newButtonClass | string | Overwrite default from :ref:`configuration` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| newButtonGlyphIcon | string | Overwrite default from :ref:`configuration` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| extraButtonInfoClass | string | Overwrite default from :ref:`configuration` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| extraButtonInfoMinWidth | string | See :ref:`extraButtonInfo` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| fillStoreVar | string | Fill the STORE_VAR with custom values. See :ref:`STORE_VARS`. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| showIdInFormTitle | string | Overwrite default from :ref:`configuration` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| formSubmitLogMode | string | Overwrite default from :ref:`configuration` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| sessionTimeoutSeconds | int | Overwrite default from :ref:`configuration`. See :ref:`sessionTimeoutSeconds`. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| maxFileSize | int | Overwrite default from :ref:`configuration` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| requiredPosition | int | See :ref:`requiredPosition` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| clearMe | 0 / 1 | Overwrite default from :ref:`configuration`. Show a small 'x' in every input or textarea to clear field. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| rememberLastPill | 0 / 1 | Overwrite default from :ref:`configuration`. On form load, bring last used pill to front |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| doNotLogColumn | string | Overwrite default from :ref:`configuration`. Comma separated list of Form-Element names. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| fieldsetClass | string | Overwrite default from :ref:`configuration`. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| btnPreviousNextSql | string | Query that selects records which are then accessible by the previous/next buttons. |
| | | See :ref:`btnPreviousNextSql` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| btnPreviousNextLoop | digit | 0: off, 1: Allow to loop through the records (from last to first and vice versa). |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| btnPreviousNextWrap | string | Wrap the buttons in custom HTML. Default: ''|
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
* Example in field Form.parameter::
maxVisiblePill = 5
class = container-fluid
classBody = qfq-form-right
.. _submitButtonText:
submitButtonText
""""""""""""""""
If specified and non empty, display a regular submit button at the bottom of the page with the given text.
This gives the form a ordinary HTML-form look 'n' feel. With this option, the standard buttons on the top right border
should be hidden to not confuse the user.
* Optional.
* Default: Empty
class
"""""
* Optional.
* Default: `container`
* Any CSS class name(s) can be specified.
* Check `typo3conf/ext/qfq/Resources/Public/Css/qfq-bs.css` for predefined classes.
* Typical use: adjust the floating rules of the form.
* See: http://getbootstrap.com/docs/3.4/css/#overview-container
* Expand the form over the whole area: `container-fluid`
classPill
"""""""""
* Optional.
* Default: `qfq-color-grey-1`
* Any CSS class name(s) can be specified.
* Check `typo3conf/ext/qfq/Resources/Public/Css/qfq-bs.css` for predefined classes.
* Typical use: adjust the background color of the `pill title` area.
* Predefined background colors: `qfq-color-white`, `qfq-color-grey-1` (dark), `qfq-color-grey-2` (light),
`qfq-color-blue-1` (dark), `qfq-color-blue-2`. (light)
* `classPill` is only visible on forms with container elements of type 'Pill'.
classBody
"""""""""
* Optional.
* Default: `qfq-color-grey-2`
* Any CSS class name(s) can be specified.
* Check `typo3conf/ext/qfq/Resources/Public/Css/qfq-bs.css` for predefined classes.
* Typical use:
* adjust the background color of the *FormElement* area.
* make all form labels right align: `qfq-form-right`.
* Predefined background colors: `qfq-color-white`, `qfq-color-grey-1` (dark), `qfq-color-grey-2` (light),
`qfq-color-blue-1` (dark), `qfq-color-blue-2`. (light)
extraDeleteForm
"""""""""""""""
Depending on the database definition, it might be necessary to delete the primary record *and* corresponding slave records.
To not repeat such 'slave record delete definition', an 'extraDeleteForm' can be specified. If the user opens a record
in a form and clicks on the 'delete' button, a defined 'extraDeleteForm'-form will be used to delete primary and slave
records instead of using the current form.
E.g. if there are multiple different forms to work on the same table, all of theses forms might reference to the same
'extraDeleteForm'-form. This simplifies the maintenance.
The 'extraDeleteForm' parameter might be specified for a 'form' and/or for 'subrecords'
See also: :ref:`delete-record`.
.. _btnPreviousNext:
btnPreviousNextSql
""""""""""""""""""
Generates two navigation buttons in the form title that link to the previous/next record.
Records are selected and ordered by a query which uses the columns 'id', 'btnPrevious' (optional), 'btnNext' (optional)
and 'btnCurrent' (optional).
Optional columns can be used to style the buttons using the AS _link notation. 'bntCurrent' generates a third button in
between the other two. Example::
# Only arrows, no text.
btnPreviousNextSql = {{!SELECT adr.id AS id FROM Address AS adr WHERE adr.personId={{personId:R}} }}
# Text
btnPreviousNextSql = {{!SELECT adr.id AS id
, CONCAT('p:{{pageSlug:T}}?form={{form:S}}&r=', adr.id, '|s|b|t:Previous: ', adr.city) AS btnPrevious
, CONCAT('p:{{pageSlug:T}}?form={{form:S}}&r=', adr.id, '|s|b|t:Next: ', adr.city) AS btnNext
FROM Address AS adr
WHERE adr.personId={{personId:R}} }}
* btnPreviousNextLoop:
* 0: no loop.
* 1: Allow to loop through the records (from last to first and vice versa).
* btnPreviousNextWrap: Wrap the buttons in custom HTML. Default: ' '|
.. _form-mode-global:
Form mode global
""""""""""""""""
A form can be operated in modes: *standard* | **readonly** | **requiredOff** | **requiredOffButMark**.
Mode *standard* is given if none of the others are defined.
The `mode` is given via (in this priority):
* Via STORE_USER: {{formModeGlobal:U}}
* Via STORE_SIP: {{formModeGlobal:S}}
* Via Form: `form.parameter.formModeGlobal=...`
Mode
;;;;
* **standard**:
* The form will behave like defined in the form editor.
* Missing required values will a) be indicated and b) block saving the record.
* **readonly**: all `FormElement` of the whole form are temporarily in `readonly` mode.
* Fast way to display the form data, without a possibility for the user to change any data of the form.
* The mode will be be inherited to all subforms.
* **requiredOff**:
* All `FormElement` with `mode=required`, will be handled as `mode=show`.
* The user can save the form without filling all required inputs!
* Required inputs are indicated by a red star - missing values **won't** be complained.
* **requiredOffButMark**:
* All `FormElement` with `mode=required`, will be handled as `mode=show`.
* The user can save the form without filling all required inputs!
* Missing required inputs will be marked:
* On lost focus.
* When the user saves the record.
* After saving the record, by default the first pill with a missing input comes to front.
* This behaviour can be switch on/off with `form.parameter.activateFirstRequiredTab=0`
Extra
;;;;;
Via :ref:`STORE_VARS` the variable `{{allRequiredGiven:V}}` shows, if the form has been filled completely - independent of
the mode. The variable is only accessible during form save.
Usage example
;;;;;;;;;;;;;
*Readonly*
Code: ``SELECT 'p:{{pageSlug}}?form=person&r=1&formModeGlobal=readonly|s|t:View|s|b' AS _link``
* The form is called with SIP parameter ``formModeGlobal=readonly`` or ``form.parameter.mode=readonly``.
* The user can't change any data.
*Readonly system wide*
Code (somewhere): ``SELECT 'requiredOff' AS '_=formModeGlobal'``
Code: ``SELECT 'p:{{pageSlug}}?form=person&r=1|s|t:View|s|b' AS _link``
* The STORE_USER variable is set `formModeGlobal=readonly`.
* All forms will be shown in readonly mode - fast option to give a user access to the website, without the possibility to
change any data.
*Draft Mode 1*
Code: ``SELECT 'p:{{pageSlug}}?form=person&r=1&formModeGlobal=requiredOff|s|t:View|s|b' AS _link``
* A form has one or more FormElement with 'fe.type=required'.
* Opening the form with `formModeGlobal=requiredOff` will allow the user to save the form, even if not all
FE.type=required elements are given. This can be called 'draft' mode.
* Opening the form without `formModeGlobal` (that's the default), forces the user to fill out
all FE.type=required fields. This can be called 'final submit' mode.
*Draft Mode 2*
Code: ``SELECT 'p:{{pageSlug}}?form=person&r=1&formModeGlobal=requiredOff|s|t:View|s|b' AS _link``
* A form has one or more FormElement with 'fe.type=required'.
* Calling the form with `formModeGlobal=requiredOff` will allow the user to save the form, even if not all
FE.type=required elements are given.
* Define an FE-Action 'afterSave', and do some action on `{{allRequiredGiven:V0}}` like::
{{UPDATE SET dataValid={{allRequiredGiven:V0}} WHERE id={{id:R}} }}
* In the application logic, open the next process step if all data is given by evaluating `dataValid`.
FormElements
------------
* Each *form* contains one or more *FormElement*.
* The *FormElements* are divided in three categories:
* :ref:`class-container`
* :ref:`class-native`
* :ref:`class-action`
* Ordering and grouping: Native *FormElements* and Container-Elements (both with feIdContainer=0) will be ordered by 'ord'.
* Inside of a container, all nested elements will be displayed.
* Technical, it's *not* necessary to configure a FormElement for the primary index column `id`.
* Additional options to a *FormElement* will be configured via the *FormElement.parameter* field (analog to *Form.parameter*
for *Forms* ).
* See also: :ref:`comment-space-character`
.. _class-container:
Class: Container
----------------
* Pills are containers for 'fieldset' *and* / *or* 'native' *FormElements*.
* Fieldsets are containers for 'native' *FormElements*.
* TemplateGroups are containers for 'fieldset' *and* / *or* 'native' *FormElements*.
Type: fieldset
^^^^^^^^^^^^^^
* Native *FormElements* can be assigned to a fieldset.
* FormElement settings:
* *name*: technical name, used as HTML identifier.
* *label*: Shown title of the fieldset.
* *mode*:
* `show`: all child elements will be shown.
* `required`: all child elements are also set to 'required'.
* `readonly`: technically it's like HTML/CSS `disabled`.
* `hidden`:
* The fieldset is invisible.
* The `FormElements` within the fieldset still exist, but are not reachable for the user via UI.
* *parameter*:
* *fieldsetClass*: Overwrite default from `Form.parameter.fieldsetClass`
Type: pill (tab)
^^^^^^^^^^^^^^^^
* Pill is synonymous for a tab and looks like a tab.
* If there is at least one pill defined:
* every native *FormElement* needs to be assigned to a pill or to a fieldset.
* every *fieldset* needs to be assigned to a pill.
* Mode:
* `show`: all child elements will be shown.
* `required`: same as 'show'. This mode has no other meaning than 'show'.
* `readonly`: technically it's like HTML/CSS `disabled`.
* The pill title is shown, but not clickable.
* The `FormElements` on the pill still exist, but are not reachable for the user via UI.
* `hidden`:
* The pill is invisible.
* The `FormElements` on the pill still exist, but are not reachable for the user via UI.
* Note: Independent of the *mode*, all child elements are always rendered and processed by the client/server.
* Pills are 'dynamicUpdate' aware. `title` and `mode` are optional recalculated during 'dynamicUpdate'.
* FormElement settings:
* *name*: technical name, used as HTML identifier.
* *label*: Label shown on the corresponding pill button or inside the drop-down menu.
* *mode*:
* *show*, *required*: regular mode. The pill will be shown.
* *readonly*: the pill and it's name is visible, but not clickable.
* *hidden*: the pill is not shown at all.
* *modeSql*:
* *type*: *pill*
* *feIdContainer*: `0` - Pill's can't be nested.
* *tooltip*: Optional tooltip on hover. Especially helpful if the pill is set to *readonly*.
* *parameter*:
* *maxVisiblePill*: `` - Number of Pill-Buttons shown. Undefined means unlimited. Excess Pill buttons will be
displayed as a drop-down menu.
Type: templateGroup
^^^^^^^^^^^^^^^^^^^
*TemplateGroups* will be used to create a series of grouped (by the given *templateGroup*) *FormElements*.
*FormElements* can be assigned to a *templateGroup*. These *templateGroup* will be rendered upto *n*-times. On 'form load'
only a single (=first) copy of the *templateGroup* will be shown. Below the last copy of the *templateGroup* an 'add'-button is
shown. If the user click on it, an additional copy of the *templateGroup* is displayed. This can be repeated up to
*templateGroup.maxLength* times. Also, the user can 'remove' previously created copies by clicking on a remove button near
beside every *templateGroup*. The first copy of a templateGroup can't be removed.
* FormElement settings:
* *label*: Shown in the FormElement-editor *container* field.
* *maxLength*: Maximum number of copies of the current *templateGroup*. Default: 5.
* *bsLabelColumn*, *bsInputColumn*, *bsNoteColumn*: column widths for row with the 'Add' button.
* *parameter*:
* *tgAddClass*: Class of the 'add' button. Default: `btn btn-default`.
* *tgAddText*: Text shown on the button. Default: `Add`.
* *tgRemoveClass*: Class of the 'remove' button. Default: `btn btn-default`.
* *tgRemoveText*: Text shown on the button. Default: `Remove`.
* *tgClass*: Class wrapped around every copy of the *templateGroup*.
E.g. the class `qfq-child-margin-top` adds a margin between two copies of the *templateGroup*. Default: empty
Multiple *templateGroups* per form are allowed.
The name of the native FormElements, inside the templateGroup, which represents the effective table columns, uses the placeholder
`%d`. E.g. the columns `grade1`, `grade2`, `grade3` needs a *FormElement.name* = `grade%d`. The counting will always start with 1.
The placeholder `%d` can also be used in the *FormElement.label*
Example of styling the Add/ Delete Button: :ref:`example_class_template_group`
Column: primary record
""""""""""""""""""""""
If the columns `%d` are real columns on the primary table, saving and delete (=empty string) are done automatically.
E.g. if there are up to five elements `grade1, ..., grade5` and the user inputs only the first three, the remaining will be set
to an empty string.
Column: non primary record
""""""""""""""""""""""""""
Additional logic is required to load, update, insert and/or delete slave records.
Load
;;;;
On each native *FormElement* of the *templateGroup* define an SQL query in the *FormElement.value* field. The query has to
select **all** values of all possible existing copies of the *FormElement* - therefore the exclamation mark is necessary.
Also define the order. E.g. *FormElement.value*::
{{!SELECT street FROM Address WHERE personId={{id}} ORDER BY id}}
Insert / Update / Delete
;;;;;;;;;;;;;;;;;;;;;;;;
Add an *action* record, type='afterSave', and assign the record to the given *templateGroup*.
In the parameter field define: ::
slaveId = {{SELECT id FROM Address WHERE personId={{id}} ORDER BY id LIMIT %D,1}}
sqlHonorFormElements = city%d, street%d
sqlUpdate = {{UPDATE Address SET city='{{city%d:FE:alnumx:s}}', street='{{street%d:FE:alnumx:s}}' WHERE id={{slaveId}} LIMIT 1}}
sqlInsert = {{INSERT INTO Address (`personId`, `city`, `street`) VALUES ({{id}}, '{{city%d:FE:alnumx:s}}' , '{{street%d:FE:alnumx:s}}') }}
sqlDelete = {{DELETE FROM Address WHERE id={{slaveId}} LIMIT 1}}
The `slaveId` needs attention: the placeholder `%d` starts always at 1. The `LIMIT` directive starts at 0 - therefore
use `%D` instead of `%d`, cause `%D` is always one below `%d` - but can **only** be used on the action element.
.. _class-native:
Class: Native
-------------
Fields:
+---------------------+-----------------------------+-----------------------------------------------------------------------------------------------------+
| Name | Type | Description |
+=====================+=============================+=====================================================================================================+
|Container | int | 0 or *FormElement*.id of container element (pill, fieldSet, templateGroup) part the current *Form* |
+---------------------+-----------------------------+-----------------------------------------------------------------------------------------------------+
|Enabled | enum('yes'|'no') | Process the current FormElement |
+---------------------+-----------------------------+-----------------------------------------------------------------------------------------------------+
|Dynamic Update | enum('yes'|'no') | In the browser, *FormElements* with "dynamicUpdate='yes'" will be updated depending on user |
| | | input. :ref:`dynamic-update` |
+---------------------+-----------------------------+-----------------------------------------------------------------------------------------------------+
|Encryption | enum('yes'|'no') | Encryption for the user input can be activated. :ref:`encryption` |
+---------------------+-----------------------------+-----------------------------------------------------------------------------------------------------+
|Name | string | |
+---------------------+-----------------------------+-----------------------------------------------------------------------------------------------------+
|Label | string | Label of *FormElement*. Depending on layout model, left or on top of the *FormElement* |
| | | Additional label description can be added by wrapping in HTML tag '' |
+---------------------+-----------------------------+-----------------------------------------------------------------------------------------------------+
|Mode | enum('show', 'readonly', | | *Show*: regular user input field. This is the default. |
| | 'required', | | *Required*: User has to specify a value. Typically, an represents 'no value'. |
| | 'hidden' ) | | *Readonly*: User can't change. Data is not saved, except for FormElement with 'processReadOnly' |
| | | | *Hidden*: *FormElement* is not visible. |
+---------------------+-----------------------------+-----------------------------------------------------------------------------------------------------+
|Mode sql | `SELECT` statement with | A value given here overwrites the setting from `mode`. Most useful with :ref:`dynamic-update`. |
| | a value like in `mode` | E.g.: {{SELECT IF( '{{otherFunding:FR:alnumx}}'='yes' ,'show', 'hidden' }} |
+---------------------+-----------------------------+-----------------------------------------------------------------------------------------------------+
|Class | enum('native', 'action', | Details below. |
| | 'container') | |
+---------------------+-----------------------------+-----------------------------------------------------------------------------------------------------+
|Type | enum('checkbox', 'date', 'time', 'datetime', 'dateJQW', 'datetimeJQW', 'extra', 'gridJQW', 'text', 'editor', 'annotate', |
| | 'imageCut', 'note', 'password', 'radio', 'select', 'subrecord', 'upload', 'fieldset', 'pill', 'beforeLoad', 'beforeSave', |
| | 'beforeInsert', 'beforeUpdate', 'beforeDelete', 'afterLoad', 'afterSave', 'afterInsert', 'afterUpdate', 'afterDelete', |
| | 'sendMail') |
+---------------------+-----------------------------+-----------------------------------------------------------------------------------------------------+
|Encode | 'none', 'specialchar' | With 'specialchar' (default) the chars <>"'& will be encoded to their html entity. _`field-encode` |
+---------------------+-----------------------------+-----------------------------------------------------------------------------------------------------+
|Check Type | enum('auto', 'alnumx', | See: :ref:`sanitize-class` |
| | 'digit', 'numerical', | |
| | 'email', 'pattern', | |
| | 'allbut', 'all') | |
+---------------------+-----------------------------+-----------------------------------------------------------------------------------------------------+
|Check Pattern | 'regexp' | _`field-checktype`: If $checkType=='pattern': pattern to match |
+---------------------+-----------------------------+-----------------------------------------------------------------------------------------------------+
|Order | string | Display order of *FormElements* ('order' is a reserved keyword) _`field-ord` |
+---------------------+-----------------------------+-----------------------------------------------------------------------------------------------------+
|labelAlign | left | Label align (default/left/center/right)/ Default: 'default' (defined by Form). |
+---------------------+-----------------------------+-----------------------------------------------------------------------------------------------------+
|Size | string | Depends on the FormElement type. E.g. visible length (and height) of input |
| | | element :ref:`input-text`. Might be omitted, depending on the chosen form layout. |
| | | Format: [,<(min) height>[,) data
of the specified record (`SELECT FROM WHERE id={{r:S}}`) on form load.
In case a new record should be created (r=0), it's sometimes wished to customize a default value::
{{:R:::}}
Explanation: STORE_RECORD (=R) is filled with the values of the current record. If there is no record (r=0), than the default
is taken.
For non primary records, this is the place to load an existing value. E.g. we're on a 'Person' detail form and would like
to edit, on the same form, a corresponding person email address (which is in a separate table): ::
{{SELECT a.email FROM Address AS a WHERE a.pId={{id:R0}} ORDER BY a.id LIMIT 1}}
Report syntax can also be used, see :ref:`report-notation`.
.. _`report-notation`:
FormElement: 'Report' notation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The FE fields 'value' and 'note' understand the :ref:`Report` syntax. Nested SQL queries as well as links with SIP encoding
are possible. To distinguish between 'Form' and 'Report' syntax, the first line has to be `#!report`::
#!report
10.sql = SELECT ...
20 {
sql = SELECT ...
5.sql = SELECT ...
}
.. _fe-parameter-attributes:
FormElement.parameter
^^^^^^^^^^^^^^^^^^^^^
* The following parameter are optional.
* Each parameter has to be on a single line.
* If a parameter is defined multiple time, the last one is the final one.
* Comment lines have to start with ``#``.
* See also documentation at specific *FormElement*.
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| Name | Note |
+=================================+==========================================================================================================+
| acceptZeroAsRequired | 0|1 - Accept a '0' as a valid input. Default '0' (=0 is not a valid input) |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| autofocus | See :ref:`input-option-autofocus` |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| capture, | See :ref:`input-upload` |
| accept, | |
| maxFileSize, | |
| fileDestination, | |
| fileTrash, | |
| fileTrashText, | |
| fileReplace, | |
| autoOrient, | |
| autoOrientCmd, | |
| autoOrientMimeType, | |
| chmodFile, chmodDir, | |
| slaveId, | |
| sqlBefore, | |
| sqlInsert, | |
| sqlUpdate, | |
| sqlDelete, | |
| sqlAfter, | |
| importToTable, | |
| importToColumns, | |
| importRegion, | |
| importMode, | |
| importType, | |
| importNamedSheetsOnly, | |
| importSetReadDataOnly, | |
| importListSheetNames, | |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| checkBoxMode | See :ref:`input-checkbox`, :ref:`input-radio`, :ref:`input-select` |
| checked | |
| unchecked | |
| label2 | |
| itemList | |
| emptyHide | |
| emptyItemAtStart | |
| emptyItemAtEnd | |
| buttonClass | |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| dateFormat | yyyy-mm-dd / dd.mm.yyyy |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| data-pattern-error | Pattern violation: Text for error message |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| data-required-error | Required violation: Text for error message |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| data-match-error | Match violation: Text for error message |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| data-error | Violation of 'check-type': Text for error message |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| decimalFormat | [precision,scale] Limits and formats input to a decimal number with the specified precision and scale. |
| | If no precision and scale are specified, the decimal format is pulled from the table definition. |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| htmlAfter | HTML Code wrapped after the complete *FormElement* |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| htmlBefore | HTML Code wrapped before the complete *FormElement* |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| extraButtonLock | [0|1] Show a 'lock' on the right side of the input element. See :ref:`extraButtonLock` |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| extraButtonPassword | [0|1] Show an 'eye' on the right side of the input element. See :ref:`extraButtonPassword` |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| extraButtonInfo | Text. Show an 'i' on the right side of the input element. See :ref:`extraButtonInfo` |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| extraButtonInfoClass | By default empty. Specify any class to be assigned to wrap extraButtonInfo |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| extraButtonInfoMinWidth | See :ref:`extraButtonInfo` |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| editor-plugins, | See :ref:`input-editor` |
| editor-toolbar, | |
| editor-statusbar, | |
| editor-forced_root_block, | |
| editor-extended_valid_elements, | |
| editor-content_css, | |
| editor-relative_urls, | |
| editorType, | |
| codemirror-mode, | |
| codemirror-lineNumbers, | |
| codemirror-lineWrapping, | |
| codemirror-tabSize, | |
| codemirror-styleActiveLine, | |
| codemirror-matchBrackets, | |
| codemirror-autoCloseBrackets, | |
| codemirror-keywords-qfq-base | |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| fileButtonText | Overwrite default 'Choose File' |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| fillStoreVar | Fill the STORE_VAR with custom values. See :ref:`STORE_VARS`. |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| form, | See :ref:`subrecord-option` |
| page, | |
| extraDeleteForm, | |
| detail, new, | |
| subrecordTableClass, | |
| subrecordTableAttribute, | |
| subrecordColumnTitleEdit, | |
| subrecordColumnTitleDelete, | |
| subrecordAppendSql, | |
| subrecordAppendClass, | |
| subrecordAppendForm, | |
| subrecordAppendExtraDeleteForm, | |
| subrecordAppendEmptyText, | |
| orderInterval, | |
| dndTable, | |
| orderColumn | |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| min s/d/n | Minimum and/or maximum allowed values for input field. Can be used for numbers, dates, or strings. |
+---------------------------------+ |
| max s/d/n | *Always use the international format 'yyyy-mm-dd[ hh:mm[:ss]]* |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| processReadOnly | [0|1] By default FE's with type='readonly' are not processed during 'save'. |
| | This option forces to process them during 'save' as well. See :ref:`processReadOnly`. |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| retype, | See :ref:`retype` |
| retypeLabel, | |
| retypeNote | |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| characterCountWrap, | See :ref:`input-text` |
| hideZero | |
| inputType, step, | |
| textareaResize, htmlAllow | |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| emptyMeansNull | Applies to all native FormElement types (input, checkbox, radio, select, ...). See :ref:`input-text` |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| showSeconds | 0|1 - Shows the seconds on form load. Default: 0 |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| showZero | 0|1 - Empty timestamp: '0'(default) - nothing shown, '1' - the string '0000-00-00 00:00:00' is displayed |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| timeIsOptional | 0|1 - Used for datetime input. 0 (default): Time is required - 1: Entering a time is optional |
| | (defaults to 00:00:00 if none entered). |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| typeAheadLimit, | See :ref:`input-typeahead` |
| typeAheadInitialSuggestion, | |
| typeAheadMinLength, | |
| typeAheadSql, | |
| typeAheadSqlPrefetch, | |
| typeAheadPedantic | |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| typeAheadTag, | See :ref:`type_ahead_tag` |
| typeAheadGlueInsert, | |
| typeAheadGlueDelete, | |
| typeAheadTagInsert, | |
| typeAheadTagDelimiter | |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| wrapRow | If specified, skip default wrapping (``). Instead the given string is used. |
+---------------------------------+ |
| wrapLabel | |
+---------------------------------+ |
| wrapInput | |
+---------------------------------+ |
| wrapNote | |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| trim | By default, whitespace is trimmed. To disable, use 'trim=none'. You can also specify custom trim |
| | characters: 'trim=\\ ' only trims spaces. |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| sqlValidate, | See :ref:`sqlValidate` |
| expectRecords, | |
| alert, | |
| qfqLog, | |
| requiredList | |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| dataReference | Optional. See :ref:`applicationTest` |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| requiredPosition | See :ref:`requiredPosition`. |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| indicateRequired | By default, indicate 'required' by an asterisk. indicateRequired=0 will hide the asterisk. Default: 1 |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| minWidth | See :ref:`checkboxRadioMinWidth`. |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| clearMe | 0 (off)|1(on) - Overwrite default from Form.parameter.clearMe or :ref:`configuration`. Show a small |
| | 'x' in input or textarea fields to clear the input. |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
| defaultValue | Set custom default value. If not set, db column default value will be taken. |
+---------------------------------+----------------------------------------------------------------------------------------------------------+
* `s/d/n`: string or date or number.
slaveId, sqlBefore, sqlAfter, ...
"""""""""""""""""""""""""""""""""
See :ref:`slave-id`
Native *FormElements*
"""""""""""""""""""""
* Like 'input', 'checkbox', ...
.. _`input-option-autofocus`:
autofocus
;;;;;;;;;
The first *FormElement* with this attribute will get the focus after form load. If there is no such attribute
given to any *FormElement*, the attribute will be automatically assigned to the first editable *FormElement*.
To disable 'autofocus' on a form, set 'autofocus=0' on the first editable *FormElement*.
Note: If there are multiple pills defined on a form, only the first pill will be set with 'autofocus'.
.. _`extraButtonLock`:
extraButtonLock
;;;;;;;;;;;;;;;
* The user has to click on the lock, before it's possible to change the value. This will protect data against unwanted modification.
* After Form load, the value is shown, but not editable.
* Shows a 'lock' on the right side of an input element of type `text`, `date`, `time` or `datetime`.
* This option is not available for FormElements with `mode=readonly`.
* There is no value needed for this parameter.
.. _`extraButtonPassword`:
extraButtonPassword
;;;;;;;;;;;;;;;;;;;
* The user has to click on the eye (un-hide) to see the value.
* After Form load, the data is hidden by asterisk.
* Shows an 'eye' on the right side of an input element of type `text`, `date`, `time` or `datetime`.
* There is no value needed for this parameter.
.. _`extraButtonInfo`:
extraButtonInfo
;;;;;;;;;;;;;;;
* After Form load, the `info` button/icon is shown but the information message is hidden.
* The user has to click on the `info` button/icon to see an additional message.
* The value of this parameter is the text shown to the user.
* Shows an `info` button/icon, depending of `extraButtonInfoPosition` in :ref:`configuration`
* `auto`, depending on `FormElement` type:
* on the right side of an input element for type `text`, `date`, `time` or `datetime`,
* below the FormElement for all other types.
* `below`: below the FormElement for all types.
* `extraButtonInfoMinWidth`: default is 250 and defines a minimal width.
* For `FormElement` with mode `below`, a `span` element with the given class in `extraButtonInfoClass` (FE, F, :ref:`configuration`)
will be applied. E.g. this might be `pull-right` to align the `info` button/icon on the right side below the input element.
.. _`processReadOnly`:
processReadOnly
;;;;;;;;;;;;;;;
By default FormElements with `mode='readonly'` are not processed. In most use cases, this is the expected behaviour: An
element which can't be modified by the user, should not be written during a save. Exceptions might be given, like: FE is
enabled by dynamic update, modified by the user, deactivated again and than the record is saved.
.. _`checkboxRadioMinWidth`:
Checkbox / Radio: minWidth
^^^^^^^^^^^^^^^^^^^^^^^^^^
Checkbox and Radio Elements, shown in plain horizontal mode, receives a minWidth to align them. The default is 80px and
might be defined per Form or per FormElement.
.. _`requiredPosition`:
Required Position
^^^^^^^^^^^^^^^^^
By default, input elements with `Mode=required` will be displayed with a 'red asterisk' right beside the label. The position
of the 'red asterisk' can be chosen via the `parameter` field::
requiredPosition = label-left|label-right|input-left|input-right|note-left|note-right
The default is 'label-right'.
The definition can be set per Form (=affects all FormElements) or per FormElement.
.. _`input-checkbox`:
Type: checkbox
^^^^^^^^^^^^^^
Checkboxes can be rendered in mode:
* *single*:
* One column in a table corresponds to one checkbox.
* The value for statuses *checked* and *unchecked* are free to choose.
* This mode is selected, if a) *checkBoxMode* = single, or b) *checkBoxMode* is missing **and** the number of fields of the column definition is <3.
* *FormElement.parameter*:
* *checkBoxMode* = single (optional)
* *checked* = (optional, the value which represents 'checked')
* If *checked* is empty or missing: If *type* = 'enum' or 'set', get first item of the definition. If *type* = string, get default.
* *unchecked* = (optional, the value which represents 'unchecked')
* If *unchecked* is empty or missing: If *type* = 'enum' or 'set', get second item of checked. If *type* = 'string', get ''.
* *label2* = (Text right beside checkbox) (optional)
* *multi*:
* One column in a table represents multiple checkboxes. This is typically useful for the column type *set*.
* The value for status *checked* are free to choose, the value for status *unchecked* is always the empty string.
* Each field key (or the corresponding value from the key/value pair) will be rendered right beside the checkbox.
* *FormElement.parameter*
* *checkBoxMode* = multi
* *itemList* - E.g.:
* ``itemList=red,blue,orange``
* ``itemList=1:red,2:blue,3:orange``
* If ':' or ',' are part of key or value, it needs to escaped by \\ .
E.g.: `itemList=1:red\\: (with colon),2:blue\\, (with comma),3:orange``
* *FormElement.sql1* = ``{{!SELECT id, value FROM SomeTable}}``
* *FormElement.maxlength* - vertical or horizontal alignment:
* Value: '', 0, 1 - The check boxes will be aligned vertical.
* Value: >1 - The check boxes will be aligned horizontal, with a linebreak every 'value' elements.
* *FormElement.parameter*:
* *emptyHide*: Existence of this item hides an entry with an empty string. This is useful for e.g. Enums, which have an empty
entry, but the empty value should not be selectable.
* *emptyItemAtStart*: Existence of this item inserts an empty entry at the beginning of the select list.
* *emptyItemAtEnd*: Existence of this item inserts an empty entry at the end of the select list.
* *buttonClass*: Instead of the plain HTML checkbox fields, Bootstrap
`buttons `_. are rendered as `checkbox` elements. Use
one of the following `classes `_:
* `btn-default` (default, grey),
* `btn-primary` (blue),
* `btn-success` (green),
* `btn-info` (light blue),
* `btn-warning` (orange),
* `btn-danger` (red).
With a given *buttonClass*, all buttons (=radios) are rendered horizontal. A value in *FormElement.maxlength* has no effect.
* *No preselection*:
* If a form is in 'new' mode and if there is a default value configured on a table column, such a value is shown by default.
There might be situations, where the user should be forced to select a value (e.g. specifying the gender). An unwanted
default value can be suppressed by specifying an explicit definition on the FormElement field `value`::
{{:RZ}}
For existing records the shown value is as expected the value of the record. For new records, it's the value `0`,
which is typically not one of the ENUM / SET values and therefore nothing is selected.
Type: date
^^^^^^^^^^
* Range datetime: '1000-01-01' to '9999-12-31' or '0000-00-00'. (http://dev.mysql.com/doc/refman/5.5/en/datetime.html)
* Optional:
* *FormElement.parameter.dateFormat*: YYYY-MM-DD | DD.MM.YYYY
Actually datetimepicker is used as default. For more options see :ref:`Installation_datetimepicker`
Type: datetime
^^^^^^^^^^^^^^
* Range datetime: '1000-01-01 00:00:00' to '9999-12-31 23:59:59' or '0000-00-00 00:00:00'. (http://dev.mysql.com/doc/refman/5.5/en/datetime.html)
* Optional:
* *FormElement.parameter*:
* *dateFormat* = YYYY-MM-DD | DD.MM.YYYY
* *showSeconds* = 0|1 - shows the seconds. Independent if the user specifies seconds, they are displayed '1' or not '0'.
* *showZero* = 0|1 - For an empty timestamp, With '0' nothing is displayed. With '1' the string '0000-00-00 00:00:00' is displayed.
Actually datetimepicker is used as default. For more options see :ref:`Installation_datetimepicker`
Type: extra
^^^^^^^^^^^
* The element behaves like, and can be used as, a HTML hidden input element - with the difference & advantage, that the
element never leaves the server and therefore can't be manipulated by a user.
* The following names are reserved and can't be used to name 'extra' FormElements: 'id', 'type', 'L'.
* The element is not transferred to the the browser.
* The element can be used to define / pre calculate values for a column, which do not already exist as a native *FormElement*.
* The element is build / computed on form load and saved alongside with the SIP parameter of the current form.
* The element is not recalculated during save - it's stored during 'Form Load' inside the current form SIP handle.
* Access the value without specifying any store (default store priority is sufficient).
.. _`input-text`:
Type: text
^^^^^^^^^^
General input for any text.
.. _`field-size`:
* By default, the maximum length of input data is automatically restricted by the underlying database column.
* HTML decides between one line input (=Input text) and multiline input (=Textarea).
* *FormElement.size* = [[,[,]]]
* The parameter is optional and controls the behaviour of the input / textarea element.
* The `` is counted in 'characters'.
* But: the *visible* width of an input element is defined by the Bootstrap column width (and *not* the width given
here). Finally: the value here is meaningless. Nevertheless it has to be given for future compatibility.
* ``:
* Counted as 'lines'.
* If not set the height is treated as 1.
* A `` of 1 forces an one line input. Exception: `` > 0 enables `auto-grow`.
* ``:
* Controls the `auto-grow`-Mode.
* Counted in 'pixel'.
* If not set it becomes the default of 350 pixels.
* If > 0, the `auto-grow` mode is activated and the height of the textarea will be dynamically updated
up to ``.
* If = 0, the `auto-grow` mode is disabled.
* *FormElement.parameter*:
.. _`retype`:
* *retype* = 1 (optional): Current input element will be rendered twice. The form can only submitted if both elements are equal.
* *retypeLabel* = (optional): The label of the second element.
* *retypeNote* = (optional): The note of the second element.
* *characterCountWrap* = ``Count: | `` (optional).
Displays a character counter below the input/textarea element.
* Also check the :ref:`fe-parameter-attributes` *data-...-error* to customize error messages shown by the validator.
* *hideZero* = 0|1 (optional): `with hideZero=1` a '0' in the value will be replaced by an empty string.
* *emptyMeansNull* = [0|1] (optional): with `emptyMeansNull` or `emptyMeansNull=1` a NULL value will be written if
the value is an empty string
* *inputType* = number (optional). Typically the HTML tag 'type' will be 'text', 'textarea' or 'number' (detected
automatically). If necessary, the HTML tag 'type' might be forced to a specific given value.
* *step* = Step size of the up/down buttons which increase/decrease the number of in the input field. Optional.
Default 1. Only useful with `inputType=number` (defined explicit via `inputType` or detected automatically).
* *textareaResize* = 0|1 (optional). Be default = 1 (=on). A textarea element is resizable by the user.
.. _`htmlAllow`:
* *htmlAllow* = p,br,img,table,u,ol,b,h2,h3,h5,sup (optional). By default every html tag is allowed. Allow only specific
html tags. This option is only useful in case `encode` is not `specialchar` (cause otherwise there are no HTML tags).
If any of the following main tags (before colon) are given, the associated tags will be added automatically:
* table: td, tr, th, tbody, thead
* ol,ul: li
* b: strong
* u,ins,del,s: span
List of most used html tags: a,b,br,div,em,h1,h2,h3,h4,h5,h6,hr,i,img,table,ol,ul,p,pre,q,section,small,span,strong,sub,sup,title,u
.. _`input-typeahead`:
Type Ahead
""""""""""
Activating `typeahead` functionality offers an instant lookup of data and displaying them to the user, while the user is
typing, a drop-down box offers the results. As datasource the regular SQL connection or a LDAP query can be used.
With every keystroke (starting from the *typeAheadMinLength* characters), the already typed value will be transmitted to
the server, the lookup will be performed and the result, upto *typeAheadLimit* entries, are displayed as a drop-down box.
* *FormElement.parameter*:
* *typeAheadLimit* = . Max numbers of result records to be shown. Default is 20.
* *typeAheadMinLength* = . Minimum length to type before the first lookup starts. Default is 2.
Depending of the `typeahead` setup, the given FormElement will contain the displayed `value` or `id` (if an id/value dict is
configured).
Configuration via Form / FormElement
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
All of the `typeAhead*` (except `typeAheadLdap`, `typeAheadInitialSuggestion`) and `ldap*` parameter can be specified either in
*Form.parameter* or in *FormElement.parameter*.
SQL
;;;
* *FormElement.parameter*:
* *typeAheadSql* = ``SELECT ... AS 'id', ... AS 'value' FROM ... WHERE name LIKE ? OR firstName LIKE ? LIMIT 100``
* If there is only one column in the SELECT statement, that one will be used and there is no dict (key/value pair).
* If there is no column `id` or no column `value`, then the first column becomes `id` and the second column becomes `value`.
* The query will be fired as a 'prepared statement'.
* The value, typed by the user, will be replaced on all places where a `?` appears.
* All `?` will be automatically surrounded by '%'. Therefore wildcard search is implemented: `... LIKE '%>%' ...`
* *typeAheadSqlPrefetch* = ``SELECT firstName, ' ', lastName FROM Person WHERE id = ?``
* If the query returns several results, only the first one is returned and displayed.
* If the query selects multiple columns, the columns are concatenated.
* *typeAheadInitialSuggestion* = ``{{!SELECT fr.id AS id, fr.name AS value FROM Fruit AS fr}}``
* Shows suggestions when the input element gets the focus, before the user starts to type anything.
* If given, *typeAheadMinLength* will be set to 0.
* Limit the number of rows via SQL ``... LIMIT ...`` clause.
LDAP
;;;;
See :ref:`LDAP_Typeahead`
.. _`type_ahead_tag`:
Type Ahead Tag
""""""""""""""
Extend a TypeAhead input element to take more than one token (=tag) in the same input element.
This mode supports only *typeAheadSql* (no LDAP).
Usage: A user might choose one or more tags from a typeahead list (to minimize typos and to reuse already given tags).
The user starts typing and for each keypress *typeAheadSql* is searched for all matches. The user selects an element
by clicking on it or by using one of the *typeAheadTagDelimiter* key presses (by default tab or comma). If a tag is
selected, it will be visual separated from the input cursor. Already selected tags can not be edited but removed
(clicking on the x). Further tags can be added.
*typeAheadTag* support two different modes: a) *Tag* , b) *Glue*.
.. _`ta_mode_tag`:
Mode: Tag
;;;;;;;;;
Tags will be loaded and saved as a comma separated list. Maximum length of saved tags is limit by
the size of the column (incl. separator).
Additional arguments needed for *typeAheadTag*:
* *FormElement.parameter*:
* *typeAheadTag* = [0|1] - Default 0 (=off), existence or =1 switches the mode *typeAheadTag* on.
* *typeAheadTagDelimiter* = List of ASCII codes to separate tags during input. Default '9,44' (tab and comma).
.. _`ta_mode_glue`:
Mode: Glue
;;;;;;;;;;
For each selected tag a glue record, pointing to the tag, is created.
The *Glue* mode will be activated by setting *FormElement.parameter.typeAheadGlueInsert* with a corresponding SQL statement.
Glue records will be created or deleted, as the user select or deselect tags. Processing of those Glue records will be done
after the primary form record has been written and before any after*-action FormElements will be processed.
*FormElement.name* should **not** point to a column in the form primary table. Instead a free name should be used for the *typeAhead*
FormElement.
The maximum number of tags is not limited - but take care to size the FormElement big enough (*FormElement.maxLength*) to
show all tags.
On *Form load* (to show already assigned tags) a comma separated list has to be given in *FormElement.value*, based on
the previously saved Glue records. The string format is identically to the one used in mode *Tag*.
Extra parameter for mode = *Tag* :
* *FormElement.parameter*:
* *typeAheadTagInsert* = {{INSERT INTO Tag (tagName..) VALUES ({{tagValue:V}}..)}} - Only needed with *typeAheadPedantic=0*.
* *typeAheadGlueInsert* = {{INSERT INTO glueTag (...) VALUES (...)}}
* *typeAheadGlueDelete* = {{DELETE FROM glueTag WHERE ...}}
**Example**:
Table *Person* with some records.
Table *Fruit* with a list of fruits.
Table *FruitPerson* with glue records.
Usage: assign favourite fruits to a person. The fruits are the tags, the glue records will assign the fruits to a person.
The form will be open with a person record and has only one FormElement.
* Form.name=personFavouriteFruits
* Form.title=Person Favourite Fruits
* Form.primaryTable = Person
* FormElement[1].name = myFavoriteFruits
* FormElement[1].type = Text
* FormElement[1].value = {{SELECT GROUP_CONCAT( CONCAT(f.id, ':', f.name)) FROM FruitPerson AS fp, Fruit AS f WHERE fp.pId={{id:R}} AND fp.fruitId=f.id ORDER BY f.name}}
* FormElement[1].parameter:
* typeAheadTag = 1
* typeAheadSql = SELECT f.id AS 'id', f.name AS 'value' FROM Fruit AS f WHERE f.name LIKE ?
* typeAheadMinLength = 1
* typeAheadGlueInsert = {{INSERT INTO FruitPerson (pId, fruitId) VALUES ({{id:R}}, {{tagId:V}} ) }}
* typeAheadGlueDelete = {{DELETE FROM FruitPerson WHERE pId={{id:R}} AND fruitId={{tagId:V}} }}
Explanation:
* On form load, without any assigned tags (=fruits), *FormElement.value* will be empty.
* The User will assign three fruits: Apple, Banana, Lemon.
* On form save, QFQ does:
* compares the old tag assigment (empty) with the new tag assigment (3 elements).
* for each new assigned tag:
* the *tagId* and *tagValue* will be stored in STORE_VAR (that's the one selected by the user and defined
via *typeAheadSql*)
* *typeAheadGlueInsert* will be fired (with the replaced variable *{{tagId:V}}*).
* The user loads the person favourite fruit form again (same user).
* *FormElement.value* will now be: ``1:Apple,3:Banana,10:Lemon``.
* The user removes 'Banana' and adds 'Orange'.
* On form save, QFQ does:
* compares the old tag assigment (3 elements) with the new tag assigment (also 3 elements, but different).
* for each new assigned tag:
* the *tagId* and *tagValue* will be stored in STORE_VAR.
* *typeAheadGlueInsert* will be fired (with the replaced variable *{{tagId:V}}*).
* for each removed assigned tag:
* the *tagId* and *tagValue* will be stored in STORE_VAR.
* *typeAheadGlueDelete* will be fired (with the replaced variable *{{tagId:V}}*).
.. _`input-editor`:
Type: editor
^^^^^^^^^^^^
* TinyMCE (https://www.tinymce.com, community edition) is used as the QFQ Rich Text Editor.
* The content will be saved as HTML code in the database.
.. important::
*FormElement.encode*: To save HTML code, incl. HTML tags (bold, table, lists, ...), the **htmlspecialchar**
encoding can't be used, cause the HTML tags loose their meaning. Therefore **single tick** or **none** is necessary.
* *FormElement.checktype*
* *all*: The only useful setting for Editor. HTML tags might contain ``% ' " < >`` and so on. This is **dangerous**
due of potential inserted malicious code! But there is no other option, cause the HTML tags are required.
* All configuration and plugins will be configured via the 'parameter' field. Just prepend the word 'editor-' in front
of each TinyMCE keyword. Check possible options under:
* https://www.tinymce.com/docs/configure/,
* https://www.tinymce.com/docs/plugins/,
* https://www.tinymce.com/docs/advanced/editor-control-identifiers/#toolbarcontrols
* Bars:
* Top: *menubar* - by default hidden.
* Top: *toolbar* - by default visible.
* Bottom: *statusbar* - by default hidden, exception: *min_height* and *max_height* are given via size parameter.
* The default setting in *FormElement.parameter* is::
editor-plugins=code link lists searchreplace table textcolor textpattern visualchars
editor-toolbar=code searchreplace undo redo | styleselect link table | bullist numlist outdent indent | forecolor backcolor bold italic editor-menubar=false
editor-statusbar=false
* To activate drag and drop option for images in TinyMCE add 'image,paste' to editor-plugins. Example: ::
editor-plugins=code link lists searchreplace table textcolor textpattern visualchars image,paste
* To deactivate the surrouding `` tag, configure in *FormElement.parameter*::
editor-forced_root_block = false
This might have impacts on the editor. See https://www.tinymce.com/docs/configure/content-filtering/#forced_root_block
* Set 'extended_valid_elements' to enable HTML tags and their attributes. Example: ::
editor-extended_valid_elements = span[class|style]
* Set 'editor-relative_urls' to allow relative paths. Example: ::
editor-relative_urls = true
* Set 'editor-content_css' to use a custom CSS to style elements inside the editor. Example: ::
editor-content_css = fileadmin/custom.css
* Set own base path for image upload. Default is *fileadmin/imageUploadDir* Example: ::
fileUploadPath = fileadmin/.../...
* *FormElement.size* = : in pixels, including top and bottom bars. E.g.: 300
* Set 'editorType' to use highlighted syntax inside the editor like reports. Available: codemirror. Example: ::
editorType = codemirror
* For *editorType = codemirror* additional customization is possible by prepending *codemirror-* to the following keywords (list not exhaustive, see codemirror 5 documentation for details): ::
codemirror-mode = qfq (only mode that is packaged with qfq, other modes available, see codemirror5 docs)
codemirror-lineNumbers = true
codemirror-lineWrapping = true
codemirror-tabSize = 2
codemirror-styleActiveLine = false
codemirror-matchBrackets = true
codemirror-autoCloseBrackets = true
codemirror-keywords-qfq-base = space delimited custom list of keywords (see javascript/src/Helper/codemirror/qfq.js for possible keyword types)
* *FormElement.size* = ,: in pixels, including top and bottom bars. E.g.: 300,600
Define allowed html tags. TinyMCE settings will be overwritten if this parameter is set.
* Following tags are not used from TinyMCE: u,del,ins,s. In this case use textDecoration to get comparable function and correct configuration. Example: ::
htmlAllow = p,br,h1,h3,table,b,textDecoration,ul,img
* By default every html tag is allowed. List with tags and their automatically associated tags :ref:`htmlAllow`
Type: annotate
^^^^^^^^^^^^^^
Annotate image or text. Typically the image or text has been uploaded during a previous step. The annotation will be
saved in *FormElement.name* column of the current record. The uploaded file itself will not be modified. The annotations
can be shown in edit (and might be modified) or in readonly mode.
Two modes are available:
grafic
A simple graphic editor to paint on top of the image (best by a tablet with pen or graphic tablet). The uploaded image
is shown in the background. All drawings are saved as a JSON fabric.js data string. Supported file types:
**png, svg**. PDF files can be easily divided into per page SVG files during upload - see :ref:`split-pdf-upload`
text
Per code line, annotation(s) can be added. Different users can add individual annotations. A user can only edit the
own annotations. The annotations are saved as QFQ internal JSON string.
.. note::
Drawing with fabric.js might produce a lot data. Take care the column type/size is big enough (>=64kB).
Grafic
""""""
An image, specified by ``FormElement.parameter.imageSource={{pathFileName}}``, will be displayed in the background. On
form load, both, the image and an optional already given graphical annotations, will be displayed. The image is SIP
protected and will be loaded on demand.
**Form.parameter**
+-------------------+-----------------------+----------------------------------------------------------------------------------+
| Attribute | Value | Description |
+===================+=======================+==================================================================================+
| annotateType | grafic | *grafic|text*. Default is *grafic*. Select mode. |
+-------------------+-----------------------+----------------------------------------------------------------------------------+
| imageSource | | Background image. E.g. `fileadmin/images/scan.png` |
+-------------------+-----------------------+----------------------------------------------------------------------------------+
| defaultPenColor | | Pen default color, after loading the fabric element. Default is '0000FF' (blue). |
+-------------------+----------------------------------------------------------------------------------------------------------+
.. note::
By using the the `FormElement` `annotate`, the JS code `fabric.min.js` and `qfq.fabric.min.js` has to be included. See :ref:`setup-css-js`.
Code
""""
**Form.parameter**
+--------------------+-----------------------+----------------------------------------------------------------------------------+
| Attribute | Value | Description |
+====================+=======================+==================================================================================+
| annotateType | text | *grafic|text*. Default is *grafic*. Select mode. |
+--------------------+-----------------------+----------------------------------------------------------------------------------+
| textSource | | Text file to annotate. |
+--------------------+-----------------------+----------------------------------------------------------------------------------+
| annotateUserName | | Will be shown at annotation line. |
+--------------------+-----------------------+----------------------------------------------------------------------------------+
| annotateUserUid | <123> | Will be shown at annotation line. |
+--------------------+-----------------------+----------------------------------------------------------------------------------+
| annotateUserAvatar | | Will be shown at annotation line. |
+--------------------+-----------------------+----------------------------------------------------------------------------------+
| highlight | auto | off,auto,javascript,qfq,python,matlab |
+--------------------+-----------------------+----------------------------------------------------------------------------------+
Type: imageCut
^^^^^^^^^^^^^^
Uploaded images can be cut or rotate via QFQ (via fabric.js). The modified image is saved under the given pathFileName.
* The 'value' of the `FormElement` has to be a valid PathFileName to an image.
* Valid image file formats are SVG, PNG, JPG, GIF.
* Invalid or missing filenames results to an empty 'imageCut' element.
* *FormElement.parameter*:
* *resizeWidth* = |[width in pixel] - the final width of the modified image. If empty (or not given), no change.
* *keepOriginal* = |[string] - By default: '.save'. If empty (no string given), don't keep the original. If an
extension is given and if there is not already a <.extension>, than the original file is to copied to it.
Type: note
^^^^^^^^^^
An FormElement without any 'input' functionality -just to show some text. Use the typical fields 'label', 'value' and
'note' to be displayed in the corresponding three standard columns.
Type: password
^^^^^^^^^^^^^^
* Like a `text` element, but every character is shown as an asterisk.
Often the following form.Parameter arguments are used here:
* retype, retypeLabel, retypeNote - see `retype`_.
* :ref:`extraButtonPassword`.
.. _`input-radio`:
Type: radio
^^^^^^^^^^^
* Radio Buttons will be built from one of three sources:
1. 'sql1': E.g. *{{!SELECT type AS label FROM Car }}* or *{{!SELECT type AS label, typeNr AS id FROM Car}}* or *{{!SHOW tables}}*.
* Resultset format 'named': column 'label' and optional a column 'id'.
* Resultset format 'index':
* One column in resultset >> first column represents *label*
* Two or more columns in resultset >> first column represents *id* and second column represents *label*.
2. *FormElement.parameter*:
* *itemList* = `` E.g.: *itemList=red,blue,orange* or *itemList=1:red,2:blue,3:orange*
* If ':' or ',' are part of key or value, it needs to escaped by \\ . E.g.: `itemList=1:red\\: (with colon),2:blue\\, (with comma),3:orange`
3. Definition of the *enum* or *set* field (only labels, ids are not possible).
* *FormElement.maxlength* = ``
* Applies only to 'plain' radio elements (not the Bootstrap 'buttonClass' from below)
* *vertical* or *horizontal* alignment:
* ``: '', 0, 1 - The radios will be aligned *vertical*.
* ``: >1 - The radios will be aligned *horizontal*, with a linebreak every 'value' elements.
* *FormElement.parameter*:
* *emptyHide*: Existence of this item hides an entry with an empty string. This is useful for e.g. Enums, which have an empty
entry, but the empty value should not be selectable.
* *emptyItemAtStart*: Existence of this item inserts an empty entry at the beginning of the selectlist.
* *emptyItemAtEnd*: Existence of this item inserts an empty entry at the end of the selectlist.
* *buttonClass* = - Instead of the plain radio fields, Bootstrap
`buttons `_. are rendered as `radio` elements. Use
one of the following `classes `_:
* `btn-default` (default, grey),
* `btn-primary` (blue),
* `btn-success` (green),
* `btn-info` (light blue),
* `btn-warning` (orange),
* `btn-danger` (red).
With a given *buttonClass*, all buttons (=radios) are rendered horizontal. A value in *FormElement.maxlength* has no effect.
* *No preselection*:
* If there is a default configured on a table column, such a value is selected by default. If the user should actively
choose an option, the 'preselection' can be omitted by specifying an explicit definition on the FormElement field `value`::
{{:RZ}}
For existing records the shown value is as expected the value of the record. For new records, it's the value `0`,
which is typically not one of the ENUM values and therefore nothing is selected.
.. _`input-select`:
Type: select
^^^^^^^^^^^^
* Select lists will be built from one of three sources:
* *FormElement.sql1* = `{{!> first column represents *label*
* Two or more columns in resultset >> first column represents *id* and second column represents *label*.
* *FormElement.parameter*:
* *itemList* = `` - E.g.: *itemList=red,blue,orange* or *itemList=1:red,2:blue:3:orange*
* If ':' or ',' are part of key or value, it needs to escaped by \\ . E.g.: `itemList=1:red\\: (with colon),2:blue\\, (with comma),3:orange`
* Definition of the *enum* or *set* field (only labels, ids are not possible).
* *FormElement.size* = ``
* ``: |0|1: drop-down list.
* ``: >1: Select field with *size* rows height. Multiple selection of items is possible.
* *FormElement.parameter*:
* *emptyItemAtStart*: Existence of this item inserts an empty entry at the beginning of the select list.
* *emptyItemAtEnd*: Existence of this item inserts an empty entry at the end of the select list.
* *emptyHide*: Existence of this item hides the empty entry. This is useful for e.g. Enums, which have an empty
entry and the empty value should not be an option to be selected.
* *datalist*: Similar to 'typeAhead'. Enables the user to select a predefined option (sql1, itemList) or supply any
free text. Attention: Safari (and some other) browsers do not support this fully - https://caniuse.com/#search=datalist.
.. _`subrecord-option`:
Type: subrecord
^^^^^^^^^^^^^^^
The *FormElement* type 'subrecord' renders a list of records (so called secondary records), typically to show, edit, delete
or add new records. The list is defined as an SQL query. The number of records shown is not limited. These *FormElement*
will be rendered inside the form as a HTML table.
* *mode / modeSql* = ``
* *show / required*: the regular mode to show the subrecords
* *readonly*: New / Edit / Delete Buttons are disabled
* *hidden*: The FormElement is rendered, but hidden with `display='none'`.
* *dynamicUpdate* - not supported at the moment.
* *sql1* = `{{!SQL Query}}`
* SQL query to select records. E.g.::
{{!SELECT addr.id AS id, CONCAT(addr.street, addr.streetnumber) AS a, addr.city AS b, addr.zip AS c FROM Address AS addr}}
* Notice the **exclamation mark** after '{{' - this is necessary to return an array of elements, instead of a single string.
* Exactly one column **'id'** has to exist; it specifies the primary record for the target form.
In case the id should not be visible to the user, it has to be named **'_id'**.
* Column name: *[title=][|[maxLength=]][|nostrip][|icon][|link][|url][|mailto][|_rowEdit][|_rowDelete][|_rowClass][|_rowTooltip]*
* All column names are optional.
* If the keyword is used, all parameter are position independent.
* Parameter are separated by '|'.
* *[title=]*: Title of the column. The keyword 'title=' is optional. Columns with a title starting with '_' won't be rendered.
* *[maxLength=]*: Max. number of characters displayed per cell. The keyword 'maxLength=' is optional. Default
maxLength '20'. A value of '0' means no limit. This setting also affects the title of the column.
* *nostrip*: by default, html tags will be stripped off the cell content before rendering. This protects the table
layout. 'nostrip' deactivates the cleaning to make pure html possible.
* *icon*: the cell value contains the name of an icon in *typo3conf/ext/qfq/Resources/Public/icons*. Empty cell values
will omit an html image tag (=nothing rendered in the cell). See :ref:`qfq-icons`.
* *link*: value will be rendered as described under :ref:`column-link`
* *url*: value will be rendered as a href url.
* *mailto*: value will be rendered as a href mailto.
* *_rowEdit*: per row controlled edit link. Use regular *... AS _link* syntax. Specify only those parameter which has
to be row specific - all other will be used from generic render process.
* *_rowDelete*: per row controlled edit link. Use regular *... AS _link* syntax. Specify only those parameter which
has to be row specific - all other will be used from generic render process.. E.g. with *renderMode* (r:3) it's
possible to prevent specific rows to be deleted.
* *_rowClass*
* The value is a CSS class name(s) which will be rendered in the ** of the subrecord table.
* The column itself is not rendered.
* By using Bootstrap, the following predefined classes are available:
* Text color: *text-muted|text-primary|text-success|text-info|text-warning|text-danger* (http://getbootstrap.com/docs/3.4/css/#helper-classes)
* Row background: *active|success|info|warning|danger* (http://getbootstrap.com/docs/3.4/css/#tables-contextual-classes)
* *_rowTooltip*
* Defines the title attribute (=tooltip) of a subrecord table row.
* Examples::
{{!SELECT id, note1 AS 'Comment', note2 AS 'Comment|50' , note3 AS 'title=Comment|maxLength=100|nostrip', note4 AS '50|Comment',
'checked.png' AS 'Status|icon', email AS 'mailto', CONCAT(homepage, '|Homepage') AS 'url',
CONCAT('d|s|F:', pathFileName) AS 'Download|link',
ELT(status,'info','warning','danger') AS '_rowClass', help AS '_rowTooltip' ...}}
* *FormElement.parameter*
* *form* = ` |