From 4ea0c4581c38a98984e67715a7ad27f5b75045d1 Mon Sep 17 00:00:00 2001
From: Carsten  Rose <carsten.rose@math.uzh.ch>
Date: Thu, 7 Nov 2019 21:43:26 +0100
Subject: [PATCH] Fixes #9521 Textarea auto-grow - PHP and JS have been lost in
 GIT!

---
 extension/Classes/Core/AbstractBuildForm.php  | 22 ++++-
 extension/Classes/Core/Constants.php          |  6 ++
 extension/Classes/Sql/formEditor.sql          | 40 ++++----
 .../Tests/Unit/Core/BuildFormPlainTest.php    | 92 +++++++++----------
 javascript/src/Main.js                        | 28 +++++-
 5 files changed, 117 insertions(+), 71 deletions(-)

diff --git a/extension/Classes/Core/AbstractBuildForm.php b/extension/Classes/Core/AbstractBuildForm.php
index dcac890c7..e7e0947e8 100644
--- a/extension/Classes/Core/AbstractBuildForm.php
+++ b/extension/Classes/Core/AbstractBuildForm.php
@@ -1406,7 +1406,6 @@ abstract class AbstractBuildForm {
 
         $attribute .= Support::doAttribute('id', $formElement[FE_HTML_ID]);
         $attribute .= Support::doAttribute('name', $htmlFormElementName);
-        $attribute .= Support::doAttribute('class', $class);
         $attribute .= Support::doAttribute(ATTRIBUTE_DATA_REFERENCE, $formElement[FE_DATA_REFERENCE]);
 
         if (isset($formElement[FE_RETYPE_SOURCE_NAME])) {
@@ -1444,10 +1443,14 @@ abstract class AbstractBuildForm {
         // Check for input type 'textarea'. Possible notation: a) '', b) '<width>', c) '<width>,<height>', d) '<width>,<min-height>,<max-height>'
         $colsRows = explode(',', $formElement[FE_SIZE], 3);
 
-        // AutoHeight
-        $colsRows[1] = HelperFormElement::textareaAutoHeight($colsRows, $value);
+        if (empty($colsRows[1])) {
+            $colsRows[1] = 1;
+        }
         $flagTextarea = ($colsRows[1] > 1);
 
+        // AutoHeight
+//        $colsRows[1] = HelperFormElement::textareaAutoHeight($colsRows, $value);
+
         $formElement = HelperFormElement::prepareExtraButton($formElement, !$flagTextarea);
 
 
@@ -1456,6 +1459,16 @@ abstract class AbstractBuildForm {
 
             $attribute .= Support::doAttribute('cols', $colsRows[0]);
             $attribute .= Support::doAttribute('rows', $colsRows[1]);
+
+            if (($formElement[FE_TEXTAREA_RESIZE] ?? '1') == '0') {
+                $attribute .= Support::doAttribute('style', 'resize: none;');
+            }
+            // Check if $colsRows[2] != 0 >> enable auto-grow (if nothing is defined: enable auto-grow)
+            $maxHeight = $colsRows[2] ?? '350';
+            if ($maxHeight != '0') {
+                $class .= ' ' . CLASS_FORM_ELEMENT_AUTO_GROW;
+                $attribute .= Support::doAttribute(ATTRIBUTE_DATA_MAX_HEIGHT, $maxHeight);
+            }
             $textarea = htmlentities($value) . '</textarea>';
         } else {
             $htmlTag = '<input';
@@ -1480,6 +1493,7 @@ abstract class AbstractBuildForm {
             $attribute .= Support::doAttribute(F_FE_DATA_PATTERN_ERROR, $formElement[F_FE_DATA_PATTERN_ERROR], true, ESCAPE_WITH_BACKSLASH);
         }
 
+
         if ($formElement[FE_MODE] == FE_MODE_REQUIRED) {
             $attribute .= Support::doAttribute(F_FE_DATA_REQUIRED_ERROR, $formElement[F_FE_DATA_REQUIRED_ERROR]);
         }
@@ -1495,6 +1509,8 @@ abstract class AbstractBuildForm {
 
         $attribute .= $this->getAttributeFeMode($formElement[FE_MODE], false);
 
+        $attribute .= Support::doAttribute('class', $class);
+
         $json = $this->getFormElementForJson($htmlFormElementName, $value, $formElement);
 
         $input = "$htmlTag $attribute>$textarea";
diff --git a/extension/Classes/Core/Constants.php b/extension/Classes/Core/Constants.php
index a7625fb6d..54e249111 100644
--- a/extension/Classes/Core/Constants.php
+++ b/extension/Classes/Core/Constants.php
@@ -858,6 +858,11 @@ const DATA_CHARACTER_COUNT_ID = 'data-character-count-id';
 
 const CLASS_FORM_ELEMENT_EDIT = 'qfq-form-element-edit';
 
+const CLASS_FORM_ELEMENT_AUTO_GROW = 'qfq-auto-grow';
+const ATTRIBUTE_DATA_MAX_HEIGHT = 'data-max-height';
+
+
+
 // BuildForm
 const SYMBOL_NEW = 'new';
 const SYMBOL_EDIT = 'edit';
@@ -1241,6 +1246,7 @@ const FE_RECORD_DESTINATION_TABLE = 'recordDestinationTable';
 const FE_RECORD_SOURCE_TABLE = 'recordSourceTable';
 const FE_TRANSLATE_ID_COLUMN = 'translateIdColumn';
 const FE_EMPTY_MEANS_NULL = 'emptyMeansNull';
+const FE_TEXTAREA_RESIZE = 'textareaResize';
 const FE_EMPTY_ITEM_AT_START = 'emptyItemAtStart';
 const FE_EMPTY_ITEM_AT_END = 'emptyItemAtEnd';
 const FE_SUBRECORD_TABLE_CLASS = 'subrecordTableClass';
diff --git a/extension/Classes/Sql/formEditor.sql b/extension/Classes/Sql/formEditor.sql
index a2c313a50..9a1568615 100644
--- a/extension/Classes/Sql/formEditor.sql
+++ b/extension/Classes/Sql/formEditor.sql
@@ -200,25 +200,25 @@ VALUES
    '<a tabindex="-1" href="{{documentation:Y}}#form-name">Info</a>', '', '', '',
    'autofocus\ndata-pattern-error=Allowed characters: alphabet, number or . - +',
    1, '', '', '', 'specialchar', 'no', '[a-zA-Z0-9._+-]+'),
-  (1, 'title', 'Title', 'show', 'text', 'all', 'native', 120, '80,2,15', 0,
+  (1, 'title', 'Title', 'show', 'text', 'all', 'native', 120, '80,2', 0,
    '<a tabindex="-1" href="{{documentation:Y}}#form-title">Info</a>',
    '', '', '', '', 1, '', '', '', 'none', 'no', ''),
-  (1, 'noteInternal', 'Note', 'show', 'text', 'all', 'native', 130, '80,2,15', 0,
+  (1, 'noteInternal', 'Note', 'show', 'text', 'all', 'native', 130, '80,2', 0,
    '<a tabindex="-1" href="{{documentation:Y}}#form-note">Info</a>', '', '', '', '', 1, '', '', '', 'specialchar', 'no',
    ''),
   (1, 'tableName', 'Table', 'required', 'select', 'all', 'native', 140, 0, 0,
    '<a tabindex="-1" href="{{documentation:Y}}#form-tablename">Info</a>', '', '', '{{[{{indexData:Y}}]!SHOW tables}}',
    'emptyItemAtStart', 1, '', '', '', 'specialchar', 'no', ''),
-  (1, 'parameterLanguageA', 'Language: {{formLanguageALabel:YE}}', 'show', 'text', 'all', 'native', 150, '80,2,15', 0,
+  (1, 'parameterLanguageA', 'Language: {{formLanguageALabel:YE}}', 'show', 'text', 'all', 'native', 150, '80,2', 0,
    '<a tabindex="-1" href="{{documentation:Y}}#multi-language-form">Info</a>', '', '', '', '', 1, '',
    '{{SELECT IF("{{formLanguageAId:YE}}"="","hidden","show" ) }}', '', 'none', 'no', ''),
-  (1, 'parameterLanguageB', 'Language: {{formLanguageBLabel:YE}}', 'show', 'text', 'all', 'native', 160, '80,2,15', 0,
+  (1, 'parameterLanguageB', 'Language: {{formLanguageBLabel:YE}}', 'show', 'text', 'all', 'native', 160, '80,2', 0,
    '<a tabindex="-1" href="{{documentation:Y}}#multi-language-form">Info</a>', '', '', '', '', 1, '',
    '{{SELECT IF("{{formLanguageBId:YE}}"="","hidden","show" ) }}', '', 'none', 'no', ''),
-  (1, 'parameterLanguageC', 'Language: {{formLanguageCLabel:YE}}', 'show', 'text', 'all', 'native', 170, '80,2,15', 0,
+  (1, 'parameterLanguageC', 'Language: {{formLanguageCLabel:YE}}', 'show', 'text', 'all', 'native', 170, '80,2', 0,
    '<a tabindex="-1" href="{{documentation:Y}}#multi-language-form">Info</a>', '', '', '', '', 1, '',
    '{{SELECT IF("{{formLanguageCId:YE}}"="","hidden","show" ) }}', '', 'none', 'no', ''),
-  (1, 'parameterLanguageD', 'Language: {{formLanguageDLabel:YE}}', 'show', 'text', 'all', 'native', 180, '80,2,15', 0,
+  (1, 'parameterLanguageD', 'Language: {{formLanguageDLabel:YE}}', 'show', 'text', 'all', 'native', 180, '80,2', 0,
    '<a tabindex="-1" href="{{documentation:Y}}#multi-language-form">Info</a>', '', '', '', '', 1, '',
    '{{SELECT IF("{{formLanguageDId:YE}}"="","hidden","show" ) }}', '', 'none', 'no', ''),
 
@@ -238,7 +238,7 @@ VALUES
   (1, 'labelAlign', 'Label Align', 'show', 'radio', 'alnumx', 'native', 225, 0, 5,
    '<a tabindex="-1" href="{{documentation:Y}}#definition">Info</a>', '', '', '', 'buttonClass', 3, '',
    '', '', 'specialchar', 'no', ''),
-  (1, 'parameter', 'Parameter', 'show', 'text', 'all', 'native', 230, '80,2,15', 0,
+  (1, 'parameter', 'Parameter', 'show', 'text', 'all', 'native', 230, '80,2', 0,
    '<a tabindex="-1" href="{{documentation:Y}}#form-parameter">Info</a>', '', '', '', '', 3, '', '', '', 'none', 'no',
    ''),
   (1, 'bsLabelColumns', 'BS Label Columns', 'show', 'text', 'all', 'native', 240, 0, 0,
@@ -302,7 +302,7 @@ VALUES
   (1, 'multiMode', 'Multi Mode', 'show', 'radio', 'all', 'native', 520, 0, 0, '', '', '', '', 'buttonClass', 5, '', '',
    '',
    'specialchar', 'no', ''),
-  (1, 'multiSql', 'Multi SQL', 'show', 'text', 'all', 'native', 530, '80,2,15', 0, '', '', '', '', '', 5, '', '', '',
+  (1, 'multiSql', 'Multi SQL', 'show', 'text', 'all', 'native', 530, '80,2', 0, '', '', '', '', '', 5, '', '', '',
    'none', 'no', ''),
   (1, 'multiDetailForm', 'Multi Detail Form', 'show', 'text', 'all', 'native', 540, 0, 0, '', '', '', '', '', 5,
    '', '', '', 'specialchar', 'no', ''),
@@ -380,22 +380,22 @@ VALUES (2, 'feIdContainer', 'Container', 'show', 'select', 'all', 'native', 120,
         '', 100, '', 'yes', '', '', '',
         '{{ SELECT IF("{{type:FRE:alnumx}}"="subrecord" AND "{{class:FRE:alnumx}}"="native", "show", "hidden") }}', '',
         'specialchar'),
-       (2, 'parameterLanguageA', 'Language: {{formLanguageALabel:YE}}', 'show', 'text', 'all', 'native', 210, '80,2,15',
+       (2, 'parameterLanguageA', 'Language: {{formLanguageALabel:YE}}', 'show', 'text', 'all', 'native', 210, '80,2',
         0,
         '<a tabindex="-1" href="{{documentation:Y}}#multi-language-form">Info</a>', '', '', '', '', 100, '', 'no', '',
         '', '',
         '{{SELECT IF("{{formLanguageAId:YE}}"="","hidden","show" ) }}', '', 'none'),
-       (2, 'parameterLanguageB', 'Language: {{formLanguageBLabel:YE}}', 'show', 'text', 'all', 'native', 210, '80,2,15',
+       (2, 'parameterLanguageB', 'Language: {{formLanguageBLabel:YE}}', 'show', 'text', 'all', 'native', 210, '80,2',
         0,
         '<a tabindex="-1" href="{{documentation:Y}}#multi-language-form">Info</a>', '', '', '', '', 100, '', 'no', '',
         '', '',
         '{{SELECT IF("{{formLanguageBId:YE}}"="","hidden","show" ) }}', '', 'none'),
-       (2, 'parameterLanguageC', 'Language: {{formLanguageCLabel:YE}}', 'show', 'text', 'all', 'native', 210, '80,2,15',
+       (2, 'parameterLanguageC', 'Language: {{formLanguageCLabel:YE}}', 'show', 'text', 'all', 'native', 210, '80,2',
         0,
         '<a tabindex="-1" href="{{documentation:Y}}#multi-language-form">Info</a>', '', '', '', '', 100, '', 'no', '',
         '', '',
         '{{SELECT IF("{{formLanguageCId:YE}}"="","hidden","show" ) }}', '', 'none'),
-       (2, 'parameterLanguageD', 'Language: {{formLanguageDLabel:YE}}', 'show', 'text', 'all', 'native', 210, '80,2,15',
+       (2, 'parameterLanguageD', 'Language: {{formLanguageDLabel:YE}}', 'show', 'text', 'all', 'native', 210, '80,2',
         0,
         '<a tabindex="-1" href="{{documentation:Y}}#multi-language-form">Info</a>', '', '', '', '', 100, '', 'no', '',
         '', '',
@@ -427,7 +427,7 @@ VALUES (2, 'feIdContainer', 'Container', 'show', 'select', 'all', 'native', 120,
        #         '<a tabindex="-1" href="{{documentation:Y}}#field-tabindex">Info</a>', '', '', '', '', 101, '', 'no', '', '',
        #         '', '', '',
        #         'specialchar'),
-       (2, 'adminNote', 'Internal Note', 'show', 'text', 'all', 'native', 360, '80,2,15', 0, '', '', '', '', '', 101,
+       (2, 'adminNote', 'Internal Note', 'show', 'text', 'all', 'native', 360, '80,2', 0, '', '', '', '', '', 101,
         '',
         'no',
         '', '',
@@ -465,7 +465,7 @@ VALUES (2, 'feIdContainer', 'Container', 'show', 'select', 'all', 'native', 120,
         '<a tabindex="-1" href="{{documentation:Y}}#field-maxlength">Info</a>', '', '', '', '', 102, '', 'no', '', '',
         '', '', '',
         'specialchar'),
-       (2, 'note', 'Note', 'show', 'text', 'all', 'native', 460, '80,2,15', 0,
+       (2, 'note', 'Note', 'show', 'text', 'all', 'native', 460, '80,2', 0,
         '<a tabindex="-1" href="{{documentation:Y}}#field-note">Info</a>', '', '', '', '', 102, '', 'no', '', '', '',
         '', '', 'none'),
        (2, 'tooltip', 'Tooltip', 'show', 'text', 'all', 'native', 470, 0, 0,
@@ -477,14 +477,14 @@ VALUES (2, 'feIdContainer', 'Container', 'show', 'select', 'all', 'native', 120,
         '', '', '',
         'none'),
 
-       (2, 'value', 'value', 'show', 'text', 'all', 'native', 500, '80,2,15', 0,
+       (2, 'value', 'value', 'show', 'text', 'all', 'native', 500, '80,2', 0,
         '<a tabindex="-1" href="{{documentation:Y}}#field-value">Info</a>', '', '', '', '', 103, '', 'no', '', '', '',
         '', '',
         'none'),
-       (2, 'sql1', 'sql1', 'show', 'text', 'all', 'native', 510, '80,2,15', 0,
+       (2, 'sql1', 'sql1', 'show', 'text', 'all', 'native', 510, '80,2', 0,
         '<a tabindex="-1" href="{{documentation:Y}}#sql1">Info</a><br><br>MariaDB: <a tabindex="-1" href="https://mariadb.com/kb/en/mariadb/select/">Select</a>, <a tabindex="-1" href="https://mariadb.com/kb/en/mariadb/functions-and-operators/">Functions</a>',
         '', '', '', '', 103, '', 'no', '', '', '', '', '', 'none'),
-       (2, 'parameter', 'Parameter', 'show', 'text', 'all', 'native', 520, '80,2,15', 0,
+       (2, 'parameter', 'Parameter', 'show', 'text', 'all', 'native', 520, '80,2', 0,
         '<a tabindex="-1" href="{{documentation:Y}}#fe-parameter-attributes">Info</a>',
         '', '', '', '', 103, '', 'no', '', '', '', '', '', 'none');
 
@@ -642,10 +642,10 @@ VALUES (4, 'status', 'Enabled', 'show', '', 'checkbox', 'specialchar', 'alnumx',
        (4, 'sql1', 'Mail', 'show', '{{SELECT IF("{{type:FR:alnumx}}"="mail","show","hidden") }}', 'text', 'none', 'all',
         60,
         'extraButtonInfo = Query: &#123;&#123;!SELECT ... as sendMailTo...&#125;&#125;<br><b>sendMailTo / sendMailCc / sendMailBcc</b>: Separate multiple by comma.<br><b>sendMailFrom</b><br><b>sendMailSubject</b><br><b>sendMailReplyTo</b>: Optional<br><b>sendMailFlagAutoSubmit</b>: Optional. on|off. Default on - if "on", suppresses OoO answers from receivers.<br><b>sendMailGrId</b>: Optional<br><b>sendMailXId</b>: Optional',
-        '80,2,15', '', 'yes', '', '', ''),
+        '80,2', '', 'yes', '', '', ''),
        (4, 'content', '{{SELECT IF("{{type:FR:alnumx}}"="mail","Mail body","URL") }}', 'show', '', 'text', 'none',
         'all', 70,
-        '', '80,2,15',
+        '', '80,2',
         'Website: URL absolute like "http://..." or relative like "?id=pagealias..."<br>Mail: Static Body or &#123;{SELECT ...&#125;}',
         'yes', '', '', ''),
 
@@ -660,7 +660,7 @@ VALUES (4, 'status', 'Enabled', 'show', '', 'checkbox', 'specialchar', 'alnumx',
         'yes', '', '', ''),
 
        (4, 'lastRun', 'Last run', 'readonly', '', 'text', 'specialchar', 'alnumx', 120, '', '', '', 'no', '', '', ''),
-       (4, 'lastStatus', 'Laststatus', 'readonly', '', 'text', 'specialchar', 'alnumx', 130, '', '80,2,15', '', 'no',
+       (4, 'lastStatus', 'Laststatus', 'readonly', '', 'text', 'specialchar', 'alnumx', 130, '', '80,2', '', 'no',
         '3',
         '9',
         '0'),
diff --git a/extension/Tests/Unit/Core/BuildFormPlainTest.php b/extension/Tests/Unit/Core/BuildFormPlainTest.php
index 1729f4159..bf5fd673a 100644
--- a/extension/Tests/Unit/Core/BuildFormPlainTest.php
+++ b/extension/Tests/Unit/Core/BuildFormPlainTest.php
@@ -100,38 +100,38 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
         $label['123-r'][API_ELEMENT_ATTRIBUTE] = ['class' => ''];
 
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" data-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+        $this->assertEquals('<input id="123" name="name:1" maxlength="255" type="input" value="" data-error="Error" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
         $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);
 
         // Min/Max
         $formElement[FE_MIN] = '1';
         $formElement[FE_MAX] = '10';
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="number" value="" data-error="Error" min="1" max="10" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+        $this->assertEquals('<input id="123" name="name:1" maxlength="255" type="number" value="" data-error="Error" min="1" max="10" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
         $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);
 
         $formElement[FE_MIN] = '1';
         $formElement[FE_MAX] = '';
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" data-error="Error" min="1" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+        $this->assertEquals('<input id="123" name="name:1" maxlength="255" type="input" value="" data-error="Error" min="1" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
         $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);
 
         $formElement[FE_MIN] = '';
         $formElement[FE_MAX] = '10';
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" data-error="Error" max="10" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+        $this->assertEquals('<input id="123" name="name:1" maxlength="255" type="input" value="" data-error="Error" max="10" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
         $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);
 
         $formElement[FE_MIN] = '0';
         $formElement[FE_MAX] = '10';
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" data-error="Error" min="0" max="10" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+        $this->assertEquals('<input id="123" name="name:1" maxlength="255" type="input" value="" data-error="Error" min="0" max="10" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
         $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);
 
         $formElement[FE_MIN] = '-5';
         $formElement[FE_MAX] = '0';
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" data-error="Error" min="-5" max="0" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+        $this->assertEquals('<input id="123" name="name:1" maxlength="255" type="input" value="" data-error="Error" min="-5" max="0" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
         $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);
 
         // reset so they don't interfere with next tests
@@ -142,14 +142,14 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
         $formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_PATTERN;
         $formElement[FE_CHECK_PATTERN] = '^[a-z]*$';
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="^[a-z]*$" data-pattern-error="' . F_FE_DATA_PATTERN_ERROR_DEFAULT . '" data-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+        $this->assertEquals('<input id="123" name="name:1" maxlength="255" type="input" value="" pattern="^[a-z]*$" data-pattern-error="' . F_FE_DATA_PATTERN_ERROR_DEFAULT . '" data-error="Error" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
         $label['123'][API_ELEMENT_ATTRIBUTE]['pattern'] = '^[a-z]*$';
         $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);
 
         $formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_DIGIT;
         $formElement[FE_CHECK_PATTERN] = '';
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="^[\d]*$" data-pattern-error="' . SANITIZE_ALLOW_DIGIT_MESSAGE . '" data-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+        $this->assertEquals('<input id="123" name="name:1" maxlength="255" type="input" value="" pattern="^[\d]*$" data-pattern-error="' . SANITIZE_ALLOW_DIGIT_MESSAGE . '" data-error="Error" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
 
         $label['123'][API_ELEMENT_ATTRIBUTE]['pattern'] = '^[\d]*$';
         $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);
@@ -158,7 +158,7 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
         $formElement[FE_CHECK_PATTERN] = '';
         $result = $build->buildInput($formElement, 'name:1', '', $json);
         $label['123'][API_ELEMENT_ATTRIBUTE]['pattern'] = '^([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})?$';
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="^([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})?$" data-pattern-error="' . SANITIZE_ALLOW_EMAIL_MESSAGE . '" data-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+        $this->assertEquals('<input id="123" name="name:1" maxlength="255" type="input" value="" pattern="^([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})?$" data-pattern-error="' . SANITIZE_ALLOW_EMAIL_MESSAGE . '" data-error="Error" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
         $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);
 
         $formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_ALL;
@@ -168,7 +168,7 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
         // Decimal format
         $formElement[FE_DECIMAL_FORMAT] = '5,2';
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="^-?[0-9]{0,3}(\.[0-9]{0,2})?$" data-pattern-error="Requested decimal format (mantis,decimal): 5,2" data-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+        $this->assertEquals('<input id="123" name="name:1" maxlength="255" type="input" value="" pattern="^-?[0-9]{0,3}(\.[0-9]{0,2})?$" data-pattern-error="Requested decimal format (mantis,decimal): 5,2" data-error="Error" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
         $label['123'][API_ELEMENT_ATTRIBUTE]['pattern'] = '^-?[0-9]{0,3}(\.[0-9]{0,2})?$';
         $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);
 
@@ -179,14 +179,14 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
         $formElement['size'] = 40;
         $formElement['maxLength'] = 40;
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="40" type="input" size="40" value="" data-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+        $this->assertEquals('<input id="123" name="name:1" maxlength="40" type="input" size="40" value="" data-error="Error" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
         unset($label['123'][API_ELEMENT_ATTRIBUTE]['pattern']);
         $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);
 
         // maxlength bigger than physical spec:
         $formElement['maxLength'] = 1000;
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="1000" type="input" size="40" value="" data-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+        $this->assertEquals('<input id="123" name="name:1" maxlength="1000" type="input" size="40" value="" data-error="Error" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
         $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);
 
         // no size, no maxlength and column not in primary table
@@ -195,24 +195,24 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
         $formElement2['size'] = '';
         $formElement2['name'] = 'specialname';
         $result = $build->buildInput($formElement2, 'specialname:1', '', $json);
-        $this->assertEquals('<input id="123" name="specialname:1" class="form-control" type="input" value="" data-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+        $this->assertEquals('<input id="123" name="specialname:1" type="input" value="" data-error="Error" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
 
         // no size,  given maxlength and column not in primary table
         $formElement2['maxLength'] = '10';
         $result = $build->buildInput($formElement2, 'specialname:1', '', $json);
-        $this->assertEquals('<input id="123" name="specialname:1" class="form-control" maxlength="10" type="input" value="" data-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+        $this->assertEquals('<input id="123" name="specialname:1" maxlength="10" type="input" value="" data-error="Error" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
 
         // size given, no maxlength and column not in primary table
         $formElement2['maxLength'] = '';
         $formElement2['size'] = '10';
         $result = $build->buildInput($formElement2, 'specialname:1', '', $json);
-        $this->assertEquals('<input id="123" name="specialname:1" class="form-control" type="input" size="10" value="" data-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+        $this->assertEquals('<input id="123" name="specialname:1" type="input" size="10" value="" data-error="Error" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
 
         // size given, maxlength given and column not in primary table
         $formElement2['maxLength'] = '20';
         $formElement2['size'] = '10';
         $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-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+        $this->assertEquals('<input id="123" name="specialname:1" maxlength="20" type="input" size="10" value="" data-error="Error" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
         $formElement2['maxLength'] = '';
         $formElement2['size'] = '';
 
@@ -220,20 +220,20 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
         $formElement2['tooltip'] = 'Nice Tooltip';
         $formElement2['placeholder'] = 'Please type a name';
         $result = $build->buildInput($formElement2, 'name:1', 'Hello World', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" type="input" value="Hello World" placeholder="Please type a name" data-error="Error" title="Nice Tooltip" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+        $this->assertEquals('<input id="123" name="name:1" type="input" value="Hello World" placeholder="Please type a name" data-error="Error" title="Nice Tooltip" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
         $label['123'][API_ELEMENT_ATTRIBUTE] = ['value' => 'Hello World', 'required' => false, 'hidden' => false];
         $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => 'Hello World', API_ELEMENT_UPDATE => $label], $json);
 
         // textarea
         $formElement2['size'] = '40,10';
         $result = $build->buildInput($formElement2, 'name:1', 'Hello World', $json);
-        $this->assertEquals('<textarea id="123" name="name:1" class="form-control" cols="40" rows="10" placeholder="Please type a name" data-error="Error" title="Nice Tooltip" data-hidden="no" data-required="no" >Hello World</textarea><div class="help-block with-errors hidden"></div>', $result);
+        $this->assertEquals('<textarea id="123" name="name:1" cols="40" rows="10" data-max-height="350" placeholder="Please type a name" data-error="Error" title="Nice Tooltip" data-hidden="no" data-required="no" class="form-control qfq-auto-grow" >Hello World</textarea><div class="help-block with-errors hidden"></div>', $result);
 
         $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => 'Hello World', API_ELEMENT_UPDATE => $label], $json);
 
         $formElement2['size'] = ' 40     , 10 ';
         $result = $build->buildInput($formElement2, 'name:1', 'Hello World', $json);
-        $this->assertEquals('<textarea id="123" name="name:1" class="form-control" cols="40" rows="10" placeholder="Please type a name" data-error="Error" title="Nice Tooltip" data-hidden="no" data-required="no" >Hello World</textarea><div class="help-block with-errors hidden"></div>', $result);
+        $this->assertEquals('<textarea id="123" name="name:1" cols="40" rows="10" data-max-height="350" placeholder="Please type a name" data-error="Error" title="Nice Tooltip" data-hidden="no" data-required="no" class="form-control qfq-auto-grow" >Hello World</textarea><div class="help-block with-errors hidden"></div>', $result);
         $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => 'Hello World', API_ELEMENT_UPDATE => $label], $json);
     }
 
@@ -259,44 +259,44 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
 
         $formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_ALNUMX;
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="' . PATTERN_ALNUMX .
+        $this->assertEquals('<input id="123" name="name:1" maxlength="255" type="input" value="" pattern="' . PATTERN_ALNUMX .
             '" data-pattern-error="' . SANITIZE_ALLOW_ALNUMX_MESSAGE .
-            '" data-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+            '" data-error="Error" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
 
         $formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_DIGIT;
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="' . PATTERN_DIGIT .
+        $this->assertEquals('<input id="123" name="name:1" maxlength="255" type="input" value="" pattern="' . PATTERN_DIGIT .
             '" data-pattern-error="' . SANITIZE_ALLOW_DIGIT_MESSAGE .
-            '" data-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+            '" data-error="Error" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
 
         $formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_NUMERICAL;
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="' . PATTERN_NUMERICAL .
+        $this->assertEquals('<input id="123" name="name:1" maxlength="255" type="input" value="" pattern="' . PATTERN_NUMERICAL .
             '" data-pattern-error="' . SANITIZE_ALLOW_NUMERICAL_MESSAGE .
-            '" data-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+            '" data-error="Error" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
 
         $formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_EMAIL;
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="' . PATTERN_EMAIL .
+        $this->assertEquals('<input id="123" name="name:1" maxlength="255" type="input" value="" pattern="' . PATTERN_EMAIL .
             '" data-pattern-error="' . SANITIZE_ALLOW_EMAIL_MESSAGE .
-            '" data-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+            '" data-error="Error" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
 
         $formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_ALLBUT;
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="' . PATTERN_ALLBUT .
+        $this->assertEquals('<input id="123" name="name:1" maxlength="255" type="input" value="" pattern="' . PATTERN_ALLBUT .
             '" data-pattern-error="' . SANITIZE_ALLOW_ALLBUT_MESSAGE .
-            '" data-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+            '" data-error="Error" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
 
         $formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_ALL;
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" data-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+        $this->assertEquals('<input id="123" name="name:1" maxlength="255" type="input" value="" data-error="Error" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
 
         $formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_PATTERN;
         $formElement[FE_CHECK_PATTERN] = '^[0-2]$';
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="' . $formElement[FE_CHECK_PATTERN] .
+        $this->assertEquals('<input id="123" name="name:1" maxlength="255" type="input" value="" pattern="' . $formElement[FE_CHECK_PATTERN] .
             '" data-pattern-error="' . F_FE_DATA_PATTERN_ERROR_DEFAULT .
-            '" data-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+            '" data-error="Error" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
     }
 
     /**
@@ -322,37 +322,37 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
         // Defaults data-pattern-error: ALNUMX
         $formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_ALNUMX;
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="' . PATTERN_ALNUMX .
+        $this->assertEquals('<input id="123" name="name:1" maxlength="255" type="input" value="" pattern="' . PATTERN_ALNUMX .
             '" data-pattern-error="' . SANITIZE_ALLOW_ALNUMX_MESSAGE .
-            '" data-error="' . F_FE_DATA_ERROR_DEFAULT . '" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+            '" data-error="' . F_FE_DATA_ERROR_DEFAULT . '" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
 
         // Defaults data-pattern-error: DIGIT
         $formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_DIGIT;
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="' . PATTERN_DIGIT .
+        $this->assertEquals('<input id="123" name="name:1" maxlength="255" type="input" value="" pattern="' . PATTERN_DIGIT .
             '" data-pattern-error="' . SANITIZE_ALLOW_DIGIT_MESSAGE .
-            '" data-error="' . F_FE_DATA_ERROR_DEFAULT . '" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+            '" data-error="' . F_FE_DATA_ERROR_DEFAULT . '" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
 
         // Defaults data-pattern-error: NUMERICAL
         $formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_NUMERICAL;
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="' . PATTERN_NUMERICAL .
+        $this->assertEquals('<input id="123" name="name:1" maxlength="255" type="input" value="" pattern="' . PATTERN_NUMERICAL .
             '" data-pattern-error="' . SANITIZE_ALLOW_NUMERICAL_MESSAGE .
-            '" data-error="' . F_FE_DATA_ERROR_DEFAULT . '" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+            '" data-error="' . F_FE_DATA_ERROR_DEFAULT . '" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
 
         // Defaults data-pattern-error: EMAIL
         $formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_EMAIL;
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="' . PATTERN_EMAIL .
+        $this->assertEquals('<input id="123" name="name:1" maxlength="255" type="input" value="" pattern="' . PATTERN_EMAIL .
             '" data-pattern-error="' . SANITIZE_ALLOW_EMAIL_MESSAGE .
-            '" data-error="' . F_FE_DATA_ERROR_DEFAULT . '" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+            '" data-error="' . F_FE_DATA_ERROR_DEFAULT . '" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
 
         // Defaults data-pattern-error: ALLBUT
         $formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_ALLBUT;
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="' . PATTERN_ALLBUT .
+        $this->assertEquals('<input id="123" name="name:1" maxlength="255" type="input" value="" pattern="' . PATTERN_ALLBUT .
             '" data-pattern-error="' . SANITIZE_ALLOW_ALLBUT_MESSAGE .
-            '" data-error="' . F_FE_DATA_ERROR_DEFAULT . '" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+            '" data-error="' . F_FE_DATA_ERROR_DEFAULT . '" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
     }
 
     /**
@@ -380,9 +380,9 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
         $formElement[F_FE_DATA_ERROR] = 'custom data text';
         $formElement[F_FE_DATA_PATTERN_ERROR] = 'custom pattern text';
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="' . PATTERN_ALNUMX .
+        $this->assertEquals('<input id="123" name="name:1" maxlength="255" type="input" value="" pattern="' . PATTERN_ALNUMX .
             '" data-pattern-error="' . $formElement[F_FE_DATA_PATTERN_ERROR] .
-            '" data-error="' . $formElement[F_FE_DATA_ERROR] . '" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+            '" data-error="' . $formElement[F_FE_DATA_ERROR] . '" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
 
         // Defaults data-error: ALNUMX
         $formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_PATTERN;
@@ -390,9 +390,9 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
         $formElement[F_FE_DATA_ERROR] = 'custom data text';
         $formElement[F_FE_DATA_PATTERN_ERROR] = 'custom pattern text';
         $result = $build->buildInput($formElement, 'name:1', '', $json);
-        $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="[0-4]' .
+        $this->assertEquals('<input id="123" name="name:1" maxlength="255" type="input" value="" pattern="[0-4]' .
             '" data-pattern-error="' . $formElement[F_FE_DATA_PATTERN_ERROR] .
-            '" data-error="' . $formElement[F_FE_DATA_ERROR] . '" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
+            '" data-error="' . $formElement[F_FE_DATA_ERROR] . '" data-hidden="no" data-required="no" class="form-control" ><div class="help-block with-errors hidden"></div>', $result);
     }
 
     /**
diff --git a/javascript/src/Main.js b/javascript/src/Main.js
index ca5996884..f56e00b06 100644
--- a/javascript/src/Main.js
+++ b/javascript/src/Main.js
@@ -13,19 +13,43 @@ $(document).ready( function () {
         }); // end .each()
 
         $('.qfq-auto-grow').each(function() {
+            var minHeight = $(this).attr("rows") * 14 + 18;
             var newHeight = $(this).prop('scrollHeight');
             var maxHeight = $(this).data('max-height') || 0;
-            if(newHeight < maxHeight || maxHeight === 0) {
+
+            if ($(this).val === '' || newHeight < minHeight) {
+                return;
+            }
+
+            if (newHeight < maxHeight || maxHeight === 0) {
                 $(this).height(newHeight);
             } else {
                 $(this).height(maxHeight);
             }
         });
 
+        $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
+            $('.qfq-auto-grow').each(function () {
+                var minHeight = $(this).attr("rows") * 14 + 18;
+                var newHeight = $(this).prop('scrollHeight');
+                var maxHeight = $(this).data('max-height') || 0;
+
+                if ($(this).val === '' || newHeight < minHeight) {
+                    return;
+                }
+
+                if (newHeight < maxHeight || maxHeight === 0) {
+                    $(this).height(newHeight);
+                } else {
+                    $(this).height(maxHeight);
+                }
+            });
+        });
+
         $('.qfq-auto-grow').on('input', function() {
             var newHeight = $(this).prop('scrollHeight');
             var maxHeight = $(this).data('max-height') || 0;
-            if($(this).height() + 10 < newHeight) {
+            if ($(this).outerHeight() < newHeight) {
                 if(newHeight < maxHeight || maxHeight === 0) {
                     $(this).height(newHeight);
                 }
-- 
GitLab