diff --git a/extension/Classes/Core/AbstractBuildForm.php b/extension/Classes/Core/AbstractBuildForm.php index fdedb2f22915a0f59a5c95a00d07906983fe8460..111f3af107284bd410780463e542a7b1725dcefa 100644 --- a/extension/Classes/Core/AbstractBuildForm.php +++ b/extension/Classes/Core/AbstractBuildForm.php @@ -1037,22 +1037,10 @@ abstract class AbstractBuildForm { $t3VarsSip = $this->store->copyT3VarsToSip(); - return $this->buildNativeHidden(CLIENT_TYPO3VARS, $t3VarsSip); + return HelperFormElement::buildNativeHidden(CLIENT_TYPO3VARS, $t3VarsSip); } - /** - * Builds a real HTML hidden form element. Useful for checkboxes, Multiple-Select and Radios. - * - * @param $htmlFormElementName - * @param string $value - * - * @return string - */ - public function buildNativeHidden($htmlFormElementName, $value) { - return '<input type="hidden" name="' . $htmlFormElementName . '" value="' . htmlentities($value) . '">'; - } - /** * */ @@ -1101,7 +1089,7 @@ abstract class AbstractBuildForm { $json[] = $this->getFormElementForJson(CLIENT_SIP, $sipValue, [FE_MODE => FE_MODE_SHOW]); - return $this->buildNativeHidden(CLIENT_SIP, $sipValue); + return HelperFormElement::buildNativeHidden(CLIENT_SIP, $sipValue); } /** @@ -1123,7 +1111,7 @@ abstract class AbstractBuildForm { private function getFormElementForJson($htmlFormElementName, $value, array $formElement, $optionIdx = 0, $optionClass = '') { $addClassRequired = array(); - $json = $this->getJsonFeMode($formElement[FE_MODE]); // disabled, required + $json = HelperFormElement::getJsonFeMode($formElement[FE_MODE]); // disabled, required $json[API_FORM_UPDATE_FORM_ELEMENT] = $htmlFormElementName; @@ -1155,7 +1143,7 @@ abstract class AbstractBuildForm { // Label if (isset($formElement[FE_LABEL])) { $key = $formElement[FE_HTML_ID] . HTML_ID_EXTENSION_LABEL; - $json[API_ELEMENT_UPDATE][$key][API_ELEMENT_CONTENT] = $this->buildLabel($htmlFormElementName, $formElement[FE_LABEL], $addClassRequired[FE_LABEL] ?? ''); + $json[API_ELEMENT_UPDATE][$key][API_ELEMENT_CONTENT] = HelperFormElement::buildLabel($htmlFormElementName, $formElement[FE_LABEL], $addClassRequired[FE_LABEL] ?? ''); } // Note @@ -1194,7 +1182,7 @@ abstract class AbstractBuildForm { // Update label class (i.e.: 'qfq-disabled') of Checkbox/Radio (i.e. readonly on/off). if (isset($formElement[FE_TMP_CLASS_OPTION])) { - $optionsLabelId = $this->getCheckboxRadioOptionId($formElement[FE_HTML_ID], $optionIdx, HTML_ID_EXTENSION_LABEL); + $optionsLabelId = HelperFormElement::getCheckboxRadioOptionId($formElement[FE_HTML_ID], $optionIdx, HTML_ID_EXTENSION_LABEL); $json[API_ELEMENT_UPDATE][$optionsLabelId][API_ELEMENT_ATTRIBUTE]['class'] = $formElement[FE_TMP_CLASS_OPTION]; } } @@ -1244,41 +1232,6 @@ abstract class AbstractBuildForm { return $json; } - /** - * Set corresponding JSON attributes readonly/required/disabled, based on $formElement[FE_MODE]. - * - * @param string $feMode - * - * @return array - * @throws \UserFormException - */ - private function getJsonFeMode($feMode) { - - HelperFormElement::getFeMode($feMode, $dummy, $disabled, $required); - - return [API_FORM_UPDATE_DISABLED => ($disabled === 'yes'), API_FORM_UPDATE_REQUIRED => ($required === 'yes')]; - } - - - /** - * Builds a label, typically for an html-'<input>'-element. - * - * @param string $htmlFormElementName - * @param string $label - * @param string $addClass - * - * @return string - * @throws \CodeException - */ - public function buildLabel($htmlFormElementName, $label, $addClass = '') { - $attributes = Support::doAttribute('for', $htmlFormElementName); - $attributes .= Support::doAttribute('class', ['control-label', $addClass]); - - $html = Support::wrapTag("<label $attributes>", $label); - - return $html; - } - /** * Takes the current SIP ('form' and additional parameter), set SIP_RECORD_ID=0 and create a new 'NewRecordUrl'. * @@ -1516,7 +1469,7 @@ abstract class AbstractBuildForm { } } - $input .= $this->getHelpBlock() . $elementCharacterCount; + $input .= HelperFormElement::getHelpBlock() . $elementCharacterCount; if (isset($formElement[FE_INPUT_EXTRA_BUTTON_INFO])) { $input .= $formElement[FE_INPUT_EXTRA_BUTTON_INFO]; @@ -1631,16 +1584,6 @@ abstract class AbstractBuildForm { return $sql; } - - /** - * Build HelpBlock - * - * @return string - */ - private function getHelpBlock() { - return '<div class="help-block with-errors hidden"></div>'; - } - /** * Builds HTML 'checkbox' element. * @@ -1708,406 +1651,6 @@ abstract class AbstractBuildForm { } - /** - * Build a Checkbox based on two values. Either in HTML plain layout or with Bootstrap Button class. - * - * @param array $formElement - * @param string $htmlFormElementName - * @param string $attribute - * @param string $value - * @param array $json - * @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE - * - * @return string - * @throws \CodeException - * @throws \UserFormException - */ - public function buildCheckboxSingle(array $formElement, $htmlFormElementName, $attribute, $value, array &$json, $mode = FORM_LOAD) { - - if (isset($formElement[FE_BUTTON_CLASS])) { - - if ($formElement[FE_BUTTON_CLASS] == '') { - $formElement[FE_BUTTON_CLASS] = 'btn-default'; - } - - if ($formElement[FE_MODE] == FE_MODE_READONLY) { - $formElement[FE_BUTTON_CLASS] .= ' disabled'; - } - - return $this->constructCheckboxSingleButton($formElement, $htmlFormElementName, $attribute, $value, $json); - } else { - return $this->constructCheckboxSinglePlain($formElement, $htmlFormElementName, $attribute, $value, $json); - } - } - - /** - * Build a Checkbox based on two values with Bootstrap Button class. - * - * <div class="btn-group" data-toggle="buttons"> - * <input type="hidden" name="$htmlFormElementName" value="$valueUnChecked"> - * <label class="btn btn-primary active"> - * <input type="checkbox" autocomplete="off" name="$htmlFormElementName" value="$valueChecked"checked> - * Checkbox 1 (pre-checked) - * </label> - * </div> - * - * @param array $formElement - * @param string $htmlFormElementName - * @param string $attribute - * @param string $value - * @param array $json - * - * @return string - * @throws \CodeException - * @throws \UserFormException - */ - public function constructCheckboxSingleButton(array $formElement, $htmlFormElementName, $attribute, $value, array &$json) { - $html = ''; - $valueJson = false; - - $attribute .= Support::doAttribute('id', $formElement[FE_HTML_ID]); - $attribute .= Support::doAttribute('name', $htmlFormElementName); - $attribute .= Support::doAttribute('value', $formElement[FE_CHECKBOX_CHECKED], false); - $attribute .= Support::doAttribute('data-load', ($formElement[FE_DYNAMIC_UPDATE] === 'yes') ? 'data-load' : ''); - $attribute .= Support::doAttribute(FE_INPUT_AUTOCOMPLETE, 'off'); - $attribute .= Support::doAttribute(ATTRIBUTE_DATA_REFERENCE, $formElement[FE_DATA_REFERENCE]); - - $classActive = ''; - if ($formElement[FE_CHECKBOX_CHECKED] === $value) { - $attribute .= Support::doAttribute('checked', 'checked'); - $valueJson = true; - $classActive = ' active'; - } - - $attribute .= HelperFormElement::getAttributeList($formElement, ['autofocus']); - $attribute .= HelperFormElement::getAttributeList($formElement, [F_FE_DATA_PATTERN_ERROR, F_FE_DATA_REQUIRED_ERROR, F_FE_DATA_MATCH_ERROR, F_FE_DATA_ERROR]); - - $htmlHidden = $this->buildNativeHidden($htmlFormElementName, $formElement[FE_CHECKBOX_UNCHECKED]); - $this->store->setVar($htmlFormElementName, $htmlHidden, STORE_ADDITIONAL_FORM_ELEMENTS, false); - $html = ''; - - $htmlElement = '<input ' . $attribute . '>'; - if (isset($formElement['label2'])) { - $htmlElement .= $formElement['label2']; - } else { - $htmlElement .= $formElement['checked']; - } - - $labelAttribute = Support::doAttribute('title', $formElement[FE_TOOLTIP]); - $labelAttribute .= Support::doAttribute('class', 'btn ' . $formElement[FE_BUTTON_CLASS] . $classActive); - $html .= Support::wrapTag("<label $labelAttribute>", $htmlElement, true); - $html = Support::wrapTag('<div class="btn-group" data-toggle="buttons">', $html); - - $json = $this->getFormElementForJson($htmlFormElementName, $valueJson, $formElement); - - return $html; - } - - /** - * Build a single HTML plain checkbox based on two values. - * Create a 'hidden' input field and a 'checkbox' input field - both with the same HTML 'name'. - * HTML does not submit an unchecked checkbox. Then only the 'hidden' input field is submitted. - * - * Format: <input type="hidden" name="$htmlFormElementName" value="$valueUnChecked"> - * <input name="$htmlFormElementName" type="radio" [autofocus="autofocus"] - * [required="required"] [disabled="disabled"] value="<value>" [checked="checked"] > - * - * @param array $formElement - * @param string $htmlFormElementName - * @param string $attribute - * @param string $value - * @param array $json - * - * @return string - * @throws \CodeException - * @throws \UserFormException - */ - public function constructCheckboxSinglePlain(array $formElement, $htmlFormElementName, $attribute, $value, array &$json) { - $html = ''; - $valueJson = false; - - $attribute .= Support::doAttribute('id', $formElement[FE_HTML_ID]); - $attribute .= Support::doAttribute('name', $htmlFormElementName); - $attribute .= Support::doAttribute('value', $formElement[FE_CHECKBOX_CHECKED], false); - $attribute .= Support::doAttribute('data-load', ($formElement[FE_DYNAMIC_UPDATE] === 'yes') ? 'data-load' : ''); - $attribute .= Support::doAttribute(ATTRIBUTE_DATA_REFERENCE, $formElement[FE_DATA_REFERENCE]); - - if ($formElement[FE_CHECKBOX_CHECKED] === $value) { - $attribute .= Support::doAttribute('checked', 'checked'); - $valueJson = $value; - } - - $attribute .= HelperFormElement::getAttributeList($formElement, ['autofocus']); - $attribute .= HelperFormElement::getAttributeList($formElement, [F_FE_DATA_PATTERN_ERROR, F_FE_DATA_REQUIRED_ERROR, F_FE_DATA_MATCH_ERROR, F_FE_DATA_ERROR]); - - $htmlHidden = $this->buildNativeHidden($htmlFormElementName, $formElement[FE_CHECKBOX_UNCHECKED]); - $this->store->setVar($htmlFormElementName, $htmlHidden, STORE_ADDITIONAL_FORM_ELEMENTS, false); - $html = ''; - - $html .= '<input ' . $attribute . '>'; - if (isset($formElement['label2'])) { - $html .= Support::wrapTag("<span style='font-weight: 400;'>", $formElement['label2']); - } - - $labelAttribute = Support::doAttribute('title', $formElement[FE_TOOLTIP]); - - $class = 'checkbox'; - if ($formElement[FE_MODE] == FE_MODE_READONLY) { - $class .= ' qfq-disabled'; // necessary for own style checkboxes to display them 'disabled' - } - - $html = Support::wrapTag("<label class='$class' $labelAttribute>", $html, true); -// $html = Support::wrapTag("<div class='checkbox'>", $html, true); - - $json = $this->getFormElementForJson($htmlFormElementName, $valueJson, $formElement); - - return $html; - } - - /** - * Build a Checkbox based on two values. Either in HTML plain layout or with Bootstrap Button class. - * - * @param array $formElement - * @param string $htmlFormElementName - * @param $attributeBase - * @param string $value - * @param array $itemKey - * @param array $itemValue - * @param array $json - * @return string - * @throws \CodeException - * @throws \UserFormException - */ - public function buildCheckboxMulti(array $formElement, $htmlFormElementName, $attributeBase, $value, array $itemKey, array $itemValue, array &$json) { - - if (isset($formElement[FE_BUTTON_CLASS])) { - - if ($formElement[FE_BUTTON_CLASS] == '') { - $formElement[FE_BUTTON_CLASS] = 'btn-default'; - } - - if ($formElement[FE_MODE] == FE_MODE_READONLY) { - $formElement[FE_BUTTON_CLASS] .= ' disabled'; - } - - return $this->constructCheckboxMultiButton($formElement, $htmlFormElementName, $attributeBase, $value, $itemKey, $itemValue, $json); - } else { - return $this->constructCheckboxMultiPlain($formElement, $htmlFormElementName, $attributeBase, $value, $itemKey, $itemValue, $json); - } - } - - /** - * @param array $formElement - * @param string $htmlFormElementName - * @param string $htmlHidden - * @throws \CodeException - * @throws \UserFormException - */ - private function fillStoreAdditionalFormElementsCheckboxHidden(array $formElement, $htmlFormElementName, $htmlHidden) { - - if (isset($formElement[NAME_TG_COPIES]) && $formElement[NAME_TG_COPIES] > 0) { - for ($ii = 1; $ii <= $formElement[NAME_TG_COPIES]; $ii++) { - $key = str_replace('%d', $ii, $htmlFormElementName); - $value = str_replace('%d', $ii, $htmlHidden); - $this->store->setVar($key, $value, STORE_ADDITIONAL_FORM_ELEMENTS, true); - } - } else { - $this->store->setVar($htmlFormElementName, $htmlHidden, STORE_ADDITIONAL_FORM_ELEMENTS, false); - } - } - - /** - * Build as many Checkboxes as items. - * - * Layout: The Bootstrap Layout needs very special setup, the checkboxes are wrapped differently with <div - * class=checkbox> depending of if they aligned horizontal or vertical. - * - * @param array $formElement - * @param string $htmlFormElementName - * @param string $attributeBase - * @param string $value - * @param array $itemKey - * @param array $itemValue - * @param array $json - * - * @return string - * @throws \CodeException - * @throws \UserFormException - */ - public function constructCheckboxMultiButton(array $formElement, $htmlFormElementName, $attributeBase, $value, array $itemKey, array $itemValue, array &$json) { - $json = array(); - - // Defines which of the checkboxes will be checked. - $values = explode(',', $value); - - $attributeBase .= Support::doAttribute('data-load', ($formElement[FE_DYNAMIC_UPDATE] === 'yes') ? 'data-load' : ''); - $attributeBase .= HelperFormElement::getAttributeList($formElement, [F_FE_DATA_PATTERN_ERROR, F_FE_DATA_REQUIRED_ERROR, F_FE_DATA_MATCH_ERROR, F_FE_DATA_ERROR]); - - $key = HelperFormElement::prependFormElementNameCheckBoxMulti($htmlFormElementName, 'h', true); - $htmlHidden = $this->buildNativeHidden($key, ''); - $this->fillStoreAdditionalFormElementsCheckboxHidden($formElement, $htmlFormElementName, $htmlHidden); - - $html = ''; - - $attribute = $attributeBase; - if (isset($formElement[FE_AUTOFOCUS])) { - $attribute .= Support::doAttribute('autofocus', $formElement[FE_AUTOFOCUS]); - } - - for ($ii = 0, $jj = 1; $ii < count($itemKey); $ii++, $jj++) { - $jsonValue = false; - $classActive = ''; - $htmlFormElementNameUniq = HelperFormElement::prependFormElementNameCheckBoxMulti($htmlFormElementName, $ii, true); - $attribute .= Support::doAttribute('id', $formElement[FE_HTML_ID] . '-' . $ii); - $attribute .= Support::doAttribute('name', $htmlFormElementNameUniq); - $attribute .= Support::doAttribute(ATTRIBUTE_DATA_REFERENCE, $formElement[FE_DATA_REFERENCE] . '-' . $ii); - - - $attribute .= Support::doAttribute('value', $itemKey[$ii], false); - - // Check if the given key is found in field. - if (false !== array_search($itemKey[$ii], $values)) { - $attribute .= Support::doAttribute('checked', 'checked'); - $jsonValue = true; - $classActive = ' active'; - } - - // ' ' - This is necessary to correctly align an empty input. - $value = ($itemValue[$ii] === '') ? ' ' : $itemValue[$ii]; - - $htmlElement = '<input ' . $attribute . '>' . $value; - - $html .= Support::wrapTag("<label class='btn " . $formElement[FE_BUTTON_CLASS] . "$classActive'>", - $htmlElement, true); - - $json[] = $this->getFormElementForJson($htmlFormElementNameUniq, $jsonValue, $formElement); - - // Init for the next checkbox - $attribute = $attributeBase; - } - - $html = Support::wrapTag('<div class="btn-group" data-toggle="buttons">', $html); - - return $html; - } - - /** - * Build as many Checkboxes as items. - * - * Layout: The Bootstrap Layout needs very special setup, the checkboxes are wrapped differently with <div - * class=checkbox> depending of if they aligned horizontal or vertical. - * - * @param array $formElement - * @param string $htmlFormElementName - * @param string $attributeBase - * @param string $value - * @param array $itemKey - * @param array $itemValue - * @param array $json - * - * @return string - * @throws \CodeException - * @throws \UserFormException - */ - public function constructCheckboxMultiPlain(array $formElement, $htmlFormElementName, $attributeBase, $value, array $itemKey, array $itemValue, array &$json) { - $json = array(); - - // Defines which of the checkboxes will be checked. - $values = explode(',', $value); - - $attributeBase .= Support::doAttribute('data-load', ($formElement[FE_DYNAMIC_UPDATE] === 'yes') ? 'data-load' : ''); - $attributeBase .= HelperFormElement::getAttributeList($formElement, [F_FE_DATA_PATTERN_ERROR, F_FE_DATA_REQUIRED_ERROR, F_FE_DATA_MATCH_ERROR, F_FE_DATA_ERROR]); - - // 'font-weight: 400;': class 'checkbox' forces bold for the label - this is not ok. - $attributeBaseLabel = Support::doAttribute('style', 'min-width: ' . $formElement[F_FE_MIN_WIDTH] . 'px; font-weight: 400;'); - -// $key = HelperFormElement::prependFormElementNameCheckBoxMulti($htmlFormElementName, 'h'); -// $htmlHidden = $this->buildNativeHidden($key, ''); -// $this->fillStoreAdditionalFormElementsCheckboxHidden($formElement, $htmlFormElementName, $htmlHidden); - - $html = ''; - - $orientation = ($formElement[FE_MAX_LENGTH] > 1) ? ALIGN_HORIZONTAL : ALIGN_VERTICAL; - $checkboxClass = ($orientation === ALIGN_HORIZONTAL) ? 'checkbox-inline' : 'checkbox'; - if ($formElement[FE_MODE] == FE_MODE_READONLY) { - $checkboxClass .= ' qfq-disabled'; // necessary for own style checkboxes to display them 'disabled' - } - // Used in getFormElementForJson() for dynamic update. - $formElement[FE_TMP_CLASS_OPTION] = $checkboxClass; - - $br = ''; - - $flagFirst = true; - for ($ii = 0, $jj = 1; $ii < count($itemKey); $ii++, $jj++) { - $jsonValue = false; - $attribute = $attributeBase; - $htmlFormElementNameUniq = HelperFormElement::prependFormElementNameCheckBoxMulti($htmlFormElementName, $ii, true); - $checkboxId = $this->getCheckboxRadioOptionId($formElement[FE_HTML_ID], $ii); - $attribute .= Support::doAttribute('id', $checkboxId); - $attribute .= Support::doAttribute('name', $htmlFormElementNameUniq); - $attribute .= Support::doAttribute(ATTRIBUTE_DATA_REFERENCE, $formElement[FE_DATA_REFERENCE] . '-' . $ii); - - // Do this only the first round. - if ($flagFirst) { - $flagFirst = false; - if (isset($formElement[FE_AUTOFOCUS])) - $attribute .= Support::doAttribute('autofocus', $formElement[FE_AUTOFOCUS]); - } - - $attribute .= Support::doAttribute('value', $itemKey[$ii], false); - - // Check if the given key is found in field. - if (false !== array_search($itemKey[$ii], $values)) { - $attribute .= Support::doAttribute('checked', 'checked'); - $jsonValue = true; - } - - // ' ' - This is necessary to correctly align an empty input. - $value = ($itemValue[$ii] === '') ? ' ' : $itemValue[$ii]; - - $htmlElement = '<input ' . $attribute . '>' . $value; - - // With ALIGN_HORIZONTAL: the label causes some trouble: skip it -// if (($orientation === ALIGN_VERTICAL)) { -// $htmlElement = Support::wrapTag('<label>', $htmlElement); -// } - - $checkboxLabelId = $this->getCheckboxRadioOptionId($formElement[FE_HTML_ID], $ii, HTML_ID_EXTENSION_LABEL); - $htmlElement = Support::wrapTag("<label class='$checkboxClass' $attributeBaseLabel id='$checkboxLabelId'>", $htmlElement, true); - - // control orientation - if ($formElement[FE_MAX_LENGTH] > 1) { - - if ($jj == $formElement[FE_MAX_LENGTH]) { - $jj = 0; - $br = '<br>'; - } else { - $br = ''; - } - } - - $html .= $htmlElement . $br; - $json[] = $this->getFormElementForJson($htmlFormElementNameUniq, $jsonValue, $formElement, $ii, $checkboxClass); - - } - - return $html; - } - - /** - * Construct HTML ID for checkbox/radio option elements. - * Optional add $type. - * Example: $base='173-21612-1-0', $index='0', $type='l' >> '173-21612-1-0-0-l' - * - * @param $base - * @param $index - * @param string $type - ';' for label - * @return string - */ - private function getCheckboxRadioOptionId($base, $index, $type = '') { - return $base . '-' . $index . $type; - } - /** * Submit extra (hidden) values by SIP. * @@ -2167,7 +1710,7 @@ abstract class AbstractBuildForm { $formElement = HelperFormElement::prepareExtraButton($formElement, false); - return $html . $formElement[FE_TMP_EXTRA_BUTTON_HTML] . $this->getHelpBlock() . $formElement[FE_INPUT_EXTRA_BUTTON_INFO]; + return $html . $formElement[FE_TMP_EXTRA_BUTTON_HTML] . HelperFormElement::getHelpBlock() . $formElement[FE_INPUT_EXTRA_BUTTON_INFO]; } @@ -2281,6 +1824,7 @@ abstract class AbstractBuildForm { * @return string * @throws \CodeException * @throws \UserFormException + * @throws \UserReportException */ private function constructRadioPlain(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) { $attributeBase = ''; @@ -2326,7 +1870,7 @@ abstract class AbstractBuildForm { for ($ii = 0; $ii < count($itemValue); $ii++) { $jj++; - $optionId = $this->getCheckboxRadioOptionId($formElement[FE_HTML_ID], $ii); + $optionId = HelperFormElement::getCheckboxRadioOptionId($formElement[FE_HTML_ID], $ii); $attribute .= Support::doAttribute('id', $optionId); $attribute .= Support::doAttribute('value', $itemKey[$ii], false); // Always set value, even to '' - #3832 $attribute .= Support::doAttribute(ATTRIBUTE_DATA_REFERENCE, $formElement[FE_DATA_REFERENCE] . '-' . $ii); @@ -2358,7 +1902,7 @@ abstract class AbstractBuildForm { $wrapAttribute = Support::doAttribute('title', $formElement[FE_TOOLTIP]); $wrapAttribute .= Support::doAttribute('class', $radioClass); - $radioLabelId = $this->getCheckboxRadioOptionId($formElement[FE_HTML_ID], $ii, HTML_ID_EXTENSION_LABEL); + $radioLabelId = HelperFormElement::getCheckboxRadioOptionId($formElement[FE_HTML_ID], $ii, HTML_ID_EXTENSION_LABEL); $htmlElement = Support::wrapTag("<label $wrapAttribute $attributeBaseLabel id='$radioLabelId'>", $htmlElement) . $br; $html .= $htmlElement; @@ -2366,7 +1910,7 @@ abstract class AbstractBuildForm { $attribute = $attributeBase; // Update label class (i.e.: 'qfq-disabled') of Checkbox/Radio (i.e. readonly on/off). - $optionLabelId = $this->getCheckboxRadioOptionId($formElement[FE_HTML_ID], $ii, HTML_ID_EXTENSION_LABEL); + $optionLabelId = HelperFormElement::getCheckboxRadioOptionId($formElement[FE_HTML_ID], $ii, HTML_ID_EXTENSION_LABEL); $jsonTmp[API_ELEMENT_UPDATE][$optionLabelId][API_ELEMENT_ATTRIBUTE]['class'] = $formElement[FE_TMP_CLASS_OPTION]; $jsonTmp[API_ELEMENT_UPDATE][$optionId][API_ELEMENT_ATTRIBUTE]['required'] = ($formElement[FE_MODE] == FE_MODE_REQUIRED) ? 'required' : 'false'; @@ -2462,7 +2006,7 @@ abstract class AbstractBuildForm { } else { $html = '<select ' . $attribute . '>' . $option . '</select>'; } - $html = $html . $this->getHelpBlock() . $formElement[FE_TMP_EXTRA_BUTTON_HTML]; + $html = $html . HelperFormElement::getHelpBlock() . $formElement[FE_TMP_EXTRA_BUTTON_HTML]; return $html . $formElement[FE_INPUT_EXTRA_BUTTON_INFO]; } @@ -3083,7 +2627,7 @@ abstract class AbstractBuildForm { $sipUpload = $this->sip->queryStringToSip(OnArray::toString($arr), RETURN_SIP); - $hiddenSipUpload = $this->buildNativeHidden($htmlFormElementName, $sipUpload); + $hiddenSipUpload = HelperFormElement::buildNativeHidden($htmlFormElementName, $sipUpload); $attribute .= Support::doAttribute('id', $formElement[FE_HTML_ID]); $attribute .= Support::doAttribute('name', $htmlFormElementName); @@ -3116,7 +2660,7 @@ abstract class AbstractBuildForm { $attribute .= HelperFormElement::getAttributeFeMode($formElement[FE_MODE]); $attribute .= Support::doAttribute('class', $uploadClass, true); -// $htmlInputFile = '<input ' . $attribute . '>' . $this->getHelpBlock(); +// $htmlInputFile = '<input ' . $attribute . '>' . HelperFormElement::getHelpBlock(); // <input type="file"> with BS3: https://stackoverflow.com/questions/11235206/twitter-bootstrap-form-file-element-upload-button/25053973#25053973 $attribute .= Support::doAttribute('style', "display:none;"); @@ -3253,7 +2797,7 @@ abstract class AbstractBuildForm { $htmlInput = Support::wrapTag('<input ' . $attributeInput . ' >', '', false); - $html = $htmlAnnotate . $htmlInput . $this->getHelpBlock(); + $html = $htmlAnnotate . $htmlInput . HelperFormElement::getHelpBlock(); // $json = $this->getFormElementForJson($htmlFormElementName, $value, $formElement); @@ -3316,7 +2860,7 @@ abstract class AbstractBuildForm { $htmlInput = Support::wrapTag('<input ' . $attributeInput . ' >', '', false); - $html = $htmlFabric . $htmlInput . $this->getHelpBlock(); + $html = $htmlFabric . $htmlInput . HelperFormElement::getHelpBlock(); // $json = $this->getFormElementForJson($htmlFormElementName, $value, $formElement); @@ -3389,7 +2933,7 @@ abstract class AbstractBuildForm { $attributeImage = Support::doAttribute('id', $htmlFabricImageId); $htmlImage = Support::wrapTag('<img ' . $attributeImage . '>', '', false); - $html = $htmlFabric . $this->getHelpBlock() . $htmlInput . $htmlImage; + $html = $htmlFabric . HelperFormElement::getHelpBlock() . $htmlInput . $htmlImage; // $tmpUrlParam[DOWNLOAD_MODE] = $this->getDownloadModeNCheck($vars); // $tmpUrlParam[DOWNLOAD_EXPORT_FILENAME] = $vars[NAME_DOWNLOAD]; @@ -3528,7 +3072,7 @@ abstract class AbstractBuildForm { $attribute .= HelperFormElement::getAttributeFeMode($formElement[FE_MODE]); - $input = "<input $attribute>" . $this->getHelpBlock() . $formElement[FE_TMP_EXTRA_BUTTON_HTML]; + $input = "<input $attribute>" . HelperFormElement::getHelpBlock() . $formElement[FE_TMP_EXTRA_BUTTON_HTML]; if ($formElement[FE_TMP_EXTRA_BUTTON_HTML] !== '') { $input = Support::wrapTag('<div class="input-group">', $input); @@ -3622,7 +3166,7 @@ abstract class AbstractBuildForm { $element = Support::wrapTag("<div $attribute>", '', false); - return $element . $this->getHelpBlock(); + return $element . HelperFormElement::getHelpBlock(); } /** @@ -3672,7 +3216,7 @@ abstract class AbstractBuildForm { $html = Support::wrapTag("<textarea $attribute>", htmlentities($value), false); $formElement = HelperFormElement::prepareExtraButton($formElement, false); - return $html . $this->getHelpBlock() . $formElement[FE_TMP_EXTRA_BUTTON_HTML] . $formElement[FE_INPUT_EXTRA_BUTTON_INFO]; + return $html . HelperFormElement::getHelpBlock() . $formElement[FE_TMP_EXTRA_BUTTON_HTML] . $formElement[FE_INPUT_EXTRA_BUTTON_INFO]; } /** diff --git a/extension/Classes/Core/BuildFormBootstrap.php b/extension/Classes/Core/BuildFormBootstrap.php index 11cea35a30c27cefc903762394f1933cc131eae5..8922293e18252b548af7374e8a98ed23f5976e9b 100644 --- a/extension/Classes/Core/BuildFormBootstrap.php +++ b/extension/Classes/Core/BuildFormBootstrap.php @@ -807,7 +807,7 @@ EOF; // Label if ($formElement[FE_BS_LABEL_COLUMNS] != '0') { - $htmlLabel = $this->buildLabel($htmlFormElementName, $formElement[FE_LABEL], $addClassRequired[FE_LABEL] ?? ''); + $htmlLabel = HelperFormElement::buildLabel($htmlFormElementName, $formElement[FE_LABEL], $addClassRequired[FE_LABEL] ?? ''); } $html .= $this->customWrap($formElement, $htmlLabel, FE_WRAP_LABEL, $formElement[FE_BS_LABEL_COLUMNS], diff --git a/extension/Classes/Core/Form/Checkbox.php b/extension/Classes/Core/Form/Checkbox.php index 727b841ef44a40674423c65e89b245f232517770..a167c55d8e4846b9cf766d52f5e7996b0982012e 100644 --- a/extension/Classes/Core/Form/Checkbox.php +++ b/extension/Classes/Core/Form/Checkbox.php @@ -23,6 +23,7 @@ use IMATHUZH\Qfq\Core\Helper\Support; //use IMATHUZH\Qfq\Core\Store\Sip; use IMATHUZH\Qfq\Core\Helper\HelperFormElement; use IMATHUZH\Qfq\Core\Store\Store; +use TYPO3\PharStreamWrapper\Helper; /** @@ -96,7 +97,7 @@ class Checkbox { $formElement = HelperFormElement::prepareExtraButton($formElement, false); - return $html . $formElement[FE_TMP_EXTRA_BUTTON_HTML] . $this->getHelpBlock() . $formElement[FE_INPUT_EXTRA_BUTTON_INFO]; + return $html . $formElement[FE_TMP_EXTRA_BUTTON_HTML] . HelperFormElement::getHelpBlock() . $formElement[FE_INPUT_EXTRA_BUTTON_INFO]; } /** @@ -135,7 +136,532 @@ class Checkbox { if ($formElement[FE_CHECKBOX_CHECKED] === $formElement[FE_CHECKBOX_UNCHECKED]) { throw new \UserFormException('FormElement: type=checkbox - checked and unchecked can\'t be the same: ' . $formElement[FE_CHECKBOX_CHECKED], ERROR_CHECKBOX_EQUAL); } + } + + /** + * Build a Checkbox based on two values. Either in HTML plain layout or with Bootstrap Button class. + * + * @param array $formElement + * @param string $htmlFormElementName + * @param $attributeBase + * @param string $value + * @param array $itemKey + * @param array $itemValue + * @param array $json + * @return string + * @throws \CodeException + * @throws \UserFormException + */ + public function buildCheckboxMulti(array $formElement, $htmlFormElementName, $attributeBase, $value, array $itemKey, array $itemValue, array &$json) { + + if (isset($formElement[FE_BUTTON_CLASS])) { + + if ($formElement[FE_BUTTON_CLASS] == '') { + $formElement[FE_BUTTON_CLASS] = 'btn-default'; + } + + if ($formElement[FE_MODE] == FE_MODE_READONLY) { + $formElement[FE_BUTTON_CLASS] .= ' disabled'; + } + return $this->constructCheckboxMultiButton($formElement, $htmlFormElementName, $attributeBase, $value, $itemKey, $itemValue, $json); + } else { + return $this->constructCheckboxMultiPlain($formElement, $htmlFormElementName, $attributeBase, $value, $itemKey, $itemValue, $json); + } } + /** + * Build as many Checkboxes as items. + * + * Layout: The Bootstrap Layout needs very special setup, the checkboxes are wrapped differently with <div + * class=checkbox> depending of if they aligned horizontal or vertical. + * + * @param array $formElement + * @param string $htmlFormElementName + * @param string $attributeBase + * @param string $value + * @param array $itemKey + * @param array $itemValue + * @param array $json + * + * @return string + * @throws \CodeException + * @throws \UserFormException + */ + private function constructCheckboxMultiButton(array $formElement, $htmlFormElementName, $attributeBase, $value, array $itemKey, array $itemValue, array &$json) { + $json = array(); + + // Defines which of the checkboxes will be checked. + $values = explode(',', $value); + + $attributeBase .= Support::doAttribute('data-load', ($formElement[FE_DYNAMIC_UPDATE] === 'yes') ? 'data-load' : ''); + $attributeBase .= HelperFormElement::getAttributeList($formElement, [F_FE_DATA_PATTERN_ERROR, F_FE_DATA_REQUIRED_ERROR, F_FE_DATA_MATCH_ERROR, F_FE_DATA_ERROR]); + + $key = HelperFormElement::prependFormElementNameCheckBoxMulti($htmlFormElementName, 'h', true); + $htmlHidden = HelperFormElement::buildNativeHidden($key, ''); + $this->fillStoreAdditionalFormElementsCheckboxHidden($formElement, $htmlFormElementName, $htmlHidden); + + $html = ''; + + $attribute = $attributeBase; + if (isset($formElement[FE_AUTOFOCUS])) { + $attribute .= Support::doAttribute('autofocus', $formElement[FE_AUTOFOCUS]); + } + + for ($ii = 0, $jj = 1; $ii < count($itemKey); $ii++, $jj++) { + $jsonValue = false; + $classActive = ''; + $htmlFormElementNameUniq = HelperFormElement::prependFormElementNameCheckBoxMulti($htmlFormElementName, $ii, true); + $attribute .= Support::doAttribute('id', $formElement[FE_HTML_ID] . '-' . $ii); + $attribute .= Support::doAttribute('name', $htmlFormElementNameUniq); + $attribute .= Support::doAttribute(ATTRIBUTE_DATA_REFERENCE, $formElement[FE_DATA_REFERENCE] . '-' . $ii); + + + $attribute .= Support::doAttribute('value', $itemKey[$ii], false); + + // Check if the given key is found in field. + if (false !== array_search($itemKey[$ii], $values)) { + $attribute .= Support::doAttribute('checked', 'checked'); + $jsonValue = true; + $classActive = ' active'; + } + + // ' ' - This is necessary to correctly align an empty input. + $value = ($itemValue[$ii] === '') ? ' ' : $itemValue[$ii]; + + $htmlElement = '<input ' . $attribute . '>' . $value; + + $html .= Support::wrapTag("<label class='btn " . $formElement[FE_BUTTON_CLASS] . "$classActive'>", + $htmlElement, true); + + $json[] = $this->getFormElementForJsonCheckBox($htmlFormElementNameUniq, $jsonValue, $formElement); + + // Init for the next checkbox + $attribute = $attributeBase; + } + + $html = Support::wrapTag('<div class="btn-group" data-toggle="buttons">', $html); + + return $html; + } + + /** + * Build as many Checkboxes as items. + * + * Layout: The Bootstrap Layout needs very special setup, the checkboxes are wrapped differently with <div + * class=checkbox> depending of if they aligned horizontal or vertical. + * + * @param array $formElement + * @param string $htmlFormElementName + * @param string $attributeBase + * @param string $value + * @param array $itemKey + * @param array $itemValue + * @param array $json + * + * @return string + * @throws \CodeException + * @throws \UserFormException + */ + private function constructCheckboxMultiPlain(array $formElement, $htmlFormElementName, $attributeBase, $value, array $itemKey, array $itemValue, array &$json) { + $json = array(); + + // Defines which of the checkboxes will be checked. + $values = explode(',', $value); + + $attributeBase .= Support::doAttribute('data-load', ($formElement[FE_DYNAMIC_UPDATE] === 'yes') ? 'data-load' : ''); + $attributeBase .= HelperFormElement::getAttributeList($formElement, [F_FE_DATA_PATTERN_ERROR, F_FE_DATA_REQUIRED_ERROR, F_FE_DATA_MATCH_ERROR, F_FE_DATA_ERROR]); + + // 'font-weight: 400;': class 'checkbox' forces bold for the label - this is not ok. + $attributeBaseLabel = Support::doAttribute('style', 'min-width: ' . $formElement[F_FE_MIN_WIDTH] . 'px; font-weight: 400;'); + +// $key = HelperFormElement::prependFormElementNameCheckBoxMulti($htmlFormElementName, 'h'); +// $htmlHidden = HelperFormElement::buildNativeHidden($key, ''); +// $this->fillStoreAdditionalFormElementsCheckboxHidden($formElement, $htmlFormElementName, $htmlHidden); + + $html = ''; + + $orientation = ($formElement[FE_MAX_LENGTH] > 1) ? ALIGN_HORIZONTAL : ALIGN_VERTICAL; + $checkboxClass = ($orientation === ALIGN_HORIZONTAL) ? 'checkbox-inline' : 'checkbox'; + if ($formElement[FE_MODE] == FE_MODE_READONLY) { + $checkboxClass .= ' qfq-disabled'; // necessary for own style checkboxes to display them 'disabled' + } + // Used in getFormElementForJson() for dynamic update. + $formElement[FE_TMP_CLASS_OPTION] = $checkboxClass; + + $br = ''; + + $flagFirst = true; + for ($ii = 0, $jj = 1; $ii < count($itemKey); $ii++, $jj++) { + $jsonValue = false; + $attribute = $attributeBase; + $htmlFormElementNameUniq = HelperFormElement::prependFormElementNameCheckBoxMulti($htmlFormElementName, $ii, true); + $checkboxId = HelperFormElement::getCheckboxRadioOptionId($formElement[FE_HTML_ID], $ii); + $attribute .= Support::doAttribute('id', $checkboxId); + $attribute .= Support::doAttribute('name', $htmlFormElementNameUniq); + $attribute .= Support::doAttribute(ATTRIBUTE_DATA_REFERENCE, $formElement[FE_DATA_REFERENCE] . '-' . $ii); + + // Do this only the first round. + if ($flagFirst) { + $flagFirst = false; + if (isset($formElement[FE_AUTOFOCUS])) + $attribute .= Support::doAttribute('autofocus', $formElement[FE_AUTOFOCUS]); + } + + $attribute .= Support::doAttribute('value', $itemKey[$ii], false); + + // Check if the given key is found in field. + if (false !== array_search($itemKey[$ii], $values)) { + $attribute .= Support::doAttribute('checked', 'checked'); + $jsonValue = true; + } + + // ' ' - This is necessary to correctly align an empty input. + $value = ($itemValue[$ii] === '') ? ' ' : $itemValue[$ii]; + + $htmlElement = '<input ' . $attribute . '>' . $value; + + // With ALIGN_HORIZONTAL: the label causes some trouble: skip it +// if (($orientation === ALIGN_VERTICAL)) { +// $htmlElement = Support::wrapTag('<label>', $htmlElement); +// } + + $checkboxLabelId = HelperFormElement::getCheckboxRadioOptionId($formElement[FE_HTML_ID], $ii, HTML_ID_EXTENSION_LABEL); + $htmlElement = Support::wrapTag("<label class='$checkboxClass' $attributeBaseLabel id='$checkboxLabelId'>", $htmlElement, true); + + // control orientation + if ($formElement[FE_MAX_LENGTH] > 1) { + + if ($jj == $formElement[FE_MAX_LENGTH]) { + $jj = 0; + $br = '<br>'; + } else { + $br = ''; + } + } + + $html .= $htmlElement . $br; + $json[] = $this->getFormElementForJsonCheckbox($htmlFormElementNameUniq, $jsonValue, $formElement, $ii, $checkboxClass); + + } + + return $html; + } + + /** + * @param array $formElement + * @param string $htmlFormElementName + * @param string $htmlHidden + * @throws \CodeException + * @throws \UserFormException + */ + private function fillStoreAdditionalFormElementsCheckboxHidden(array $formElement, $htmlFormElementName, $htmlHidden) { + + if (isset($formElement[NAME_TG_COPIES]) && $formElement[NAME_TG_COPIES] > 0) { + for ($ii = 1; $ii <= $formElement[NAME_TG_COPIES]; $ii++) { + $key = str_replace('%d', $ii, $htmlFormElementName); + $value = str_replace('%d', $ii, $htmlHidden); + $this->store->setVar($key, $value, STORE_ADDITIONAL_FORM_ELEMENTS, true); + } + } else { + $this->store->setVar($htmlFormElementName, $htmlHidden, STORE_ADDITIONAL_FORM_ELEMENTS, false); + } + } + + + /** + * Build a Checkbox based on two values. Either in HTML plain layout or with Bootstrap Button class. + * + * @param array $formElement + * @param string $htmlFormElementName + * @param string $attribute + * @param string $value + * @param array $json + * @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE + * + * @return string + * @throws \CodeException + * @throws \UserFormException + */ + public function buildCheckboxSingle(array $formElement, $htmlFormElementName, $attribute, $value, array &$json, $mode = FORM_LOAD) { + + if (isset($formElement[FE_BUTTON_CLASS])) { + + if ($formElement[FE_BUTTON_CLASS] == '') { + $formElement[FE_BUTTON_CLASS] = 'btn-default'; + } + + if ($formElement[FE_MODE] == FE_MODE_READONLY) { + $formElement[FE_BUTTON_CLASS] .= ' disabled'; + } + + return $this->constructCheckboxSingleButton($formElement, $htmlFormElementName, $attribute, $value, $json); + } else { + return $this->constructCheckboxSinglePlain($formElement, $htmlFormElementName, $attribute, $value, $json); + } + } + + /** + * Build a Checkbox based on two values with Bootstrap Button class. + * + * <div class="btn-group" data-toggle="buttons"> + * <input type="hidden" name="$htmlFormElementName" value="$valueUnChecked"> + * <label class="btn btn-primary active"> + * <input type="checkbox" autocomplete="off" name="$htmlFormElementName" value="$valueChecked"checked> + * Checkbox 1 (pre-checked) + * </label> + * </div> + * + * @param array $formElement + * @param string $htmlFormElementName + * @param string $attribute + * @param string $value + * @param array $json + * + * @return string + * @throws \CodeException + * @throws \UserFormException + */ + public function constructCheckboxSingleButton(array $formElement, $htmlFormElementName, $attribute, $value, array &$json) { + $html = ''; + $valueJson = false; + + $attribute .= Support::doAttribute('id', $formElement[FE_HTML_ID]); + $attribute .= Support::doAttribute('name', $htmlFormElementName); + $attribute .= Support::doAttribute('value', $formElement[FE_CHECKBOX_CHECKED], false); + $attribute .= Support::doAttribute('data-load', ($formElement[FE_DYNAMIC_UPDATE] === 'yes') ? 'data-load' : ''); + $attribute .= Support::doAttribute(FE_INPUT_AUTOCOMPLETE, 'off'); + $attribute .= Support::doAttribute(ATTRIBUTE_DATA_REFERENCE, $formElement[FE_DATA_REFERENCE]); + + $classActive = ''; + if ($formElement[FE_CHECKBOX_CHECKED] === $value) { + $attribute .= Support::doAttribute('checked', 'checked'); + $valueJson = true; + $classActive = ' active'; + } + + $attribute .= HelperFormElement::getAttributeList($formElement, ['autofocus']); + $attribute .= HelperFormElement::getAttributeList($formElement, [F_FE_DATA_PATTERN_ERROR, F_FE_DATA_REQUIRED_ERROR, F_FE_DATA_MATCH_ERROR, F_FE_DATA_ERROR]); + + $htmlHidden = HelperFormElement::buildNativeHidden($htmlFormElementName, $formElement[FE_CHECKBOX_UNCHECKED]); + $this->store->setVar($htmlFormElementName, $htmlHidden, STORE_ADDITIONAL_FORM_ELEMENTS, false); + $html = ''; + + $htmlElement = '<input ' . $attribute . '>'; + if (isset($formElement['label2'])) { + $htmlElement .= $formElement['label2']; + } else { + $htmlElement .= $formElement['checked']; + } + + $labelAttribute = Support::doAttribute('title', $formElement[FE_TOOLTIP]); + $labelAttribute .= Support::doAttribute('class', 'btn ' . $formElement[FE_BUTTON_CLASS] . $classActive); + $html .= Support::wrapTag("<label $labelAttribute>", $htmlElement, true); + $html = Support::wrapTag('<div class="btn-group" data-toggle="buttons">', $html); + + $json = $this->getFormElementForJsonCheckbox($htmlFormElementName, $valueJson, $formElement); + + return $html; + } + + /** + * Create an array with standard elements for 'mode' (hidden, disabled, required, readonly) + * and add 'form-element', 'value'. + * 'Generic Element Update': add via API_ELEMENT_UPDATE 'label' and 'note'. + * All collected data as array - will be later converted to JSON. + * + * @param string $htmlFormElementName + * @param string|array $value + * @param array $formElement + * + * @param int $optionIdx + * @param string $class + * @return array + * @throws \CodeException + * @throws \UserFormException + */ + private function getFormElementForJsonCheckBox($htmlFormElementName, $value, array $formElement, $optionIdx = 0, $optionClass = '') { + $addClassRequired = array(); + + $json = HelperFormElement::getJsonFeMode($formElement[FE_MODE]); // disabled, required + + $json[API_FORM_UPDATE_FORM_ELEMENT] = $htmlFormElementName; + + if (isset($formElement[FE_FLAG_ROW_OPEN_TAG]) && isset($formElement[FE_FLAG_ROW_CLOSE_TAG])) { + $flagRowUpdate = ($formElement[FE_FLAG_ROW_OPEN_TAG] && $formElement[FE_FLAG_ROW_CLOSE_TAG]); + } else { + $flagRowUpdate = true; + } + + $statusHidden = ($formElement[FE_MODE] == 'hidden'); + $pattern = null; + if (isset($formElement[FE_CHECK_PATTERN]) && $formElement[FE_CHECK_PATTERN] != '') { + $pattern = $statusHidden ? false : $formElement[FE_CHECK_PATTERN]; + } + + // 'value' update via 'form-update' on the full row: only if there is no other FE in that row + if ($flagRowUpdate) { + $json[API_FORM_UPDATE_VALUE] = $value; + +//CR if ($pattern !== null) { +// $json['pattern'] = $pattern; +// } + } + + if ($formElement[FE_MODE] == FE_MODE_REQUIRED || $formElement[FE_MODE] == FE_MODE_SHOW_REQUIRED) { + $addClassRequired = HelperFormElement::getRequiredPositionClass($formElement[F_FE_REQUIRED_POSITION]); + } + + // Label + if (isset($formElement[FE_LABEL])) { + $key = $formElement[FE_HTML_ID] . HTML_ID_EXTENSION_LABEL; + $json[API_ELEMENT_UPDATE][$key][API_ELEMENT_CONTENT] = HelperFormElement::buildLabel($htmlFormElementName, $formElement[FE_LABEL], $addClassRequired[FE_LABEL] ?? ''); + } + + // Note + if (isset($formElement[FE_NOTE])) { + $key = $formElement[FE_HTML_ID] . HTML_ID_EXTENSION_NOTE; + if (!empty($addClassRequired[FE_NOTE])) { + $formElement[FE_NOTE] = Support::wrapTag('<span class="' . $addClassRequired[FE_NOTE] . '">', $formElement[FE_NOTE]); + } + $json[API_ELEMENT_UPDATE][$key][API_ELEMENT_CONTENT] = $formElement[FE_NOTE]; + } + + // Input + if (isset($formElement[FE_TYPE])) { + $key = $formElement[FE_HTML_ID] . HTML_ID_EXTENSION_INPUT; + + // For FE.type='note': update the column 'input' + if ($formElement[FE_TYPE] === FE_TYPE_NOTE) { + $json[API_ELEMENT_UPDATE][$key][API_ELEMENT_CONTENT] = $value; + } + + // Check show/hide: only FE with FE_MODE_SQL given, might change. + if (!empty($formElement[FE_MODE_SQL])) { + $class = is_numeric($formElement[FE_BS_INPUT_COLUMNS]) ? ('col-md-' . $formElement[FE_BS_INPUT_COLUMNS]) : $formElement[FE_BS_INPUT_COLUMNS]; +// $class = 'col-md-' . $formElement[FE_BS_INPUT_COLUMNS] . ' '; + + $json[API_ELEMENT_UPDATE][$key][API_ELEMENT_ATTRIBUTE]['required'] = ($formElement[FE_MODE] == 'required'); + $json[API_ELEMENT_UPDATE][$key][API_ELEMENT_ATTRIBUTE]['hidden'] = $statusHidden; + $json[API_ELEMENT_UPDATE][$key][API_ELEMENT_ATTRIBUTE]['readonly'] = $json['disabled'] ? 'readonly' : 'false'; + + // Checkbox: Copy attributes to every checkbox (appreciated by screen reader): + if ($formElement[FE_TYPE] == FE_TYPE_CHECKBOX) { + $optionsId = $formElement[FE_HTML_ID] . '-' . $optionIdx; + $json[API_ELEMENT_UPDATE][$optionsId][API_ELEMENT_ATTRIBUTE] = $json[API_ELEMENT_UPDATE][$key][API_ELEMENT_ATTRIBUTE]; + $json[API_ELEMENT_UPDATE][$optionsId][API_ELEMENT_ATTRIBUTE]['data-disabled'] = $json['disabled'] ? 'yes' : 'no'; + $json[API_ELEMENT_UPDATE][$optionsId][API_ELEMENT_ATTRIBUTE]['data-required'] = $json['required'] ? 'yes' : 'no'; + + // Update label class (i.e.: 'qfq-disabled') of Checkbox/Radio (i.e. readonly on/off). + if (isset($formElement[FE_TMP_CLASS_OPTION])) { + $optionsLabelId = HelperFormElement::getCheckboxRadioOptionId($formElement[FE_HTML_ID], $optionIdx, HTML_ID_EXTENSION_LABEL); + $json[API_ELEMENT_UPDATE][$optionsLabelId][API_ELEMENT_ATTRIBUTE]['class'] = $formElement[FE_TMP_CLASS_OPTION]; + } + } + + $class .= ($formElement[FE_MODE] == FE_MODE_HIDDEN) ? ' hidden' : ''; + $json[API_ELEMENT_UPDATE][$key][API_ELEMENT_ATTRIBUTE]['class'] = $class; + + if ($pattern !== null) { + $json[API_ELEMENT_UPDATE][$key][API_ELEMENT_ATTRIBUTE]['pattern'] = $pattern; + } + + } + + // #3647 +// if (!$flagRowUpdate) { + + // #4771 - temporary workaround: SELECT in 'multi FE row' won't updated after 'save' or with dynamic update. + //TODO #5016 - exception for FE_TYPE_CHECKBOX should be removed ASAP + if ($formElement[FE_TYPE] != FE_TYPE_SELECT && $formElement[FE_TYPE] != FE_TYPE_UPLOAD && $formElement[FE_TYPE] != FE_TYPE_CHECKBOX) { + $json[API_ELEMENT_UPDATE][$formElement[FE_HTML_ID]][API_ELEMENT_ATTRIBUTE]['value'] = $value; + $json[API_ELEMENT_UPDATE][$formElement[FE_HTML_ID]][API_ELEMENT_ATTRIBUTE]['required'] = ($formElement[FE_MODE] == 'required'); + $json[API_ELEMENT_UPDATE][$formElement[FE_HTML_ID]][API_ELEMENT_ATTRIBUTE]['hidden'] = $statusHidden; + + if ($pattern !== null) { + $json[API_ELEMENT_UPDATE][$formElement[FE_HTML_ID]][API_ELEMENT_ATTRIBUTE]['pattern'] = $pattern; + } + } + } + + // Show / Hide the complete FormElement Row. + if (isset($formElement[FE_HTML_ID])) { // HIDDEN_SIP comes without a real existing FE structure. + // Activate 'show' or 'hidden' on the current FormElement via JSON 'API_ELEMENT_UPDATE' + $class = "form-group clearfix"; + if ($formElement[FE_MODE] == FE_MODE_HIDDEN) { + $class .= ' hidden'; + } + + if (!empty($addClassRequired[FE_INPUT])) { + $class .= ' ' . $addClassRequired[FE_INPUT]; + } + + $key = $formElement[FE_HTML_ID] . HTML_ID_EXTENSION_ROW; + $json[API_ELEMENT_UPDATE][$key][API_ELEMENT_ATTRIBUTE]['class'] = $class; +// $json[API_ELEMENT_UPDATE][$key][API_ELEMENT_ATTRIBUTE]['buggy'] = $class; + } + + return $json; + } + + /** + * Build a single HTML plain checkbox based on two values. + * Create a 'hidden' input field and a 'checkbox' input field - both with the same HTML 'name'. + * HTML does not submit an unchecked checkbox. Then only the 'hidden' input field is submitted. + * + * Format: <input type="hidden" name="$htmlFormElementName" value="$valueUnChecked"> + * <input name="$htmlFormElementName" type="radio" [autofocus="autofocus"] + * [required="required"] [disabled="disabled"] value="<value>" [checked="checked"] > + * + * @param array $formElement + * @param string $htmlFormElementName + * @param string $attribute + * @param string $value + * @param array $json + * + * @return string + * @throws \CodeException + * @throws \UserFormException + */ + public function constructCheckboxSinglePlain(array $formElement, $htmlFormElementName, $attribute, $value, array &$json) { + $html = ''; + $valueJson = false; + + $attribute .= Support::doAttribute('id', $formElement[FE_HTML_ID]); + $attribute .= Support::doAttribute('name', $htmlFormElementName); + $attribute .= Support::doAttribute('value', $formElement[FE_CHECKBOX_CHECKED], false); + $attribute .= Support::doAttribute('data-load', ($formElement[FE_DYNAMIC_UPDATE] === 'yes') ? 'data-load' : ''); + $attribute .= Support::doAttribute(ATTRIBUTE_DATA_REFERENCE, $formElement[FE_DATA_REFERENCE]); + + if ($formElement[FE_CHECKBOX_CHECKED] === $value) { + $attribute .= Support::doAttribute('checked', 'checked'); + $valueJson = $value; + } + + $attribute .= HelperFormElement::getAttributeList($formElement, ['autofocus']); + $attribute .= HelperFormElement::getAttributeList($formElement, [F_FE_DATA_PATTERN_ERROR, F_FE_DATA_REQUIRED_ERROR, F_FE_DATA_MATCH_ERROR, F_FE_DATA_ERROR]); + + $htmlHidden = HelperFormElement::buildNativeHidden($htmlFormElementName, $formElement[FE_CHECKBOX_UNCHECKED]); + $this->store->setVar($htmlFormElementName, $htmlHidden, STORE_ADDITIONAL_FORM_ELEMENTS, false); + $html = ''; + + $html .= '<input ' . $attribute . '>'; + if (isset($formElement['label2'])) { + $html .= Support::wrapTag("<span style='font-weight: 400;'>", $formElement['label2']); + } + + $labelAttribute = Support::doAttribute('title', $formElement[FE_TOOLTIP]); + + $class = 'checkbox'; + if ($formElement[FE_MODE] == FE_MODE_READONLY) { + $class .= ' qfq-disabled'; // necessary for own style checkboxes to display them 'disabled' + } + + $html = Support::wrapTag("<label class='$class' $labelAttribute>", $html, true); +// $html = Support::wrapTag("<div class='checkbox'>", $html, true); + + $json = $this->getFormElementForJsonCheckBox($htmlFormElementName, $valueJson, $formElement); + + return $html; + } } \ No newline at end of file diff --git a/extension/Classes/Core/Helper/HelperFormElement.php b/extension/Classes/Core/Helper/HelperFormElement.php index 6a1a02449049bf00657c4763c7318abf380447bb..97e6790c47045d67cdfaece017d07a47aed0272d 100644 --- a/extension/Classes/Core/Helper/HelperFormElement.php +++ b/extension/Classes/Core/Helper/HelperFormElement.php @@ -20,7 +20,7 @@ class HelperFormElement { /** * @var Store */ - protected $store = null; + private static $store = null; /** * Expand column $keyName to row array as virtual columns. @@ -790,4 +790,74 @@ EOF; return $attribute; } + /** + * Builds a real HTML hidden form element. Useful for checkboxes, Multiple-Select and Radios. + * + * @param $htmlFormElementName + * @param string $value + * + * @return string + */ + public static function buildNativeHidden($htmlFormElementName, $value) { + return '<input type="hidden" name="' . $htmlFormElementName . '" value="' . htmlentities($value) . '">'; + } + + /** + * Set corresponding JSON attributes readonly/required/disabled, based on $formElement[FE_MODE]. + * + * @param string $feMode + * + * @return array + * @throws \UserFormException + */ + public static function getJsonFeMode($feMode) { + + self::getFeMode($feMode, $dummy, $disabled, $required); + + return [API_FORM_UPDATE_DISABLED => ($disabled === 'yes'), API_FORM_UPDATE_REQUIRED => ($required === 'yes')]; + } + + /** + * Builds a label, typically for an html-'<input>'-element. + * + * @param string $htmlFormElementName + * @param string $label + * @param string $addClass + * + * @return string + * @throws \CodeException + */ + public static function buildLabel($htmlFormElementName, $label, $addClass = '') { + $attributes = Support::doAttribute('for', $htmlFormElementName); + $attributes .= Support::doAttribute('class', ['control-label', $addClass]); + + $html = Support::wrapTag("<label $attributes>", $label); + + return $html; + } + + /** + * Construct HTML ID for checkbox/radio option elements. + * Optional add $type. + * Example: $base='173-21612-1-0', $index='0', $type='l' >> '173-21612-1-0-0-l' + * + * @param $base + * @param $index + * @param string $type - ';' for label + * @return string + */ + public static function getCheckboxRadioOptionId($base, $index, $type = '') { + return $base . '-' . $index . $type; + } + + /** + * Build HelpBlock + * + * @return string + */ + public static function getHelpBlock() { + return '<div class="help-block with-errors hidden"></div>'; + } + + } \ No newline at end of file