From 0c9f96b5a550505f7ae9e1fd7a5b8e708841999b Mon Sep 17 00:00:00 2001
From: Carsten  Rose <carsten.rose@math.uzh.ch>
Date: Fri, 29 Apr 2016 20:07:03 +0200
Subject: [PATCH] Bootstrap grip columns are configurable. A default on the
 form and, if necessary, per formelement. The default is now changed from
 2,6,4 to 2,9,1 UsersManual/index.rst: updated to the new behaviour.
 Support.php: setIfNotSet() has a new third parameter. AbstractBuildForm.php,
 BuildFormBootstrap.php, BuildFormPlain.php, BuildFormPlain.php,
 QuickFormQuery.php: New abstract function fillWrapLabelInputNote().

---
 extension/Documentation/UsersManual/Index.rst | 162 +++++++++---------
 extension/qfq/qfq/AbstractBuildForm.php       |   7 +
 extension/qfq/qfq/BuildFormBootstrap.php      |  39 +++--
 extension/qfq/qfq/BuildFormPlain.php          |   3 +
 extension/qfq/qfq/BuildFormTable.php          |   3 +
 extension/qfq/qfq/Constants.php               |   4 +
 extension/qfq/qfq/QuickFormQuery.php          |   6 +-
 extension/qfq/qfq/helper/Support.php          |  10 +-
 extension/qfq/sql/formEditor.sql              |  84 ++++-----
 9 files changed, 181 insertions(+), 137 deletions(-)

diff --git a/extension/Documentation/UsersManual/Index.rst b/extension/Documentation/UsersManual/Index.rst
index 215bd8dc0..f3e5300bb 100644
--- a/extension/Documentation/UsersManual/Index.rst
+++ b/extension/Documentation/UsersManual/Index.rst
@@ -387,9 +387,9 @@ Form: basic setup
 +------------------------+----------------------------------------------------------+-----------------------------------------------------------------------------------------+
 |forwardPage             | string / query                                           | If $forward=="page": page to jump to                                                    |
 +------------------------+----------------------------------------------------------+-----------------------------------------------------------------------------------------+
-|bsLabelColumns          | string                                                   | title: default number of 'bootstrap 12grid' columns                                     |
-+------------------------+----------------------------------------------------------+-----------------------------------------------------------------------------------------+
-|bsInputColumns          | string                                                   | input: default number of 'bootstrap 12grid' columns                                     |
+|bsLabelColumns          | string                                                   | The bootstrap grid system is based on 12 columns. The sum of *bsLabelColumns*,          |
++------------------------+----------------------------------------------------------+ *bsInputColumns* and *bsNoteColumns* should be 12. These values here are the base values|
+|bsInputColumns          | string                                                   | for all formelements. Exceptions per formelement can be specified per formelement.      |
 +------------------------+----------------------------------------------------------+-----------------------------------------------------------------------------------------+
 |bsNoteColumns           | string                                                   | note: default number of 'bootstrap 12grid' columns                                      |
 +------------------------+----------------------------------------------------------+-----------------------------------------------------------------------------------------+
