Commit 031296d7 authored by Carsten  Rose's avatar Carsten Rose
Browse files

OnArray.php: some doc enhanced

parent 4d6214ec
......@@ -58,4 +58,5 @@ QFQ Extension
:maxdepth: 4
Manual
Release
Links
......@@ -417,10 +417,12 @@ Escape
* 's' - single ticks will be escaped.
* 'd' - double ticks will be escaped.
* 'l' - LDAP search filter values will be escaped.
* 'L' - LDAP DN values will be escaped.
* It's not possible to escape single and double ticks at the same time.
* Even it's possible to escape single and double ticks at the same time, this makes no sense.
* Which of them to escape (single or double) depends on the surrounding SQL query.
* Escaping is only necessary inside of SQL queries.
* Escaping is only necessary inside of SQL or LDAP queries.
Sanitize class
^^^^^^^^^^^^^^
......@@ -485,6 +487,8 @@ Only variables that are known in a specified store can be substituted.
+-----+----------------------------------------------------------------------------------------+----------------------------------------------------------------------------+
| V | :ref:`STORE_VARS`: Generic variables | |
+-----+----------------------------------------------------------------------------------------+----------------------------------------------------------------------------+
| L | :ref:`STORE_LDAP`: Will be filled on demand during processing of a *FormElement* | Custom specified list of LDAP attributes |
+-----+----------------------------------------------------------------------------------------+----------------------------------------------------------------------------+
| 0 | *Zero* - allways value: 0, might be helpful if a variable is empty or undefined and | Any key |
| | will be used in an SQL statement. | |
+-----+----------------------------------------------------------------------------------------+----------------------------------------------------------------------------+
......@@ -669,6 +673,21 @@ Store: *VARS* - V
| fileDestinaton | Destination (path & filename) for an uploaded file. Defined in an 'upload'-FormElement.parameter. Valid: same as 'filename'. |
+-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+
.. _STORE_LDAP:
Store: *LDAP* - L
^^^^^^^^^^^^^^^^^
* Sanatized: *yes*
* See :ref:`STORE_LDAP`:
+-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+
| Name | Explanation |
+=========================+============================================================================================================================================+
| <custom defined> | See *ldapAttributes* |
+-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+
.. _STORE_SYSTEM:
......@@ -762,6 +781,114 @@ SQL Statement
* This is only possible for the outermost SELECT.
.. _LDAP:
LDAP
====
A form can retrieve values from an LDAP server to display or to save them. Configuration options for LDAP will be specified
in the *parameter* field of the *Form* and/or the *FormElement*. Definitions of the *FormElement* will overwrite definitions
of the *Form*. If LDAP access is:
* only necessary in one *FormElement*, most usefull setup is to specify all values in that specific *FormElement*,
* needed on multiple *FormElement*s (of the same *Form*, e.g. one *input* with *typeAhead*, one *note* and one *action*), it's more
efficient to specify the base parameter *ldapServer*, *ldapBaseDn* in *Form.parameter* and the rest on the current
*FormElement*.
+--------------------------+----------------------------------+------------------------------------------------------------+------+-------------+----------+
| Parameter | Example | Description | Form | FormElement | Used for |
+==========================+==================================+============================================================+======+=============+==========+
| ldapServer | directory.example.com | Hostname | x | x | TA, FSL |
+--------------------------+----------------------------------+------------------------------------------------------------+------+-------------+----------+
| ldapBaseDn | ou=Addressbook,dc=example,dc=com | Base DN to start the search | x | x | TA, FSL |
+--------------------------+----------------------------------+------------------------------------------------------------+------+-------------+----------+
| ldapAttributes | cn, email | List of attributes to save in STORE_LDAP | x | x | FSL |
+--------------------------+----------------------------------+------------------------------------------------------------+------+-------------+----------+
| ldapSearch | (mail=john.doe@example.com) | Regular LDAP search expresssion | x | x | FSL |
+--------------------------+----------------------------------+------------------------------------------------------------+------+-------------+----------+
| ldapTimeLimit | 3 (default) | Maximum time to wait for an answer of the LDAP Server | x | x | TA, FSL |
+--------------------------+----------------------------------+------------------------------------------------------------+------+-------------+----------+
| typeAheadLdap | - | Enable LDAP as 'Typeahead' data source | | x | TA |
+--------------------------+----------------------------------+------------------------------------------------------------+------+-------------+----------+
| typeAheadldapSearch | (|(cn=*?*)(mail=*?*)) | Regular LDAP search expresssion | x | x | TA |
+--------------------------+----------------------------------+------------------------------------------------------------+------+-------------+----------+
| typeAheadLdapValuePrintf | `'%s / %s', cn, email` | Custom format to disply attributes, as value | x | x | TA |
+--------------------------+----------------------------------+------------------------------------------------------------+------+-------------+----------+
| typeAheadLdapKeyPrintf | `'%s', email` | Custom format to disply attributes, as key | x | x | TA |
+--------------------------+----------------------------------+------------------------------------------------------------+------+-------------+----------+
| typeAheadLimit | 20 (default) | Result will be limited to this number of entries | x | x | TA |
+--------------------------+----------------------------------+------------------------------------------------------------+------+-------------+----------+
| typeAheadMinLength | 2 (default) | Minimum number of characters before starting the search | x | x | TA |
+--------------------------+----------------------------------+------------------------------------------------------------+------+-------------+----------+
| fillStoreLdap | - | Activate `Fill STORE LDAP` with the first retrieved record | | x | FSL |
+--------------------------+----------------------------------+------------------------------------------------------------+------+-------------+----------+
* At the moment only anonymous access is supported.
* *typeAheadLimit*: there might be a hard limit on the server side (e.g. 100) - which can't be extended.
.. _LDAP_Typeahead:
Typeahead (TA)
--------------
*Typeahead* offers continous searching of a LDAP directoy by using a regular *FormElement* of type *text*.
The *FormElement.parameter*=*typeAheadLdap* will trigger LDAP searches on every user **keystroke**
(starting after *typeAheadMinLength* keystrokes) for the current *FormElement* - this is different from *dynamicUpdate*
(triggered by leaving focus of an input element). Typeahead delivers a list of elements.
* *FormElement.parameter.typeAheadLdap* - activate the mode *Typeahead* - no value is needed, the existence is suffucient.
* *Form.parameter* or *FormElement.parameter*:
* *ldapServer* = `directory.example.com`
* *ldapBaseDn* = `ou=Addressbook,dc=example,dc=com`
* *typeAheadldapSearch* = `(|(cn=*?*)(mail=*?*))`
* *typeAheadLdapValuePrintf* = `'%s / %s', cn, email`
* *typeAheadLdapKeyPrintf* = `'%s', email`
All fetched LDAP values will be formatted with:
* *typeAheadLdapValuePrintf*, shown to the user in a drop-down box and
* *typeAheadLdapKeyPrintf*, which represents the final data to save.
The `key/value` translation is compareable to a regular select drop-down box with key/value pairs.
Only attributes, defined in *typeAheadLdapValuePrintf* / *typeAheadLdapKeyPrintf* will be fetched from the LDAP directory.
To examine all possible values of an LDAP server, use the commandline tool `ldapsearch`. E.g.::
ldapsearch -x -h directory.example.com -L -b ou=Addressbook,dc=example,dc=com "(mail=john.doe@example.com)"
All occurences of a '?' in *ldapSearch* will be replaced by the user data typed in via the text-*FormElement*.
The typed data will be escaped to fullfill LDAP search limitations.
Regular *Form* variables might be used on all parameter and will be evaluated during form load - *not* at the time when
the user types something.
.. _Fill_LDAP_STORE:
Fill STORE LDAP (FSL)
---------------------
Before processing a *FormElement*, an optional configured FLS-action loads **one** record from a LDAP directory and stores
the named attributes in STORE_LDAP. FLS is triggered on *Form*
* load,
* dynamic update,
* save.
The FLS happens *before* the main *FormElement* processing starts. Therefore the fetched LDAP data (specified by *ldapAttributes*),
are available via `{{<attributename>:L:allbut:s}}` during the regular *FormElement* processing. Take care to specify
a sanatize class and optional escaping on further processing of those data.
Important: LDAP access might slow down the *Form* processing on load, update or save! The timeout (default: 3 seconds) have
to be multiplied by number of access. E.g. a broken LDAP connection and 3 *FormELements* with *FSL*
results to 9 seconds delay on save. Also be prepared not to receive the expected data.
* *FormElement.parameter.fillStoreLdap* - activate the mode *Fill S* - no value is needed, the existence is suffucient.
* *Form.parameter* or *FormElement.parameter*:
* *ldapServer* = directory.example.com
* *ldapBaseDn* = ou=Addressbook,dc=example,dc=com
* *typeAheadldapSearch* = (|(cn=*?*)(mail=*?*))
* *ldapAttributes* = givenName, sn, telephoneNumber, email
* *ldapSearch* = (mail={{email::l}})
After filling the store, access the content via `{{<attributename>:allbut:L:s}}`.
Form
====
......@@ -865,7 +992,7 @@ parameter
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| Name | Type | Description |
+==========================+========+==========================================================================================================+
| maxVisiblePill | int | Show pills upto <maxVisiblePill> as button, all further in a dropdown menu. Eg.: maxVisiblePill=3 |
| maxVisiblePill | int | Show pills upto <maxVisiblePill> 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 |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
......@@ -885,24 +1012,33 @@ parameter
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| 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' +
| 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 |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| ldapServer | string | FQDN Ldap Server. E.g.: ldap.example.com |
| ldapBaseDn | string | E.g.: `ou=Addressbook,dc=example,dc=com` |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| ldapBaseDn | string | E.g.: ou=dept,dc=example,dc=com |
| ldapAttributes | string | List of attributes to fill STORE_LDAP with. E.g.: cn, email |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| ldapSearch | string | E.g.: (|(cn=*?*)(mail=*?*)(ou=*?*)(roomNumber=*?*)(telephoneNumber=*?*)) |
| 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 expresssion. E.g.: `(|(cn=*?*)(mail=*?*))` |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| typeAheadLdapValuePrintf | string | Value formatting of LDAP result, per entry. E.g.: `'%s / %s / %s', mail, roomnumber, telephonenumber` |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| typeAheadLdapKeyPrintf | string | Key formatting of LDAP result, per entry. E.g.: `'%s', mail` |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| 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. |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| typeAheadLdapValuePrintf | string | Value formatting of LDAP result, per entry. E.g.: '%s / %s / %s', mail, roomnumber, telephonenumber |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| typeAheadLdapKeyPrintf | string | Key formatting of LDAP result, per entry. E.g.: '%s', mail |
| fillStoreLdap | - | Activate `Fill STORE LDAP` with the first retrieved record |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
* Example:
* maxVisiblePill = 5
......@@ -1022,13 +1158,13 @@ Type: pill
* FormElement settings:
* *name*: technical name, used as HTML identifier.
* *label*: Label shown on the corresponding pill button or inside the dropdown menu.
* *label*: Label shown on the corresponding pill button or inside the drop-down menu.
* *type*: *pill*
* *feIdContainer*: `0` - Pill's can't be nested.
* *parameter*:
* *maxVisiblePill*: `<nr>` - Number of Pill-Buttons shown. Undefined means unlimited. Excess Pill buttons will be
displayed as a dropdown menu.
displayed as a drop-down menu.
.. _class-native:
......@@ -1413,9 +1549,9 @@ Type Ahead
''''''''''
Activating `typeahead` functionality offers an instant lookup of data and displaying them to the user, while the user is
typing a dropdown box offers the results. As datasource the regular SQL connection or a LDAP query can be used.
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 the dropdown box.
the server, the lookup will be performed and the result, upto *typeAheadLimit* entries, are displayed as a drop-down box.
* *FormElement.parameter*:
......@@ -1428,7 +1564,8 @@ configured).
Configuration via Form / FormElement
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
All of the `typeAhead*` (exception: `typeAheadLdap`) and `ldap*` parameter can be specified in either on the Form.parameter or on FormElement.parameter.
All of the `typeAhead*` (except `typeAheadLdap`) and `ldap*` parameter can be specified either in
*Form.parameter* or in *FormElement.parameter*.
SQL
;;;
......@@ -1445,16 +1582,7 @@ SQL
LDAP
;;;;
* *FormElement.parameter*:
* *typeAheadLdap* This entry activates the *LDAP* typeahead functionality.
* *ldapServer* = FQDN of the searched server. E.g.: `directory.uzh.ch`
* *ldapBaseDn* = Base DN. E.g.: `ou=Addressbook,dc=uzh,dc=ch`
* *ldapSearch* = LDAP search expression. Every '?' will be replaced with the current typed content.
E.g.: `(|(cn=*?*)(mail=*?*)(ou=*?*)(roomNumber=*?*)(telephoneNumber=*?*))`
* *typeAheadLdapValuePrintf* = regular printf expression, LDAP attributenames will be used as variablenames. Will be shown
in the dropdownbox. E.g.: `'%s / %s / %s', mail, roomNumber, telephoneNumber`
* *typeAheadLdapKeyPrintf* = Same as `ldapValuePrintf` - on save, these content will be saved. E.g.: `'%s', mail`
See :ref:`LDAP_Typeahead`
Type: editor
^^^^^^^^^^^^
......@@ -1570,7 +1698,7 @@ Type: select
* *FormElement.size*: `<value>`
* `<value>`: <empty>|0|1: Dropdown list.
* `<value>`: <empty>|0|1: drop-down list.
* `<value>`: >1: Select field with *size* rows height. Multiple selection of items is possible.
* *FormElement.parameter*:
......@@ -1943,26 +2071,29 @@ Dynamic Update
--------------
The 'Dynamic Update' feature makes a form more interactive. If a user change a *FormElement* who is tagged with
'dynamicUpdate', *all* elements who are tagged with 'DynamicUpdate', will be recalculated and rerendered.
'dynamicUpdate', *all* elements who are tagged with 'dynamicUpdate', will be recalculated and rerendered.
The following fields will be recalculated during 'Dynamic Update'
* 'modeSql' - Possible values: 'show', 'required', 'readonly', 'hidden'
* 'label'
* 'value'
* 'parameter.*' - especially 'itemList'
* 'note'
* 'label'
* 'parameter.*' - especially 'itemList'
To make a form dynamic:
* Mark all *FormElements* with `dynamic update`=`enabled`, which **initiates** or **receives** updates.
* Define the receiving *FormElements* in a way, that they will interpret the recent user change. The form variable of the
* Mark all *FormElements* with `dynamic update`=`enabled`, which should **initiate** or **receive** updates.
* Define the receiving *FormElements* in a way, that they will interpret the recent user change! The form variable of the
specific sender *FormElement* `{{<sender element>:F:<sanitize>}}` should be part of one of the above fields to get an
impact. E.g.:
::
[receiving *FormElement*].parameter: itemList={{ SELECT IF({{carPriceRange:FE:alnumx}}='expensive','Ferrari,Tesla,Jaguar','General Motors,Honda,Seat,Fiat') }}
Remember to specify a 'sanatize' class - a missing sanatize class means 'digit', every content which is not numeric
violate the sanatize class and becomes therefore an empty string!
Examples
^^^^^^^^
......@@ -1986,7 +2117,6 @@ Show / Hide a *FormElement*
modeSql={{SELECT IF( '{{music:FR:alnumx}}'='pop' ,'show', 'hidden' }}
.. _form-layout:
Form Layout
......@@ -2106,17 +2236,17 @@ via SIP parameter to the secondary form.
On the secondary form: for 'new' records choose the computed value, for existing records leave the value
unchanged.
* Primary form, `subrecord` *FormElement*, field `parameter`: set ::
* Master form, `subrecord` *FormElement*, field `parameter`: set ::
detail=id:formId,{{SELECT '&', IFNULL(fe.ord,0)+10 FROM Form AS f LEFT JOIN *FormElement* AS fe ON fe.formId=f.id WHERE
f.id={{r:S0}} ORDER BY fe.ord DESC LIMIT 1}}:ord
* Secondary form, `ord` *FormElement*, field `value`: set
* Slave form, `ord` *FormElement*, field `value`: set
::
`{{RS0}}`.
`{{ord:RS0}}`.
Version 2
'''''''''
......@@ -3819,256 +3949,3 @@ Same as above, but written in the nested notation ::
}
* Columns starting with a '_' won't be printed but can be accessed as regular columns.
.. _release:
Release
=======
Version 0.future
----------------
Changes
^^^^^^^
* Play formEditor.sql.
* Dropdownlist of container assignment:
* Display 'type' ('pill', 'fieldset', 'templategroup') instead of 'class' (always 'container').
* Display 'name' (internal name) instead of 'label' (shown on the website and might not so usefull as 'name' which is nowhere else used than in that dropdown.
* FormElement.placeholder colum width extended to 512:
ALTER TABLE `FormElement` CHANGE `placeholder` `placeholder` VARCHAR(512) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '';
Features
^^^^^^^^
Bug Fixes
^^^^^^^^^
Version 0.13
------------
Changes
^^^^^^^
* Play formEditor.sql.
* formEditor.sql:
* Checktype of `Form.name` restricted to `alnumx` (prior `all`).
* Changed `access` for Form `form` & '`ormElement` from `always` to `sip`.
* Table `FormElement`
* Modified column: `checkType` - new value `numerical`
ALTER TABLE FormElement MODIFY COLUMN checkType ENUM('alnumx','digit','numerical','email','min|max','min|max date',
'pattern','allbut','all') NOT NULL DEFAULT 'alnumx'
* Example Report for `forms` extended by a delete button per row.
Features
^^^^^^^^
* print.php: offers 'print page' for any local page - create a PDF on the fly (printout is then browser independent).
* Install `wkhtmltopdf` on the webserver (http://wkhtmltopdf.org/).
* In config.qfq.ini setup:
BASE_URL_PRINT=http://www.../
WKHTMLTOPDF=/opt/wkhtmltox/bin/wkhtmltopdf
* Check and error report if 'php_intl' is missing.
* New Checktype 'allow numerical'.
* Documentation: example for 'radio' with no pre selection.
* #3063, Radios and checkboxes optional rendered in Bootstrap layout.
* Added 'help-box with-errors'-DIV after radios and checkboxes.
* Respect attribute `data-class-on-change` on save buttons.
Bug Fixes
^^^^^^^^^
* #2138 / digit sanitize: new class 'numerical' implemented.
* Fixed recursive thrown exception.
* #2064 / search of a default value for a non existing tablecolumn returns 'false'.
* Fixed setting of STORE_SYSTEM / showDebugInfo during API call.
* #2081, #3180 Form: Label & note - update via `DynamicUpdate`
* #3253, if there is no STORE_TYPO3 (calls through .../api/ like save, delete, load): use SIP / CLIENT_TYPO3VARS.
* qfq-bs.css:
* Alignment of checkboxes and radios optimized.
* CSS class 'qfq-note' for 'notes' (third column in a form).
Version 0.12
------------
Changes
^^^^^^^
* Table 'FormElement'
* New column: rowLabelInputNote
ALTER TABLE `FormElement` ADD `rowLabelInputNote` set('row','label','/label','input','/input','note','/note','/row')
NOT NULL DEFAULT 'row,label,/label,input,/input,note,/note,/row' AFTER `bsNoteColumns` ;
* Modified column: 'type' - new value 'templateGroup'
ALTER TABLE `FormElement` CHANGE `type` `type` ENUM( 'checkbox', 'date', 'datetime', 'dateJQW', 'datetimeJQW', 'extra',
'gridJQW', 'text', 'editor', 'time', 'note', 'password', 'radio', 'select', 'subrecord', 'upload', 'fieldset', 'pill',
'templateGroup', 'beforeLoad', 'beforeSave', 'beforeInsert', 'beforeUpdate', 'beforeDelete', 'afterLoad', 'afterSave',
'afterInsert', 'afterUpdate', 'afterDelete', 'sendMail' ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'text';
* formEditor.sql: Added HTML 'placeholder' in FormEditor for bs*Columns.
* PLAY 'formEditor.sql'.
* User Input will be UTF8 normalized.
* INSTALL 'php5-intl' or 'php7.0-intl' on Webserver.
* Add globalize.js to be included. Needed by jqx-all.js
* UPDATE EXISTING TypoScript TEMPLATES of QFQ Installation.
* Name of variable '_filename' (used in field 'parameter') has changed. Old: '_filename', New: 'filename'
* UPDATE `FormElement` SET parameter = REPLACE(parameter, '_filename', 'filename')
Features
^^^^^^^^
* User input will be UTF8 normalized
* config.qfq-ini:
* New configuration values: FORM_BS_LABEL_COLUMNS / FORM_BS_INPUT_COLUMNS / FORM_BS_NOTE_COLUMNS
* Comment empty variables - the new default setting is, that empty parameter in config.qfq.ini means EMPTY (=parameter is set and will not be overwritten by internal default), not UNDEFINED (overwritten by internal default).
* FileUpload:
* Implemented new Formelement.parameter: fileReplace=always - will replace existing files.
* Multiple / Advanced Upload: new logic implements slaveId, sqlInsert, sqlUpdate, sqlDelete.
* FormElement.parameter: sqlBefore / sqlAfter fired during 'Form' save for action elements.
* STORE FORM: variable 'filename' moved to STORE VAR - sanatize class needs no longer specified.
* STORE VAR: two new variables 'filename' and 'fileDestination' valid during processing of current upload FormElement.
* Default store priority list changed. Old: 'FSRD', New: 'FSRVD'.
* CODING.md: update doc for FormElement 'upload' and general 'Form' rendering & save (recursive rendering).
* User manual:
* Described form layout options: description for bsLabelColumn, bsInputColumn, bsNoteColumn
* Update 'file-upload' doc.
* Described 3 examples for upload forms.
* Administrator manual:
* Add description page.meta...
* New FormElement (type= 'container') added: 'templateGroup'
* FormElement.parameter.tgAddClass | tgAddText | tgRemoveClass | tgRemoveText | tgClass
* FormElement.maxSize: max number of duplicates
* #3230 templateGroup: margin between copies. 'tgClass' implemented.
* Native FormElements:
* FormElement.parameter.htlmlBefore|htmlAfter - add the specified HTML code before or after the element (outside of any wrapping)
* #3224, #3231 Html Tag <hr> als FormElement. >> htmlBefore | htmlAfter.
* FormElement.parameter.wrapLabel | wrapInput | wrapAfter | wrapRow - if specified, any default wrapping is omitted.
* FormElement.bsNoteColumns | bsInputColumns | bsNoteColumns - a '0' will suppress the whole rendering of the item.
* FormElement.rowLabelInputNote - switch on/off rendering of the corresponding system wrapping items.
* #3232 Define custom 'on-change' color - used for the save button: Form.parameter.buttonOnChangeClass=...
* Form.parameter & FormElement.parameter: Lines starting with '#' are treated as comments and will not be parsed.
Bug fixes
^^^^^^^^^
* User manual:
* Fixed double include of validator.js in T3 Typoscript template example.
* Fixed wrong store name SYSTEM: S > Y
* Fixed wrong STORE_FORM variable names.
* Reformat FormElement.parameter description.
* Styling errors fixed.
* Use of 'decryptCurlyBraces()' to get better error messages.
* Skip unwanted parameter expansion during save.
* Fixed bug with uninitialized FE_SLAVE_ID
* formEditor.sql:
* The defintion as 'editor' (not text) for FormElement 'note' has been lost - reinserted.
* Fixed problem while playing SQL query - deleting old FormElements of Formeditor deleted also FormElements of other forms.
* #3066 / help-text with-error - CSS class 'hidden' will be rendered by default (as long there is no error).
* Labels are skipped, if FormElement.bsLabelColumns=0.
* Respect attribute `data-class-on-change` on save buttons.
Version 0.11
------------
Features
^^^^^^^^
* Added STORE_BEFORE, #3146 - Mainly used to compare old and new values during a form 'save' action.
* Added 'best practice' for defining and using of 'Central configure values' in UserManual.
* Added accent characters to sanatize class 'alnumx', #3183.
* Set default all QFQ send mails to 'auto-submit'.
* Added possibility to customize error messages ('data-pattern-error', 'data-rquired-error', 'data-match-error',
'data-error') if validation fails. Customization can be done on global level (config.qfq.ini), per Form or per FormElement.
* *FormElement*: Double an input element and validate that the input match: FormElement.parameter.retype=1
* Autofocus in Forms is now supported. By default the first Input Element receives the focus. Can be customized.
* Added a timestamp in shown exceptions. Usefull for screenshots, send by customer, to find the problem in SQL logfiles.
Bug fixes
^^^^^^^^^
* Fixed missing docutmentation for FormElement 'note'.
* Failed SQL queries will now always be logged, even if they do not modify some data.
Version 0.10
------------
Features
^^^^^^^^
* Implemented Parameter 'extraDeleteForm' for 'forms' and 'subrecords'. Update doc.
Bug fixes
^^^^^^^^^
* Suppress rendering of form title during a 'delete' call. No one will see it and required parameters are not supplied.
* In case of broken SQL queries, print them in ajax error message.
* Remove parameter 'table' from Delete SIP URLs. ToolTip updated.
Version 0.9
-----------
Features
^^^^^^^^
* FormEditor:
* design update - new default background color: grey.
* per form configureable background colors.
* Optional right align of all form element labels.
* Added config.qfq.ini values CSS_CLASS_QFQ_FORM_PILL, CSS_CLASS_QFQ_FORM_BODY, CSS_CLASS_QFQ_CONTAINER.
Bug fixes
^^^^^^^^^
* BuildFormBootstrap.php: added new class name 'qfq-label' to form labels - needed to assign 'qfq-form-right' class. Changed wrapping of formelements from 'col-md-8' (wrong) to 'col-md-12'.
* QuickFormQuery.php: Set default for new F_CLASS_PILL & F_CLASS_BODY.
* formEditor.sql: New default background color for formElements is blue.
* qfq-bs.css.less: add classes qfq-form-pill, qfq-form-body, form-group (center), qfq-color-..., qfq-form-right.
* Index.rst: Add note to hierachy chars. Fixed uncomplete doc to a) bs*Columns, showButton. Add classPill, classBody. Rewrote form.paramter.class.
* QuickFormQuery.php: Button save/ close/ delete/ new - align to right border of form.
* UsersManual/index.rst: renamed chapter for formelements. Cleanup formelement types. Wrote chapter 'Detailed concept'.
* QuickFormQuery.php, FormAction.php: '#2931 / afterSave Hauptrecord xId nicht direkt verfügbar' - load master record again, after 'action'-elements has been processed.
* UsersManual/index.rst: Startet FAQ section.
* config.qfq.example.ini: Added comment where to save config.qfq.ini.
* UsersManual/index.rst: Rewrite of 'action'-FormElement definition.
* #2739: beforeDelete / afterDelete.
* PROTOCOL.md: update 'delete' description.
* delete.php: fixed unwanted loose of MSG_CONTENT.
* Report.php: Fixed double '&&' in building UrlParam.
* FormAction.php: In case of 'AFTER_DELETE', do not try to load primary record - that one is already deleted.
* Sip.php: Do not skip SIP_TARGET_URL as parameter for the SIP.
* #3001 Report: delete implementieren.
* Index.rst, Constants.php: reverted parameter '_table' in delete links back to 'table' - Reason: 'form' needs to be 'form' (instead of '_form') due to many used places already.
* Sip.php: move SIP_TARGET_URL back to stored inside SIP - it's necessary for 'delete'-links.
* Report.php, Constants.php: Remove code to handle unecessary 'p:' tag for delete links.
* Link.php: Check paged / Paged that the parameter r, table and form are given in the right combination.
* Link.php, Report.php: New '_link' token 'x'. '_paged' and '_Paged' are rendered via Link() class, Link() class now supports delete links.
* QuickFormQuery.php: for modeForm='Form Delete' the 'required param' are not respected - this makes sense, cause these parameters typically filled in newly created records.
* Fixed: #3076 Delete Button bei Subrecords erzeugt sporadisch Javascript Exceptions (Webkit: Chrome / Vivaldi) - kein loeschen moeglich.
.. _release:
Release
=======
Version 0.future
----------------
Changes
^^^^^^^
* Play formEditor.sql.
* Dropdownlist of container assignment:
* Display 'type' ('pill', 'fieldset', 'templategroup') instead of 'class' (always 'container').
* Display 'name' (internal name) instead of 'label' (shown on the website and might not so usefull as 'name' which is nowhere else used than in that dropdown.
* FormElement.placeholder colum width extended to 512:
ALTER TABLE `FormElement` CHANGE `placeholder` `placeholder` VARCHAR(512) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '';
Features
^^^^^^^^
Bug Fixes
^^^^^^^^^
Version 0.13
------------
Changes
^^^^^^^
* Play formEditor.sql.
* formEditor.sql: