diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5cf2834253a6485ba76f7534cbd53fd7855a79fd..f492d2248a76d3cc86397791eca5377d01ff06ac 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -9,7 +9,7 @@ variables: stages: - before - build - - selenium +# - selenium documentation: stage: before @@ -48,29 +48,29 @@ release: - scp qfq_${VERSION}_*.zip w16:qfq/releases/ - mv qfq_${VERSION}_*.zip build/qfq.zip -selenium: - stage: selenium - script: - - unzip -q build/qfq.zip -d qfq - - cd docker/ - - ./run_qfq_docker.sh -no-deploy - - ./deploy_to_container.sh ../qfq - - ./run_selenium_tests_docker.sh - - echo "hello" - after_script: -# remove containers and move logs to persistent location - - cd docker; ./remove-containers.sh <<< "y" - - cd .. - - umask 002 - - mkdir "$SELENIUM_LOGS_PATH/$CI_COMMIT_SHORT_SHA" - - cp extension/Tests/selenium/selenium_logs/* "$SELENIUM_LOGS_PATH/$CI_COMMIT_SHORT_SHA/" - - echo "Selenium Logs copied to $SELENIUM_LOGS_PATH/$CI_COMMIT_SHORT_SHA/" - - echo "Or download result (log/screenshot) in gitlab under CI/CD > Pipelines > right side 'Artifacts'" +# selenium: +# stage: selenium +# script: +# - unzip -q build/qfq.zip -d qfq +# - cd docker/ +# - ./run_qfq_docker.sh -no-deploy +# - ./deploy_to_container.sh ../qfq +# - ./run_selenium_tests_docker.sh +# - echo "hello" +# after_script: +# # remove containers and move logs to persistent location +# - cd docker; ./remove-containers.sh <<< "y" +# - cd .. +# - umask 002 +# - mkdir "$SELENIUM_LOGS_PATH/$CI_COMMIT_SHORT_SHA" +# - cp extension/Tests/selenium/selenium_logs/* "$SELENIUM_LOGS_PATH/$CI_COMMIT_SHORT_SHA/" +# - echo "Selenium Logs copied to $SELENIUM_LOGS_PATH/$CI_COMMIT_SHORT_SHA/" +# - echo "Or download result (log/screenshot) in gitlab under CI/CD > Pipelines > right side 'Artifacts'" - artifacts: - expire_in: 1 week - paths: - - extension/Tests/selenium/selenium_logs/ +# artifacts: +# expire_in: 1 week +# paths: +# - extension/Tests/selenium/selenium_logs/ diff --git a/Documentation/Manual.rst b/Documentation/Manual.rst index 14cbc08d60f3e9c972784fa733c95c55c5f781fc..77b2ec1071d0516c65af2dc9af38c62f12cd5889 100644 --- a/Documentation/Manual.rst +++ b/Documentation/Manual.rst @@ -2544,7 +2544,7 @@ Parameter +-----------------------------+--------+----------------------------------------------------------------------------------------------------------+ | typeAheadLdap | | Enable LDAP as 'Typeahead' data source. | +-----------------------------+--------+----------------------------------------------------------------------------------------------------------+ -| typeAheadLdapSearch | string | Regular LDAP search expression. E.g.: `(|(cn=*?*)(mail=*?*))` | +| typeAheadLdapSearch | string | Regular LDAP search expression. E.g.: `(|(cn=*?*)(mail=*?*))`   | +-----------------------------+--------+----------------------------------------------------------------------------------------------------------+ | typeAheadLdapValuePrintf | string | Value formatting of LDAP result, per entry. E.g.: `'%s / %s / %s', mail, roomnumber, telephonenumber` | +-----------------------------+--------+----------------------------------------------------------------------------------------------------------+ @@ -2559,6 +2559,9 @@ Parameter | mode | string | The value `readonly` will activate a global readonly mode of the form - the user can't change any data. | | | | See :ref:`form-mode-global` | +-----------------------------+--------+----------------------------------------------------------------------------------------------------------+ +| activeFirstRequiredTab | digit | 0: off, 1: (default) - with formModeGlobal=requiredOffButMark bring pill to front on save. | +| | | See :ref:`form-mode-global` | ++-----------------------------+--------+----------------------------------------------------------------------------------------------------------+ | enterAsSubmit | digit | 0: off, 1: Pressing *enter* in a form means *save* and *close*. Takes default from configuration_. | +-----------------------------+--------+----------------------------------------------------------------------------------------------------------+ | submitButtonText | string | Show a save button at the bottom of the form, with . See `submitButtonText`_. | @@ -2616,6 +2619,10 @@ Parameter +-----------------------------+--------+----------------------------------------------------------------------------------------------------------+ | minWidth | int | See checkboxRadioMinWidth_ . | +-----------------------------+--------+----------------------------------------------------------------------------------------------------------+ +| minWidth | int | See checkboxRadioMinWidth_ . | ++-----------------------------+--------+----------------------------------------------------------------------------------------------------------+ +| minWidth | int | See checkboxRadioMinWidth_ . | ++-----------------------------+--------+----------------------------------------------------------------------------------------------------------+ * Example: @@ -2702,7 +2709,7 @@ The `mode` is given via (in this priority): * Via STORE_USER: {{formModeGlobal:U}} * Via STORE_SIP: {{formModeGlobal:S}} -* Via Form: `form.parameter.mode=...` +* Via Form: `form.parameter.formModeGlobal=...` Mode ;;;; @@ -2732,6 +2739,11 @@ Mode * On lost focus. * When the user saves the record. + * After saving the record, by default the first pill with a missing input comes to front. This behaviour can be + switch on/off with `form.parameter.requiredOffButMark=0|1` + + + Extra ;;;;; diff --git a/extension/Classes/Controller/QfqController.php b/extension/Classes/Controller/QfqController.php index 5d04c434221689a970f30da4e94279c8a2113fce..642287eff7eb6abd3985f7b8173b5682fa347919 100644 --- a/extension/Classes/Controller/QfqController.php +++ b/extension/Classes/Controller/QfqController.php @@ -31,6 +31,7 @@ class QfqController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController { */ public function showAction() { + $html = ''; $origErrorReporting = ''; $flagOk = false; diff --git a/extension/Classes/Core/AbstractBuildForm.php b/extension/Classes/Core/AbstractBuildForm.php index 111f3af107284bd410780463e542a7b1725dcefa..4e82dfe9d2d6eb9ac8862b600b94b5133baa648a 100644 --- a/extension/Classes/Core/AbstractBuildForm.php +++ b/extension/Classes/Core/AbstractBuildForm.php @@ -605,6 +605,7 @@ abstract class AbstractBuildForm { $attribute[FE_INPUT_AUTOCOMPLETE] = 'on'; $attribute['enctype'] = $this->getEncType(); $attribute['data-disable-return-key-submit'] = $this->formSpec[F_ENTER_AS_SUBMIT] == '1' ? "false" : "true"; // attribute meaning is inverted + $attribute['data-activate-first-required-tab'] = $this->formSpec[F_ACTIVATE_FIRST_REQUIRED_TAB] == '1' ? "true" : "false"; // attribute meaning is inverted return $attribute; } diff --git a/extension/Classes/Core/Constants.php b/extension/Classes/Core/Constants.php index 59920b0f1777962a80e929e3c5616094e134063a..a6fb4f89fb51eca84f89d6838e2bbe5da5b196e9 100644 --- a/extension/Classes/Core/Constants.php +++ b/extension/Classes/Core/Constants.php @@ -1046,6 +1046,7 @@ const F_NEW_BUTTON_CLASS = SYSTEM_NEW_BUTTON_CLASS; const F_NEW_BUTTON_GLYPH_ICON = SYSTEM_NEW_BUTTON_GLYPH_ICON; const F_ENTER_AS_SUBMIT = SYSTEM_ENTER_AS_SUBMIT; +const F_ACTIVATE_FIRST_REQUIRED_TAB = 'activeFirstRequiredTab'; const F_DRAG_AND_DROP_ORDER_SQL = 'dragAndDropOrderSql'; const F_ORDER_INTERVAL = 'orderInterval'; diff --git a/extension/Classes/Core/Database/Database.php b/extension/Classes/Core/Database/Database.php index f8f5fc37e3041ccfcef46be6a6e4ae59e93218d9..e30aeec8e706e753354f267f059d1576bb4ce771 100644 --- a/extension/Classes/Core/Database/Database.php +++ b/extension/Classes/Core/Database/Database.php @@ -74,7 +74,7 @@ class Database { $this->store = Store::getInstance(); $storeSystem = $this->store->getStore(STORE_SYSTEM); - $this->sqlLog = $storeSystem[SYSTEM_SQL_LOG]; + $this->sqlLog = $storeSystem[SYSTEM_SITE_PATH] . '/' . $storeSystem[SYSTEM_SQL_LOG]; $dbInit = $storeSystem[SYSTEM_DB_INIT]; $config = $this->getConnectionDetails($dbIndex, $storeSystem); diff --git a/extension/Classes/Core/QuickFormQuery.php b/extension/Classes/Core/QuickFormQuery.php index 8ac42e195b3e93deed2244321cfd7bc21c5ec1fd..1163e66c7a07c51e40876b98b5de2eb14c39f2ca 100644 --- a/extension/Classes/Core/QuickFormQuery.php +++ b/extension/Classes/Core/QuickFormQuery.php @@ -1427,6 +1427,7 @@ class QuickFormQuery { * @return array * @throws \CodeException * @throws \UserFormException + * @throws \UserReportException */ private function initForm(array $formSpec, $recordId) { @@ -1442,6 +1443,7 @@ class QuickFormQuery { Support::setIfNotSet($formSpec, F_MULTI_MSG_NO_RECORD, F_MULTI_MSG_NO_RECORD_TEXT); Support::setIfNotSet($formSpec, F_FE_MIN_WIDTH, F_FE_MIN_WIDTH_DEFAULT); Support::setIfNotSet($formSpec, FE_INPUT_EXTRA_BUTTON_INFO_MIN_WIDTH, FE_INPUT_EXTRA_BUTTON_INFO_MIN_WIDTH_DEFAULT); + Support::setIfNotSet($formSpec, F_ACTIVATE_FIRST_REQUIRED_TAB, 1); // In case there is no F_MODE defined on the form, check if there is one in STORE_SIP. // if ($formSpec[F_MODE] == '') { diff --git a/extension/Classes/Core/Save.php b/extension/Classes/Core/Save.php index 8514f9e8eb41b2d7cd90e92b953d5a5a89757329..bc3e5d08d9f863073e2369ee4703aa639a629c86 100644 --- a/extension/Classes/Core/Save.php +++ b/extension/Classes/Core/Save.php @@ -71,7 +71,7 @@ class Save { $this->evaluate = new Evaluate($this->store, $this->db); $this->formAction = new FormAction($formSpec, $this->db); - $this->qfqLogFilename = $this->store->getVar(SYSTEM_QFQ_LOG, STORE_SYSTEM); + $this->qfqLogFilename = $this->store->getVar(SYSTEM_SITE_PATH, STORE_SYSTEM) . '/' . $this->store->getVar(SYSTEM_QFQ_LOG, STORE_SYSTEM); } diff --git a/extension/Classes/Sql/formEditor.sql b/extension/Classes/Sql/formEditor.sql index 9840ec3224ba2cecb51693f6ccc126042182693a..6b3809d252ca7d56c0e2d960bbd510833264958c 100644 --- a/extension/Classes/Sql/formEditor.sql +++ b/extension/Classes/Sql/formEditor.sql @@ -405,10 +405,11 @@ VALUES (2, 'feIdContainer', 'Container', 'show', 'select', 'all', 'native', 120, '{{SELECT IF("{{formLanguageDId:YE}}"="","hidden","show" ) }}', '', 'none'), (2, 'encode', 'Encode', 'show', 'radio', 'all', 'native', 300, 0, 0, - 'Info', '', '', '', 'buttonClass=btn-default', 101, - '', 'no', '', - '', - '', '', '', 'specialchar'), + 'Info {{SELECT IF(''{{encode:FRE:alnumx}}'' = ''specialchar'' AND ''{{checkType:FRE:alnumx}}'' = ''allbut'', "
Encode ''specialchar'' is not completely compatible with Check Type ''allbut'': certain user input will be converted to its HTML representation (e.g. &quot;), which makes use of a non-supported character (&)", '''') }}', + '', '', '', 'buttonClass=btn-default', + 101, '', 'yes', '', '', '', '', '', 'specialchar'), + + (2, 'checkType', 'Check Type', 'show', 'radio', 'all', 'native', 310, 0, 0, 'Info', '', '', '', 'buttonClass=btn-default', 101, '', 'yes', diff --git a/javascript/src/QfqForm.js b/javascript/src/QfqForm.js index 1d8889f29c3c85d365b08b6e2ac4c1d6ef29c918..db3c6721b8330e6fef19ec407e5a8c6be9582966 100644 --- a/javascript/src/QfqForm.js +++ b/javascript/src/QfqForm.js @@ -54,6 +54,8 @@ var QfqNS = QfqNS || {}; this.formImmutableDueToConcurrentAccess = false; this.lockRenewalPhase = false; this.goToAfterSave = false; + this.skipRequiredCheck = false; + this.activateFirstRequiredTab = true; this.additionalQueryParameters = { 'recordHashMd5': this.getRecordHashMd5() @@ -73,6 +75,10 @@ var QfqNS = QfqNS || {}; this.skipRequiredCheck = false; } + if (typeof $('#' + QfqNS.escapeJqueryIdSelector(this.formId)).data('activate-first-required-tab') !== 'undefined') { + this.activateFirstRequiredTab = $('#' + QfqNS.escapeJqueryIdSelector(this.formId)).data('activate-first-required-tab'); + } + this.infoLockedButton = this.infoLockedButton.bind(this); // This is required when displaying validation messages, in order to activate the tab, which has validation @@ -624,10 +630,11 @@ var QfqNS = QfqNS || {}; if (this.form.validate() !== true) { + var element = this.form.getFirstNonValidElement(); if (element.hasAttribute('name') && this.bsTabs) { var tabId = this.bsTabs.getContainingTabIdForFormControl(element.getAttribute('name')); - if (tabId) { + if (tabId && this.activateFirstRequiredTab) { this.bsTabs.activateTab(tabId); } diff --git a/less/qfq-bs.css.less b/less/qfq-bs.css.less index 30bac305372204cdb0179df6e501a4baebb38385..07256bd9449c0371835075a7d0fcfc33f7ff03c9 100644 --- a/less/qfq-bs.css.less +++ b/less/qfq-bs.css.less @@ -1147,12 +1147,18 @@ input.qfq-clear-me { } legend { - margin-bottom: 0; - margin-top: 15px; + margin-bottom: 25px; padding-bottom: 5px; font-size: 17px; } +.qfq-fieldset { + margin-top: 38px; +} + +.qfq-fieldset:first-child { + margin-top: 15px; +} /* glyphicon functions */ .icon-flipped { transform: scaleX(-1); diff --git a/mockup/error.html b/mockup/error.html new file mode 100644 index 0000000000000000000000000000000000000000..465aeacdb1481ece18fb73d44f0ba9771b34d8c7 --- /dev/null +++ b/mockup/error.html @@ -0,0 +1,168 @@ + + + + + + + + + + + + + Input Mode Switcher + + + + +
+
+ +
+
+
+
+ +
+
+ + +
+
+ +
+
+ + + +
+
+
+ + + + + + + + + + + + + \ No newline at end of file