@@ -480,81 +480,87 @@ Type: pill
 Class: Native
 -------------
 
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-| Name         | Type                        | Description                                                                                       |
-+==============+=============================+===================================================================================================+
-| id           | int                         |                                                                                                   |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-| formId       | int                         |                                                                                                   |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|feIdContainer | int                         |                                                                                                   |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|enabled       | enum('yes'|'no')            |                                                                                                   |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|dynamicUpdate | enum('yes'|'no')            | In the browser, formelements with "dynamicUpdate='yes'"  will be updated depending on user input. |
-|              |                             | :ref:`dynamic-update`                                                                             |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|name          | string                      |                                                                                                   |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|label         | string                      | Label of formelement. Depending on layout model, left or on top of the formelement                |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|mode          | enum('show', 'readonly',    | Default: show - *Show*: regular user input field. *Readonly* : user can't change any data.        |
-|              | 'required',  'lock',        | *Important* : user manipulated data won't be saved. *Required* User has to specify a value.       |
-|              | 'disabled' )                | Typically, an <empty string> represents 'no value'. *Lock* form element is read only and grayed   |
-|              |                             | out, *Disabled*: form element is not visible                                                      |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|class         | enum('native', 'action',    | Details below.                                                                                    |
-|              | 'container')                |                                                                                                   |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|type          | enum('checkbox', 'date', 'time', 'datetime',  'dateJQW', 'datetimeJQW', 'gridJQW', 'hidden', 'text', 'note', 'password',        |
-|              | 'radio', 'select', 'subrecord', 'textarea', 'timeJQW', 'upload', 'fieldset', 'pill', 'before_load', 'before_save',              |
-|              | 'before_insert', 'before_update', 'before_delete', 'after_load', 'after_save', 'after_insert', 'after_update', 'after_delete',  |
-|              | 'feGroup', 'sendmail')                                                                                                          |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|checkType     | enum('min|max', 'pattern',  |                                                                                                   |
-|              | 'number', 'email')          |                                                                                                   |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|checkPattern  | 'regexp'                    |if $check_type=='pattern': pattern to match                                                        |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|onChange      | string                      |list of 'form element names' of current form, separated by ', ', If one of the named form elements |
-|              |                             | change, reload own data / status / mode                                                           |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|ord           | string                      |display order of form elements ('order' is a reserved keyword)                                     |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|tabindex      | string                      |HTML tabindex attribute                                                                            |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|size          | string                      |Visible length of input element. Might be ommited, depending on the choosen form layout.           |
-|              |                             |Format: <width>,<height> (in characters)                                                           |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|maxLength     | string                      |Maximum characters for input.                                                                      |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|note          | string                      |Note of formelement. Depending on layout model, right or below of the formelement                  |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|tooltip       | text                        |Display this text as tooltip on mouse over                                                         |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|placeholder   | string                      |Text, displayed inside the input element in light grey                                             |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|clientJs      | text                        |Javascript called on 'on change' formelements                                                      |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|value         | text                        |Default value                                                                                      |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|sql1          | text                        |SQL query  ('sql' is a reserved keyword)                                                           |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|sql2          | text                        |second SQL query                                                                                   |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|parameter     | text                        |might contain misc parameter. Depends on the type of formelement.                                  |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|feGroup       | string                      | Comma-separated list of Typo3 FE Group ID. NOT SURE IF THIS WILL BE IMPLEMENTED. Native           |
-|              |                             | formElements, fieldsets and pills can be assigned to feGroups. Group status: show, hidden,        |
-|              |                             | disabled. Group Access: FE-Groups. User will be assigned to FE-Groups and the form defintion      |
-|              |                             | reference such FE-groups. Easy way of granting permission.                                        |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|deleted       | string                      |'yes'|'no'.                                                                                        |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|modified      | timestamp                   |updated autmatically through stored procedure                                                      |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
-|created       | datetime                    |set once through QFQ                                                                               |
-+--------------+-----------------------------+---------------------------------------------------------------------------------------------------+
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+| Name          | Type                        | Description                                                                                       |
++===============+=============================+===================================================================================================+
+| id            | int                         |                                                                                                   |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+| formId        | int                         |                                                                                                   |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|feIdContainer  | int                         |                                                                                                   |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|enabled        | enum('yes'|'no')            |                                                                                                   |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|dynamicUpdate  | enum('yes'|'no')            | In the browser, formelements with "dynamicUpdate='yes'"  will be updated depending on user input. |
+|               |                             | :ref:`dynamic-update`                                                                             |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|name           | string                      |                                                                                                   |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|label          | string                      | Label of formelement. Depending on layout model, left or on top of the formelement                |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|mode           | enum('show', 'readonly',    | Default: show - *Show*: regular user input field. *Readonly* : user can't change any data.        |
+|               | 'required',  'lock',        | *Important* : user manipulated data won't be saved. *Required* User has to specify a value.       |
+|               | 'disabled' )                | Typically, an <empty string> represents 'no value'. *Lock* form element is read only and grayed   |
+|               |                             | out, *Disabled*: form element is not visible                                                      |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|class          | enum('native', 'action',    | Details below.                                                                                    |
+|               | 'container')                |                                                                                                   |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|type           | enum('checkbox', 'date', 'time', 'datetime',  'dateJQW', 'datetimeJQW', 'gridJQW', 'hidden', 'text', 'note', 'password',        |
+|               | 'radio', 'select', 'subrecord', 'textarea', 'timeJQW', 'upload', 'fieldset', 'pill', 'before_load', 'before_save',              |
+|               | 'before_insert', 'before_update', 'before_delete', 'after_load', 'after_save', 'after_insert', 'after_update', 'after_delete',  |
+|               | 'feGroup', 'sendmail')                                                                                                          |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|checkType      | enum('min|max', 'pattern',  |                                                                                                   |
+|               | 'number', 'email')          |                                                                                                   |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|checkPattern   | 'regexp'                    |if $check_type=='pattern': pattern to match                                                        |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|onChange       | string                      |list of 'form element names' of current form, separated by ', ', If one of the named form elements |
+|               |                             | change, reload own data / status / mode                                                           |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|ord            | string                      |display order of form elements ('order' is a reserved keyword)                                     |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|tabindex       | string                      |HTML tabindex attribute                                                                            |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|size           | string                      |Visible length of input element. Might be ommited, depending on the choosen form layout.           |
+|               |                             |Format: <width>,<height> (in characters)                                                           |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|bsLabelColumns | string                      | Number of bootstrap grid columns for label. By default empty, value inherits from the form.       |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|bsInputColumns | string                      | Number of bootstrap grid columns for input. By default empty, value inherits from the form.       |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|bsNoteColumns  | string                      | Number of bootstrap grid columns for note. By default empty, value inherits from the form.        |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|maxLength      | string                      |Maximum characters for input.                                                                      |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|note           | string                      |Note of formelement. Depending on layout model, right or below of the formelement                  |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|tooltip        | text                        |Display this text as tooltip on mouse over                                                         |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|placeholder    | string                      |Text, displayed inside the input element in light grey                                             |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|clientJs       | text                        |Javascript called on 'on change' formelements                                                      |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|value          | text                        |Default value                                                                                      |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|sql1           | text                        |SQL query  ('sql' is a reserved keyword)                                                           |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|sql2           | text                        |second SQL query                                                                                   |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|parameter      | text                        |might contain misc parameter. Depends on the type of formelement.                                  |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|feGroup        | string                      | Comma-separated list of Typo3 FE Group ID. NOT SURE IF THIS WILL BE IMPLEMENTED. Native           |
+|               |                             | formElements, fieldsets and pills can be assigned to feGroups. Group status: show, hidden,        |
+|               |                             | disabled. Group Access: FE-Groups. User will be assigned to FE-Groups and the form defintion      |
+|               |                             | reference such FE-groups. Easy way of granting permission.                                        |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|deleted        | string                      |'yes'|'no'.                                                                                        |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|modified       | timestamp                   |updated autmatically through stored procedure                                                      |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
+|created        | datetime                    |set once through QFQ                                                                               |
++---------------+-----------------------------+---------------------------------------------------------------------------------------------------+
 
 
 +------------------+----------+---------+-------------+----------+--------+-------+------+----------+-------+--------+-----------+----------+---------+--------+
