diff --git a/Documentation-develop/CONFIG.md b/Documentation-develop/CONFIG.md
new file mode 100644
index 0000000000000000000000000000000000000000..27f440c5bbf8d493c87546244f564348c8701404
--- /dev/null
+++ b/Documentation-develop/CONFIG.md
@@ -0,0 +1,35 @@
+Config
+======
+
+During QFQ bootstrap three config files are read:
+
+* qfq.project.path.php (QFQ)
+* fileadmin/protected/qfqProject/qfq.json (QFQ)
+* typo3conf/LocalConfiguration.php (Typo3 > QFQ)
+
+Get config
+==========
+
+Stacktrace bis die LocalConfiguration.php gelesen wird:
+
+IMATHUZH\Qfq\Core\QuickFormQuery->__construct()
+IMATHUZH\Qfq\Core\Store\Store->__construct()
+IMATHUZH\Qfq\Core\Store\Store::getInstance()
+IMATHUZH\Qfq\Core\Store\Store::fillStoreSystem()
+IMATHUZH\Qfq\Core\Store\Config::getConfigArray()
+IMATHUZH\Qfq\Core\Store\Config::readConfig()
+
+To create a new QFQ Config option:
+
+ext_conf_template.txt:
+
+* create new entry
+* set a default value in ext_conf_template.txt
+
+config::setDefaults()
+
+* Define defaults if nothing is given
+
+DatabaseUpdate=>checkT3QfqConfig():
+
+* In case existing installations should get a new default during QFQ update. 
diff --git a/Documentation-develop/DRAGANDDROP.md b/Documentation-develop/DRAGANDDROP.md
index 700705263d0ed40ebb2373a4e0ec6607dbb24bd5..ee9a5f011985904f568aa351234cb1de329d39a0 100644
--- a/Documentation-develop/DRAGANDDROP.md
+++ b/Documentation-develop/DRAGANDDROP.md
@@ -1,6 +1,8 @@
-# Drag And Drop
+Drag And Drop
+=============
 
-## Sort
+Sort
+----
 Initialize a dnd container by adding the class "qfq-dnd"
 
 Set container object class to `class="qfq-dnd qfq-dnd-sort"`.
@@ -20,7 +22,8 @@ Request will be sent containing following GET variables:
 
 Example: http://something/bla?dragId=uno&dragPosition=1&setTo=before&hoverId=tre&hoverPosition=3
 
-## Drag'n'drop in forms
+Drag'n'drop in forms
+--------------------
 
 * For FormElement.typ=subrecord DND is automatically detected. 
 * The encoded SIP contains: dnd-subrecord-form-id, dnd-subrecord-form-table, dnd-subrecord-id, dndTable, oderColumn, 
diff --git a/Documentation-develop/FORM.md b/Documentation-develop/FORM.md
new file mode 100644
index 0000000000000000000000000000000000000000..046779a2bc42531b94cfc46e77052d866514a14d
--- /dev/null
+++ b/Documentation-develop/FORM.md
@@ -0,0 +1,3 @@
+Bootstrap QFQ Form
+==================
+
diff --git a/Documentation-develop/FORMEDITOR.md b/Documentation-develop/FORMEDITOR.md
index e2486452b117d4ba95d5cf755b0881f1bc1598cc..192c2b84cf5d1aba6e927f1bbb04b643e52515d5 100644
--- a/Documentation-develop/FORMEDITOR.md
+++ b/Documentation-develop/FORMEDITOR.md
@@ -1,8 +1,10 @@
-# Formeditor
+Formeditor
+==========
 
 The Formeditor is defined in Resources/Private/Form/form.json, formElement.json, formJson.json
 
-# Changes
+Changes
+=======
 
 Any modifications on the Formeditor have to be applied in the JSON files. It is fine to do all customizations and create
 the JSON file (T3 page 'form' > click on JSON for the wished form) and copy the while content to form.json.
diff --git a/Documentation-develop/HTML.md b/Documentation-develop/HTML.md
index 51294185d545a3de361bcd2513600b0c2f534a6e..cd4927d9543fd099917b0dd8c884485cf60efa38 100644
--- a/Documentation-develop/HTML.md
+++ b/Documentation-develop/HTML.md
@@ -1,52 +1,53 @@
-# HTML
+HTML
+====
 
 This document explains the HTML markup used by QFQ.
 
-## Hooks
+Hooks
+-----
 
-Hooks are used on the Client to gather information required for
-asynchronous requests and to add predefined event handlers to HTML Elements.
+Hooks are used on the Client to gather information required for asynchronous requests and to add predefined event
+handlers to HTML Elements.
 
+form.data-toggle="validator"
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-### form.data-toggle="validator"
+Adding the attribute `data-toggle="validator"` to a `<form>` element, enables the Bootstrap Validator on that HTML Form.
 
-Adding the attribute `data-toggle="validator"` to a `<form>` element,
-enables the Bootstrap Validator on that HTML Form.
+.data-sip ^^^^^^^^^
 
-
-### .data-sip
-
-Asynchronous requests require to pass a SID to the Server. Elements
-triggering an asynchronous request, may gather the SIP from the
+Asynchronous requests require to pass a SID to the Server. Elements triggering an asynchronous request, may gather the
+SIP from the
 `data-sip` attribute assigned to the HTML Form Element.
 
-
-### .class="record-delete"
+.class="record-delete"
+^^^^^^^^^^^^^^^^^^^^^^
 
 HTML Form Buttons having the class `record-delete` set, will get an
 `onclick` handler attached by `QfqNS.QfqRecordList`. Each `<button>`
 also requires an `data-sip` attribute.
 
+.data-load=""
+^^^^^^^^^^^^^
 
-### .data-load=""
-
-HTML Form Elements having the attribute `data-load`, will trigger a
-call to `api/load.php` upon change.
+HTML Form Elements having the attribute `data-load`, will trigger a call to `api/load.php` upon change.
 
 ### id="save-button"
 ### id="close-button"
 ### id="delete-button"
 ### id="form-new-button"
 
-## Typeahead
+Typeahead
+---------
 
 Typeahead capable text input elements will be defined by the following attributes:
- 
-### .class='qfq-typeahead'
 
-### .data-typeahead-sip
+.class='qfq-typeahead'
+^^^^^^^^^^^^^^^^^^^^^^
+
+.data-typeahead-sip ^^^^^^^^^^^^^^^^^^^
 
-The SIP will store: 
+The SIP will store:
 
 Use with SQL: `typeAheadSql`
 
@@ -56,43 +57,43 @@ Use with LDAP: `typeAheadLdap`
 * `typeAheadLdapSearch`
 * `typeAheadLdapValuePrintf`
 * `typeAheadLdapKeyPrintf`
- 
-### .data-typeahead-limit
+
+.data-typeahead-limit ^^^^^^^^^^^^^^^^^^^^^
 
 * Defines the limit of entries shown on the client. Default on client is 5. The server will always send a value. 
   The server default is 20.
 
-### .data-typeahead-minlength
+.data-typeahead-minlength ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 * Defines the string minlength, typed by the user, before the first lookup is started. Default is 2.
- 
-### data-typeahead-pedantic
+
+data-typeahead-pedantic ^^^^^^^^^^^^^^^^^^^^^^^
 
 * If present, only suggested values are allowed in the input element
 
+Tags Form Element
+-----------------
 
-## Tags Form Element
- 
-The tags form element depends on Typeahead by default. The following attributes define the tags form element, additional 
+The tags form element depends on Typeahead by default. The following attributes define the tags form element, additional
 to the attributes for Typeahead (see above).
 
 Mockups can be found in `mockup/typahead.php`
 
-### .data-typeahead-tags
+.data-typeahead-tags ^^^^^^^^^^^^^^^^^^^^
 
 * If present, the field becomes a tag field
 
-### .data-typeahead-tag-delimiters
+.data-typeahead-tag-delimiters ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 * List of ascii key codes of the keys which may be pressed to add a new tag when typing.
 
-### .value
+.value ^^^^^^
 
 * JSON encoded list of key value pairs of existing tags. e.g. 
   
   `[{value: "Alaska", key: "AK"}, {value: "Alabama", key: "AL"}]`
-  
-### POST data
+
+POST data ^^^^^^^^^
 
 * JSON encoded list of key value pairs of the selected tags. e.g.
 
diff --git a/Documentation-develop/LAYOUT.md b/Documentation-develop/LAYOUT.md
index d5479cab0f60b78dbb9fcf715bf8a5cce1cda7c0..71ab753b0b15c30222cc59b5a0347dbc181cb75d 100644
--- a/Documentation-develop/LAYOUT.md
+++ b/Documentation-develop/LAYOUT.md
@@ -1,4 +1,5 @@
-= Plain =
+Plain
+=====
 
 <form>
 
@@ -13,16 +14,19 @@
 </form>
 
 # Subrecord
+
 <table> 
     <tr><th> id </th> </tr>
     <tr><td> 1 </td></tr>
     <tr><td> 2 </td></tr>
 </table>
 
-= Table =
+Table
+=====
+
 <form>
     <table>
-    
+
     <tr>
         # Element 1
         <td>Title</td> <td><input type="input"></td> <td>note</td>
@@ -45,9 +49,12 @@
         </td>
     </tr>
     </table>
+
 </form>
 
-# Subrecord
+Subrecord
+=========
+
 <table> 
     <tr><th> id </th> </tr>
     <tr><td> 1 </td></tr>
@@ -56,7 +63,9 @@
 
 
 
-= Bootstrap =
+Bootstrap
+=========
+
 <div class="container-fluid">
     # Ttitle
     <div class="row hidden-xs">
diff --git a/Documentation-develop/REST.md b/Documentation-develop/REST.md
index 64fa9b10b850cba3c2f386f9dd2eb30ac036ea8b..d3864a4f23cfe425b5506423fd6c69a087b80a0a 100644
--- a/Documentation-develop/REST.md
+++ b/Documentation-develop/REST.md
@@ -1,4 +1,3 @@
-====
 REST
 ====
 
diff --git a/Documentation-develop/TABLESORTER.md b/Documentation-develop/TABLESORTER.md
index 7c4dd06c3a3a943aa2dd1a6416d46a5bed8a5fb1..85ddf46c081730db6321373e7ac2ba706db5aafc 100644
--- a/Documentation-develop/TABLESORTER.md
+++ b/Documentation-develop/TABLESORTER.md
@@ -1,4 +1,3 @@
-===========
 Tablesorter
 ===========
 
