1<?php 2 3declare(strict_types=1); 4 5/* 6 * This file is part of the TYPO3 CMS project. 7 * 8 * It is free software; you can redistribute it and/or modify it under 9 * the terms of the GNU General Public License, either version 2 10 * of the License, or any later version. 11 * 12 * For the full copyright and license information, please read the 13 * LICENSE.txt file that was distributed with this source code. 14 * 15 * The TYPO3 project - inspiring people to share! 16 */ 17 18namespace TYPO3\CMS\Backend\Form\Element; 19 20use TYPO3\CMS\Backend\Form\NodeFactory; 21use TYPO3\CMS\Core\Imaging\IconRegistry; 22use TYPO3\CMS\Core\Utility\GeneralUtility; 23use TYPO3\CMS\Core\Utility\StringUtility; 24 25/** 26 * Generation of TCEform elements of the type "check" 27 */ 28class CheckboxToggleElement extends AbstractFormElement 29{ 30 /** 31 * @var IconRegistry 32 */ 33 private $iconRegistry; 34 35 /** 36 * Default field information enabled for this element. 37 * 38 * @var array 39 */ 40 protected $defaultFieldInformation = [ 41 'tcaDescription' => [ 42 'renderType' => 'tcaDescription', 43 ], 44 ]; 45 46 /** 47 * Default field wizards enabled for this element. 48 * 49 * @var array 50 */ 51 protected $defaultFieldWizard = [ 52 'localizationStateSelector' => [ 53 'renderType' => 'localizationStateSelector', 54 ], 55 'otherLanguageContent' => [ 56 'renderType' => 'otherLanguageContent', 57 'after' => [ 58 'localizationStateSelector' 59 ], 60 ], 61 'defaultLanguageDifferences' => [ 62 'renderType' => 'defaultLanguageDifferences', 63 'after' => [ 64 'otherLanguageContent', 65 ], 66 ], 67 ]; 68 69 /** 70 * @param NodeFactory $nodeFactory 71 * @param array $data 72 */ 73 public function __construct(NodeFactory $nodeFactory, array $data) 74 { 75 parent::__construct($nodeFactory, $data); 76 $this->iconRegistry = GeneralUtility::makeInstance(IconRegistry::class); 77 } 78 79 /** 80 * This will render a checkbox or an array of checkboxes 81 * 82 * @return array As defined in initializeResultArray() of AbstractNode 83 */ 84 public function render(): array 85 { 86 $resultArray = $this->initializeResultArray(); 87 88 $elementHtml = ''; 89 $disabled = false; 90 if ($this->data['parameterArray']['fieldConf']['config']['readOnly']) { 91 $disabled = true; 92 } 93 // Traversing the array of items 94 $items = $this->data['parameterArray']['fieldConf']['config']['items']; 95 96 $numberOfItems = count($items); 97 if ($numberOfItems === 0) { 98 $items[] = ['', '']; 99 $numberOfItems = 1; 100 } 101 $formElementValue = (int)$this->data['parameterArray']['itemFormElValue']; 102 $cols = (int)$this->data['parameterArray']['fieldConf']['config']['cols']; 103 if ($cols > 1) { 104 [$colClass, $colClear] = $this->calculateColumnMarkup($cols); 105 $elementHtml .= '<div class="checkbox-row row">'; 106 $counter = 0; 107 // $itemKey is important here, because items could have been removed via TSConfig 108 foreach ($items as $itemKey => $itemDefinition) { 109 $label = $itemDefinition[0]; 110 $elementHtml .= 111 '<div class="checkbox-column ' . $colClass . '">' 112 . $this->renderSingleCheckboxElement($label, $itemKey, $formElementValue, $numberOfItems, $this->data['parameterArray'], $disabled) . 113 '</div>'; 114 ++$counter; 115 if ($counter < $numberOfItems && !empty($colClear)) { 116 foreach ($colClear as $rowBreakAfter => $clearClass) { 117 if ($counter % $rowBreakAfter === 0) { 118 $elementHtml .= '<div class="clearfix ' . $clearClass . '"></div>'; 119 } 120 } 121 } 122 } 123 $elementHtml .= '</div>'; 124 } else { 125 $counter = 0; 126 foreach ($items as $itemKey => $itemDefinition) { 127 $label = $itemDefinition[0]; 128 $elementHtml .= $this->renderSingleCheckboxElement($label, $counter, $formElementValue, $numberOfItems, $this->data['parameterArray'], $disabled); 129 ++$counter; 130 } 131 } 132 if (!$disabled) { 133 $elementHtml .= '<input type="hidden" name="' . htmlspecialchars($this->data['parameterArray']['itemFormElName']) . '" value="' . htmlspecialchars((string)$formElementValue) . '" />'; 134 } 135 136 $fieldInformationResult = $this->renderFieldInformation(); 137 $fieldInformationHtml = $fieldInformationResult['html']; 138 $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false); 139 140 $fieldWizardResult = $this->renderFieldWizard(); 141 $fieldWizardHtml = $fieldWizardResult['html']; 142 $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldWizardResult, false); 143 144 $html = []; 145 $html[] = '<div class="formengine-field-item t3js-formengine-field-item">'; 146 $html[] = $fieldInformationHtml; 147 $html[] = '<div class="form-wizards-wrap">'; 148 $html[] = '<div class="form-wizards-element">'; 149 $html[] = $elementHtml; 150 $html[] = '</div>'; 151 if (!$disabled && !empty($fieldWizardHtml)) { 152 $html[] = '<div class="form-wizards-items-bottom">'; 153 $html[] = $fieldWizardHtml; 154 $html[] = '</div>'; 155 } 156 $html[] = '</div>'; 157 $html[] = '</div>'; 158 159 $resultArray['html'] = implode(LF, $html); 160 return $resultArray; 161 } 162 163 /** 164 * This functions builds the HTML output for the checkbox 165 * 166 * @param string $label Label of this item 167 * @param int $itemCounter Number of this element in the list of all elements 168 * @param int $formElementValue Value of this element 169 * @param int $numberOfItems Full number of items 170 * @param array $additionalInformation Information with additional configuration options. 171 * @param bool $disabled TRUE if form element is disabled 172 * @return string Single element HTML 173 */ 174 protected function renderSingleCheckboxElement($label, $itemCounter, $formElementValue, $numberOfItems, $additionalInformation, $disabled): string 175 { 176 $config = $additionalInformation['fieldConf']['config']; 177 $inline = !empty($config['cols']) && $config['cols'] === 'inline'; 178 $invert = isset($config['items'][0]['invertStateDisplay']) && $config['items'][0]['invertStateDisplay'] === true; 179 $checkboxParameters = $this->checkBoxParams( 180 $additionalInformation['itemFormElName'], 181 $formElementValue, 182 $itemCounter, 183 $numberOfItems, 184 implode('', $additionalInformation['fieldChangeFunc']) 185 ); 186 $uniqueId = StringUtility::getUniqueId('_'); 187 $checkboxId = $additionalInformation['itemFormElID'] . '_' . $itemCounter . $uniqueId; 188 return ' 189 <div class="checkbox checkbox-type-toggle' . ($invert ? ' checkbox-invert' : '') . ($inline ? ' checkbox-inline' : '') . (!$disabled ? '' : ' disabled') . '"> 190 <input type="checkbox" 191 class="checkbox-input" 192 value="1" 193 data-formengine-input-name="' . htmlspecialchars($additionalInformation['itemFormElName']) . '" 194 ' . $checkboxParameters . ' 195 ' . (!$disabled ? '' : ' disabled="disabled"') . ' 196 id="' . $checkboxId . '" /> 197 <label class="checkbox-label" for="' . $checkboxId . '"> 198 <span class="checkbox-label-text">' . $this->appendValueToLabelInDebugMode(($label ? htmlspecialchars($label) : ' '), $formElementValue) . '</span> 199 </label> 200 </div>'; 201 } 202} 203