diff --git a/extension/qfq/qfq/AbstractBuildForm.php b/extension/qfq/qfq/AbstractBuildForm.php
index 4ef9cfacb..b5ccec7b5 100644
--- a/extension/qfq/qfq/AbstractBuildForm.php
+++ b/extension/qfq/qfq/AbstractBuildForm.php
@@ -355,6 +355,11 @@ abstract class AbstractBuildForm {
             // Some Defaults
             $formElement = Support::setFeDefaults($formElement);
 
+            $label = ($formElement[F_BS_LABEL_COLUMNS] == '') ? $this->formSpec[F_BS_LABEL_COLUMNS] : $formElement[F_BS_LABEL_COLUMNS];
+            $input = ($formElement[F_BS_INPUT_COLUMNS] == '') ? $this->formSpec[F_BS_INPUT_COLUMNS] : $formElement[F_BS_INPUT_COLUMNS];
+            $note = ($formElement[F_BS_NOTE_COLUMNS] == '') ? $this->formSpec[F_BS_NOTE_COLUMNS] : $formElement[F_BS_NOTE_COLUMNS];
+            $this->fillWrapLabelInputNote($label, $input, $note);
+
             // Get default value
             $value = ($formElement['value'] === '') ? $this->store->getVar($formElement['name'], $storeUse,
                 $formElement['checkType']) : $formElement['value'];
@@ -404,6 +409,8 @@ abstract class AbstractBuildForm {
         return $html;
     }
 
+    abstract public function fillWrapLabelInputNote($label, $input, $note);
+
     /**
      * Create a hidden sip, based on latest STORE_SIP Values. Return complete HTML 'hidden' element.
      *
diff --git a/extension/qfq/qfq/BuildFormBootstrap.php b/extension/qfq/qfq/BuildFormBootstrap.php
index 3ab2562bd..e60a29338 100644
--- a/extension/qfq/qfq/BuildFormBootstrap.php
+++ b/extension/qfq/qfq/BuildFormBootstrap.php
@@ -46,34 +46,41 @@ class BuildFormBootstrap extends AbstractBuildForm {
      */
     public function fillWrap() {
 
-
 //        $this->wrap[WRAP_SETUP_OUTER][WRAP_SETUP_START] = '<div class="tab-content">';
 //        $this->wrap[WRAP_SETUP_OUTER][WRAP_SETUP_END] = '</div>';
 
-        $this->wrap[WRAP_SETUP_TITLE][WRAP_SETUP_START] = '<div class="row hidden-xs"><div class="col-md-12"><h1>';
-        $this->wrap[WRAP_SETUP_TITLE][WRAP_SETUP_END] = '</h1></div></div>';
+        $this->wrap[WRAP_SETUP_TITLE][WRAP_SETUP_START] = "<div class='row hidden-xs'><div class='col-md-12'><h1>";
+        $this->wrap[WRAP_SETUP_TITLE][WRAP_SETUP_END] = "</h1></div></div>";
 
         // Element: Label + Input + Note
-        $this->wrap[WRAP_SETUP_ELEMENT][WRAP_SETUP_START] = '<div class="form-group">';
-        $this->wrap[WRAP_SETUP_ELEMENT][WRAP_SETUP_END] = '</div>';
-
-        $this->wrap[WRAP_SETUP_LABEL][WRAP_SETUP_START] = '<div class="col-md-2">';
-        $this->wrap[WRAP_SETUP_LABEL][WRAP_SETUP_END] = '</div>';
-        $this->wrap[WRAP_SETUP_INPUT][WRAP_SETUP_START] = '<div class="col-md-6">';
-        $this->wrap[WRAP_SETUP_INPUT][WRAP_SETUP_END] = '</div>';
-        $this->wrap[WRAP_SETUP_NOTE][WRAP_SETUP_START] = '<div class="col-md-4">';
-        $this->wrap[WRAP_SETUP_NOTE][WRAP_SETUP_END] = '</div>';
+        $this->wrap[WRAP_SETUP_ELEMENT][WRAP_SETUP_START] = "<div class='form-group'>";
+        $this->wrap[WRAP_SETUP_ELEMENT][WRAP_SETUP_END] = "</div>";
 
-        $this->wrap[WRAP_SETUP_SUBRECORD][WRAP_SETUP_START] = '<div class="col-md-12">';
-        $this->wrap[WRAP_SETUP_SUBRECORD][WRAP_SETUP_END] = '</div>';
+        $this->wrap[WRAP_SETUP_SUBRECORD][WRAP_SETUP_START] = "<div class='col-md-12'>";
+        $this->wrap[WRAP_SETUP_SUBRECORD][WRAP_SETUP_END] = "</div>";
 
-        $this->wrap[WRAP_SETUP_IN_FIELDSET][WRAP_SETUP_START] = '<p>';
-        $this->wrap[WRAP_SETUP_IN_FIELDSET][WRAP_SETUP_END] = '</p>';
+        $this->wrap[WRAP_SETUP_IN_FIELDSET][WRAP_SETUP_START] = "<p>";
+        $this->wrap[WRAP_SETUP_IN_FIELDSET][WRAP_SETUP_END] = "</p>";
 
 //        $this->feDivClass['radio'] = 'radio';
 //        $this->feDivClass['checkbox'] = 'checkbox';
     }
 
+    /**
+     * @param $label
+     * @param $input
+     * @param $note
+     */
+    public function fillWrapLabelInputNote($label, $input, $note) {
+        $this->wrap[WRAP_SETUP_LABEL][WRAP_SETUP_START] = "<div class='col-md-$label'>";
+        $this->wrap[WRAP_SETUP_LABEL][WRAP_SETUP_END] = "</div>";
+        $this->wrap[WRAP_SETUP_INPUT][WRAP_SETUP_START] = "<div class='col-md-$input'>";
+        $this->wrap[WRAP_SETUP_INPUT][WRAP_SETUP_END] = "</div>";
+        $this->wrap[WRAP_SETUP_NOTE][WRAP_SETUP_START] = "<div class='col-md-$note'>";
+        $this->wrap[WRAP_SETUP_NOTE][WRAP_SETUP_END] = "</div>";
+
+    }
+
     /**
      * @return string
      */
diff --git a/extension/qfq/qfq/BuildFormPlain.php b/extension/qfq/qfq/BuildFormPlain.php
index 78b76d0da..116573c7e 100644
--- a/extension/qfq/qfq/BuildFormPlain.php
+++ b/extension/qfq/qfq/BuildFormPlain.php
@@ -41,6 +41,9 @@ class BuildFormPlain extends AbstractBuildForm {
 
     }
 
+    public function fillWrapLabelInputNote($label, $input, $note) {
+
+    }
     /**
      * @return string
      */
diff --git a/extension/qfq/qfq/BuildFormTable.php b/extension/qfq/qfq/BuildFormTable.php
index c3977fc63..f993de756 100644
--- a/extension/qfq/qfq/BuildFormTable.php
+++ b/extension/qfq/qfq/BuildFormTable.php
@@ -45,6 +45,9 @@ class BuildFormTable extends AbstractBuildForm {
 
     }
 
+    public function fillWrapLabelInputNote($label, $input, $note) {
+
+    }
     /**
      * @return string
      */
diff --git a/extension/qfq/qfq/Constants.php b/extension/qfq/qfq/Constants.php
index 7f9d378a0..e06175cc5 100644
--- a/extension/qfq/qfq/Constants.php
+++ b/extension/qfq/qfq/Constants.php
@@ -33,6 +33,10 @@ const FORM_FORWARD_MODE_NO = 'no';
 const FORM_FORWARD_MODE_AUTO = 'auto';
 const FORM_FORWARD_MODE_PAGE = 'page';
 
+const F_BS_LABEL_COLUMNS = 'bsLabelColumns';
+const F_BS_INPUT_COLUMNS = 'bsInputColumns';
+const F_BS_NOTE_COLUMNS = 'bsNoteColumns';
+
 const SESSION_FE_USER_UID = 'fe_user_uid';
 
 const RETURN_URL = 'return_url';
diff --git a/extension/qfq/qfq/QuickFormQuery.php b/extension/qfq/qfq/QuickFormQuery.php
index 1ae56f358..a37085a41 100644
--- a/extension/qfq/qfq/QuickFormQuery.php
+++ b/extension/qfq/qfq/QuickFormQuery.php
@@ -294,8 +294,10 @@ class QuickFormQuery {
         HelperFormElement::explodeParameter($this->formSpec);
 
         # Set defaults:
-        if (!isset($this->formSpec['class']))
-            $this->formSpec['class'] = '';
+        Support::setIfNotSet($this->formSpec, 'class', '');
+        Support::setIfNotSet($this->formSpec, F_BS_LABEL_COLUMNS, 2, '');
+        Support::setIfNotSet($this->formSpec, F_BS_INPUT_COLUMNS, 9, '');
+        Support::setIfNotSet($this->formSpec, F_BS_NOTE_COLUMNS, 1, '');
 
         // Clear
         $this->store->setVar(SYSTEM_FORM_ELEMENT, '', STORE_SYSTEM);
diff --git a/extension/qfq/qfq/helper/Support.php b/extension/qfq/qfq/helper/Support.php
index db3c5ac67..71417abb5 100644
--- a/extension/qfq/qfq/helper/Support.php
+++ b/extension/qfq/qfq/helper/Support.php
@@ -519,11 +519,17 @@ class Support {
      * @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.
      */
-    public static function setIfNotSet(array &$arr, $index, $value = '') {
+    public static function setIfNotSet(array &$arr, $index, $value = '', $overwriteThis = false) {
 
-        if (!isset($arr[$index]))
+        if (!isset($arr[$index])) {
             $arr[$index] = $value;
+        }
+
+        if ($overwriteThis !== false && $arr[$index] === $overwriteThis) {
+            $arr[$index] = $value;
+        }
     }
 
     /**
diff --git a/extension/qfq/sql/formEditor.sql b/extension/qfq/sql/formEditor.sql
index f17b231e9..84ce8f3aa 100644
--- a/extension/qfq/sql/formEditor.sql
+++ b/extension/qfq/sql/formEditor.sql
@@ -81,6 +81,9 @@ CREATE TABLE IF NOT EXISTS `FormElement` (
 
   `size`            VARCHAR(255)                                                                            NOT NULL  DEFAULT '',
   `maxLength`       VARCHAR(255)                                                                            NOT NULL  DEFAULT '',
+  `bsLabelColumns` VARCHAR(255) NOT NULL  DEFAULT '',
+  `bsInputColumns` VARCHAR(255) NOT NULL  DEFAULT '',
+  `bsNoteColumns`  VARCHAR(255) NOT NULL  DEFAULT '',
   `note`            TEXT                                                                                    NOT NULL,
   `tooltip`         VARCHAR(255)                                                                            NOT NULL  DEFAULT '',
   `placeholder`     VARCHAR(255)                                                                            NOT NULL  DEFAULT '',
@@ -131,9 +134,9 @@ VALUES
   (1, 'multi', 'Multi', 'show', 'pill', 'all', 'container', 40, 0, 0, '', '', '', '', '', '', 0, ''),
   (1, 'formelement', 'Formelement', 'show', 'pill', 'all', 'container', 50, 0, 0, '', '', '', '', '', '', 0, ''),
 
-  (1, 'id', 'id', 'readonly', 'text', 'all', 'native', 100, 10, 11, '', '', '', '', '', '', 1, ''),
-  (1, 'name', 'Name', 'required', 'text', 'all', 'native', 120, 40, 255, '', '', '', '', '', 'autofocus', 1, ''),
-  (1, 'title', 'Title', 'show', 'text', 'all', 'native', 130, 40, 255, '', '', '', '', '', '', 1, ''),
+  (1, 'id', 'id', 'readonly', 'text', 'all', 'native', 100, 0, 11, '', '', '', '', '', '', 1, ''),
+  (1, 'name', 'Name', 'required', 'text', 'all', 'native', 120, 0, 255, '', '', '', '', '', 'autofocus', 1, ''),
+  (1, 'title', 'Title', 'show', 'text', 'all', 'native', 130, 0, 255, '', '', '', '', '', '', 1, ''),
   (1, 'noteInternal', 'Note', 'show', 'text', 'all', 'native', 140, '40,3', 0, '', '', '', '', '', '', 1, ''),
   (1, 'tableName', 'Table', 'required', 'select', 'all', 'native', 150, 0, 0, '', '', '', '{{!SHOW tables}}', '', 'emptyItemAtStart', 1, ''),
 
@@ -143,23 +146,23 @@ VALUES
   (1, 'showButton', 'Show button', 'show', 'checkbox', 'all', 'native', 200, 0, 0, '', '', '', '', '', 'checkBoxMode = multi\norientation=vertical', 2, ''),
 
   (1, 'forwardMode', 'Forward', 'show', 'radio', 'all', 'native', 260, 0, 0, '', '', '', '', '', '', 3, ''),
-  (1, 'forwardPage', 'Forward Page', 'show', 'text', 'all', 'native', 270, 40, 255, '', '', '', '', '', '', 3, ''),
+  (1, 'forwardPage', 'Forward Page', 'show', 'text', 'all', 'native', 270, 0, 255, '', '', '', '', '', '', 3, ''),
   (1, 'parameter', 'Parameter', 'show', 'text', 'all', 'native', 275, '40,3', 0, '', '', '', '', '', '', 3, ''),
 
-  (1, 'bsLabelColumns', 'BS Label Columns', 'show', 'text', 'all', 'native', 280, 40, 250, '', '', '', '', '', '', 3, ''),
-  (1, 'bsInputColumns', 'BS Input Columns', 'show', 'text', 'all', 'native', 290, 40, 250, '', '', '', '', '', '', 3, ''),
-  (1, 'bsNoteColumns', 'BS Note Columns', 'show', 'text', 'all', 'native', 300, 40, 250, '', '', '', '', '', '', 3, ''),
+  (1, 'bsLabelColumns', 'BS Label Columns', 'show', 'text', 'all', 'native', 280, 0, 250, '', '', '', '', '', '', 3, ''),
+  (1, 'bsInputColumns', 'BS Input Columns', 'show', 'text', 'all', 'native', 290, 0, 250, '', '', '', '', '', '', 3, ''),
+  (1, 'bsNoteColumns', 'BS Note Columns', 'show', 'text', 'all', 'native', 300, 0, 250, '', '', '', '', '', '', 3, ''),
 
   (1, 'deleted', 'Deleted', 'show', 'checkbox', 'all', 'native', 405, 0, 0, '', '', '', '', '', '', 3, ''),
-  (1, 'modified', 'Modified', 'readonly', 'text', 'all', 'native', 410, 40, 20, '', '', '', '', '', '', 3, ''),
-  (1, 'created', 'Created', 'readonly', 'text', 'all', 'native', 420, 40, 20, '', '', '', '', '', '', 3, ''),
+  (1, 'modified', 'Modified', 'readonly', 'text', 'all', 'native', 410, 0, 20, '', '', '', '', '', '', 3, ''),
+  (1, 'created', 'Created', 'readonly', 'text', 'all', 'native', 420, 0, 20, '', '', '', '', '', '', 3, ''),
 
   (1, 'multi', 'Multi', 'show', 'fieldset', 'all', 'native', 210, 0, 0, '', '', '', '', '', '', 4, ''),
   (1, 'multiMode', 'Multi Mode', 'show', 'radio', 'all', 'native', 220, 0, 0, '', '', '', '', '', '', 4, ''),
   (1, 'multiSql', 'Multi SQL', 'show', 'text', 'all', 'native', 230, '40,3', 0, '', '', '', '', '', '', 4, ''),
-  (1, 'multiDetailForm', 'Multi Detail Form', 'show', 'text', 'all', 'native', 240, 40, 255, '', '', '', '', '', '', 4,
+  (1, 'multiDetailForm', 'Multi Detail Form', 'show', 'text', 'all', 'native', 240, 0, 255, '', '', '', '', '', '', 4,
    ''),
-  (1, 'multiDetailFormParameter', 'Multi Detail Form Parameter', 'show', 'text', 'all', 'native', 250, 40, 255, '', '',
+  (1, 'multiDetailFormParameter', 'Multi Detail Form Parameter', 'show', 'text', 'all', 'native', 250, 0, 255, '', '',
    '', '',
    '', '', 4, ''),
 
@@ -188,15 +191,15 @@ VALUES
 INSERT INTO FormElement (formId, name, label, mode, type, checkType, class, ord, size, maxLength, note, clientJs, value, sql1, sql2, parameter, feIdContainer, subrecordOption, dynamicUpdate)
 VALUES
 
-  (2, 'id', 'id', 'readonly', 'text', 'all', 'native', 100, 10, 11, '', '', '', '', '', '', 100, '', 'no'),
-  (2, 'formId', 'formId', 'readonly', 'text', 'all', 'native', 110, 40, 255, '', '', '', '', '', '', 100, '', 'no'),
+  (2, 'id', 'id', 'readonly', 'text', 'all', 'native', 100, 0, 11, '', '', '', '', '', '', 100, '', 'no'),
+  (2, 'formId', 'formId', 'readonly', 'text', 'all', 'native', 110, 0, 255, '', '', '', '', '', '', 100, '', 'no'),
   (2, 'feIdContainer', 'Container', 'show', 'select', 'all', 'native', 120, 0, 0, '', '', '',
    '{{!SELECT fe.id, CONCAT(fe.class, " / ", fe.label) FROM FormElement As fe WHERE fe.formId={{formId}} AND fe.class="container" ORDER BY fe.ord }}',
    '', 'emptyItemAtStart', 100, '', 'no'),
   (2, 'enabled', 'Enabled', 'show', 'checkbox', 'all', 'native', 130, 0, 0, '', '', '', '', '', '', 100, '', 'no'),
   (2, 'dynamicUpdate', 'Dynamic Update', 'show', 'checkbox', 'all', 'native', 135, 0, 0, 'This element will be updated on change and trigger other.', '', '', '', '', '', 100, '', 'no'),
-  (2, 'name', 'Name', 'required', 'text', 'all', 'native', 140, 40, 255, '', '', '', '', '', '', 100, '', 'no'),
-  (2, 'label', 'Label', 'show', 'text', 'all', 'native', 150, 40, 255, '', '', '', '', '', '', 100, '', 'no'),
+  (2, 'name', 'Name', 'required', 'text', 'all', 'native', 140, 0, 255, '', '', '', '', '', '', 100, '', 'no'),
+  (2, 'label', 'Label', 'show', 'text', 'all', 'native', 150, 0, 255, '', '', '', '', '', '', 100, '', 'no'),
   (2, 'mode', 'Mode', 'show', 'select', 'all', 'native', 160, 0, 255, '', '', '', '', '', '', 100, '', 'no'),
   (2, 'class', 'Class', 'show', 'select', 'all', 'native', 170, 0, 255, '', '', '{{class:FSRD0:alnumx}}', '', '', '', 100, '', 'yes'),
   (2, 'type', 'Type', 'show', 'select', 'all', 'native', 180, 0, 255, '', '', '', '', '',
@@ -204,24 +207,27 @@ VALUES
    100, '', 'yes'),
   (2, 'subrecordOption', 'Subrecord Option', 'show', 'checkbox', 'all', 'native', 190, 0, 0, '', '', '', '', '', '', 100, '', 'no'),
   (2, 'checkType', 'Check Type', 'show', 'select', 'all', 'native', 200, 0, 255, '', '', '', '', '', '', 101, '', 'no'),
-  (2, 'checkPattern', 'Check Pattern', 'show', 'text', 'all', 'native', 210, 40, 255, '', '', '', '', '', '', 101, '', 'no'),
-  (2, 'onChange', 'JS onChange', 'show', 'text', 'all', 'native', 220, 40, 255, '', '', '', '', '', '', 101, '', 'no'),
-  (2, 'ord', 'Order', 'show', 'text', 'all', 'native', 230, 40, 255, '', '', '', '', '', '', 101, '', 'no'),
-  (2, 'tabindex', 'tabindex', 'show', 'text', 'all', 'native', 240, 40, 255, '', '', '', '', '', '', 101, '', 'no'),
-  (2, 'size', 'Size', 'show', 'text', 'all', 'native', 250, 40, 255, '', '', '', '', '', '', 102, '', 'no'),
-  (2, 'maxLength', 'Maxlength', 'show', 'text', 'all', 'native', 260, 40, 255, '', '', '', '', '', '', 102, '', 'no'),
-  (2, 'note', 'note', 'show', 'text', 'all', 'native', 270, 40, 255, '', '', '', '', '', '', 102, '', 'no'),
-  (2, 'tooltip', 'Tooltip', 'show', 'text', 'all', 'native', 280, 40, 255, '', '', '', '', '', '', 102, '', 'no'),
-  (2, 'placeholder', 'Placeholder', 'show', 'text', 'all', 'native', 290, 40, 255, '', '', '', '', '', '', 102, '', 'no'),
-  (2, 'value', 'value', 'show', 'text', 'all', 'native', 300, 40, 255, '', '', '', '', '', '', 103, '', 'no'),
-  (2, 'sql1', 'sql1', 'show', 'text', 'all', 'native', 310, '70,5', 255, '', '', '', '', '', '', 103, '', 'no'),
-  (2, 'parameter', 'Parameter', 'show', 'text', 'all', 'native', 320, '40,4', 255, '', '', '', '', '', '', 103, '',
+  (2, 'checkPattern', 'Check Pattern', 'show', 'text', 'all', 'native', 210, 0, 255, '', '', '', '', '', '', 101, '', 'no'),
+  (2, 'onChange', 'JS onChange', 'show', 'text', 'all', 'native', 220, 0, 255, '', '', '', '', '', '', 101, '', 'no'),
+  (2, 'ord', 'Order', 'show', 'text', 'all', 'native', 230, 0, 255, '', '', '', '', '', '', 101, '', 'no'),
+  (2, 'tabindex', 'tabindex', 'show', 'text', 'all', 'native', 240, 0, 255, '', '', '', '', '', '', 101, '', 'no'),
+  (2, 'size', 'Size', 'show', 'text', 'all', 'native', 250, 0, 255, '', '', '', '', '', '', 102, '', 'no'),
+  (2, 'bsLabelColumns', 'BS Label Columns', 'show', 'text', 'all', 'native', 260, 0, 255, '', '', '', '', '', '', 102, '', 'no'),
+  (2, 'bsInputColumns', 'BS Input Columns', 'show', 'text', 'all', 'native', 270, 0, 255, '', '', '', '', '', '', 102, '', 'no'),
+  (2, 'bsNoteColumns', 'BS Note Columns', 'show', 'text', 'all', 'native', 280, 0, 255, '', '', '', '', '', '', 102, '', 'no'),
+  (2, 'maxLength', 'Maxlength', 'show', 'text', 'all', 'native', 290, 0, 255, '', '', '', '', '', '', 102, '', 'no'),
+  (2, 'note', 'note', 'show', 'text', 'all', 'native', 300, 0, 255, '', '', '', '', '', '', 102, '', 'no'),
+  (2, 'tooltip', 'Tooltip', 'show', 'text', 'all', 'native', 310, 0, 255, '', '', '', '', '', '', 102, '', 'no'),
+  (2, 'placeholder', 'Placeholder', 'show', 'text', 'all', 'native', 320, 0, 255, '', '', '', '', '', '', 102, '', 'no'),
+  (2, 'value', 'value', 'show', 'text', 'all', 'native', 330, 0, 255, '', '', '', '', '', '', 103, '', 'no'),
+  (2, 'sql1', 'sql1', 'show', 'text', 'all', 'native', 340, '70,5', 255, '', '', '', '', '', '', 103, '', 'no'),
+  (2, 'parameter', 'Parameter', 'show', 'text', 'all', 'native', 350, '40,4', 255, '', '', '', '', '', '', 103, '',
    'no'),
-  (2, 'clientJs', 'ClientJS', 'show', 'text', 'all', 'native', 330, 40, 255, '', '', '', '', '', '', 103, '', 'no'),
-  (2, 'feGroup', 'feGroup', 'show', 'text', 'all', 'native', 340, 40, 255, '', '', '', '', '', '', 104, '', 'no'),
-  (2, 'deleted', 'Deleted', 'show', 'checkbox', 'all', 'native', 350, 0, 0, '', '', '', '', '', '', 104, '', 'no'),
-  (2, 'modified', 'Modified', 'readonly', 'text', 'all', 'native', 360, 40, 20, '', '', '', '', '', '', 104, '', 'no'),
-  (2, 'created', 'Created', 'readonly', 'text', 'all', 'native', 370, 40, 20, '', '', '', '', '', '', 104, '', 'no');
+  (2, 'clientJs', 'ClientJS', 'show', 'text', 'all', 'native', 360, 0, 255, '', '', '', '', '', '', 103, '', 'no'),
+  (2, 'feGroup', 'feGroup', 'show', 'text', 'all', 'native', 370, 0, 255, '', '', '', '', '', '', 104, '', 'no'),
+  (2, 'deleted', 'Deleted', 'show', 'checkbox', 'all', 'native', 380, 0, 0, '', '', '', '', '', '', 104, '', 'no'),
+  (2, 'modified', 'Modified', 'readonly', 'text', 'all', 'native', 390, 0, 20, '', '', '', '', '', '', 104, '', 'no'),
+  (2, 'created', 'Created', 'readonly', 'text', 'all', 'native', 400, 0, 20, '', '', '', '', '', '', 104, '', 'no');
 
 # FormEditor: Small
 INSERT INTO Form (name, title, noteInternal, tableName, permitNew, permitEdit, render, multiSql, parameter) VALUES
@@ -233,9 +239,9 @@ INSERT INTO Form (name, title, noteInternal, tableName, permitNew, permitEdit, r
 INSERT INTO FormElement (id, formId, name, label, mode, type, checkType, class, ord, size, maxLength, note, clientJs, value, sql1, sql2, parameter, feIdContainer, subrecordOption)
 VALUES
 
-  (200, 3, 'name', 'Name', 'show', 'text', 'all', 'native', 10, 50, 255, '', '', '', '', '', '', 0, ''),
-  (201, 3, 'firstname', 'Firstname', 'show', 'text', 'all', 'native', 20, 50, 255, '', '', '', '', '', '', 0, ''),
-  (202, 3, 'birthday', 'Birthday', 'show', 'date', 'all', 'native', 30, 50, 255, '', '', '', '', '', '', 0, '');
+  (200, 3, 'name', 'Name', 'show', 'text', 'all', 'native', 10, 0, 255, '', '', '', '', '', '', 0, ''),
+  (201, 3, 'firstname', 'Firstname', 'show', 'text', 'all', 'native', 20, 0, 255, '', '', '', '', '', '', 0, ''),
+  (202, 3, 'birthday', 'Birthday', 'show', 'date', 'all', 'native', 30, 0, 255, '', '', '', '', '', '', 0, '');
 
 # ----------------------------------------------------------------------
 #
@@ -247,8 +253,8 @@ INSERT INTO Form (name, title, noteInternal, tableName, permitNew, permitEdit, r
 # FormEditor: FormElements
 INSERT INTO FormElement (id, formId, name, label, mode, type, checkType, class, ord, size, maxLength, note, clientJs, value, sql1, sql2, parameter, feIdContainer, subrecordOption)
 VALUES
-  (300, 4, 'id', 'id', 'readonly', 'text', 'all', 'native', 100, 10, 11, '', '', '', '', '', '', 0, ''),
-  (310, 4, 'name', 'Name', 'show', 'text', 'all', 'native', 120, 40, 255, '', '', '', '', '', '', 0, '');
+  (300, 4, 'id', 'id', 'readonly', 'text', 'all', 'native', 100, 0, 11, '', '', '', '', '', '', 0, ''),
+  (310, 4, 'name', 'Name', 'show', 'text', 'all', 'native', 120, 0, 255, '', '', '', '', '', '', 0, '');
 
 # Form: table
 INSERT INTO Form (name, title, noteInternal, tableName, permitNew, permitEdit, render, multiSql, parameter) VALUES
@@ -257,5 +263,5 @@ INSERT INTO Form (name, title, noteInternal, tableName, permitNew, permitEdit, r
 # FormEditor: FormElements
 INSERT INTO FormElement (id, formId, name, label, mode, type, checkType, class, ord, size, maxLength, note, clientJs, value, sql1, sql2, parameter, feIdContainer, subrecordOption)
 VALUES
-  (400, 5, 'id', 'id', 'readonly', 'text', 'all', 'native', 100, 10, 11, '', '', '', '', '', '', 0, ''),
-  (410, 5, 'name', 'Name', 'show', 'text', 'all', 'native', 120, 40, 255, '', '', '', '', '', '', 0, '');
+  (400, 5, 'id', 'id', 'readonly', 'text', 'all', 'native', 100, 0, 11, '', '', '', '', '', '', 0, ''),
+  (410, 5, 'name', 'Name', 'show', 'text', 'all', 'native', 120, 0, 255, '', '', '', '', '', '', 0, '');
-- 
GitLab