diff --git a/Documentation-develop/diagram/bootstrap.drawio b/Documentation-develop/diagram/bootstrap.drawio
index efebceceaa1c330ff51c2b98150eca2714d29fc2..4cfe061089e31f9ec79715a3e09504ee6357ba51 100644
--- a/Documentation-develop/diagram/bootstrap.drawio
+++ b/Documentation-develop/diagram/bootstrap.drawio
@@ -1 +1 @@
-<mxfile host="Electron" modified="2021-12-13T20:56:29.538Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/12.6.5 Chrome/80.0.3987.86 Electron/8.0.0 Safari/537.36" etag="XShEQdH8GtIbQazLTkWy" version="12.6.5" type="device"><diagram id="9q-i_z5IJf1DyX_JrZ7c" name="Page-1">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</diagram></mxfile>
\ No newline at end of file
+<mxfile host="Electron" modified="2022-12-11T13:03:38.492Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/12.6.5 Chrome/80.0.3987.86 Electron/8.0.0 Safari/537.36" etag="0kF6e3kMB-1GKugcZT_4" version="12.6.5" type="device" pages="3"><diagram id="9q-i_z5IJf1DyX_JrZ7c" name="Overview">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</diagram><diagram id="PixdtdoYfBAjwVCCUgM2" name="QFQ-Bootstrap">3ZZdb5swFEB/DY+V+C59bJOmrbRMo9lUdS+RMRdwYjA1JkB//ZxiQhiR2k5NJkWKkDnXvibn3jho1iSt7zjKkzkLgWqmHtaaNdVM88rw5HULmha4rtWCmJOwRUYPFuQVFNQVLUkIxWCiYIwKkg8hZlkGWAwY4pxVw2kRo8NdcxTDCCwwomP6REKRtNRz9J7fA4mTbmdDV5EUdZMVKBIUsmoPWbeaNeGMiXaU1hOgW3edF+RHgc1/Nxcvz+WqWno/biC4aJPNPrNk9xU4ZOKfUy+D7ys3jesNepha0/Uc9Oa+S71BtFS+FoJxObyWnxjEQ1YIlGFQBkTTaeWszELYptY166ZKiIBFjvA2Wsk+kiwRKZV3hhxGhNIJo4y/rbXACB24lLwQnK1hL3LlXlrIlRH1WMAF1H/V8R0Jxq4ysqOBpSB4I9epLLaniqm62eiKW/W9sWPJXl+4iiHVjvEuda9cDpT1T1TAHFUgg0qCKRIoQMXXmg8ReBE+ZN7FHgTRCc2b+gnNO8njryX+ubrOUhxtHuFu/S1XP5exeb8keD1jPPVLUNt8lf/Iw4AP+g88x3b0I/o37Q90vnMk/y9PulEFdBnPMXlFqV0luX7Avz/z23+CiMTn6t30/rf38ZkflISG244/V+n2ocPmpNLHxzyHnHFxrsadIx4v8rZ/63qL7b26Wrd/AA==</diagram><diagram id="BMNIQ1UUD8PApaxZDuDF" name="Form">nZNNU4MwEIZ/DUdnApHaXqWoF09Uy3jLkC2JEwgTgkB/vUEWKPbg1BO7z37Avrt4NCq6Z8Mq8ao5KC8gvPPo3gsC3yeBewykH8nDLhxBbiTHpAUk8gwICdJGcqhXiVZrZWW1hpkuS8jsijFjdLtOO2m1fmvFcrgCScbUNT1KbsVItyFZ+AvIXNh5YIwUbEpGUAvGdXuBaOzRyGhtR6voIlCDeJMuPN3ujuH+vmYHkpx6P/lU5G5s9nRLyTyCgdL+u/UbqM7E70FaHzZpcI7khyyxhHwx1aBeOKvtJwGNbkoOQxPi0cdWSAtJxbIh2rqTcUzYQjnPdya2A2Oh+6X/Hx/vz4q6UwRdgDW9q8Mu0w76tdsuG/UnJi62uUHG8IjyufEilDNQq8ldVvoTu/gxaPwN</diagram></mxfile>
\ No newline at end of file
diff --git a/Documentation/Form.rst b/Documentation/Form.rst
index a3171562e7a6094c70944dbf525bf2d63d879a4d..7e68e6be73ba1138e768177f3c1d3a6131924341 100644
--- a/Documentation/Form.rst
+++ b/Documentation/Form.rst
@@ -210,7 +210,7 @@ Form Settings
 +-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
 |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`.                                |
+|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`                                               |
 +-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
@@ -437,7 +437,7 @@ Form.parameter
 +-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
 | typeAheadLdap               |        | Enable LDAP as 'Typeahead' data source.                                                                  |
 +-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
