diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..bdc24025ae4834d80be3f099b82f1621c4f07380
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,898 @@
+.. ==================================================
+.. Header hierachy
+.. ==
+..  --
+..   ^^
+..    ''
+..     ;;
+..      ,,
+..
+.. --------------------------------------------------
+.. Best Practice T3 reST  https://docs.typo3.org/typo3cms/drafts/github/xperseguers/RstPrimer/
+.. External Links: `Bootstrap <http://getbootstrap.com/>`_:
+.. Add Images: https://wiki.typo3.org/ReST_Syntax#Images
+..
+.. -*- coding: utf-8 -*- with BOM.
+
+
+.. include:: Includes.txt
+
+.. _release:
+
+Release
+=======
+
+Version 0.future
+----------------
+
+Date: <date>
+
+Notes
+^^^^^
+
+Features
+^^^^^^^^
+
+Bug Fixes
+^^^^^^^^^
+
+Version 0.23.0
+--------------
+
+Date: 17.09.2017
+
+Notes
+^^^^^
+
+Features
+^^^^^^^^
+
+* #3752 / Pills auf mode|modeSql=hidden|readonly setzen - implemented during 'form load' (not dynamic update)
+
+Bug Fixes
+^^^^^^^^^
+
+* #4548 /Template Group: 'form-update' broken - Broken Redirect after Save - Broken same HTML ID for FE copies in a template group.
+* #4548 /Template Group: 'form-update' broken - max tg element value/index shown after save instead of last user supplied value, but save is ok. Neu wird nach dem Speichern das Formular nochmal komplett geladen. Das ist wichtig um die durch aftersave geaenderten Records in die Formularelemente zu bekommen.
+
+Release
+=======
+
+Version 0.22
+------------
+
+Date: 14.09.2017
+
+Notes
+^^^^^
+
+* Form Editor: element 'forwardPage' is static again (no dynamic update) - see features in #4511.
+
+Features
+^^^^^^^^
+
+* #4511 / Form: URL Forward - mode dynamic computed
+
+Bug Fixes
+^^^^^^^^^
+
+* #4512 | SIP URL does not respect anker token '#'- fixed PLUS: L and type _GET Params included in links which contain a SIP (regular links still open).
+* #4508 / Form: during Save with FE with 'report'-Note/Values an exception is thrown - report does not expect, to be called without typo3 - but this is the case during save and generating the JSON.
+* #4021 / "required" asterik does not handle multi column labels correctly
+* #4423 / Date inputs with readonly: label is grey.
+* Empty date might create '2001-00-00'
+* #4504 / Upload Button: required asterik missing after save - seems to be a problem for every element - should be fixed now.
+
+Version 0.21.0
+--------------
+
+Date: 10.09.2017
+
+Notes
+^^^^^
+
+* The Form-Editor now has two 'requiredParamter' fields: one for 'New' record and one 'Edit'. Existing settings will be
+  automatically copied to both.
+* The FormElement-Editor field 'Note' is not anymore a TinyMCE Editor. Instead a regular 'textarea' is used. Main reason
+  are incompatibilities between TinyMCE HTML mode and the neede CR/LF linebreaks needed for 'Report' Syntax in the 'note'
+  column.
+
+Features
+^^^^^^^^
+
+* #4431 / FE.type=note: QFQ Report Syntax in 'FE.value' and 'FE.note'
+* #4456 / formModeGlobal=requiredOff - Switches FormElement.mode=required to 'show' for all FE of the current Form.
+* Feature #4356 / Form: required parameter - split between 'New' & 'Edit'
+
+Version 0.20.0
+--------------
+
+Changes
+^^^^^^^
+
+* New configuration value EXTRA_BUTTON_INFO_POSITION in config.qfq.ini
+
+Features
+^^^^^^^^
+
+* #4386 Fuer GRC: Optional Info Button bei 'input' wie bei 'textarea' - EXTRA_BUTTON_INFO_POSITION=below
+* #4429 / subrecord: new FE parameter 'subrecordTableCass' - a custom class for the subrecord table might be specified.
+* #4428 / subrecord: mode=readonly
+* #4421 / subrecord: column of the sql1 row should go into the edit link - implemented
+* #4399 / Do not render '_pdf' when r:5 or empty string
+
+Bug Fixes
+^^^^^^^^^
+
+* #4396 / FE: Justify DATE and TIME in case it's DATETIME on a non primary table.
+* #2414 / Deaktivieren von Option 'new' bei subrecord hat keine Folge
+* #4426 / Subrecord: mode=hidden - still shown
+* #4425/ Subrecords: Table head is not wrapped in <thead>
+* #4331 / SQL Statement 'REPLACE' not fired - Keyword missing in list of SQL Keywords
+
+
+Version 0.19.7
+--------------
+
+Changes
+^^^^^^^
+
+* #4306 / Update Text Subrecord: Please save this record first
+
+Features
+^^^^^^^^
+
+Bug Fixes
+^^^^^^^^^
+
+* #4278 / Language: Check that language settings are respectet inside of container / pill / fieldset / templateGroup.
+* #4310 / Fixed error where custom values wouldn't be saved, nor not found for non pedantic.
+* #4311 / Record Lock: expired lock wird nicht geloescht bei form reload.
+* #4309 / typeahead: allow free entry
+
+Version 0.19.6
+--------------
+
+Features
+^^^^^^^^
+
+* #4299 / HTML Element 'Select': Placeholder
+* Changes to the alert generation and added btn-group for multiple buttons.
+* Should only show reload button and be modal when the conflict is mandatory.
+* #4144 / Close/New: bei acquireLock=false anschliessend keine Nachfrage ob gespeichert werden soll
+* #4120 / Removed Timeout from Dirty Alert Message
+* #4283 / FE.parameter=emptyMeansNull
+
+Bug Fixes
+^^^^^^^^^
+
+* #4281 Prevent save from being clicked multiple times. Save no turns orange when saving.
+
+Version 0.19.5
+--------------
+
+Features
+^^^^^^^^
+
+* #3790 / Multilanguage: German/ English/ ...
+
+Bug Fixes
+^^^^^^^^^
+* #4274 / ItemList: escape ',' ':'
+
+
+Version 0.19.4
+--------------
+
+Features
+^^^^^^^^
+
+* Feature: Form Paste Records - skip columns during copy if they do not exist on the source side.
+
+Bug Fixes
+^^^^^^^^^
+
+* #4266 / FormElement Type=Editor: value not saved - fixed
+* #4253 / Record Lock not deleted, when window closes without save.
+
+Version 0.19.3
+--------------
+
+Changes
+^^^^^^^
+
+* Changing buttons for the dirty Events depending on status
+
+Bug Fixes
+^^^^^^^^^
+
+* #4257 / Dynamic update broken - after changing JSON data structure, update load.php has been missed.
+
+Open
+^^^^
+
+* #4253 / Record Lock not deleted when window closes without save
+
+Version 0.19.2
+--------------
+
+Features
+^^^^^^^^
+
+* #4250 / autocron: sending mails
+* #4248 / FormElement: TypeAhead fuer den Spaltennamen - Implemented
+* #4144 / Close/New: bei acquireLock=false anschliessend keine Nachfrage ob gespeichert werden soll
+* #4120: Removed Timeout from Dirty Alert Message
+
+Version 0.19.1
+--------------
+
+Features
+^^^^^^^^
+
+ * #4172 /record locking: Bob tries to delete a record and get 'status=error': Client should disable 'delete' button
+ * #4185 / Detect modified record
+ * #4143 / New alert removes old alert(s)
+ * #4173 / Form: User open's a new tab and press close - alert to inform user that he has to close the tab
+ * #1930, #3980 /  Client: Bei Form Submit den Status 'submit_reason=save|save,close' mitsenden
+ * Implemented: New > Close (save) now closes correctly the current page. Addtional, #1930 has been solved implizit.
+
+Bug Fixes
+^^^^^^^^^
+
+ * Bug #4174 / record locking: error message if delete fails due to record locking
+ * Bug: SQL 'CREATE' implemented as a valid command.
+
+Version 0.19.0
+--------------
+
+Changes
+^^^^^^^
+
+* bower.json: change bootstrap version number from micro to minor.
+* Sip.php: Guarantee that uniqid() is unique at least for the current user.
+* Makefile: change installation of phpDocumentor to --alldeps and remove 'phpdoc/'.
+
+Features
+^^^^^^^^
+
+* #3881 / Variables: Ex 'keySemId', New 'periodId' (System Store)
+* AbstractBuildForm.php: if a datetime / timestamp has the string 'CURRENT_TIMESTAMP' it will be replaced by the current date/time.
+* Add new STORE_TYPO3 vars: pageAlias, pageTitle
+* Config.php: cleanup of checking GET variables.
+* #3981 / Record Locking
+* Manual.rst: add documentation for record locking
+* Manual.rst: more details about QFQ variables.
+* plantuml: sequence diagrams for record locking
+
+Bug Fixes
+^^^^^^^^^
+
+* Bug #4158 / Delete Button im Form fehlen die SIP Parameter.
+* Bug #4159 / missing htmlspecialchar_decode() for FE.value supplied content.
+* Bug Makefile: fixed unwanted removing of whole 'doc' by 'maintainer-clean' - doc nowadays contains QFQ related manually created documentation.
+* Bug typeahead.php: An exception catched in typeahead.php has been assigned as array element, instead of a whole array. Fixed.
+
+
+
+
+Version 0.18.7
+--------------
+
+Changes
+^^^^^^^
+
+* Makefile: 'make bootstrap' udpates all JS Lib packages. Double npm install removed.
+
+Features
+^^^^^^^^
+
+* #3947 / Attack detectect: logout current user (only QFQ, FE User still logged in).
+* #3959 / Class _link: implement 'any' Bootstrap glyphicons. New token 'G:' for '_link'.
+
+Bug Fixes
+^^^^^^^^^
+
+* #3953 / Radio buttons: Auswahl nicht angezeigt, wenn per itemList definiert
+* Feature #3982 / Filename Sanatize: remove spaces. Filename not properbly enclosed by double ticks.
+
+Version 0.18.6
+--------------
+
+Features
+^^^^^^^^
+
+* Feature #3460 / Report: new column types '_striptags, '_htmlentities', '_+Tag'
+
+Version 0.18.5
+--------------
+
+Features
+^^^^^^^^
+
+* QuickFormQuery.php: added function to check if there are copyForm paste records
+* Manual.rst, formEditor.sql: add several links in Form 'FormEditor' to the online documentation. The FormEditor now
+  contains links to the Online Documentation. Add missing explanations: Required Parameter, Forward.
+
+Bug Fixes
+^^^^^^^^^
+
+* Bug #3912 / templateGroup: max. 5 instances are saved.
+* Manual.rst: Fixed missing '{{' and '%' in examples.
+* Bug #3925 / templateGroup / non primary / delete records: only one at a time
+* Makefile: Artifactory builds fails at chromedriver - temporary remove npm install of chromedriver
+
+Version 0.18.4
+--------------
+
+Bug Fixes
+^^^^^^^^^
+* Bug #3910 / 'submitButtonText' not shown
+
+Version 0.18.3b
+---------------
+
+Features
+^^^^^^^^
+
+* Feature #3906 / Mark required inputs with an asterik
+
+Bug Fixes
+^^^^^^^^^
+
+* Bug #3903 / Copy/Paste form: references inside a record are not updated at all
+
+Version 0.18.3a
+---------------
+
+Changes
+^^^^^^^
+
+* Copy / Paste form: take care that there is now Form.id=3. This is now the reserved formId for the 'copyForm'.
+
+      UPDATE `FormElement` SET formId=100 WHERE formId=3
+      UPDATE `Form` SET `id` = '100' WHERE `Form`.`id` = 3;
+
+Bug Fixes
+^^^^^^^^^
+
+Version 0.18.3
+--------------
+
+Features
+^^^^^^^^
+
+* #3899 / Copy/Paste
+
+  * DatabaseUpdate.php: New table Clipboard, New FE.type='paste', New Form.forwardMode='url-sip' - will be applied for 0.18.3.
+  * Store.php: New member in STORE_CLIENT 'CLIENT_COOKIE_QFQ' - might be used to identify current user.
+  * formEditor.sql: New form 'copyForm'. New table 'Clipboard'
+
+
+Version 0.18.2
+--------------
+
+Changes
+^^^^^^^
+
+* Feature #3891 / Dynamic Update: Multiple Elements in a row - single show/hide - First implementation: Show / Hide via dynamicUpdate for a second element, wrapped in an own 'col-md' div.
+
+Bug Fixes
+^^^^^^^^^
+
+* Bug #3875 / FormElement 'extra': Fehler bei neuen Records.
+* Bug #3647 / Dynamic Update: Multiple Elements in a row not updated properly.
+* Bug #3890 / upload-FormElement: mode 'hide' without effect
+* Bug #3876 / upload-FormElement: verschwindet bei dynamicUpdate.
+
+Version 0.18.1
+--------------
+
+* Update unit tests
+
+Version 0.18.0
+--------------
+
+Changes
+^^^^^^^
+*  New defaults to FormElement.type=`file` (=Upload).
+
+  * `access` = `application/pdf`
+  * `maxFileSize` = `10485760` (10MB)
+
+Features
+^^^^^^^^
+
+* Make the image shown for ExtraButtonInfo configureable. Manual.rst: added documentation for new config.qfq.ini
+  variables GFX_EXTRA_BUTTON_INFO_INLINE, GFX_EXTRA_BUTTON_INFO_BELOW.
+* Manual.rst: description added for `extraButtonLock` ,`extraButtonPassword`, `extraButtonInfo`. Example on how to reuse
+  custom vars defined in `config.qfq.ini`. Add three more examples to _pdf. How to access local online documentation.
+  Add note about wkhtml only on linux boxes. More wkhtml explanations.
+* #3773 / Button: Info / Unlock / ShowPassword: FE_PARAMETER: extraButtonLock / extraButtonPassword / extraButtopnInfo.
+* #3769 / Allow specific GET variables longer than SECURITY_GET_MAX_LENGTH. config.php: implemented special handling of
+  GET vars, named with '..._<num>'.
+* #3766 / SQL_LOG per tt_content record einstellbar machen. Add `sqlLog` and `sqlLogMode` to QFQ tt-content records.
+  Add mode 'error' and `none` to sqlLogMode. Manual.rst: Added explanations for SQL_LOG, SQL_LOG_MODE, and tt-content
+  pendants sqlLog, sqlLogMode. Update config.qfq.ini to latest attributes.
+* Config.php: Set defaults for config.qfq.ini SQL_LOG and SQL_LOG_MODE
+* Manual.rst:
+* config.qfq.example.ini: Remove DB_NAME_TEST, Add some details about SQL_LOG, add example for TECHNICAL_CONTACT
+* Session.php: Activate cookie_httponly for QFQ cookies.
+* Html2Pdf.php:  recode setting of $this->logFile.
+* config.qfq.ini: new syntax for SHOW_DEBUG_INFO - [yes,no,auto][,download]
+* #3711 / Upload Button opens the camera on a smartphone. New attribute 'capture'.
+* Database.php: Add SQL keyword 'DROP'.
+* #3706 / Check File Upload: a) mime type, b) max file size. Implemented: file upload check for mime type and max file size.
+* New 'pageForward'-Mode: 'url-skip-history'.
+* FormEditor:
+
+  * Most radio FEs changed from HTML standard to Bootstrap Design.
+  * FE 'feIdContainer' will only be shown if there is at least one FE container element.
+  * Use dynamicUpdate to hide/show FE 'forwardPage'.
+  * FE 'subrecordOption' shown only for FE.type==subrecord.
+  * FE 'checkPattern' shown only for FE.checkType=='pattern|min%'.
+  * In form 'FormElement' the FE 'formId' removed - not necessary.
+
+* #3568 / Form: fuer alle Buttons (save, close, new, delete) eine optionale class & text konfigurierbar.
+* #3569 / Input Optional '0' unterdruecken.
+* #3863: New config var 'DB_UPDATE' in config.qfq.ini.
+
+Bug Fixes
+^^^^^^^^^
+
+* #3770 / Attack Delay: merge processing to one codeplace. Config.php: new function attackDetectedExitNow(). Sip.php:
+  replace local sleep(PENALTY_TIME_BROKEN_SIP) with central function attackDetectedExitNow().
+* #3768 / log to sql.log: ip, formname, feuser
+* Store.php: Fix problem that an empty SQL_LOG will be added to SYSTEM_PATH_EXT. Logger.php: do nothing if there is no
+  file defined.
+* #3751 / download FE_GROUP protected pages failed. Implement additional 'SHOW_DEBUG_INFO = download' to track down
+  problems with 'session forwarding'.
+* Allow spaces in value when selection <radio> and <select> tags.
+* #3812 / extraButtonInfo (extraButtonLock, extraButtonPassword) - Problems in TemplateGroups.
+* #3832 / Dynamic Update und Radio buttons - leerer value ( '' ) kann nicht angewählt werden
+* #3612 / Konflikt typeAheadLdap mit dynamic modesql: inputs with typeahead lacks 'dynamicUpdate' via 'modeSql'.
+* #3853 / New > Save: Reload des Forms mit neuer SIP und neu erstellter recordId.
+* #3854 / Wrong final page: a) New > Save > Close, b) New > Save > Delete, c) New > New
+  formEditor.sql: update table 'Form.forwardMode' to ('client', 'no', 'url', 'url-skip-history').
+* #2337 / Checkbox: checked/unchecked parameters genügen nicht.
+* #2542 / FormElement-Typ 'note' funktioniert nicht mit dynamic update
+* #3863 / DB Update Fails: Expected no record, got 2 rows: SHOW TABLE STATUS WHERE Name='Form'
+
+Version 0.17.0
+--------------
+
+Changes
+^^^^^^^
+
+* ALTER TABLE  `FormElement` ADD  `encode` ENUM(  'none',  'specialchar' ) NOT NULL DEFAULT  'specialchar' AFTER  `subrecordOption` ;
+* UPDATE `FormElement` SET encode='none' WHERE class='native' AND type='editor'
+
+* ALTER TABLE  `Form` ADD  `escapeTypeDefault` ENUM(  '',  's',  'd',  'l',  'L',  'm',  '-' ) NOT NULL DEFAULT  '' AFTER  `permitEdit` ;
+
+* In order to not break functionality of existing forms, it might be necessary (bad for security, good for stability) to
+  leave existing forms untouched: `UPDATE Form SET escapeTypeDefault='-'`
+
+* Play formEditor.sql
+
+Features
+^^^^^^^^
+
+* New security option `escapeTypeDefault`: will be defined 1) sytem wide in config.qfq.ini, or 2) more specific per
+  Form or 3) individually per variable. The later has priority.
+* #3544 / Form: view current form - It's now possible to direct view a form, which is currently loaded/edited in the
+   FormEditor: Button 'eye' near left of button 'save'.
+* #3552 / typeAheadLdapSearchPerToken - webpass kann nicht gleichzeitig nach Vornamen und Nachnamen suchen. Added option
+  typeAheadLdapSearchPerToken to split search value in token and OR-combine every search with the individual tokens.
+* Download latest QFQ builds and releases: https://w3.math.uzh.ch/qfq/.
+* #3218, #3600 / download.php / export: QFQ is now able to create PDFs and ZIPs on the fly. The sources might be
+  uploaded PDFs or Websites (local or remote) which will be converted to PDFs.
+* Implement 'encode=specialchar' - new option per FormElement which is now the default for every FormElement.
+* Sanatize.php: New function urlDecodeArr(). Decode all _GET vars.
+* Implemented max GET parameter lenght. Default: 50.
+* Implemented new escape class 'mysql' (realEscapeString).
+* LICENSE.txt: Add GPLv3
+* Html2Pdf.php: Add SIP support wkhtmltopdf URLs. Move cookies for wkhtmltopdf from commandline arguments to filebased.
+* SessionCookie.php: New class to save current cookies in a file.
+* Html2Pdf.php: implemented session forwarding to wkhtmltopdf.
+* Session.php: introduced close(). This will unlock the current session. Take care on subsequent calls to reopen primary session again.
+* Database.php: Set charset to real_escape_string() functions properly. Proxy for mysqli::real_escape_string()
+* Implement honeypot variables to detect bots.
+* HTML special char encode all URL GET parameter. This can't be skipped.
+
+Bug Fixes
+^^^^^^^^^
+
+* Sip.php: Parameter XDEBUG_SESSUIB_START excluded from GET parameter copied to SIP.
+* Manual.rst: add libxrender1 to install by using wkhtmltopdf.
+* Download.php: Skip 'pdftk' if there is only one PDF file to concatenate.
+* #3615 / download.php: Das Popup schliesst nicht automatisch bei ZIP, im FF, Warnung in der Console, hourglass wobbles.
+* Split PHP 'print.php' in a pure API file 'print.php' and a class 'Html2Pdf.php' - the class will be reused by Download.php
+* #3573 / TypeaheadLdap: Prefetch funktioniert nicht
+* #3547 / FE of type 'note' causes writing of empty fields.
+* #3546 / Throw of a UserFormException with wrong parameter. Fixed.
+* #3545 / Errormessages via API/JSON not displayed
+* #3536 / a) Datum (datetime / timestamp) werden nicht angezeigt, b) Angezeigte Datumsformat String und aktzeptierte Eingabe matchen nicht.
+* #3533 / afterSave: sqlUpdate auf child-record ändert xId von Hauptrecord auf 0
+
+Version 0.16
+------------
+
+Changes
+^^^^^^^
+
+* Play:
+
+    ALTER TABLE `FormElement` ADD INDEX `feIdContainer` (`feIdContainer`);
+    ALTER TABLE `FormElement` ADD INDEX `ord` (`ord`);
+    ALTER TABLE `FormElement` ADD INDEX `feGroup` (`feGroup`);
+
+    ALTER TABLE `FormElement` ADD `adminNote` TEXT NOT NULL AFTER `note`;
+
+* Play formEditor.sql
+
+Features
+^^^^^^^^
+
+* formEditor.sql:
+
+  * Added 'on update current timestamp'.
+  * Add three indexes to formEditor.sql.
+  * Column FormElement.adminNote added.
+  * Change default width on Form for subrecord FormElement.name
+  * Changed input height of 'parameter of FormEditor and FormElementEditor to 8 lines.
+
+* Enlarge placeholder value in FormElement. Old 512, New 2048.
+* #3466 / Input Typeahead: optional only allow specified input. Mode: typeAheadPedantic
+* #3465 / Save button: optional 'active after form load': `Form.parameter.saveButtonActive` - if this attribute is set,
+  the save button will be enabled directly on form load.
+* #3463 / form.mode=readonly. Make a form complete `readonly`. This can be done statically or dynamically via variable (e.g. SIP).
+* #3447 / Icons das man im FrontEnd direkt das gewaehlte FormElement im Formulareditor bearbeiten kann. Add checkbox left
+  to the 'EditForm'-Button, to toogle the 'FormElemnt'-Icons. Like the  'Form Edit'-Pencil, the 'FormElement Checkbox'
+  is only displayed if the user is logged in BE.
+* #3456 / LDAP: with Credentials (e.g. to access 'webpass'). Updated doc for a) config.qfq.ini: LDAP_1_RDN, LDAP_1_PASSWORD,
+  b) Form.parameter|FormElement.parameter: ldapUseBindCredentials
+
+  * ErrorHandler.php: removed details - the end user should not too many details.
+  * FormAction.php, Ldap.php, QuickFormQuery.php: implement 'ldapUseBindCredentials'
+  * Ldap.php: set_error_handler() to catch ldap_bind() problems. Always set LDAP_OPT_PROTOCOL_VERSION=3 - this might cause problems with som LDAP Servers - we will see.
+
+
+Bug Fixes
+^^^^^^^^^
+
+* 3509 / SELECT Element: value wird nicht selektiert
+* 3502 / TemplateGroups: Checkboxen werden beim ersten Speichern (insert) nicht geschrieben - ein anschliessendes Update
+  ist ok
+* 3385 / templateGroup: insert/update/delete non primary records
+
+  * Non primary record leads to a problem that the default values, given as an array, are not replaced by scalar values. fixed.
+  * Update doc how to insert/update/delete non primary templateGroup records.
+  * Removed $templateGroupIndex - solved implicit by defining a LIMIT on 'slaveId' . Implemented '%D' (one below %d). Implemented FE_SQL_HONOR_FORM_ELEMENTS - reduces unecassary SQL queries.
+  * Fill STORE_RECORD during Formload - to read templateGroup records very early. Local copy of `getNativeFormElements()`, new `explodeTemplateGroupElements()`
+
+* TypeAhead.js: Handle <ENTER> key properly.
+* #3462 / FormElement.parameter: requiredList not ok for non numeric content. STORE_FORM had been called without 'sanatize class'.
+   Therefore, all non numeric values has been sanatized by default. New: SANATIZE_ALLOW_ALL.
+* Corrected error message to use 'itemList' instead of 'itemValues'. Renamed constant too.
+* #2542 / FormElement-Typ 'note' funktioniert nicht mit dynamic update. 'Label' and 'note' are fixed - 'value' is still not updated, open.
+
+Version 0.15
+------------
+
+Changes
+^^^^^^^
+
+ * Play formEditor.sql.
+
+   * Form 'FormElement' failed to display the formtitle of the current form in case of a new FE.
+   * Updated subrecord in 'Form' for 'FormElements' - columns 'size' and 'sql1' removed and 'dyn' inserted. Play formEditor.sql.
+
+   *  #3431, Parameter keyword 'typeAheadLdapKeyPrintf' changed to 'typeAheadLdapIdPrintf'.::
+
+        UPDATE FormElement SET parameter = REPLACE(parameter, 'typeAheadLdapKeyPrintf', 'typeAheadLdapIdPrintf')
+
+   * Size 'placeholder' increased::
+
+        ALTER TABLE  `FormElement` CHANGE  `placeholder`  `placeholder` VARCHAR( 2048 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT  '';
+
+Features
+^^^^^^^^
+
+ * Introduce new config.qfq.ini setting 'EDIT_FORM_PAGE' - by default set to 'form' - the wrench symbol on every Form
+   will direct to that page. Fix #3420 / Quicklink 'editform' on form: directs to the current T3 page which might be insufficient.
+ * Form 'subrecord' columns: the default width limit of 20 chars are disabled if 'nostrip' is specifed.
+ * #3431 / typeAheadSql: columnname 'key' is a reserverd SQL statement - replace by 'id'. Additional the parametername
+   'typeAheadLdapKeyPrintf' renamed to 'typeAheadLdapIdPrintf'. By using 'id' instead of 'key' the quoting of the columnname
+   is not necessary anoymore.
+
+
+
+Bug Fixes
+^^^^^^^^^
+
+ * Fix #3419 / typeAheadSql: Array with only one column or non standard columnnames are not handeld properbly.
+   Detection of missing LIMIT implemented.
+ * #3425 / Form.parameter, FormElement.parameter: comment handling, trailing & leading spaces
+    Manual.rst: commented handling of 'comment character' and 'escaping of leading/trailing spaces'
+    Support.php: new funtion handleEscapeSpaceComment().
+ * Evaluate.php: parse all F|FE.parameter via handleEscapeSpaceComment(). A leading '#' or ' ' might be escaped by '\'.
+ * Saving 'extra' FE in STORE_SIP has been done with inappropiate FE_NAME. Correct is the pure FE_NAME, without any
+   extension like recordId. Unessary and broken decoding removed.
+ * #3426 | Dynamic Update: Inputs loose the new content and shows the old value
+ * Through fix #2064 the FE.checkType has not been used anymore. This is fixed now.
+ * #3433 | templateGroup on primary Record: Values of removed copies are not deleted. The new implementation creates empty
+   fake instances of all copies of templateGroup FormElements. Those are empty. Before save, the submitted form values
+   will be expanded with the empty fake templateGroup FormElements and such empty values will be saved.
+
+
+Version 0.14
+------------
+
+Changes
+^^^^^^^
+
+ * Play formEditor.sql.
+
+   * All Form & FormEditor input elements now have a maxlength definition of 0, which means take the column definition value.
+   * Drop-down list of container assignment:
+
+     * Display 'type' ('pill', 'fieldset', 'templategroup') instead of 'class' (always 'container').
+     * Display 'name' (internal name) instead of 'label' (shown on the website and might not so usefull as 'name' which is nowhere else used than in that drop-down.
+
+   * FormElement.placeholder colum width extended to 512:
+
+     ALTER TABLE `FormElement` CHANGE `placeholder` `placeholder` VARCHAR(512) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ''
+
+ * New class Ldap.php.
+
+Features
+^^^^^^^^
+
+ * Typeahead for SQL and LDAP Datasources implemented.
+ * formEditor.sql: Changed width of column FormElement.placeholder from 255 to 512. Removed hardcoded 'size' in FormElement 'placeholder'.
+ * Character Count: Display a `counter` on input or textarea fields, activated by specifying the formElement.parameter 'characterCountWrap'.
+ * Evaluate.php: Two new escape options 'l' and 'L'. Backport of ldap_escape() for PHP <5.6. Multiple escaping for one value now possible.
+ * Manual.rst: add some example for TypeAhead and for saving LDAP value.
+ * Load foreign values in templatGroups - saving is not implemented yet.
+ * Manual: Added howto prevent <p>-wrap in TinyMCE
+ * TemplateGroup: Add button now disabled if max. number of copies reached.
+ * #3414/QuickFormQuery.php: wrap whole form in 'col-md-XX' - User controls the width of an QFQ form.
+
+Bug Fixes
+^^^^^^^^^
+
+ * Dynamic Update has been broken since implementing of 'element-update' (#3180). Now both methods, 'element-update' and 'form-update' should be fine.
+ * qfq-bs.css.less: Fixed problem with 'typeahead input elements' not expanded to Bootstrap column width. Changed
+   Layout/Design Typeahead drop-down box. Add hoover for the drop-down box with a blue background
+ * AbstractBuildForm.php: #3374 - textarea elements now contains 'maxlength' attribute.
+ * BuildFormBootstrap.php: wrapping of optional 'submitButtonText' now done with the 'per form' values.
+ * typeahead.php: if there is an exception, the message body is sent as regular 'content' for the drop-down box. At the
+   moment this is the only way to transmit any error messages.
+ * formEditor.sql: removed all 'maxLength' string values for 'Form' and 'FormElement' forms.
+ * Save button becomes active if a templateGroup copy is removed.
+ * #3413 Form ohne Pill hat kein padding am Rand. Fix: if there are no pills, an additinal col-md-12 will be rendered.
+
+
+Version 0.13
+------------
+
+Changes
+^^^^^^^
+
+ * Play formEditor.sql.
+ * formEditor.sql:
+
+   * Checktype of `Form.name` restricted to `alnumx` (prior `all`).
+   * Changed `access` for Form `form` & '`ormElement` from `always` to `sip`.
+
+ * Table `FormElement`
+
+   * Modified column: `checkType` - new value `numerical`
+
+     ALTER TABLE FormElement MODIFY COLUMN checkType ENUM('alnumx','digit','numerical','email','min|max','min|max date',
+       'pattern','allbut','all') NOT NULL DEFAULT 'alnumx'
+
+ * Example Report for `forms` extended by a delete button per row.
+
+Features
+^^^^^^^^
+
+ * print.php: offers 'print page' for any local page - create a PDF on the fly (printout is then browser independent).
+
+   * Install `wkhtmltopdf` on the webserver (http://wkhtmltopdf.org/).
+   * In config.qfq.ini setup:
+
+        BASE_URL_PRINT=http://www.../
+        WKHTMLTOPDF=/opt/wkhtmltox/bin/wkhtmltopdf
+
+ * Check and error report if 'php_intl' is missing.
+ * New Checktype 'allow numerical'.
+ * Documentation: example for 'radio' with no pre selection.
+ * #3063, Radios and checkboxes optional rendered in Bootstrap layout.
+ * Added 'help-box with-errors'-DIV after radios and checkboxes.
+ * Respect attribute `data-class-on-change` on save buttons.
+
+
+Bug Fixes
+^^^^^^^^^
+
+ * #2138 / digit sanitize: new class 'numerical' implemented.
+ * Fixed recursive thrown exception.
+ * #2064 / search of a default value for a non existing tablecolumn returns 'false'.
+
+   * Fixed setting of STORE_SYSTEM / showDebugInfo during API call.
+
+ * #2081, #3180 Form: Label & note - update via `DynamicUpdate`
+ * #3253, if there is no STORE_TYPO3 (calls through .../api/ like save, delete, load): use SIP / CLIENT_TYPO3VARS.
+ * qfq-bs.css:
+
+   * Alignment of checkboxes and radios optimized.
+   * CSS class 'qfq-note' for 'notes' (third column in a form).
+
+
+Version 0.12
+------------
+
+Changes
+^^^^^^^
+
+ * Table 'FormElement'
+   * New column: rowLabelInputNote
+
+      ALTER TABLE  `FormElement` ADD `rowLabelInputNote` set('row','label','/label','input','/input','note','/note','/row')
+      NOT NULL DEFAULT 'row,label,/label,input,/input,note,/note,/row' AFTER  `bsNoteColumns` ;
+
+   * Modified column: 'type' - new value 'templateGroup'
+
+      ALTER TABLE  `FormElement` CHANGE  `type`  `type` ENUM(  'checkbox',  'date',  'datetime',  'dateJQW',  'datetimeJQW',  'extra',
+      'gridJQW',  'text',  'editor',  'time',  'note',  'password',  'radio',  'select',  'subrecord',  'upload',  'fieldset', 'pill',
+      'templateGroup',  'beforeLoad',  'beforeSave',  'beforeInsert',  'beforeUpdate',  'beforeDelete',  'afterLoad',  'afterSave',
+      'afterInsert',  'afterUpdate',  'afterDelete',  'sendMail' ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT  'text'
+
+ * formEditor.sql: Added HTML 'placeholder' in FormEditor for bs*Columns.
+
+   * PLAY 'formEditor.sql'.
+
+ * User Input will be UTF8 normalized.
+
+   * INSTALL 'php5-intl' or 'php7.0-intl' on Webserver.
+
+ * Add globalize.js to be included. Needed by jqx-all.js
+
+   * UPDATE EXISTING TypoScript TEMPLATES of QFQ Installation.
+
+ * Name of variable '_filename' (used in field 'parameter') has changed. Old: '_filename', New: 'filename'
+
+   * UPDATE `FormElement` SET parameter = REPLACE(parameter, "_filename", "filename")
+
+
+Features
+^^^^^^^^
+
+ * User input will be UTF8 normalized
+ * config.qfq-ini:
+   * New configuration values: FORM_BS_LABEL_COLUMNS / FORM_BS_INPUT_COLUMNS / FORM_BS_NOTE_COLUMNS
+   * Comment empty variables - the new default setting is, that empty parameter in config.qfq.ini means EMPTY (=parameter is set and will not be overwritten by internal default), not UNDEFINED (overwritten by internal default).
+ * FileUpload:
+   * Implemented new Formelement.parameter: fileReplace=always - will replace existing files.
+   * Multiple / Advanced Upload: new logic implements slaveId, sqlInsert, sqlUpdate, sqlDelete.
+ * FormElement.parameter: sqlBefore / sqlAfter fired during 'Form' save for action elements.
+ * STORE FORM: variable 'filename' moved to STORE VAR - sanatize class needs no longer specified.
+ * STORE VAR: two new variables 'filename' and 'fileDestination' valid during processing of current upload FormElement.
+ * Default store priority list changed. Old: 'FSRD', New: 'FSRVD'.
+ * CODING.md: update doc for FormElement 'upload' and general 'Form' rendering & save (recursive rendering).
+ * User manual:
+   * Described form layout options: description for bsLabelColumn, bsInputColumn, bsNoteColumn
+   * Update 'file-upload' doc.
+   * Described 3 examples for upload forms.
+ * Administrator manual:
+   * Add description page.meta...
+ * New FormElement (type= 'container') added: 'templateGroup'
+   * FormElement.parameter.tgAddClass | tgAddText | tgRemoveClass | tgRemoveText | tgClass
+   * FormElement.maxSize: max number of duplicates
+   * #3230 templateGroup: margin between copies. 'tgClass' implemented.
+ * Native FormElements:
+   * FormElement.parameter.htlmlBefore|htmlAfter - add the specified HTML code before or after the element (outside of any wrapping)
+   * #3224, #3231 Html Tag <hr> als FormElement. >> htmlBefore | htmlAfter.
+   * FormElement.parameter.wrapLabel | wrapInput | wrapAfter | wrapRow - if specified, any default wrapping is omitted.
+   * FormElement.bsNoteColumns | bsInputColumns | bsNoteColumns - a '0' will suppress the whole rendering of the item.
+   * FormElement.rowLabelInputNote - switch on/off rendering of the corresponding system wrapping items.
+ * #3232 Define custom 'on-change' color - used for the save button: Form.parameter.buttonOnChangeClass=...
+ * Form.parameter & FormElement.parameter: Lines starting with '#' are treated as comments and will not be parsed.
+
+Bug fixes
+^^^^^^^^^
+
+ * User manual:
+   * Fixed double include of validator.js in T3 Typoscript template example.
+   * Fixed wrong store name SYSTEM: S > Y
+   * Fixed wrong STORE_FORM variable names.
+   * Reformat FormElement.parameter description.
+   * Styling errors fixed.
+ * Use of 'decryptCurlyBraces()' to get better error messages.
+ * Skip unwanted parameter expansion during save.
+ * Fixed bug with uninitialized FE_SLAVE_ID
+ * formEditor.sql:
+   * The defintion as 'editor' (not text) for FormElement 'note' has been lost - reinserted.
+   * Fixed problem while playing SQL query - deleting old FormElements of Formeditor deleted also FormElements of other forms.
+ * #3066 / help-text with-error - CSS class 'hidden' will be rendered by default (as long there is no error).
+ * Labels are skipped, if FormElement.bsLabelColumns=0.
+ * Respect attribute `data-class-on-change` on save buttons.
+
+Version 0.11
+------------
+
+Features
+^^^^^^^^
+
+ * Added STORE_BEFORE, #3146 - Mainly used to compare old and new values during a form 'save' action.
+ * Added 'best practice' for defining and using of 'Central configure values' in UserManual.
+ * Added accent characters to sanatize class 'alnumx', #3183.
+ * Set default all QFQ send mails to 'auto-submit'.
+ * Added possibility to customize error messages ('data-pattern-error', 'data-rquired-error', 'data-match-error',
+   'data-error') if validation fails. Customization can be done on global level (config.qfq.ini), per Form or per FormElement.
+ * *FormElement*: Double an input element and validate that the input match: FormElement.parameter.retype=1
+ * Autofocus in Forms is now supported. By default the first Input Element receives the focus. Can be customized.
+ * Added a timestamp in shown exceptions. Usefull for screenshots, send by customer, to find the problem in SQL logfiles.
+
+Bug fixes
+^^^^^^^^^
+
+ * Fixed missing docutmentation for FormElement 'note'.
+ * Failed SQL queries will now always be logged, even if they do not modify some data.
+
+Version 0.10
+------------
+
+Features
+^^^^^^^^
+
+ * Implemented Parameter 'extraDeleteForm' for 'forms' and 'subrecords'. Update doc.
+
+Bug fixes
+^^^^^^^^^
+
+ * Suppress rendering of form title during a 'delete' call. No one will see it and required parameters are not supplied.
+ * In case of broken SQL queries, print them in ajax error message.
+ * Remove parameter 'table' from Delete SIP URLs. ToolTip updated.
+
+Version 0.9
+-----------
+
+Features
+^^^^^^^^
+
+ * FormEditor:
+   * design update - new default background color: grey.
+   * per form configureable background colors.
+   * Optional right align of all form element labels.
+   * Added config.qfq.ini values CSS_CLASS_QFQ_FORM_PILL, CSS_CLASS_QFQ_FORM_BODY, CSS_CLASS_QFQ_CONTAINER.
+
+Bug fixes
+^^^^^^^^^
+
+ * BuildFormBootstrap.php: added new class name 'qfq-label' to form labels - needed to assign 'qfq-form-right' class. Changed wrapping of formelements from 'col-md-8' (wrong) to 'col-md-12'.
+ * QuickFormQuery.php: Set default for new F_CLASS_PILL & F_CLASS_BODY.
+ * formEditor.sql: New default background color for formElements is blue.
+ * qfq-bs.css.less: add classes qfq-form-pill, qfq-form-body, form-group (center), qfq-color-..., qfq-form-right.
+ * Index.rst: Add note to hierachy chars. Fixed uncomplete doc to a) bs*Columns, showButton. Add classPill, classBody. Rewrote form.paramter.class.
+ * QuickFormQuery.php: Button save/ close/ delete/ new - align to right border of form.
+ * UsersManual/index.rst: renamed chapter for formelements. Cleanup formelement types. Wrote chapter 'Detailed concept'.
+ * QuickFormQuery.php, FormAction.php: '#2931 / afterSave Hauptrecord xId nicht direkt verfügbar' - load master record again, after 'action'-elements has been processed.
+ * UsersManual/index.rst: Startet FAQ section.
+ * config.qfq.example.ini: Added comment where to save config.qfq.ini.
+ * UsersManual/index.rst: Rewrite of 'action'-FormElement definition.
+ * #2739: beforeDelete / afterDelete.
+ * PROTOCOL.md: update 'delete' description.
+ * delete.php: fixed unwanted loose of MSG_CONTENT.
+ * Report.php: Fixed double '&&' in building UrlParam.
+ * FormAction.php: In case of 'AFTER_DELETE', do not try to load primary record - that one is already deleted.
+ * Sip.php: Do not skip SIP_TARGET_URL as parameter for the SIP.
+ * #3001 Report: delete implementieren.
+ * Index.rst, Constants.php: reverted parameter '_table' in delete links back to 'table' - Reason: 'form' needs to be 'form' (instead of '_form') due to many used places already.
+ * Sip.php: move SIP_TARGET_URL back to stored inside SIP - it's necessary for 'delete'-links.
+ * Report.php, Constants.php: Remove code to handle unecessary 'p:' tag for delete links.
+ * Link.php: Check paged / Paged that the parameter r, table and form are given in the right combination.
+ * Link.php, Report.php: New '_link' token 'x'. '_paged' and '_Paged' are rendered via Link() class, Link() class now supports delete links.
+ * QuickFormQuery.php: for modeForm='Form Delete' the 'required param' are not respected - this makes sense, cause these parameters typically filled in newly created records.
+ * Fixed: #3076 Delete Button bei Subrecords erzeugt sporadisch Javascript Exceptions (Webkit: Chrome / Vivaldi) - kein loeschen moeglich.
diff --git a/README.md b/README.md
index 7e86745bdd72ae96f916111b10a42dbaaf88b5f0..3eca9b17ef0e96cafe276081ea542dd5a156bef3 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-QFQ: Typo3 Extbase Extension
-===============================
+QFQ: Quick Form Query - Typo3 Extbase Extension
+===============================================
 
 Version: see `extension/ext_emconf.php`
 
@@ -20,7 +20,9 @@ See: https://w3.math.uzh.ch/qfq/
 Documentation
 -------------
 
-a) See the documentation provided with the exentions inside Typo3
+Latest stable version under https://docs.typo3.org/typo3cms/drafts/github/T3DocumentationStarter/Public-Info-053/Index.html
+
+Local: See the documentation provided with the exentions inside Typo3
  <your Typo3 installation>/typo3conf/ext/qfq/Documentation/html/Index.html
 
 If you get a 'Page forbidden / not found' there might be some Webserver restrictions. E.g. the Typo3 example of `.htaccess`
@@ -32,6 +34,4 @@ server). For a development server instead, activate the documentation. `.htacces
   development:  RewriteRule (?:typo3conf/ext|typo3/sysext|typo3/ext)/[^/]+/(?:Configuration|Resources/Private|Tests?|docs?)/ - [F]
 </pre>  
  
-b) Latest stable version under https://docs.typo3.org/typo3cms/drafts/github/T3DocumentationStarter/Public-Info-053/Index.html
-
 
diff --git a/doc/CODING.md b/doc/CODING.md
index 2f7ec1cb5ffd944db162b8e5bf4f76f2f6e752bb..5f6cd691b6bc6a6d806b9f58a8cf2c648251f09a 100644
--- a/doc/CODING.md
+++ b/doc/CODING.md
@@ -155,7 +155,7 @@ Upload
   browse button and to the upload delete button.  
   * The individual sipUpload is necessary to correctly handle multiple simultaenously forms when using r=0. Also, through 
     this uniq id it's easy to distinguish between asynchron uploaded files.
-  * The SIP on ther server contains the individual '_FILES' information submitted during the upload.
+  * The SIP on the server contains the individual '_FILES' information submitted during the upload.
 * Via the hidden element <feName> 'save()', access to the form individual upload status informations is given. 
 
 Upload to server, before 'save'
@@ -171,12 +171,12 @@ Upload to server, before 'save'
     [STORE_EXTRA][<uploadSip>][FILES_NAME]
     [STORE_EXTRA][<uploadSip>][FILES_ERROR]
     [STORE_EXTRA][<uploadSip>][FILE_SIZE]
-* Clicks the user on delete button:
+* Clicks the user on the delete button:
   * In the usersession a flagDelete will be set: 
      [STORE_EXTRA][<uploadSip>][FILES_FLAG_DELETE]='1'
   * An optional previous upload file (still not saved on the final place) will be deleted.
   * An optional existing variable [STORE_EXTRA][<uploadSip>][FILES_TMP_NAME] will be deleted. The 'flagDelete' must not 
-    be change - it's later needed to detect to delete, earlier uploaded files.
+    be change - it's later needed to detect to delete, of earlier uploaded files.
 
 Form save
 .........
diff --git a/doc/NewVersion.md b/doc/NewVersion.md
index 0d48f6e5f1b66e67e11530156feda2105a73754d..94370a81f2e1ed0e8ea1c5b4d7521aaca7c2983e 100644
--- a/doc/NewVersion.md
+++ b/doc/NewVersion.md
@@ -13,10 +13,14 @@ Neue Versionsnummer
 
 2) Die aktuellen Commits anschauen und wichtige Topics uebernehmen (git log > ~/qfq.log, alles bis zum letzten TAG anschauen):
 
-   * git log | grep -v -e '^commit ' -e  '^Author: ' -e '^Date: ' -e '^Merge: ' > /tmp/out; pluma  /tmp/out
+   # complicated: * git log | grep -v -e '^commit ' -e  '^Author: ' -e '^Date: ' -e '^Merge: ' > /tmp/out; pluma  /tmp/out
+   
+   # Zeigt alle Commits an, die seit dem aendern von NewVersion gemacht wurden! Das sollten alle Commits seit der letzten Version sein.
+   * git log --pretty=%s --after="`stat -c %y doc/NewVersion.md`"
 
    * qfq/extension/Documentation/Release.rst  
    * Den Inhalt von Release.rst kopieren nach qfq/extension/RELEASE.txt.
+   * Den Inhalt von Release.rst kopieren nach CHANGELOG.md.
 
 3) In folgenden Files anpassen:
 
@@ -33,12 +37,14 @@ Neue Versionsnummer
 
 5) Commit
    * Update the version number in this document (topic 6)
-   * Commit & Push new version changes to master branch: New version x.y.z.
+   * Commit & Push new version changes to master branch: 
+   
+      New version x.y.z.
 
 6) New Tag: 
 
-   git tag v0.19.6
-   git push -u origin v0.19.6
+   git tag v0.23.1
+   git push -u origin v0.23.1
 
 7) PhpStorm: Sync all files to VM qfq.
 
@@ -52,3 +58,5 @@ https://docs.typo3.org/typo3cms/drafts/github/T3DocumentationStarter/Public-Info
 2) In `qfq-doc` Projektverzeichnis wechseln und auf github einchecken:
    git commit -a
    git push        # User: math-uzh, PW: <kpit>
+
+one line:  make update-qfq-doc; pushd ../qfq-doc; git commit -a; git push; popd
\ No newline at end of file
diff --git a/extension/Documentation/Manual.rst b/extension/Documentation/Manual.rst
index 826c3f38f6c1fa8056debd5e382008dea32c6a68..a2587867138031bd24baa03d3e8a066a6d003f1d 100644
--- a/extension/Documentation/Manual.rst
+++ b/extension/Documentation/Manual.rst
@@ -77,8 +77,10 @@ wkhtmltopdf
 `wkhtmltopdf <http://wkhtmltopdf.org/>`_ will be used by QFQ to offer 'website print' and 'HTML to PDF' conversion.
 The program is not included in QFQ and has to be manually installed.
 
-* The Ubuntu package `wkhtmltopdf` needs a running Xserver - this does not work on a headless webserver. Best is to
-  install the QT version from the named website above.
+* The Ubuntu package `wkhtmltopdf` needs a running Xserver - this does not work on a headless webserver.
+
+  * Best is to install the QT version from the named website above.
+  * In case of trouble with wkhtmltopdf, also install 'libxrender1'.
 
 In `config-qfq-ini`_ specify the:
 
@@ -296,9 +298,13 @@ config.qfq.ini
 | SECURITY_GET_MAX_LENGTH     | SECURITY_GET_MAX_LENGTH = 50                    | GET vars longer than 'x' chars triggers an `attack-recognized`.            |
 |                             |                                                 | `ExceptionMaxLength`_                                                      |
 +-----------------------------+-------------------------------------------------+----------------------------------------------------------------------------+
-|GFX_EXTRA_BUTTON_INFO_INLINE | <img src="info.png">                            | Image for `extraButtonInfo`_ (inline)                                      |
+| GFX_EXTRA_BUTTON_INFO_INLINE| <img src="info.png">                            | Image for `extraButtonInfo`_ (inline)                                      |
++-----------------------------+-------------------------------------------------+----------------------------------------------------------------------------+
+| GFX_EXTRA_BUTTON_INFO_BELOW | <img src="info.png">                            | Image for `extraButtonInfo`_ (below)                                       |
 +-----------------------------+-------------------------------------------------+----------------------------------------------------------------------------+
-|GFX_EXTRA_BUTTON_INFO_BELOW  | <img src="info.png">                            | Image for `extraButtonInfo`_ (below)                                       |
+| EXTRA_BUTTON_INFO_POSITION  | SYSTEM_EXTRA_BUTTON_INFO_POSITION=below         | 'auto' (default) or 'below'. See `extraButtonInfo`_                        |
++-----------------------------+-------------------------------------------------+----------------------------------------------------------------------------+
+| EXTRA_BUTTON_INFO_CLASS     | SYSTEM_EXTRA_BUTTON_INFO_CLASS=pull-right       | '' (default) or 'pull-right'. See `extraButtonInfo`_                       |
 +-----------------------------+-------------------------------------------------+----------------------------------------------------------------------------+
 | SAVE_BUTTON_TEXT            | SAVE_BUTTON_TEXT =                              | Default text on the form save button. Typically none.                      |
 +-----------------------------+-------------------------------------------------+----------------------------------------------------------------------------+
@@ -429,13 +435,18 @@ Example: *typo3conf/config.qfq.ini*
 
 	;RECORD_LOCK_TIMEOUT_SECONDS = 900
 
-    ; Local Documentation (doc fits to installed version):  typo3conf/ext/qfq/Documentation/html/Manual.html
+	; Local Documentation (doc fits to installed version):  typo3conf/ext/qfq/Documentation/html/Manual.html
 	;DOCUMENTATION_QFQ = https://docs.typo3.org/typo3cms/drafts/github/T3DocumentationStarter/Public-Info-053/Manual.html
 
-    ;VAR_ADD_BY_SQL = {{!SELECT s.id AS _periodId FROM Period AS s WHERE s.start<=NOW() ORDER BY s.start DESC LIMIT 1}}
+	;VAR_ADD_BY_SQL = {{!SELECT s.id AS _periodId FROM Period AS s WHERE s.start<=NOW() ORDER BY s.start DESC LIMIT 1}}
+
+	;FORM_LANGUAGE_A_ID = 1
+	;FORM_LANGUAGE_A_LABEL = english
 
-    ;FORM_LANGUAGE_A_ID = 1
-    ;FORM_LANGUAGE_A_LABEL = english
+	;GFX_EXTRA_BUTTON_INFO_INLINE = <img src='info.png'>
+	;GFX_EXTRA_BUTTON_INFO_BELOW = <img src='info.png'>
+	;EXTRA_BUTTON_INFO_POSITION = auto | below
+	;EXTRA_BUTTON_INFO_CLASS = pull-right
 
 .. _`CustomVariables`:
 
@@ -1210,6 +1221,8 @@ Store: *TYPO3* (Bodytext) - T
  +-------------------------+-------------------------------------------------------------------+----------+
  | feUserGroup             | FE groups of logged in Typo3 FE User                              |          |
  +-------------------------+-------------------------------------------------------------------+----------+
+ | beUserLoggedIn          | 'yes' | 'no' - Status if a BE-User is logged in                   |          |
+ +-------------------------+-------------------------------------------------------------------+----------+
 
 * **note**: not available:
 
@@ -1619,7 +1632,9 @@ Definition
 +-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
 |Table                    | Primary table of the form. _`form-tablename`                                                                                                       |
 +-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
-|Required Parameter       | Name of required SIP parameter, seperated by comma. '#' as comment delimiter. See `form-requiredParameter`_                                        |
+|Required Parameter NEW   | Name of required SIP parameter to create a new record (r=0), separated by comma. '#' as comment delimiter. See `form-requiredParameter`_           |
++-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
+|Required Parameter EDIT  | Name of required SIP parameter to edit an existing record (r>0), separated by comma. '#' as comment delimiter. See `form-requiredParameter`_       |
 +-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
 |Permit New               | 'sip, logged_in, logged_out, always, never' (Default: sip): See `form-permitNewEdit`_                                                              |
 +-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
@@ -1629,9 +1644,9 @@ Definition
 +-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
 |Show button              | 'new, delete, close, save' (Default: 'new,delete,close,save'): Shown named buttons in the upper right corner of the form.  See `form-showButton`_  |
 +-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
-|Forward                  | 'client | no | url | url-skip-history' (Default: client): See `form-forward`_.                                                                     |
+|Forward Mode             | 'client | no | url | url-skip-history' (Default: client): See `form-forward`_.                                                                     |
 +-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
-|Forward Page             | URL or Typo3 page id/alias. See `form-forward`_.                                                                                                   |
+|Forward (Mode) Page      | a) URL / Typo3 page id/alias or b) Forward Mode (via '{{...}}') or combination of a) & b). See `form-forward`_.                                    |
 +-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
 |Parameter                |  Misc additional parameters. See `form-parameter`_.                                                                                                |
 +-------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
@@ -1703,12 +1718,21 @@ Depending on `r`, the following access permission will be taken:
 
 .. _`form-requiredParameter`:
 
-Required Parameter
-^^^^^^^^^^^^^^^^^^
+Required Parameter NEW|EDIT
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Comma separated list of variable names. On form load, an error message will be shown in case of missing parameters.
+The parameters must be given by SIP.
+
+The list of required parameter has to be defined for 'NEW' (r=0, create a new record) and for 'EDIT' (r>0, edit existing
+record).
 
-Comma separated list of variable names. The form will show an error message, if it was called without the named
-parameters. Especially subforms often requires additional parameters - if such parameters are missing, the record cannot
-saved correctly. The parameters must be given by SIP.
+Optional a comment might be attached to the parameter, direct after the parameter name. The comment should not contain any ','.
+
+E.g.: ::
+
+  NEW: grId, pId # Always specify a person, grId2
+  EDIT: pId
 
 .. _`form-showButton`:
 
@@ -1729,33 +1753,65 @@ Display or hide the button `new`, `delete`, `close`, `save`.
 Forward: Save / Close
 ^^^^^^^^^^^^^^^^^^^^^
 
-Forward
-'''''''
+Forward (=forwardMode)
+''''''''''''''''''''''
 
 After the user presses *Save*, *Close*, *Delete* or *New*, different actions are possible where the browser redirects to.
 
-* `client` (default) - the QFQ Javascript logic, inside the browser, decides to stay on the page or to force a redirection 
+* `client` (default) - the QFQ browser Javascript logic, decides to stay on the page or to force a redirection
   to a previous page.
   
-  * *Close* closes the current page and goes back to the previous page.
+  * *Close* closes the current page and goes back to the previous page. Note: if a new tab is opened and the user presses
+    QFQ close (in any way) - in that new browser tab there is no previous page! QFQ won't close the tab, instead a message
+    is shown
   * *Save* stays on the current page.
   
 * `no` - no change, the browser remains on the current side. Close does not close the page. It just triggers a save if 
   there are modified data.
-* `url` - the browser redirects to the named URL or T3 page. Independent if the user presses `save` or `close`.
+* `url` - the browser redirects to the URL or T3 page named in `Forward URL / Page`. Independent if the user presses `save` or `close`.
 * `url-skip-history` - same as `url`, but the current location won't saved in the browser history.
 
 Only with `Forward` == `url` | `url-skip-history`, the definition of `Forward URL / Page` becomes active.
 
-Forward URL / Page
-''''''''''''''''''
+Forward URL / Page (=forwardPage)
+'''''''''''''''''''''''''''''''''
+
+Format: [<url>] or [<mode>|<url>]
+
+* `<url>`:
+
+  * `http://www.example.com/index.html?a=123#bottom`
+  * `website.html?a=123#bottom`
+  * `?<T3 Alias pageid>&a=123#bottom, ?id=<T3 page id>&a=123#bottom`
+  * `{{SELECT ...}}`
+  * `<mode>|<url>`
+
+* `<mode>` - Valid keywords are as above: `no|client|url|url-skip-history`
+
+Specifying the mode in `forwardPage` overwrites `formMode` (but only if `formMode` is `url...`).
+
+Also regular QFQ statements like {{var}} or {{SELECT ...}} are possible in `forwardPage`. This is useful to dynamically
+redirect to different targets, depending on user input or any other dependencies.
+
+If a forwardMode 'url...' is specified and there is no `forwardPage`, QFQ falls down to `client` mode.
+
+On a form, the user might click 'save' or 'save,close' or 'close' (with modified data this leads to 'save,close').
+The CLIENT `submit_reason` shows the user action:
+
+* `{{submit_reason:CE:alnumx}}` = `save` or `save,close`
+
+Example forwardPage
+^^^^^^^^^^^^^^^^^^^
+
+* `{{SELECT IF('{{formModeGlobal:S:anumx}}'='requiredOff', 'no', 'client') }}`
+* `{{SELECT IF('{{submit_reason:CE:alnumx}}'='save', 'no', 'url'), '|http://example.com' }}`
+
+Type: combined dynamic mode & URL/page
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-Possible values:
+Syntax: `forwardPage=<mode>|<page>`
 
-* `http://john-doe.com` - fix URL.
-* `?thanks` - fix URL, inside current Typo3 installation.
-* `{{SELECT ... }}` - dynamically calculated, after all processing is done. This is very usefull, to redirect to different
-  targets, depending on user input or whatever.
+* `forwardPage={{SELECT IF(a.url='','no','url'), '|', a.url FROM address AS a }}`
 
 
 .. _form-parameter:
@@ -1817,7 +1873,7 @@ parameter
 | typeAheadMinLength          | int    | Minimum number of characters which have to typed to start the search.                                    |
 +-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
 | mode                        | string | The value `readonly` will activate a global readonly mode of the form - the user can't change any data.  |
-|                             |        | See :ref:`form-mode-readonly`                                                                            |
+|                             |        | See :ref:`form-mode-global`                                                                              |
 +-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
 | saveButtonActive            | -      | Make the 'save'-button active on *Form* load (instead of waiting for the first user change)              |
 +-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
@@ -1853,6 +1909,8 @@ parameter
 +-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
 | newButtonGlyphIcon          | string | Overwrite default from config.qfq.ini: NEW_BUTTON_GLYPH_ICON                                             |
 +-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
+| extraButtonInfoClass        | string | Overwrite default from config.qfq.ini: EXTRA_BUTTON_INFO_CLASS                                           |
++-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
 
 * Example:
 
@@ -1922,10 +1980,10 @@ The 'extraDeleteForm' parameter might be specified for a 'form' and/or for 'subr
 
 See also: `delete-record`_.
 
-.. _form-mode-readonly:
+.. _form-mode-global:
 
-Global Form mode 'readonly'
-'''''''''''''''''''''''''''
+Form mode global - 'readonly'
+'''''''''''''''''''''''''''''
 
 The form.parameter setting `mode=readonly` will switch the whole form into a `readonly` mode, which is a fast way to use
 an existing *Form* just to display the form data, without a possibility for the user to change any data of the form.
@@ -1985,12 +2043,21 @@ Type: pill
 * Pill is synonymous for a tab. A pill looks like a tab.
 * Pills are only available with mode render='bootstrap'.
 * If there is at least one pill defined, every native *FormElement* needs to be assigned to a pill or to a fieldset.
-* If there is at least one pill defined, every fieldset needs to be assigned to a pill.
+* If there is at least one pill defined, every *fieldset* needs to be assigned to a pill.
+* Pills are not 'dynamicUpdate' aware (at the moment). At least during form load, *modeSql* can be dynamically computed to
+  switch the pill in show / readonly (disabled) / hidden state.
 
 * FormElement settings:
 
   * *name*: technical name, used as HTML identifier.
   * *label*: Label shown on the corresponding pill button or inside the drop-down menu.
+  * *mode*:
+
+    * *show*, *required*: regular mode. The pill will be shown.
+    * *readonly*: the pill and it's name is visible, but not clickable.
+    * *hidden*: the pill is not shown at all.
+
+  * *modeSql*:
   * *type*: *pill*
   * *feIdContainer*: `0`  - Pill's can't be nested.
   * *parameter*:
@@ -2088,6 +2155,7 @@ Fields:
 |Name                 | string                      |                                                                                                     |
 +---------------------+-----------------------------+-----------------------------------------------------------------------------------------------------+
 |Label                | string                      | Label of *FormElement*. Depending on layout model, left or on top of the *FormElement*              |
+|                     |                             | Additional label description can be added by wrapping in HTML tag '<small>'                         |
 +---------------------+-----------------------------+-----------------------------------------------------------------------------------------------------+
 |Mode                 | enum('show', 'readonly',    | *Show*: regular user input field. This is the default.                                              |
 |                     | 'required',                 | *Required*: User has to specify a value. Typically, an <empty string> represents 'no value'.        |
@@ -2166,6 +2234,20 @@ to edit, on the same form, a corresponding person email address (which is in a s
 
   {{SELECT a.email FROM Address AS a WHERE a.pId={{id:R0}} ORDER BY a.id LIMIT 1}}
 
+FE: 'Report' notation
+^^^^^^^^^^^^^^^^^^^^^
+
+The FE fields 'value' and 'note' understand the `Report`_ syntax. Nested SQL queries as well as links with SIP encoding
+are possible. To distinguish between 'Form' and 'Report' syntax, the first line has to be `#!report` ::
+
+    #!report
+
+    10.sql = SELECT ...
+
+    20 {
+      sql = SELECT ...
+      5.sql = SELECT ...
+    }
 
 .. _fe-parameter-attributes:
 
@@ -2201,7 +2283,9 @@ See also at specific *FormElement* definitions.
 +------------------------+--------+----------------------------------------------------------------------------------------------------------+
 | extraButtonPassword    | none   | No value. Show an 'eye' on the right side of the input element. See `extraButtonPassword`_               |
 +------------------------+--------+----------------------------------------------------------------------------------------------------------+
-| extraButtonInfo        | string | Text. Show a 'i' on the right side of the input element. See `extraButtonInfo`_                          |
+| extraButtonInfo        | string | Text. Show an 'i' on the right side of the input element. See `extraButtonInfo`_                         |
++------------------------+--------+----------------------------------------------------------------------------------------------------------+
+| extraButtonInfoClass   | string | By default empty. Specify any class to be assigned to wrap extraButtonInfo                               |
 +------------------------+--------+----------------------------------------------------------------------------------------------------------+
 | autofocus              | string | See `input-option-autofocus`_                                                                            |
 +------------------------+--------+----------------------------------------------------------------------------------------------------------+
@@ -2241,6 +2325,7 @@ See also at specific *FormElement* definitions.
 | title                  | string |                                                                                                          |
 | extraDeleteForm        | string |                                                                                                          |
 | detail                 | string |                                                                                                          |
+| subrecordTableClass    | string |                                                                                                          |
 +------------------------+--------+----------------------------------------------------------------------------------------------------------+
 | capture                | string | See `input-upload`_                                                                                      |
 | accept                 | string |                                                                                                          |
@@ -2404,12 +2489,19 @@ extraButtonInfo
 ;;;;;;;;;;;;;;;
 
 * The user has to click on the `info` button/icon to see an additional message.
-* After Form load, the information message is hided.
+* After Form load, the information message is hidden.
 * The value of this parameter is the text shown.
-* Shows an `info` button/icon, depending of the type:
+* Shows an `info` button/icon, depending of EXTRA_BUTTON_INFO_POSITION in `config.qfq.ini`_
+
+  * `auto`, depending on `FormElement` type:
 
-  * on the right side of an input element for type `text`, `date`, `time` or `datetime`,
-  * below the FormElement for all other types.
+    * on the right side of an input element for type `text`, `date`, `time` or `datetime`,
+    * below the FormElement for all other types.
+
+  * `below`: below the FormElement for all types.
+
+* With display `below`, a defined class in `extraButtonInfoClass` (FE, F, config.qfq.ini) will be applied. E.g. this
+  might be `pull-right` to align the grafic on the right side of the input element.
 
 .. _`input-checkbox`:
 
@@ -2730,6 +2822,13 @@ The *FormElement* type 'subrecord' renders a list of records (so called secondar
 or add new records. The list is defined as a SQL query. The number of records shown is not limited. These *FormElement*
 will be rendered inside the form as a HTML table.
 
+* *mode / modeSql*:
+  * *show / required*: the regular mode to show the subrecords
+  * *readonly*: New / Edit / Delete Buttons are disabled
+  * *hidden*: The FormElement is rendered, but disabled with `display='none'`.
+
+* *dynamicUpdate*: not supported at the moment.
+
 * *sql1*: SQL query to select records. E.g.::
 
    {{!SELECT a.id AS id, CONCAT(a.street, a.streetnumber) AS a, a.city AS b, a.zip AS c FROM Address AS a}}
@@ -2766,9 +2865,9 @@ will be rendered inside the form as a HTML table.
 
     * Examples::
 
-         SELECT note1 AS 'Comment', note2 AS 'Comment|50' , note3 AS 'title=Comment|width=100|nostrip', note4 AS '50|Comment',
+         {{!SELECT id, note1 AS 'Comment', note2 AS 'Comment|50' , note3 AS 'title=Comment|width=100|nostrip', note4 AS '50|Comment',
          'checked.png' AS 'Status|icon', email AS 'mailto', CONCAT(homepage, '|Homepage') AS 'url',
-         ELT(status,'info','warning','danger') AS '_rowClass', help AS '_rowTitle' ...
+         ELT(status,'info','warning','danger') AS '_rowClass', help AS '_rowTitle' ...}}
 
 * *FormElement.parameter*
 
@@ -2776,13 +2875,13 @@ will be rendered inside the form as a HTML table.
   * *page*: Target page with detail form. If none specified, use the current page.
   * *title*: Title displayed over the table in the current form.
   * *extraDeleteForm*: Optional. The per row delete Button will reference the form specified here (for deleting) instead of the default (*form*).
-  * *detail*: Mapping of values from the primary form to the target form (defined via `form=...`).
+  * *detail*: Mapping of values from a) the primary form, b) the current row, c) any constant or '{{...}}' - to the target form (defined via `form=...`).
 
     * Syntax::
 
         <source table column name 1|&constant 1>:<target column name 1>[,<source table column name 2|&constant 2>:<target column name 2>][...]
 
-    * Example: *detail=id:personId,&12:xId,&{{a}}:personId*
+    * Example: *detail=id:personId,rowId:secId,&12:xId,&{{a}}:personId*  (rowId is a column of the current selected row defined by sql1)
     * By default, the given value will overwrite values on the target record. In most situations, this is the wished behaviour.
     * Exceptions of the default behaviour have to be defined on the target form in the corresponding *FormElement* in the
       field *value* by changing the default Store priority definition. E.g. `{{<columnname>:RS0}}` - For existing records,
@@ -2793,6 +2892,8 @@ will be rendered inside the form as a HTML table.
     * *Constant '&'*: Indicate a 'constant' value. E.g. `&12:xId` or `{{...}}` (all possibilities, incl. further SELECT
       statements) might be used.
 
+  * *subrecordTableClass*: Optional. Default: 'table table-hover'. If given, the default will be overwritten.
+
 Type: time
 ^^^^^^^^^^
 
@@ -2859,8 +2960,8 @@ and will be processed after saving the primary record and before any action Form
 
         fileDestination={{SELECT 'fileadmin/user/pictures/', p.name, '-{{filename}}' FROM Person AS p WHERE p.id={{id:R0}} }}
 
-      * The original filename will be sanitized: only alnum characters are allowed. German 'umlaut' will be replaced by
-        'ae', 'ue', 'oe'. All non valid characters will be replaced by '-'.
+      * The original filename will be sanitized: only '<alnum>', '.' and '_' characters are allowed. German 'umlaut' will
+        be replaced by 'ae', 'ue', 'oe'. All non valid characters will be replaced by '_'.
 
     * If a file already exist under `fileDestination`, an error message is shown and 'save' is aborted. The user has no
       possibility to overwrite the already existing file. If the whole workflow is correct, this situation should no
@@ -3270,7 +3371,7 @@ See #3426 / Dynamic Update: Inputs loose the new content and shows the old value
 
 * On **all** `dynamic update` *FormElements* an explicit definition of `value`, including a sanitize class, is necessary
   (except the field is numeric). **A missing definition let's the content overwrite all the time with the old value**.
-  A typical definition for `value` looks like::
+  A typical definition for `value` looks like (default store priority is: FSRVD)::
 
      {{<FormElement name>::alnumx}}
 
@@ -3284,6 +3385,10 @@ See #3426 / Dynamic Update: Inputs loose the new content and shows the old value
   Remember to specify a 'sanitize' class - a missing sanitize class means 'digit', every content, which is not numeric,
   violates the sanitize class and becomes therefore an empty string!
 
+* If the dynamic update should work on existing and *new* records, it's important to guarantee that the query result is not empty!
+  even if the primary record does not exist! E.g. use a `LEFT JOIN`. The following query is ok for `new` and `edit`. ::
+
+    {{SELECT IF( IFNULL(adr.type,'') LIKE '%token%','show','hidden') FROM (SELECT 1) AS fake LEFT JOIN Address AS adr ON adr.type='{{type:FR0}}' LIMIT 1}}
 
 Examples
 ^^^^^^^^
@@ -3514,6 +3619,13 @@ already a lock for a `tablename` / `record id` pair, the most restrictive will b
 Best practice
 -------------
 
+Custom default value only for 'new records'
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In the specific `FormElement` set `value={{columnName:RSE}}`. The link to the form should be rendered with
+'"...&columnName=<data>&..." AS _page'. The trick is that the STORE_RECORD is empty for new records, and therefore the
+corresponding value from STORE_SIP will be returned. Existing records will use the already saved value.
+
 Central configured values
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/extension/Documentation/Release.rst b/extension/Documentation/Release.rst
index 4fd718b21488a8d70a23f5de25cb8371bdf05174..bdc24025ae4834d80be3f099b82f1621c4f07380 100644
--- a/extension/Documentation/Release.rst
+++ b/extension/Documentation/Release.rst
@@ -25,15 +25,131 @@ Release
 Version 0.future
 ----------------
 
+Date: <date>
+
+Notes
+^^^^^
+
+Features
+^^^^^^^^
+
+Bug Fixes
+^^^^^^^^^
+
+Version 0.23.0
+--------------
+
+Date: 17.09.2017
+
+Notes
+^^^^^
+
+Features
+^^^^^^^^
+
+* #3752 / Pills auf mode|modeSql=hidden|readonly setzen - implemented during 'form load' (not dynamic update)
+
+Bug Fixes
+^^^^^^^^^
+
+* #4548 /Template Group: 'form-update' broken - Broken Redirect after Save - Broken same HTML ID for FE copies in a template group.
+* #4548 /Template Group: 'form-update' broken - max tg element value/index shown after save instead of last user supplied value, but save is ok. Neu wird nach dem Speichern das Formular nochmal komplett geladen. Das ist wichtig um die durch aftersave geaenderten Records in die Formularelemente zu bekommen.
+
+Release
+=======
+
+Version 0.22
+------------
+
+Date: 14.09.2017
+
+Notes
+^^^^^
+
+* Form Editor: element 'forwardPage' is static again (no dynamic update) - see features in #4511.
+
+Features
+^^^^^^^^
+
+* #4511 / Form: URL Forward - mode dynamic computed
+
+Bug Fixes
+^^^^^^^^^
+
+* #4512 | SIP URL does not respect anker token '#'- fixed PLUS: L and type _GET Params included in links which contain a SIP (regular links still open).
+* #4508 / Form: during Save with FE with 'report'-Note/Values an exception is thrown - report does not expect, to be called without typo3 - but this is the case during save and generating the JSON.
+* #4021 / "required" asterik does not handle multi column labels correctly
+* #4423 / Date inputs with readonly: label is grey.
+* Empty date might create '2001-00-00'
+* #4504 / Upload Button: required asterik missing after save - seems to be a problem for every element - should be fixed now.
+
+Version 0.21.0
+--------------
+
+Date: 10.09.2017
+
+Notes
+^^^^^
+
+* The Form-Editor now has two 'requiredParamter' fields: one for 'New' record and one 'Edit'. Existing settings will be
+  automatically copied to both.
+* The FormElement-Editor field 'Note' is not anymore a TinyMCE Editor. Instead a regular 'textarea' is used. Main reason
+  are incompatibilities between TinyMCE HTML mode and the neede CR/LF linebreaks needed for 'Report' Syntax in the 'note'
+  column.
+
+Features
+^^^^^^^^
+
+* #4431 / FE.type=note: QFQ Report Syntax in 'FE.value' and 'FE.note'
+* #4456 / formModeGlobal=requiredOff - Switches FormElement.mode=required to 'show' for all FE of the current Form.
+* Feature #4356 / Form: required parameter - split between 'New' & 'Edit'
+
+Version 0.20.0
+--------------
+
+Changes
+^^^^^^^
+
+* New configuration value EXTRA_BUTTON_INFO_POSITION in config.qfq.ini
+
+Features
+^^^^^^^^
+
+* #4386 Fuer GRC: Optional Info Button bei 'input' wie bei 'textarea' - EXTRA_BUTTON_INFO_POSITION=below
+* #4429 / subrecord: new FE parameter 'subrecordTableCass' - a custom class for the subrecord table might be specified.
+* #4428 / subrecord: mode=readonly
+* #4421 / subrecord: column of the sql1 row should go into the edit link - implemented
+* #4399 / Do not render '_pdf' when r:5 or empty string
+
+Bug Fixes
+^^^^^^^^^
+
+* #4396 / FE: Justify DATE and TIME in case it's DATETIME on a non primary table.
+* #2414 / Deaktivieren von Option 'new' bei subrecord hat keine Folge
+* #4426 / Subrecord: mode=hidden - still shown
+* #4425/ Subrecords: Table head is not wrapped in <thead>
+* #4331 / SQL Statement 'REPLACE' not fired - Keyword missing in list of SQL Keywords
+
+
+Version 0.19.7
+--------------
+
 Changes
 ^^^^^^^
 
+* #4306 / Update Text Subrecord: Please save this record first
+
 Features
 ^^^^^^^^
 
 Bug Fixes
 ^^^^^^^^^
 
+* #4278 / Language: Check that language settings are respectet inside of container / pill / fieldset / templateGroup.
+* #4310 / Fixed error where custom values wouldn't be saved, nor not found for non pedantic.
+* #4311 / Record Lock: expired lock wird nicht geloescht bei form reload.
+* #4309 / typeahead: allow free entry
+
 Version 0.19.6
 --------------
 
diff --git a/extension/Documentation/Settings.cfg b/extension/Documentation/Settings.cfg
index 99d7da82c71667183664733e71d1ef455d8909fb..e84a9fb9b2f8d9911ab5608a647f1821ba9c2dce 100644
--- a/extension/Documentation/Settings.cfg
+++ b/extension/Documentation/Settings.cfg
@@ -2,8 +2,8 @@
 [general]
 
 project     = QFQ - Quick Form Query
-version     = 0.19
-release     = 0.19.6
+version     = 0.23
+release     = 0.23.1
 t3author    = Carsten Rose
 copyright   = since 2017 by the author
 
diff --git a/extension/Documentation/_make/conf.py b/extension/Documentation/_make/conf.py
index 4e47d0ee1f3b75c48c112ad97b9d0f30c989a6b4..221a4260872b297acb683eee024023ade4b3d8c7 100644
--- a/extension/Documentation/_make/conf.py
+++ b/extension/Documentation/_make/conf.py
@@ -57,9 +57,9 @@ copyright = u'2017, Carsten Rose'
 # built documents.lease
 #
 # The short X.Y version.
-version = '0.19'
+version = '0.23'
 # The full version, including alpha/beta/rc tags.
-release = '0.19.6'
+release = '0.23.1'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/extension/RELEASE.txt b/extension/RELEASE.txt
index 4fd718b21488a8d70a23f5de25cb8371bdf05174..bdc24025ae4834d80be3f099b82f1621c4f07380 100644
--- a/extension/RELEASE.txt
+++ b/extension/RELEASE.txt
@@ -25,15 +25,131 @@ Release
 Version 0.future
 ----------------
 
+Date: <date>
+
+Notes
+^^^^^
+
+Features
+^^^^^^^^
+
+Bug Fixes
+^^^^^^^^^
+
+Version 0.23.0
+--------------
+
+Date: 17.09.2017
+
+Notes
+^^^^^
+
+Features
+^^^^^^^^
+
+* #3752 / Pills auf mode|modeSql=hidden|readonly setzen - implemented during 'form load' (not dynamic update)
+
+Bug Fixes
+^^^^^^^^^
+
+* #4548 /Template Group: 'form-update' broken - Broken Redirect after Save - Broken same HTML ID for FE copies in a template group.
+* #4548 /Template Group: 'form-update' broken - max tg element value/index shown after save instead of last user supplied value, but save is ok. Neu wird nach dem Speichern das Formular nochmal komplett geladen. Das ist wichtig um die durch aftersave geaenderten Records in die Formularelemente zu bekommen.
+
+Release
+=======
+
+Version 0.22
+------------
+
+Date: 14.09.2017
+
+Notes
+^^^^^
+
+* Form Editor: element 'forwardPage' is static again (no dynamic update) - see features in #4511.
+
+Features
+^^^^^^^^
+
+* #4511 / Form: URL Forward - mode dynamic computed
+
+Bug Fixes
+^^^^^^^^^
+
+* #4512 | SIP URL does not respect anker token '#'- fixed PLUS: L and type _GET Params included in links which contain a SIP (regular links still open).
+* #4508 / Form: during Save with FE with 'report'-Note/Values an exception is thrown - report does not expect, to be called without typo3 - but this is the case during save and generating the JSON.
+* #4021 / "required" asterik does not handle multi column labels correctly
+* #4423 / Date inputs with readonly: label is grey.
+* Empty date might create '2001-00-00'
+* #4504 / Upload Button: required asterik missing after save - seems to be a problem for every element - should be fixed now.
+
+Version 0.21.0
+--------------
+
+Date: 10.09.2017
+
+Notes
+^^^^^
+
+* The Form-Editor now has two 'requiredParamter' fields: one for 'New' record and one 'Edit'. Existing settings will be
+  automatically copied to both.
+* The FormElement-Editor field 'Note' is not anymore a TinyMCE Editor. Instead a regular 'textarea' is used. Main reason
+  are incompatibilities between TinyMCE HTML mode and the neede CR/LF linebreaks needed for 'Report' Syntax in the 'note'
+  column.
+
+Features
+^^^^^^^^
+
+* #4431 / FE.type=note: QFQ Report Syntax in 'FE.value' and 'FE.note'
+* #4456 / formModeGlobal=requiredOff - Switches FormElement.mode=required to 'show' for all FE of the current Form.
+* Feature #4356 / Form: required parameter - split between 'New' & 'Edit'
+
+Version 0.20.0
+--------------
+
+Changes
+^^^^^^^
+
+* New configuration value EXTRA_BUTTON_INFO_POSITION in config.qfq.ini
+
+Features
+^^^^^^^^
+
+* #4386 Fuer GRC: Optional Info Button bei 'input' wie bei 'textarea' - EXTRA_BUTTON_INFO_POSITION=below
+* #4429 / subrecord: new FE parameter 'subrecordTableCass' - a custom class for the subrecord table might be specified.
+* #4428 / subrecord: mode=readonly
+* #4421 / subrecord: column of the sql1 row should go into the edit link - implemented
+* #4399 / Do not render '_pdf' when r:5 or empty string
+
+Bug Fixes
+^^^^^^^^^
+
+* #4396 / FE: Justify DATE and TIME in case it's DATETIME on a non primary table.
+* #2414 / Deaktivieren von Option 'new' bei subrecord hat keine Folge
+* #4426 / Subrecord: mode=hidden - still shown
+* #4425/ Subrecords: Table head is not wrapped in <thead>
+* #4331 / SQL Statement 'REPLACE' not fired - Keyword missing in list of SQL Keywords
+
+
+Version 0.19.7
+--------------
+
 Changes
 ^^^^^^^
 
+* #4306 / Update Text Subrecord: Please save this record first
+
 Features
 ^^^^^^^^
 
 Bug Fixes
 ^^^^^^^^^
 
+* #4278 / Language: Check that language settings are respectet inside of container / pill / fieldset / templateGroup.
+* #4310 / Fixed error where custom values wouldn't be saved, nor not found for non pedantic.
+* #4311 / Record Lock: expired lock wird nicht geloescht bei form reload.
+* #4309 / typeahead: allow free entry
+
 Version 0.19.6
 --------------
 
diff --git a/extension/config.qfq.example.ini b/extension/config.qfq.example.ini
index 1132338a01a5bb3bcfc2636c74ba6ccfc6da1086..3157412e042268df4a92adbc40e31502f10aa94c 100644
--- a/extension/config.qfq.example.ini
+++ b/extension/config.qfq.example.ini
@@ -67,6 +67,11 @@ WKHTMLTOPDF = /opt/wkhtmltox/bin/wkhtmltopdf
 ;SECURITY_SHOW_MESSAGE=true
 ;SECURITY_GET_MAX_LENGTH=50
 
+;GFX_EXTRA_BUTTON_INFO_INLINE = <img src="file.png">
+;GFX_EXTRA_BUTTON_INFO_BELOW = <img src="file.png">
+;EXTRA_BUTTON_INFO_POSITION = auto | below
+;EXTRA_BUTTON_INFO_POSITION_CLASS = pull-right
+
 ;SAVE_BUTTON_TEXT =
 ;SAVE_BUTTON_TOOLTIP = save
 ;SAVE_BUTTON_CLASS = btn btn-default navbar-btn
diff --git a/extension/ext_emconf.php b/extension/ext_emconf.php
index abdd785df6dd6df04a2d500e1bc4edc6c1a063df..190868622e971d5f6f24c4eec138ae79866033f4 100644
--- a/extension/ext_emconf.php
+++ b/extension/ext_emconf.php
@@ -10,6 +10,6 @@ $EM_CONF[$_EXTKEY] = array(
     'dependencies' => 'fluid,extbase',
     'clearcacheonload' => true,
     'state' => 'alpha',
-    'version' => '0.19.6',
+    'version' => '0.23.1',
 );
 
diff --git a/extension/qfq/api/load.php b/extension/qfq/api/load.php
index cea64974f5fcdc436d89b21b103332b792ad3c18..aa49f0760bddab08984352ee909a02ac0b4fdb42 100644
--- a/extension/qfq/api/load.php
+++ b/extension/qfq/api/load.php
@@ -25,14 +25,13 @@ require_once(__DIR__ . '/../qfq/QuickFormQuery.php');
  * field-name: <field name>
  * field-message: <message>
  * form-data: [ fieldname1 => value1, fieldname2 => value2, ... ]
- * form-control: [ fieldname1 => status1, fieldname2 => status2, ... ]  status: show|hide, enabled|disabled, readonly|readwrite
+ * form-control: [ fieldname1 => status1, fieldname2 => status2, ... ]  status: show|hide, enabled|disabled,
+ * readonly|readwrite
  *
  * Description:
  *
- * Save successfull. Button 'close', 'new'. Form.forward: 'auto'. Client logic decide to redirect or not. Show message if no redirect.
- *  status = 'success'
- *  message = <message>
- *  redirect = 'client'
+ * Save successfull. Button 'close', 'new'. Form.forward: 'auto'. Client logic decide to redirect or not. Show message
+ * if no redirect. status = 'success' message = <message> redirect = 'client'
  *
  * Save successfull. Button 'close': Form.forward: 'page'. Client redirect to url.
  *  status = 'success'
@@ -40,13 +39,9 @@ require_once(__DIR__ . '/../qfq/QuickFormQuery.php');
  *  redirect = 'url'
  *  redirect-url = <URL>
  *
- * Save failed: Button: any. Show message and set 'alert' on _optional_ specified form element. Bring 'pill' of specified form element to front.
- *  status = 'error'
- *  message = <message>
- *  redirect = 'no'
- *  Optional:
- *   field-name = <field name>
- *   field-message = <message appearing as tooltip (or similar) near the form element>
+ * Save failed: Button: any. Show message and set 'alert' on _optional_ specified form element. Bring 'pill' of
+ * specified form element to front. status = 'error' message = <message> redirect = 'no' Optional: field-name = <field
+ * name> field-message = <message appearing as tooltip (or similar) near the form element>
  */
 
 $answer = array();
diff --git a/extension/qfq/api/save.php b/extension/qfq/api/save.php
index f0d4eb44075494cce2b90813c032e851851c5e84..dad0a20416f5a33a54f83b01244aae44ee192cda 100644
--- a/extension/qfq/api/save.php
+++ b/extension/qfq/api/save.php
@@ -28,14 +28,13 @@ require_once(__DIR__ . '/../qfq/exceptions/DbException.php');
  * field-name: <field name>
  * field-message: <message>
  * form-data: [ fieldname1 => value1, fieldname2 => value2, ... ]
- * form-control: [ fieldname1 => status1, fieldname2 => status2, ... ]  status: show|hide, enabled|disabled, readonly|readwrite
+ * form-control: [ fieldname1 => status1, fieldname2 => status2, ... ]  status: show|hide, enabled|disabled,
+ * readonly|readwrite
  *
  * Description:
  *
- * Save successfull. Button 'close', 'new'. Form.forward: 'auto'. Client logic decide to redirect or not. Show message if no redirect.
- *  status = 'success'
- *  message = <message>
- *  redirect = 'client'
+ * Save successfull. Button 'close', 'new'. Form.forward: 'auto'. Client logic decide to redirect or not. Show message
+ * if no redirect. status = 'success' message = <message> redirect = 'client'
  *
  * Save successfull. Button 'close': Form.forward: 'page'. Client redirect to url.
  *  status = 'success'
@@ -43,13 +42,9 @@ require_once(__DIR__ . '/../qfq/exceptions/DbException.php');
  *  redirect = 'url'
  *  redirect-url = <URL>
  *
- * Save failed: Button: any. Show message and set 'alert' on _optional_ specified form element. Bring 'pill' of specified form element to front.
- *  status = 'error'
- *  message = <message>
- *  redirect = 'no'
- *  Optional:
- *   field-name = <field name>
- *   field-message = <message appearing as tooltip (or similar) near the form element>
+ * Save failed: Button: any. Show message and set 'alert' on _optional_ specified form element. Bring 'pill' of
+ * specified form element to front. status = 'error' message = <message> redirect = 'no' Optional: field-name = <field
+ * name> field-message = <message appearing as tooltip (or similar) near the form element>
  */
 
 $answer = array();
diff --git a/extension/qfq/external/AutoCron.php b/extension/qfq/external/AutoCron.php
index e92a29e37f6c83ce99d503298f29e1b997ac5b95..e35b0e8e091743d79488280d7053313a8a4094d0 100644
--- a/extension/qfq/external/AutoCron.php
+++ b/extension/qfq/external/AutoCron.php
@@ -56,6 +56,7 @@ class AutoCron {
      * Check if there started cronJobs, older than $ageMaxMinutes
      *
      * @param int $ageMaxMinutes
+     *
      * @throws CodeException
      * @throws DbException
      */
@@ -66,6 +67,7 @@ class AutoCron {
 
     /**
      * @param array $job
+     *
      * @return array
      * @throws CodeException
      * @throws DbException
@@ -80,6 +82,7 @@ class AutoCron {
         // With no frequency: stop future repeating by setting nextRun=0
         if ($job[AUTOCRON_FREQUENCY] == '') {
             $job[AUTOCRON_NEXT_RUN] = 0;
+
             return $job;
         }
 
@@ -106,6 +109,7 @@ class AutoCron {
      * Calls the Webpage given in $job[AUTOCRON_CONTENT].
      *
      * @param array $job
+     *
      * @return array $job, updated with AUTOCRON_LAST_STATUS
      */
     private function doJobWebsite(array $job) {
@@ -133,6 +137,7 @@ class AutoCron {
 
     /**
      * @param array $mailEntry
+     *
      * @return array
      */
     private function mailEntryFill(array $mailEntry) {
@@ -142,6 +147,7 @@ class AutoCron {
                 $mailEntry[$key] = '';
             }
         }
+
         return $mailEntry;
     }
 
@@ -150,6 +156,7 @@ class AutoCron {
      * Do not send mails if: no record OR no receiver OR empty body
      *
      * @param array $job
+     *
      * @return array $job, updated with AUTOCRON_LAST_STATUS
      */
     private function doJobMail(array $job) {
diff --git a/extension/qfq/qfq/AbstractBuildForm.php b/extension/qfq/qfq/AbstractBuildForm.php
index 453fa3a7a948add53668830e0bf05ba15d8fb4e7..de34a7047380998467f9172d79953d1d62ad9ec9 100644
--- a/extension/qfq/qfq/AbstractBuildForm.php
+++ b/extension/qfq/qfq/AbstractBuildForm.php
@@ -16,6 +16,8 @@ use qfq;
 
 require_once(__DIR__ . '/store/Store.php');
 require_once(__DIR__ . '/Constants.php');
+require_once(__DIR__ . '/Evaluate.php');
+require_once(__DIR__ . '/BodytextParser.php');
 require_once(__DIR__ . '/exceptions/DbException.php');
 require_once(__DIR__ . '/exceptions/UserFormException.php');
 require_once(__DIR__ . '/database/Database.php');
@@ -24,6 +26,7 @@ require_once(__DIR__ . '/helper/Support.php');
 require_once(__DIR__ . '/helper/OnArray.php');
 require_once(__DIR__ . '/helper/Ldap.php');
 require_once(__DIR__ . '/report/Link.php');
+require_once(__DIR__ . '/report/Report.php');
 
 /**
  * Class AbstractBuildForm
@@ -58,6 +61,14 @@ abstract class AbstractBuildForm {
      * @var Sip
      */
     private $sip = null;
+    /**
+     * @var Report
+     */
+    private $report = null;
+    /**
+     * @var BodytextParser
+     */
+    private $bodytextParser = null;
 
     /**
      * AbstractBuildForm constructor.
@@ -129,6 +140,7 @@ abstract class AbstractBuildForm {
         ];
 
         $this->symbol[SYMBOL_EDIT] = "<span class='glyphicon " . GLYPH_ICON_EDIT . "'></span>";
+        $this->symbol[SYMBOL_SHOW] = "<span class='glyphicon " . GLYPH_ICON_SHOW . "'></span>";
         $this->symbol[SYMBOL_NEW] = "<span class='glyphicon " . GLYPH_ICON_NEW . "'></span>";
         $this->symbol[SYMBOL_DELETE] = "<span class='glyphicon " . GLYPH_ICON_DELETE . "'></span>";
 
@@ -148,7 +160,7 @@ abstract class AbstractBuildForm {
      * @throws DbException
      * @throws \qfq\UserFormException
      */
-    public function process($mode, $htmlElementNameIdZero = false) {
+    public function process($mode, $htmlElementNameIdZero = false, $latestFeSpecNative = array()) {
         $htmlHead = '';
         $htmlTail = '';
         $htmlT3vars = '';
@@ -156,6 +168,11 @@ abstract class AbstractBuildForm {
         $htmlElements = '';
         $json = array();
 
+        // After action 'afterSave', it's necessary to reinitialize the FeSpecNative
+        if (!empty($latestFeSpecNative)) {
+            $this->feSpecNative = $latestFeSpecNative;
+        }
+
         $modeCollectFe = FLAG_DYNAMIC_UPDATE;
         $storeUse = STORE_USE_DEFAULT;
 
@@ -185,12 +202,6 @@ abstract class AbstractBuildForm {
             $htmlElements = $this->elements($recordId, $filter, 0, $json, $modeCollectFe, $htmlElementNameIdZero, $storeUse, $mode);
 
             if ($mode === FORM_SAVE && $recordId != 0) {
-//                $json[] = [API_ELEMENT_UPDATE => [DIRTY_RECORD_HASH_MD5 => [API_ELEMENT_ATTRIBUTE => ['value' => $newMd5]]]];
-//                $json[] = [API_ELEMENT_UPDATE => [DIRTY_RECORD_HASH_MD5 =>  ['value' => $newMd5]]];
-
-                // element-update: with 'content'
-//                $inputMd5 = $this->buildInputRecordHashMd5(false);
-//                $json[][API_ELEMENT_UPDATE][DIRTY_RECORD_HASH_MD5_SPAN][API_ELEMENT_CONTENT] = $inputMd5;
 
                 // element-update: with 'value'
                 $recordId = $this->store->getVar(SIP_RECORD_ID, STORE_SIP . STORE_ZERO);
@@ -198,10 +209,6 @@ abstract class AbstractBuildForm {
 
                 // Via 'element-update'
                 $json[][API_ELEMENT_UPDATE][DIRTY_RECORD_HASH_MD5][API_ELEMENT_ATTRIBUTE]['value'] = $md5;
-
-                // Via 'form-update'
-//                $json[] =  [API_FORM_UPDATE_FORM_ELEMENT => DIRTY_RECORD_HASH_MD5, API_FORM_UPDATE_VALUE => $md5,
-//                    API_FORM_UPDATE_DISABLED => false, API_FORM_UPDATE_REQUIRED => false ];
             }
         }
 
@@ -435,6 +442,41 @@ abstract class AbstractBuildForm {
 
     abstract public function getProcessFilter();
 
+    /**
+     * @param array|string $value
+     *
+     * @return array|string
+     * @throws UserFormException
+     */
+    private function processReportSyntax($value) {
+
+        if (is_array($value)) {
+            $new = array();
+
+            //might happen for e.g Template Groups
+            foreach ($value as $item) {
+                $new[] = $this->processReportSyntax($item);
+            }
+
+            return $new;
+        }
+
+        if (substr($value, 0, 8) == SHEBANG_REPORT) {
+            if ($this->report === null) {
+                $this->report = new Report(array(), $this->evaluate, false);
+            }
+
+            if ($this->bodytextParser === null) {
+                $this->bodytextParser = new BodytextParser();
+            }
+
+            $value = $this->report->process($this->bodytextParser->process($value));
+
+        }
+
+        return $value;
+    }
+
     /**
      * Process all FormElements in $this->feSpecNative: Collect and return all HTML code & JSON.
      *
@@ -464,7 +506,8 @@ abstract class AbstractBuildForm {
 
         // get current data record
         if ($recordId > 0 && $this->store->getVar('id', STORE_RECORD) === false) {
-            $row = $this->db->sql('SELECT * FROM ' . $this->formSpec[F_TABLE_NAME] . " WHERE id = ?", ROW_EXPECT_1,
+            $tableName = $this->formSpec[F_TABLE_NAME];
+            $row = $this->db->sql("SELECT * FROM $tableName WHERE id = ?", ROW_EXPECT_1,
                 array($recordId), "Form '" . $this->formSpec[F_NAME] . "' failed to load record '$recordId' from table '" .
                 $this->formSpec[F_TABLE_NAME] . "'.");
             $this->store->setStore($row, STORE_RECORD);
@@ -472,6 +515,8 @@ abstract class AbstractBuildForm {
 
         $this->checkAutoFocus();
 
+        $parameterLanguageFieldName = $this->store->getVar(SYSTEM_PARAMETER_LANGUAGE_FIELD_NAME, STORE_SYSTEM);
+
         // Iterate over all FormElements
         foreach ($this->feSpecNative as $fe) {
             $storeUse = $storeUseDefault;
@@ -483,16 +528,10 @@ abstract class AbstractBuildForm {
                 continue; // skip this FE
             }
 
-            $flagOutput = ($fe[FE_TYPE] !== FE_TYPE_EXTRA); // type='extra' will not displayed and not transmitted to the form
+            $flagOutput = ($fe[FE_TYPE] !== FE_TYPE_EXTRA); // type='extra' will not displayed and not transmitted to the form.
 
             $debugStack = array();
 
-            // Copy global readonly mode.
-            if ($this->formSpec[F_MODE] == F_MODE_READONLY) {
-                $fe[FE_MODE] = FE_MODE_READONLY;
-                $fe[FE_MODE_SQL] = '';
-            }
-
             // Preparation for Log, Debug
             $this->store->setVar(SYSTEM_FORM_ELEMENT, Logger::formatFormElementName($fe), STORE_SYSTEM);
 
@@ -506,12 +545,22 @@ abstract class AbstractBuildForm {
                 $this->store->setVar(VAR_SLAVE_ID, $slaveId, STORE_VAR);
             }
 
+            $fe[FE_VALUE] = $this->processReportSyntax($fe[FE_VALUE]);
+            $fe[FE_NOTE] = $this->processReportSyntax($fe[FE_NOTE]);
+
             // ** evaluate current FormElement **
             $formElement = $this->evaluate->parseArray($fe, $skip, $debugStack);
+            $formElement = HelperFormElement::setLanguage($formElement, $parameterLanguageFieldName);
 
             // Some Defaults
             $formElement = Support::setFeDefaults($formElement, $this->formSpec);
 
+//            // Copy global readonly mode.
+//            if ($this->formSpec[F_MODE] == F_MODE_READONLY) {
+//                $fe[FE_MODE] = FE_MODE_READONLY;
+//                $fe[FE_MODE_SQL] = '';
+//            }
+
             if ($flagOutput === true) {
                 $this->fillWrapLabelInputNote($formElement[FE_BS_LABEL_COLUMNS], $formElement[FE_BS_INPUT_COLUMNS], $formElement[FE_BS_NOTE_COLUMNS]);
             }
@@ -808,7 +857,8 @@ abstract class AbstractBuildForm {
 
         if (isset($formElement[FE_LABEL])) {
             $key = $formElement[FE_HTML_ID] . HTML_ID_EXTENSION_LABEL;
-            $json[API_ELEMENT_UPDATE][$key][API_ELEMENT_CONTENT] = $this->buildLabel($htmlFormElementName, $formElement[FE_LABEL]);
+            $addClass = ($formElement[FE_MODE] == FE_MODE_REQUIRED) ? CSS_REQUIRED : '';
+            $json[API_ELEMENT_UPDATE][$key][API_ELEMENT_CONTENT] = $this->buildLabel($htmlFormElementName, $formElement[FE_LABEL], $addClass);
         }
 
         if (isset($formElement[FE_NOTE])) {
@@ -1030,10 +1080,9 @@ abstract class AbstractBuildForm {
         if ($formElement[FE_HIDE_ZERO] != '0' && $value == '0') {
             $value = '';
         }
-//        $formElement = HelperFormElement::prepareExtraButton($formElement, !$flagTextarea, $extraButton);
+
         $formElement = HelperFormElement::prepareExtraButton($formElement, !$flagTextarea);
         if ($flagTextarea) {
-            // <textarea>
             $htmlTag = '<textarea';
 
             $attribute .= Support::doAttribute('cols', $colsRows[0]);
@@ -1176,6 +1225,7 @@ abstract class AbstractBuildForm {
         // MIN( $formElement['maxLength'], tabledefinition)
         $maxLength = $this->getColumnSize($formElement[FE_NAME]);
 
+        $feMaxLength = false;
         switch ($formElement[FE_TYPE]) {
             case 'date':
                 $feMaxLength = 10;
@@ -1186,12 +1236,14 @@ abstract class AbstractBuildForm {
             case 'time':
                 $feMaxLength = 8;
                 break;
-            default:
-                $feMaxLength = false;
-                break;
         }
 
-        // In case the underlying tablecolumn is not of type date/time, the $maxLength might be to high: correct
+        // In case there is no limit of the underlying table column, or a non primary table column, and the FE_TYPE is date/time.
+        if ($maxLength === false && $feMaxLength !== false) {
+            $maxLength = $feMaxLength;
+        }
+
+        // In case the underlying table column is not of type date/time, the $maxLength might be to high: correct
         if ($feMaxLength !== false && $maxLength !== false && $feMaxLength < $maxLength) {
             $maxLength = $feMaxLength;
         }
@@ -2220,7 +2272,6 @@ abstract class AbstractBuildForm {
         // Fill $itemKey & $itemValue
         $this->getKeyValueListFromSqlEnumSpec($formElement, $itemKey, $itemValue);
 
-        $attribute .= $this->getAttributeFeMode($formElement[FE_MODE]);
         $attribute .= Support::doAttribute('id', $formElement[FE_HTML_ID]);
         $attribute .= Support::doAttribute('name', $htmlFormElementName);
         $attribute .= Support::doAttribute('class', 'form-control');
@@ -2263,9 +2314,9 @@ abstract class AbstractBuildForm {
 
         $json = $this->getFormElementForJson($htmlFormElementName, $jsonValues, $formElement);
 
-        $html = '<select ' . $attribute . '>' . $option . '</select>';
-
         $formElement = HelperFormElement::prepareExtraButton($formElement, false);
+        $attribute .= $this->getAttributeFeMode($formElement[FE_MODE]);
+        $html = '<select ' . $attribute . '>' . $option . '</select>';
         $html = $html . $this->getHelpBlock() . $formElement[FE_TMP_EXTRA_BUTTON_HTML];
 
         return $html . $formElement[FE_INPUT_EXTRA_BUTTON_INFO];
@@ -2273,8 +2324,8 @@ abstract class AbstractBuildForm {
 
     /**
      * Construct a HTML table of the subrecord data.
-     * Column syntax definition:
-     * https://wikiit.math.uzh.ch/it/projekt/qfq/qfq-jqwidgets/Documentation#Type:_subrecord
+     * Column syntax
+     * definition:https://docs.typo3.org/typo3cms/drafts/github/T3DocumentationStarter/Public-Info-053/Manual.html#type-subrecord
      *
      * @param array  $formElement
      * @param string $htmlFormElementName
@@ -2289,7 +2340,7 @@ abstract class AbstractBuildForm {
     public function buildSubrecord(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
         $rcText = false;
         $nameColumnId = 'id';
-        $targetTableName = '';
+//        $targetTableName = '';
         $flagNew = false;
         $flagEdit = false;
         $flagDelete = false;
@@ -2307,14 +2358,13 @@ abstract class AbstractBuildForm {
             Support::setIfNotSet($formElement, F_EXTRA_DELETE_FORM, '');
             $formElement[F_FINAL_DELETE_FORM] = $formElement[F_EXTRA_DELETE_FORM] != '' ? $formElement[F_EXTRA_DELETE_FORM] : $formElement[SUBRECORD_PARAMETER_FORM];
 
-            $linkNew = Support::wrapTag('<th>', $this->createFormLink($formElement, 0, $primaryRecord, $this->symbol[SYMBOL_NEW], 'New'));
-
             // Decode settings in subrecordOption
-            $flagNew = Support::findInSet(SUBRECORD_NEW, $formElement[FE_SUBRECORD_OPTION]);
+            $flagNew = Support::findInSet(SUBRECORD_NEW, $formElement[FE_SUBRECORD_OPTION]) && ($formElement[FE_MODE] != FE_MODE_READONLY);
+
             $flagEdit = Support::findInSet(SUBRECORD_EDIT, $formElement[FE_SUBRECORD_OPTION]);
-            if ($flagDelete = Support::findInSet(SUBRECORD_DELETE, $formElement[FE_SUBRECORD_OPTION])) {
-                $targetTableName = $this->getFormTable($formElement[SUBRECORD_PARAMETER_FORM]);
-            }
+            $flagDelete = Support::findInSet(SUBRECORD_DELETE, $formElement[FE_SUBRECORD_OPTION]) && ($formElement[FE_MODE] != FE_MODE_READONLY);
+
+            $linkNew = $flagNew ? Support::wrapTag('<th>', $this->createFormLink($formElement, 0, $primaryRecord, $this->symbol[SYMBOL_NEW], 'New')) : '<th></th>';
         }
 
         $columns = $linkNew;
@@ -2332,13 +2382,15 @@ abstract class AbstractBuildForm {
         }
 
         // Table head
-        $html = Support::wrapTag('<tr>', $columns);
+        $html = Support::wrapTag('<thead><tr>', $columns);
 
         foreach ($formElement[FE_SQL1] as $row) {
             $rowHtml = '';
 
             if ($flagEdit) {
-                $rowHtml .= Support::wrapTag('<td>', $this->createFormLink($formElement, $row[$nameColumnId], $primaryRecord, $this->symbol[SYMBOL_EDIT], 'Edit'));
+                $toolTip = ($formElement[FE_MODE] == FE_MODE_READONLY) ? 'Show' : 'Edit';
+                $symbol = ($formElement[FE_MODE] == FE_MODE_READONLY) ? $this->symbol[SYMBOL_SHOW] : $this->symbol[SYMBOL_EDIT];
+                $rowHtml .= Support::wrapTag('<td>', $this->createFormLink($formElement, $row[$nameColumnId], $primaryRecord, $symbol, $toolTip, $row));
             } elseif ($flagNew) {
                 $rowHtml .= Support::wrapTag('<td>', $rowHtml, false);
             }
@@ -2357,13 +2409,8 @@ abstract class AbstractBuildForm {
                     $toolTip .= PHP_EOL . "form = '" . $formElement[F_FINAL_DELETE_FORM] . "'" . PHP_EOL . "r = '" . $row[$nameColumnId] . "'";
                 }
 
-//                $buttonDelete = $this->buildButtonCode('delete-button', $toolTip, GLYPH_ICON_DELETE, $disabled);
-
                 $s = $this->createDeleteUrl($formElement[F_FINAL_DELETE_FORM], $row[$nameColumnId], RETURN_SIP);
-//                $rowHtml .= Support::wrapTag('<td>', Support::wrapTag("<button type='button' class='record-delete btn btn-default' data-sip='$s'>", '<span class="glyphicon ' . GLYPH_ICON_DELETE . '"></span>'));
                 $rowHtml .= Support::wrapTag('<td>', Support::wrapTag("<button type='button' class='record-delete btn btn-default' data-sip='$s' " . Support::doAttribute('title', $toolTip) . ">", '<span class="glyphicon ' . GLYPH_ICON_DELETE . '"></span>'));
-
-
             }
 
             Support::setIfNotSet($row, FE_SUBRECORD_ROW_CLASS);
@@ -2378,7 +2425,9 @@ abstract class AbstractBuildForm {
             $html .= Support::wrapTag("<tr $rowAttribute>", $rowHtml, true);
         }
 
-        return Support::wrapTag('<table class="table table-hover">', $html, true);
+        $attribute = Support::doAttribute('class', $formElement[FE_SUBRECORD_TABLE_CLASS]);
+
+        return Support::wrapTag("<table $attribute>", $html, true);
     }
 
     /**
@@ -2398,7 +2447,7 @@ abstract class AbstractBuildForm {
     private function prepareSubrecod(array $formElement, array $primaryRecord, &$rcText, &$nameColumnId) {
 
         if (!isset($primaryRecord['id'])) {
-            $rcText = 'Please save and close record and reopen it.';
+            $rcText = 'Please save this record first.';
 
             return false;
         }
@@ -2452,7 +2501,7 @@ abstract class AbstractBuildForm {
      * @return string
      * @throws UserFormException
      */
-    private function createFormLink(array $formElement, $targetRecordId, array $record, $symbol, $toolTip) {
+    private function createFormLink(array $formElement, $targetRecordId, array $record, $symbol, $toolTip, $currentRow = array()) {
 
         //TODO: Umstellen auf Benutzung der Link Klasse.
 
@@ -2461,6 +2510,11 @@ abstract class AbstractBuildForm {
             SIP_RECORD_ID => $targetRecordId,
         ];
 
+        // Inherit current F_MODE
+        if ($this->formSpec[F_MODE] != '') {
+            $queryStringArray[F_MODE_GLOBAL] = $this->formSpec[F_MODE];
+        }
+
         // Add custom query parameter
         if (isset($formElement[SUBRECORD_PARAMETER_DETAIL])) {
             $detailParam = KeyValueStringParser::parse($formElement[SUBRECORD_PARAMETER_DETAIL]);
@@ -2473,7 +2527,18 @@ abstract class AbstractBuildForm {
                 // Form record values or parameter
                 if (isset($record[$src])) {
                     $queryStringArray[$dest] = $record[$src];
+                    continue;
+                }
+
+                // Current row - check '$src' and  '_$src' )
+                foreach (['', '_'] as $pre) {
+                    if (isset($currentRow[$pre . $src])) {
+                        $queryStringArray[$dest] = $currentRow[$pre . $src];
+                        continue 2;
+                    }
                 }
+
+                $queryStringArray[$dest] = ERROR_SUBRECORD_DETAIL_COLUMN_NOT_FOUND;
             }
         }
 
@@ -2742,17 +2807,26 @@ abstract class AbstractBuildForm {
         $attribute .= Support::doAttribute('data-load', ($formElement[FE_DYNAMIC_UPDATE] === 'yes') ? 'data-load' : '');
         $attribute .= Support::doAttribute('data-sip', $sipUpload);
 
+
+        $json = $this->getFormElementForJson($htmlFormElementName, $value, $formElement); // Below, $formElement[FE_MODE]=FE_MODE_REQUIRED will be changed. Get the JSON unchanged
+
         if ($value === '' || $value === false) {
             $textDeleteClass = 'hidden';
             $uploadClass = '';
         } else {
+
             $textDeleteClass = '';
             $uploadClass = 'hidden';
+            if ($formElement[FE_MODE] == FE_MODE_REQUIRED) {
+                $formElement[FE_MODE] = FE_MODE_SHOW; // #4495 - Upload, which already has been uploaded should not marked as requires
+                $attribute .= Support::doAttribute(DATA_REQUIRED, FE_MODE_REQUIRED);
+            }
 //            $formElement[FE_MODE] = FE_MODE_HIDDEN; // #3876, CR did not understand why we need this here. Comment. If active, this element will be hide on each dynamic update.
         }
 
         $attribute .= $this->getAttributeFeMode($formElement[FE_MODE]);
         $attribute .= Support::doAttribute('class', $uploadClass, true);
+
         $htmlInputFile = '<input ' . $attribute . '>' . $this->getHelpBlock();
 
         $deleteButton = Support::wrapTag("<button type='button' class='delete-file' data-sip='$sipUpload' name='delete-$htmlFormElementName'>", $this->symbol[SYMBOL_DELETE]);
@@ -2762,7 +2836,6 @@ abstract class AbstractBuildForm {
 
 //        <button type="button" class="file-delete" data-sip="571d1fc9e6974"><span class="glyphicon glyphicon-trash"></span></button>
 
-        $json = $this->getFormElementForJson($htmlFormElementName, $value, $formElement);
 
         $formElement = HelperFormElement::prepareExtraButton($formElement, false);
 
@@ -2818,7 +2891,6 @@ abstract class AbstractBuildForm {
      *           [maxlength="$maxLength"] [placeholder="$placeholder"] [size="$size"] [min="$min"] [max="$max"]
      *           [pattern="$pattern"] [required="required"] [disabled="disabled"] value="$value">
      *
-     *
      * @param array  $formElement
      * @param string $htmlFormElementName
      * @param string $value
@@ -2915,12 +2987,17 @@ abstract class AbstractBuildForm {
             $attribute .= Support::doAttribute('max', $arrMinMax[1]);
         }
 
-        $attribute .= $this->getAttributeFeMode($formElement[FE_MODE]);
-
         $json = $this->getFormElementForJson($htmlFormElementName, $value, $formElement);
 
         $formElement = HelperFormElement::prepareExtraButton($formElement, true);
-        $input = Support::wrapTag('<div class="input-group">', "<input $attribute>" . $this->getHelpBlock() . $formElement[FE_TMP_EXTRA_BUTTON_HTML]);
+
+        $attribute .= $this->getAttributeFeMode($formElement[FE_MODE]);
+
+        $input = "<input $attribute>" . $this->getHelpBlock() . $formElement[FE_TMP_EXTRA_BUTTON_HTML];
+
+        if ($formElement[FE_TMP_EXTRA_BUTTON_HTML] !== '') {
+            $input = Support::wrapTag('<div class="input-group">', $input);
+        }
 
         return $input . $formElement[FE_INPUT_EXTRA_BUTTON_INFO];
 
@@ -3239,7 +3316,6 @@ abstract class AbstractBuildForm {
             ['yes', $this->formSpec["id"], 'native,container', $formElement[FE_ID]], $this->formSpec);
 
         $html .= $this->elements($this->store->getVar(SIP_RECORD_ID, STORE_SIP), FORM_ELEMENTS_NATIVE_SUBRECORD, 0, $json);
-
         $html .= $this->wrap[WRAP_SETUP_IN_FIELDSET][WRAP_SETUP_END];
 
         $html .= '</fieldset>';
@@ -3259,6 +3335,7 @@ abstract class AbstractBuildForm {
      * @return array
      */
     private function fillFeSpecNativeCheckboxWithTgMax(array $formElementArr, $tgMaxCopies) {
+
         foreach ($formElementArr as $key => $formElement) {
             if ($formElement[FE_TYPE] = FE_TYPE_CHECKBOX) {
                 $formElementArr[$key][NAME_TG_COPIES] = $tgMaxCopies;
@@ -3331,7 +3408,7 @@ EOT;
         // Count defined FormElements in the current templateGroup
         $elementsTotal = count($this->feSpecNative);
         if ($elementsTotal < 1) {
-            // Nothting to do: return.
+            // Nothing to do: return.
             $this->feSpecNative = $feSpecNativeSave;
 
             return '';
diff --git a/extension/qfq/qfq/BodytextParser.php b/extension/qfq/qfq/BodytextParser.php
index 8545210df3c322725c80f8791ca0b305728968ee..fb9f5274bd629c6ed20b11360ec7221330b1d410 100644
--- a/extension/qfq/qfq/BodytextParser.php
+++ b/extension/qfq/qfq/BodytextParser.php
@@ -17,6 +17,7 @@ class BodytextParser {
 
     /**
      * @param $bodytext
+     *
      * @return mixed|string
      * @throws UserFormException
      */
@@ -39,13 +40,16 @@ class BodytextParser {
         if (strpos($bodytext, NESTING_TOKEN_OPEN) !== false) {
             throw new \qfq\UserFormException("Missing close delimiter: $bodytext", ERROR_MISSING_CLOSE_DELIMITER);
         }
+
         return $bodytext;
 
     }
 
     /**
      * Trim all lines, remove all empty lines and  all lines which start with '#'
+     *
      * @param $bodytext
+     *
      * @return string
      */
 
@@ -97,6 +101,7 @@ class BodytextParser {
         if ($firstLine === false || $firstLine === '' || $firstLine[0] !== '#') {
             $nestingOpen = '{';
             $nestingClose = '}';
+
             return;
         }
 
@@ -146,6 +151,7 @@ class BodytextParser {
      *  g,h:     ^(\d+\.)*(sql|head)\s*=
      *
      * @param array $bodytextArray
+     *
      * @return string
      */
     private function joinLine($bodytext, $nestingOpen, $nestingClose) {
@@ -198,6 +204,7 @@ class BodytextParser {
      * Valid close (complete line): }
      *
      * @param $bodytext
+     *
      * @return mixed
      */
     private function encryptNestingDelimeter($bodytext, $nestingOpen, $nestingClose) {
@@ -231,6 +238,7 @@ class BodytextParser {
      * 10.20.30.sql = DELETE
      *
      * @param $bodytext
+     *
      * @return mixed|string
      * @throws UserFormException
      */
@@ -297,6 +305,7 @@ class BodytextParser {
      * Decrypt complex token by '{\n' and '}\n'
      *
      * @param $bodytext
+     *
      * @return mixed
      */
     private function decryptNestingDelimeter($bodytext, $nestingOpen, $nestingClose) {
diff --git a/extension/qfq/qfq/BuildFormBootstrap.php b/extension/qfq/qfq/BuildFormBootstrap.php
index cc0466d069586f9ba9dc351f61b7c1df1f2be681..35ca762f573fae0859613186ccfd0e7a2a30dec2 100644
--- a/extension/qfq/qfq/BuildFormBootstrap.php
+++ b/extension/qfq/qfq/BuildFormBootstrap.php
@@ -9,7 +9,6 @@
 namespace qfq;
 
 use qfq;
-use qfq\UserFormException;
 
 require_once(__DIR__ . '/../qfq/Constants.php');
 require_once(__DIR__ . '/../qfq/helper/OnArray.php');
@@ -72,6 +71,7 @@ class BuildFormBootstrap extends AbstractBuildForm {
 
     /**
      * @param string $addClass
+     *
      * @return string
      */
     public function getRowOpenTag($addClass = '') {
@@ -116,7 +116,7 @@ class BuildFormBootstrap extends AbstractBuildForm {
     public function head() {
         $html = '';
 
-        $html .= '<div ' . Support::doAttribute('class', $this->formSpec[F_CLASS], TRUE) . '>'; // main <div class=...> around everything, Whole FORM; class="container" or class="container-fluid"
+        $html .= '<div ' . Support::doAttribute('class', $this->formSpec[F_CLASS], true) . '>'; // main <div class=...> around everything, Whole FORM; class="container" or class="container-fluid"
 
         //TODO: nicer error reporting - make test with 'unknown index' here - unset($this->formSpec['title']) - See #3424
         $title = Support::wrapTag('<div class="hidden-xs col-sm-6 col-md-8">', Support::wrapTag('<h3>', $this->formSpec['title']));
@@ -168,9 +168,9 @@ class BuildFormBootstrap extends AbstractBuildForm {
         $formId = $this->store->getVar(COLUMN_ID, STORE_RECORD . STORE_ZERO);
 
         $queryStringArray = [
-            'id' => $this->store->getVar(SYSTEM_EDIT_FORM_PAGE, STORE_SYSTEM),
+            'id'   => $this->store->getVar(SYSTEM_EDIT_FORM_PAGE, STORE_SYSTEM),
             'form' => 'copyForm',
-            'r' => 0,
+            'r'    => 0,
             'idSrc' => $formId,
         ];
         $queryString = Support::arrayToQueryString($queryStringArray);
@@ -216,7 +216,7 @@ class BuildFormBootstrap extends AbstractBuildForm {
             $queryStringArray = [
                 'id' => $this->store->getVar(SYSTEM_EDIT_FORM_PAGE, STORE_SYSTEM),
                 'form' => $form,
-                'r' => 0
+                'r'  => 0,
             ];
             $queryString = Support::arrayToQueryString($queryStringArray);
             $sip = $this->store->getSipInstance();
@@ -318,6 +318,7 @@ class BuildFormBootstrap extends AbstractBuildForm {
      * @param string $icon
      * @param string $disabled
      * @param string $class
+     *
      * @return string
      */
     private function buildButtonAnchor($url, $buttonHtmlId, $text, $toolTip, $icon, $disabled = '', $class = '') {
@@ -344,6 +345,7 @@ class BuildFormBootstrap extends AbstractBuildForm {
      * @param string $tooltip
      * @param string $icon
      * @param string $disabled
+     *
      * @return string
      */
     private function buildButtonCode($buttonHtmlId, $text, $tooltip, $icon, $disabled = '', $buttonOnChangeClass = '', $class = '') {
@@ -363,6 +365,7 @@ class BuildFormBootstrap extends AbstractBuildForm {
 
     /**
      * @param $pillArray
+     *
      * @return string
      * @throws UserFormException
      */
@@ -376,10 +379,20 @@ class BuildFormBootstrap extends AbstractBuildForm {
 
         $maxVisiblePill = (isset($this->formSpec['maxVisiblePill']) && $this->formSpec['maxVisiblePill'] !== '') ? $this->formSpec['maxVisiblePill'] : 1000;
 
+        $parameterLanguageFieldName = $this->store->getVar(SYSTEM_PARAMETER_LANGUAGE_FIELD_NAME, STORE_SYSTEM);
+
         // Iterate over all 'pill'
         $ii = 0;
         $active = 'class="active"';
         foreach ($pillArray as $formElement) {
+
+            $formElement = $this->evaluate->parseArray($formElement);
+            HelperFormElement::explodeParameter($formElement, F_PARAMETER);
+            $formElement = HelperFormElement::setLanguage($formElement, $parameterLanguageFieldName);
+            if (!empty($formElement[FE_MODE_SQL])) {
+                $formElement[FE_MODE] = $formElement[FE_MODE_SQL];
+            }
+
             $ii++;
 
             if ($formElement[FE_NAME] === '' || $formElement[FE_LABEL] === '') {
@@ -389,12 +402,34 @@ class BuildFormBootstrap extends AbstractBuildForm {
             }
 
             // Anker for pill navigation
-            $a = '<a ' . Support::doAttribute('href', '#' . $this->createAnker($formElement['id'])) . ' data-toggle="tab">' . $formElement[FE_LABEL] . '</a>';
+//            $a = '<a ' . Support::doAttribute('href', '#' . $this->createAnker($formElement[FE_ID])) . ' data-toggle="tab">' . $formElement[FE_LABEL] . '</a>';
+
+            $attributeA = 'data-toggle="tab" ';
+            $hrefTarget = '#' . $this->createAnker($formElement[FE_ID]);
+
+            switch ($formElement[FE_MODE]) {
+                case FE_MODE_SHOW:
+                case FE_MODE_REQUIRED:
+                    $attributeLi = '';
+                    break;
+                case FE_MODE_READONLY:
+                    $attributeLi = Support::doAttribute('class', 'disabled');
+                    $hrefTarget = '#';
+                    $attributeA .= Support::doAttribute('class', 'noclick');
+                    break;
+                case FE_MODE_HIDDEN:
+                    $attributeLi = Support::doAttribute('style', 'display: none');
+                    $a = '';
+                    break;
+                default:
+                    throw new UserFormException("Unknown Mode: " . $formElement[FE_MODE], ERROR_UNKNOWN_MODE);
+            }
+            $a = Support::wrapTag("<a  $attributeA" . Support::doAttribute('href', $hrefTarget) . ">", $formElement[FE_LABEL]);
 
             if ($ii <= $maxVisiblePill) {
-                $pillButton .= '<li role="presentation" ' . $active . '>' . $a . '</li>';
+                $pillButton .= '<li role="presentation"' . $attributeLi . $active . ">" . $a . "</li>";
             } else {
-                $pillDropdown .= '<li>' . $a . '</li>';
+                $pillDropdown .= '<li ' . $attributeLi . '>' . $a . "</li>";
             }
             $active = '';
         }
@@ -416,10 +451,11 @@ class BuildFormBootstrap extends AbstractBuildForm {
      * Create an identifier for the pill navigation menu
      *
      * @param $id
+     *
      * @return string
      */
     private function createAnker($id) {
-        return $this->formSpec['name'] . '_' . $id;
+        return $this->formSpec[FE_NAME] . '_' . $id;
     }
 
     /**
@@ -524,8 +560,9 @@ EOF;
 
     /**
      * @param array $formElement
-     * @param $htmlFormElementName
-     * @param $value
+     * @param       $htmlFormElementName
+     * @param       $value
+     *
      * @return mixed
      */
     public function buildPill(array $formElement, $htmlFormElementName, $value, array &$json) {
@@ -546,9 +583,10 @@ EOF;
     }
 
     /**
-     * @param array $formElement Complete FormElement, especially some FE_WRAP
+     * @param array  $formElement Complete FormElement, especially some FE_WRAP
      * @param string $htmlElement Content to wrap.
-     * @param $htmlFormElementName
+     * @param        $htmlFormElementName
+     *
      * @return string               Wrapped $htmlElement
      * @throws \qfq\UserFormException
      */
@@ -602,13 +640,14 @@ EOF;
      * - if $formElement[$wrapName] is given: wrap with that one. Else: wrap with $wrapArray
      * - if $htmlId is give, inject it in $wrap.
      *
-     * @param array $formElement Complete FormElement, especially some FE_WRAP
+     * @param array  $formElement Complete FormElement, especially some FE_WRAP
      * @param string $htmlElement Content to wrap.
-     * @param string $wrapName FE_WRAP_ROW, FE_WRAP_LABEL, FE_WRAP_INPUT, FE_WRAP_NOTE
-     * @param int $bsColumns
-     * @param array $wrapArray Systemwide Defaults: [ 'open wrap', 'close wrap' ]
+     * @param string $wrapName    FE_WRAP_ROW, FE_WRAP_LABEL, FE_WRAP_INPUT, FE_WRAP_NOTE
+     * @param int    $bsColumns
+     * @param array  $wrapArray   Systemwide Defaults: [ 'open wrap', 'close wrap' ]
      * @param string $htmlId
      * @param string $class
+     *
      * @return string Wrapped $htmlElement
      * @throws CodeException
      * @throws \qfq\UserFormException
@@ -642,6 +681,7 @@ EOF;
     /**
      * @param $formElement
      * @param $elementHtml
+     *
      * @return string
      */
     public function buildRowPill(array $formElement, $elementHtml) {
@@ -685,14 +725,18 @@ EOF;
     /**
      * @param $formElement
      * @param $elementHtml
+     *
      * @return string
      */
     public function buildRowSubrecord(array $formElement, $elementHtml) {
-        $html = '';
-        $html .= $this->wrapItem(WRAP_SETUP_ELEMENT, $this->wrapItem(WRAP_SETUP_SUBRECORD, $formElement[FE_LABEL]));
+
+        $html = $this->wrapItem(WRAP_SETUP_ELEMENT, $this->wrapItem(WRAP_SETUP_SUBRECORD, $formElement[FE_LABEL]));
         $html .= $this->wrapItem(WRAP_SETUP_ELEMENT, $this->wrapItem(WRAP_SETUP_SUBRECORD, $elementHtml));
         $html .= $this->wrapItem(WRAP_SETUP_ELEMENT, $this->wrapItem(WRAP_SETUP_SUBRECORD, $formElement[FE_NOTE]));
 
-        return $html;
+        $attribute = ($formElement[FE_MODE] == FE_MODE_HIDDEN) ? ' style="display: none;"' : '';
+        $attribute .= Support::doAttribute('id', $formElement[FE_HTML_ID]);
+
+        return Support::wrapTag("<span name='qfq-subrecord' $attribute>", $html);
     }
 }
\ No newline at end of file
diff --git a/extension/qfq/qfq/BuildFormPlain.php b/extension/qfq/qfq/BuildFormPlain.php
index a65efbddd3241a1b906c68390f5bbfb458491b12..2043768f359cac814aa57198fac4ad8b8fc287ea 100644
--- a/extension/qfq/qfq/BuildFormPlain.php
+++ b/extension/qfq/qfq/BuildFormPlain.php
@@ -61,6 +61,7 @@ class BuildFormPlain extends AbstractBuildForm {
      */
     public function doSubrecords() {
         $json = array();
+
         //TODO: $json is not returned - which is wrong. In this case, dynamic update won't work for subrecords
         return $this->elements($this->store->getVar(SIP_RECORD_ID, STORE_SIP), FORM_ELEMENTS_SUBRECORD, $json);
     }
@@ -69,6 +70,7 @@ class BuildFormPlain extends AbstractBuildForm {
      * @param $htmlFormElementName
      * @param $formElement
      * @param $value
+     *
      * @return string
      */
     public function buildRowNative(array $formElement, $htmlElement, $htmlFormElementName) {
@@ -78,13 +80,13 @@ class BuildFormPlain extends AbstractBuildForm {
 //        $buildElementFunctionName = 'build' . $this->buildElementFunctionName[$formElement[FE_TYPE]];
 
 
-        if($formElement['nestedInFieldSet']==='no') {
+        if ($formElement['nestedInFieldSet'] === 'no') {
             $html .= $this->wrap[WRAP_SETUP_ELEMENT][WRAP_SETUP_START];
         }
         $html .= $this->wrapItem(WRAP_SETUP_LABEL, $formElement[FE_LABEL]);
         $html .= $this->wrapItem(WRAP_SETUP_INPUT, $htmlElement);
         $html .= $this->wrapItem(WRAP_SETUP_NOTE, $formElement[FE_NOTE]);
-        if($formElement['nestedInFieldSet']==='no') {
+        if ($formElement['nestedInFieldSet'] === 'no') {
             $html .= $this->wrap[WRAP_SETUP_ELEMENT][WRAP_SETUP_END];
         }
 
diff --git a/extension/qfq/qfq/BuildFormTable.php b/extension/qfq/qfq/BuildFormTable.php
index a78aeb4621a622f104853f31ccbb6ddae0d5a2b7..9fda201e812d879410173d3ae9b74e951cd866d8 100644
--- a/extension/qfq/qfq/BuildFormTable.php
+++ b/extension/qfq/qfq/BuildFormTable.php
@@ -51,6 +51,7 @@ class BuildFormTable extends AbstractBuildForm {
     public function fillWrapLabelInputNote($label, $input, $note) {
 
     }
+
     /**
      * @return string
      */
@@ -64,6 +65,7 @@ class BuildFormTable extends AbstractBuildForm {
     public function doSubrecords() {
         //TODO: $json is not returned - which is wrong. In this case, dynamic update won't work for subrecords
         $json = array();
+
         return $this->elements($this->store->getVar(SIP_RECORD_ID, STORE_SIP), FORM_ELEMENTS_SUBRECORD, $json);
     }
 
@@ -73,7 +75,7 @@ class BuildFormTable extends AbstractBuildForm {
     public function head() {
         $html = '';
 
-        $html .= '<div ' . Support::doAttribute('class', $this->formSpec[F_CLASS], TRUE) . '>'; // main <div class=...> around everything
+        $html .= '<div ' . Support::doAttribute('class', $this->formSpec[F_CLASS], true) . '>'; // main <div class=...> around everything
 
         // Logged in BE User will see a FormEdit Link
         $sipParamString = OnArray::toString($this->store->getStore(STORE_SIP), ':', ', ', "'");
@@ -93,7 +95,7 @@ class BuildFormTable extends AbstractBuildForm {
     /**
      * @param $htmlFormElementName
      * @param $formElement
-     * @param $value
+     *
      * @return string
      */
     public function buildRowNative(array $formElement, $htmlElement, $htmlFormElementName) {
@@ -117,7 +119,7 @@ class BuildFormTable extends AbstractBuildForm {
             } else {
                 $html .= $this->wrapItem(WRAP_SETUP_IN_FIELDSET, $formElement[FE_LABEL]);
                 $html .= $this->wrapItem(WRAP_SETUP_IN_FIELDSET, $htmlElement);
-                if($formElement[FE_NOTE]!=='')
+                if ($formElement[FE_NOTE] !== '')
                     $html .= $this->wrapItem(WRAP_SETUP_IN_FIELDSET, $formElement[FE_NOTE]);
             }
         }
diff --git a/extension/qfq/qfq/Constants.php b/extension/qfq/qfq/Constants.php
index 081f8622c0570e444f63b2681a7c54449d549f94..205547ea90ecd8a5de6faa9f47ac6357b7ba4a66 100644
--- a/extension/qfq/qfq/Constants.php
+++ b/extension/qfq/qfq/Constants.php
@@ -178,7 +178,7 @@ const ERROR_PLAY_SQL_FILE = 1080;
 
 // Subrecord
 const ERROR_SUBRECORD_MISSING_COLUMN_ID = 1100;
-
+const ERROR_SUBRECORD_DETAIL_COLUMN_NOT_FOUND = 'Column not found in primary record or current row';
 // Store
 const ERROR_STORE_VALUE_ALREADY_CODPIED = 1200;
 const ERROR_STORE_KEY_EXIST = 1201;
@@ -330,7 +330,7 @@ const CLIENT_COOKIE_QFQ = 'cookieQfq';
 // T3 Bodytext Keywords
 const TYPO3_FORM = CLIENT_FORM;
 const TYPO3_RECORD_ID = CLIENT_RECORD_ID;
-const TYPO3_BE_USER_LOGGED_IN = 'beUser';   // 'yes' | 'no'
+const TYPO3_BE_USER_LOGGED_IN = 'beUserLoggedIn';   // 'yes' | 'no'
 const TYPO3_FE_USER = 'feUser';
 const TYPO3_FE_USER_UID = 'feUserUid';
 const TYPO3_FE_USER_GROUP = 'feUserGroup';
@@ -410,6 +410,10 @@ const GET_EXTRA_LENGTH_TOKEN = '_';
 
 const SYSTEM_GFX_EXTRA_BUTTON_INFO_INLINE = 'GFX_EXTRA_BUTTON_INFO_INLINE';
 const SYSTEM_GFX_EXTRA_BUTTON_INFO_BELOW = 'GFX_EXTRA_BUTTON_INFO_BELOW';
+const SYSTEM_EXTRA_BUTTON_INFO_POSITION = 'EXTRA_BUTTON_INFO_POSITION';
+const SYSTEM_EXTRA_BUTTON_INFO_POSITION_AUTO = 'auto';
+const SYSTEM_EXTRA_BUTTON_INFO_POSITION_BELOW = 'below';
+const SYSTEM_EXTRA_BUTTON_INFO_CLASS = 'EXTRA_BUTTON_INFO_CLASS';
 
 const SYSTEM_SAVE_BUTTON_TEXT = 'SAVE_BUTTON_TEXT';
 const SYSTEM_SAVE_BUTTON_TOOLTIP = 'SAVE_BUTTON_TOOLTIP';
@@ -479,6 +483,7 @@ const DOWNLOAD_POPUP_REQUEST = 'true';
 const DOWNLOAD_POPUP_REPLACE_TEXT = '#downloadPopupReplaceText#';
 const DOWNLOAD_POPUP_REPLACE_TITLE = '#downloadPopupReplaceTitle#';
 
+const SYSTEM_PARAMETER_LANGUAGE_FIELD_NAME = 'parameterLanguageFieldName';
 const CSS_REQUIRED = 'required-field';
 
 // die folgenden Elemente sind vermutlich nicht noetig, wenn Store Klassen gloable Vars benutzt.
@@ -660,6 +665,7 @@ const CLASS_FORM_ELEMENT_EDIT = 'qfq-form-element-edit';
 // BuildForm
 const SYMBOL_NEW = 'new';
 const SYMBOL_EDIT = 'edit';
+const SYMBOL_SHOW = 'show';
 const SYMBOL_DELETE = 'delete';
 
 //CHECKBOX
@@ -699,7 +705,8 @@ const F_ID = 'id';
 const F_NAME = 'name';
 const F_TITLE = 'title';
 const F_TABLE_NAME = 'tableName';
-const F_REQUIRED_PARAMETER = 'requiredParameter';
+const F_REQUIRED_PARAMETER_NEW = 'requiredParameterNew';
+const F_REQUIRED_PARAMETER_EDIT = 'requiredParameterEdit';
 const F_EXTRA_DELETE_FORM = 'extraDeleteForm';
 const F_FINAL_DELETE_FORM = 'finalDeleteForm';
 const F_DIRTY_MODE = 'dirtyMode';
@@ -752,6 +759,8 @@ const F_TYPEAHEAD_LDAP_SEARCH_PER_TOKEN = 'typeAheadLdapSearchPerToken';
 
 const F_MODE = 'mode';
 const F_MODE_READONLY = 'readonly';
+const F_MODE_REQUIRED_OFF = 'requiredOff';
+const F_MODE_GLOBAL = 'formModeGlobal';
 
 const F_SAVE_BUTTON_ACTIVE = 'saveButtonActive';
 
@@ -891,6 +900,7 @@ const FE_CHARACTER_COUNT_WRAP = 'characterCountWrap';
 const FE_INPUT_EXTRA_BUTTON_LOCK = 'extraButtonLock';
 const FE_INPUT_EXTRA_BUTTON_PASSWORD = 'extraButtonPassword';
 const FE_INPUT_EXTRA_BUTTON_INFO = 'extraButtonInfo';
+const FE_INPUT_EXTRA_BUTTON_INFO_CLASS = 'extraButtonInfoClass';
 const FE_TMP_EXTRA_BUTTON_HTML = '_extraButtonHtml'; // will be filled on the fly during building extrabutton
 const FE_CHECKBOX_CHECKED = 'checked';
 const FE_CHECKBOX_UNCHECKED = 'unchecked';
@@ -900,6 +910,7 @@ const FE_TRANSLATE_ID_COLUMN = 'translateIdColumn';
 const FE_EMPTY_MEANS_NULL = 'emptyMeansNull';
 const FE_EMPTY_ITEM_AT_START = 'emptyItemAtStart';
 const FE_EMPTY_ITEM_AT_END = 'emptyItemAtEnd';
+const FE_SUBRECORD_TABLE_CLASS = 'subrecordTableClass';
 
 const FE_FLAG_ROW_OPEN_TAG = '_flagRowOpenTag'; // will be automatically computed during Formload: true | false
 const FE_FLAG_ROW_CLOSE_TAG = '_flagRowCloseTag'; // will be automatically computed during Formload: true | false
@@ -946,6 +957,8 @@ const FE_TYPE_PASTE = 'paste';
 
 const FE_TYPE_TEMPLATE_GROUP = 'templateGroup';
 
+const SHEBANG_REPORT = '#!report';
+
 // SUPPORT
 const PARAM_T3_ALL = 't3 all';
 const PARAM_T3_NO_ID = "t3 no id";
@@ -1173,4 +1186,3 @@ const AUTOCRON_SQL1 = 'sql1';
 const AUTOCRON_UNIT = 'unit';
 const AUTOCRON_COUNT = 'count';
 
-
diff --git a/extension/qfq/qfq/Delete.php b/extension/qfq/qfq/Delete.php
index b51c2b3b7aca4eee592a7cd94d6510b0b60b7481..fdf71624528e292163ea82f646fdf2c2cb0fb1f6 100644
--- a/extension/qfq/qfq/Delete.php
+++ b/extension/qfq/qfq/Delete.php
@@ -35,10 +35,12 @@ class Delete {
     /**
      * Deletes the record id=$recordId from table $form[F_TABLE_NAME].
      * If the table has a column named COLUMN_PATH_FILE_NAME and the value of that specific record column points
-     * to a file: delete such a file if their are no other records in the same table which also have a reference to that file.
+     * to a file: delete such a file if their are no other records in the same table which also have a reference to
+     * that file.
      *
-     * @param string $tableName
+     * @param string  $tableName
      * @param integer $recordId
+     *
      * @throws CodeException
      * @throws DbException
      * @throws UserFormException
@@ -84,7 +86,8 @@ class Delete {
      * If no: do nothing, continue with the next column.
      *
      * @param array $row
-     * @param $tableName
+     * @param       $tableName
+     *
      * @throws CodeException
      * @throws DbException
      * @throws UserFormException
diff --git a/extension/qfq/qfq/Evaluate.php b/extension/qfq/qfq/Evaluate.php
index 175e1473686af5f0592c6d1bb66426144f70992b..93b9ca22927429e4521c21082ceae21babc80e94 100644
--- a/extension/qfq/qfq/Evaluate.php
+++ b/extension/qfq/qfq/Evaluate.php
@@ -9,7 +9,6 @@
 namespace qfq;
 
 use qfq;
-use qfq\Store;
 
 require_once(__DIR__ . '/../qfq/store/Store.php');
 require_once(__DIR__ . '/../qfq/database/Database.php');
@@ -33,7 +32,7 @@ class Evaluate {
     private $startDelimiterLength = 0;
     private $endDelimiter = '';
     private $endDelimiterLength = 0;
-    private $sqlKeywords = array('SELECT ', 'INSERT ', 'DELETE ', 'UPDATE ', 'SHOW ');
+    private $sqlKeywords = array('SELECT ', 'INSERT ', 'DELETE ', 'UPDATE ', 'SHOW ', 'REPLACE ');
     private $escapeTypeDefault = '';
 
 //    private $debugStack = array();
@@ -41,9 +40,9 @@ class Evaluate {
 
     /**
      * @param \qfq\Store $store
-     * @param Database $db
-     * @param string $startDelimiter
-     * @param string $endDelimiter
+     * @param Database   $db
+     * @param string     $startDelimiter
+     * @param string     $endDelimiter
      */
     public function __construct(Store $store, Database $db, $startDelimiter = '{{', $endDelimiter = '}}') {
         $this->store = $store;
@@ -58,9 +57,10 @@ class Evaluate {
     /**
      * Evaluate a whole array or a array of arrays.
      *
-     * @param $tokenArray
+     * @param       $tokenArray
      * @param array $skip Optional Array with keynames, which will not be evaluated.
      * @param array $debugStack
+     *
      * @return array
      * @throws UserFormException
      */
@@ -87,13 +87,14 @@ class Evaluate {
     }
 
     /**
-     * Recursive evaluation of 'line'. Constant string, Variables or SQL Query or all of them. All queries will be fired.
-     * In case of an 'INSERT' statement, return the last_insert_id().
+     * Recursive evaluation of 'line'. Constant string, Variables or SQL Query or all of them. All queries will be
+     * fired. In case of an 'INSERT' statement, return the last_insert_id().
      *
      * Token to replace have to be enclosed by '{{' and '}}'
      *
-     * @param $line
+     * @param     $line
      * @param int $recursion
+     *
      * @return array|mixed|null|string
      * @throws UserFormException
      */
@@ -179,7 +180,9 @@ class Evaluate {
      * If neither a) or b) match, return the token itself.
      *
      * @param string $token
-     * @param string $foundInStore Returns the name of the store where $key has been found. If $key is not found, return ''.
+     * @param string $foundInStore Returns the name of the store where $key has been found. If $key is not found,
+     *                             return ''.
+     *
      * @return array|null|string
      * @throws CodeException
      * @throws DbException
@@ -202,6 +205,7 @@ class Evaluate {
         // SQL Statement?
         if (in_array(strtoupper($arr[0] . ' '), $this->sqlKeywords)) {
             $foundInStore = TOKEN_FOUND_IN_STORE_QUERY;
+
             return $this->db->sql($token, $sqlMode);
         }
 
diff --git a/extension/qfq/qfq/File.php b/extension/qfq/qfq/File.php
index 58e4f6cc1bf6e4de15207e293c9073e1b815a53c..46abe13f09cb5c16e2dffad7d1f1c34c2d5265c7 100644
--- a/extension/qfq/qfq/File.php
+++ b/extension/qfq/qfq/File.php
@@ -34,13 +34,13 @@ class File {
         $this->store = Store::getInstance('', $phpUnit);
 
         $this->uploadErrMsg = [
-            UPLOAD_ERR_INI_SIZE => "The uploaded file exceeds the upload_max_filesize directive in php.ini",
+            UPLOAD_ERR_INI_SIZE  => "The uploaded file exceeds the upload_max_filesize directive in php.ini",
             UPLOAD_ERR_FORM_SIZE => "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form",
-            UPLOAD_ERR_PARTIAL => "The uploaded file was only partially uploaded",
-            UPLOAD_ERR_NO_FILE => "No file was uploaded",
+            UPLOAD_ERR_PARTIAL   => "The uploaded file was only partially uploaded",
+            UPLOAD_ERR_NO_FILE   => "No file was uploaded",
             UPLOAD_ERR_NO_TMP_DIR => "Missing a temporary folder",
             UPLOAD_ERR_CANT_WRITE => "Failed to write file to disk",
-            UPLOAD_ERR_EXTENSION => "File upload stopped by extension"
+            UPLOAD_ERR_EXTENSION => "File upload stopped by extension",
         ];
     }
 
@@ -73,7 +73,8 @@ class File {
 
     /**
      * @param string $sipUpload
-     * @param array $statusUpload
+     * @param array  $statusUpload
+     *
      * @throws CodeException
      * @throws UserFormException
      */
@@ -106,13 +107,15 @@ class File {
     /**
      * Checks the file filetype against the allowed mimetype definition. Return true as soon as one match is found.
      * Types recognized:
-     *   * 'mime type' as delivered by `file` which matches a definition on http://www.iana.org/assignments/media-types/media-types.xhtml
+     *   * 'mime type' as delivered by `file` which matches a definition on
+     *   http://www.iana.org/assignments/media-types/media-types.xhtml
      *   * Joker based: audio/*, video/*, image/*
      *   * Filename extension based: .pdf,.doc,..
      *
      * @param string $tmp_name
      * @param string $name
      * @param string $accept
+     *
      * @return bool
      * @throws UserFormException
      */
@@ -165,6 +168,7 @@ class File {
     /**
      * @param $sipUpload
      * @param $statusUpload
+     *
      * @throws CodeException
      * @throws UserFormException
      * @internal param string $keyStoreExtra
diff --git a/extension/qfq/qfq/QuickFormQuery.php b/extension/qfq/qfq/QuickFormQuery.php
index 5c91186fecec58ac203809988d6d524f3fb849a5..4b6907974c6ca037bfda1112ea2b962f9b479d04 100644
--- a/extension/qfq/qfq/QuickFormQuery.php
+++ b/extension/qfq/qfq/QuickFormQuery.php
@@ -111,11 +111,12 @@ class QuickFormQuery {
     /**
      * Construct the Form Class and Store too. This is the base initialization moment.
      *
-     * As a result of instantiating of Form, the class Store will initially called the first time and therefore instantiated automatically.
-     * Store might throw an exception, in case the URL-passed SIP is invalid.
+     * As a result of instantiating of Form, the class Store will initially called the first time and therefore
+     * instantiated automatically. Store might throw an exception, in case the URL-passed SIP is invalid.
      *
      * @param array $t3data
-     * @param bool $phpUnit
+     * @param bool  $phpUnit
+     *
      * @throws CodeException
      * @throws UserFormException
      */
@@ -167,7 +168,8 @@ class QuickFormQuery {
      */
     public function getForwardMode() {
 
-        $forwardPage = $this->eval->parse($this->formSpec[F_FORWARD_PAGE]);
+        $forwardPage = $this->formSpec[F_FORWARD_PAGE];
+
         if ($this->formSpec[F_FORWARD_MODE] == F_FORWARD_MODE_URL_SIP) {
             $forwardPage = store::getSipInstance()->queryStringToSip($forwardPage, RETURN_URL);
             // F_FORWARD_MODE_URL_SIP is not defined in API PROTOCOL. At the moment it's only used for 'copyForm'.
@@ -211,6 +213,25 @@ class QuickFormQuery {
         return $html;
     }
 
+    /**
+     * Determine the name of the language parameter field, which has to be taken to fill language specific defintions.
+     */
+    private function setParameterLanguageFieldName() {
+
+        $typo3PageLanguage = $this->store->getVar(TYPO3_PAGE_LANGUAGE, STORE_TYPO3);
+        if (empty($typo3PageLanguage)) {
+            return;
+        }
+
+        foreach (['A', 'B', 'C', 'D'] as $key) {
+            $languageIdx = SYSTEM_FORM_LANGUAGE . "_$key" . "_ID";
+            if ($this->store->getVar($languageIdx, STORE_SYSTEM) == $typo3PageLanguage) {
+                $this->store->setVar(SYSTEM_PARAMETER_LANGUAGE_FIELD_NAME, 'parameterLanguage' . $key, STORE_SYSTEM);
+                break;
+            }
+        }
+    }
+
     /**
      * Process form.
      * $mode=
@@ -220,6 +241,7 @@ class QuickFormQuery {
      *   FORM_DELETE:
      *
      * @param string $formMode FORM_LOAD | FORM_UPDATE | FORM_SAVE | FORM_DELETE
+     *
      * @return array|string
      * @throws CodeException
      * @throws UserFormException
@@ -235,6 +257,7 @@ class QuickFormQuery {
         }
 
         $recordId = $this->store->getVar(SIP_RECORD_ID, STORE_SIP . STORE_TYPO3 . STORE_CLIENT . STORE_ZERO);
+        $this->setParameterLanguageFieldName();
 
         $formName = $this->loadFormSpecification($formMode, $recordId, $foundInStore);
         if ($formName === false && $formMode !== FORM_DELETE) {
@@ -277,6 +300,7 @@ class QuickFormQuery {
             // In case of a conflict, return immediately
             if ($answer[API_STATUS] != API_ANSWER_STATUS_SUCCESS) {
                 $answer[API_STATUS] = API_ANSWER_STATUS_ERROR;
+
                 return $answer;
             }
         }
@@ -370,28 +394,34 @@ class QuickFormQuery {
                 // Action: Sendmail
                 $formAction->elements($rc, $this->feSpecAction, FE_TYPE_SENDMAIL);
 
-                //                $htmlElementNameIdZero = false;
+
+                $customForward = $this->setForwardModePage();
+
+                // Logic: If a) r=0 and
+                //           b) User presses only 'save' (not save & close) and
+                //           c) there is no forwardMode=='url...'
+                // then the client should reload the current page with the newly created record. A new SIP is necessary!
                 $getJson = true;
-                // Retrieve current STORE_SIP.
-                $sipArray = $this->store->getStore(STORE_SIP);
-                if ($sipArray[SIP_RECORD_ID] == 0 && API_SUBMIT_REASON_SAVE == $this->store->getVar(API_SUBMIT_REASON, STORE_CLIENT . STORE_EMPTY, SANITIZE_ALLOW_ALNUMX)) {
-//                if ($sipArray[SIP_RECORD_ID] == 0 ) {
-
-                    if ($this->formSpec[F_FORWARD_MODE] !== F_FORWARD_MODE_URL &&
-                        $this->formSpec[F_FORWARD_MODE] !== F_FORWARD_MODE_URL_SKIP_HISTORY &&
-                        $this->formSpec[F_FORWARD_MODE] !== F_FORWARD_MODE_URL_SIP
-                    ) {
-                        $this->formSpec = $this->buildNSetReloadUrl($this->formSpec, $rc);
-                    }
+                if (0 == $this->store->getVar(SIP_RECORD_ID, STORE_SIP) &&
+                    API_SUBMIT_REASON_SAVE == $this->store->getVar(API_SUBMIT_REASON, STORE_CLIENT . STORE_EMPTY, SANITIZE_ALLOW_ALNUMX) &&
+                    $customForward == false
+                ) {
+                    $this->formSpec = $this->buildNSetReloadUrl($this->formSpec, $rc);
                     $getJson = false;
                 }
 
                 if ($getJson) {
+
+                    // Values of FormElements might be changed during 'afterSave': rebuild the form to load the new values. Especially for non primary template groups.
+//                    $this->loadFormSpecification($formMode, $recordId, $foundInStore);
+                    $this->feSpecNative = $this->getNativeFormElements(SQL_FORM_ELEMENT_NATIVE_TG_COUNT, [$this->formSpec["id"]], $this->formSpec);
+
                     // Retrieve FE Values as JSON
                     // $data['form-update']=...
-//                    $data = $build->process($formMode, $htmlElementNameIdZero);
-                    $data = $build->process($formMode);
+                    // $data = $build->process($formMode, $htmlElementNameIdZero);
+                    $data = $build->process($formMode, false, $this->feSpecNative);
                 }
+
                 break;
 
             default:
@@ -406,11 +436,78 @@ class QuickFormQuery {
         return $data;
     }
 
+
+    /**
+     * Check if forwardMode='url...'.
+     * yes: process 'forwardPage' and fill $this->formSpec[F_FORWARD_MODE] and $this->formSpec[F_FORWARD_PAGE]
+     * no: do nothing
+     *
+     * '$this->formSpec[F_FORWARD_PAGE]' might give a new forwardMode. If so, set $this->formSpec[F_FORWARD_MODE] to
+     * it.
+     *
+     * '$this->formSpec[F_FORWARD_PAGE]':
+     * a) url     http://www.nzz.ch/index.html?a=123#bottom, website.html?a=123#bottom,
+     *            ?<T3 Alias pageid>&a=123#bottom, ?id=<T3 page id>&a=123#bottom
+     * b) mode      no|client|url|...
+     * c) mode|url  combination of above
+     *
+     * @return bool  TRUE if F_FORWARD_MODE = 'url..', else FALSE
+     *
+     * @throws UserFormException
+     */
+    private function setForwardModePage() {
+
+        if ('url' != substr($this->formSpec[F_FORWARD_MODE], 0, 3)) {
+            return false;
+        }
+
+        $forwardPageTmp = $this->eval->parse($this->formSpec[F_FORWARD_PAGE]);
+
+        // Format: [mode/url][|url]
+        $forwardArray = explode('|', $forwardPageTmp, 2);
+        $forward = trim($forwardArray[0]);
+        switch ($forward) {
+
+            case F_FORWARD_MODE_CLIENT:
+            case F_FORWARD_MODE_NO:
+            case F_FORWARD_MODE_URL:
+            case F_FORWARD_MODE_URL_SKIP_HISTORY:
+            case F_FORWARD_MODE_URL_SIP:
+                $this->formSpec[F_FORWARD_MODE] = $forward;
+                if (isset($forwardArray[1])) {
+                    $this->formSpec[F_FORWARD_PAGE] = trim($forwardArray[1]);
+                } else {
+                    $this->formSpec[F_FORWARD_PAGE] = '';
+                }
+                break;
+
+            default:
+                $this->formSpec[F_FORWARD_PAGE] = $forward;
+                break;
+        }
+
+        if ('url' == substr($this->formSpec[F_FORWARD_MODE], 0, 3)) {
+            if ($this->formSpec[F_FORWARD_PAGE] == '') {
+                $this->formSpec[F_FORWARD_MODE] = F_FORWARD_MODE_CLIENT;
+                $customForward = false;
+            } else {
+                $customForward = true;
+            }
+
+        } else {
+            $customForward = false;
+        }
+
+        return $customForward;
+
+    }
+
     /**
      * Iterate over all Clipboard source records and fire for each all FE.type=paste records.
      *
-     * @param int $formId
+     * @param int        $formId
      * @param FormAction $formAction
+     *
      * @throws CodeException
      * @throws DbException
      * @throws UserFormException
@@ -447,6 +544,7 @@ class QuickFormQuery {
                 return true;
             }
         }
+
         return false;
 
     }
@@ -456,7 +554,8 @@ class QuickFormQuery {
      * used parameters. Do this by building a new SIP with the new recordId.
      *
      * @param array $formSpec
-     * @param int $recordId
+     * @param int   $recordId
+     *
      * @return array
      * @throws CodeException
      * @throws UserFormException
@@ -490,8 +589,9 @@ class QuickFormQuery {
      * Loaded 'native' FormElements are in $this->feSpecNative
      *
      * @param string $mode FORM_LOAD|FORM_SAVE|FORM_UPDATE
-     * @param int $recordId
+     * @param int    $recordId
      * @param string $foundInStore
+     *
      * @return bool|string if found the formName, else 'false'.
      * @throws CodeException
      * @throws DbException
@@ -519,7 +619,8 @@ class QuickFormQuery {
         }
 
         // Load form
-        $form = $this->db->sql("SELECT * FROM Form AS f WHERE f." . F_NAME . " LIKE ? AND f.deleted='no'", ROW_EXPECT_1,
+        $constant = F_NAME; // PhpStorm complains if the constant is directly defined in the string below
+        $form = $this->db->sql("SELECT * FROM Form AS f WHERE f.$constant LIKE ? AND f.deleted='no'", ROW_EXPECT_1,
             [$formName], 'Form not found or multiple forms with the same name.');
 
         $form = $this->modeCleanFormConfig($mode, $form);
@@ -530,7 +631,9 @@ class QuickFormQuery {
 
         $formSpec = $this->eval->parseArray($form);
         HelperFormElement::explodeParameter($formSpec, F_PARAMETER);
-        $formSpec = $this->setLanguage($formSpec);
+
+        $parameterLanguageFieldName = $this->store->getVar(SYSTEM_PARAMETER_LANGUAGE_FIELD_NAME, STORE_SYSTEM);
+        $formSpec = HelperFormElement::setLanguage($formSpec, $parameterLanguageFieldName);
 
         $formSpec = $this->syncSystemFormConfig($formSpec);
         $formSpec = $this->initForm($formSpec);
@@ -563,7 +666,6 @@ class QuickFormQuery {
 
             case FORM_SAVE:
             case FORM_UPDATE:
-//              $this->feSpecNative = $this->db->getNativeFormElements(SQL_FORM_ELEMENT_ALL_CONTAINER, ['no', $this->formSpec["id"], 'native'], $this->formSpec);
             $feSpecNative = $this->getNativeFormElements(SQL_FORM_ELEMENT_NATIVE_TG_COUNT, [$this->formSpec["id"]], $this->formSpec);
                 break;
 
@@ -575,47 +677,20 @@ class QuickFormQuery {
                 break;
         }
 
-        $this->feSpecNative = $this->setLanguage($feSpecNative);
+        $this->feSpecNative = HelperFormElement::setLanguage($feSpecNative, $parameterLanguageFieldName);
 
         return $formName;
     }
 
-    /**
-     * @param array $formSpec
-     * @return array
-     * @throws UserFormException
-     */
-    private function setLanguage(array $formSpec) {
-
-        $typo3PageLanguage = $this->store->getVar(TYPO3_PAGE_LANGUAGE, STORE_TYPO3);
-        if (empty($typo3PageLanguage)) {
-            return $formSpec;
-        }
-
-        foreach (['A', 'B', 'C', 'D'] as $key) {
-            $languageIdx = SYSTEM_FORM_LANGUAGE . "_$key" . "_ID";
-            if ($this->store->getVar($languageIdx, STORE_SYSTEM) == $typo3PageLanguage) {
-                $parameterField = 'parameterLanguage' . $key;
-                break;
-            }
-        }
-
-        if (!isset($parameterField)) {
-            throw new UserFormException("Language not configured in QFQ for L=" . $typo3PageLanguage, ERROR_LANGUAGE_NOT_CONFIGURED_IN_QFQ);
-        }
-
-        HelperFormElement::explodeParameter($formSpec, $parameterField, true);
-
-        return $formSpec;
-    }
-
     /**
      * Depending on $sql reads FormElements to a specific container or all. Preprocess all FormElements.
-     * This code is dirty: the nearly same function exists in class 'Database' - the difference is only 'explodeTemplateGroupElements()'.
+     * This code is dirty: the nearly same function exists in class 'Database' - the difference is only
+     * 'explodeTemplateGroupElements()'.
+     *
+     * @param string $sql      SQL_FORM_ELEMENT_SPECIFIC_CONTAINER | SQL_FORM_ELEMENT_ALL_CONTAINER
+     * @param array  $param    Parameter which matches the prepared statement in $sql
+     * @param array  $formSpec Main FormSpec to copy generic parameter to FormElements
      *
-     * @param string $sql SQL_FORM_ELEMENT_SPECIFIC_CONTAINER | SQL_FORM_ELEMENT_ALL_CONTAINER
-     * @param array $param Parameter which matches the prepared statement in $sql
-     * @param array $formSpec Main FormSpec to copy generic parameter to FormElements
      * @return array|int
      * @throws \qfq\CodeException
      * @throws \qfq\DbException
@@ -642,16 +717,18 @@ class QuickFormQuery {
     }
 
     /**
-     * Iterate over all FormElements in $elements. If a row has a column NAME_TG_COPIES, copy those elements NAME_TG_COPIES-times.
-     * Adjust FE_TEMPLATE_GROUP_NAME_PATTERN (='%d') with current count on column FE_NAME and FE_LABEL.
+     * Iterate over all FormElements in $elements. If a row has a column NAME_TG_COPIES, copy those elements
+     * NAME_TG_COPIES-times. Adjust FE_TEMPLATE_GROUP_NAME_PATTERN (='%d') with current count on column FE_NAME and
+     * FE_LABEL.
      *
-     * This code is dirty: only to get JSON value, we have to initialize the STORE_RECORD (done earlier) to be capable to
-     *  parse fe[FE_VALUE], which probably contains as string like '{{!SELECT value FROM table WHERE xId={{id}} ORDER BY id}}' -
-     *  the {{id}} needs to be replaced by the current recordId (primary record).
+     * This code is dirty: only to get JSON value, we have to initialize the STORE_RECORD (done earlier) to be capable
+     * to parse fe[FE_VALUE], which probably contains as string like '{{!SELECT value FROM table WHERE xId={{id}} ORDER
+     * BY id}}' - the {{id}} needs to be replaced by the current recordId (primary record).
      *
      * Attention: The resulting order of the FormElements, is not the same as on the Form during FormLoad!
      *
      * @param array $elements
+     *
      * @return array
      */
     private function explodeTemplateGroupElements(array $elements) {
@@ -674,12 +751,14 @@ class QuickFormQuery {
                     unset($tmpRow[NAME_TG_COPIES]);
                     $tmpRow[FE_NAME] = str_replace(FE_TEMPLATE_GROUP_NAME_PATTERN, $ii, $tmpRow[FE_NAME]);
                     $tmpRow[FE_LABEL] = str_replace(FE_TEMPLATE_GROUP_NAME_PATTERN, $ii, $tmpRow[FE_LABEL]);
+                    $tmpRow[FE_TG_INDEX] = $ii;
                     $new[] = $tmpRow;
                 }
             } else {
                 $new[] = $row;
             }
         }
+
         return $new;
     }
 
@@ -691,9 +770,9 @@ class QuickFormQuery {
      *   Specified in T3 body text with form=<formname>            Returned Store:Typo3
      *   Specified in T3 body text with form={{form}} ':FSRD'      Returned Store:SIP
      *   Specified in T3 body text with form={{form:C:ALNUMX}}     Returned Store:Client
-     *   Specified in T3 body text with form={{SELECT registrationFormName FROM Conference WHERE id={{conferenceId:S0}} }}
-     *   Specified in T3 body text with form={{SELECT registrationFormName FROM Conference WHERE id={{conferenceId:C0:DIGIT}} }}
-     *   Specified in SIP
+     *   Specified in T3 body text with form={{SELECT registrationFormName FROM Conference WHERE id={{conferenceId:S0}}
+     *   }} Specified in T3 body text with form={{SELECT registrationFormName FROM Conference WHERE
+     *   id={{conferenceId:C0:DIGIT}} }} Specified in SIP
      *
      * FORM_SAVE:
      *   Specified in SIP
@@ -701,6 +780,7 @@ class QuickFormQuery {
      *
      * @param string $mode FORM_LOAD|FORM_SAVE|FORM_UPDATE
      * @param string $foundInStore
+     *
      * @return bool|string  Formname (Form.name) or FALSE (if no formname found)
      * @throws CodeException
      * @throws UserFormException
@@ -745,7 +825,8 @@ class QuickFormQuery {
      * E.g.: the form title is not important during a delete.
      *
      * @param string $mode
-     * @param array $form
+     * @param array  $form
+     *
      * @return array
      */
     private function modeCleanFormConfig($mode, array $form) {
@@ -767,9 +848,10 @@ class QuickFormQuery {
      * STORE_SYSTEM if filled with the default values (config.qfq.ini or if note exist than QFQ hardcoded)
      * Copying the 'Form' definition back to the system store helps to access the values
      * by '{{ ...:Y}}' (system store). E.g. the value of bs-*-columns might be displayed as placeholder in the
-     * corresponding inputfield.
+     * corresponding input field.
      *
      * @param array $formSpec
+     *
      * @return array
      */
     private function syncSystemFormConfig(array $formSpec) {
@@ -809,6 +891,7 @@ class QuickFormQuery {
 
             F_RECORD_LOCK_TIMEOUT_SECONDS,
 
+            FE_INPUT_EXTRA_BUTTON_INFO_CLASS,
         ];
 
         // By definition: existing vars which are empty, means: EMPTY - do not use any default!
@@ -836,6 +919,7 @@ class QuickFormQuery {
      * Set form parameter which are expected to exist.
      *
      * @param array $formSpec
+     *
      * @return array
      */
     private function initForm(array $formSpec) {
@@ -845,6 +929,14 @@ class QuickFormQuery {
         Support::setIfNotSet($formSpec, F_LDAP_USE_BIND_CREDENTIALS, '');
         Support::setIfNotSet($formSpec, F_MODE, '');
 
+        // In case there is no F_MODE defined on the form, check if there is one in STORE_SIP.
+        if ($formSpec[F_MODE] == '') {
+            $formModeGlobal = $this->store->getVar(F_MODE_GLOBAL, STORE_SIP);
+            if ($formModeGlobal !== false) {
+                $formSpec[F_MODE] = $formModeGlobal;
+            }
+        }
+
         if ($formSpec[F_MODE] == F_MODE_READONLY) {
             $formSpec[F_SHOW_BUTTON] = FORM_BUTTON_CLOSE;
             $formSpec[F_SUBMIT_BUTTON_TEXT] = '';
@@ -862,6 +954,7 @@ class QuickFormQuery {
      *
      * @param string $formNameFoundInStore
      * @param string $formMode
+     *
      * @return bool 'true' if SIP exists, else 'false'
      * @throws \qfq\CodeException
      * @throws \qfq\UserFormException
@@ -872,7 +965,7 @@ class QuickFormQuery {
         // Retrieve record_id either from SIP (prefered) or via URL
         $r = $this->store->getVar(SIP_RECORD_ID, STORE_SIP . STORE_TYPO3 . STORE_CLIENT, '', $recordIdFoundInStore);
 
-        // Set missing 'r'.
+        // If not found: Fake a definition in STORE_TYPO3.
         if ($r === false) {
             $r = 0;
             $this->store->setVar(TYPO3_RECORD_ID, $r, STORE_TYPO3);
@@ -924,7 +1017,8 @@ class QuickFormQuery {
         if ($formMode !== FORM_DELETE) {
             $sipArray = $this->store->getStore(STORE_SIP);
             // Check: requiredParameter: '' or 'form' or 'form,grId' or 'form #formname for form,grId'
-            $param = explode(',', $this->formSpec[F_REQUIRED_PARAMETER]);
+            $requiredParameter = ($r > 0) ? $this->formSpec[F_REQUIRED_PARAMETER_EDIT] : $this->formSpec[F_REQUIRED_PARAMETER_NEW];
+            $param = explode(',', $requiredParameter);
             foreach ($param AS $name) {
 
                 $name = explode('#', $name, 2);
@@ -949,6 +1043,7 @@ class QuickFormQuery {
      * @param string $table tablename from where to load record wiht $recordId
      * @param string $recordId record ID of current record
      * @param string $store name of store where to save the record
+     *
      * @throws CodeException
      * @throws DbException
      * @throws UserFormException
@@ -965,6 +1060,7 @@ class QuickFormQuery {
      * All found elements collect under $collect[API_ELEMENT_UPDATE]... . Leave the rest unchanged.
      *
      * @param array $dataArray
+     *
      * @return array to build JSON
      */
     private function groupElementUpdateEntries(array $dataArray) {
@@ -1045,7 +1141,7 @@ class QuickFormQuery {
      * Based on the given SIP, create a new uniqe SIP by copying the relevant old params and taking the new recordId..
      *
      * @param array $sipArray
-     * @param int $recordId
+     * @param int   $recordId
      */
     private function newRecordCreateSip(array $sipArray, $recordId) {
 
diff --git a/extension/qfq/qfq/Save.php b/extension/qfq/qfq/Save.php
index bcf1c1863d6a319cec044ab44347c5b121422510..95835a1b704428aac7773fe243f02ff4be1f3d59 100644
--- a/extension/qfq/qfq/Save.php
+++ b/extension/qfq/qfq/Save.php
@@ -75,6 +75,7 @@ class Save {
      * Create empty FormElements based on templateGroups, for those who not already exist.
      *
      * @param array $formValues
+     *
      * @return array
      */
     private function createEmptyTemplateGroupElements(array $formValues) {
@@ -95,11 +96,13 @@ class Save {
                 $formValues[$feName] = $formElement[FE_VALUE];
             }
         }
+
         return $formValues;
     }
 
     /**
      * @param $feName
+     *
      * @return bool
      */
     private function isSetEmptyMeansNull($feName) {
@@ -112,9 +115,11 @@ class Save {
     }
 
     /**
-     * Build an array of all values which should be saved. Values must exist as a 'form value' as well as a regular 'table column'.
+     * Build an array of all values which should be saved. Values must exist as a 'form value' as well as a regular
+     * 'table column'.
      *
      * @param $recordId
+     *
      * @return int   record id (in case of insert, it's different from $recordId)
      * @throws CodeException
      * @throws DbException
@@ -198,6 +203,7 @@ class Save {
             if ($formElement[FE_NAME] === $feName && $formElement[FE_TYPE] == 'upload')
                 return true;
         }
+
         return false;
     }
 
@@ -205,6 +211,7 @@ class Save {
      * Insert new record in table $this->formSpec['tableName'].
      *
      * @param array $values
+     *
      * @return int  last insert id
      * @throws DbException
      */
@@ -226,8 +233,9 @@ class Save {
 
     /**
      * @param string $tableName
-     * @param array $values
-     * @param int $recordId
+     * @param array  $values
+     * @param int    $recordId
+     *
      * @return bool|int     false if $values is empty, else affectedrows
      * @throws CodeException
      * @throws DbException
@@ -260,7 +268,8 @@ class Save {
     }
 
     /**
-     * Process all Upload Formelements for the given $recordId. After processing &$formValues will be updated with the final filenames.
+     * Process all Upload Formelements for the given $recordId. After processing &$formValues will be updated with the
+     * final filenames.
      *
      */
     public function processAllUploads($recordId) {
@@ -309,10 +318,12 @@ class Save {
      *
      * Check also: doc/CODING.md
      *
-     * @param array $formElement FormElement 'upload'
-     * @param string $sipUpload SIP
-     * @param Sip $sip
-     * @param string $modeUpload UPLOAD_MODE_UNCHANGED | UPLOAD_MODE_NEW | UPLOAD_MODE_DELETEOLD | UPLOAD_MODE_DELETEOLD_NEW
+     * @param array  $formElement FormElement 'upload'
+     * @param string $sipUpload   SIP
+     * @param Sip    $sip
+     * @param string $modeUpload  UPLOAD_MODE_UNCHANGED | UPLOAD_MODE_NEW | UPLOAD_MODE_DELETEOLD |
+     *                            UPLOAD_MODE_DELETEOLD_NEW
+     *
      * @return false|string New pathFilename or false on error
      * @throws CodeException
      * @throws UserFormException
@@ -371,6 +382,7 @@ class Save {
      *
      * @param array $formElement
      * @param array $statusUpload
+     *
      * @return array|mixed|null|string
      * @throws CodeException
      * @throws UserFormException
@@ -423,7 +435,8 @@ class Save {
      * Create/update or delete the slave record.
      *
      * @param array $fe
-     * @param bool $flagNewUpload
+     * @param bool  $flagNewUpload
+     *
      * @return int
      * @throws CodeException
      * @throws UserFormException
@@ -491,6 +504,7 @@ class Save {
      * Get the complete FormElement for $name
      *
      * @param $name
+     *
      * @return bool|array if found the FormElement, else false.
      */
     private function getFormElementByName($name) {
diff --git a/extension/qfq/qfq/database/Database.php b/extension/qfq/qfq/database/Database.php
index 53eb9018177e980afffdc14d58d95b8088706fa6..d7044779490e6a91698bbce43442e49fd2f09fbf 100644
--- a/extension/qfq/qfq/database/Database.php
+++ b/extension/qfq/qfq/database/Database.php
@@ -9,11 +9,6 @@
 namespace qfq;
 
 use qfq;
-use qfq\CodeException;
-use qfq\DbException;
-use qfq\UserFormException;
-use qfq\Support;
-use qfq\Store;
 
 require_once(__DIR__ . '/../exceptions/UserFormException.php');
 require_once(__DIR__ . '/../exceptions/CodeException.php');
@@ -121,23 +116,25 @@ class Database {
     }
 
     /**
-     * Fires query $sql and fetches result as assoc array (all modes but ROW_KEYS) or as num array (mode: ROW_KEYS). Throws exception.
+     * Fires query $sql and fetches result as assoc array (all modes but ROW_KEYS) or as num array (mode: ROW_KEYS).
+     * Throws exception.
      *
      * $mode
      *  ROW_REGULAR: Return 2-dimensional assoc array. Every query row is one array row.
      *  ROW_IMPLODE_ALL: Return string. All cells of all rows imploded to one string.
      *  ROW_EXPECT_0: Return empty string if there is no record row, Else an exception.
      *  ROW_EXPECT_1: Return 1-dimensional assoc array if there are exact one row. Else an exception.
-     *  ROW_EXPECT_0_1: Return empty array if there is no row. Return 1-dimensional assoc array if there is one row. Else an exception.
-     *  ROW_EXPECT_GE_1: Like 'ROW_REGULAR'. Throws an exception if there is an empty resultset.
+     *  ROW_EXPECT_0_1: Return empty array if there is no row. Return 1-dimensional assoc array if there is one row.
+     *  Else an exception. ROW_EXPECT_GE_1: Like 'ROW_REGULAR'. Throws an exception if there is an empty resultset.
      *  ROW_KEYS: Return 2-dimensional num(!) array. Every query row is one array row. $keys are the column names.
      *
-     * @param $sql
+     * @param        $sql
      * @param string $mode
-     * @param array $parameterArray
+     * @param array  $parameterArray
      * @param string $specificMessage
-     * @param array $keys
-     * @param array $stat DB_NUM_ROWS | DB_INSERT_ID | DB_AFFECTED_ROWS
+     * @param array  $keys
+     * @param array  $stat DB_NUM_ROWS | DB_INSERT_ID | DB_AFFECTED_ROWS
+     *
      * @return array|int
      *      SELECT | SHOW | DESCRIBE | EXPLAIN: see $mode
      *      INSERT: last_insert_id
@@ -176,30 +173,33 @@ class Database {
                     $result = $this->fetchAll($mode, $keys);
                     break;
                 case ROW_EXPECT_0:
-                    if ($count === 0)
+                    if ($count === 0) {
                         $result = array();
-                    else
+                    } else {
                         throw new DbException($specificMessage . "Expected none record, got $count rows: $sql", ERROR_DB_TOO_MANY_ROWS);
+                    }
                     break;
                 case ROW_EXPECT_1:
-                    if ($count === 1)
+                    if ($count === 1) {
                         $result = $this->fetchAll($mode)[0];
-                    else
+                    } else {
                         throw new DbException($specificMessage . "Expected one record, got $count: $sql", ERROR_DB_COUNT_DO_NOT_MATCH);
+                    }
                     break;
                 case ROW_EXPECT_0_1:
-                    if ($count === 1)
+                    if ($count === 1) {
                         $result = $this->fetchAll($mode)[0];
-                    elseif ($count === 0)
+                    } elseif ($count === 0) {
                         $result = array();
-                    else
+                    } else
                         throw new DbException($specificMessage . "Expected no record, got $count rows: $sql", ERROR_DB_TOO_MANY_ROWS);
                     break;
                 case ROW_EXPECT_GE_1:
-                    if ($count > 0)
+                    if ($count > 0) {
                         $result = $this->fetchAll($mode);
-                    else
+                    } else {
                         throw new DbException($specificMessage . "Expected at least one record, got nothing: $sql", ERROR_DB_TOO_FEW_ROWS);
+                    }
                     break;
 
                 default:
@@ -229,8 +229,9 @@ class Database {
 
         if ($this->mysqli_stmt !== null && $this->mysqli_stmt !== false) {
             $this->mysqli_stmt->free_result();
-            if (!$this->mysqli_stmt->close())
+            if (!$this->mysqli_stmt->close()) {
                 throw new DbException('Error closing mysqli_stmt' . ERROR_DB_CLOSE_MYSQLI_STMT);
+            }
         }
         $this->mysqli_stmt = null;
         $this->mysqli_result = null;
@@ -239,12 +240,15 @@ class Database {
     /**
      * Execute a prepared SQL statement like SELECT, INSERT, UPDATE, DELETE, SHOW, ...
      *
-     * Returns the number of selected rows (SELECT, SHOW, ..) or the affected rows (UPDATE, INSERT). $stat contains appropriate num_rows, insert_id or rows_affected.
+     * Returns the number of selected rows (SELECT, SHOW, ..) or the affected rows (UPDATE, INSERT). $stat contains
+     * appropriate num_rows, insert_id or rows_affected.
+     *
+     * @param string $sql            SQL statement with prepared statement variable.
+     * @param array  $parameterArray parameter array for prepared statement execution.
+     * @param string $queryType      returns QUERY_TYPE_SELECT | QUERY_TYPE_UPDATE | QUERY_TYPE_INSERT, depending on
+     *                               the query.
+     * @param array  $stat           DB_NUM_ROWS | DB_INSERT_ID | DB_AFFECTED_ROWS
      *
-     * @param string $sql SQL statement with prepared statement variable.
-     * @param array $parameterArray parameter array for prepared statement execution.
-     * @param string $queryType returns QUERY_TYPE_SELECT | QUERY_TYPE_UPDATE | QUERY_TYPE_INSERT, depending on the query.
-     * @param array $stat DB_NUM_ROWS | DB_INSERT_ID | DB_AFFECTED_ROWS
      * @return int|mixed
      * @throws \qfq\CodeException
      * @throws \qfq\DbException
@@ -344,6 +348,7 @@ class Database {
      * Check if the given SQL Statement might modify data.
      *
      * @param $sql
+     *
      * @return bool  true is the statement might modify data, else: false
      */
     private function isSqlModify($sql) {
@@ -365,8 +370,9 @@ class Database {
     /**
      * Decide if the SQL statement has to be logged. If yes, create a timestamp and do the log.
      *
-     * @param $sql
+     * @param       $sql
      * @param array $parameterArray
+     *
      * @return string
      * @throws \qfq\UserFormException
      */
@@ -434,6 +440,7 @@ class Database {
     /**
      * @param $sql
      * @param $parameterArray
+     *
      * @return string
      */
     private function preparedStatementInsertParameter($sql, $parameterArray) {
@@ -481,7 +488,8 @@ class Database {
      *  default: Return 2-dimensional assoc array
      *
      * @param string $mode
-     * @param array $keys
+     * @param array  $keys
+     *
      * @return array|bool|mixed|string false in case of an error.
      *              Empty string is returned if the query didn't yield any rows.
      *              All rows as Multi Assoc array if $mode!=IMPLODE_ALL.
@@ -503,6 +511,7 @@ class Database {
                 foreach ($this->mysqli_result->fetch_all(MYSQLI_NUM) as $row) {
                     $str .= implode($row);
                 }
+
                 return $str;
                 break;
 
@@ -512,6 +521,7 @@ class Database {
                 for ($ii = 0; $ii < $this->mysqli_result->field_count; $ii++) {
                     $keys[$ii] = $this->mysqli_result->fetch_field_direct($ii)->name;
                 }
+
                 return $this->mysqli_result->fetch_all(MYSQLI_NUM);
                 break;
 
@@ -577,6 +587,7 @@ class Database {
      * @param string $table name of the table
      *
      * @param string $columnName name of the column
+     *
      * @return array the definition of the column as retrieved by Database::getTableDefinition().
      *
      * @throws \qfq\DbException
@@ -613,9 +624,10 @@ class Database {
     /**
      * Wrapper for sql(), to simplyfy access.
      *
-     * @param $sql
-     * @param array $keys
-     * @param array $stat
+     * @param              $sql
+     * @param array        $keys
+     * @param array        $stat
+     *
      * @return array|bool
      * @throws \qfq\CodeException
      * @throws \qfq\DbException
@@ -639,6 +651,7 @@ class Database {
      * Searches for the table '$name'.
      *
      * @param $name
+     *
      * @return bool  true if found, else false
      */
     public function existTable($name) {
@@ -661,9 +674,10 @@ class Database {
     /**
      * Depending on $sql reads FormElements to a specific container or all. Preprocess all FormElements.
      *
-     * @param string $sql SQL_FORM_ELEMENT_SPECIFIC_CONTAINER | SQL_FORM_ELEMENT_ALL_CONTAINER
-     * @param array $param Parameter which matches the prepared statement in $sql
-     * @param array $formSpec Main FormSpec to copy generic parameter to FormElements
+     * @param string $sql      SQL_FORM_ELEMENT_SPECIFIC_CONTAINER | SQL_FORM_ELEMENT_ALL_CONTAINER
+     * @param array  $param    Parameter which matches the prepared statement in $sql
+     * @param array  $formSpec Main FormSpec to copy generic parameter to FormElements
+     *
      * @return array|int
      * @throws \qfq\CodeException
      * @throws \qfq\DbException
@@ -691,6 +705,7 @@ class Database {
      * returns true for '... LIMIT', '.... LIMIT 1, ... LIMIT 1,2, ... LIMIT 1 , 2
      *
      * @param $sql
+     *
      * @return bool
      */
     public function hasLimit($sql) {
@@ -721,14 +736,15 @@ class Database {
     /**
      * $arr will be converted to a two column array with keys $keyName1 and $keyName2.
      * $arr might contain one or more columns.
-     * Only when $keyName1 and $keyName2 exist, those will be used. Else the first column becomes $keyName1 and the second becomes $keyName2.
-     * If there is only one column, that column will be doubled.
+     * Only when $keyName1 and $keyName2 exist, those will be used. Else the first column becomes $keyName1 and the
+     * second becomes $keyName2. If there is only one column, that column will be doubled.
      *
      * @param array $arr
      * @param string $srcColumn1
      * @param string $srcColumn2
      * @param string $destColumn1
      * @param string $destColumn2
+     *
      * @return array
      */
     public function makeArrayDict(array $arr, $srcColumn1, $srcColumn2, $destColumn1 = '', $destColumn2 = '') {
@@ -773,6 +789,7 @@ class Database {
      * Proxy for mysqli::real_escape_string()
      *
      * @param string $value
+     *
      * @return string
      */
     public function realEscapeString($value) {
@@ -781,6 +798,7 @@ class Database {
 
     /**
      * @param $filename
+     *
      * @throws \qfq\CodeException
      */
     public function playSqlFile($filename) {
diff --git a/extension/qfq/qfq/database/DatabaseUpdate.php b/extension/qfq/qfq/database/DatabaseUpdate.php
index 60ecf8c0871f746bb05efda02be4276817f01df9..248aa895fe41af5f957b9f0e370eaa2cf09d90b3 100644
--- a/extension/qfq/qfq/database/DatabaseUpdate.php
+++ b/extension/qfq/qfq/database/DatabaseUpdate.php
@@ -45,7 +45,7 @@ class DatabaseUpdate {
     private function getExtensionVersion() {
         $path = __DIR__ . '/../../../ext_emconf.php';
         $_EXTKEY = EXT_KEY;
-        $EM_CONF = NULL;
+        $EM_CONF = null;
         if (@file_exists($path)) {
             include $path;
 
@@ -88,6 +88,7 @@ class DatabaseUpdate {
 
     /**
      * @param $version
+     *
      * @throws CodeException
      * @throws DbException
      */
@@ -121,6 +122,7 @@ class DatabaseUpdate {
 
     /**
      * @param $path
+     *
      * @return array
      * @throws CodeException
      */
diff --git a/extension/qfq/qfq/database/DatabaseUpdateData.php b/extension/qfq/qfq/database/DatabaseUpdateData.php
index 7f4c65782a569d2d34e4f23bfe0a6b93d585feb1..b279f8a76f2768636168655ef7d4ca9aa5bfccf3 100644
--- a/extension/qfq/qfq/database/DatabaseUpdateData.php
+++ b/extension/qfq/qfq/database/DatabaseUpdateData.php
@@ -57,7 +57,7 @@ $UPDATE_ARRAY = array(
         "ALTER TABLE  `Form` ADD  `dirtyMode` ENUM( 'exclusive', 'advisory', 'none' ) NOT NULL DEFAULT  'exclusive' AFTER  `requiredParameter`",
         "ALTER TABLE  `Form` ADD  `recordLockTimeoutSeconds` INT NOT NULL DEFAULT  '900' AFTER  `parameter`",
         "CREATE TABLE IF NOT EXISTS `Period` (`id` INT(11) NOT NULL AUTO_INCREMENT, `start` DATETIME NOT NULL, `name` VARCHAR(255) NOT NULL, `modified` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `created` DATETIME NOT NULL, PRIMARY KEY (`id`), KEY `start` (`start`)) ENGINE = InnoDB DEFAULT CHARSET = utf8 AUTO_INCREMENT = 0;",
-        "INSERT INTO Period (start, name, created) VALUES (NOW(), 'dummy', NOW());",
+        "INSERT INTO Period (start, name, created) VALUES (NOW(), 'dummy', NOW());"
     ],
 
     '0.19.5' => [
@@ -72,6 +72,12 @@ $UPDATE_ARRAY = array(
         "ALTER TABLE `FormElement` ADD `parameterLanguageD` TEXT NOT NULL AFTER `parameterLanguageC`",
     ],
 
+    '0.21.0' => [
+        "ALTER TABLE  `Form` CHANGE  `requiredParameter`  `requiredParameterNew` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT  ''",
+        "ALTER TABLE  `Form` ADD  `requiredParameterEdit` VARCHAR( 255 ) NOT NULL AFTER  `requiredParameterNew`",
+        "UPDATE Form SET requiredParameterEdit=requiredParameterNew",
+    ],
+
     '0.24.0' => [
         "ALTER TABLE  `FormElement` CHANGE  `type`  `type` ENUM(  'checkbox',  'date',  'datetime',  'dateJQW',  'datetimeJQW',  'extra',  'gridJQW',  'text',  'editor',  'time',  'note',  'password',  'radio',  'select',  'subrecord',  'upload', 'annotate',  'fieldset',  'pill',  'templateGroup',  'beforeLoad',  'beforeSave',  'beforeInsert',  'beforeUpdate',  'beforeDelete',  'afterLoad',  'afterSave',  'afterInsert',  'afterUpdate',  'afterDelete',  'sendMail',  'paste' ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT  'text';",
     ],
diff --git a/extension/qfq/qfq/exceptions/AbstractException.php b/extension/qfq/qfq/exceptions/AbstractException.php
index 6a27585f418961034fb9afcf949774726c7dfbcd..447d6fb0f06e90a8b45a1423b5cf2ebede340356 100644
--- a/extension/qfq/qfq/exceptions/AbstractException.php
+++ b/extension/qfq/qfq/exceptions/AbstractException.php
@@ -98,6 +98,7 @@ class AbstractException extends \Exception {
             }
             $debug = "<table border=1>" . $debug . "</table>";
         }
+
         return $html . $debug;
     }
 
diff --git a/extension/qfq/qfq/exceptions/ErrorHandler.php b/extension/qfq/qfq/exceptions/ErrorHandler.php
index e2965f6ed5bb97dd0b4873aaadcdeeb4bebd7339..e19acfa10f517636500a45fb0bf5e1375fe4c03d 100644
--- a/extension/qfq/qfq/exceptions/ErrorHandler.php
+++ b/extension/qfq/qfq/exceptions/ErrorHandler.php
@@ -20,7 +20,7 @@ class ErrorHandler {
         }
 //        throw new CodeException(": Catchable Error in '$file' on line $line: " . $message . " - CWD: " . getcwd(), $severity, NULL);
         // Do not show too much to the user. E.g. 'ldap_bind()' might have problems, but the user should not see the file and linenumber.
-        throw new CodeException($message, $severity, NULL);
+        throw new CodeException($message, $severity, null);
     }
 
 }
\ No newline at end of file
diff --git a/extension/qfq/qfq/form/Dirty.php b/extension/qfq/qfq/form/Dirty.php
index fb871031604673da7b8da218bdfdecc91f8b911c..c3d4c956a5280ebf54ebf6f322ffa1a6aa0e2866 100644
--- a/extension/qfq/qfq/form/Dirty.php
+++ b/extension/qfq/qfq/form/Dirty.php
@@ -102,6 +102,7 @@ class Dirty {
      * @param int    $recordId
      * @param array  $tableVars
      * @param string $recordHashMd5
+     *
      * @return array
      * @throws \qfq\CodeException
      */
@@ -141,6 +142,7 @@ class Dirty {
      *
      * @param string $tableName
      * @param int    $recordId
+     *
      * @return array   DirtyRecord or empty array.
      * @throws CodeException
      * @throws DbException
@@ -163,6 +165,7 @@ class Dirty {
      *
      * @param array  $recordDirty
      * @param string $currentFormDirtyMode
+     *
      * @return array
      */
     private function conflict(array $recordDirty, $currentFormDirtyMode) {
@@ -202,11 +205,12 @@ class Dirty {
     /**
      * Write a 'Dirty'-Record.
      *
-     * @param string $s SIP given by URL GET
+     * @param string $s        SIP given by URL GET
      * @param int    $recordId extracted from SIP
      * @param array  $tableVars columns: F_TABLE_NAME, F_DIRTY_MODE, F_RECORD_LOCK_TIMEOUT_SECONDS
      * @param string $feUser
      * @param string $recordHashMd5
+     *
      * @return array
      * @throws \qfq\CodeException
      * @throws \qfq\DbException
@@ -225,8 +229,8 @@ class Dirty {
             [$s, $tableName, $recordId, $expire, $recordHashMd5, $feUser, $this->client[CLIENT_COOKIE_QFQ], $formDirtyMode,
                 $this->client[CLIENT_REMOTE_ADDRESS], date('YmdHis')]);
 
-        return [API_STATUS => API_ANSWER_STATUS_SUCCESS, API_MESSAGE => '',
-            API_LOCK_TIMEOUT => $tableVars[F_RECORD_LOCK_TIMEOUT_SECONDS]];
+        return [API_STATUS       => API_ANSWER_STATUS_SUCCESS, API_MESSAGE => '',
+                API_LOCK_TIMEOUT => $tableVars[F_RECORD_LOCK_TIMEOUT_SECONDS]];
 
     }
 
@@ -236,13 +240,14 @@ class Dirty {
      * @param string $tableName
      * @param int    $recordId
      * @param string $recordHashMd5 - timestamp e.g. '2017-07-27 14:06:56'
+     *
      * @return bool true if $recordHashMd5 is different from current record md5 hash.
      * @throws CodeException
      * @throws DbException
      */
     private function isRecordModified($tableName, $recordId, $recordHashMd5, &$rcMd5) {
 
-        if($recordHashMd5 =='') {
+        if ($recordHashMd5 == '') {
             return false; // If there is no recordHashMd5, the check is not possible. Always return 'not modified' (=ok)
         }
 
@@ -260,6 +265,7 @@ class Dirty {
      * @param int    $recordId
      * @param array  $recordDirty - return dirty record if one exist.
      * @param string $msg - return preformatted message in case of conflict
+     *
      * @return int LOCK_NOT_FOUND | LOCK_FOUND_OWNER | LOCK_FOUND_CONFLICT,
      */
     public function getCheckDirty($tableName, $recordId, array &$recordDirty, &$msg) {
@@ -301,6 +307,7 @@ class Dirty {
      * @param string $dirtyMode DIRTY_MODE_EXCLUSIVE, DIRTY_MODE_ADVISORY, DIRTY_MODE_NONE
      * @param string $tableName
      * @param int    $recordId
+     *
      * @return array
      * @throws \qfq\CodeException
      * @throws \qfq\UserFormException
@@ -349,6 +356,7 @@ class Dirty {
             }
 
             $answer = [API_STATUS => API_ANSWER_STATUS_CONFLICT, API_MESSAGE => $rcMsg];
+
             return $answer;
         }
 
@@ -361,6 +369,7 @@ class Dirty {
 
             // Clear the lock
             $this->deleteDirtyRecord($rcRecordDirty[COLUMN_ID]);
+
             return $answer;
         }
 
@@ -375,6 +384,7 @@ class Dirty {
         // Check if the record is timed out
         if ($lockTimeout > 0 && $rcRecordDirty[DIRTY_EXPIRE] < date('Y-m-d H:i:s')) {
             $this->deleteDirtyRecord($rcRecordDirty[COLUMN_ID]);
+
             return $answer;
         }
 
@@ -385,6 +395,7 @@ class Dirty {
      * Delete the dirtyRecord with $recordDirtyId. Throw an exception if the record has not been deleted.
      *
      * @param int $recordDirtyId
+     *
      * @throws CodeException
      * @throws DbException
      */
diff --git a/extension/qfq/qfq/form/FormAction.php b/extension/qfq/qfq/form/FormAction.php
index 38c2b084425af61555672559627ea503e64b082f..e9dfc80f34898ba7de9134a4f89c348432111bd5 100644
--- a/extension/qfq/qfq/form/FormAction.php
+++ b/extension/qfq/qfq/form/FormAction.php
@@ -58,11 +58,12 @@ class FormAction {
 
     /**
      * @param integer $recordId
-     * @param array $feSpecAction
-     * @param string $feTypeList
+     * @param array   $feSpecAction
+     * @param string  $feTypeList
      *         On FormLoad: FE_TYPE_BEFORE_LOAD, FE_TYPE_AFTER_LOAD
      *         Before Save: FE_TYPE_BEFORE_SAVE, FE_TYPE_BEFORE_INSERT, FE_TYPE_BEFORE_UPDATE, FE_TYPE_BEFORE_DELETE
      *         After Save: FE_TYPE_AFTER_SAVE, FE_TYPE_AFTER_INSERT, FE_TYPE_AFTER_UPDATE, FE_TYPE_AFTER_DELETE
+     *
      * @return int: ACTION_ELEMENT_MODIFIED if there are potential changes on the DB like fired SQL statements,
      *              ACTION_ELEMENT_NO_CHANGE if nothing happened
      *              ACTION_ELEMENT_DELETED:  if a record has been deleted (only in recursive calls, not the initial one)
@@ -177,6 +178,7 @@ class FormAction {
      *
      * @param $table
      * @param $recordId
+     *
      * @throws CodeException
      * @throws DbException
      * @throws UserFormException
@@ -199,6 +201,7 @@ class FormAction {
      * If none FormElement is specified, return true.
      *
      * @param array $fe
+     *
      * @return bool  true if none FE is specified or all specified are non empty.
      */
     private function checkRequiredList(array $fe) {
@@ -249,6 +252,7 @@ class FormAction {
      * Else throw UserFormException with error message of fe.parameter.FE_MESSAGE_FAIL
      *
      * @param array $fe
+     *
      * @throws UserFormException
      */
     private function validate(array $fe) {
@@ -285,10 +289,12 @@ class FormAction {
     }
 
     /**
-     * Create the slave record. First try to evaluate a slaveId. Depending if the slaveId > 0 choose `sqlUpdate` or `sqlInsert`
+     * Create the slave record. First try to evaluate a slaveId. Depending if the slaveId > 0 choose `sqlUpdate` or
+     * `sqlInsert`
      *
      * @param array $fe
-     * @param int $recordId
+     * @param int   $recordId
+     *
      * @return int  ACTION_ELEMENT_MODIFIED if there are potential(!) changes on the DB like INSERT / UPDATE,
      *              ACTION_ELEMENT_NO_CHANGE if nothing happened
      *              ACTION_ELEMENT_DELETED:  if a record has been deleted
@@ -368,7 +374,9 @@ class FormAction {
      * of the give elements is non empty, return true. If all elements are empty, return false.
      *
      * @param string $listOfFormElementNames E.g.: 'city, street, number'
-     * @return bool true if at lease one of the named elements is non empty on STORE_FORM (use SANATIZE_ALLOW_ALL to perform the check)
+     *
+     * @return bool true if at lease one of the named elements is non empty on STORE_FORM (use SANATIZE_ALLOW_ALL to
+     *              perform the check)
      */
     private function checkFormElements($listOfFormElementNames) {
         $arr = explode(',', $listOfFormElementNames);
@@ -379,6 +387,7 @@ class FormAction {
                 return true;
             }
         }
+
         return false;
     }
 
@@ -386,6 +395,7 @@ class FormAction {
      * Set all necessary keys - subsequent 'isset()' are not necessary anymore.
      *
      * @param array $fe
+     *
      * @return array
      */
     private function initActionFormElement(array $fe) {
@@ -408,11 +418,13 @@ class FormAction {
      * Process all FE.type='paste' for the given master record in clipboard.
      * Will store the clipboard in STORE_PARENT.
      *
-     * @param array $feSpecAction - all FE.class='action' - just process 'paste'
-     * @param string $recordSourceTable - table name from where to copy the source records
+     * @param array  $feSpecAction           - all FE.class='action' - just process 'paste'
+     * @param string $recordSourceTable      - table name from where to copy the source records
      * @param string $recordDestinationTable - table name where the records will be duplicated to.
-     * @param string $sub - on the highest level an empty string. It's a filter, value comes from FE.name, to specify sub-sub copy rules.
-     * @param array $clipboard
+     * @param string $sub                    - on the highest level an empty string. It's a filter, value comes from
+     *                                       FE.name, to specify sub-sub copy rules.
+     * @param array  $clipboard
+     *
      * @throws CodeException
      * @throws UserFormException
      */
@@ -456,13 +468,16 @@ class FormAction {
     /**
      *
      *
-     * @param array $feSpecActionAll - all FE.class='action' - just process 'paste'
-     * @param array $updateRecords - array of records: 'id' is the source.id, all other fields will replace source columns.
-     * @param $recordSourceTable - table name from where to copy the source records
-     * @param $recordDestinationTable - table name where the records will be duplicated to.
-     * @param string $sub - on the highest level an empty string. It's a filter, value comes from FE.name, to specify sub-sub copy rules.
-     * @param array $clipboard -
-     * @param string $field - name of a column where to save the lastInsertId.
+     * @param array  $feSpecActionAll        - all FE.class='action' - just process 'paste'
+     * @param array  $updateRecords          - array of records: 'id' is the source.id, all other fields will replace
+     *                                       source columns.
+     * @param        $recordSourceTable      - table name from where to copy the source records
+     * @param        $recordDestinationTable - table name where the records will be duplicated to.
+     * @param string $sub                    - on the highest level an empty string. It's a filter, value comes from
+     *                                       FE.name, to specify sub-sub copy rules.
+     * @param array  $clipboard              -
+     * @param string $field                  - name of a column where to save the lastInsertId.
+     *
      * @return int - lastInsertId
      * @throws CodeException
      * @throws DbException
@@ -545,6 +560,7 @@ class FormAction {
     /**
      * @param array $rowSrc
      * @param array $rowDest
+     *
      * @throws UserFormException
      */
     private function checkNCopyFiles(array $rowSrc, array $rowDest) {
@@ -574,8 +590,9 @@ class FormAction {
      * If there is nothing to copy - Do nothing.
      * Columns with name 'id', 'modified' or 'created' are skipped.
      *
-     * @param array $row
+     * @param array  $row
      * @param string $destTable
+     *
      * @return int - lastInsertId
      * @throws CodeException
      * @throws DbException
diff --git a/extension/qfq/qfq/form/TypeAhead.php b/extension/qfq/qfq/form/TypeAhead.php
index 8dc4e72bb49430b3c7b74754c81cfbd452211b60..3decaf4f34bfebe33733dd3f572d664e1a7125d4 100644
--- a/extension/qfq/qfq/form/TypeAhead.php
+++ b/extension/qfq/qfq/form/TypeAhead.php
@@ -92,8 +92,9 @@ class TypeAhead {
      * If there is no 'LIMIT x' defined, append it.
      * Returns an dict array [ API_TYPEAHEAD_KEY => key, API_TYPEAHEAD_VALUE => value ]
      *
-     * @param array $config
+     * @param array  $config
      * @param string $value
+     *
      * @return array
      * @throws CodeException
      * @throws DbException
diff --git a/extension/qfq/qfq/helper/BindParam.php b/extension/qfq/qfq/helper/BindParam.php
index 993a0d2812f30d2e4a4836b880ff49bbe7787ff8..100b27748b8483db2fc356f5f853b46ba827cb02 100644
--- a/extension/qfq/qfq/helper/BindParam.php
+++ b/extension/qfq/qfq/helper/BindParam.php
@@ -22,6 +22,7 @@ class BindParam {
      * Depending of $value, returns i (integer), d (double) or s (string). This is needed for mysqli_bind().
      *
      * @param $value
+     *
      * @return string
      */
     private function getParameterBindType($value) {
diff --git a/extension/qfq/qfq/helper/HelperFormElement.php b/extension/qfq/qfq/helper/HelperFormElement.php
index afee4793b7eae01311bede6a21b11615655e0f3b..3503ca275c77b5ba023f76027addce7192796231 100644
--- a/extension/qfq/qfq/helper/HelperFormElement.php
+++ b/extension/qfq/qfq/helper/HelperFormElement.php
@@ -9,8 +9,6 @@
 namespace qfq;
 
 use qfq;
-use qfq\Store;
-use qfq\UserFormException;
 
 require_once(__DIR__ . '/../../qfq/store/Store.php');
 require_once(__DIR__ . '/../../qfq/Constants.php');
@@ -22,9 +20,12 @@ class HelperFormElement {
     /**
      * Expand column $keyName to row array as virtual columns.
      * E.g.: [ 'id' => '1', 'name' => 'John', 'parameter' => 'detail=xId:grId\nShowEmptyAtStart=1' ] beocmes:
-     *  [ 'id' => '1', 'name' => 'John', 'parameter' => 'detail=xId:grId\nShowEmptyAtStart=1', 'detail' => 'xId:grId', 'showEmptyAtStart'='1']
+     *  [ 'id' => '1', 'name' => 'John', 'parameter' => 'detail=xId:grId\nShowEmptyAtStart=1', 'detail' => 'xId:grId',
+     *  'showEmptyAtStart'='1']
+     *
      * @param array $elements
      * @param string $keyName Typically F_PARAMETER or FE_PARAMETER (both: 'parameter')
+     *
      * @throws \qfq\UserFormException
      */
     public static function explodeParameterInArrayElements(array &$elements, $keyName) {
@@ -37,6 +38,7 @@ class HelperFormElement {
 
     /**
      * @param array $elements
+     *
      * @return array
      */
     public static function formElementSetDefault(array $elements) {
@@ -52,6 +54,7 @@ class HelperFormElement {
      *
      * @param array $element
      * @param string $keyName Typically F_PARAMETER or FE_PARAMETER (both: 'parameter')
+     *
      * @throws CodeException
      * @throws \qfq\UserFormException
      */
@@ -77,13 +80,30 @@ class HelperFormElement {
         }
     }
 
+    /**
+     * Take language specific definitions and overwrite the default values.
+     *
+     * @param array $formSpecFeSpecNative
+     *
+     * @return array
+     * @throws UserFormException
+     */
+    public static function setLanguage(array $formSpecFeSpecNative, $parameterLanguageFieldName) {
+
+        if (is_string($parameterLanguageFieldName) && isset($formSpecFeSpecNative[$parameterLanguageFieldName])) {
+            self::explodeParameter($formSpecFeSpecNative, $parameterLanguageFieldName, true);
+        }
+
+        return $formSpecFeSpecNative;
+    }
+
     /**
      * Build the FE name: <field>-<record index)
      *
-     * @param array $formElement
+     * @param array  $formElement
      * @param string $id
+     *
      * @return string
-     * @internal param string $field
      */
     public static function buildFormElementName(array $formElement, $id) {
         $field = ($formElement[FE_NAME] == '') ? $formElement[FE_ID] : $formElement[FE_NAME];
@@ -98,6 +118,7 @@ class HelperFormElement {
      * @param $formElementId
      * @param $recordId
      * @param $formElementCopy
+     *
      * @return string
      */
     public static function buildFormElementId($formId, $formElementId, $recordId, $formElementCopy) {
@@ -109,6 +130,7 @@ class HelperFormElement {
      *
      * @param string $field
      * @param string $index
+     *
      * @return string
      */
     public static function prependFormElementNameCheckBoxMulti($field, $index) {
@@ -120,6 +142,7 @@ class HelperFormElement {
      * If yes: duplicate such elements and update FE_NAME, FE_LABEL, FE_NOTE.
      *
      * @param array $elements
+     *
      * @return array
      */
     public static function duplicateRetypeElements(array $elements) {
@@ -152,6 +175,8 @@ class HelperFormElement {
                     unset($fe[FE_RETYPE_NOTE]);
                 }
 
+                $fe[FE_TG_INDEX] = 1; // Not sure if this is helpfull in case of dynamic update - but it will make the element uniqe.
+
                 unset($fe[FE_RETYPE]);
                 $arr[] = $fe;
             }
@@ -165,6 +190,7 @@ class HelperFormElement {
      *
      * @param array $formSpec
      * @param array $feSpecNative
+     *
      * @return mixed
      */
     public static function copyAttributesToFormElements(array $formSpec, array $feSpecNative) {
@@ -183,6 +209,7 @@ class HelperFormElement {
      * Set all necessary keys - subsequent 'isset()' are not necessary anymore.
      *
      * @param array $fe
+     *
      * @return array
      */
     public static function initActionFormElement(array $fe) {
@@ -203,6 +230,7 @@ class HelperFormElement {
      * Set all necessary keys - subsequent 'isset()' are not necessary anymore.
      *
      * @param array $fe
+     *
      * @return array
      */
     public static function initUploadFormElement(array $fe) {
@@ -230,7 +258,8 @@ class HelperFormElement {
      *    * $formElement[FE_TYPE] - for 'password' it will be faked to 'password'
      *
      * @param array $formElement
-     * @param bool $showInline
+     * @param bool  $showInline
+     *
      * @return array
      */
     public static function prepareExtraButton(array $formElement, $showInline) {
@@ -240,6 +269,10 @@ class HelperFormElement {
         $infoSymbolInside = $store->getVar(SYSTEM_GFX_EXTRA_BUTTON_INFO_INLINE, STORE_SYSTEM);
         $infoSymbolOutside = $store->getVar(SYSTEM_GFX_EXTRA_BUTTON_INFO_BELOW, STORE_SYSTEM);
 
+        if (SYSTEM_EXTRA_BUTTON_INFO_POSITION_BELOW == $store->getVar(SYSTEM_EXTRA_BUTTON_INFO_POSITION, STORE_SYSTEM)) {
+            $showInline = false;
+        }
+
         $extraButton = '';
         $id = $formElement[FE_HTML_ID];
 
@@ -272,10 +305,12 @@ EOF;
         $js = " onclick=\"$('#$id-extra-info').slideToggle('swing')\" ";
         $arr = explode(' ', $infoSymbolOutside, 2);
         $infoSymbolOutside = $arr[0] . $js . $arr[1];
+
         // INFO: $showinline == FALSE (e.g. 'textarea' elemente)
         if (isset($formElement[FE_INPUT_EXTRA_BUTTON_INFO]) && !$showInline) {
+            $class = $formElement[FE_INPUT_EXTRA_BUTTON_INFO_CLASS];
             $extraButton .= <<<EOF
-            $infoSymbolOutside
+            <span class="$class">$infoSymbolOutside</span>
 EOF;
 
             $value = $formElement[FE_INPUT_EXTRA_BUTTON_INFO];
@@ -328,6 +363,7 @@ EOF;
      * Returns $maxLenght if greater than 0, else FE_TEMPLATE_GROUP_DEFAULT_MAX_LENGTH
      *
      * @param $maxLength
+     *
      * @return int
      */
     public static function tgGetMaxLength($maxLength) {
diff --git a/extension/qfq/qfq/helper/KeyValueStringParser.php b/extension/qfq/qfq/helper/KeyValueStringParser.php
index 5771725a1f5f07ca699ffcdcec11b2eb64ac6d31..a95cc9063a7014b7b73be3304bf6778d46e41152 100644
--- a/extension/qfq/qfq/helper/KeyValueStringParser.php
+++ b/extension/qfq/qfq/helper/KeyValueStringParser.php
@@ -11,7 +11,6 @@
 namespace qfq;
 
 use qfq;
-use qfq\UserFormException;
 
 require_once(__DIR__ . '/../exceptions/UserFormException.php');
 require_once(__DIR__ . '/../../qfq/Constants.php');
@@ -42,6 +41,7 @@ class KeyValueStringParser {
      * @param array $keyValueArray
      * @param string $keyValueDelimiter
      * @param string $listDelimiter
+     *
      * @return string
      */
     public static function unparse(array $keyValueArray, $keyValueDelimiter = ":", $listDelimiter = ",") {
@@ -65,6 +65,7 @@ class KeyValueStringParser {
 
     /**
      * @param $string
+     *
      * @return bool
      */
     private static function isFirstAndLastCharacterIdentical($string) {
@@ -84,8 +85,11 @@ class KeyValueStringParser {
      * @param string $keyValueDelimiter
      * @param string $listDelimiter
      * @param string $valueMode
-     *  * KVP_VALUE_GIVEN: If only a key is given, the value is ''.  E.G. 'a,b' >> [ 'a' => '', 'b' => '' ]
-     *  * KVP_IF_VALUE_EMPTY_COPY_KEY: If only a key is given, the value is the same as the key. E.G. 'a,b' >> [ 'a' => 'a', 'b' => 'b' ].
+     *                               * KVP_VALUE_GIVEN: If only a key is given, the value is ''.  E.G. 'a,b' >> [ 'a'
+     *                               => '', 'b' => '' ]
+     *                               * KVP_IF_VALUE_EMPTY_COPY_KEY: If only a key is given, the value is the same as
+     *                               the key. E.G. 'a,b' >> [ 'a' => 'a', 'b' => 'b' ].
+     *
      * @return array  associative array indexed by keys
      * @throws UserFormException Thrown if there is a value but no key.
      */
@@ -149,7 +153,8 @@ class KeyValueStringParser {
      *
      * @param string $delimiter
      * @param string $data
-     * @param int $max
+     * @param int    $max
+     *
      * @return array
      */
     public static function explodeEscape($delimiter, $data, $max = 0) {
@@ -172,6 +177,7 @@ class KeyValueStringParser {
 
     /**
      * @param $string
+     *
      * @return string
      */
     public static function quoteUnwrap($string) {
@@ -184,17 +190,20 @@ class KeyValueStringParser {
         if (in_array($string[0], $quotes) === true && self::isFirstAndLastCharacterIdentical($string)) {
             return substr($string, 1, strlen($string) - 2);
         }
+
         return $string;
     }
 
     /**
-     * Works like PHP 'explode()', but respects $delimeter wrapped in ticks (single or double): those are not interpreted as delimiter.
+     * Works like PHP 'explode()', but respects $delimeter wrapped in ticks (single or double): those are not
+     * interpreted as delimiter.
      *
      * E.g.: "a,b,'c,d',e" with delimiter ',' will result in [ 'a', 'b', 'c,d', 'e' ]
      *
-     * @param $delimeter
-     * @param $str
+     * @param     $delimeter
+     * @param     $str
      * @param int $limit
+     *
      * @return array|bool
      * @throws CodeException
      */
diff --git a/extension/qfq/qfq/helper/Ldap.php b/extension/qfq/qfq/helper/Ldap.php
index f745420d9bce0aab3e03177bcf6183da80d9315f..74c77e89f6dbbbd3b960ee9f088adc3efc11d9be 100644
--- a/extension/qfq/qfq/helper/Ldap.php
+++ b/extension/qfq/qfq/helper/Ldap.php
@@ -29,6 +29,7 @@ class Ldap {
 
     /**
      * @param $ldapServer
+     *
      * @return resource
      * @throws UserFormException
      */
@@ -47,9 +48,10 @@ class Ldap {
     }
 
     /**
-     * @param $ds
-     * @param array $config
-     * @param array $attr
+     * @param              $ds
+     * @param array        $config
+     * @param array        $attr
+     *
      * @return resource
      */
     private function ldapSearch($ds, array $config, array $attr) {
@@ -74,10 +76,12 @@ class Ldap {
      * Calculate all tuple permutations of the search token. From every permutation, take the reverse order.
      * Fill the tuple with the two entries. 'and' combine the tuple. 'or' combine all the 'and' tuples.
      *
-     * (|(a=?)(b=?)(c=?)), ?=X|Y:  (| (&(a=X)(b=Y)) (&(a=Y)(b=X)) (&(a=X)(c=Y)) (&(a=Y)(c=X)) (&(b=X)(c=Y)) (&(=Y)(c=X)) )
+     * (|(a=?)(b=?)(c=?)), ?=X|Y:  (| (&(a=X)(b=Y)) (&(a=Y)(b=X)) (&(a=X)(c=Y)) (&(a=Y)(c=X)) (&(b=X)(c=Y))
+     * (&(=Y)(c=X)) )
      *
      * @param string $ldapSearch
      * @param string $searchValue
+     *
      * @return string
      */
     private function explodePermutSearch($ldapSearch, $searchValue) {
@@ -115,10 +119,12 @@ class Ldap {
     /**
      * Explode $ldapValue by ' '. If more than one entry is found, append the search, replaced by word 1, word 2, ...
      *
-     * (|(a=*?*)(b=*?*)(c=*?*)), ?=X Y Z:    (& (|(a=*X*)(b=*X*)(c=*X*))  (|(a=*Y*)(b=*Y*)(c=*Y*)) (|(a=*Z*)(b=*Z*)(c=*Z*)) )
+     * (|(a=*?*)(b=*?*)(c=*?*)), ?=X Y Z:    (& (|(a=*X*)(b=*X*)(c=*X*))  (|(a=*Y*)(b=*Y*)(c=*Y*))
+     * (|(a=*Z*)(b=*Z*)(c=*Z*)) )
      *
      * @param string $ldapSearch
      * @param string $searchValue
+     *
      * @return string
      */
     private function explodeSearchPerToken($ldapSearch, $searchValue) {
@@ -147,6 +153,7 @@ class Ldap {
      * @param array $config
      * @param string $searchValue
      * @param string $mode
+     *
      * @return array
      * @throws UserFormException
      */
@@ -190,9 +197,11 @@ class Ldap {
 
     /**
      *
-     * @param array $config [FE_LDAP_SERVER , FE_LDAP_BASE_DN, FE_LDAP_SEARCH, FE_TYPEAHEAD_LIMIT, FE_TYPEAHEAD_LDAP_KEY_PRINTF, FE_TYPEAHEAD_LDAP_VALUE_PRINTF]
+     * @param array  $config      [FE_LDAP_SERVER , FE_LDAP_BASE_DN, FE_LDAP_SEARCH, FE_TYPEAHEAD_LIMIT,
+     *                            FE_TYPEAHEAD_LDAP_KEY_PRINTF, FE_TYPEAHEAD_LDAP_VALUE_PRINTF]
      * @param string $searchValue value to search via $config[FE_LDAP_SEARCH]
-     * @param string $mode MODE_LDAP_SINGLE | MODE_LDAP_MULTI | MODE_LDAP_PREFETCH
+     * @param string $mode        MODE_LDAP_SINGLE | MODE_LDAP_MULTI | MODE_LDAP_PREFETCH
+     *
      * @return array Array: [ [ 'key' => '...', 'value' => '...' ], ]
      * @throws UserFormException
      */
@@ -288,9 +297,10 @@ class Ldap {
     /**
      * Very specific function to prepare the later 'printfResult()'.
      *
-     * @param array $config Check existence and take element $key
-     * @param string $key FE_TYPEAHEAD_LDAP_KEY_PRINTF, FE_TYPEAHEAD_LDAP_VALUE_PRINTF
+     * @param array  $config Check existence and take element $key
+     * @param string $key    FE_TYPEAHEAD_LDAP_KEY_PRINTF, FE_TYPEAHEAD_LDAP_VALUE_PRINTF
      * @param string $fmtFirst Returns the first part of $fmtComplete - the printf format string without any args.
+     *
      * @return array            Array with all requested keynames from $fmtComplete
      * @throws CodeException
      * @throws UserFormException
@@ -326,6 +336,7 @@ class Ldap {
      *
      * @param $format
      * @param $infoElement
+     *
      * @return string       output of sprintf
      * @throws CodeException
      * @throws UserFormException
diff --git a/extension/qfq/qfq/helper/Logger.php b/extension/qfq/qfq/helper/Logger.php
index 5b4533bb18187786e229c44831a62a743607a80d..8d2c78cb5814320ed18fd65a40216d977501be47 100644
--- a/extension/qfq/qfq/helper/Logger.php
+++ b/extension/qfq/qfq/helper/Logger.php
@@ -18,6 +18,7 @@ class Logger {
      *
      * @param $msg
      * @param $filename
+     *
      * @throws UserFormException
      */
     public static function logMessage($msg, $filename) {
@@ -30,7 +31,7 @@ class Logger {
             throw new UserFormException("Error - cannot open. File: " . $filename . " ( CWD: " . getcwd() . ")", ERROR_IO_OPEN);
         }
 
-        if (fwrite($handle, $msg . PHP_EOL) === FALSE) {
+        if (fwrite($handle, $msg . PHP_EOL) === false) {
             throw new UserFormException("Error - cannot write. File: " . $filename . " ( CWD: " . getcwd() . ")", ERROR_IO_WRITE);
         }
 
@@ -39,6 +40,7 @@ class Logger {
 
     /**
      * @param array $fe
+     *
      * @return string
      */
     public static function formatFormElementName(array $fe) {
diff --git a/extension/qfq/qfq/helper/OnArray.php b/extension/qfq/qfq/helper/OnArray.php
index 895c978ef55fd36c2963d19c30ef42a9876d4edf..692537f903ac6c2158d386c0a298d9e5ec0dd188 100644
--- a/extension/qfq/qfq/helper/OnArray.php
+++ b/extension/qfq/qfq/helper/OnArray.php
@@ -30,6 +30,7 @@ class OnArray {
      * @param string $keyValueGlue
      * @param string $rowGlue
      * @param string $encloseValue - char (or string) to enclose the value with.
+     *
      * @return string
      */
     public static function toString(array $dataArray, $keyValueGlue = '=', $rowGlue = '&', $encloseValue = '') {
@@ -44,6 +45,7 @@ class OnArray {
         }
 
         $glueLength = strlen($rowGlue);
+
         return substr($dataString, 0, strlen($dataString) - $glueLength);
     }
 
@@ -70,14 +72,16 @@ class OnArray {
      * Trim all elemements in an array.
      * The array has to be a 1-dimensional array.
      *
-     * @param array $arr
+     * @param array  $arr
      * @param string $character_mask
+     *
      * @return array
      */
     public static function trimArray(array $arr, $character_mask = " \t\n\r\0\x0B") {
         foreach ($arr as $key => $item) {
             $arr[$key] = trim($item, $character_mask);
         }
+
         return $arr;
     }
 
@@ -85,8 +89,9 @@ class OnArray {
      * Iterates over all records and return those with $row[$column]==$value
      *
      * @param array $dataArray
-     * @param $column
-     * @param $value
+     * @param       $column
+     * @param       $value
+     *
      * @return array
      */
     public static function filter(array $dataArray, $column, $value) {
@@ -97,6 +102,7 @@ class OnArray {
                 $result[] = $row;
             }
         }
+
         return $result;
     }
 
@@ -104,12 +110,14 @@ class OnArray {
      * Converts a onedimensional array by using htmlentities on all elements
      *
      * @param array $arr
+     *
      * @return array
      */
     public static function htmlentitiesOnArray(array $arr) {
         foreach ($arr as $key => $value) {
             $arr[$key] = htmlentities($arr[$key], ENT_QUOTES);
         }
+
         return $arr;
     }
 
@@ -118,6 +126,7 @@ class OnArray {
      *
      * @param string $delimiter
      * @param string $str
+     *
      * @return array
      * @throws UserReportException
      */
@@ -143,6 +152,7 @@ class OnArray {
      * Iterates over $arr and removes all empty (='') elements. Preserves keys
      *
      * @param array $arr
+     *
      * @return array
      */
     public static function removeEmptyElementsFromArray(array $arr) {
@@ -171,7 +181,9 @@ class OnArray {
 
     /**
      * Convert all values of an array to lowercase.
+     *
      * @param array $arr
+     *
      * @return array
      */
     public static function arrayValueToLower(array $arr) {
@@ -180,6 +192,7 @@ class OnArray {
         foreach ($arr as $key => $value) {
             $new[$key] = strtolower($value);
         }
+
         return $new;
     }
 
@@ -189,6 +202,7 @@ class OnArray {
      * @param array $src
      * @param array $dest
      * @param array $keyNames
+     *
      * @return array $dest filled with new values
      */
     public static function copyArrayItemsIfNotAlreadyExist(array $src, array $dest, array $keyNames) {
@@ -210,7 +224,8 @@ class OnArray {
      *
      * @param array $src
      * @param array $keyNames
-     * @param bool $createMissing
+     * @param bool  $createMissing
+     *
      * @return array
      */
     public static function getArrayItems(array $src, array $keyNames, $createMissing = false, $skipZero = false, $skipEmpty = false) {
@@ -241,8 +256,9 @@ class OnArray {
      *
      * E.g. [ 'mode' => 'pdf', '1_pageId' => 123, '2_file' => 'example.pdf' ], with $keyName='1_' >> [ 'pageId' => 123 ]
      *
-     * @param array $src
+     * @param array  $src
      * @param string $keyName
+     *
      * @return array
      */
     public static function getArrayItemKeyNameStartWith(array $src, $keyName) {
@@ -265,8 +281,9 @@ class OnArray {
      * Iterates over an array and replaces $search with $replace in all elements. Returns the new array.
      *
      * @param array $src
-     * @param $search
-     * @param $replace
+     * @param       $search
+     * @param       $replace
+     *
      * @return array
      */
     public static function arrayValueReplace(array $src, $search, $replace) {
@@ -283,6 +300,7 @@ class OnArray {
      * Performs escapeshellarg() on all elements of an array.
      *
      * @param array $src
+     *
      * @return array
      */
     public static function arrayEscapeshellarg(array $src) {
@@ -301,6 +319,7 @@ class OnArray {
 
     /**
      * @param array $data
+     *
      * @return string md5 of implode $data
      */
     public static function getMd5(array $data) {
diff --git a/extension/qfq/qfq/helper/Sanitize.php b/extension/qfq/qfq/helper/Sanitize.php
index 6238071c51cc3c793e484fe50af58642a6172b5a..512ba3db6aa0278b0297dbda40d9d588bc8f4887 100644
--- a/extension/qfq/qfq/helper/Sanitize.php
+++ b/extension/qfq/qfq/helper/Sanitize.php
@@ -34,7 +34,8 @@ class Sanitize {
      * @param string $value value to check
      * @param string $sanitizeClass SANITIZE_ALLOW_*
      * @param string $patternOrRange Pattern as regexp or MIN|MAX values
-     * @param string $mode SANITIZE_EXCEPTION | SANITIZE_EMPTY_STRING
+     * @param string $mode  SANITIZE_EXCEPTION | SANITIZE_EMPTY_STRING
+     *
      * @return string
      * @throws UserFormException
      * @throws \qfq\CodeException
@@ -138,15 +139,15 @@ class Sanitize {
     public static function inputCheckPatternArray() {
         //EMail Regex: http://www.regular-expressions.info/email.html
         return [
-            SANITIZE_ALLOW_ALNUMX => '^[@\-_\.,;: \/\(\)a-zA-Z0-9ÀÈÌÒÙàèìòùÁÉÍÓÚÝáéíóúýÂÊÎÔÛâêîôûÃÑÕãñõÄËÏÖÜŸäëïöüÿç]*$', // ':alnum:' does not work here in FF
-            SANITIZE_ALLOW_DIGIT => '^[\d]*$',
+            SANITIZE_ALLOW_ALNUMX  => '^[@\-_\.,;: \/\(\)a-zA-Z0-9ÀÈÌÒÙàèìòùÁÉÍÓÚÝáéíóúýÂÊÎÔÛâêîôûÃÑÕãñõÄËÏÖÜŸäëïöüÿç]*$', // ':alnum:' does not work here in FF
+            SANITIZE_ALLOW_DIGIT   => '^[\d]*$',
             SANITIZE_ALLOW_NUMERICAL => '^[\d.+-]*$',
-            SANITIZE_ALLOW_EMAIL => '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
+            SANITIZE_ALLOW_EMAIL   => '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
             SANITIZE_ALLOW_MIN_MAX => '',
             SANITIZE_ALLOW_MIN_MAX_DATE => '',
             SANITIZE_ALLOW_PATTERN => '',
-            SANITIZE_ALLOW_ALLBUT => '^[^\[\]{}%&\\\\#]*$',
-            SANITIZE_ALLOW_ALL => '.*'
+            SANITIZE_ALLOW_ALLBUT  => '^[^\[\]{}%&\\\\#]*$',
+            SANITIZE_ALLOW_ALL     => '.*',
         ];
     }
 
@@ -154,6 +155,7 @@ class Sanitize {
      * Sanatizes a filename. Copied from http://www.phpit.net/code/filename-safe/
      *
      * @param $filename
+     *
      * @return mixed
      */
     public static function safeFilename($filename) {
@@ -172,7 +174,7 @@ class Sanitize {
             'ae', 'Ae',
             'oe', 'Oe',
             'ue', 'Ue',
-            '_'
+            '_',
         );
 
         return preg_replace($search, $replace, $filename);
@@ -182,7 +184,8 @@ class Sanitize {
      * htmlentities($data) - if $data is an array, convert it recursively.
      *
      * @param string|array $data
-     * @param int $mode
+     * @param int          $mode
+     *
      * @return array|string
      */
     public static function htmlentitiesArr($data, $mode = ENT_QUOTES) {
@@ -209,6 +212,7 @@ class Sanitize {
      * with composed characters (happens e.g. on Apple Mac / Safari without special user invention).
      *
      * @param array|string $item
+     *
      * @return array|string
      * @throws CodeException
      */
@@ -226,13 +230,16 @@ class Sanitize {
                 throw new qfq\CodeException ("Expect type 'string / numeric / array' - but there is something else.", ERROR_UNEXPECTED_TYPE);
             }
         }
+
         return $item;
     }
 
     /**
-     * urlencode() any input and decode again. This normalizes all characters and guarantees that there are no more urlencoded characters.
+     * urlencode() any input and decode again. This normalizes all characters and guarantees that there are no more
+     * urlencoded characters.
      *
      * @param array|string $item
+     *
      * @return array|string
      * @throws CodeException
      */
@@ -250,6 +257,7 @@ class Sanitize {
                 throw new qfq\CodeException ("Expect type 'string / numeric / array' - but there is something else.", ERROR_UNEXPECTED_TYPE);
             }
         }
+
         return $item;
 
     }
diff --git a/extension/qfq/qfq/helper/SessionCookie.php b/extension/qfq/qfq/helper/SessionCookie.php
index 5a4cc296c3f00621e090fb9b070ad43cd97c1f32..87c0caf1c66d3bfaf91c81a5b9573d71b3cc9205 100644
--- a/extension/qfq/qfq/helper/SessionCookie.php
+++ b/extension/qfq/qfq/helper/SessionCookie.php
@@ -26,6 +26,7 @@ class SessionCookie {
      * Copy all current cookies to a temporary file.
      *
      * @param array $config
+     *
      * @throws CodeException
      */
     public function __construct(array $config) {
diff --git a/extension/qfq/qfq/helper/Support.php b/extension/qfq/qfq/helper/Support.php
index a49b8e1cbbe2353b502e46a6fce504730fa79222..d0bb08225dd7ba2d6083ccb9c40d860fdd403e31 100644
--- a/extension/qfq/qfq/helper/Support.php
+++ b/extension/qfq/qfq/helper/Support.php
@@ -17,8 +17,8 @@ const LONG_CURLY_CLOSE = '#/+close+/#';
 class Support {
 
     /**
-     * @param array $queryArray Empty or prefilled assoc array with url parameter
-     * @param string $mode PARAM_T3_NO_ID, PARAM_T3_ALL
+     * @param array  $queryArray Empty or prefilled assoc array with url parameter
+     * @param string $mode       PARAM_T3_NO_ID, PARAM_T3_ALL
      */
     public static function appendTypo3ParameterToArray(array &$queryArray, $mode = PARAM_T3_ALL) {
 //        if (isset($_GET['id']))
@@ -47,6 +47,7 @@ class Support {
      * Builds a urlencoded query string of an assoc array.
      *
      * @param array $queryArray
+     *
      * @return string Querystring (e.g.: id=23&type=99
      */
     public static function arrayToQueryString(array $queryArray) {
@@ -64,16 +65,29 @@ class Support {
     }
 
     /**
-     * Extract Tag from $tag (eg: <input class="form-control">, might contain further attributes) and wrap it around $value. If $flagOmitEmpty==true && $value=='': return ''.
+     * Extract Tag(s) from $tag (eg: <div><input class="form-control">, might contain further attributes) and wrap it
+     * around
+     * $value. If $flagOmitEmpty==true && $value=='': return ''.
      *
-     * @param string $tag
-     * @param string $value
+     * @param string     $tag
+     * @param string     $value
      * @param bool|false $omitIfValueEmpty
+     *
      * @return string
      */
     public static function wrapTag($tag, $value, $omitIfValueEmpty = false) {
-        if ($omitIfValueEmpty && $value === "")
-            return '';
+
+        $tag = trim($tag);
+
+        if ($tag == '' || ($omitIfValueEmpty && $value == "")) {
+            return $value;
+        }
+
+        $tagArray = explode('>', $tag, 2);
+        if (count($tagArray) > 1 && $tagArray[1] != '') {
+            $value = self::wrapTag($tagArray[1], $value, $omitIfValueEmpty);
+            $tag = $tagArray[0] . '>';
+        }
 
         // a) <div class="container-fluid">, b) <label>
         $arr = explode(' ', $tag);
@@ -84,6 +98,37 @@ class Support {
         return $tag . $value . $closing;
     }
 
+    /**
+     * Removes '$tag' and closing $tag from $value, if they are the outermost.
+     * E.g.  unWrapTag('<p>', '<p>Hello World</p>')    returns  'Hello World'
+     *
+     * @param string $tag
+     * @param string $value
+     *
+     * @return string
+     */
+    public static function unWrapTag($tag, $value) {
+
+        if ($tag == '' || $value == '') {
+            return $value;
+        }
+
+        $lenTag = strlen($tag);
+        $lenValue = strlen($value);
+
+        if ($lenValue < $lenTag + $lenTag + 1) {
+            return $value;
+        }
+
+        $closeTag = $tag[0] . '/' . substr($tag, 1);
+
+        if (substr($value, 0, $lenTag) == $tag && substr($value, $lenValue - $lenTag - 1) == $closeTag) {
+            $value = substr($value, $lenTag, $lenValue - $lenTag - $lenTag - 1);
+        }
+
+        return $value;
+    }
+
     /**
      * Wraps some $inner fragment with a CSS styled $tooltipText . CSS is configured in 'Resources/Public/qfq-jqw.css'.
      *
@@ -91,6 +136,7 @@ class Support {
      *
      * @param string $htmlId
      * @param string $tooltipText
+     *
      * @return string
      */
     public static function doTooltip($htmlId, $tooltipText) {
@@ -102,10 +148,11 @@ class Support {
      * Format's an attribute: $type=$value. If $flagOmitEmpty==true && $value=='': return ''.
      * Add's a space at the end.
      *
-     * @param string $type
+     * @param string       $type
      * @param string|array $value
-     * @param bool $flagOmitEmpty
-     * @param string $modeEscape
+     * @param bool         $flagOmitEmpty
+     * @param string       $modeEscape
+     *
      * @return string correctly fomratted attribute. Space at the end.
      * @throws CodeException
      */
@@ -148,8 +195,9 @@ class Support {
      *
      * TinyMCE: Encoding JS Attributes (keys & values) for TinyMCE needs to be encapsulated in '&quot;' instead of '\"'.
      *
-     * @param $str
+     * @param        $str
      * @param string $modeEscape
+     *
      * @return string
      * @throws CodeException
      */
@@ -181,11 +229,12 @@ class Support {
      * Format's an attribute and inserts them at the beginning of the $htmlTag:
      * If $flagOmitEmpty==true && $value=='': insert nothing
      *
-     * @param string $htmlTag with open and closing angle.
-     * @param string $type
+     * @param string       $htmlTag with open and closing angle.
+     * @param string       $type
      * @param string|array $value
-     * @param bool $flagOmitEmpty
-     * @param string $modeEscape
+     * @param bool         $flagOmitEmpty
+     * @param string       $modeEscape
+     *
      * @return string correctly fomratted attribute. Space at the end.
      * @throws CodeException
      */
@@ -215,6 +264,7 @@ class Support {
      *
      * @param string $needle
      * @param string $haystack
+     *
      * @return boolean     true if found, else false
      */
     public static function findInSet($needle, $haystack) {
@@ -230,6 +280,7 @@ class Support {
      * 1.2.1979 14:21:5 > 1979-02-01 14:21:05
      *
      * @param string $dateTimeString
+     *
      * @return string
      * @throws UserFormException
      */
@@ -265,7 +316,7 @@ class Support {
                 break;
         }
 
-        if ($dateRaw === '') {
+        if ($dateRaw === '' || $dateRaw === '0000-00-00') {
             $date = '0000-00-00';
         } else {
             // International format: YYYY-MM-DD
@@ -289,7 +340,7 @@ class Support {
             }
         }
 
-        if ($timeRaw === '') {
+        if ($timeRaw === '' || $timeRaw === '00:00:00') {
             $time = '00:00:00';
         } else {
             if (preg_match('/^\d{1,2}:\d{1,2}(:\d{1,2})?$/', $timeRaw) !== 1) {
@@ -317,6 +368,7 @@ class Support {
      * @param string $type date | datetime | time
      * @param string $format FORMAT_DATE_INTERNATIONAL | FORMAT_DATE_GERMAN
      * @param string $showSeconds
+     *
      * @return string
      * @throws UserFormException
      */
@@ -360,6 +412,7 @@ class Support {
      * @param string $showZero
      * @param string $showTime
      * @param string $showSeconds
+     *
      * @return string
      * @throws UserFormException
      */
@@ -450,8 +503,9 @@ class Support {
      *
      * @param string $dateFormat FORMAT_DATE_INTERNATIONAL | FORMAT_DATE_GERMAN
      * @param string $showZero
-     * @param string $showTime '0' | '1'
+     * @param string $showTime   '0' | '1'
      * @param string $showSeconds '0' | '1'
+     *
      * @return string
      */
     private static function dateTimeZero($dateFormat, $showZero, $showTime, $showSeconds) {
@@ -479,6 +533,7 @@ class Support {
      * Split date FORMAT_DATE_GERMAN | FORMAT_DATE_INTERNATIONAL to array with arr[0]=yyyy, arr[1]=mm, arr[2]=dd.
      *
      * @param string $dateString
+     *
      * @return array
      * @throws UserFormException
      */
@@ -514,6 +569,7 @@ class Support {
      * Calculates the placeholder for date/dateTime/local input fields.
      *
      * @param array $formElement
+     *
      * @return string
      * @throws UserFormException
      */
@@ -542,6 +598,7 @@ class Support {
      * Encrypt curly braces by an uncommon string. Helps preventing unwished action on curly braces.
      *
      * @param string $text
+     *
      * @return mixed
      */
     public
@@ -556,6 +613,7 @@ class Support {
      * Decrypt curly braces by an uncommon string. Helps preventing unwished action on curly braces
      *
      * @param string $text
+     *
      * @return mixed
      */
     public static function decryptDoubleCurlyBraces($text) {
@@ -572,6 +630,7 @@ class Support {
 
     /**
      * @param int $length Length of the required hash string
+     *
      * @return string       A random alphanumeric hash
      */
     public static function randomAlphaNum($length) {
@@ -589,6 +648,7 @@ class Support {
      *
      * @param string $url
      * @param string $param
+     *
      * @return string
      */
     public static function concatUrlParam($url, $param) {
@@ -597,6 +657,7 @@ class Support {
         }
 
         $token = (strpos($url, '?') === false) ? '?' : '&';
+
         return $url . $token . $param;
     }
 
@@ -610,6 +671,7 @@ class Support {
      * @param string $host
      * @param string $hostOrPath
      * @param string $query
+     *
      * @return string
      * @throws CodeException
      */
@@ -650,6 +712,7 @@ class Support {
      * Set Defaults for the current formElement.
      *
      * @param array $formElement
+     *
      * @return array
      */
     public static function setFeDefaults(array $formElement, array $formSpec = array()) {
@@ -665,7 +728,9 @@ class Support {
         self::setIfNotSet($formElement, FE_HTML_BEFORE);
         self::setIfNotSet($formElement, FE_HTML_AFTER);
 
-        if (count($formSpec) > 0) {
+        self::setIfNotSet($formElement, FE_SUBRECORD_TABLE_CLASS, 'table table-hover');
+
+        if (isset($formSpec[F_BS_LABEL_COLUMNS])) {
             self::setIfNotSet($formElement, F_BS_LABEL_COLUMNS, $formSpec[F_BS_LABEL_COLUMNS], '');
             self::setIfNotSet($formElement, F_BS_INPUT_COLUMNS, $formSpec[F_BS_INPUT_COLUMNS], '');
             self::setIfNotSet($formElement, F_BS_NOTE_COLUMNS, $formSpec[F_BS_NOTE_COLUMNS], '');
@@ -675,6 +740,10 @@ class Support {
             $formElement[FE_MODE] = $formElement[FE_MODE_SQL];
         }
 
+        if (isset($formSpec[F_MODE])) {
+            $formElement[FE_MODE] = self::applyFormModeToFormElement($formElement[FE_MODE], $formSpec[F_MODE]);
+        }
+
         // Will be used to change dynamicUpdate behaviour
         if (isset($formElement[FE_WRAP_ROW_LABEL_INPUT_NOTE])) {
             $formElement[FE_FLAG_ROW_OPEN_TAG] = Support::findInSet('row', $formElement[FE_WRAP_ROW_LABEL_INPUT_NOTE]);
@@ -684,17 +753,59 @@ class Support {
             $formElement[FE_FLAG_ROW_CLOSE_TAG] = false;
         }
 
+        self::setIfNotSet($formElement, FE_INPUT_EXTRA_BUTTON_INFO_CLASS, $store->getVar(FE_INPUT_EXTRA_BUTTON_INFO_CLASS, STORE_SYSTEM));
+
         return $formElement;
     }
 
+    /**
+     * Depending on $formMode and $feMode, calculate a new $feMode.
+     * - If $formMode='' : no change.
+     * - If $formMode=F_MODE_READ_ONLY: set feMode=FE_MODE_READ_ONLY, for all visible elements.
+     * - If $formMode=F_MODE_REQUIRED_OFF: set feMode=FE_MODE_SHOW, who have have FE_MODE_REQUIRE before.
+     *
+     * @param string $feMode   FE_MODE_SHOW | FE_MODE_REQUIRED | FE_MODE_READONLY | FE_MODE_HIDDEN |
+     * @param string $formMode '' | F_MODE_READONLY | F_MODE_REQUIRED_OFF
+     *
+     * @return array|string
+     * @throws CodeException
+     */
+    private function applyFormModeToFormElement($feMode, $formMode) {
+
+        if ($formMode == '') {
+            return $feMode; //no change
+        }
+
+        switch ($feMode) {
+            case FE_MODE_HIDDEN:
+            case FE_MODE_READONLY:
+                break;
+
+            case FE_MODE_SHOW:
+            case FE_MODE_REQUIRED:
+                if ($formMode == F_MODE_READONLY) {
+                    $feMode = FE_MODE_READONLY;
+                } elseif ($formMode == F_MODE_REQUIRED_OFF && $feMode = FE_MODE_REQUIRED) {
+                    $feMode = FE_MODE_SHOW;
+                }
+                break;
+
+            default:
+                throw new CodeException('Unknown mode: ' . $feMode, ERROR_UNKNOWN_MODE);
+        }
+
+        return $feMode;
+    }
+
     /**
      * Looks in $arr if there is an element $index. If not, set it to $value.
      * If  $overwriteThis!=false, replace the the original value with $value, if $arr[$index]==$overwriteThis.
      *
-     * @param array $arr
+     * @param array  $arr
      * @param string $index
      * @param string $value
      * @param string|bool $overwriteThis If there is already something which is equal to $overwrite: take new default.
+     *
      * @return mixed
      */
     public static function setIfNotSet(array &$arr, $index, $value = '', $overwriteThis = false) {
@@ -713,6 +824,7 @@ class Support {
     /**
      * @param string $filename
      * @param string $extend
+     *
      * @return string
      */
     public static function extendFilename($filename, $extend) {
@@ -720,9 +832,11 @@ class Support {
     }
 
     /**
-     * Creates all necessary directories in $pathFileName, but not the last part, the filename. A filename has to be specified.
+     * Creates all necessary directories in $pathFileName, but not the last part, the filename. A filename has to be
+     * specified.
      *
      * @param string $pathFileName Path with Filename
+     *
      * @throws UserFormException
      */
     public static function mkDirParent($pathFileName) {
@@ -761,6 +875,7 @@ class Support {
      * Convert 'false' and 'empty' to '0'.
      *
      * @param $val
+     *
      * @return string
      */
     public static function falseEmptyToZero($val) {
@@ -773,6 +888,7 @@ class Support {
      * Check if the string starts or ends with an 'escape space' - strip the escape character.
      *
      * @param string $str
+     *
      * @return string
      */
     public static function handleEscapeSpaceComment($str) {
@@ -805,9 +921,10 @@ class Support {
      * Workaround for PHP < 5.6.0: there is no ldap_escape() - use this code instead.
      *
      * @param string $subject The subject string
-     * @param string $ignore Set of characters to leave untouched
-     * @param int $flags Any combination of LDAP_ESCAPE_* flags to indicate the
-     *                   set(s) of characters to escape.
+     * @param string $ignore  Set of characters to leave untouched
+     * @param int    $flags   Any combination of LDAP_ESCAPE_* flags to indicate the
+     *                        set(s) of characters to escape.
+     *
      * @return string
      **/
     public static function ldap_escape($subject, $ignore = '', $flags = 0) {
diff --git a/extension/qfq/qfq/report/Download.php b/extension/qfq/qfq/report/Download.php
index 2c5ea8c7bd25fbdb54a07e1142978e722baee587..8f53ef159c0113b9746094a589ff7fef1fa02e3c 100644
--- a/extension/qfq/qfq/report/Download.php
+++ b/extension/qfq/qfq/report/Download.php
@@ -82,6 +82,7 @@ class Download {
      * Concatenate all named files to one PDF file. Return name of new full PDF.
      *
      * @param array $files
+     *
      * @return string  - fileName of concatenated file
      * @throws DownloadException
      */
@@ -138,6 +139,7 @@ class Download {
      * @param string $filename
      * @param string $outputFilename
      * @param string $rcMimetype
+     *
      * @return string possible updated $outputFilename, according the mimetype.
      */
     private function targetFilenameExtension($filename, $outputFilename, &$rcMimetype) {
@@ -202,6 +204,7 @@ class Download {
      * Interprets $element and fetches corresponding content as file.
      *
      * @param string $element - U:id=myExport&r=12, u:http://www.nzz.ch/issue?nr=21, f:fileadmin/sample.pdf
+     *
      * @return string filename - already ready or fresh exported. Fresh exported needs to be deleted later.
      * @throws DownloadException
      * @throws \exception
@@ -238,6 +241,7 @@ class Download {
      * Creates a ZIP Files of all given $files
      *
      * @param array $files
+     *
      * @return string ZIP filename - has to be deleted later.
      * @throws DownloadException
      */
@@ -250,7 +254,7 @@ class Download {
 
         $zip = new \ZipArchive();
 
-        if ($zip->open($zipFile, \ZipArchive::CREATE) !== TRUE) {
+        if ($zip->open($zipFile, \ZipArchive::CREATE) !== true) {
             throw new DownloadException("Error creating/opening new empty zip file: $zipFile", ERROR_IO_OPEN);
         }
 
@@ -282,6 +286,7 @@ class Download {
      * <i>_file=<filename>
      *
      * @param array $vars [ DOWNLOAD_EXPORT_FILENAME, DOWNLOAD_MODE, SIP_DOWNLOAD_PARAMETER ]
+     *
      * @throws DownloadException
      * @internal param array $elements
      */
diff --git a/extension/qfq/qfq/report/Error.php b/extension/qfq/qfq/report/Error.php
index 263ad0a76025d7a8d25f1d9b0cba240f942e5486..4e038ecc6cd31579c2c87052c840ee60ddd8be55 100644
--- a/extension/qfq/qfq/report/Error.php
+++ b/extension/qfq/qfq/report/Error.php
@@ -29,23 +29,24 @@ namespace qfq;
 /**
  * syntaxException: Webmaster made a mistake in tt_content record or form definition
  *
- * @param    string $message
- * @param    string $code
- * @param    string $file
- * @param    string $line
- * @param    string|array $customMessage =array()   a) string: "key: value",  b) array("key1: value1","key2: value2", ...) - all items will be displayed on an own line in the error message.
+ * @param    string       $message
+ * @param    string       $code
+ * @param    string       $file
+ * @param    string       $line
+ * @param    string|array $customMessage =array()   a) string: "key: value",  b) array("key1: value1","key2: value2",
+ *                                       ...) - all items will be displayed on an own line in the error message.
  */
 class SyntaxReportException extends \Exception {
     private $fr_error;
 
     /**
-     * @param string $message
-     * @param int $code
+     * @param string     $message
+     * @param int        $code
      * @param \Exception $previous
-     * @param $file
-     * @param $line
-     * @param array $customMessage
-     * @param array $fr_error
+     * @param            $file
+     * @param            $line
+     * @param array      $customMessage
+     * @param array      $fr_error
      */
     public function __construct($message, $code, $previous, $file, $line, $customMessage = array(), $fr_error = array()) {
         parent::__construct($message);
@@ -104,11 +105,11 @@ class SqlReportException extends \Exception {
     private $fr_error;
 
     /**
-     * @param string $message
-     * @param int $sql
+     * @param string     $message
+     * @param int        $sql
      * @param \Exception $file
-     * @param $line
-     * @param array $fr_error
+     * @param            $line
+     * @param array      $fr_error
      */
     public function __construct($message, $sql, $file, $line, $fr_error = array()) {
         parent::__construct($message);
@@ -139,6 +140,7 @@ class SqlReportException extends \Exception {
         } else {
             $errorMsg = "<hr />Error: <strong>" . htmlentities($this->getMessage()) . "</strong><hr />";
         }
+
         return $errorMsg;
     }  // errorMessage()
 } // class sqlException
@@ -187,7 +189,8 @@ class CodeReportException extends \Exception {
 
 
 /**
- * userException: Exception on user-level: Session expired, invalid form submission, no authorization, invalid request, etc.
+ * userException: Exception on user-level: Session expired, invalid form submission, no authorization, invalid request,
+ * etc.
  *
  * @param    string $message
  * @param    string $file
diff --git a/extension/qfq/qfq/report/Html2Pdf.php b/extension/qfq/qfq/report/Html2Pdf.php
index 8950f2d775f60d99aeb7475778b695c23ff3050c..a820996cfb354df456ffbadf847bac456d3b797a 100644
--- a/extension/qfq/qfq/report/Html2Pdf.php
+++ b/extension/qfq/qfq/report/Html2Pdf.php
@@ -45,14 +45,15 @@ class Html2Pdf {
     /**
      * @var string
      */
-    private $logfile = '';
+    private $logFile = '';
 
     /**
      * Read QFQ config. Only SYSTEM_BASE_URL_PRINT and SYSTEM_WKHTMLTOPDF will be used.
      * Check and get all clean _GET Parameter. Build a URL based on SYSTEM_BASE_URL_PRINT and the delivered URL params.
      *
      * @param array $config
-     * @param $phpUnit
+     * @param       $phpUnit
+     *
      * @throws UserFormException
      * @throws \exception
      */
@@ -122,8 +123,9 @@ class Html2Pdf {
      * - '_sip' - to activate that `urlParam` parameters will be SIP encoded.
      *
      * @param string $urlParamString
-     * @param array $rcArgs
-     * @param bool $rcSipEncode
+     * @param array  $rcArgs
+     * @param bool   $rcSipEncode
+     *
      * @return array The remaining 'real' URL parameter to call the T3 page.
      * @throws UserFormException
      */
@@ -157,6 +159,7 @@ class Html2Pdf {
      *
      * @param string $token TOKEN_URL | TOKEN_URL_PARAM
      * @param string $url id=exportPage&r=123, www.nzz.ch/issue?id=456
+     *
      * @return string rendered file - please delete later
      * @throws CodeException
      * @throws UserFormException
diff --git a/extension/qfq/qfq/report/Link.php b/extension/qfq/qfq/report/Link.php
index bf1a4a280adc2ba367b90d3bbe9d6c4802b43510..08cb95c12951144cbfbf17387070c190c6dbebe6 100644
--- a/extension/qfq/qfq/report/Link.php
+++ b/extension/qfq/qfq/report/Link.php
@@ -143,73 +143,73 @@ class Link {
     private $ttContentUid = '';
 
     private $callTable = [
-        TOKEN_URL => 'buildUrl',
-        TOKEN_MAIL => 'buildMail',
-        TOKEN_PAGE => 'buildPage',
+        TOKEN_URL     => 'buildUrl',
+        TOKEN_MAIL    => 'buildMail',
+        TOKEN_PAGE    => 'buildPage',
         TOKEN_DOWNLOAD => 'buildDownload',
         TOKEN_TOOL_TIP => 'buildToolTip',
         TOKEN_PICTURE => 'buildPicture',
-        TOKEN_BULLET => 'buildBullet',
-        TOKEN_CHECK => 'buildCheck',
-        TOKEN_DELETE => 'buildDeleteIcon',
+        TOKEN_BULLET  => 'buildBullet',
+        TOKEN_CHECK   => 'buildCheck',
+        TOKEN_DELETE  => 'buildDeleteIcon',
         TOKEN_ACTION_DELETE => 'buildActionDelete',
-        TOKEN_EDIT => 'buildEdit',
-        TOKEN_HELP => 'buildHelp',
-        TOKEN_INFO => 'buildInfo',
-        TOKEN_NEW => 'buildNew',
-        TOKEN_SHOW => 'buildShow',
-        TOKEN_FILE => 'buildFile',
-        TOKEN_GLYPH => 'buildGlyph',
+        TOKEN_EDIT    => 'buildEdit',
+        TOKEN_HELP    => 'buildHelp',
+        TOKEN_INFO    => 'buildInfo',
+        TOKEN_NEW     => 'buildNew',
+        TOKEN_SHOW    => 'buildShow',
+        TOKEN_FILE    => 'buildFile',
+        TOKEN_GLYPH   => 'buildGlyph',
     ];
 
     private $tableVarName = [
-        TOKEN_URL => NAME_URL,
-        TOKEN_MAIL => NAME_MAIL,
-        TOKEN_PAGE => NAME_PAGE,
-        TOKEN_DOWNLOAD => NAME_DOWNLOAD,
+        TOKEN_URL       => NAME_URL,
+        TOKEN_MAIL      => NAME_MAIL,
+        TOKEN_PAGE      => NAME_PAGE,
+        TOKEN_DOWNLOAD  => NAME_DOWNLOAD,
         TOKEN_DOWNLOAD_MODE => NAME_DOWNLOAD_MODE,
-        TOKEN_TEXT => NAME_TEXT,
-        TOKEN_ALT_TEXT => NAME_ALT_TEXT,
-        TOKEN_TOOL_TIP => NAME_TOOL_TIP,
-        TOKEN_PICTURE => NAME_IMAGE,
-        TOKEN_BULLET => NAME_IMAGE,
-        TOKEN_CHECK => NAME_IMAGE,
-        TOKEN_DELETE => NAME_IMAGE,
-        TOKEN_EDIT => NAME_IMAGE,
-        TOKEN_HELP => NAME_IMAGE,
-        TOKEN_INFO => NAME_IMAGE,
-        TOKEN_NEW => NAME_IMAGE,
-        TOKEN_SHOW => NAME_IMAGE,
-        TOKEN_GLYPH => NAME_IMAGE,
-        TOKEN_RENDER => NAME_RENDER,
-        TOKEN_TARGET => NAME_TARGET,
-        TOKEN_CLASS => NAME_LINK_CLASS,
-        TOKEN_QUESTION => NAME_QUESTION,
+        TOKEN_TEXT      => NAME_TEXT,
+        TOKEN_ALT_TEXT  => NAME_ALT_TEXT,
+        TOKEN_TOOL_TIP  => NAME_TOOL_TIP,
+        TOKEN_PICTURE   => NAME_IMAGE,
+        TOKEN_BULLET    => NAME_IMAGE,
+        TOKEN_CHECK     => NAME_IMAGE,
+        TOKEN_DELETE    => NAME_IMAGE,
+        TOKEN_EDIT      => NAME_IMAGE,
+        TOKEN_HELP      => NAME_IMAGE,
+        TOKEN_INFO      => NAME_IMAGE,
+        TOKEN_NEW       => NAME_IMAGE,
+        TOKEN_SHOW      => NAME_IMAGE,
+        TOKEN_GLYPH     => NAME_IMAGE,
+        TOKEN_RENDER    => NAME_RENDER,
+        TOKEN_TARGET    => NAME_TARGET,
+        TOKEN_CLASS     => NAME_LINK_CLASS,
+        TOKEN_QUESTION  => NAME_QUESTION,
         TOKEN_ENCRYPTION => NAME_ENCRYPTION,
-        TOKEN_SIP => NAME_SIP,
+        TOKEN_SIP       => NAME_SIP,
         TOKEN_URL_PARAM => NAME_URL_PARAM,
-        TOKEN_RIGHT => NAME_RIGHT,
+        TOKEN_RIGHT     => NAME_RIGHT,
         TOKEN_ACTION_DELETE => NAME_ACTION_DELETE,
-        TOKEN_FILE => NAME_FILE,
+        TOKEN_FILE      => NAME_FILE,
     ];
 
     // Used to find double definitions.
     private $tokenMapping = [
-        TOKEN_URL => LINK_ANCHOR,
-        TOKEN_MAIL => LINK_ANCHOR,
-        TOKEN_PAGE => LINK_ANCHOR,
+        TOKEN_URL    => LINK_ANCHOR,
+        TOKEN_MAIL   => LINK_ANCHOR,
+        TOKEN_PAGE   => LINK_ANCHOR,
         TOKEN_DOWNLOAD => LINK_ANCHOR,
 
         TOKEN_PICTURE => LINK_PICTURE,
         TOKEN_BULLET => LINK_PICTURE,
-        TOKEN_CHECK => LINK_PICTURE,
+        TOKEN_CHECK  => LINK_PICTURE,
         TOKEN_DELETE => LINK_PICTURE,
-        TOKEN_EDIT => LINK_PICTURE,
-        TOKEN_HELP => LINK_PICTURE,
-        TOKEN_INFO => LINK_PICTURE,
-        TOKEN_NEW => LINK_PICTURE,
-        TOKEN_SHOW => LINK_PICTURE,
-        TOKEN_GLYPH => LINK_PICTURE,
+        TOKEN_EDIT   => LINK_PICTURE,
+        TOKEN_HELP   => LINK_PICTURE,
+        TOKEN_INFO   => LINK_PICTURE,
+        TOKEN_NEW    => LINK_PICTURE,
+        TOKEN_SHOW   => LINK_PICTURE,
+        TOKEN_GLYPH  => LINK_PICTURE,
     ];
 
     /**
@@ -280,7 +280,9 @@ class Link {
      * Build the whole link
      *
      * @param string $str Qualifier with params. 'report'-syntax. F.e.:  A:u:www.example.com|G:P:home.gif|t:Home"
-     * @return string The complete HTML encoded Link like <a href='http://example.com' class='external'><img src='iconf.gif' title='help text'>Description</a>
+     *
+     * @return string The complete HTML encoded Link like <a href='http://example.com' class='external'><img
+     *                src='iconf.gif' title='help text'>Description</a>
      * @throws UserReportException
      */
     public function renderLink($str) {
@@ -364,6 +366,7 @@ class Link {
      * Order $param. Parameter with Priotrity are hardcoded at the moment.
      *
      * @param array $param
+     *
      * @return array
      */
     private function paramPriority(array $param) {
@@ -386,7 +389,8 @@ class Link {
 
     /**
      * @param string $str
-     * @param array $tokenGiven
+     * @param array  $tokenGiven
+     *
      * @return array
      * @throws UserReportException
      */
@@ -478,42 +482,42 @@ class Link {
     private function initVars() {
 
         return [
-            NAME_MAIL => '',
-            NAME_URL => '',
-            NAME_PAGE => '',
-
-            NAME_TEXT => '',
-            NAME_ALT_TEXT => '',
-            NAME_IMAGE => '',
-            NAME_IMAGE_TITLE => '',
-            NAME_GLYPH => '',
-            NAME_GLYPH_TITLE => '',
-            NAME_QUESTION => '',
-            NAME_TARGET => '',
-            NAME_TOOL_TIP => '',
-            NAME_TOOL_TIP_JS => '',
-            NAME_URL_PARAM => '',
+            NAME_MAIL          => '',
+            NAME_URL           => '',
+            NAME_PAGE          => '',
+
+            NAME_TEXT          => '',
+            NAME_ALT_TEXT      => '',
+            NAME_IMAGE         => '',
+            NAME_IMAGE_TITLE   => '',
+            NAME_GLYPH         => '',
+            NAME_GLYPH_TITLE   => '',
+            NAME_QUESTION      => '',
+            NAME_TARGET        => '',
+            NAME_TOOL_TIP      => '',
+            NAME_TOOL_TIP_JS   => '',
+            NAME_URL_PARAM     => '',
             NAME_EXTRA_CONTENT_WRAP => '',
             NAME_DOWNLOAD_MODE => '',
             NAME_DOWNLOAD_ELEMENTS => array(),
 
-            NAME_RENDER => '0',
-            NAME_RIGHT => 'l',
-            NAME_SIP => '0',
-            NAME_ENCRYPTION => '0',
-            NAME_DELETE => '',
+            NAME_RENDER        => '0',
+            NAME_RIGHT         => 'l',
+            NAME_SIP           => '0',
+            NAME_ENCRYPTION    => '0',
+            NAME_DELETE        => '',
 
-            NAME_LINK_CLASS => '', // class name
+            NAME_LINK_CLASS    => '', // class name
             NAME_LINK_CLASS_DEFAULT => '', // Depending of 'as page' or 'as url'. Only used if class is not explizit set.
 
             NAME_ACTION_DELETE => '',
 
-            FINAL_HREF => '',
-            FINAL_CONTENT => '',
-            FINAL_SYMBOL => '',
-            FINAL_TOOL_TIP => '',
-            FINAL_CLASS => '',
-            FINAL_QUESTION => ''
+            FINAL_HREF         => '',
+            FINAL_CONTENT      => '',
+            FINAL_SYMBOL       => '',
+            FINAL_TOOL_TIP     => '',
+            FINAL_CLASS        => '',
+            FINAL_QUESTION     => '',
         ];
 
     }
@@ -523,6 +527,7 @@ class Link {
      *
      * @param string $key
      * @param string $value
+     *
      * @return string
      * @throws UserReportException
      */
@@ -571,6 +576,7 @@ class Link {
      *
      * @param $key
      * @param $value
+     *
      * @return mixed
      * @throws UserReportException
      */
@@ -602,6 +608,7 @@ class Link {
      * Check for double definition.
      *
      * @param array $tokenGiven
+     *
      * @throws UserReportException
      */
     private function checkParam(array $tokenGiven, array $vars) {
@@ -645,6 +652,7 @@ class Link {
      *
      * @param array $vars
      * @param array $tokenGiven
+     *
      * @return string
      * @throws UserReportException
      */
@@ -663,6 +671,7 @@ class Link {
 
     /**
      * @param array $vars
+     *
      * @return string
      * @throws UserFormException
      */
@@ -705,6 +714,7 @@ class Link {
      *
      * @param array $vars
      * @param array $tokenGiven
+     *
      * @return string
      * @throws CodeException
      * @throws UserReportException
@@ -762,6 +772,7 @@ class Link {
     /**
      * @param $tokenActionDelete
      * @param $nameUrlParam
+     *
      * @return string
      * @throws UserReportException
      */
@@ -798,6 +809,7 @@ class Link {
      * Return $vars[NAME_TOOL_TIP]. If $vars[NAME_TOOL_TIP] is empty, set $vars[NAME_GLYPH_TITLE] as tooltip.
      *
      * @param array $vars
+     *
      * @return mixed
      */
     private function doToolTip(array $vars) {
@@ -814,6 +826,7 @@ class Link {
      * Parse CSS Class Settings
      *
      * @param array $vars
+     *
      * @return    string
      */
     private function doCssClass(array $vars) {
@@ -847,6 +860,7 @@ class Link {
      * Create Image HTML Tag
      *
      * @param array $vars
+     *
      * @return string
      */
     private function doSymbol(array $vars) {
@@ -874,6 +888,7 @@ class Link {
      * Concat Text and/or Image and or Glyph. Depending of $vars[NAME_RIGHT_PICTURE_POSITION], swapp the position,
      *
      * @param array $vars
+     *
      * @return string
      */
     private function doContent(array $vars) {
@@ -905,6 +920,7 @@ class Link {
      * Return JS Code to place in '<a>' tag. Be carefull: function creates a uniqe 'id' tag.
      *
      * @param array $vars
+     *
      * @return string
      */
     private function doQuestion(array $vars) {
@@ -952,6 +968,7 @@ EOF;
      * - <a href="http://example.com" title=".." class="..">
      *
      * @param array $vars
+     *
      * @return string
      * @throws UserReportException
      */
@@ -967,14 +984,16 @@ EOF;
         $attributes .= $vars[FINAL_QUESTION];
 
         $anchor = '<a ' . $attributes . '>';
+
         return $anchor;
     }
 
     /**
      * Get mode from table $this->renderControl, depending on $modeRender, $modeUrl, $modeText
      *
-     * @param array $vars
+     * @param array  $vars
      * @param string $prefix
+     *
      * @return string
      * @throws UserReportException
      */
@@ -1021,6 +1040,7 @@ EOF;
      *
      * @param array $vars
      * @param bool|TRUE $href TRUE: create a '<a>',   false: just encrypt or show the email, no link.
+     *
      * @return string
      */
     private function encryptMailtoJS(array $vars, $href = true) {
@@ -1073,6 +1093,7 @@ EOF;
      *
      * @param $mailto
      * @param $delimiter
+     *
      * @return array
      */
     private function splitAndAddDelimter($mailto, $delimiter) {
@@ -1097,6 +1118,7 @@ EOF;
      *
      * @param $vars
      * @param $value
+     *
      * @return array
      */
     private function buildUrl($vars, $value) {
@@ -1110,6 +1132,7 @@ EOF;
      *
      * @param $vars
      * @param $value
+     *
      * @return array
      */
     private function buildMail($vars, $value) {
@@ -1123,6 +1146,7 @@ EOF;
      *
      * @param $vars
      * @param $value
+     *
      * @return array
      * @throws UserReportException
      */
@@ -1143,6 +1167,7 @@ EOF;
      *
      * @param $vars
      * @param $value
+     *
      * @return array
      * @throws UserReportException
      */
@@ -1171,6 +1196,7 @@ EOF;
      *
      * @param $vars
      * @param $value
+     *
      * @return array
      */
     private function buildPicture($vars, $value) {
@@ -1189,6 +1215,7 @@ EOF;
      *
      * @param $vars
      * @param $value
+     *
      * @return array
      */
     private function buildBullet($vars, $value) {
@@ -1212,6 +1239,7 @@ EOF;
      *
      * @param $vars
      * @param $value
+     *
      * @return array
      */
     private function buildCheck($vars, $value) {
@@ -1235,6 +1263,7 @@ EOF;
      * Called by $this->callTable
      *
      * @param $vars
+     *
      * @return array
      */
     private function buildDeleteIcon($vars) {
@@ -1251,6 +1280,7 @@ EOF;
      *
      * @param $vars
      * @param $value
+     *
      * @return array
      * @throws UserReportException
      */
@@ -1279,6 +1309,7 @@ EOF;
      * In case of missing parameter, throw an exception.
      *
      * @param $urlParam
+     *
      * @throws UserReportException in case parameter is missing.
      */
     private function checkDeleteParam($urlParam) {
@@ -1304,6 +1335,7 @@ EOF;
      *
      * @param $vars
      * @param $value
+     *
      * @return array
      */
     private function buildEdit($vars, $value) {
@@ -1320,6 +1352,7 @@ EOF;
      *
      * @param $vars
      * @param $value
+     *
      * @return array
      */
     private function buildHelp($vars, $value) {
@@ -1336,6 +1369,7 @@ EOF;
      *
      * @param $vars
      * @param $value
+     *
      * @return array
      */
     private function buildInfo($vars, $value) {
@@ -1352,6 +1386,7 @@ EOF;
      *
      * @param $vars
      * @param $value
+     *
      * @return array
      */
     private function buildNew($vars, $value) {
@@ -1368,6 +1403,7 @@ EOF;
      *
      * @param $vars
      * @param $value
+     *
      * @return array
      */
     private function buildShow($vars, $value) {
@@ -1384,6 +1420,7 @@ EOF;
      *
      * @param $vars
      * @param $value
+     *
      * @return array
      */
     private function buildGlyph($vars, $value) {
@@ -1400,6 +1437,7 @@ EOF;
      *
      * @param $vars
      * @param $value
+     *
      * @return array
      */
     private function buildFile($vars, $value) {
@@ -1419,6 +1457,7 @@ EOF;
      *
      * @param $vars
      * @param $value
+     *
      * @return array
      */
     private function buildToolTip($vars, $value) {
diff --git a/extension/qfq/qfq/report/Report.php b/extension/qfq/qfq/report/Report.php
index 40366e708daaab523bb11c2df7b590ecf1fa0f25..df7e8dc68bdf9cfc2a190eea29f4a2a87fa84451 100644
--- a/extension/qfq/qfq/report/Report.php
+++ b/extension/qfq/qfq/report/Report.php
@@ -73,7 +73,8 @@ class Report {
     private $pageDefaults = array();
 
     /**
-     * @var array - Emulate global variable: will be set much earlier in other functions. Will be shown in error messages.
+     * @var array - Emulate global variable: will be set much earlier in other functions. Will be shown in error
+     *      messages.
      */
     private $fr_error = array('uid' => '', 'pid' => '', 'row' => '', 'debug_level' => '0', 'full_level' => '');
 
@@ -84,9 +85,9 @@ class Report {
     /**
      * Report constructor.
      *
-     * @param array $t3data
+     * @param array    $t3data
      * @param Evaluate $eval
-     * @param bool $phpUnit
+     * @param bool     $phpUnit
      */
     public function __construct(array $t3data, Evaluate $eval, $phpUnit = false) {
 
@@ -134,7 +135,8 @@ class Report {
     }
 
     /**
-     * If a variable 'sqlLog' is given in STORE_TYPO3 (=Bodytext) make them relative to SYSTEM_PATH_EXT and copy it to STORE_SYSTEM
+     * If a variable 'sqlLog' is given in STORE_TYPO3 (=Bodytext) make them relative to SYSTEM_PATH_EXT and copy it to
+     * STORE_SYSTEM
      */
     private function checkUpdateSqlLog() {
 
@@ -187,6 +189,7 @@ class Report {
      * Example: 10.50.5.sql = select * from person
      *
      * @param    string $ttLine : line to split in level, command, content
+     *
      * @throws SyntaxReportException
      * @return    void
      */
@@ -196,15 +199,17 @@ class Report {
         $arr = explode("=", trim($ttLine), 2);
 
         // no elements or only one: do nothing
-        if (count($arr) < 2)
+        if (count($arr) < 2) {
             return;
+        }
 
         // 10.50.5.sql
         $key = strtolower(trim($arr[0]));
 
         // comment ?
-        if (empty($key) || $key[0] === "#")
+        if (empty($key) || $key[0] === "#") {
             return;
+        }
 
         // select ...
         $value = trim($arr[1]);
@@ -256,8 +261,9 @@ class Report {
         if ($frCmd === TOKEN_SQL) {
             $arr = explode('|', TOKEN_VALID_LIST);
             foreach ($arr as $key) {
-                if (!isset($this->frArray[$level . "." . $key]))
+                if (!isset($this->frArray[$level . "." . $key])) {
                     $this->frArray[$level . "." . $key] = '';
+                }
             }
         }
     }
@@ -265,7 +271,7 @@ class Report {
     /**
      * Sorts the associative array.
      *
-     * @param array $ary : The unsorted Level Array
+     * @param array  $ary    : The unsorted Level Array
      * @param string $clause : the sort argument 0 ASC, 1 ASC... according to the number of columns
      * @param bool|true $ascending
      */
@@ -357,7 +363,8 @@ class Report {
      *
      * @param int $cur_level Which level it will call [10] = level 1, [10.10] = level 2 ...
      * @param string $super_level_array The Value-Array of the indexarray [0=>10, 1=>50]
-     * @param int $counter The outer numeric Arraykey of indexarray
+     * @param int $counter   The outer numeric Arraykey of indexarray
+     *
      * @return string                       The content that is displayed on the website
      * @throws codeException
      * @throws SqlReportException
@@ -435,8 +442,9 @@ class Report {
             }
 
             // HEAD: If there is at least one record, do 'head'.
-            if ($rowTotal > 0)
+            if ($rowTotal > 0) {
                 $content .= $this->variables->doVariables($this->frArray[$full_level . "." . TOKEN_HEAD]);
+            }
 
             // Prepare row alteration
             $arrRbgd = explode("|", $this->frArray[$full_level . "." . TOKEN_RBGD]);
@@ -508,11 +516,12 @@ class Report {
      * 3) if none above take default
      * Set value on $full_level
      *
-     * @param    string $level_key - 'db' or 'debug'
+     * @param    string $level_key  - 'db' or 'debug'
      * @param    string $full_super_level - f.e.: 10.10.
      * @param    string $full_level - f.e.: 10.10.10.
-     * @param    string $cur_level - f.e.: 2
-     * @param    string $default - f.e.: 0
+     * @param    string $cur_level  - f.e.: 2
+     * @param    string $default    - f.e.: 0
+     *
      * @return   string  The calculated value.
      */
     private function getValueParentDefault($level_key, $full_super_level, $full_level, $cur_level, $default) {
@@ -534,10 +543,11 @@ class Report {
     /**
      * Steps through 'row' and collects all columns
      *
-     * @param array $row Recent row fetch from sql resultset.
-     * @param array $keys List of all columnnames
+     * @param array  $row      Recent row fetch from sql resultset.
+     * @param array  $keys     List of all columnnames
      * @param string $full_level Recent position to work on.
      * @param string $rowIndex Index of recent row in resultset.
+     *
      * @return string               Collected content of all printable columns
      * @throws SyntaxReportException
      */
@@ -562,6 +572,7 @@ class Report {
                 $fsep = $this->frArray[$full_level . "." . TOKEN_FSEP];
             }
         }
+
         return ($content);
     }
 
@@ -573,6 +584,7 @@ class Report {
      * @param string $columnValue
      * @param string $full_level
      * @param string $rowIndex
+     *
      * @return string rendered column
      * @throws SyntaxReportException
      */
@@ -705,7 +717,9 @@ class Report {
 
                 $t1 = explode("@", $mailarr[0], 2);
                 $content .= "<script language=javascript><!--" . chr(10);
-                if (empty($mailarr[1])) $mailarr[1] = $mailarr[0];
+                if (empty($mailarr[1])) {
+                    $mailarr[1] = $mailarr[0];
+                }
 
                 $content .= 'var contact = "' . substr($mailarr[1], 0, 2) . '"' . chr(10);
                 $content .= 'var contact1 = "' . substr($mailarr[1], 2) . '"' . chr(10);
@@ -817,6 +831,7 @@ class Report {
      * RC: if RC==0 Returns Output, else 'RC - Output'
      *
      * @param    string $cmd : contains the Comand
+     *
      * @return   string  The content that is displayed on the website
      */
     private function myExec($cmd) {
@@ -824,8 +839,9 @@ class Report {
         exec($cmd, $arr, $rc);
 
         $output = implode('<BR>', $arr);
-        if ($rc != 0)
+        if ($rc != 0) {
             $output = $rc . " - " . $output;
+        }
 
         return ($output);
     }
@@ -835,6 +851,7 @@ class Report {
      *
      * @param    string $content : The PlugIn content
      * @param    array $conf : The PlugIn configuration
+     *
      * @return    string The content that is displayed on the website
      */
     //Checkt ob der Beginn von Array2 gleich ist wie Array1
@@ -845,6 +862,7 @@ class Report {
      *
      * @param    string $columnName
      * @param    string $columnValue
+     *
      * @return string rendered link
      *
      * $columnValue:
@@ -933,6 +951,7 @@ class Report {
      * <exportFilename> | <text> | <1: urlparam|file> | <2: urlparam|file> | ... | <n: urlparam|file>
      *
      * @param string $columnValue
+     *
      * @return string rendered link
      * @throws SyntaxReportException
      */
@@ -1071,14 +1090,21 @@ class Report {
 
     /**
      * Renders _download: extract token and determine if any default value has to be applied
-     * [d:<exportFilename][U:<params>][u:<url>][f:file][t:<text>][a:<message>]|[o:<tooltip>]|[c:<class>]|[r:<render mode>]
+     * [d:<exportFilename][U:<params>][u:<url>][f:file][t:<text>][a:<message>]|[o:<tooltip>]|[c:<class>]|[r:<render
+     * mode>]
      *
      * @param string $columnName
      * @param string $columnValue
+     *
      * @return string rendered link
      * @throws CodeException
      */
     private function doDownload($columnName, $columnValue) {
+
+        if ($columnValue == '') {
+            return '';
+        }
+
         $columNameToMode = [COLUMN_PDF => DOWNLOAD_MODE_PDF, COLUMN_FILE => DOWNLOAD_MODE_FILE, COLUMN_ZIP => DOWNLOAD_MODE_ZIP];
 
         $param = explode('|', $columnValue);
@@ -1107,6 +1133,12 @@ class Report {
                     $defaultMode = '';
                     break;
 
+                case TOKEN_RENDER:
+                    if (isset($key[2]) && $key[2] == '5') {
+                        return '';
+                    }
+                    break;
+
                 default:
                     break;
             }
@@ -1133,11 +1165,13 @@ class Report {
      * Generate SortArgument
      *
      * @param $variable
+     *
      * @return string
      */
     private function getResultArrayIndex($variable) {
 
         $variable = substr($variable, 1, strlen($variable));
+
         return "[" . preg_replace_callback("/[a-z]/", "replaceToIndex", $variable) . "][" . preg_replace_callback("/[^a-z]/", "replaceToIndex", $variable) . "]";
 
     }
@@ -1145,6 +1179,7 @@ class Report {
     /**
      * @param $arr1
      * @param $arr2
+     *
      * @return bool
      */
     private function compareArraystart($arr1, $arr2) {
@@ -1154,12 +1189,14 @@ class Report {
                 return false;
             }
         }
+
         return true;
     }
 
     /**
      * @param $arr1
      * @param $arr2
+     *
      * @return bool
      */
     private function compareArraylength($arr1, $arr2) {
@@ -1167,6 +1204,7 @@ class Report {
         if (count($arr1) + 1 == count($arr2)) {
             return true;
         }
+
         return false;
     }
 }
diff --git a/extension/qfq/qfq/report/Sendmail.php b/extension/qfq/qfq/report/Sendmail.php
index dd6aa30e68cb6de9bf91f08f161aac2efa7305d3..6d434ea69cc77af954fa54361adb2b596a1856b6 100644
--- a/extension/qfq/qfq/report/Sendmail.php
+++ b/extension/qfq/qfq/report/Sendmail.php
@@ -29,6 +29,7 @@ class Sendmail {
      *    SENDMAIL_IDX_X_ID                 optional: integer
      *
      * @param $mailarr
+     *
      * @throws UserFormException
      */
     public function __construct(array $mailarr) {
@@ -69,6 +70,7 @@ class Sendmail {
 
     /**
      * @param array $mailarr
+     *
      * @return string
      */
     private function buildHeader(array $mailarr) {
@@ -100,7 +102,8 @@ class Sendmail {
      * Creates a new MailLog Record based on $mailArr / $header.
      *
      * @param array $mailarr
-     * @param $header
+     * @param       $header
+     *
      * @throws CodeException
      * @throws DbException
      */
diff --git a/extension/qfq/qfq/report/Variables.php b/extension/qfq/qfq/report/Variables.php
index c4ee1e95ce3ceb410b08f7d6c725ffc48438a4a7..d382759bf36b8d4703b122c2c1f879dccaf58828 100644
--- a/extension/qfq/qfq/report/Variables.php
+++ b/extension/qfq/qfq/report/Variables.php
@@ -55,11 +55,13 @@ class Variables {
      * Matches on the variables {{10.20.name}} and substitutes them with the values
      *
      * @param string $text
+     *
      * @return mixed
      */
     public function doVariables($text) {
 //        $str = preg_replace_callback("/(~([a-zA-Z0-9._])*)/", array($this, 'replaceVariables'), $text);
         $str = preg_replace_callback("/{{(([a-zA-Z0-9.:_])*)}}/", array($this, 'replaceVariables'), $text);
+
         return $str;
     }
 
@@ -68,6 +70,7 @@ class Variables {
      * Replaces the variablenames whith the value from the resultArray
      *
      * @param $matches
+     *
      * @return string The content that is displayed on the website
      * @internal param string $content : The PlugIn content
      * @internal param array $conf : The PlugIn configuration
@@ -103,6 +106,7 @@ class Variables {
      * Collect Global Variables
      *
      * @param    void
+     *
      * @return    array with global variables which might be replaced
      */
     public function collectGlobalVariables() {
@@ -134,11 +138,12 @@ class Variables {
         }
 
         $arr["be_user_uid"] = (isset($GLOBALS['BE_USER'])) ? $GLOBALS['BE_USER']->user["uid"] : '-';
-        $arr["page_id"] = $GLOBALS["TSFE"]->id;
-        $arr["page_type"] = $GLOBALS["TSFE"]->type;
-        $arr["page_language_uid"] = $GLOBALS["TSFE"]->sys_language_uid;
         $arr["ttcontent_uid"] = $this->tt_content_uid;
-
+        if (isset($GLOBALS["TSFE"])) {
+            $arr["page_id"] = $GLOBALS["TSFE"]->id;
+            $arr["page_type"] = $GLOBALS["TSFE"]->type;
+            $arr["page_language_uid"] = $GLOBALS["TSFE"]->sys_language_uid;
+        }
         // Add all variables from ext_localconf
         //		database aliases can be used in form sql queries (e.g. select * from "{{global.t3_name}}".fe_users...)
         //		localconf can be used to configure an application
@@ -164,8 +169,8 @@ class Variables {
     }
 
     /**
-     * @param $arr
-     * @param $return
+     * @param        $arr
+     * @param        $return
      * @param string $keyPath
      */
     public function linearizeArray($arr, &$return, $keyPath = "") {
diff --git a/extension/qfq/qfq/store/Config.php b/extension/qfq/qfq/store/Config.php
index 36a469aaaeef516afa1f9a47514a5a68ee949b96..37619141efc37e19814d7a65bf9b144dca5dca9b 100644
--- a/extension/qfq/qfq/store/Config.php
+++ b/extension/qfq/qfq/store/Config.php
@@ -19,6 +19,7 @@ class Config {
      * Read config.qfq.ini.
      *
      * @param string $fileConfigIni
+     *
      * @return array
      * @throws UserFormException
      */
@@ -134,6 +135,7 @@ class Config {
 
     /**
      * @param array $config
+     *
      * @return array
      */
     private static function setDefaults(array $config) {
@@ -178,6 +180,8 @@ class Config {
         Support::setIfNotSet($config, SYSTEM_ESCAPE_TYPE_DEFAULT, TOKEN_ESCAPE_SINGLE_TICK);
         Support::setIfNotSet($config, SYSTEM_GFX_EXTRA_BUTTON_INFO_INLINE, '<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>');
         Support::setIfNotSet($config, SYSTEM_GFX_EXTRA_BUTTON_INFO_BELOW, '<span class="glyphicon glyphicon-info-sign text-info" aria-hidden="true"></span>');
+        Support::setIfNotSet($config, SYSTEM_EXTRA_BUTTON_INFO_CLASS, '');
+
 
         Support::setIfNotSet($config, SYSTEM_DB_UPDATE, SYSTEM_DB_UPDATE_AUTO);
         Support::setIfNotSet($config, SYSTEM_RECORD_LOCK_TIMEOUT_SECONDS, SYSTEM_RECORD_LOCK_TIMEOUT_SECONDS_DEFAULT);
@@ -191,9 +195,11 @@ class Config {
 
     /**
      * Rename Elements defined in config.qfq.ini to more appropriate in user interaction.
-     * E.g.: in config.qfq.ini everything is in upper case and word space is '_'. In Form.parameter it's lowercase and camel hook.
+     * E.g.: in config.qfq.ini everything is in upper case and word space is '_'. In Form.parameter it's lowercase and
+     * camel hook.
      *
      * @param array $config
+     *
      * @return array
      */
     private static function renameConfigElements(array $config) {
@@ -234,6 +240,8 @@ class Config {
             [SYSTEM_NEW_BUTTON_CLASS, F_NEW_BUTTON_CLASS],
             [SYSTEM_NEW_BUTTON_GLYPH_ICON, F_NEW_BUTTON_GLYPH_ICON],
 
+            [SYSTEM_EXTRA_BUTTON_INFO_CLASS, FE_INPUT_EXTRA_BUTTON_INFO_CLASS],
+
         ];
 
         foreach ($setting as $row) {
diff --git a/extension/qfq/qfq/store/FillStoreForm.php b/extension/qfq/qfq/store/FillStoreForm.php
index 3a36cb100a0d8aebf04854a6ed25c6019704eac1..e935a4bbb1f65981d047e618d2dd51d98c539b12 100644
--- a/extension/qfq/qfq/store/FillStoreForm.php
+++ b/extension/qfq/qfq/store/FillStoreForm.php
@@ -57,6 +57,7 @@ class FillStoreForm {
      * @throws UserFormException
      */
     private function loadFormElementsBasedOnSIP() {
+
         $formName = $this->store->getVar(SIP_FORM, STORE_SIP);
 
         // Preparation for Log, Debug
@@ -80,6 +81,7 @@ class FillStoreForm {
      *
      * @param array $feSpecTemplateGroup
      * @param array $feSpecNative
+     *
      * @return array
      */
     private function expandTemplateGroupFormElement(array $feSpecTemplateGroup, array $feSpecNative) {
@@ -136,6 +138,7 @@ class FillStoreForm {
         $newValues = array();
 
         $clientValues = $this->store->getStore(STORE_CLIENT);
+        $formModeGlobal = $this->store->getVar(F_MODE_GLOBAL, STORE_SIP . STORE_EMPTY);
 
         // If called through 'api/...': get STORE_TYPO3 via SIP parameter.
         if (isset($clientValues[CLIENT_TYPO3VARS])) {
@@ -183,7 +186,7 @@ class FillStoreForm {
             $clientFieldName = HelperFormElement::buildFormElementName($formElement, $fakeRecordId);
 
             // Some Defaults
-            $formElement = Support::setFeDefaults($formElement);
+            $formElement = Support::setFeDefaults($formElement, [F_MODE => $formModeGlobal]);
 
             if ($formElement[FE_TYPE] === FE_TYPE_EXTRA) {
                 // Extra elements will be transferred by SIP
@@ -198,7 +201,7 @@ class FillStoreForm {
             // Checkbox Multi: collect values
             if ($formElement[FE_TYPE] === 'checkbox') {
                 $val = $this->collectMultiValues($clientFieldName, $clientValues);
-                if($val !== false) {
+                if ($val !== false) {
                     $clientValues[$clientFieldName] = $val;
                 }
             }
@@ -213,15 +216,21 @@ class FillStoreForm {
             if (isset($clientValues[$clientFieldName])) {
                 if ($formElement[FE_DYNAMIC_UPDATE] === 'yes' || $formElement[FE_MODE] === FE_MODE_REQUIRED || $formElement[FE_MODE] === FE_MODE_SHOW) {
                     switch ($formElement[FE_TYPE]) {
-                        case 'date':
-                        case 'datetime':
-                        case 'time':
+                        case FE_TYPE_DATE:
+                        case FE_TYPE_DATETIME:
+                        case FE_TYPE_TIME:
                             if ($clientValues[$clientFieldName] !== '') // do not check empty values
                                 $newValues[$formElement[FE_NAME]] = $this->doDateTime($formElement, $clientValues[$clientFieldName]);
                             break;
                         default:
                             $val = $clientValues[$clientFieldName];
-                            // Check only if their is something
+
+                            if ($formElement[FE_TYPE] == FE_TYPE_EDITOR) {
+                                // Tiny MCE always wrap a '<p>' around the content. Remove it before saving.
+                                $val = Support::unWrapTag('<p>', $val);
+                            }
+
+                            // Check only if their is something.
                             if ($val !== '') {
                                 $val = Sanitize::sanitize($val, $formElement[FE_CHECK_TYPE], $formElement[FE_CHECK_PATTERN], SANITIZE_EXCEPTION);
                                 if ($formElement[FE_ENCODE] === FE_ENCODE_SPECIALCHAR) {
@@ -239,11 +248,13 @@ class FillStoreForm {
     }
 
     /**
-     * Steps through all $clientValues (POST vars) and collect all with the name _?_${clientFieldName} in a comma seperated string (MYSQL ENUM type).
-     * If there is no element '_h_${clientFieldName}', than there are no multi values - return the already given `$clientValues[$clientFieldName]`.
+     * Steps through all $clientValues (POST vars) and collect all with the name _?_${clientFieldName} in a comma
+     * seperated string (MYSQL ENUM type). If there is no element '_h_${clientFieldName}', than there are no multi
+     * values - return the already given `$clientValues[$clientFieldName]`.
      *
-     * @param $clientFieldName
+     * @param       $clientFieldName
      * @param array $clientValues
+     *
      * @return string
      */
     private function collectMultiValues($clientFieldName, array $clientValues) {
@@ -252,7 +263,7 @@ class FillStoreForm {
 
         // For templateGroups: all expanded FormElements will be tried to collect - this fails for not submitted fields.
         // Therefore skip not existing clientvalues.
-        if(!isset($clientValues[$checkboxKey])) {
+        if (!isset($clientValues[$checkboxKey])) {
             return false;
         }
 
@@ -280,8 +291,9 @@ class FillStoreForm {
     /**
      * Check  $value as date/datime/time value and convert it to FORMAT_DATE_INTERNATIONAL.
      *
-     * @param array $formElement - if not set, set $formElement[FE_DATE_FORMAT]
-     * @param string $value - date/datetime/time value in format FORMAT_DATE_INTERNATIONAL or FORMAT_DATE_GERMAN
+     * @param array  $formElement - if not set, set $formElement[FE_DATE_FORMAT]
+     * @param string $value       - date/datetime/time value in format FORMAT_DATE_INTERNATIONAL or FORMAT_DATE_GERMAN
+     *
      * @return string - checked datetime string
      * @throws UserFormException
      */
diff --git a/extension/qfq/qfq/store/Session.php b/extension/qfq/qfq/store/Session.php
index 9efd992014cbddec89b27c244152837647c99634..fc5bb8ec01e6ce3094b048d996d2f4a5d87d1350 100644
--- a/extension/qfq/qfq/store/Session.php
+++ b/extension/qfq/qfq/store/Session.php
@@ -19,6 +19,7 @@ class Session {
 
     /**
      * @param bool|false $phpUnit
+     *
      * @throws CodeException
      */
     private function __construct($phpUnit = false) {
@@ -87,11 +88,11 @@ class Session {
     /**
      * Check if the feUserUid is stored in the session (even with 'false' which indicates not logged in user).
      *   If not, clear the session and save the feUser, feUserUid in the session.
-     * Check if the recent logged in feUserUid is equal to the one stored in session: If different, invalidate (clear) the session and
-     *   save the new feUser, feUserUid in the session.
-     * If isset($GLOBALS["TSFE"]), than we're in a T3 environment, else we are called as API classes and need to fake
-     *   feUser / feUserUid from previous stored session.
-     * It's neccessary to have feUser / feUserUid available in API classes, due to dynamic update which might reload data based on feUser / feUserUid.
+     * Check if the recent logged in feUserUid is equal to the one stored in session: If different, invalidate (clear)
+     * the session and save the new feUser, feUserUid in the session. If isset($GLOBALS["TSFE"]), than we're in a T3
+     * environment, else we are called as API classes and need to fake feUser / feUserUid from previous stored session.
+     * It's neccessary to have feUser / feUserUid available in API classes, due to dynamic update which might reload
+     * data based on feUser / feUserUid.
      */
     private static function checkFeUserUid() {
 
@@ -128,6 +129,7 @@ class Session {
      * Return 'false' if not found.
      *
      * @param $key
+     *
      * @return bool
      */
     public static function get($key) {
@@ -204,6 +206,7 @@ class Session {
 
     /**
      * @param bool|false $phpUnit
+     *
      * @return Session class
      */
     public static function getInstance($phpUnit = false) {
diff --git a/extension/qfq/qfq/store/Sip.php b/extension/qfq/qfq/store/Sip.php
index 42cd683f616edccf78189e020589678a881c9c97..779afc68fbac37abdfcc0ce12deb25c4bb87acb5 100644
--- a/extension/qfq/qfq/store/Sip.php
+++ b/extension/qfq/qfq/store/Sip.php
@@ -8,11 +8,6 @@
 
 namespace qfq;
 
-use qfq\CodeException;
-use qfq\UserFormException;
-use qfq\OnArray;
-use qfq\KeyValueStringParser;
-
 require_once(__DIR__ . '/../helper/OnArray.php');
 require_once(__DIR__ . '/../Constants.php');
 require_once(__DIR__ . '/../store/Config.php');
@@ -28,23 +23,28 @@ class Sip {
 
     private $phpUnit = false;
     private $staticUniqId = false;
+    private $getParamL = '';
+    private $getParamType = '';
 
     /**
      * @param bool|false $phpUnit
      */
-    function __construct($phpUnit = false) {
+    public function __construct($phpUnit = false) {
 
         $this->phpUnit = $phpUnit;
     }
 
+
     /**
      * @param string $queryString Possible variants:
-     *   * http://www.math.uzh.ch/index.php?a=1&s=4b3403665fea6&r=45&type=99&id=person
-     *   * index.php?a=1&s=4b3403665fea6&r=45&type=99&id=person
-     *   * ?a=1&s=4b3403665fea6&r=45&type=99&id=person
-     *   * a=1&s=4b3403665fea6&r=45&type=99&id=person
+     *                            * http://www.math.uzh.ch/index.php?a=1&s=4b3403665fea6&r=45&type=99&id=person#pill12
+     *                            * index.php?a=1&s=4b3403665fea6&r=45&type=99&id=person#pill12
+     *                            * ?a=1&s=4b3403665fea6&r=45&type=99&id=person#pill12
+     *                            * a=1&s=4b3403665fea6&r=45&type=99&id=person#pill12
+     *                            * a=1&s=4b3403665fea6&r=45&type=99&id=person#pill12
+     *
+     * @param string $mode        Possible values: RETURN_URL|RETURN_SIP
      *
-     * @param string $mode Possible values: RETURN_URL|RETURN_SIP
      * @return string/array
      *  * mode=RETURN_URL: return complete URL
      *  * mode=RETURN_SIP: returns only the sip
@@ -66,8 +66,11 @@ class Sip {
         }
 
         // Split parameter between Script, Client and SIP
-        $script = $this->splitParamClientSip($paramArray, $clientArray, $sipArray);
-
+        $anchor = '';
+        $script = $this->splitParamClientSip($paramArray, $clientArray, $sipArray, $anchor);
+        if ($anchor != '') {
+            $anchor = '#' . $anchor;
+        }
         // Generate keyname for $_SESSION[]
         $sipParamString = $this->buildParamStringFromArray($sipArray);
 
@@ -88,7 +91,7 @@ class Sip {
             $script = $phpScriptName . $script;
         }
 
-        $clientArray['_url'] = $script . OnArray::toString($clientArray);
+        $clientArray['_url'] = $script . OnArray::toString($clientArray) . $anchor;
 
         switch ($mode) {
             case RETURN_URL:
@@ -108,17 +111,22 @@ class Sip {
     }
 
     /**
-     * Splits the $paramArray in &$clientArray and &$sipArray. $sipArray contains all key/values pairs wich are not belong to Typo3.
+     * Splits the $paramArray in &$clientArray and &$sipArray. $sipArray contains all key/values pairs which do not
+     * belong to Typo3.
+     *
+     * @param array  $paramArray
+     * @param array  $clientArray
+     * @param array  $sipArray
+     *
+     * @param string $anchor
      *
-     * @param array $paramArray
-     * @param array $clientArray
-     * @param array $sipArray
      * @return string
-     * @throws \qfq\CodeException
+     * @throws CodeException
      */
-    private function splitParamClientSip(array $paramArray, array &$clientArray, array &$sipArray) {
+    private function splitParamClientSip(array $paramArray, array &$clientArray, array &$sipArray, &$anchor) {
 
         $script = '';
+        $anchor = '';
 
         // Possible variants:
         //   http://www.math.uzh.ch/index.php?a=1&s=4b3403665fea6&r=45&type=99&id=person
@@ -135,6 +143,13 @@ class Sip {
                 $script = $this->splitAndFix($key, $value);
             }
 
+            //Check for anker in Parameter
+            $anchorArray = explode('#', $value, 2);
+            if (!empty($anchorArray[1])) {
+                $value = $anchorArray[0];
+                $anchor = $anchorArray[1];
+            }
+
             // copy every parameter either to $clientArray or to $sipArray
             switch ($key) {
                 //special T3 parameter.
@@ -157,6 +172,14 @@ class Sip {
             }
         }
 
+        if (empty($clientArray[SIP_EXCLUDE_L]) && isset($_GET[CLIENT_PAGE_LANGUAGE]) != '' && ctype_digit($_GET[CLIENT_PAGE_LANGUAGE])) {
+            $clientArray[CLIENT_PAGE_LANGUAGE] = $_GET[CLIENT_PAGE_LANGUAGE];
+        }
+
+        if (empty($clientArray[SIP_EXCLUDE_TYPE]) && isset($_GET[CLIENT_PAGE_TYPE]) != '' && ctype_digit($_GET[CLIENT_PAGE_TYPE])) {
+            $clientArray[SIP_EXCLUDE_TYPE] = $_GET[CLIENT_PAGE_TYPE];
+        }
+
         return $script;
     }
 
@@ -165,6 +188,7 @@ class Sip {
      *
      * @param $key
      * @param $value
+     *
      * @return string Part upto first '?',
      */
     private function splitAndFix(&$key, &$value) {
@@ -189,10 +213,12 @@ class Sip {
     }
 
     /**
-     * Takes the values form an array and creates a urlparamstring. Skip values which should not passed to the urlparamstring.
+     * Takes the values form an array and creates a urlparamstring. Skip values which should not passed to the
+     * urlparamstring.
      * - SIP_TARGET_URL is necessary for 'delete' links (via 'report') - may be unecessary in other situations.
      *
      * @param array $sipArray
+     *
      * @return string
      */
     private function buildParamStringFromArray(array $sipArray) {
@@ -222,6 +248,7 @@ class Sip {
      * Returns a new uniqid (unique per session), which will be used as a SIP identifier.
      *
      * @param bool|false $staticUniqId
+     *
      * @return bool|string
      */
     public function sipUniqId($staticUniqId = false) {
@@ -230,6 +257,7 @@ class Sip {
             if ($staticUniqId !== false) {
                 $this->staticUniqId = $staticUniqId;
             }
+
             return $this->staticUniqId;
         }
 
@@ -237,7 +265,7 @@ class Sip {
 
         // It seems there is a chance that uniqid() is not unique: http://php.net/manual/en/function.uniqid.php
         // Check if the newly created uniqid() is unique for the current user (sufficient).
-        while(Session::get($sip)!==false) {
+        while (Session::get($sip) !== false) {
             $sip = uniqid();
         }
 
@@ -267,6 +295,7 @@ class Sip {
      * Retrieve Params stored in $_SESSION[$s]
      *
      * @param $s
+     *
      * @return array Parameter Array
      * @throws UserFormException
      * @throws \qfq\UserFormException
@@ -298,6 +327,7 @@ class Sip {
      * If $vars is a string, than this is the SIP - retrieve parameter from SIP and process those.
      *
      * @param string|array $vars
+     *
      * @return string
      * @throws \qfq\UserFormException
      */
@@ -322,6 +352,7 @@ class Sip {
      * Returns the sip for the given querystring. The querystring has to be sorted.
      *
      * @param $queryString
+     *
      * @return mixed
      */
     public function getSipFromQueryString($queryString) {
@@ -332,6 +363,7 @@ class Sip {
      * Returns the querystring for the given $sip
      *
      * @param $sip
+     *
      * @return bool
      */
     public function getQueryStringFromSip($sip) {
diff --git a/extension/qfq/qfq/store/Store.php b/extension/qfq/qfq/store/Store.php
index 1e42e07150b8d6f2a6cfbf6a97940801344a77b4..991e7ae222a36eeb7372b5e5a19057346745b823 100644
--- a/extension/qfq/qfq/store/Store.php
+++ b/extension/qfq/qfq/store/Store.php
@@ -8,9 +8,6 @@
 
 namespace qfq;
 
-use qfq\CodeException;
-use qfq\keyValueStringParser;
-use qfq\OnArray;
 use qfq;
 
 require_once(__DIR__ . '/../../qfq/helper/KeyValueStringParser.php');
@@ -84,6 +81,7 @@ class Store {
     /**
      * @param string $bodytext
      * @param string $fileConfigIni
+     *
      * @throws UserFormException
      * @throws \qfq\CodeException
      */
@@ -104,31 +102,31 @@ class Store {
 //            TYPO3_FE_USER_UID => SANITIZE_ALLOW_DIGIT,
 //            TYPO3_FE_USER_GROUP => SANITIZE_ALLOW_ALNUMX,
 
-            CLIENT_SIP => SANITIZE_ALLOW_ALNUMX,
-            CLIENT_TYPO3VARS => SANITIZE_ALLOW_ALNUMX,
-            CLIENT_RECORD_ID => SANITIZE_ALLOW_DIGIT,
-            CLIENT_KEY_SEM_ID => SANITIZE_ALLOW_DIGIT,
+            CLIENT_SIP           => SANITIZE_ALLOW_ALNUMX,
+            CLIENT_TYPO3VARS     => SANITIZE_ALLOW_ALNUMX,
+            CLIENT_RECORD_ID     => SANITIZE_ALLOW_DIGIT,
+            CLIENT_KEY_SEM_ID    => SANITIZE_ALLOW_DIGIT,
             CLIENT_KEY_SEM_ID_USER => SANITIZE_ALLOW_DIGIT,
-            CLIENT_PAGE_ID => SANITIZE_ALLOW_DIGIT,
-            CLIENT_PAGE_TYPE => SANITIZE_ALLOW_DIGIT,
+            CLIENT_PAGE_ID       => SANITIZE_ALLOW_DIGIT,
+            CLIENT_PAGE_TYPE     => SANITIZE_ALLOW_DIGIT,
             CLIENT_PAGE_LANGUAGE => SANITIZE_ALLOW_DIGIT,
-            CLIENT_FORM => SANITIZE_ALLOW_ALNUMX,
+            CLIENT_FORM          => SANITIZE_ALLOW_ALNUMX,
 
             // Part of $_SERVER. Missing vars must be requested individual with the needed sanitize class.
-            CLIENT_SCRIPT_URL => SANITIZE_ALLOW_ALNUMX,
-            CLIENT_SCRIPT_URI => SANITIZE_ALLOW_ALNUMX,
-            CLIENT_HTTP_HOST => SANITIZE_ALLOW_ALNUMX,
+            CLIENT_SCRIPT_URL    => SANITIZE_ALLOW_ALNUMX,
+            CLIENT_SCRIPT_URI    => SANITIZE_ALLOW_ALNUMX,
+            CLIENT_HTTP_HOST     => SANITIZE_ALLOW_ALNUMX,
             CLIENT_HTTP_USER_AGENT => SANITIZE_ALLOW_ALNUMX,
-            CLIENT_SERVER_NAME => SANITIZE_ALLOW_ALNUMX,
+            CLIENT_SERVER_NAME   => SANITIZE_ALLOW_ALNUMX,
             CLIENT_SERVER_ADDRESS => SANITIZE_ALLOW_ALNUMX,
-            CLIENT_SERVER_PORT => SANITIZE_ALLOW_DIGIT,
+            CLIENT_SERVER_PORT   => SANITIZE_ALLOW_DIGIT,
             CLIENT_REMOTE_ADDRESS => SANITIZE_ALLOW_ALNUMX,
             CLIENT_REQUEST_SCHEME => SANITIZE_ALLOW_ALNUMX,
             CLIENT_SCRIPT_FILENAME => SANITIZE_ALLOW_ALNUMX,
-            CLIENT_QUERY_STRING => SANITIZE_ALLOW_ALL,
-            CLIENT_REQUEST_URI => SANITIZE_ALLOW_ALL,
-            CLIENT_SCRIPT_NAME => SANITIZE_ALLOW_ALNUMX,
-            CLIENT_PHP_SELF => SANITIZE_ALLOW_ALNUMX,
+            CLIENT_QUERY_STRING  => SANITIZE_ALLOW_ALL,
+            CLIENT_REQUEST_URI   => SANITIZE_ALLOW_ALL,
+            CLIENT_SCRIPT_NAME   => SANITIZE_ALLOW_ALNUMX,
+            CLIENT_PHP_SELF      => SANITIZE_ALLOW_ALNUMX,
 //            CLIENT_UPLOAD_FILENAME => SANITIZE_ALLOW_ALLBUT,
 
 //            SYSTEM_DBUSER => SANITIZE_ALLOW_ALNUMX,
@@ -152,22 +150,22 @@ class Store {
         ];
 
         self::$sanitizeStore = [
-            STORE_FORM => true,
-            STORE_SIP => false,
-            STORE_RECORD => false,
-            STORE_BEFORE => false,
-            STORE_PARENT_RECORD => false,
-            STORE_TABLE_DEFAULT => false,
-            STORE_TABLE_COLUMN_TYPES => false,
-            STORE_CLIENT => true,
-            STORE_TYPO3 => false,
-            STORE_VAR => false,
-            STORE_ZERO => false,
-            STORE_EMPTY => false,
-            STORE_SYSTEM => false,
-            STORE_EXTRA => false,
-            STORE_LDAP => false,
-            STORE_ADDITIONAL_FORM_ELEMENTS => false
+            STORE_FORM                     => true,
+            STORE_SIP                      => false,
+            STORE_RECORD                   => false,
+            STORE_BEFORE                   => false,
+            STORE_PARENT_RECORD            => false,
+            STORE_TABLE_DEFAULT            => false,
+            STORE_TABLE_COLUMN_TYPES       => false,
+            STORE_CLIENT                   => true,
+            STORE_TYPO3                    => false,
+            STORE_VAR                      => false,
+            STORE_ZERO                     => false,
+            STORE_EMPTY                    => false,
+            STORE_SYSTEM                   => false,
+            STORE_EXTRA                    => false,
+            STORE_LDAP                     => false,
+            STORE_ADDITIONAL_FORM_ELEMENTS => false,
         ];
 
         self::fillStoreSystem($fileConfigIni);
@@ -199,7 +197,9 @@ class Store {
 
     /**
      * QFQ might be called via Typo3 (index.php) or directly via AJAX (directory: api). The
+     *
      * @param array $config
+     *
      * @return array
      */
     private static function doSystemPath(array $config) {
@@ -235,6 +235,7 @@ class Store {
      * Depending on some configuration value, update corresponding values.
      *
      * @param array $config
+     *
      * @return array
      */
     private static function adjustConfig(array $config) {
@@ -251,6 +252,7 @@ class Store {
 
     /**
      * @param string $value
+     *
      * @return string
      */
     private static function adjustConfigShowDebugInfo($value, $flag) {
@@ -279,6 +281,7 @@ class Store {
      * Iterate over all Parameter which have to exist in the config. Throw an array if any is missing.
      *
      * @param array $config
+     *
      * @throws UserFormException
      */
     private static function checkMandatoryParameter(array $config) {
@@ -294,9 +297,10 @@ class Store {
     /**
      * Set or overwrite a complete store.
      *
-     * @param array $dataArray
-     * @param $store
+     * @param array      $dataArray
+     * @param            $store
      * @param bool|false $flagOverwrite
+     *
      * @throws UserFormException
      * @throws \qfq\CodeException
      */
@@ -318,9 +322,11 @@ class Store {
 
     /**
      * Copy the BodyText as well as some T3 specific vars to STORE_TYPO3.
-     * Attention: if called through API, there is no T3 environment. The only values which are available are fe_user and fe_user_uid.
+     * Attention: if called through API, there is no T3 environment. The only values which are available are fe_user
+     * and fe_user_uid.
      *
      * @param $bodytext
+     *
      * @throws CodeException
      */
     private static function fillStoreTypo3($bodytext) {
@@ -384,9 +390,11 @@ class Store {
      * During cycling: fill cache with requestet value and sanitize raw value.
      *
      * @param string $key
-     * @param string $useStores f.e.: 'FSRD'
+     * @param string $useStores    f.e.: 'FSRD'
      * @param string $sanitizeClass
-     * @param string $foundInStore Returns the name of the store where $key has been found. If $key is not found, return ''.
+     * @param string $foundInStore Returns the name of the store where $key has been found. If $key is not found,
+     *                             return ''.
+     *
      * @return string a) if found: value, b) false
      * @throws \qfq\CodeException
      */
@@ -440,15 +448,18 @@ class Store {
                     // We do not have any pattern or min|max values at this point. For those who be affected, they already checked earlier. So set 'no check'
                     $sanitizeClass = SANITIZE_ALLOW_ALL;
                 }
+
                 return \qfq\Sanitize::sanitize($rawVal, $sanitizeClass, '', SANITIZE_EMPTY_STRING);
             } else {
                 if ($store == STORE_SIP && (substr($key, 0, $len) == SIP_PREFIX_BASE64)) {
                     $rawVal = base64_decode($rawVal);
                 }
+
                 return $rawVal;
             }
         }
         $foundInStore = '';
+
         return false;
     }
 
@@ -476,9 +487,10 @@ class Store {
     /**
      * Returns a pointer to this Class.
      *
-     * @param string $bodytext
+     * @param string     $bodytext
      * @param bool|false $phpUnit
-     * @param string $fileConfigIni
+     * @param string     $fileConfigIni
+     *
      * @return null|Store
      * @throws UserFormException
      * @throws \qfq\CodeException
@@ -527,6 +539,7 @@ class Store {
      * Deletes a store assigning a new empty array to it.
      *
      * @param $store
+     *
      * @throws UserFormException
      * @throws \qfq\CodeException
      */
@@ -547,10 +560,11 @@ class Store {
     /**
      * Set's a single $key/$value pair $store.
      *
-     * @param string $key
+     * @param string       $key
      * @param string|array $value
-     * @param string $store
-     * @param bool|true $overWrite
+     * @param string       $store
+     * @param bool|true    $overWrite
+     *
      * @throws UserFormException
      * @throws \qfq\CodeException
      */
@@ -587,6 +601,7 @@ class Store {
      * Create a SIP after a form load. This is necessary on forms without a sip and on forms with r=0 (new record).
      *
      * @param $formName
+     *
      * @throws CodeException
      */
     public static function createSipAfterFormLoad($formName) {
@@ -654,6 +669,7 @@ class Store {
      * Returns a complete $store.
      *
      * @param $store
+     *
      * @return array
      * @throws UserFormException
      * @throws \qfq\CodeException
@@ -685,6 +701,7 @@ class Store {
      * Found elements will be base64_decode().
      *
      * @param array $vars
+     *
      * @return array - incl. decoded base64 vars.
      */
     private static function checkDecodeBase64Arr(array $vars) {
@@ -696,6 +713,7 @@ class Store {
                 $vars[$key] = base64_decode($value);
             }
         }
+
         return $vars;
     }
 
@@ -712,6 +730,7 @@ class Store {
      * Fills STORE_TABLE_DEFAULT and STORE_TABLE_COLUMN_TYPES
      *
      * @param $tableName
+     *
      * @throws CodeException
      */
     public static function fillStoreTableDefaultColumnType($tableName) {
@@ -769,7 +788,8 @@ class Store {
         self::setStore($typo3VarsArray, STORE_TYPO3, true);
 
         $value = self::getVar(SYSTEM_SHOW_DEBUG_INFO, STORE_SYSTEM);
-        $value = self::adjustConfigShowDebugInfo($value, ($typo3VarsArray[TYPO3_BE_USER_LOGGED_IN] == 'yes'));
+        $flag = isset($typo3VarsArray[TYPO3_BE_USER_LOGGED_IN]) && ($typo3VarsArray[TYPO3_BE_USER_LOGGED_IN] == 'yes');
+        $value = self::adjustConfigShowDebugInfo($value, $flag);
         self::setVar(SYSTEM_SHOW_DEBUG_INFO, $value, STORE_SYSTEM);
     }
 
diff --git a/extension/qfq/qfq/store/T3Info.php b/extension/qfq/qfq/store/T3Info.php
index df859e2b66685b8268685db7b08a24197085ace9..0960f3afbc8a242f9e35fe2a81dc73cce8ebe8f9 100644
--- a/extension/qfq/qfq/store/T3Info.php
+++ b/extension/qfq/qfq/store/T3Info.php
@@ -37,6 +37,9 @@ class T3Info {
 
         $t3vars[TYPO3_PAGE_LANGUAGE] = isset($GLOBALS["TSFE"]->sys_language_uid) ? $GLOBALS["TSFE"]->sys_language_uid : '';
 
+        $t3vars[TYPO3_BE_USER_LOGGED_IN] = (isset($GLOBALS["TSFE"]->beUserLogin) && $GLOBALS["TSFE"]->beUserLogin === true) ? 'yes' : 'no';
+
+
         return $t3vars;
     }
 }
\ No newline at end of file
diff --git a/extension/qfq/sql/formEditor.sql b/extension/qfq/sql/formEditor.sql
index 65376a26b7f65906f7b93ba2133a7f06dfb9c46d..cb407146f55676b9e866a3b1a41565ca3d3d9f6d 100644
--- a/extension/qfq/sql/formEditor.sql
+++ b/extension/qfq/sql/formEditor.sql
@@ -11,7 +11,8 @@ CREATE TABLE IF NOT EXISTS `Form` (
   `permitEdit`               ENUM('sip', 'logged_in', 'logged_out', 'always', 'never')  NOT NULL  DEFAULT 'sip',
   `escapeTypeDefault`        VARCHAR(32)                                                NOT NULL  DEFAULT 'c',
   `render`                   ENUM('bootstrap', 'table', 'plain')                        NOT NULL  DEFAULT 'bootstrap',
-  `requiredParameter`        VARCHAR(255)                                               NOT NULL  DEFAULT '',
+  `requiredParameterNew`  VARCHAR(255) NOT NULL  DEFAULT '',
+  `requiredParameterEdit` VARCHAR(255) NOT NULL  DEFAULT '',
   `dirtyMode`                ENUM('exclusive', 'advisory', 'none')                      NOT NULL  DEFAULT 'exclusive',
   `showButton`               SET('new', 'delete', 'close', 'save')                      NOT NULL  DEFAULT 'new,delete,close,save',
   `multiMode`                ENUM('none', 'horizontal', 'vertical')                     NOT NULL  DEFAULT 'none',
@@ -27,10 +28,10 @@ CREATE TABLE IF NOT EXISTS `Form` (
   `bsNoteColumns`            VARCHAR(255)                                               NOT NULL  DEFAULT '',
 
   `parameter`                TEXT                                                       NOT NULL,
-  `parameterLanguageA` TEXT NOT NULL,
-  `parameterLanguageB` TEXT NOT NULL,
-  `parameterLanguageC` TEXT NOT NULL,
-  `parameterLanguageD` TEXT NOT NULL,
+  `parameterLanguageA`    TEXT         NOT NULL,
+  `parameterLanguageB`    TEXT         NOT NULL,
+  `parameterLanguageC`    TEXT         NOT NULL,
+  `parameterLanguageD`    TEXT         NOT NULL,
   `recordLockTimeoutSeconds` INT(11)                                                    NOT NULL  DEFAULT 900,
 
   `deleted`                  ENUM('yes', 'no')                                          NOT NULL  DEFAULT 'no',
@@ -220,7 +221,8 @@ VALUES
    '<a href="{{DOCUMENTATION_QFQ:Y}}#multi-language-form">Info</a>', '', '', '', '', 1, '', '{{SELECT IF("{{FORM_LANGUAGE_C_ID:YE}}"="","hidden","show" ) }}', '', 'none', 'no', ''),
   (1, 'parameterLanguageD', 'Language: {{FORM_LANGUAGE_D_LABEL:YE}}', 'show', 'text', 'all', 'native', 160, '60,2', 0,
    '<a href="{{DOCUMENTATION_QFQ:Y}}#multi-language-form">Info</a>', '', '', '', '', 1, '', '{{SELECT IF("{{FORM_LANGUAGE_D_ID:YE}}"="","hidden","show" ) }}', '', 'none', 'no', ''),
-  (1, 'requiredParameter', 'Required Parameter', 'show', 'text', 'all', 'native', 200, 0, 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#form-requiredParameter">Info</a>', '', '', '', '', 2, '', '', '', 'specialchar', 'no', ''),
+  (1, 'requiredParameterNew', 'Required Parameter NEW', 'show', 'text', 'all', 'native', 200, 0, 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#form-requiredParameter">Info</a>', '', '', '', '', 2, '', '', '', 'specialchar', 'no', ''),
+  (1, 'requiredParameterEdit', 'Required Parameter EDIT', 'show', 'text', 'all', 'native', 200, 0, 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#form-requiredParameter">Info</a>', '', '', '', '', 2, '', '', '', 'specialchar', 'no', ''),
   (1, 'permitNew', 'Permit New', 'show', 'radio', 'all', 'native', 210, 0, 10, '<a href="{{DOCUMENTATION_QFQ:Y}}#form-permitNewEdit">Info</a>', '', '', '', 'buttonClass=btn-default', 2, '', '', '', 'specialchar', 'no', ''),
   (1, 'permitEdit', 'Permit Edit', 'show', 'radio', 'all', 'native', 220, 0, 10, '<a href="{{DOCUMENTATION_QFQ:Y}}#form-permitNewEdit">Info</a>', '', '', '', 'buttonClass=btn-default', 2, '', '', '', 'specialchar', 'no', ''),
   (1, 'escapeTypeDefault', 'Escape type default', 'show', 'radio', 'all', 'native', 230, 0, 10, '<a href="{{DOCUMENTATION_QFQ:Y}}#variable-escape">Info</a>', '', '', '',
@@ -230,9 +232,9 @@ VALUES
   (1, 'recordLockTimeoutSeconds', 'Lock timeout (seconds)', 'show', 'text', 'all', 'native', 245, 0, 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#form-requiredParameter">Info</a>', '',
    '{{SELECT IF("{{recordLockTimeoutSeconds:R0}}"=0,"{{RECORD_LOCK_TIMEOUT_SECONDS:Y0}}","{{recordLockTimeoutSeconds:R0}}")}}', '', '', 2, '', '', '', 'specialchar', 'no', ''),
   (1, 'showButton', 'Show button', 'show', 'checkbox', 'all', 'native', 250, 0, 5, '<a href="{{DOCUMENTATION_QFQ:Y}}#form-showButton">Info</a>', '', '', '', 'checkBoxMode = multi\norientation=vertical', 2, '', '', '', 'specialchar', 'no', ''),
-  (1, 'forwardMode', 'Forward', 'show', 'radio', 'all', 'native', 300, 0, 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#form-forward">Info</a>', '', '', '', 'buttonClass=btn-default', 3, '', '', '', 'specialchar', 'yes', ''),
+  (1, 'forwardMode', 'Forward', 'show', 'radio', 'all', 'native', 300, 0, 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#form-forward">Info</a>', '', '', '', 'buttonClass=btn-default', 3, '', '', '', 'specialchar', 'no', ''),
   (1, 'forwardPage', 'Forward URL / Page', 'show', 'text', 'all', 'native', 310, 0, 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#form-forward">Info</a>', '', '', '', '', 3, '',
-   '{{SELECT IF( "{{forwardMode:FE:alnumx}}" LIKE "url%", "show", "hidden")}}', '', 'none', 'yes', ''),
+   '', '', 'none', 'no', ''),
   (1, 'parameter', 'Parameter', 'show', 'text', 'all', 'native', 320, '40,8', 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#form-parameter">Info</a>', '', '', '', '', 3, '', '', '', 'none', 'no', ''),
   (1, 'bsLabelColumns', 'BS Label Columns', 'show', 'text', 'all', 'native', 330, 0, 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#form-layout">Info</a>', '', '', '', '', 3, '', '', '{{bsLabelColumns:Y}}', 'specialchar', 'no', ''),
   (1, 'bsInputColumns', 'BS Input Columns', 'show', 'text', 'all', 'native', 340, 0, 0, '', '', '', '', '', 3, '', '', '{{bsInputColumns:Y}}', 'specialchar', 'no', ''),
@@ -259,7 +261,7 @@ VALUES
 
 #
 # FormEditor: FormElement
-INSERT INTO Form (id, name, title, noteInternal, tableName, permitNew, permitEdit, render, multiSql, parameter, requiredParameter)
+INSERT INTO Form (id, name, title, noteInternal, tableName, permitNew, permitEdit, render, multiSql, parameter, requiredParameterNew)
 VALUES
   (2, 'formElement',
    'Form Element Editor. Form : {{SELECT f.id, " / ",  f.name  FROM Form AS f WHERE f.id = {{formId:S0}}  }}',
@@ -330,9 +332,7 @@ VALUES
   (2, 'bsNoteColumns', 'BS Note Columns', 'show', 'text', 'all', 'native', 430, 0, 0, '', '', '', '', '', 102, '', 'no', '', '', '', '', '{{bsNoteColumns:Y}}', 'specialchar'),
   (2, 'rowLabelInputNote', 'Label / Input / Note', 'show', 'checkbox', 'alnumx', 'native', 440, 0, 10, '<a href="{{DOCUMENTATION_QFQ:Y}}#field-rowLabelInputNote">Info</a>', '', '', '', '', 102, '', 'no', '', '', '', '', '', 'specialchar'),
   (2, 'maxLength', 'Maxlength', 'show', 'text', 'all', 'native', 450, 0, 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#field-maxLength">Info</a>', '', '', '', '', 102, '', 'no', '', '', '', '', '', 'specialchar'),
-  (2, 'note', 'Note', 'show', 'editor', 'all', 'native', 460, '', 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#field-note">Info</a>', '', '', '',
-   'editor-plugins=code link table textcolor textpattern\neditor-toolbar=code | styleselect link table | bullist numlist | forecolor backcolor bold italic\neditor-menubar=false\neditor-statusbar=false',
-   102, '', 'no', '', '', '', '', '', 'none'),
+  (2, 'note', 'Note', 'show', 'text', 'all', 'native', 460, '40,5', 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#field-note">Info</a>', '', '', '', '', 102, '', 'no', '', '', '', '', '', 'none'),
   (2, 'tooltip', 'Tooltip', 'show', 'text', 'all', 'native', 470, 0, 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#field-tooltip">Info</a>', '', '', '', '', 102, '', 'no', '', '', '', '', '', 'none'),
   (2, 'placeholder', 'Placeholder', 'show', 'text', 'all', 'native', 480, 0, 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#field-placeholder">Info</a>', '', '', '', '', 102, '', 'no', '', '', '', '', '', 'none'),
   (2, 'value', 'value', 'show', 'text', 'all', 'native', 500, '40,2', 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#field-value">Info</a>', '', '', '', '', 103, '', 'no', '', '', '', '', '', 'none'),
@@ -341,7 +341,8 @@ VALUES
    '', '', '', '', 103, '', 'no', '', '', '', '', '', 'none'),
   (2, 'parameter', 'Parameter', 'show', 'text', 'all', 'native', 520, '40,8', 0, '<a href="{{DOCUMENTATION_QFQ:Y}}#fe-parameter-attributes">Info</a>',
    '', '', '', '', 103, '', 'no', '', '', '', '', '', 'none'),
-  (2, 'adminNote', 'Admin Note', 'show', 'text', 'all', 'native', 600, 0, 0, '', '', '', '', '', 104, '', 'no', '', '', '', '', '', 'specialchar'),
+  (2, 'adminNote', 'Admin Note', 'show', 'text', 'all', 'native', 600, 0, 0, '', '', '', '', '', 104, '', 'no', '', '',
+   '', '', '', 'specialchar'),
   (2, 'feGroup', 'feGroup', 'show', 'text', 'all', 'native', 610, 0, 0, '', '', '', '', '', 104, '', 'no', '', '', '',
    '', '', 'specialchar'),
   (2, 'deleted', 'Deleted', 'show', 'checkbox', 'all', 'native', 620, 0, 0, '', '', '', '', '', 104, '', 'no', '', '',
@@ -351,7 +352,6 @@ VALUES
   (2, 'created', 'Created', 'readonly', 'text', 'all', 'native', 640, 0, 20, '', '', '', '', '', 104, '', 'no', '',
    '', '', '', '', 'specialchar');
 
-
 # ----------------------------------------
 # MailLog
 
diff --git a/extension/qfq/tests/phpunit/BuildFormPlainTest.php b/extension/qfq/tests/phpunit/BuildFormPlainTest.php
index 7dc1534f2433b290c45c2b5527440040b56686bb..2f8afee67fc04a267c525dd97e5702f4f30d748d 100644
--- a/extension/qfq/tests/phpunit/BuildFormPlainTest.php
+++ b/extension/qfq/tests/phpunit/BuildFormPlainTest.php
@@ -7,6 +7,7 @@ require_once(__DIR__ . '/AbstractDatabaseTest.php');
 require_once(__DIR__ . '/../../qfq/database/Database.php');
 require_once(__DIR__ . '/../../qfq/exceptions/DbException.php');
 require_once(__DIR__ . '/../../qfq/QuickFormQuery.php');
+require_once(__DIR__ . '/../../qfq/helper/Support.php');
 
 class BuildFormPlainTest extends AbstractDatabaseTest {
 
@@ -149,7 +150,6 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
         $result = $build->buildInput($formElement2, 'specialname:1', '', $json);
         $this->assertEquals('<input id="123" name="specialname:1" class="form-control" maxlength="20" type="input" size="10" value="" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
 
-
         // Explicit: further
         $formElement['tooltip'] = 'Nice Tooltip';
         $formElement['placeholder'] = 'Please type a name';
@@ -322,113 +322,116 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
         $json = array();
 
         $this->templateFormNFormElement($form, $formElement);
+        $formElement = \qfq\Support::setFeDefaults($formElement);
+        
         // CheckType
         $build = new \qfq\BuildFormPlain($form, array(), [$formElement]);
 
         // id: 1, firstName: John, name: Doe
         $formElement['sql1'] = $this->db->sql('SELECT id, name, firstName FROM Person ORDER BY id LIMIT 2');
+
         $result = $build->buildSubrecord($formElement, 'name:1', '', $json);
-        $this->assertEquals('<table class="table table-hover"><tr><th>id</th><th>name</th><th>firstName</th></tr><tr class="record" ><td>1</td><td>Doe</td><td>John</td></tr><tr class="record" ><td>2</td><td>Smith</td><td>Jane</td></tr></table>', $result);
+        $this->assertEquals('<table class="table table-hover" ><thead><tr><th>id</th><th>name</th><th>firstName</th></tr></thead><tr class="record" ><td>1</td><td>Doe</td><td>John</td></tr><tr class="record" ><td>2</td><td>Smith</td><td>Jane</td></tr></table>', $result);
 
         // _id: 1, name: Doe,
         $formElement['sql1'] = $this->db->sql('SELECT id AS "_id", name FROM Person ORDER BY id LIMIT 2');
         $result = $build->buildSubrecord($formElement, 'name:1', '', $json);
-        $this->assertEquals('<table class="table table-hover"><tr><th>name</th></tr><tr class="record" ><td>Doe</td></tr><tr class="record" ><td>Smith</td></tr></table>', $result);
+        $this->assertEquals('<table class="table table-hover" ><thead><tr><th>name</th></tr></thead><tr class="record" ><td>Doe</td></tr><tr class="record" ><td>Smith</td></tr></table>', $result);
 
         // _id: 1, name: Doe,title=''
         $formElement['sql1'] = $this->db->sql('SELECT id AS "_id", name AS "title=" FROM Person ORDER BY id LIMIT 2');
         $result = $build->buildSubrecord($formElement, 'name:1', '', $json);
-        $this->assertEquals('<table class="table table-hover"><tr><th></th></tr><tr class="record" ><td>Doe</td></tr><tr class="record" ><td>Smith</td></tr></table>', $result);
+        $this->assertEquals('<table class="table table-hover" ><thead><tr><th></th></tr></thead><tr class="record" ><td>Doe</td></tr><tr class="record" ><td>Smith</td></tr></table>', $result);
 
         // _id: 1, name: Doe, column: _Person
         $formElement['sql1'] = $this->db->sql('SELECT id AS "_id", name AS "unused|width=2|title=_Person", firstName  FROM Person ORDER BY id LIMIT 2');
         $result = $build->buildSubrecord($formElement, 'name:1', '', $json);
-        $this->assertEquals('<table class="table table-hover"><tr><th>firstName</th></tr><tr class="record" ><td>John</td></tr><tr class="record" ><td>Jane</td></tr></table>', $result);
+        $this->assertEquals('<table class="table table-hover" ><thead><tr><th>firstName</th></tr></thead><tr class="record" ><td>John</td></tr><tr class="record" ><td>Jane</td></tr></table>', $result);
 
         // _id: 1, name: Doe, title: PERSON
         $formElement['sql1'] = $this->db->sql('SELECT id AS "_id", name AS "PERSON" FROM Person ORDER BY id LIMIT 2');
         $result = $build->buildSubrecord($formElement, 'name:1', '', $json);
-        $this->assertEquals('<table class="table table-hover"><tr><th>PERSON</th></tr><tr class="record" ><td>Doe</td></tr><tr class="record" ><td>Smith</td></tr></table>', $result);
+        $this->assertEquals('<table class="table table-hover" ><thead><tr><th>PERSON</th></tr></thead><tr class="record" ><td>Doe</td></tr><tr class="record" ><td>Smith</td></tr></table>', $result);
 
         // _id: 1, "This is a much longer text than necessary": Default max:20
         $formElement['sql1'] = $this->db->sql('SELECT id AS "_id", "This is a much longer text than necessary" FROM Person ORDER BY id LIMIT 1');
         $result = $build->buildSubrecord($formElement, 'name:1', '', $json);
-        $this->assertEquals('<table class="table table-hover"><tr><th>This is a much longe</th></tr><tr class="record" ><td>This is a much longe</td></tr></table>', $result);
+        $this->assertEquals('<table class="table table-hover" ><thead><tr><th>This is a much longe</th></tr></thead><tr class="record" ><td>This is a much longe</td></tr></table>', $result);
 
         // _id: 1, name: Jo (width:2)
         $formElement['sql1'] = $this->db->sql('SELECT id AS "_id", name AS "2" FROM Person ORDER BY id LIMIT 2');
         $result = $build->buildSubrecord($formElement, 'name:1', '', $json);
-        $this->assertEquals('<table class="table table-hover"><tr><th></th></tr><tr class="record" ><td>Do</td></tr><tr class="record" ><td>Sm</td></tr></table>', $result);
+        $this->assertEquals('<table class="table table-hover" ><thead><tr><th></th></tr></thead><tr class="record" ><td>Do</td></tr><tr class="record" ><td>Sm</td></tr></table>', $result);
 
         // _id: 1, name: Jo (width:2)
         $formElement['sql1'] = $this->db->sql('SELECT id AS "_id", name AS "2|PERSON" FROM Person ORDER BY id LIMIT 2');
         $result = $build->buildSubrecord($formElement, 'name:1', '', $json);
-        $this->assertEquals('<table class="table table-hover"><tr><th>PE</th></tr><tr class="record" ><td>Do</td></tr><tr class="record" ><td>Sm</td></tr></table>', $result);
+        $this->assertEquals('<table class="table table-hover" ><thead><tr><th>PE</th></tr></thead><tr class="record" ><td>Do</td></tr><tr class="record" ><td>Sm</td></tr></table>', $result);
 
         // _id: 1, name: Doe ('width':3)
         $formElement['sql1'] = $this->db->sql('SELECT id AS "_id", name AS "Name|width=3" FROM Person ORDER BY id LIMIT 2');
         $result = $build->buildSubrecord($formElement, 'name:1', '', $json);
-        $this->assertEquals('<table class="table table-hover"><tr><th>Nam</th></tr><tr class="record" ><td>Doe</td></tr><tr class="record" ><td>Smi</td></tr></table>', $result);
+        $this->assertEquals('<table class="table table-hover" ><thead><tr><th>Nam</th></tr></thead><tr class="record" ><td>Doe</td></tr><tr class="record" ><td>Smi</td></tr></table>', $result);
 
         // _id: 1, name: Doe (width:3, title:PERSON)
         $formElement['sql1'] = $this->db->sql('SELECT id AS "_id", name AS "3|title=PERSON" FROM Person ORDER BY id LIMIT 2');
         $result = $build->buildSubrecord($formElement, 'name:1', '', $json);
-        $this->assertEquals('<table class="table table-hover"><tr><th>PER</th></tr><tr class="record" ><td>Doe</td></tr><tr class="record" ><td>Smi</td></tr></table>', $result);
+        $this->assertEquals('<table class="table table-hover" ><thead><tr><th>PER</th></tr></thead><tr class="record" ><td>Doe</td></tr><tr class="record" ><td>Smi</td></tr></table>', $result);
 
         // _id: 1, name: <b>Doe</b>
         $formElement['sql1'] = $this->db->sql('SELECT id AS "_id", CONCAT("<b>", name, "</b>") AS "Name" FROM Person ORDER BY id LIMIT 2');
         $result = $build->buildSubrecord($formElement, 'name:1', '', $json);
-        $this->assertEquals('<table class="table table-hover"><tr><th>Name</th></tr><tr class="record" ><td>Doe</td></tr><tr class="record" ><td>Smith</td></tr></table>', $result);
+        $this->assertEquals('<table class="table table-hover" ><thead><tr><th>Name</th></tr></thead><tr class="record" ><td>Doe</td></tr><tr class="record" ><td>Smith</td></tr></table>', $result);
 
         // _id: 1, name: <b>Doe</b>, width=2
         $formElement['sql1'] = $this->db->sql('SELECT id AS "_id", CONCAT("<b>", name, "</b>") AS "Name|2" FROM Person ORDER BY id LIMIT 2');
         $result = $build->buildSubrecord($formElement, 'name:1', '', $json);
-        $this->assertEquals('<table class="table table-hover"><tr><th>Na</th></tr><tr class="record" ><td>Do</td></tr><tr class="record" ><td>Sm</td></tr></table>', $result);
+        $this->assertEquals('<table class="table table-hover" ><thead><tr><th>Na</th></tr></thead><tr class="record" ><td>Do</td></tr><tr class="record" ><td>Sm</td></tr></table>', $result);
 
         // _id: 1, name: <b>Doe</b> , nostrip
         $formElement['sql1'] = $this->db->sql('SELECT id AS "_id", CONCAT("<b>", name, "</b>") AS "Name|nostrip" FROM Person ORDER BY id LIMIT 2');
         $result = $build->buildSubrecord($formElement, 'name:1', '', $json);
-        $this->assertEquals('<table class="table table-hover"><tr><th>Name</th></tr><tr class="record" ><td><b>Doe</b></td></tr><tr class="record" ><td><b>Smith</b></td></tr></table>', $result);
+        $this->assertEquals('<table class="table table-hover" ><thead><tr><th>Name</th></tr></thead><tr class="record" ><td><b>Doe</b></td></tr><tr class="record" ><td><b>Smith</b></td></tr></table>', $result);
 
         // _id: 1, icon: bullet-green.gif
         $formElement['sql1'] = $this->db->sql('SELECT id AS "_id", "bullet-green.gif" AS "Status|icon" FROM Person ORDER BY id LIMIT 2');
         $result = $build->buildSubrecord($formElement, 'name:1', '', $json);
-        $this->assertEquals('<table class="table table-hover"><tr><th>Status</th></tr><tr class="record" ><td><image src=\'typo3conf/ext/qfq/Resources/Public/icons/bullet-green.gif\'></td></tr><tr class="record" ><td><image src=\'typo3conf/ext/qfq/Resources/Public/icons/bullet-green.gif\'></td></tr></table>', $result);
+        $this->assertEquals('<table class="table table-hover" ><thead><tr><th>Status</th></tr></thead><tr class="record" ><td><image src=\'typo3conf/ext/qfq/Resources/Public/icons/bullet-green.gif\'></td></tr><tr class="record" ><td><image src=\'typo3conf/ext/qfq/Resources/Public/icons/bullet-green.gif\'></td></tr></table>', $result);
 
         // _id: 1, mailto: john@doe.com
         $formElement['sql1'] = $this->db->sql('SELECT id AS "_id", "john@doe.com" AS "EMail|mailto" FROM Person ORDER BY id LIMIT 2');
         $result = $build->buildSubrecord($formElement, 'name:1', '', $json);
-        $this->assertEquals('<table class="table table-hover"><tr><th>EMail</th></tr><tr class="record" ><td><a href="mailto:john@doe.com" >john@doe.com</a></td></tr><tr class="record" ><td><a href="mailto:john@doe.com" >john@doe.com</a></td></tr></table>', $result);
+        $this->assertEquals('<table class="table table-hover" ><thead><tr><th>EMail</th></tr></thead><tr class="record" ><td><a href="mailto:john@doe.com" >john@doe.com</a></td></tr><tr class="record" ><td><a href="mailto:john@doe.com" >john@doe.com</a></td></tr></table>', $result);
 
         // _id: 1, url: www.uzh.ch
         $formElement['sql1'] = $this->db->sql('SELECT id AS "_id", "www.uzh.ch" AS "URL|url" FROM Person ORDER BY id LIMIT 2');
         $result = $build->buildSubrecord($formElement, 'name:1', '', $json);
-        $this->assertEquals('<table class="table table-hover"><tr><th>URL</th></tr><tr class="record" ><td><a href="www.uzh.ch" >www.uzh.ch</a></td></tr><tr class="record" ><td><a href="www.uzh.ch" >www.uzh.ch</a></td></tr></table>', $result);
+        $this->assertEquals('<table class="table table-hover" ><thead><tr><th>URL</th></tr></thead><tr class="record" ><td><a href="www.uzh.ch" >www.uzh.ch</a></td></tr><tr class="record" ><td><a href="www.uzh.ch" >www.uzh.ch</a></td></tr></table>', $result);
 
         // _id: 1, name: Doe, _rowclass (text)
         $formElement['sql1'] = $this->db->sql('SELECT id AS "_id", name, IF(id=1,"text-warning", "text-danger") AS _rowClass FROM Person ORDER BY id LIMIT 2');
         $result = $build->buildSubrecord($formElement, 'name:1', '', $json);
-        $this->assertEquals('<table class="table table-hover"><tr><th>name</th></tr><tr class="record text-warning" ><td>Doe</td></tr><tr class="record text-danger" ><td>Smith</td></tr></table>', $result);
+        $this->assertEquals('<table class="table table-hover" ><thead><tr><th>name</th></tr></thead><tr class="record text-warning" ><td>Doe</td></tr><tr class="record text-danger" ><td>Smith</td></tr></table>', $result);
 
         // _id: 1, name: Doe, _rowClass (text & background)
         $formElement['sql1'] = $this->db->sql('SELECT id AS "_id", name, IF(id=1,"text-warning active", "text-danger success") AS _rowClass FROM Person ORDER BY id LIMIT 2');
         $result = $build->buildSubrecord($formElement, 'name:1', '', $json);
-        $this->assertEquals('<table class="table table-hover"><tr><th>name</th></tr><tr class="record text-warning active" ><td>Doe</td></tr><tr class="record text-danger success" ><td>Smith</td></tr></table>', $result);
+        $this->assertEquals('<table class="table table-hover" ><thead><tr><th>name</th></tr></thead><tr class="record text-warning active" ><td>Doe</td></tr><tr class="record text-danger success" ><td>Smith</td></tr></table>', $result);
 
         // _id: 1, name: Doe, _rowTitle
         $formElement['sql1'] = $this->db->sql('SELECT id AS "_id", name, firstName AS _rowTitle FROM Person ORDER BY id LIMIT 2');
         $result = $build->buildSubrecord($formElement, 'name:1', '', $json);
-        $this->assertEquals('<table class="table table-hover"><tr><th>name</th></tr><tr class="record" title="John" ><td>Doe</td></tr><tr class="record" title="Jane" ><td>Smith</td></tr></table>', $result);
+        $this->assertEquals('<table class="table table-hover" ><thead><tr><th>name</th></tr></thead><tr class="record" title="John" ><td>Doe</td></tr><tr class="record" title="Jane" ><td>Smith</td></tr></table>', $result);
 
         // _id: 1, name: Doe, title, width, nostrip
         $formElement['sql1'] = $this->db->sql('SELECT id AS "_id", name, "<b>This again is a very long text</b>" AS "title=Important|width=10|nostrip" FROM Person ORDER BY id LIMIT 2');
         $result = $build->buildSubrecord($formElement, 'name:1', '', $json);
-        $this->assertEquals('<table class="table table-hover"><tr><th>name</th><th>Important</th></tr><tr class="record" ><td>Doe</td><td><b>This again is a very long text</b></td></tr><tr class="record" ><td>Smith</td><td><b>This again is a very long text</b></td></tr></table>', $result);
+        $this->assertEquals('<table class="table table-hover" ><thead><tr><th>name</th><th>Important</th></tr></thead><tr class="record" ><td>Doe</td><td><b>This again is a very long text</b></td></tr><tr class="record" ><td>Smith</td><td><b>This again is a very long text</b></td></tr></table>', $result);
 
         // _id: 1, name: Doe, link
         $formElement['sql1'] = $this->db->sql('SELECT id AS "_id", name, CONCAT("s:1|p:form&form=person&r=" , id , "|t:", name) AS "link" FROM Person ORDER BY id LIMIT 2');
         $result = $build->buildSubrecord($formElement, 'name:1', '', $json);
-        $this->assertEquals('<table class="table table-hover"><tr><th>name</th><th></th></tr><tr class="record" ><td>Doe</td><td><a href="index.php?id=form&s=badcaffee1234" class="internal" >Doe</a></td></tr><tr class="record" ><td>Smith</td><td><a href="index.php?id=form&s=badcaffee1234" class="internal" >Smith</a></td></tr></table>', $result);
+        $this->assertEquals('<table class="table table-hover" ><thead><tr><th>name</th><th></th></tr></thead><tr class="record" ><td>Doe</td><td><a href="index.php?id=form&s=badcaffee1234" class="internal" >Doe</a></td></tr><tr class="record" ><td>Smith</td><td><a href="index.php?id=form&s=badcaffee1234" class="internal" >Smith</a></td></tr></table>', $result);
     }
 
     /**
@@ -436,54 +439,55 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
      */
     private function templateFormNFormElement(array &$form, array &$formElement) {
         $form = [
-            'id' => '1',
-            'name' => 'form',
-            'title' => 'Form Editor: {{SELECT id, " / ", title FROM Form WHERE id => {{recordId:S0}}}}',
-            'noteInternal' => 'Please secure the form',
-            'tableName' => 'Form',
-            'permitNew' => 'always',
-            'permitEdit' => 'always',
+            'id'              => '1',
+            'name'            => 'form',
+            'title'           => 'Form Editor: {{SELECT id, " / ", title FROM Form WHERE id => {{recordId:S0}}}}',
+            'noteInternal'    => 'Please secure the form',
+            'tableName'       => 'Form',
+            'permitNew'       => 'always',
+            'permitEdit'      => 'always',
             'permitUrlParameter' => '',
-            'render' => 'bootstrap',
-            'multiMode' => 'none',
-            'multiSql' => '',
+            'render'          => 'bootstrap',
+            'multiMode'       => 'none',
+            'multiSql'        => '',
             'multiDetailForm' => '',
             'multiDetailFormParameter' => '',
-            F_FORWARD_MODE => 'auto',
-            F_FORWARD_PAGE => '',
-            'bsLabelColumns' => '',
-            'bsInputColumns' => '',
-            'bsNoteColumns' => '',
-            'parameter' => 'maxVisiblePill=>3',
-            'deleted' => 'no',
+            F_FORWARD_MODE    => 'auto',
+            F_FORWARD_PAGE    => '',
+            'bsLabelColumns'  => '',
+            'bsInputColumns'  => '',
+            'bsNoteColumns'   => '',
+            'parameter'       => 'maxVisiblePill=>3',
+            'deleted'         => 'no',
         ];
 
         $formElement = [
-            'id' => 123,
-            FE_ID => 1,
+            'id'            => 123,
+            FE_ID           => 1,
             FE_ID_CONTAINER => 0,
             FE_DYNAMIC_UPDATE => 'no',
-            'enabled' => 'yes',
-            FE_NAME => 'name',
-            FE_LABEL => 'Name',
-            FE_MODE => 'show',
-            'class' => 'native',
-            FE_TYPE => 'input',
-            'value' => '',
-            'sql1' => '',
-            'parameter' => '',
-            'debug' => 'no',
-            'deleted' => 'no',
-            'size' => '',
-            'maxLength' => '255',
-            'tooltip' => '',
-            'placeholder' => '',
-            FE_CHECK_TYPE => '',
+            'enabled'       => 'yes',
+            FE_NAME         => 'name',
+            FE_LABEL        => 'Name',
+            FE_MODE         => 'show',
+            FE_MODE_SQL => '',
+            'class'         => 'native',
+            FE_TYPE         => 'input',
+            'value'         => '',
+            'sql1'          => '',
+            'parameter'     => '',
+            'debug'         => 'no',
+            'deleted'       => 'no',
+            'size'          => '',
+            'maxLength'     => '255',
+            'tooltip'       => '',
+            'placeholder'   => '',
+            FE_CHECK_TYPE   => '',
             FE_CHECK_PATTERN => '',
-            FE_HTML_ID => '123',
-            FE_HIDE_ZERO => '0',
+            FE_HTML_ID      => '123',
+            FE_HIDE_ZERO    => '0',
 
-            'tabindex' => 0
+            'tabindex'      => 0,
         ];
 
     }
diff --git a/extension/qfq/tests/phpunit/DatabaseTest.php b/extension/qfq/tests/phpunit/DatabaseTest.php
index 0bff4ce11b4a7628afda1553b57050483927db48..a01b6c77696a14ec5b9a8a260de34c30e1fabf52 100644
--- a/extension/qfq/tests/phpunit/DatabaseTest.php
+++ b/extension/qfq/tests/phpunit/DatabaseTest.php
@@ -36,20 +36,20 @@ class DatabaseTest extends AbstractDatabaseTest {
 
         $expected = [
             [
-                'id' => '1',
-                'name' => 'Doe',
+                'id'     => '1',
+                'name'   => 'Doe',
                 'firstName' => 'John',
-                'adrId' => '0',
+                'adrId'  => '0',
                 'gender' => 'male',
-                'groups' => 'c'
+                'groups' => 'c',
             ],
             [
-                'id' => '2',
-                'name' => 'Smith',
+                'id'     => '2',
+                'name'   => 'Smith',
                 'firstName' => 'Jane',
-                'adrId' => '0',
+                'adrId'  => '0',
                 'gender' => 'female',
-                'groups' => 'a,c'
+                'groups' => 'a,c',
             ],
         ];
 
diff --git a/extension/qfq/tests/phpunit/DirtyTest.php b/extension/qfq/tests/phpunit/DirtyTest.php
index 2b3170a0a23cb0ee904f9987e82a541c164484e4..31c469802c55cee05adaa656178769f9c3b84a5c 100644
--- a/extension/qfq/tests/phpunit/DirtyTest.php
+++ b/extension/qfq/tests/phpunit/DirtyTest.php
@@ -432,7 +432,7 @@ class DirtyTest extends \AbstractDatabaseTest {
 
         $result = $dirty->process();
 
-        $expected = [API_STATUS => API_ANSWER_STATUS_SUCCESS, API_MESSAGE => '', API_LOCK_TIMEOUT => 900    ];
+        $expected = [API_STATUS => API_ANSWER_STATUS_SUCCESS, API_MESSAGE => '', API_LOCK_TIMEOUT => 900];
         $this->assertEquals($expected, $result);
 
         // Create clean environment
@@ -734,7 +734,7 @@ class DirtyTest extends \AbstractDatabaseTest {
 
         $result = $dirty->process();
 
-        $expected = [API_STATUS => API_ANSWER_STATUS_SUCCESS, API_MESSAGE => '', API_LOCK_TIMEOUT => 900    ];
+        $expected = [API_STATUS => API_ANSWER_STATUS_SUCCESS, API_MESSAGE => '', API_LOCK_TIMEOUT => 900];
         $this->assertEquals($expected, $result);
 
         // Create clean environment
@@ -776,7 +776,7 @@ class DirtyTest extends \AbstractDatabaseTest {
 
         $result = $dirty->process();
 
-        $expected = [API_STATUS => API_ANSWER_STATUS_SUCCESS, API_MESSAGE => '' ];
+        $expected = [API_STATUS => API_ANSWER_STATUS_SUCCESS, API_MESSAGE => ''];
         $this->assertEquals($expected, $result);
 
         // Create clean environment
@@ -808,7 +808,7 @@ class DirtyTest extends \AbstractDatabaseTest {
 
         $result = $dirty->process();
 
-        $expected = [API_STATUS => API_ANSWER_STATUS_SUCCESS, API_MESSAGE => '' ];
+        $expected = [API_STATUS => API_ANSWER_STATUS_SUCCESS, API_MESSAGE => ''];
         $this->assertEquals($expected, $result);
 
         // Create clean environment
@@ -840,7 +840,7 @@ class DirtyTest extends \AbstractDatabaseTest {
 
         $result = $dirty->process();
 
-        $expected = [API_STATUS => API_ANSWER_STATUS_SUCCESS, API_MESSAGE => '', API_LOCK_TIMEOUT => 900 ];
+        $expected = [API_STATUS => API_ANSWER_STATUS_SUCCESS, API_MESSAGE => '', API_LOCK_TIMEOUT => 900];
         $this->assertEquals($expected, $result);
 
         // Create clean environment
@@ -877,7 +877,7 @@ class DirtyTest extends \AbstractDatabaseTest {
 
         $result = $dirty->process();
 
-        $expected = [API_STATUS => API_ANSWER_STATUS_SUCCESS, API_MESSAGE => '', API_LOCK_TIMEOUT => 900 ];
+        $expected = [API_STATUS => API_ANSWER_STATUS_SUCCESS, API_MESSAGE => '', API_LOCK_TIMEOUT => 900];
         $this->assertEquals($expected, $result);
 
         // Create clean environment
@@ -914,7 +914,7 @@ class DirtyTest extends \AbstractDatabaseTest {
 
         $result = $dirty->process();
 
-        $expected = [API_STATUS => API_ANSWER_STATUS_SUCCESS, API_MESSAGE => '', API_LOCK_TIMEOUT => 900 ];
+        $expected = [API_STATUS => API_ANSWER_STATUS_SUCCESS, API_MESSAGE => '', API_LOCK_TIMEOUT => 900];
         $this->assertEquals($expected, $result);
 
         // Create clean environment
@@ -951,7 +951,7 @@ class DirtyTest extends \AbstractDatabaseTest {
 
         $result = $dirty->process();
 
-        $expected = [API_STATUS => API_ANSWER_STATUS_SUCCESS, API_MESSAGE => '', API_LOCK_TIMEOUT => 900 ];
+        $expected = [API_STATUS => API_ANSWER_STATUS_SUCCESS, API_MESSAGE => '', API_LOCK_TIMEOUT => 900];
         $this->assertEquals($expected, $result);
 
         // Create clean environment
@@ -1018,12 +1018,12 @@ class DirtyTest extends \AbstractDatabaseTest {
      *
      * @param $cookie
      */
-    private function clean($cookie='') {
+    private function clean($cookie = '') {
 
         $session = \qfq\Session::getInstance(true);
         $session::clearAll();
 
-        if($cookie!='') {
+        if ($cookie != '') {
             $_COOKIE[SESSION_NAME] = $cookie;
         }
 
diff --git a/extension/qfq/tests/phpunit/EvaluateTest.php b/extension/qfq/tests/phpunit/EvaluateTest.php
index 1740ced922855a7b3c58020fb72a373bef26b88a..5deb215ba95feb8e0b502ad275bc01e36e83282e 100644
--- a/extension/qfq/tests/phpunit/EvaluateTest.php
+++ b/extension/qfq/tests/phpunit/EvaluateTest.php
@@ -8,7 +8,6 @@
 
 namespace qfq;
 
-use qfq\Store;
 use qfq;
 
 require_once(__DIR__ . '/AbstractDatabaseTest.php');
@@ -59,12 +58,12 @@ class EvaluateTest extends \AbstractDatabaseTest {
         // Get 2 row Array
         $expected = [
             [
-                'id' => '1',
-                'name' => 'Doe'
+                'id'   => '1',
+                'name' => 'Doe',
             ],
             [
-                'id' => '2',
-                'name' => 'Smith'
+                'id'   => '2',
+                'name' => 'Smith',
             ],
         ];
         $this->assertEquals($expected, $eval->parse('{{!SELECT id, name FROM Person WHERE id < 3 ORDER BY id}}'));
@@ -109,27 +108,27 @@ class EvaluateTest extends \AbstractDatabaseTest {
             'formName' => 'MyTestForm',
             'title' => 'Person: {{SELECT firstname, " ", name FROM Person LIMIT 1}} / Employee',
             'key1' => 'Hello',
-            'key2' => 'World'
+            'key2' => 'World',
         ];
         $expected = [
             'formName' => 'MyTestForm',
             'title' => 'Person: John Doe / Employee',
             'key1' => 'Hello',
-            'key2' => 'World'
+            'key2' => 'World',
         ];
 
         $this->assertEquals($expected, $eval->parseArray($data));
 
         $expected2 = $expected;
         $expected2['title'] = $data['title'];
-        $this->assertEquals($expected2, $eval->parseArray($data, [ 'formName', 'title' ]));
+        $this->assertEquals($expected2, $eval->parseArray($data, ['formName', 'title']));
 
         $expected2 = $expected;
-        $data['formName'] = "SELECT FROM unknown garbage with missing parameter";
+        $data['formName'] = "SELECT FROM unknown garbage WITH missing parameter";
         $expected2['formName'] = $data['formName'];
 
         $expected2['title'] = $data['title'];
-        $this->assertEquals($expected2, $eval->parseArray($data, [ 'formName', 'title' ]));
+        $this->assertEquals($expected2, $eval->parseArray($data, ['formName', 'title']));
     }
 
 
@@ -138,22 +137,22 @@ class EvaluateTest extends \AbstractDatabaseTest {
         $data = [
             [
                 'formName' => 'MyTestForm',
-                'title' => 'Person: {{SELECT firstname, " ", name FROM Person LIMIT 1}} / Employee'
+                'title' => 'Person: {{SELECT firstname, " ", name FROM Person LIMIT 1}} / Employee',
             ],
             [
                 'order' => '100',
-                'class' => 'Person: {{SELECT firstname, " ", name FROM Person LIMIT 1}} / Employee'
-            ]
+                'class' => 'Person: {{SELECT firstname, " ", name FROM Person LIMIT 1}} / Employee',
+            ],
         ];
         $expected = [
             [
                 'formName' => 'MyTestForm',
-                'title' => 'Person: John Doe / Employee'
+                'title' => 'Person: John Doe / Employee',
             ],
             [
                 'order' => '100',
-                'class' => 'Person: John Doe / Employee'
-            ]
+                'class' => 'Person: John Doe / Employee',
+            ],
         ];
 
         $this->assertEquals($expected, $eval->parseArray($data));
diff --git a/extension/qfq/tests/phpunit/FormActionTest.php b/extension/qfq/tests/phpunit/FormActionTest.php
index 9788f769b40545172d801f5a9fdf7853d4d70ba1..58cd48f1c38dfbc2a426857a54aba056b26b6b47 100644
--- a/extension/qfq/tests/phpunit/FormActionTest.php
+++ b/extension/qfq/tests/phpunit/FormActionTest.php
@@ -306,7 +306,6 @@ class FormActionTest extends \AbstractDatabaseTest {
     }
 
 
-
     protected function setUp() {
 
         $this->store = Store::getInstance('form=TestFormName', true);
diff --git a/extension/qfq/tests/phpunit/HelperFormElementTest.php b/extension/qfq/tests/phpunit/HelperFormElementTest.php
index 44573d8ba1d40c1d8baed226d94fd2051829dc04..3b84b666b6b462ba5134d605dad16317734e7ab4 100644
--- a/extension/qfq/tests/phpunit/HelperFormElementTest.php
+++ b/extension/qfq/tests/phpunit/HelperFormElementTest.php
@@ -9,8 +9,6 @@
 
 namespace qfq;
 
-use qfq\HelperFormElement;
-
 require_once(__DIR__ . '/../../qfq/helper/HelperFormElement.php');
 require_once(__DIR__ . '/../../qfq/Constants.php');
 
@@ -106,7 +104,7 @@ class HelperFormElementTest extends \PHPUnit_Framework_TestCase {
             FE_SENDMAIL_GR_ID, FE_SENDMAIL_X_ID];
 
         $expect = array();
-        foreach($list as $key) {
+        foreach ($list as $key) {
             $expect[$key] = '';
         }
 
@@ -134,10 +132,10 @@ class HelperFormElementTest extends \PHPUnit_Framework_TestCase {
      */
     public function testInitUploadFormElement() {
 
-        $list = [ FE_SQL_BEFORE, FE_SQL_INSERT, FE_SQL_UPDATE, FE_SQL_DELETE, FE_SQL_AFTER ];
+        $list = [FE_SQL_BEFORE, FE_SQL_INSERT, FE_SQL_UPDATE, FE_SQL_DELETE, FE_SQL_AFTER];
 
         $expect = array();
-        foreach($list as $key) {
+        foreach ($list as $key) {
             $expect[$key] = '';
         }
 
diff --git a/extension/qfq/tests/phpunit/KeyValueStringParserTest.php b/extension/qfq/tests/phpunit/KeyValueStringParserTest.php
index e1f5d7b4a74be8e72bfadeb1437874317021dbe2..d491b4071ca248d6d7ece28d4d1b47045de20d8b 100644
--- a/extension/qfq/tests/phpunit/KeyValueStringParserTest.php
+++ b/extension/qfq/tests/phpunit/KeyValueStringParserTest.php
@@ -95,7 +95,7 @@ class KeyValueStringParserTest extends \PHPUnit_Framework_TestCase {
             'key1' => ' val:ue1 ',
             'key2' => ' value2 ',
             'key3' => "\"value3'",
-            'key4' => ''
+            'key4' => '',
         ];
         $this->assertEquals($expected, $actual);
     }
diff --git a/extension/qfq/tests/phpunit/OnArrayTest.php b/extension/qfq/tests/phpunit/OnArrayTest.php
index 15e3476c7fdc0ef9579fbdb375a9ff43db76f537..54ec551aa0b1e33cd00142b0b4c1a83931b65978 100644
--- a/extension/qfq/tests/phpunit/OnArrayTest.php
+++ b/extension/qfq/tests/phpunit/OnArrayTest.php
@@ -14,19 +14,19 @@ require_once(__DIR__ . '/../../qfq/helper/OnArray.php');
 class OnArrayTest extends \PHPUnit_Framework_TestCase {
     public function testSortByKey() {
         $unsorted = [
-            'a' => 'z',
-            '1' => 'y',
-            'Aa' => 'y0',
-            'zZ' => 'X9',
-            '0000' => 'h'
+            'a'    => 'z',
+            '1'    => 'y',
+            'Aa'   => 'y0',
+            'zZ'   => 'X9',
+            '0000' => 'h',
         ];
 
         $sorted = [
             '0000' => 'h',
-            '1' => 'y',
+            '1'  => 'y',
             'Aa' => 'y0',
-            'a' => 'z',
-            'zZ' => 'X9'
+            'a'  => 'z',
+            'zZ' => 'X9',
         ];
 
         $expected = $unsorted;
diff --git a/extension/qfq/tests/phpunit/StoreTest.php b/extension/qfq/tests/phpunit/StoreTest.php
index f377e44fc2b35d554115758b1dc7f467c186748f..d721e503d379248f4bc56301c4f08d23abbd7281 100644
--- a/extension/qfq/tests/phpunit/StoreTest.php
+++ b/extension/qfq/tests/phpunit/StoreTest.php
@@ -9,7 +9,6 @@
 namespace qfq;
 
 use qfq;
-use qfq\Store;
 
 //use qfq\exceptions\CodeException;
 
@@ -215,6 +214,7 @@ class StoreTest extends \PHPUnit_Framework_TestCase {
 
     /**
      * @param $body
+     *
      * @return string
      */
     private function createFile($body) {
@@ -246,57 +246,58 @@ class StoreTest extends \PHPUnit_Framework_TestCase {
 EOT;
 
         $expect = [
-            SYSTEM_DB_USER => '<DBUSER>',
-            SYSTEM_DB_SERVER => '<DBSERVER>',
-            SYSTEM_DB_PASSWORD => '<DBPW>',
-            SYSTEM_DB_NAME => '<DB>',
-            SYSTEM_DB_NAME_TEST => '<TESTDB>',
-            SYSTEM_DB_INIT => 'set names utf8',
-            SYSTEM_SQL_LOG_MODE => 'modify',
-            SYSTEM_DATE_FORMAT => 'yyyy-mm-dd',
-            SYSTEM_SHOW_DEBUG_INFO => SYSTEM_SHOW_DEBUG_INFO_NO,
-            F_BS_COLUMNS => '12',
-            F_BS_LABEL_COLUMNS => '3',
-            F_BS_INPUT_COLUMNS => '6',
-            F_BS_NOTE_COLUMNS => '3',
-            F_CLASS_PILL => 'qfq-color-grey-1',
-            F_CLASS_BODY => 'qfq-color-grey-2',
-
-            F_SAVE_BUTTON_TEXT => '',
-            F_SAVE_BUTTON_TOOLTIP => 'Save',
-            F_SAVE_BUTTON_CLASS => 'btn btn-default navbar-btn',
-            F_SAVE_BUTTON_GLYPH_ICON => 'glyphicon-ok',
-
-            F_CLOSE_BUTTON_TEXT => '',
-            F_CLOSE_BUTTON_TOOLTIP => 'Close',
-            F_CLOSE_BUTTON_CLASS => 'btn btn-default navbar-btn',
-            F_CLOSE_BUTTON_GLYPH_ICON => 'glyphicon-remove',
-
-            F_DELETE_BUTTON_TEXT => '',
-            F_DELETE_BUTTON_TOOLTIP => 'Delete',
-            F_DELETE_BUTTON_CLASS => 'btn btn-default navbar-btn',
-            F_DELETE_BUTTON_GLYPH_ICON => 'glyphicon-trash',
-
-            F_NEW_BUTTON_TEXT => '',
-            F_NEW_BUTTON_TOOLTIP => 'New',
-            F_NEW_BUTTON_CLASS => 'btn btn-default navbar-btn',
-            F_NEW_BUTTON_GLYPH_ICON => 'glyphicon-plus',
-
-            F_BUTTON_ON_CHANGE_CLASS => 'btn-info alert-info',
-            SYSTEM_EDIT_FORM_PAGE => 'form',
-            SYSTEM_SECURITY_VARS_HONEYPOT => 'email,username,password',
-            SYSTEM_SECURITY_ATTACK_DELAY => '5',
-            SYSTEM_SECURITY_SHOW_MESSAGE => '0',
-            SYSTEM_SECURITY_GET_MAX_LENGTH => '50',
-            SYSTEM_ESCAPE_TYPE_DEFAULT => 's',
+            SYSTEM_DB_USER                     => '<DBUSER>',
+            SYSTEM_DB_SERVER                   => '<DBSERVER>',
+            SYSTEM_DB_PASSWORD                 => '<DBPW>',
+            SYSTEM_DB_NAME                     => '<DB>',
+            SYSTEM_DB_NAME_TEST                => '<TESTDB>',
+            SYSTEM_DB_INIT                     => 'set names utf8',
+            SYSTEM_SQL_LOG_MODE                => 'modify',
+            SYSTEM_DATE_FORMAT                 => 'yyyy-mm-dd',
+            SYSTEM_SHOW_DEBUG_INFO             => SYSTEM_SHOW_DEBUG_INFO_NO,
+            F_BS_COLUMNS                       => '12',
+            F_BS_LABEL_COLUMNS                 => '3',
+            F_BS_INPUT_COLUMNS                 => '6',
+            F_BS_NOTE_COLUMNS                  => '3',
+            F_CLASS_PILL                       => 'qfq-color-grey-1',
+            F_CLASS_BODY                       => 'qfq-color-grey-2',
+
+            F_SAVE_BUTTON_TEXT                 => '',
+            F_SAVE_BUTTON_TOOLTIP              => 'Save',
+            F_SAVE_BUTTON_CLASS                => 'btn btn-default navbar-btn',
+            F_SAVE_BUTTON_GLYPH_ICON           => 'glyphicon-ok',
+
+            F_CLOSE_BUTTON_TEXT                => '',
+            F_CLOSE_BUTTON_TOOLTIP             => 'Close',
+            F_CLOSE_BUTTON_CLASS               => 'btn btn-default navbar-btn',
+            F_CLOSE_BUTTON_GLYPH_ICON          => 'glyphicon-remove',
+
+            F_DELETE_BUTTON_TEXT               => '',
+            F_DELETE_BUTTON_TOOLTIP            => 'Delete',
+            F_DELETE_BUTTON_CLASS              => 'btn btn-default navbar-btn',
+            F_DELETE_BUTTON_GLYPH_ICON         => 'glyphicon-trash',
+
+            F_NEW_BUTTON_TEXT                  => '',
+            F_NEW_BUTTON_TOOLTIP               => 'New',
+            F_NEW_BUTTON_CLASS                 => 'btn btn-default navbar-btn',
+            F_NEW_BUTTON_GLYPH_ICON            => 'glyphicon-plus',
+
+            F_BUTTON_ON_CHANGE_CLASS           => 'btn-info alert-info',
+            SYSTEM_EDIT_FORM_PAGE              => 'form',
+            SYSTEM_SECURITY_VARS_HONEYPOT      => 'email,username,password',
+            SYSTEM_SECURITY_ATTACK_DELAY       => '5',
+            SYSTEM_SECURITY_SHOW_MESSAGE       => '0',
+            SYSTEM_SECURITY_GET_MAX_LENGTH     => '50',
+            SYSTEM_ESCAPE_TYPE_DEFAULT         => 's',
             SYSTEM_GFX_EXTRA_BUTTON_INFO_INLINE => '<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>',
             SYSTEM_GFX_EXTRA_BUTTON_INFO_BELOW => '<span class="glyphicon glyphicon-info-sign text-info" aria-hidden="true"></span>',
+            SYSTEM_EXTRA_BUTTON_INFO_CLASS     => '',
 
-            SYSTEM_DB_UPDATE => SYSTEM_DB_UPDATE_AUTO,
+            SYSTEM_DB_UPDATE                   => SYSTEM_DB_UPDATE_AUTO,
             SYSTEM_RECORD_LOCK_TIMEOUT_SECONDS => SYSTEM_RECORD_LOCK_TIMEOUT_SECONDS_DEFAULT,
 
-            DOCUMENTATION_QFQ => DOCUMENTATION_QFQ_URL,
-            SYSTEM_VAR_ADD_BY_SQL => 'SELECT id AS periodId FROM Period WHERE start<=NOW() ORDER BY start DESC LIMIT 1',
+            DOCUMENTATION_QFQ                  => DOCUMENTATION_QFQ_URL,
+            SYSTEM_VAR_ADD_BY_SQL              => 'SELECT id AS periodId FROM Period WHERE start<=NOW() ORDER BY start DESC LIMIT 1',
 
         ];
 
@@ -313,7 +314,6 @@ EOT;
         // check default values
         $this->assertEquals($expect, $value, "Retrieve system store.");
 
-
         //
         $body .= PHP_EOL . SYSTEM_FORM_BS_LABEL_COLUMNS . ' = 4';
         $body .= PHP_EOL . SYSTEM_FORM_BS_INPUT_COLUMNS . ' = 5';
diff --git a/extension/qfq/tests/phpunit/SupportTest.php b/extension/qfq/tests/phpunit/SupportTest.php
index 11da3393a1608aff027d09de935d0464ba848be7..03b184d6e8da4f979613e42beeaf20f9dd99d5d0 100644
--- a/extension/qfq/tests/phpunit/SupportTest.php
+++ b/extension/qfq/tests/phpunit/SupportTest.php
@@ -20,7 +20,6 @@ class FakeTSFE {
 
 class SupportTest extends \PHPUnit_Framework_TestCase {
 
-
     /**
      * @var Store
      */
@@ -76,6 +75,42 @@ class SupportTest extends \PHPUnit_Framework_TestCase {
     public function testWrapTag() {
 //        $build = new \qfq\BuildFormPlain(array(), array(), array());
 
+        $result = Support::wrapTag("", '');
+        $this->assertEquals('', $result);
+
+        $result = Support::wrapTag(" ", '');
+        $this->assertEquals('', $result);
+
+        $result = Support::wrapTag("", ' ');
+        $this->assertEquals(' ', $result);
+
+        $result = Support::wrapTag(" ", ' ');
+        $this->assertEquals(' ', $result);
+
+        $result = Support::wrapTag("", '', true);
+        $this->assertEquals('', $result);
+
+        $result = Support::wrapTag(" ", '', true);
+        $this->assertEquals('', $result);
+
+        $result = Support::wrapTag("", ' ', true);
+        $this->assertEquals(' ', $result);
+
+        $result = Support::wrapTag(" ", ' ', true);
+        $this->assertEquals(' ', $result);
+
+        $result = Support::wrapTag("<p>", '', true);
+        $this->assertEquals('', $result);
+
+        $result = Support::wrapTag("<p>", '', false);
+        $this->assertEquals('<p></p>', $result);
+
+        $result = Support::wrapTag("<p> ", '', true);
+        $this->assertEquals('', $result);
+
+        $result = Support::wrapTag(" <p>", '', false);
+        $this->assertEquals('<p></p>', $result);
+
         $result = Support::wrapTag("<p class='test'>", 'Hello World', false);
         $this->assertEquals("<p class='test'>Hello World</p>", $result);
 
@@ -88,17 +123,27 @@ class SupportTest extends \PHPUnit_Framework_TestCase {
         $result = Support::wrapTag("<p class='test'>", '', true);
         $this->assertEquals('', $result);
 
-        $result = Support::wrapTag("<p>", '', true);
-        $this->assertEquals('', $result);
-
-        $result = Support::wrapTag("<p>", '', false);
-        $this->assertEquals('<p></p>', $result);
-
         $result = Support::wrapTag("<p>", 'Hello World', true);
         $this->assertEquals('<p>Hello World</p>', $result);
 
         $result = Support::wrapTag("<p>", 'Hello World', false);
         $this->assertEquals('<p>Hello World</p>', $result);
+
+        $result = Support::wrapTag("<p><i>", 'Hello World', false);
+        $this->assertEquals('<p><i>Hello World</i></p>', $result);
+
+        $result = Support::wrapTag("  <p>  <i>  ", 'Hello World', false);
+        $this->assertEquals('<p><i>Hello World</i></p>', $result);
+
+        $result = Support::wrapTag("<p><i><strong>", 'Hello World', false);
+        $this->assertEquals('<p><i><strong>Hello World</strong></i></p>', $result);
+
+        $result = Support::wrapTag("<p class='test'><i>", 'Hello World', false);
+        $this->assertEquals("<p class='test'><i>Hello World</i></p>", $result);
+
+        $result = Support::wrapTag("<p class='test1'><i class='test2'><strong class='test3'>", 'Hello World', false);
+        $this->assertEquals("<p class='test1'><i class='test2'><strong class='test3'>Hello World</strong></i></p>", $result);
+
     }
 
     public function testDateTime2mysql() {
@@ -514,6 +559,14 @@ class SupportTest extends \PHPUnit_Framework_TestCase {
 
     }
 
+    public function testUnWrapTag() {
+        $this->assertEquals('', Support::unWrapTag('', ''));
+        $this->assertEquals('', Support::unWrapTag('<p>', ''));
+        $this->assertEquals('Hello World', Support::unWrapTag('<p>', 'Hello World'));
+        $this->assertEquals('Hello World', Support::unWrapTag('<p>', '<p>Hello World</p>'));
+    }
+
+
     protected function setUp() {
         parent::setUp();
 
diff --git a/extension/qfq/tests/phpunit/fixtures/TestDirty.sql b/extension/qfq/tests/phpunit/fixtures/TestDirty.sql
index ce620da2d0515f02722f15a43020fe5a3787eb13..338e5f5e25dedb887f4d448de4795602bcea4115 100644
--- a/extension/qfq/tests/phpunit/fixtures/TestDirty.sql
+++ b/extension/qfq/tests/phpunit/fixtures/TestDirty.sql
@@ -1,12 +1,14 @@
 DELETE FROM Dirty;
 
-DELETE FROM Form WHERE name LIKE 'lock%';
+DELETE FROM Form
+WHERE name LIKE 'lock%';
 
 # FormEditor: Small
-INSERT INTO Form ( name, title, noteInternal, tableName, permitNew, permitEdit, render, multiSql, parameter, dirtyMode) VALUES
-  ( 'lockNone', 'Text None', 'note internal', 'Person', 'always', 'always', 'bootstrap', '', '', 'none'),
-  ( 'lockAdvisory', 'Text Advisory', 'note internal', 'Person', 'always', 'always', 'bootstrap', '', '', 'advisory'),
-  ( 'lockExclusive', 'Text Exclusive', 'note internal', 'Person', 'always', 'always', 'bootstrap', '', '', 'exclusive'),
-  ( 'lockAdvisory2', 'Text Advisory', 'note internal', 'Person', 'always', 'always', 'bootstrap', '', '', 'advisory'),
-  ( 'lockExclusive2', 'Text Exclusive', 'note internal', 'Person', 'always', 'always', 'bootstrap', '', '', 'exclusive');
+INSERT INTO Form (name, title, noteInternal, tableName, permitNew, permitEdit, render, multiSql, parameter, dirtyMode)
+VALUES
+  ('lockNone', 'Text None', 'note internal', 'Person', 'always', 'always', 'bootstrap', '', '', 'none'),
+  ('lockAdvisory', 'Text Advisory', 'note internal', 'Person', 'always', 'always', 'bootstrap', '', '', 'advisory'),
+  ('lockExclusive', 'Text Exclusive', 'note internal', 'Person', 'always', 'always', 'bootstrap', '', '', 'exclusive'),
+  ('lockAdvisory2', 'Text Advisory', 'note internal', 'Person', 'always', 'always', 'bootstrap', '', '', 'advisory'),
+  ('lockExclusive2', 'Text Exclusive', 'note internal', 'Person', 'always', 'always', 'bootstrap', '', '', 'exclusive');
 
diff --git a/javascript/src/Element/FormGroup.js b/javascript/src/Element/FormGroup.js
index b86623e3e2f043d55327dd90b9cc43f6f0ea640b..d2f298b307d06f92f66e21d429c00f81da775cf8 100644
--- a/javascript/src/Element/FormGroup.js
+++ b/javascript/src/Element/FormGroup.js
@@ -141,12 +141,12 @@ QfqNS.Element = QfqNS.Element || {};
         this.$element.prop('disabled', !enabled);
 
         if (enabled) {
-            this.$formGroup.removeClass("text-muted");
-            this.$label.removeClass("disabled");
+            //this.$formGroup.removeClass("text-muted");
+            //this.$label.removeClass("disabled");
             this.$element.parents("div.radio").removeClass("disabled");
         } else {
-            this.$formGroup.addClass("text-muted");
-            this.$label.addClass("disabled");
+            //this.$formGroup.addClass("text-muted");
+            //this.$label.addClass("disabled");
             this.$element.parents("div.radio").addClass("disabled");
         }
     };
diff --git a/javascript/src/QfqForm.js b/javascript/src/QfqForm.js
index dbdd2a27b568056d4627828130f9bacdef6f4e20..31e1a1c0bca3cf0b987fe799e4313da61839fbf1 100644
--- a/javascript/src/QfqForm.js
+++ b/javascript/src/QfqForm.js
@@ -395,6 +395,10 @@ var QfqNS = QfqNS || {};
         $inputFile.prop("disabled", false);
         $inputFile.removeClass('hidden');
 
+        if ($inputFile.data('required')=='required') {
+            $inputFile.prop("required", true);
+        }
+
         $inputFile.val("");
 
         this.form.markChanged();
diff --git a/less/qfq-bs.css.less b/less/qfq-bs.css.less
index 4d926907e163de1705288be5a13a3afb961f41f3..566f91a0d81d4200a58130f66ad38d96e800627f 100644
--- a/less/qfq-bs.css.less
+++ b/less/qfq-bs.css.less
@@ -86,9 +86,9 @@ i.@{spinner_class} {
 .required-field:after {
   color: #d00;
   content: "*";
-  position: absolute;
+  //position: absolute;
   margin-left: 3px;
-  top: 10px;
+  //top: 10px;
 }
 
 .qfq-table-50 {
@@ -158,6 +158,10 @@ i.@{spinner_class} {
   padding-top: 7px;
 }
 
+.control-label .small, .control-label small {
+  font-weight: normal;
+}
+
 // Fabric Plugin classes
 .fabric-text {
   width: 100%;
@@ -483,4 +487,8 @@ i.@{spinner_class} {
     -webkit-transform: rotate(359deg);
     transform: rotate(359deg);
   }
+}
+
+a.noclick {
+  pointer-events: none;
 }
\ No newline at end of file
diff --git a/test.html b/test.html
index 26c2263d8869112c3875074eeae52aa2dd7273e0..d09bd02730b68966379aa297cc4c8de21d474f15 100644
--- a/test.html
+++ b/test.html
@@ -1,22 +1,17 @@
-<!--  CONTENT ELEMENT, uid:42/qfq_qfq [begin] -->
-<div id="c42"><h1>BROKEN data!!!!!</h1>
+<div class="col-md-6 col-sm-9">
 
-    <div style="height: 1024px; width: 640px;"><h3>Number requests per Institute</h3>
-        <canvas id="barchart" width="1240" height="640"></canvas>
+    <!--  CONTENT ELEMENT, uid:4/html [begin] -->
+    <div id="c4">
+        <!--  Raw HTML content: [begin] -->
+        <a href="?u10" class="button-big blue play">U10</a>
+        <a href="?u12" class="button-big blue crayon">U12</a>
+        <a href="?u14" class="button-big blue library">U14</a>
+        <a href="?fs" class="button-big blue promo font-big">Frühstudium</a>
+        <a href="?u18" class="button-big blue blackboard">U18</a>
+        <a href="?olympics" class="button-big blue track font-big">Olympics</a>
+        <!--  Raw HTML content: [end] -->
     </div>
-    <script src="typo3conf/ext/qfq/Resources/Public/JavaScript/Chart.min.js"></script>
-    <script> $(function () {
-        var ctx = document.getElementById("barchart");
-        var barChart = new Chart(ctx, {
-            type: 'horizontalBar',
-            data: {
-                labels: ['Theologische Fakultät', 'Rechtswissenschaftliche Fakultät', 'Wirtschaftwissenschaftliche Fakultät', 'Medizinische Fakultät', 'Vetsuisse-Fakultät', 'Philosophische Fakultät', 'Mathematisch-naturwissenschaftliche Fakultät'],
-                datasets: [{
-                    data: ['3', '1', '12', '12', '1', '16', '10'],
-                    backgroundColor: ['rgba(255, 99, 132, 1)', 'rgba(54, 162, 235, 1)', 'rgba(255, 206, 86, 1)', 'rgba(75, 192, 192, 1)', 'rgba(153, 102, 255, 1)', 'rgba(255, 159, 64, 1)', 'rgba(0, 255, 0, 1)'],
-                    label: "Requests"
-                }]
-            }
-        });
-    }); </script>
+    <!--  CONTENT ELEMENT, uid:4/html [end] -->
+
+
 </div>
\ No newline at end of file