-| typeAheadLdapSearch         | string | Regular LDAP search expression. E.g.:  `(|(cn=*?*)(mail=*?*))`                                           |
+| 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, roomnumber, telephonenumber`    |
 +-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
@@ -504,16 +504,18 @@ Form.parameter
 +-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
 | formSubmitLogMode           | string | Overwrite default from :ref:`configuration`                                                              |
 +-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
-| sessionTimeoutSeconds       | int    | Overwrite default from :ref:`configuration` . See :ref:`sessionTimeoutSeconds`.                          |
+| sessionTimeoutSeconds       | int    | Overwrite default from :ref:`configuration`. See :ref:`sessionTimeoutSeconds`.                           |
 +-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
-| maxFileSize                 | int    | Overwrite default from :ref:`configuration` .                                                            |
+| maxFileSize                 | int    | Overwrite default from :ref:`configuration`                                                              |
 +-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
-| requiredPosition            | int    | See :ref:`requiredPosition` .                                                                            |
+| 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.                 |
++-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
 
 * Example in field Form.parameter::
 
@@ -1381,12 +1383,25 @@ General input for any text.
   * *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.
+  * *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
@@ -1567,7 +1582,7 @@ Type: editor
 
 .. important::
 
-    *FormElement.encode*: To save HTML code, incl. HTML tags (bold, table, lists, ...), the **htmspecialchar**
+    *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.
 
 
@@ -1594,6 +1609,7 @@ Type: editor
     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
@@ -1623,6 +1639,12 @@ Type: editor
 
 * *FormElement.size* = <min_height>,<max_height>: 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
 ^^^^^^^^^^^^^^
diff --git a/Documentation/Installation.rst b/Documentation/Installation.rst
index a54e922ab270bbadb643591f0e564b901f6c9fc4..45ea43cc5dc3d07c9a6bcf04e4cb8d0cd96da77d 100644
--- a/Documentation/Installation.rst
+++ b/Documentation/Installation.rst
@@ -448,7 +448,9 @@ Example: *typo3conf/config.qfq.php*: ::
 qfq.json
 ^^^^^^^^
 
-* Additionally to the keywords bellow one can also override the configuration values defined in the Typo3 extension manager: :ref:`extension-manager-qfq-configuration`
+* Additionally to the keywords bellow one can also override the configuration values defined in the Typo3 extension
+  manager: :ref:`extension-manager-qfq-configuration`
+
   * e.g. if `qfq.json` contains `"flagProduction":"no"` then this value is taken instead of the one set in the extension manager.
 
 +-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------------------------------------+
@@ -496,14 +498,14 @@ Example: *fileadmin/protected/qfqProject/qfq.json*: ::
 config.qfq.php
 ^^^^^^^^^^^^^^
 
-**DEPRECATED** : use `qfq.json` as described above. :ref:`qfq.json`
+**DEPRECATED** : use :ref:`qfq.json` as described above.
 
 .. _extension-manager-qfq-configuration:
 
 Extension Manager: QFQ Configuration
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-* These configuration values can be overwritten by `qfq.json`. :ref:`qfq.json`
+* These configuration values can be overwritten by :ref:`qfq.json`
 
 +-----------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
 | Keyword                           | Default / Example                                     | Description                                                                |
@@ -669,6 +671,9 @@ Extension Manager: QFQ Configuration
 +-----------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
 | rememberLastPill                  | 0 (off), 1 (on)                                       | On form load, bring last used pill to front. Default is on.                |
 +-----------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
+| doNotLogColumn                    | password                                              | Do not log named FE-Elements during form save in table FormSubmitLog.      |
+|                                   |                                                       | Default: password                                                          |
++-----------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
 | **Form-Layout**                                                                                                                                                        |
 +-----------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
 | labelAlign                        | left                                                  | Label align (left/center/right)/ Default: left. Will be inherited to Form. |
diff --git a/Documentation/License.rst b/Documentation/License.rst
index 6a51955c8263c231099a2bc7d63042caa5afd274..06f42624a3f2f68e5a271825ec07a6e9b8f45962 100644
--- a/Documentation/License.rst
+++ b/Documentation/License.rst
@@ -59,3 +59,5 @@ Software distributed together with QFQ
 * Event Emitter - https://git.io/ee
 * FullCalendar - https://fullcalendar.io/
 * Datetimepicker - https://getdatepicker.com/
+* HTMLPurifier - https://github.com/ezyang/htmlpurifier
+* Font Password-Dots - https://fontstruct.com/fontstructions/show/1106896  The FontStruction “Password Dots” by “JimProuty” is licensed under a Creative Commons Attribution license (http://creativecommons.org/licenses/by/3.0/).
diff --git a/Documentation/Report.rst b/Documentation/Report.rst
index 8a5c7845a50962b52b7ac33cc553999c6b110ecb..c17abd4b76aefa61631e582148f70dd158ad016b 100644
--- a/Documentation/Report.rst
+++ b/Documentation/Report.rst
@@ -767,6 +767,9 @@ Column: _link
 +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
 |   |   |Tooltip       |o:<text>                           |o:More information here    |Tooltip text                                                                                                                            |
 +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
+|   |   | Order        |Y:<value>                          |Y:{{p.id:R}}               |Value wrapped in `<span style="display: none;">` (hidden) left to rendered link. Use: possibility to order/filter links/buttons in a    |
+|   |   |(invisible)   |                                   |                           |column of a html table via tablesorter.                                                                                                 |
++---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
 |   |   |Alttext       |a:<text>                           |a:Name of person           |a) Alttext for images, b) Message text for :ref:`download` popup window.                                                                |
 +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
 |   |   |Class         |c:[n|<text>]                       |c:text-muted               |CSS class for link. n:no class attribute, <text>: explicit named                                                                        |
@@ -786,6 +789,10 @@ Column: _link
 |   |   |Mode          |M:file|pdf|qfqpdf|zip              |M:file, M:pdf, M:qfqpdf,   |Mode. Used to specify type of download. One or more element sources needs to be configured. See :ref:`download`.                        |
 |   |   |              |                                   |M:zip                      |                                                                                                                                        |
 +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
+|   |   |Text before   |v:text before link                 |v:Some Text                |Useful to show text before a link, delivered through `... AS _link`. See :ref:`linkTextBeforeAfter`                                     |
++---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
+|   |   |Text after    |V:text after link                  |v:Some Text                |Useful to show text after a link, delivered through `... AS _link`. See :ref:`linkTextBeforeAfter`                                      |
++---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
 |   |   |File          |F:<filename>                       |F:fileadmin/file.pdf       |Element source for download mode file|pdf|zip. See :ref:`download`.                                                                     |
 +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
 |   |   |Delete record | x[:a|r|c]                         |x, x:r, x:c                |a: ajax (only QFQ internal used), r: report (default), c: close (current page, open last page)                                          |
@@ -886,6 +893,8 @@ Link Examples
 | SELECT  "y|s:1|F:dir/data.R|t:Data|o:Clipboard|b" AS _link            | <button class="btn btn-info" onClick="new QfqNS.Clipboard({uri: 'typo3conf/.../download.php?s=badcaffee1234'});"                        |
 |                                                                       | title='Copy to clipboard'>Data</button>                                                                                                 |
 +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+
+| SELECT  "p:/form_person|v:Hello |V: world.|t:Link" AS _link           | 'Hello <a href="/form_person">Link</a> world.'                                                                                          |
++-----------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+
 
 .. _question:
 
@@ -935,6 +944,32 @@ Examples:
 | SELECT "p:/form_person|q:Edit Person:::10:0" AS _link      | The Alert will be shown 10 seconds and is not modal.                      |
 +------------------------------------------------------------+---------------------------------------------------------------------------+
 
+
+.. _linkTextBeforeAfter:
+
+Text before / after link
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+* Renders text before and/or after a link.
+* Example: `SELECT 'p:{{pageAlias:T}}|t:Reload|v:Some text before |v: some text after' AS _link`
+* A typical usecase is to get several `AS _link` columns in one HTML table cell, by still using `fbeg,fend`::
+
+  10 {
+    sql = SELECT p.id
+                 , 'p:{{pageAlias:T}}|t:Reload 1|v:<td>Some text before |V: - ' AS '_link|_noWrap'
+                 , 'p:{{pageAlias:T}}|t:Reload 2|V:</td>' AS '_link|_noWrap'
+                 , p.name
+             FROM Person AS p
+    head = <table>
+    tail = </table>
+    rbeg = <tr>
+    rend = </tr>
+    fbeg = <td>
+    fend = </td>
+  }
+
+
+
 .. _column_pageX:
 
 Columns: _page[X]
diff --git a/Documentation/Tutorial.rst b/Documentation/Tutorial.rst
index 97a9f07437ac063e40b64d3620ad7363c3f2d3a2..d473bcbf2ced37733cc885b9129375a5876423f9 100644
--- a/Documentation/Tutorial.rst
+++ b/Documentation/Tutorial.rst
@@ -1140,28 +1140,3 @@ we automatically add the reviewers. So that when somebody applies for a job X, t
 job X will automatically be assigned to that specific application.
 So let's do that. So go into the formEditor and edit the form "JobOffers". You have to add a new formElement.
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Gruntfile.js b/Gruntfile.js
index 90a1205800b54321ca88a8301e34763b469c9cdc..84fb901babd4cc71c89a55877a0a9daaf1e224af 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -563,6 +563,19 @@ module.exports = function (grunt) {
                     }
                 ]
             },
+            fontPassword: {
+                files: [
+                    {
+                        cwd: 'resources/custom_fonts/',
+                        src: [
+                            'password-dots.ttf'
+                        ],
+                        expand: true,
+                        dest: 'extension/Resources/Public/fonts/',
+                        flatten: true
+                    }
+                ]
+            },
         },
         uglify: {
             options: {
diff --git a/extension/Classes/Core/AbstractBuildForm.php b/extension/Classes/Core/AbstractBuildForm.php
index c33cdc12f27284c0fd002c97d3f210de386f71c7..f04a3768881c9a15394940d7be57888b85d1d732 100644
--- a/extension/Classes/Core/AbstractBuildForm.php
+++ b/extension/Classes/Core/AbstractBuildForm.php
@@ -820,7 +820,7 @@ abstract class AbstractBuildForm {
             }
 
             $value = $formElement[FE_VALUE];
-
+            $prefetchTypeAheadArray = array();
             if ($value === '') {
                 // #2064 / Only take the default, if the FE is a real tablecolumn.
                 // #3426 / Dynamic Update: Inputs loose the new content and shows the old value.
@@ -837,12 +837,21 @@ abstract class AbstractBuildForm {
 
                 // For typeAhead fields: perform prefetch to display description instead of key (#5444)
                 if ($mode == FORM_SAVE && isset($fe[FE_TYPEAHEAD_SQL_PREFETCH])) {
+                    // Get new record store if value is empty. In case if a previous formElement has modified data from actual used record and a new value exists.
+                    $tableName = $this->dbArray[$this->dbIndexData]->getTableNameById($fe[FE_FORM_ID])[0]['tableName'];
+                    if ($value === '' || $value === 0) {
+                        $this->store::fillStoreWithRecord($tableName, $recordId, $this->dbArray[$this->dbIndexData]);
+                        $value = $this->store->getVar($name, $storeUse, $sanitizeClass, $foundInStore);
+                    }
+
                     $config = [FE_TYPEAHEAD_SQL_PREFETCH => $fe[FE_TYPEAHEAD_SQL_PREFETCH]];
                     $value = TypeAhead::typeAheadSqlPrefetch($config, $value, $this->dbArray[$this->dbIndexData]);
+                    $prefetchTypeAheadArray = $value;
+                    $value = OnArray::getFirstValueFromArray($value);
                 }
             }
 
-            // Typehead might deliver an array, which is unwanted: fix this
+            // Typehead might deliver an array, which is unwanted. Except typeahead prefetch, which needs key/value pair to show refreshed data.
             if (is_array($value) && (isset($value[0][API_TYPEAHEAD_VALUE]) || empty($value))) {
                 $value = OnArray::getFirstValueFromArray($value);
             }
@@ -871,6 +880,12 @@ abstract class AbstractBuildForm {
             $jsonElement = array();
             $elementExtra = '';
 
+            // Backup array from typeAheadPrefetch if exists before json is built.
+            if (!empty($prefetchTypeAheadArray)) {
+                OnArray::setFirstValueInArray($prefetchTypeAheadArray, 'value', $value);
+                $value = $prefetchTypeAheadArray;
+            }
+
             switch ($formElement[FE_TYPE]) {
                 case FE_TYPE_CHECKBOX:
                     $elementHtml = $this->buildCheckbox($formElement, $htmlFormElementName, $value, $jsonElement, $mode);
@@ -1463,7 +1478,6 @@ abstract class AbstractBuildForm {
             $class .= ' ' . CLASS_CHARACTER_COUNT;
             $attribute .= Support::doAttribute(DATA_CHARACTER_COUNT_ID, $formElement[FE_HTML_ID] . HTML_ID_EXTENSION_CHARACTER_COUNT);
             $attributeCC = Support::doAttribute('id', $formElement[FE_HTML_ID] . HTML_ID_EXTENSION_CHARACTER_COUNT);
-
             $classCC = ($formElement[FE_CHARACTER_COUNT_WRAP] == '') ? Support::doAttribute('class', 'qfq-cc-style') : '';
             $elementCharacterCount = "<span $attributeCC $classCC></span>";
 
@@ -1480,7 +1494,7 @@ abstract class AbstractBuildForm {
         $attribute .= Support::doAttribute(ATTRIBUTE_DATA_REFERENCE, $formElement[FE_DATA_REFERENCE]);
 
         if (isset($formElement[FE_RETYPE_SOURCE_NAME])) {
-            $htmlFormElementNamePrimary = str_replace(RETYPE_FE_NAME_EXTENSION, '', $htmlFormElementName);
+            $htmlFormElementNamePrimary = str_replace(FE_RETYPE_NAME_EXTENSION, '', $htmlFormElementName);
             $attribute .= Support::doAttribute('data-match', '[name=' . str_replace(':', '\\:', $htmlFormElementNamePrimary) . ']');
         }
 
@@ -1540,15 +1554,19 @@ abstract class AbstractBuildForm {
                 $class .= ' qfq-password';
             }
             $attribute .= HelperFormElement::getAttributeList($formElement, [FE_TYPE, 'size']);
-            $attribute .= Support::doAttribute('value', htmlentities($value), false);
+
+            // Typeahead prefetch needs key as attribute. Key/value pair is needed later on client side.
+            if (isset($formElement[FE_TYPEAHEAD_SQL_PREFETCH]) && is_array($value)) {
+                $attributeValue = OnArray::getFirstValueFromArray($value, true);
+            } else {
+                $attributeValue = $value;
+            }
+
+            $attribute .= Support::doAttribute('value', htmlentities($attributeValue), false);
+
 //            $attribute .= Support::doAttribute('value', htmlentities($value, ENT_QUOTES, 'UTF-8'), false);
         }
 
-        // Set for password to give choice of generated password for user and not autofill password field. Deprecated, we dont use type password anymore.
-        //       if($formElement[FE_TYPE] === 'password') {
-        //           $attribute .= Support::doAttribute('autocomplete', 'new-password');
-        //       }
-
         $attribute .= HelperFormElement::getAttributeList($formElement, [FE_INPUT_AUTOCOMPLETE, 'autofocus', 'placeholder']);
 
         $formElement[FE_CHECK_PATTERN] = Sanitize::getInputCheckPattern($formElement[FE_CHECK_TYPE], $formElement[FE_CHECK_PATTERN]
@@ -1598,11 +1616,6 @@ abstract class AbstractBuildForm {
             $input .= $formElement[FE_INPUT_EXTRA_BUTTON_INFO];
         }
 
-        //Generate an empty input type text to ignore autocomplete in other elements. deprecated because not using type password anymore.
-//        if($formElement[FE_TYPE] === 'password'){
-//            $input = '<input type="text" style="display:none;">'.$input;
-//        }
-
         return $input;
     }
 
@@ -3412,7 +3425,7 @@ abstract class AbstractBuildForm {
 
         // plugins
         if (!isset($formElement[FE_EDITOR_PREFIX . 'plugins'])) {
-            $formElement[FE_EDITOR_PREFIX . 'plugins'] = 'code link lists searchreplace table textcolor textpattern visualchars';
+            $formElement[FE_EDITOR_PREFIX . 'plugins'] = 'code link lists searchreplace table textcolor textpattern visualchars image,paste';
         }
 
         // toolbar: https://www.tinymce.com/docs/advanced/editor-control-identifiers/#toolbarcontrols
@@ -3432,6 +3445,122 @@ abstract class AbstractBuildForm {
             $formElement[FE_EDITOR_PREFIX . 'auto_focus'] = $htmlFormElementName;
         }
 
+        // valid elements
+        // Set defaults for tinyMce
+        $imgToken = 'img[longdesc|usemap|src|border|alt=|title|hspace|vspace|width|height|align]';
+        $textDecoration = 'span[style]';
+        $table = 'table[style|align|border],td[style],th[style],tr[style],tbody[style],thead[style]';
+        $url = 'a[href|target|title]';
+        $paragraphToken = 'p[align]';
+        $strong = 'strong';
+
+        $htmlAllowArray = explode(',', $formElement[FE_HTML_ALLOW]);
+        $formatDropdownElements = array();
+        $customEditorToolbar = 'code |';
+
+        // flags to prevent multiple same values
+        $listFlag = false;
+        $decorationFlag = false;
+        $formatDropdownFlag = false;
+        $customEditorToolbarFlags = array();
+
+        foreach ($htmlAllowArray as $htmlToken => $value) {
+            switch ($value) {
+                case 'a':
+                    $htmlAllowArray[$htmlToken] = $url;
+                    $this->setTinymceEditorToolbarAttributes($customEditorToolbarFlags, $customEditorToolbar, 'link');
+                    break;
+                case 'table':
+                    $htmlAllowArray[$htmlToken] = $table;
+                    $this->setTinymceEditorToolbarAttributes($customEditorToolbarFlags, $customEditorToolbar, 'table');
+                    break;
+                case 'textDecoration':
+                case 'u':
+                case 'ins':
+                case 's':
+                case 'del':
+                    if (!$decorationFlag) {
+                        $htmlAllowArray[$htmlToken] = $textDecoration;
+                        $this->setTinymceEditorToolbarAttributes($customEditorToolbarFlags, $customEditorToolbar, 'textDecoration', 'underline strikethrough');
+                        $decorationFlag = true;
+                    }
+                    break;
+                case 'img':
+                    $htmlAllowArray[$htmlToken] = $imgToken;
+                    $this->setTinymceEditorToolbarAttributes($customEditorToolbarFlags, $customEditorToolbar, 'image');
+                    break;
+                case 'ul':
+                    if (!$listFlag) {
+                        $htmlAllowArray[$htmlToken] = 'ul,li';
+                        $listFlag = true;
+                    } else {
+                        $htmlAllowArray[$htmlToken] = 'ul';
+                    }
+                    $this->setTinymceEditorToolbarAttributes($customEditorToolbarFlags, $customEditorToolbar, 'bullist');
+                    break;
+                case 'ol':
+                    if (!$listFlag) {
+                        $htmlAllowArray[$htmlToken] = 'ol,li';
+                        $listFlag = true;
+                    } else {
+                        $htmlAllowArray[$htmlToken] = 'ol';
+                    }
+                    $this->setTinymceEditorToolbarAttributes($customEditorToolbarFlags, $customEditorToolbar, 'numlist');
+                    break;
+                case 'b':
+                case 'strong':
+                    $htmlAllowArray[$htmlToken] = $strong;
+                    $this->setTinymceEditorToolbarAttributes($customEditorToolbarFlags, $customEditorToolbar, 'bold');
+                    break;
+                case 'i':
+                case 'em':
+                    $this->setTinymceEditorToolbarAttributes($customEditorToolbarFlags, $customEditorToolbar, 'italic');
+                    break;
+                case 'sub':
+                    $this->setTinymceEditorToolbarAttributes($customEditorToolbarFlags, $customEditorToolbar, 'subscript');
+                    break;
+                case 'sup':
+                    $this->setTinymceEditorToolbarAttributes($customEditorToolbarFlags, $customEditorToolbar, 'supscript');
+                    break;
+                case 'h1':
+                case 'h2':
+                case 'h3':
+                case 'h4':
+                case 'h5':
+                case 'h6':
+                case 'p':
+                case 'div':
+                case 'pre':
+                    if ($value === 'p') {
+                        $htmlAllowArray[$htmlToken] = $paragraphToken;
+                    }
+                    $this->setTinymceBlockFormats($value, $formatDropdownElements);
+                    if (!$formatDropdownFlag) {
+                        $formatDropdownFlag = true;
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        // set format dropdown at the end of the toolbar if its used
+        if ($formatDropdownFlag) {
+            $this->setTinymceEditorToolbarAttributes($customEditorToolbarFlags, $customEditorToolbar, 'formatselect');
+        }
+
+        // If htmlAllow is used: toolbar will be overwritten with the customized one
+        if (!empty($customEditorToolbarFlags)) {
+            $formElement[FE_EDITOR_PREFIX . 'toolbar'] = $customEditorToolbar;
+        }
+
+        // Set allowed values and corrected dropdown from formats
+        if (isset($formElement[FE_HTML_ALLOW])) {
+            $formElement[FE_EDITOR_PREFIX . 'valid_elements'] = implode(',', $htmlAllowArray);
+            $formElement[FE_TINYMCE_DROPDOWN_FORMATS] = implode(';', $formatDropdownElements);
+            $formElement[FE_EDITOR_PREFIX . 'block_formats'] = $formElement[FE_TINYMCE_DROPDOWN_FORMATS];
+        }
+
         // Check for min_height, max_height
         $minMax = explode(',', $formElement[FE_SIZE], 2);
         if (isset($minMax[0]) && ctype_digit($minMax[0]) && !isset($formElement[FE_EDITOR_PREFIX . 'min_height'])) {
@@ -3450,6 +3579,67 @@ abstract class AbstractBuildForm {
         return $formElement;
     }
 
+    /**
+     * Tinymce toolbar attributes needs to be defined separately
+     *
+     * @param $toolbarFlags
+     * @param $attributeList
+     * @param $attributeName
+     * @param $specialAttributeName
+     * @return void
+     */
+    private function setTinymceEditorToolbarAttributes(&$toolbarFlags, &$attributeList, $attributeName, $specialAttributeName = '') {
+        if (!empty($toolbarFlags[$attributeName]) && !$toolbarFlags[$attributeName]) {
+            if ($specialAttributeName === '') {
+                $attributeList .= ' ' . $attributeName;
+            } else {
+                $attributeList .= ' ' . $specialAttributeName;
+            }
+            $toolbarFlags[$attributeName] = true;
+        }
+    }
+
+    /**
+     * Tinymce has individual strings for some html block configurations. They need to be set here.
+     *
+     * @param $format
+     * @param $formatDropdownElements
+     * @return void
+     */
+    private function setTinymceBlockFormats($format, &$formatDropdownElements) {
+
+        switch ($format) {
+            case 'h1':
+                $formatDropdownElements[] = 'Heading 1=h1';
+                break;
+            case 'h2':
+                $formatDropdownElements[] = 'Heading 2=h2';
+                break;
+            case 'h3':
+                $formatDropdownElements[] = 'Heading 3=h3';
+                break;
+            case 'h4':
+                $formatDropdownElements[] = 'Heading 4=h4';
+                break;
+            case 'h5':
+                $formatDropdownElements[] = 'Heading 5=h5';
+                break;
+            case 'h6':
+                $formatDropdownElements[] = 'Heading 6=h6';
+                break;
+            case 'p':
+                $formatDropdownElements[] = 'Paragraph=p';
+                break;
+            case 'div':
+                $formatDropdownElements[] = 'Div-Container=div';
+                break;
+            case 'pre':
+                $formatDropdownElements[] = 'Preformat=pre';
+                break;
+            default:
+                break;
+        }
+    }
 
     /**
      * Searches for '$prefix*' elements in $formElement. Collect all found elements, strip $prefix (=$keyName) and
diff --git a/extension/Classes/Core/Constants.php b/extension/Classes/Core/Constants.php
index 99157da3e98b90d377b30bf83d53208d1eef15af..5fc81d7fa6cc4b5e37d6bf7f8fb83af584c6769f 100644
--- a/extension/Classes/Core/Constants.php
+++ b/extension/Classes/Core/Constants.php
@@ -710,6 +710,7 @@ const SYSTEM_CMD_IMG2PDF = 'cmdImg2pdf';
 const SYSTEM_CMD_HEIF_CONVERT = 'cmdHeifConvert';
 const SYSTEM_CMD_PDF2PS = 'cmdPdf2ps';
 const SYSTEM_CMD_PS2PDF = 'cmdPs2pdf';
+const SYSTEM_DO_NOT_LOG_COLUMN_DEFAULT = 'password';
 // Thumbnail
 const SYSTEM_THUMBNAIL_DIR_SECURE_REL_TO_APP = 'thumbnailDirSecure';
 const SYSTEM_THUMBNAIL_DIR_PUBLIC_REL_TO_APP = 'thumbnailDirPublic';
@@ -743,6 +744,7 @@ const DOWNLOAD_POPUP_REPLACE_TITLE = '#downloadPopupReplaceTitle#';
 const SYSTEM_DRAG_AND_DROP_JS = 'hasDragAndDropJS';
 const SYSTEM_SQL_DIRECT_DOWNLOAD = 'sqlDirect'; // becomes sqlDirectdownload.php, sqlDirectdl.php, sqlDirectdl2.php, sqlDirectdl3.php
 const SYSTEM_EDIT_INLINE_REPORTS = 'editInlineReports';
+const SYSTEM_UNIT_TEST_FORM_CONTENT = 'unitTestFormContent';
 
 const SYSTEM_PARAMETER_LANGUAGE_FIELD_NAME = 'parameterLanguageFieldName';
 const CSS_REQUIRED_RIGHT = 'required-right';
@@ -754,6 +756,7 @@ const CSS_REQUIRED_LEFT = 'required-left';
 //const SYSTEM_FORM_ELEMENT_FIELD = 'formElementField'; // Type: SANITIZE_ALNUMX / String. Fieldname of processed Formelement. Useful for error reporting.
 
 const SYSTEM_QFQ_PROJECT_PATH = 'qfqProjectPath';
+const SYSTEM_DO_NOT_LOG_COLUMN = 'doNotLogColumn';
 
 const MODE_HTML = 'html';
 const MODE_JSON = 'json';
@@ -1166,6 +1169,7 @@ const CLIENT_REST_ID = '_id';
 const CLIENT_REST_FORM = '_form';
 
 const F_REMEMBER_LAST_PILL = SYSTEM_REMEMBER_LAST_PILL;
+const F_DO_NOT_LOG_COLUMN = SYSTEM_DO_NOT_LOG_COLUMN;
 
 // Form Columns: Only in form file
 const F_FILE_FORM_ELEMENT = 'FormElement_ff'; // Key for FormElements array saved in Form File
@@ -1346,6 +1350,7 @@ const FE_RETYPE = 'retype'; // value: <none>|0|1  , <none>==1, this element beco
 const FE_RETYPE_LABEL = 'retypeLabel'; // value: label text for retype FormElement
 const FE_RETYPE_NOTE = 'retypeNote'; // value: note text for retype FormElement
 const FE_RETYPE_SOURCE_NAME = '_retypeSourceName'; // QFQ internal reference to name of source FormElement.
+const FE_RETYPE_NAME_EXTENSION = 'RETYPE';
 const FE_WRAP_ROW = 'wrapRow';
 const FE_WRAP_LABEL = 'wrapLabel';
 const FE_WRAP_INPUT = 'wrapInput';
@@ -1427,8 +1432,8 @@ const FE_FLAG_ROW_CLOSE_TAG = '_flagRowCloseTag'; // will be automatically compu
 
 const FE_MIN = 'min';
 const FE_MAX = 'max';
-
-const RETYPE_FE_NAME_EXTENSION = 'RETYPE';
+const FE_HTML_ALLOW = 'htmlAllow';
+const FE_TINYMCE_DROPDOWN_FORMATS = 'tinymceDropdownFormats';
 
 // Save form as Json
 const FE_SAVE_FORM_JSON = 'saveFormJson';
@@ -1869,6 +1874,8 @@ const NAME_SIP = 'sip';
 const NAME_URL_PARAM = 'param';
 const NAME_RIGHT = 'picturePositionRight';
 const NAME_ACTION_DELETE = 'actionDelete';
+const NAME_ORDER_TEXT ='orderText';
+const NAME_ORDER_TEXT_WRAP = 'orderTextWrap';
 const NAME_EXTRA_CONTENT_WRAP = 'extraContentWrap';
 const NAME_FILE = 'file';
 const NAME_THUMBNAIL = 'thumbnail';
@@ -1878,7 +1885,8 @@ const NAME_MONITOR = 'monitor';
 const NAME_ATTRIBUTE = 'attribute';
 const NAME_EMAIL = 'email';
 const NAME_REALNAME = 'realname';
-
+const NAME_BEFORE_LINK = 'beforeLink';
+const NAME_AFTER_LINK = 'afterLink';
 const FINAL_HREF = 'finalHref';
 const FINAL_ANCHOR = 'finalAnchor';
 const FINAL_CONTENT = 'finalContent';
@@ -1952,11 +1960,15 @@ const TOKEN_FILE = 'F';
 const TOKEN_FILE_DEPRECATED = 'f';  // since 5.12.17
 const TOKEN_DOWNLOAD_MODE = 'M';
 const TOKEN_ATTRIBUTE = 'A';
+const TOKEN_BEFORE_LINK = 'v';
+const TOKEN_AFTER_LINK = 'V';
+
 const TOKEN_FUNCTION_CALL = 'call';
 const TOKEN_ARGUMENT = 'arg';
 const TOKEN_FORM_ID = 'fid';
 const TOKEN_ENCODING_BASE_64 = 'b64';
 const TOKEN_REDUCE_KEYS = 'reduce';
+const TOKEN_ORDER_TEXT = 'Y';
 
 const TOKEN_THUMBNAIL = 'T';
 const TOKEN_THUMBNAIL_DIMENSION = 'W';
diff --git a/extension/Classes/Core/Database/DatabaseUpdate.php b/extension/Classes/Core/Database/DatabaseUpdate.php
index 91ea4867de3a9fde5da385ae2f579b492e580696..a47c401a1e395710e0d8f72abe386280334d02b7 100644
--- a/extension/Classes/Core/Database/DatabaseUpdate.php
+++ b/extension/Classes/Core/Database/DatabaseUpdate.php
@@ -136,13 +136,13 @@ class DatabaseUpdate {
      * @throws \UserFormException
      * @throws \UserReportException
      */
-    public function checkNupdate($dbUpdate) {
+    public function checkNupdate($dbUpdate, $t3ConfigQfq = array()) {
 
         $new = $this->getExtensionVersion();
         $versionInfo = $this->getDatabaseVersion();
         $old = $versionInfo[QFQ_VERSION_KEY] ?? false;
 
-        $this->checkT3QfqConfig($old, $new);
+        $this->checkT3QfqConfig($old, $new, $t3ConfigQfq);
 
         if ($dbUpdate === SYSTEM_DB_UPDATE_NEVER) {
             return;
@@ -222,14 +222,24 @@ class DatabaseUpdate {
      * @param $old
      * @param $new
      */
-    private function checkT3QfqConfig($old, $new) {
-
+    private function checkT3QfqConfig($old, $new, $t3ConfigQfq) {
+        $dirty = false;
         if ($new == $old || $old === false) {
             return;
         }
 
         if (version_compare($old, '20.2.0') == -1) {
-            T3Handler::updateT3QfqConfig(SYSTEM_RENDER_BOTH, SYSTEM_RENDER); //Legacy behaviour.
+            $t3ConfigQfq[SYSTEM_RENDER_BOTH] = SYSTEM_RENDER;
+            $dirty = true;
+        }
+
+        if (version_compare($old, '22.12.0') == -1) {
+            $t3ConfigQfq[SYSTEM_DO_NOT_LOG_COLUMN] = SYSTEM_DO_NOT_LOG_COLUMN_DEFAULT;
+            $dirty = true;
+        }
+
+        if ($dirty) {
+            T3Handler::updateT3QfqConfig($t3ConfigQfq); //Legacy behaviour.
         }
     }
 
@@ -277,7 +287,7 @@ class DatabaseUpdate {
         #####################################################################################
         ##### ONLY RUN THIS FUNCTION IF TYPO3 VERSION 9 OR HIGHER AND NOT API ENDPOINT #####
 
-        if ( ! (T3Handler::isTypo3Loaded() && T3Handler::useSlugsInsteadOfPageAlias()) ) {
+        if (!(T3Handler::isTypo3Loaded() && T3Handler::useSlugsInsteadOfPageAlias())) {
             return null;
         }
 
@@ -351,7 +361,9 @@ class DatabaseUpdate {
         $dbT3 = $this->store->getVar(SYSTEM_DB_NAME_T3, STORE_SYSTEM);
         $aliasColumn = 'zzz_deleted_alias';
         $tableDefinition = $this->db->sql("SHOW FIELDS FROM `$dbT3`.`pages`", ROW_EXPECT_GE_1);
-        $aliasColumnExists = 0 < count(array_filter($tableDefinition, function ($c) use ($aliasColumn) {return $c['Field'] === $aliasColumn;}));
+        $aliasColumnExists = 0 < count(array_filter($tableDefinition, function ($c) use ($aliasColumn) {
+                return $c['Field'] === $aliasColumn;
+            }));
 
         // Get id, slug and alias of all Typo3 pages
         $pages = $this->db->sql("SELECT `uid`, `slug`" . ($aliasColumnExists ? ", `$aliasColumn`" : '') . " FROM `" . $dbT3 . "`.`pages` WHERE `deleted`=0;");
@@ -369,23 +381,32 @@ class DatabaseUpdate {
             if (is_numeric($aliasOrId)) {
 
                 // if its an id (number), get the page with that id
-                $uidMatches = array_filter($pages, function ($p) use ($aliasOrId) {return $p['uid'] === intval($aliasOrId);});
+                $uidMatches = array_filter($pages, function ($p) use ($aliasOrId) {
+                    return $p['uid'] === intval($aliasOrId);
+                });
                 $page = reset($uidMatches);
                 return $page !== false ? $page['slug'] : $noSuggestionSymbol;
             } else {
 
                 // search alias in page slugs. ('_' was automatically replaced by '-' Typo3 v9 Migration)
                 $slugMatches = array_filter($pages, function ($p) use ($aliasOrId) {
-                    return ($p['slug'] === '/' . str_replace('_', '-', $aliasOrId)) || ($p['slug'] === '/' . $aliasOrId);});
-                $slugs = array_map(function ($p) {return $p['slug'];}, $slugMatches);
+                    return ($p['slug'] === '/' . str_replace('_', '-', $aliasOrId)) || ($p['slug'] === '/' . $aliasOrId);
+                });
+                $slugs = array_map(function ($p) {
+                    return $p['slug'];
+                }, $slugMatches);
                 if (1 === count(array_unique($slugs))) {
                     return reset($slugs);
                 }
 
                 // search alias in old alias column ('zzz_deleted_alias') if it exists
                 if ($aliasColumnExists) {
-                    $aliasMatches = array_filter($pages, function ($p) use ($aliasColumn, $aliasOrId) {return $p[$aliasColumn] === $aliasOrId;});
-                    $slugs = array_map(function ($p) {return $p['slug'];}, $aliasMatches);
+                    $aliasMatches = array_filter($pages, function ($p) use ($aliasColumn, $aliasOrId) {
+                        return $p[$aliasColumn] === $aliasOrId;
+                    });
+                    $slugs = array_map(function ($p) {
+                        return $p['slug'];
+                    }, $aliasMatches);
                     if (1 === count(array_unique($slugs))) {
                         return reset($slugs);
                     }
@@ -404,7 +425,7 @@ class DatabaseUpdate {
             '/([\'"\|]p:)((?:id=)?{{(?:pageAlias|pageId))(:T[0E]*}}[&\|"\'])/s',
             '/(href=[\'"])((?:index\.php)?\?id=[a-zA-Z0-9_\-]*)([&"\'])/s',
             '/(href=[\'"])((?:index\.php)?\?id={{(?:pageAlias|pageId))(:T[0E]*}}[&"\'])/s'
-            ];
+        ];
 
         // Patterns for which we can't make a suggestion (applied after the the patterns with suggestions were replaced)
         $patternsNeedManualFix = [
@@ -477,14 +498,15 @@ class DatabaseUpdate {
 
         // get reports from tt_content.bodytext
         $reports = $this->db->sql("SELECT tt.`uid`, tt.`header`, tt.`bodytext`, tt.`hidden`, p.`hidden` AS pageHidden FROM `" . $dbT3 . "`.`tt_content` AS tt, `" . $dbT3 . "`.`pages` AS p WHERE tt.`CType`='qfq_qfq' AND tt.`deleted`=0 AND p.`deleted`=0 AND p.uid=tt.pid");
-        $qfqCodeBlobs = array_map(function($r) use ($dbT3, $KEY_SQL_UPDATE, $KEY_CONTENT, $KEY_TITLE) {
+        $qfqCodeBlobs = array_map(function ($r) use ($dbT3, $KEY_SQL_UPDATE, $KEY_CONTENT, $KEY_TITLE) {
             $maybeHidden = (intval($r['hidden']) !== 0) || (intval($r['pageHidden']) !== 0);
             return [
                 $KEY_TITLE => 'QFQ Report with uid=' . $r['uid'] . ' and header: ' . $r['header']
                     . ($maybeHidden ? '<br><small>Note: Content element is probably hidden / not in use.</small>' : ''),
                 $KEY_CONTENT => $r['bodytext'],
                 $KEY_SQL_UPDATE => "UPDATE `$dbT3`.`tt_content` SET `bodytext` = ? WHERE uid=" . $r['uid'] . ";"
-        ];}, $reports);
+            ];
+        }, $reports);
 
         // get Forms
         $formColumnsToCheck = [
@@ -559,7 +581,7 @@ class DatabaseUpdate {
 
             // make sure the control characters are not used in the QFQ code
             if (OnString::strContains($qfqCode[$KEY_CONTENT], $noSuggestionSymbol) || OnString::strContains($qfqCode[$KEY_CONTENT], $replacedSymbol)) {
-                Thrower::dbException('Page Slug Migration.', "Unicode character $noSuggestionSymbol or $replacedSymbol found in" . $qfqCode[$KEY_TITLE] .  ". The page slug migration script can't continue since it uses those characters as control characters. Please temporarily replace those characters.");
+                Thrower::dbException('Page Slug Migration.', "Unicode character $noSuggestionSymbol or $replacedSymbol found in" . $qfqCode[$KEY_TITLE] . ". The page slug migration script can't continue since it uses those characters as control characters. Please temporarily replace those characters.");
             }
 
             // add suggestion marks to all occurrences of regex patterns in $patternsWithSuggestions
@@ -591,7 +613,9 @@ class DatabaseUpdate {
 
                     // protect matched string from being matched again by interlacing it with $preventMatchSymbol ( "string" -> "XsXtXrXiXnXg" )
                     // symbol will be removed before output
-                    $fullMatchProtected = join(array_map(function ($c) use ($preventMatchSymbol) {return $preventMatchSymbol . $c;}, str_split($fullMatch)));
+                    $fullMatchProtected = join(array_map(function ($c) use ($preventMatchSymbol) {
+                        return $preventMatchSymbol . $c;
+                    }, str_split($fullMatch)));
 
                     $replacement = $placeholderBegin . $fullMatchProtected . $placeholderArrow . $prefix_suggestion . $match_suggestion . $postfix_suggestion . $placeholderEnd;
                     $allMatches[] = $fullMatch . ' âž¡ ' . $prefix_suggestion . $match_suggestion . $postfix_suggestion;
@@ -602,7 +626,7 @@ class DatabaseUpdate {
 
             // find those patterns where we can't give a suggestion
             if (!$doReplace) {
-                $replaced_with_placeholder = preg_replace($patternsNeedManualFix, $placeholderBegin . '${1}' . '${2}'. '${3}' . $placeholderArrow . $noSuggestionSymbol . $placeholderEnd, $replaced_with_placeholder);
+                $replaced_with_placeholder = preg_replace($patternsNeedManualFix, $placeholderBegin . '${1}' . '${2}' . '${3}' . $placeholderArrow . $noSuggestionSymbol . $placeholderEnd, $replaced_with_placeholder);
             }
 
             // do the suggestion replacement if in replacement mode and construct error message
@@ -611,13 +635,13 @@ class DatabaseUpdate {
                 // We are in "display" mode, we show suggestions, no replacements are made
                 $message .= '<hr><span style="font-weight: bold; color: blue;">' . $qfqCode[$KEY_TITLE] . '</span><br><br>';
                 $message .= $qfqCode[$KEY_SQL_UPDATE];
-                $message .= '<pre>' . str_replace([$preventMatchSymbol, $placeholderBegin, $placeholderArrow,  $placeholderEnd, "\r\n", "\n"], [
-                    '',
-                    '<span style="font-weight: bold; color: red;">',
-                    '</span> âž¡ <span style="font-weight: bold; color: green;">',
-                    '</span>',
-                    "<br>", "<br>"
-                ], htmlentities($replaced_with_placeholder)) . '</pre>';
+                $message .= '<pre>' . str_replace([$preventMatchSymbol, $placeholderBegin, $placeholderArrow, $placeholderEnd, "\r\n", "\n"], [
+                        '',
+                        '<span style="font-weight: bold; color: red;">',
+                        '</span> âž¡ <span style="font-weight: bold; color: green;">',
+                        '</span>',
+                        "<br>", "<br>"
+                    ], htmlentities($replaced_with_placeholder)) . '</pre>';
             } elseif (strpos($replaced_with_placeholder, $replacedSymbol) !== false) {
 
                 // We are in "replacement" mode, show what is been replaced and do the replacement
@@ -657,7 +681,7 @@ class DatabaseUpdate {
 
             $message = ''
                 . '<h2>Automatic Replacement Completed</h2>'
-                . 'The following report has been saved to <br>' .  $reportPath
+                . 'The following report has been saved to <br>' . $reportPath
                 . '<br><br>Click <a href="?' . ACTION_SLUG_MIGRATION_UPDATE . '=null">check-again</a> to search for still existing usages of page alias.'
                 . '<h2>Overview Replacement Suggestions</h2>'
                 . join('<br>', array_unique($allMatches))
@@ -691,7 +715,7 @@ class DatabaseUpdate {
 
                 . '<li><a href="?' . ACTION_SLUG_MIGRATION_UPDATE . '=' . ACTION_SLUG_MIGRATION_DO_REPLACE . '">Auto replace</a>'
                 . ' occurrences of page aliases and page ids with the suggested page slug.'
-                . '<br>A report file with name "[timestamp]'. $reportFilePostfix .'" will be saved to "' . Path::absoluteLog() . '" after the automatic replacement. </li>'
+                . '<br>A report file with name "[timestamp]' . $reportFilePostfix . '" will be saved to "' . Path::absoluteLog() . '" after the automatic replacement. </li>'
 
                 . ' <li>To use the Form Editor you can '
                 . '<a href="?' . ACTION_SLUG_MIGRATION_UPDATE . '=' . ACTION_SLUG_MIGRATION_DO_PAUSE . '">pause the migration temporarliy</a>.</li>'
@@ -703,10 +727,6 @@ class DatabaseUpdate {
                 . "</ul>"
 
 
-
-
-
-
                 . ($forceRunMigrationCheck ? '<br><br>Note: setting ' . FORCE_RUN_PAGE_SLUG_MIGRATION_CHECK . ' is active in qfq.json.' : '')
 
                 . '<h2>Overview Replacement Suggestions</h2>'
diff --git a/extension/Classes/Core/Helper/HelperFormElement.php b/extension/Classes/Core/Helper/HelperFormElement.php
index dd182b64ad3ae1465162c648a3ec00a0d2adff21..f979fbf47f4d5ca21217ae7cc85542fa96096973 100644
--- a/extension/Classes/Core/Helper/HelperFormElement.php
+++ b/extension/Classes/Core/Helper/HelperFormElement.php
@@ -251,7 +251,7 @@ class HelperFormElement {
                 $fe[FE_RETYPE_SOURCE_NAME] = $fe[FE_NAME];
 
                 // Create copy of FE, adjust name, label, note
-                $fe[FE_NAME] .= RETYPE_FE_NAME_EXTENSION;
+                $fe[FE_NAME] .= FE_RETYPE_NAME_EXTENSION;
 
                 if (isset($fe[FE_RETYPE_LABEL])) {
                     $fe[FE_LABEL] = $fe[FE_RETYPE_LABEL];
diff --git a/extension/Classes/Core/Helper/OnArray.php b/extension/Classes/Core/Helper/OnArray.php
index e9b1286bd4a3a4004948fe9ed0c9faf4c428253a..681d8626e29b5e70a7fe448f49e619b92d74d240 100644
--- a/extension/Classes/Core/Helper/OnArray.php
+++ b/extension/Classes/Core/Helper/OnArray.php
@@ -506,7 +506,7 @@ class OnArray {
      * @param $arr
      * @return string
      */
-    public static function getFirstValueFromArray($arr): string {
+    public static function getFirstValueFromArray($arr, $reverse = false): string {
 
         if (!is_array($arr)) {
             return $arr;
@@ -516,6 +516,10 @@ class OnArray {
             $arr = array_pop($arr);
         }
 
+        if ($reverse) {
+            $arr = array_reverse($arr);
+        }
+
         $values = array_values($arr);
         if (count($values) > 1) {
             $value = $values[1];
@@ -540,4 +544,23 @@ class OnArray {
         rsort($arr);
         return isset($arr[0]) && is_array($arr[0]);
     }
+
+    /**
+     * Set value in one- or multidimensional array
+     *
+     * @param $arr
+     * @param $value
+     */
+    public static function setFirstValueInArray(&$arr, $key, $value): void {
+        if (self::is_multi_array($arr)) {
+            foreach ($arr as &$element) {
+                if (isset($element[$key])) {
+                    $element[$key] = $value;
+                    break;
+                }
+            }
+        } else if (isset($arr[$key])){
+            $arr[$key] = $value;
+        }
+    }
 }
\ No newline at end of file
diff --git a/extension/Classes/Core/Helper/Token.php b/extension/Classes/Core/Helper/Token.php
index f5019c7c5fd66f21c6f7b98f17cc15ebcf111528..a206c9a72503317bf03e52977ae0f03b12a2d6c5 100644
--- a/extension/Classes/Core/Helper/Token.php
+++ b/extension/Classes/Core/Helper/Token.php
@@ -57,6 +57,8 @@ class Token {
             case TOKEN_ACTION_DELETE:
                 $value = DEFAULT_ACTION_DELETE;
                 break;
+            case TOKEN_ORDER_TEXT:
+                throw new \UserReportException ("Missing value for token '$key'", ERROR_MISSING_VALUE);
             default:
         }
 
diff --git a/extension/Classes/Core/QuickFormQuery.php b/extension/Classes/Core/QuickFormQuery.php
index 38a267519dc708bc53325e26e67cd28c60f71d4b..c4f15feff0cc4a92a9102c6288440fdb506b27d7 100644
--- a/extension/Classes/Core/QuickFormQuery.php
+++ b/extension/Classes/Core/QuickFormQuery.php
@@ -165,8 +165,9 @@ class QuickFormQuery {
 
         $this->store = Store::getInstance($bodytext, $phpUnit);
 
-        $timeout = $this->store::getVar(SYSTEM_SESSION_TIMEOUT_SECONDS, STORE_SYSTEM);
-        Session::checkSessionExpired($timeout);
+        $t3ConfigQfq = $this->store::getStore(STORE_SYSTEM);
+
+        Session::checkSessionExpired($t3ConfigQfq[SYSTEM_SESSION_TIMEOUT_SECONDS]);
 
         // If an FE user logs out and a different user logs in (same browser session) - the old values has to be destroyed!
         if (Session::getAndDestroyFlagFeUserHasChanged()) {
@@ -190,7 +191,7 @@ class QuickFormQuery {
 
         $dbUpdate = $this->store->getVar(SYSTEM_DB_UPDATE, STORE_SYSTEM);
         $updateDb = new DatabaseUpdate($this->dbArray[$this->dbIndexQfq], $this->store);
-        $updateDb->checkNupdate($dbUpdate);
+        $updateDb->checkNupdate($dbUpdate, $t3ConfigQfq);
 
         $this->store->FillStoreSystemBySql(); // Do this after the DB-update
 
@@ -657,6 +658,11 @@ class QuickFormQuery {
             $this->formAsFileAfterSave($formFileName, $formModeNew, $formFileNameDelete);
         }
 
+        $unitTestRender = $this->store::getVar(SYSTEM_UNIT_TEST_FORM_CONTENT, STORE_SYSTEM);
+        if (isset($unitTestRender) && $unitTestRender !== false) {
+            $data = $unitTestRender;
+        }
+
         return $data;
     }
 
@@ -807,28 +813,57 @@ class QuickFormQuery {
      * @throws \UserFormException
      */
     private function logFormSubmitRequest() {
+
         $formSubmitLogMode = $this->formSpec[F_FORM_SUBMIT_LOG_MODE] ??
             $this->store->getVar(SYSTEM_FORM_SUBMIT_LOG_MODE, STORE_SYSTEM, SANITIZE_ALLOW_ALNUMX);
+
         if ($formSubmitLogMode === FORM_SUBMIT_LOG_MODE_NONE) {
             return;
         }
 
         $formData = $_POST;
         unset($formData[CLIENT_SIP]);
+        $recordId = $this->store->getVar(SIP_RECORD_ID, STORE_SIP);
+
+        // Check if specific columns should not be logged into table FormSubmitLog
+        $doNotLogColumnList = $this->formSpec[F_DO_NOT_LOG_COLUMN];
+        if (!empty($doNotLogColumnList)) {
+            $doNotLogColumnListArray = explode(',', $doNotLogColumnList);
+            // Replace content of all protected columns.
+            foreach ($doNotLogColumnListArray as $column) {
+                $column = trim($column);
+
+                // Get final $feName
+                $feName = HelperFormElement::buildFormElementName([FE_NAME => $column], $recordId);
+                if (isset($formData[$feName])) {
+                    // Only if such element exist: wipe it.
+                    $formData[$feName] = '*hide in log*';
+                }
+
+                // Password fields are often used with option RETYPE. Check and wipe them too.
+                $feNameRetype = HelperFormElement::buildFormElementName([FE_NAME => $column . FE_RETYPE_NAME_EXTENSION], $recordId);
+                if (isset($formData[$feNameRetype])) {
+                    $formData[$feNameRetype] = '*hide in log*';
+                }
+            }
+        }
+
         $formData = json_encode($formData, JSON_UNESCAPED_UNICODE);
+
+        $sql = "INSERT INTO `FormSubmitLog` (`formData`, `sipData`, `clientIp`, `feUser`, `userAgent`, `formId`, `formName`, `recordId`, `pageId`, `sessionId`, `created`)" .
+            "VALUES (?, ?, ?, ?, ?,  ?, ?, ?, ?, ?, NOW())";
+
         $clientIp = $_SERVER[CLIENT_REMOTE_ADDRESS] ?? '';
         $userAgent = $_SERVER[CLIENT_HTTP_USER_AGENT] ?? '';
         $sipData = json_encode($this->store->getStore(STORE_SIP), JSON_UNESCAPED_UNICODE);
         $formId = $this->formSpec[F_ID];
         $formName = $this->formSpec[F_NAME];
-        $recordId = $this->store->getVar(SIP_RECORD_ID, STORE_SIP);
         $feUser = $this->store->getVar(TYPO3_FE_USER, STORE_TYPO3, SANITIZE_ALLOW_ALNUMX);
         $pageId = $this->store->getVar(TYPO3_PAGE_ID, STORE_TYPO3, SANITIZE_ALLOW_ALNUMX);
         $sessionId = session_id();
 
-        $sql = "INSERT INTO `FormSubmitLog` (`formData`, `sipData`, `clientIp`, `feUser`, `userAgent`, `formId`, `formName`, `recordId`, `pageId`, `sessionId`, `created`)" .
-            "VALUES (?, ?, ?, ?, ?,  ?, ?, ?, ?, ?, NOW())";
         $params = [$formData, $sipData, $clientIp, $feUser, $userAgent, $formId, $formName, $recordId, $pageId, $sessionId];
+
         $this->dbArray[$this->dbIndexQfq]->sql($sql, ROW_REGULAR, $params);
     }
 
@@ -1402,10 +1437,12 @@ class QuickFormQuery {
             F_SHOW_ID_IN_FORM_TITLE,
             F_INPUT_CLEAR_ME,
             F_DATE_TIME_PICKER_TYPE,
+            F_DO_NOT_LOG_COLUMN,
 
             FE_FILE_MAX_FILE_SIZE,
 
             F_FE_DATA_PATTERN_ERROR_SYSTEM,  // Not a classical element to overwrite by form definition, but should be copied to detect changes per custom setting.
+
         ];
 
         // By definition: existing vars which are empty, means: EMPTY - do not use any default!
diff --git a/extension/Classes/Core/Report/Link.php b/extension/Classes/Core/Report/Link.php
index 8fcdf1ca126f9e8526e54dffefa1333bce065c0e..9126402cb918613d6e203f50bdd6c8a0f46a28a2 100644
--- a/extension/Classes/Core/Report/Link.php
+++ b/extension/Classes/Core/Report/Link.php
@@ -77,8 +77,8 @@ use IMATHUZH\Qfq\Core\Typo3\T3Handler;
  * T:Thumbnail
  * u:url
  * U:URL Param
- * v:
- * V:
+ * v:Text before link
+ * V:Text after link
  * w:websocket
  * W:Dimension
  * x:Delete
@@ -158,8 +158,12 @@ class Link {
         TOKEN_THUMBNAIL_DIMENSION => NAME_THUMBNAIL_DIMENSION,
         TOKEN_COPY_TO_CLIPBOARD => NAME_COPY_TO_CLIPBOARD,
         TOKEN_ATTRIBUTE => NAME_ATTRIBUTE,
+        TOKEN_ORDER_TEXT => NAME_ORDER_TEXT,
 
         TOKEN_MONITOR => NAME_MONITOR,
+        TOKEN_BEFORE_LINK => NAME_BEFORE_LINK,
+        TOKEN_AFTER_LINK => NAME_AFTER_LINK,
+
         // The following don't need a renaming: already 'long'
         TOKEN_L_FILE => TOKEN_L_FILE,
         TOKEN_L_TAIL => TOKEN_L_TAIL,
@@ -624,7 +628,8 @@ class Link {
                 throw new \UserReportException ("Mode not implemented. internal render mode=$mode", ERROR_UNKNOWN_MODE);
         }
 
-        return $link;
+        // Merge span to link if something exists from qualifier 'Y'
+        return $vars[NAME_BEFORE_LINK] . ($vars[NAME_ORDER_TEXT_WRAP] ?? '') . $link . $vars[NAME_AFTER_LINK];
     }
 
     /**
@@ -842,6 +847,15 @@ class Link {
                 case TOKEN_BOOTSTRAP_BUTTON:
                     $vars = $this->buildBootstrapButton($vars, $value);
                     break;
+                case TOKEN_ORDER_TEXT:
+                    $vars = $this->buildOrderText($vars, $value);
+                    break;
+                case TOKEN_BEFORE_LINK:
+                    $vars = $this->buildTextBeforeLink($vars, $value);
+                    break;
+                case TOKEN_AFTER_LINK:
+                    $vars = $this->buildTextAfterLink($vars, $value);
+                    break;
                 default:
                     break;
             }
@@ -902,6 +916,7 @@ class Link {
             NAME_COLLECT_ELEMENTS => array(),
             NAME_COPY_TO_CLIPBOARD => '',
             NAME_ATTRIBUTE => '',
+            NAME_ORDER_TEXT => '',
 
             NAME_RENDER => '0',
             NAME_RIGHT => 'l',
@@ -916,6 +931,9 @@ class Link {
 
             NAME_ACTION_DELETE => '',
 
+            NAME_BEFORE_LINK => '',
+            NAME_AFTER_LINK => '',
+
             FINAL_HREF => '',
             FINAL_CONTENT => '',
             FINAL_SYMBOL => '',
@@ -2135,6 +2153,26 @@ EOF;
         return $vars;
     }
 
+    /**
+     * @param $vars
+     * @param $value
+     * @return mixed
+     */
+    private function buildTextBeforeLink($vars, $value) {
+        $vars[NAME_BEFORE_LINK] = $value;
+        return $vars;
+    }
+
+    /**
+     * @param $vars
+     * @param $value
+     * @return mixed
+     */
+    private function buildTextAfterLink($vars, $value) {
+        $vars[NAME_AFTER_LINK] = $value;
+        return $vars;
+    }
+
     /**
      * Called by $this->callTable
      *
@@ -2224,4 +2262,15 @@ EOF;
 
         return $vars;
     }
+
+    /**
+     * Builds hidden span tag for column link, used as search criteria in table sorter.
+     *
+     * @param array $vars
+     * @return array
+     */
+    private function buildOrderText(array $vars) {
+        $vars[NAME_ORDER_TEXT_WRAP] = Support::wrapTag('<span style="display: none;">', $vars[NAME_ORDER_TEXT]);
+        return $vars;
+    }
 }
\ No newline at end of file
diff --git a/extension/Classes/Core/Save.php b/extension/Classes/Core/Save.php
index 926054d639349d1dbc237f28acb6457ccab0cf14..37b5523d007f32ac003a7ce216028070139fcb5d 100644
--- a/extension/Classes/Core/Save.php
+++ b/extension/Classes/Core/Save.php
@@ -8,6 +8,7 @@
 
 namespace IMATHUZH\Qfq\Core;
 
+use HTMLPurifier;
 use IMATHUZH\Qfq\Core\Database\Database;
 use IMATHUZH\Qfq\Core\Exception\Thrower;
 use IMATHUZH\Qfq\Core\Form\FormAction;
@@ -407,6 +408,10 @@ class Save {
         foreach ($this->feSpecNative as $fe) {
             $feColumnnTypes[$fe['name']] = $fe['type'];
         }
+
+        // Get htmlAllow parameters of all formValues and store in $feSpecsTags
+        $feSpecsTags = $this->getHtmlAllowTags($this->feSpecNative, $formValues);
+
         // Iterate over all table.columns. Built an assoc array $newValues.
         foreach ($tableColumns as $column) {
 
@@ -459,6 +464,13 @@ class Save {
             } else {
                 Support::setIfNotSet($formValues, $column);
             }
+
+            // Check for existing htmlAllow and strip tags, purify html result to prevent XSS
+            if (isset($feSpecsTags[$column]) && $feSpecsTags[$column] !== '') {
+                $formValues[$column] = $this->custom_strip_tags($formValues[$column], $feSpecsTags[$column]);
+                $formValues[$column] = $this->purifierHtml($formValues[$column]);
+            }
+
             $newValues[$column] = $formValues[$column];
             $realColumnFound = true;
         }
@@ -490,6 +502,97 @@ class Save {
         return $recordId;
     }
 
+    /**
+     * Get for every formElement htmlAllow tags from parameter
+     *
+     * @param $feSpecNative
+     * @param $formValues
+     * @return array
+     */
+    private function getHtmlAllowTags($feSpecNative, $formValues): array {
+
+        $feSpecsTags = array();
+
+        foreach ($feSpecNative as $formElement) {
+            foreach ($formValues as $keyName => $keyValue) {
+                if ($formElement[FE_NAME] === $keyName) {
+                    if (isset($formElement[FE_HTML_ALLOW]) && $formElement[FE_HTML_ALLOW] !== '') {
+                        $feSpecsTags[$keyName] = $formElement[FE_HTML_ALLOW];
+                    }
+                }
+            }
+        }
+
+        return $this->setTinyMceSpecificTags($feSpecsTags);
+    }
+
+    /**
+     * For TinyMCE there are specific tags needed for lists and text decoration (underline, strikethrough).
+     * These tags should be added here.
+     *
+     * @param $feSpecsTags
+     * @return array
+     */
+    private function setTinyMceSpecificTags($feSpecsTags): array {
+        $listFlag = false;
+        $decorationFlag = false;
+        $tableFlag = false;
+        $strongFlag = false;
+        foreach ($feSpecsTags as $key => $value) {
+            $feSpecsTagArray[$key] = explode(',', $value);
+            foreach ($feSpecsTagArray[$key] as $key2 => $tag) {
+                switch ($tag) {
+                    case 'ul':
+                    case 'ol':
+                        $listFlag = true;
+                    break;
+                    case 'textDecoration':
+                    case 'u':
+                    case 'ins':
+                    case 'del':
+                    case 's':
+                        $decorationFlag = true;
+                        break;
+                    case 'table':
+                        $tableFlag = true;
+                        break;
+                    case 'b':
+                        $strongFlag = true;
+                        break;
+                    default:
+                        $feSpecsTagArray[$key][$key2] = $tag;
+                        break;
+                }
+            }
+
+            if ($listFlag) {
+                $feSpecsTagArray[$key][] = "li";
+                $listFlag = false;
+            }
+
+            // In case of TinyMCE span is automatically used for underline and strikethrough
+            if ($decorationFlag) {
+                $feSpecsTagArray[$key][] = "span";
+                $decorationFlag = false;
+            }
+
+
+            if ($strongFlag) {
+                $feSpecsTagArray[$key][] = "strong";
+                $strongFlag = false;
+            }
+
+            if ($tableFlag) {
+                array_push($feSpecsTagArray[$key], "th", "td", "tr", "tbody", "thead");
+                $tableFlag = false;
+            }
+
+            $feSpecsTags[$key] = implode(',', $feSpecsTagArray[$key]);
+        }
+
+        return $feSpecsTags;
+    }
+
     /**
      * Process sqlBefore, sqlInsert|.... for all native FE.
      *
@@ -1696,6 +1799,7 @@ class Save {
         $mode = ($slaveId == '0') ? 'I' : 'U'; // I=Insert, U=Update
         $mode .= ($modeUpload == UPLOAD_MODE_NEW || $modeUpload == UPLOAD_MODE_DELETEOLD_NEW) ? 'N' : ''; // N=New File, '' if no new file.
         $mode .= ($modeUpload == UPLOAD_MODE_DELETEOLD) ? 'D' : ''; // Delete slave record only if there is no new and not 'unchanged'.
+
         switch ($mode) {
             case 'IN':
                 $sql = $fe[FE_SQL_INSERT];
@@ -1732,4 +1836,39 @@ class Save {
         return $slaveId;
     }
 
+    /**
+     * Remove not allowed tags.
+     *
+     * @param array $html_str
+     * @param string $allowedTags
+     * @param string $allowedAttributes
+     * @return string
+     */
+    function custom_strip_tags($html, string $allowedTags) {
+        $allowed_tags = explode(',', $allowedTags);
+        $allowed_tags = array_map('strtolower', $allowed_tags);
+        $regex_tags = '/<\/?([^>\s]+)[^>]*>/i';
+        $matches = array();
+        preg_match_all($regex_tags, $html, $matches);
+        $rhtml = preg_replace_callback($regex_tags, function ($matches) use (&$allowed_tags) {
+            return in_array(strtolower($matches[1]), $allowed_tags) ? $matches[0] : '';
+        }, $html);
+        return $rhtml;
+    }
+
+    /**
+     * Remove not allowed attributes and content which is not in whitelist
+     * Used in combination with htmlAllow.
+     * Author:  Edward Z. Yang
+     * Website: http://htmlpurifier.org/
+     *
+     * @param $html
+     * @return array|string|string[]|null
+     */
+    function purifierHtml($html) {
+        $purifier = new HTMLPurifier();
+        $rhtml = $purifier->purify($html);
+        return $rhtml;
+    }
+
 }
\ No newline at end of file
diff --git a/extension/Classes/Core/Store/Config.php b/extension/Classes/Core/Store/Config.php
index 89a01e3f09927eea8c1f69a0558d4f891f2843de..1da4a1bbfc14a8c438d52e8d7c42781c9c2c0513 100644
--- a/extension/Classes/Core/Store/Config.php
+++ b/extension/Classes/Core/Store/Config.php
@@ -186,7 +186,7 @@ class Config {
     }
 
     /**
-     * Overwrite the qfq config file with data from given array.
+     * Overwrite the CONFIG_QFQ_JSON (db credentials) file with data from given array.
      *
      * @param array $config
      * @throws \UserFormException
diff --git a/extension/Classes/Core/Store/FillStoreForm.php b/extension/Classes/Core/Store/FillStoreForm.php
index bd75b9a34e0abbdfe813a41b3868ef17e333e1c5..aa050ff94e5120e770927435caeed78fac390c3a 100644
--- a/extension/Classes/Core/Store/FillStoreForm.php
+++ b/extension/Classes/Core/Store/FillStoreForm.php
@@ -296,6 +296,13 @@ class FillStoreForm {
                     $formElement[FE_MODE] === FE_MODE_SHOW ||
                     (isset($formElement[FE_PROCESS_READ_ONLY]) && $formElement[FE_PROCESS_READ_ONLY] != '0')) {
 
+                    // Dynamically changed fe mode from show or other to readonly is not fetched here (not yet stored in db).
+                    // For this reason there is no included check for fe mode = readonly.
+                    // Theoretically processReadOnly can be used in formElements with other fe modes too.
+                    if (isset($formElement[FE_PROCESS_READ_ONLY]) && $formElement[FE_PROCESS_READ_ONLY] == '0') {
+                        continue;
+                    }
+
                     if (HelperFormElement::booleParameter($formElement[FE_TYPEAHEAD_TAG] ?? '-')) {
                         // TypeAhead Tags received as JSON key/value
                         $cntNew = 0;
diff --git a/extension/Classes/Core/Typo3/T3Handler.php b/extension/Classes/Core/Typo3/T3Handler.php
index e9310fc30b0ce36f963fcdf3a441943c97150cc0..8426a9e1c8c62ec212119876e595881d22deefb3 100644
--- a/extension/Classes/Core/Typo3/T3Handler.php
+++ b/extension/Classes/Core/Typo3/T3Handler.php
@@ -149,7 +149,9 @@ class T3Handler {
     }
 
     /**
-     * Update a single key/value pair in `typo3conf/LocalConfiguration.php` QFQ config.
+     * Update in `typo3conf/LocalConfiguration.php` QFQ config.
+     * a) key!==false: a single $key/$value pair (not used anymore)
+     * b) key===false: array in $value
      *
      * @param mixed $value
      * @param mixed $key
@@ -179,11 +181,8 @@ class T3Handler {
             $configQfq = unserialize($configT3['EXT']['extConf'][EXT_KEY]);
         }
 
-        // If key not given, merge both arrays
-        if ($key) {
-            // Set new value
-            $configQfq[$key] = $value;
-        } else {
+        if ($key === false) {
+            // key===false: merge both arrays
             // Show debug info should stay dynamically and not overwritten in config file. Unit tests are an example for this reason.
             $showDebugInfo = $configQfq[SYSTEM_SHOW_DEBUG_INFO];
             $configQfq = array_merge($configQfq, $value);
@@ -195,6 +194,9 @@ class T3Handler {
                     unset($configQfq['DB_' . $ii . '_' . $key]);
                 }
             }
+        } else {
+            // key given: set indiviudal key/value
+            $configQfq[$key] = $value;
         }
 
         // Prepare
@@ -218,8 +220,7 @@ class T3Handler {
      *
      * @return string
      */
-    public static function getTypo3Version()
-    {
+    public static function getTypo3Version() {
         self::t3AutoloadIfNotRunning();
         return \TYPO3\CMS\Core\Utility\VersionNumberUtility::getNumericTypo3Version();
     }
diff --git a/extension/Tests/Unit/Core/Helper/HelperFormElementTest.php b/extension/Tests/Unit/Core/Helper/HelperFormElementTest.php
index 069808e073e261d85c9f962381dc7f047b792da9..5884a8d907f8ea4f5e8a91f5cd75b6a6766b56e8 100644
--- a/extension/Tests/Unit/Core/Helper/HelperFormElementTest.php
+++ b/extension/Tests/Unit/Core/Helper/HelperFormElementTest.php
@@ -94,7 +94,7 @@ class HelperFormElementTest extends TestCase {
         $b = HelperFormElement::duplicateRetypeElements($a);
         $this->assertEquals(count($a) + 1, count($b), "Both arrays should be same count");
         $this->assertEquals('1', $b[0][FE_RETYPE], "FE_RETYPE should be unchanged");
-        $this->assertEquals($b[0][FE_NAME] . RETYPE_FE_NAME_EXTENSION, $b[1][FE_NAME], "New name should be extended by: " . RETYPE_FE_NAME_EXTENSION);
+        $this->assertEquals($b[0][FE_NAME] . FE_RETYPE_NAME_EXTENSION, $b[1][FE_NAME], "New name should be extended by: " . FE_RETYPE_NAME_EXTENSION);
         $this->assertEquals($b[0][FE_LABEL], $b[1][FE_LABEL], "Both text should be equal");
         $this->assertEquals($b[0][FE_NOTE], $b[1][FE_NOTE], "Both text should be equal");
 
diff --git a/extension/Tests/Unit/Core/QuickFormQueryTest.php b/extension/Tests/Unit/Core/QuickFormQueryTest.php
index 009ac79d1721b08214bade7319b603ab3b429e06..2545ea805f6786049fbd3f9e3ff9aa15d0250599 100644
--- a/extension/Tests/Unit/Core/QuickFormQueryTest.php
+++ b/extension/Tests/Unit/Core/QuickFormQueryTest.php
@@ -106,4 +106,70 @@ class QuickFormQueryTest extends TestCase {
 
     }
 
+    public function testRenderMode() {
+        $store = Store::getInstance();
+
+        // form={{form:SE}}
+        // 10.sql = SELECT '&Hello World'
+        $store->unsetStore(STORE_TYPO3);
+
+        // Set dummys for QuickFormQuery test
+        $store->setVar(SYSTEM_UNIT_TEST_FORM_CONTENT, 'FormLoaded', STORE_SYSTEM);
+        $store->setVar(SYSTEM_DRAG_AND_DROP_JS, 'false', STORE_SYSTEM);
+        $store->setVar('form', 'copyForm', STORE_SIP);
+        $store->setVar('r', '0', STORE_SIP);
+        $store->setVar(SIP_SIP, 'fakeSip', STORE_SIP);
+        $t3data[T3DATA_UID] = "123";
+
+        // QFQ Config - render = single
+        $store->setVar(SYSTEM_RENDER, SYSTEM_RENDER_SINGLE, STORE_SYSTEM);
+
+        // In report - nothing given
+        $t3data[T3DATA_BODYTEXT] = "form={{form:SE}}\n20.sql = SELECT '&Hello World'";
+        $qfq = new QuickFormQuery($t3data, true);
+        $result = $qfq->process();
+        $this->assertEquals('FormLoaded', $result);
+
+        // In report - render = both
+        $t3data[T3DATA_BODYTEXT] = "render=both\nform={{form:SE}}\n20.sql = SELECT '&Hello World'";
+        $qfq = new QuickFormQuery($t3data, true);
+        $result = $qfq->process();
+        $this->assertEquals('FormLoaded&Hello World', $result);
+
+        // In report - render = single
+        $t3data[T3DATA_BODYTEXT] = "render=single\nform={{form:SE}}\n20.sql = SELECT '&Hello World'";
+        $qfq = new QuickFormQuery($t3data, true);
+        $result = $qfq->process();
+        $this->assertEquals('FormLoaded', $result);
+
+        // QFQ Config - render = both
+        $store->setVar(SYSTEM_RENDER, SYSTEM_RENDER_BOTH, STORE_SYSTEM);
+
+        // In report - nothing given
+        $t3data[T3DATA_BODYTEXT] = "form={{form:SE}}\n20.sql = SELECT '&Hello World'";
+        $qfq = new QuickFormQuery($t3data, true);
+        $result = $qfq->process();
+        $this->assertEquals('FormLoaded&Hello World', $result);
+
+        // In report - render = both
+        $t3data[T3DATA_BODYTEXT] = "render=both\nform={{form:SE}}\n20.sql = SELECT '&Hello World'";
+        $qfq = new QuickFormQuery($t3data, true);
+        $result = $qfq->process();
+        $this->assertEquals('FormLoaded&Hello World', $result);
+
+        // In report - render = single
+        $t3data[T3DATA_BODYTEXT] = "render=single\nform={{form:SE}}\n20.sql = SELECT '&Hello World'";
+        $qfq = new QuickFormQuery($t3data, true);
+        $result = $qfq->process();
+        $this->assertEquals('FormLoaded', $result);
+
+        // In report - render = api. Unset unit test variable for this one.
+        $store->unsetVar(SYSTEM_UNIT_TEST_FORM_CONTENT, STORE_SYSTEM);
+        $GLOBALS['TYPO3_CONF_VARS'] = 'fakeVars';
+        $t3data[T3DATA_BODYTEXT] = "render=api\nform={{form:SE}}\n20.sql = SELECT '&Hello World'";
+        $qfq = new QuickFormQuery($t3data, true);
+        $result = $qfq->process();
+        $this->assertEquals('', $result);
+
+    }
 }
diff --git a/extension/Tests/Unit/Core/Report/LinkTest.php b/extension/Tests/Unit/Core/Report/LinkTest.php
index 4a3338589b296b4bee33d8a7e1b2c93b0dd2db6e..996d3ec39ba5bba32402200810ed4f9ab21f4ad7 100644
--- a/extension/Tests/Unit/Core/Report/LinkTest.php
+++ b/extension/Tests/Unit/Core/Report/LinkTest.php
@@ -101,6 +101,9 @@ class LinkTest extends TestCase {
             'finalClass' => '',
             'finalQuestion' => '',
             'finalThumbnail' => '',
+            'beforeLink' => '',
+            'afterLink' => '',
+            'orderText' => '',
         ];
 
         $link = new Link($this->sip, DB_INDEX_DEFAULT, true);
@@ -892,6 +895,24 @@ class LinkTest extends TestCase {
         $this->assertEquals('<a href="http://example.com" class="btn btn-default" title="Details" ><span class="glyphicon glyphicon-envelope" ></span></a>', $result);
     }
 
+    /**
+     * @throws \CodeException
+     * @throws \UserFormException
+     * @throws \UserReportException
+     */
+    public function testBeforeAfterText() {
+        $link = new Link($this->sip, DB_INDEX_DEFAULT, true);
+
+        $result = $link->renderLink('u:http://example.com|t:Link|v:Hello ');
+        $this->assertEquals('Hello <a href="http://example.com" >Link</a>', $result);
+
+        $result = $link->renderLink('u:http://example.com|t:Link|V: world');
+        $this->assertEquals('<a href="http://example.com" >Link</a> world', $result);
+
+        $result = $link->renderLink('u:http://example.com|t:Link|v:Hello |V: world');
+        $this->assertEquals('Hello <a href="http://example.com" >Link</a> world', $result);
+    }
+
     /**
      * @expectedException UserReportException
      *
@@ -1756,6 +1777,20 @@ EOF;
         $this->assertEquals($expect, $result);
     }
 
+    /**
+     * @throws \CodeException
+     * @throws \UserFormException
+     * @throws \UserReportException
+     */
+    public function testLinkOrderText() {
+        $link = new Link($this->sip, DB_INDEX_DEFAULT, true);
+
+        // Normal definition
+        $expect = '<span style="display: none;">searchText</span><a href="'. $this->baseUrl .'testPage" >'. $this->baseUrl .'testPage</a>';
+        $result = $link->renderLink('p:id=testPage|Y:searchText');
+        $this->assertEquals($expect, $result);
+    }
+
     /**
      * @expectedException UserReportException
      *
diff --git a/extension/Tests/Unit/Core/Store/StoreTest.php b/extension/Tests/Unit/Core/Store/StoreTest.php
index ec92bc357fd5863f8f3834776c912f3aa3040220..1921ce631bf209f565e62fb89ac86fb57561dc57 100644
--- a/extension/Tests/Unit/Core/Store/StoreTest.php
+++ b/extension/Tests/Unit/Core/Store/StoreTest.php
@@ -429,12 +429,12 @@ class StoreTest extends TestCase {
             SYSTEM_CMD_PDF2PS => 'pdf2ps',
             SYSTEM_CMD_PS2PDF => 'ps2pdf',
             SYSTEM_REMEMBER_LAST_PILL => 1,
-            SYSTEM_REMEMBER_LAST_PILL => 1,
             SYSTEM_DATE_TIME_PICKER_TYPE => 'qfq',
             SYSTEM_HTTP_ORIGIN => 'http://' . DOMAIN_EXAMPLE_COM,
             SYSTEM_IMAGE_UPLOAD_DIR => 'fileadmin/imageUploadDir',
-            'baseUrlLang' => HTTP_EXAMPLE_COM,
-            SYSTEM_FORCE_SMTP_SENDER => ''
+            SYSTEM_BASE_URL_LANG => HTTP_EXAMPLE_COM,
+            SYSTEM_FORCE_SMTP_SENDER => '',
+//            SYSTEM_DO_NOT_LOG_COLUMN => SYSTEM_DO_NOT_LOG_COLUMN_DEFAULT,
 
         ];
 
diff --git a/extension/composer.json b/extension/composer.json
index 1e0adcf6e5ff6f577ce6c1065c8cd72552a47013..0b570dba8cb4901a8e0b09065c93bfc8bde9cd49 100644
--- a/extension/composer.json
+++ b/extension/composer.json
@@ -2,7 +2,8 @@
   "require": {
     "phpoffice/phpspreadsheet": "^1.3",
     "ext-json": "*",
-    "twig/twig": "^2.0"
+    "twig/twig": "^2.0",
+    "ezyang/htmlpurifier": "^4.15"
   },
   "require-dev": {
     "phpunit/phpunit": "^6.5"
diff --git a/extension/ext_conf_template.txt b/extension/ext_conf_template.txt
index 0aa66eee90991635c02826702877002118ac5197..1121d73f76c8e774108da781be00bcb9ea934324 100644
--- a/extension/ext_conf_template.txt
+++ b/extension/ext_conf_template.txt
@@ -193,6 +193,8 @@ clearMe = 0
 # cat=form-config/config; type=boolean; label=On form load, bring last used pill to front
 rememberLastPill = 1
 
+# cat=form-config/config; type=string; label=Do not log column:Default is 'password'. Comma separated more than one column possible.
+doNotLogColumn = password
 
 
 # cat=form-layout/layout; type=string; label=FormElement label align:Default is 'left'. Possible values: 'left', 'center', 'right'.
diff --git a/javascript/src/Element/Textual.js b/javascript/src/Element/Textual.js
index 7cc73b414e6302deaf79c8d20cef3b2f55ee8270..f22ee575d36749a9ccef7d795519698640054170 100644
--- a/javascript/src/Element/Textual.js
+++ b/javascript/src/Element/Textual.js
@@ -65,7 +65,21 @@ QfqNS.Element = QfqNS.Element || {};
     Textual.prototype.constructor = Textual;
 
     Textual.prototype.setValue = function (val) {
-        this.$element.val(val);
+        // Typeahead delivers an array with refreshed value after save progress.
+        if (Array.isArray(val)) {
+            this.setTypeAheadInput(val);
+        } else {
+            this.$element.val(val);
+        }
+    };
+
+    // Apply and see changed value after save (no page reload needed), typeahead elements needs to be handled separately.
+    Textual.prototype.setTypeAheadInput = function (value) {
+        this.$element.val(value[0].key);
+        // Display new value and correctly set new key in hidden input element.
+        this.$element.eq(1).typeahead('val', value[0].value);
+        var hiddenElement =  this.$element.eq(0).closest('div').find('input[type=hidden]');
+        hiddenElement.val(value[0].key);
     };
 
     Textual.prototype.getValue = function () {
diff --git a/javascript/src/Form.js b/javascript/src/Form.js
index 359f7a230a5603555ee5c3e4588ff9c3ac228685..ad798e52c6b4b68d7cdd5044148c9ee1c74c1f24 100644
--- a/javascript/src/Form.js
+++ b/javascript/src/Form.js
@@ -166,10 +166,18 @@ var QfqNS = QfqNS || {};
 
         this.eventEmitter.emitEvent('form.submit.before', n.EventEmitter.makePayload(this, null));
         submitUrl = this.makeUrl(to, queryParameters);
-        $.post(submitUrl, this.$form.serialize())
+
+        // For better dynamic update compatibility (checkboxes). All input elements need to be not disabled for fully serializing by jquery.
+        var form = $(this.$form[0]);
+        // Get even disabled inputs
+        var disabled = form.find(':input:disabled').removeAttr('disabled');
+        var serializedForm = this.$form.serialize();
+        // Reset disabled inputs
+        disabled.attr('disabled','disabled');
+
+        $.post(submitUrl, serializedForm)
             .done(this.ajaxSuccessHandler.bind(this))
             .fail(this.submitFailureHandler.bind(this));
-        console.log(this.$form.serialize());
     };
 
     n.Form.prototype.serialize = function () {
diff --git a/javascript/src/QfqForm.js b/javascript/src/QfqForm.js
index ca0c47c9b1f826d5c4760b3d1f0833129ac4690a..ffb973c35bcb4ce787fc2fecf069e1d75a66a75b 100644
--- a/javascript/src/QfqForm.js
+++ b/javascript/src/QfqForm.js
@@ -521,7 +521,16 @@ var QfqNS = QfqNS || {};
         if (this.formImmutableDueToConcurrentAccess) {
             return;
         }
-        $.post(this.dataRefreshUrl, this.form.serialize(), "json")
+
+        // For better dynamic update compatibility (checkboxes). All input elements need to be not disabled for fully serializing by jquery.
+        var form = $(this.form.$form[0]);
+        // Get all disabled inputs
+        var disabled = form.find(':input:disabled').removeAttr('disabled');
+        var serializedForm = this.form.serialize();
+        // Reset disabled inputs
+        disabled.attr('disabled','disabled');
+
+        $.post(this.dataRefreshUrl, serializedForm, "json")
             .fail(n.Helper.showAjaxError)
             .done(function (data) {
                 this.handleFormUpdate(data);
diff --git a/less/qfq-bs.css.less b/less/qfq-bs.css.less
index c86b976ff9ffd3609062f6ab7a7e38858ddb8906..0e479dece7520ef2b1a65c89ffabc240de573e61 100644
--- a/less/qfq-bs.css.less
+++ b/less/qfq-bs.css.less
@@ -1369,12 +1369,13 @@ thead.qfq-sticky td {
 @font-face {
   font-family: 'password';
   font-style: normal;
-  font-weight: 400;
-  src: url(https://jsbin-user-assets.s3.amazonaws.com/rafaelcastrocouto/password.ttf);
+  font-size: 15px;
+  src: url(../fonts/password-dots.ttf);
 }
 
 input.qfq-password {
   font-family: 'password';
+  letter-spacing: -3px;
 }
 
 /* bootstrap correction for better looking arrows in datetimepicker */