/** * Rendering wizards for form fields. * * @param array $itemKinds Array with the real item in the first value * @param array $wizConf The "wizards" key from the config array for the field (from TCA) * @param string $table Table name * @param array $row The record array * @param string $field The field name * @param array $PA Additional configuration array. * @param string $itemName The field name * @param array $specConf Special configuration if available. * @param bool $RTE Whether the RTE could have been loaded. * * @return string The new item value. * @throws \InvalidArgumentException */ protected function renderWizards($itemKinds, $wizConf, $table, $row, $field, $PA, $itemName, $specConf, $RTE = false) { // Return not changed main item directly if wizards are disabled if (!is_array($wizConf) || $this->isWizardsDisabled()) { return $itemKinds[0]; } $languageService = $this->getLanguageService(); $fieldChangeFunc = $PA['fieldChangeFunc']; $item = $itemKinds[0]; $md5ID = 'ID' . GeneralUtility::shortMD5($itemName); $prefixOfFormElName = 'data[' . $table . '][' . $row['uid'] . '][' . $field . ']'; $flexFormPath = ''; if (GeneralUtility::isFirstPartOfStr($PA['itemFormElName'], $prefixOfFormElName)) { $flexFormPath = str_replace('][', '/', substr($PA['itemFormElName'], strlen($prefixOfFormElName) + 1, -1)); } // Add a suffix-value if the item is a selector box with renderType "selectSingleBox": if ($PA['fieldConf']['config']['type'] === 'select' && (int) $PA['fieldConf']['config']['maxitems'] > 1 && $PA['fieldConf']['config']['renderType'] === 'selectSingleBox') { $itemName .= '[]'; } // Contains wizard identifiers enabled for this record type, see "special configuration" docs $wizardsEnabledByType = $specConf['wizards']['parameters']; $buttonWizards = []; $otherWizards = []; foreach ($wizConf as $wizardIdentifier => $wizardConfiguration) { if (!isset($wizardConfiguration['module']['name']) && isset($wizardConfiguration['script'])) { throw new \InvalidArgumentException('The way registering a wizard in TCA has changed in 6.2 and was removed in CMS 7. ' . 'Please set module[name]=module_name instead of using script=path/to/script.php in your TCA. ', 1437750231); } // If an identifier starts with "_", this is a configuration option like _POSITION and not a wizard if ($wizardIdentifier[0] === '_') { continue; } // Sanitize wizard type $wizardConfiguration['type'] = (string) $wizardConfiguration['type']; // Wizards can be shown based on selected "type" of record. If this is the case, the wizard configuration // is set to enableByTypeConfig = 1, and the wizardIdentifier is found in $wizardsEnabledByType $wizardIsEnabled = true; if (isset($wizardConfiguration['enableByTypeConfig']) && (bool) $wizardConfiguration['enableByTypeConfig'] && (!is_array($wizardsEnabledByType) || !in_array($wizardIdentifier, $wizardsEnabledByType))) { $wizardIsEnabled = false; } // Disable if wizard is for RTE fields only and the handled field is no RTE field or RTE can not be loaded if (isset($wizardConfiguration['RTEonly']) && (bool) $wizardConfiguration['RTEonly'] && !$RTE) { $wizardIsEnabled = false; } // Disable if wizard is for not-new records only and we're handling a new record if (isset($wizardConfiguration['notNewRecords']) && $wizardConfiguration['notNewRecords'] && !MathUtility::canBeInterpretedAsInteger($row['uid'])) { $wizardIsEnabled = false; } // Wizard types script, colorbox and popup must contain a module name configuration if (!isset($wizardConfiguration['module']['name']) && in_array($wizardConfiguration['type'], ['script', 'colorbox', 'popup'], true)) { $wizardIsEnabled = false; } if (!$wizardIsEnabled) { continue; } // Title / icon: $iTitle = htmlspecialchars($languageService->sL($wizardConfiguration['title'])); if (isset($wizardConfiguration['icon'])) { $icon = FormEngineUtility::getIconHtml($wizardConfiguration['icon'], $iTitle, $iTitle); } else { $icon = $iTitle; } switch ($wizardConfiguration['type']) { case 'userFunc': $params = []; $params['params'] = $wizardConfiguration['params']; $params['exampleImg'] = $wizardConfiguration['exampleImg']; $params['table'] = $table; $params['uid'] = $row['uid']; $params['pid'] = $row['pid']; $params['field'] = $field; $params['flexFormPath'] = $flexFormPath; $params['md5ID'] = $md5ID; $params['returnUrl'] = $this->data['returnUrl']; $params['formName'] = 'editform'; $params['itemName'] = $itemName; $params['hmac'] = GeneralUtility::hmac($params['formName'] . $params['itemName'], 'wizard_js'); $params['fieldChangeFunc'] = $fieldChangeFunc; $params['fieldChangeFuncHash'] = GeneralUtility::hmac(serialize($fieldChangeFunc)); $params['item'] =& $item; $params['icon'] = $icon; $params['iTitle'] = $iTitle; $params['wConf'] = $wizardConfiguration; $params['row'] = $row; $otherWizards[] = GeneralUtility::callUserFunction($wizardConfiguration['userFunc'], $params, $this); break; case 'script': $params = []; $params['params'] = $wizardConfiguration['params']; $params['exampleImg'] = $wizardConfiguration['exampleImg']; $params['table'] = $table; $params['uid'] = $row['uid']; $params['pid'] = $row['pid']; $params['field'] = $field; $params['flexFormPath'] = $flexFormPath; $params['md5ID'] = $md5ID; $params['returnUrl'] = $this->data['returnUrl']; // Resolving script filename and setting URL. $urlParameters = []; if (isset($wizardConfiguration['module']['urlParameters']) && is_array($wizardConfiguration['module']['urlParameters'])) { $urlParameters = $wizardConfiguration['module']['urlParameters']; } $wScript = BackendUtility::getModuleUrl($wizardConfiguration['module']['name'], $urlParameters, ''); $url = $wScript . (strstr($wScript, '?') ? '' : '?') . GeneralUtility::implodeArrayForUrl('', ['P' => $params]); $buttonWizards[] = '<a class="btn btn-default" href="' . htmlspecialchars($url) . '" onclick="this.blur(); return !TBE_EDITOR.isFormChanged();">' . $icon . '</a>'; break; case 'popup': $params = []; $params['params'] = $wizardConfiguration['params']; $params['exampleImg'] = $wizardConfiguration['exampleImg']; $params['table'] = $table; $params['uid'] = $row['uid']; $params['pid'] = $row['pid']; $params['field'] = $field; $params['flexFormPath'] = $flexFormPath; $params['md5ID'] = $md5ID; $params['returnUrl'] = $this->data['returnUrl']; $params['formName'] = 'editform'; $params['itemName'] = $itemName; $params['hmac'] = GeneralUtility::hmac($params['formName'] . $params['itemName'], 'wizard_js'); $params['fieldChangeFunc'] = $fieldChangeFunc; $params['fieldChangeFuncHash'] = GeneralUtility::hmac(serialize($fieldChangeFunc)); // Resolving script filename and setting URL. $urlParameters = []; if (isset($wizardConfiguration['module']['urlParameters']) && is_array($wizardConfiguration['module']['urlParameters'])) { $urlParameters = $wizardConfiguration['module']['urlParameters']; } $wScript = BackendUtility::getModuleUrl($wizardConfiguration['module']['name'], $urlParameters, ''); $url = $wScript . (strstr($wScript, '?') ? '' : '?') . GeneralUtility::implodeArrayForUrl('', ['P' => $params]); $onlyIfSelectedJS = ''; if (isset($wizardConfiguration['popup_onlyOpenIfSelected']) && $wizardConfiguration['popup_onlyOpenIfSelected']) { $notSelectedText = $languageService->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:mess.noSelItemForEdit'); $onlyIfSelectedJS = 'if (!TBE_EDITOR.curSelected(' . GeneralUtility::quoteJSvalue($itemName) . ')){' . 'alert(' . GeneralUtility::quoteJSvalue($notSelectedText) . ');' . 'return false;' . '}'; } $aOnClick = 'this.blur();' . $onlyIfSelectedJS . 'vHWin=window.open(' . GeneralUtility::quoteJSvalue($url) . '+\'&P[currentValue]=\'+TBE_EDITOR.rawurlencode(' . 'document.editform[' . GeneralUtility::quoteJSvalue($itemName) . '].value,300' . ')' . '+\'&P[currentSelectedValues]=\'+TBE_EDITOR.curSelected(' . GeneralUtility::quoteJSvalue($itemName) . '),' . GeneralUtility::quoteJSvalue('popUp' . $md5ID) . ',' . GeneralUtility::quoteJSvalue($wizardConfiguration['JSopenParams']) . ');' . 'vHWin.focus();' . 'return false;'; $buttonWizards[] = '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars($aOnClick) . '">' . $icon . '</a>'; break; case 'slider': $params = []; $params['fieldConfig'] = $PA['fieldConf']['config']; $params['field'] = $field; $params['table'] = $table; $params['flexFormPath'] = $flexFormPath; $params['md5ID'] = $md5ID; $params['itemName'] = $itemName; $params['wConf'] = $wizardConfiguration; $params['row'] = $row; /** @var ValueSliderWizard $wizard */ $wizard = GeneralUtility::makeInstance(ValueSliderWizard::class); $otherWizards[] = $wizard->renderWizard($params); break; case 'select': // The select wizard is a select drop down added to the main element. It provides all the functionality // that select items can do for us, so we process this element via data processing. // @todo: This should be embedded in an own provider called in the main data group to not handle this on the fly here // Select wizard page TS can be set in TCEFORM."table"."field".wizards."wizardName" $pageTsConfig = []; if (isset($this->data['pageTsConfig']['TCEFORM.'][$table . '.'][$field . '.']['wizards.'][$wizardIdentifier . '.']) && is_array($this->data['pageTsConfig']['TCEFORM.'][$table . '.'][$field . '.']['wizards.'][$wizardIdentifier . '.'])) { $pageTsConfig['TCEFORM.']['dummySelectWizard.'][$wizardIdentifier . '.'] = $this->data['pageTsConfig']['TCEFORM.'][$table . '.'][$field . '.']['wizards.'][$wizardIdentifier . '.']; } $selectWizardDataInput = ['tableName' => 'dummySelectWizard', 'command' => 'edit', 'pageTsConfig' => $pageTsConfig, 'processedTca' => ['ctrl' => [], 'columns' => [$wizardIdentifier => ['type' => 'select', 'renderType' => 'selectSingle', 'config' => $wizardConfiguration]]]]; /** @var OnTheFly $formDataGroup */ $formDataGroup = GeneralUtility::makeInstance(OnTheFly::class); $formDataGroup->setProviderList([TcaSelectItems::class]); /** @var FormDataCompiler $formDataCompiler */ $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup); $compilerResult = $formDataCompiler->compile($selectWizardDataInput); $selectWizardItems = $compilerResult['processedTca']['columns'][$wizardIdentifier]['config']['items']; $options = []; $options[] = '<option>' . $iTitle . '</option>'; foreach ($selectWizardItems as $selectWizardItem) { $options[] = '<option value="' . htmlspecialchars($selectWizardItem[1]) . '">' . htmlspecialchars($selectWizardItem[0]) . '</option>'; } if ($wizardConfiguration['mode'] == 'append') { $assignValue = 'document.querySelectorAll(' . GeneralUtility::quoteJSvalue('[data-formengine-input-name="' . $itemName . '"]') . ')[0].value=\'\'+this.options[this.selectedIndex].value+document.editform[' . GeneralUtility::quoteJSvalue($itemName) . '].value'; } elseif ($wizardConfiguration['mode'] == 'prepend') { $assignValue = 'document.querySelectorAll(' . GeneralUtility::quoteJSvalue('[data-formengine-input-name="' . $itemName . '"]') . ')[0].value+=\'\'+this.options[this.selectedIndex].value'; } else { $assignValue = 'document.querySelectorAll(' . GeneralUtility::quoteJSvalue('[data-formengine-input-name="' . $itemName . '"]') . ')[0].value=this.options[this.selectedIndex].value'; } $otherWizards[] = '<select' . ' id="' . StringUtility::getUniqueId('tceforms-select-') . '"' . ' class="form-control tceforms-select tceforms-wizardselect"' . ' onchange="' . htmlspecialchars($assignValue . ';this.blur();this.selectedIndex=0;' . implode('', $fieldChangeFunc)) . '"' . '>' . implode('', $options) . '</select>'; break; case 'suggest': if (!empty($PA['fieldTSConfig']['suggest.']['default.']['hide'])) { break; } // The suggest wizard needs to know if we're in flex form scope to use the dataStructureIdentifier. // If so, add the processedTca of the flex config as wizard argument. $flexFormConfig = []; if ($this->data['processedTca']['columns'][$field]['config']['type'] === 'flex') { $flexFormConfig = $this->data['processedTca']['columns'][$field]; } /** @var SuggestWizard $suggestWizard */ $suggestWizard = GeneralUtility::makeInstance(SuggestWizard::class); $otherWizards[] = $suggestWizard->renderSuggestSelector($PA['itemFormElName'], $table, $field, $row, $PA, $flexFormConfig); break; } } // For each rendered wizard, put them together around the item. if (!empty($buttonWizards) || !empty($otherWizards)) { $innerContent = ''; if (!empty($buttonWizards)) { $innerContent .= '<div class="btn-group' . ($wizConf['_VERTICAL'] ? ' btn-group-vertical' : '') . '">' . implode('', $buttonWizards) . '</div>'; } $innerContent .= implode(' ', $otherWizards); // Position $classes = ['form-wizards-wrap']; if ($wizConf['_POSITION'] === 'left') { $classes[] = 'form-wizards-aside'; $innerContent = '<div class="form-wizards-items">' . $innerContent . '</div><div class="form-wizards-element">' . $item . '</div>'; } elseif ($wizConf['_POSITION'] === 'top') { $classes[] = 'form-wizards-top'; $innerContent = '<div class="form-wizards-items">' . $innerContent . '</div><div class="form-wizards-element">' . $item . '</div>'; } elseif ($wizConf['_POSITION'] === 'bottom') { $classes[] = 'form-wizards-bottom'; $innerContent = '<div class="form-wizards-element">' . $item . '</div><div class="form-wizards-items">' . $innerContent . '</div>'; } else { $classes[] = 'form-wizards-aside'; $innerContent = '<div class="form-wizards-element">' . $item . '</div><div class="form-wizards-items">' . $innerContent . '</div>'; } $item = ' <div class="' . implode(' ', $classes) . '"> ' . $innerContent . ' </div>'; } return $item; }
/** * Get type selector * * @return string */ protected function getTypeSelectHtml() { $content = ''; // find all available doktypes for the current user $types = $GLOBALS['PAGES_TYPES']; unset($types['default']); $types = array_keys($types); $types[] = PageRepository::DOKTYPE_DEFAULT; if (!$this->getBackendUser()->isAdmin() && isset($this->getBackendUser()->groupData['pagetypes_select'])) { $types = GeneralUtility::trimExplode(',', $this->getBackendUser()->groupData['pagetypes_select'], true); } $removeItems = isset($this->pagesTsConfig['doktype.']['removeItems']) ? GeneralUtility::trimExplode(',', $this->pagesTsConfig['doktype.']['removeItems'], true) : array(); $allowedDoktypes = array_diff($types, $removeItems); // fetch all doktypes in the TCA $availableDoktypes = $GLOBALS['TCA']['pages']['columns']['doktype']['config']['items']; // sort by group and allowedDoktypes $groupedData = array(); foreach ($availableDoktypes as $doktypeData) { // if it is a group, save the group label for the children underneath if ($doktypeData[1] == '--div--') { $groupLabel = $doktypeData[0]; } else { if (in_array($doktypeData[1], $allowedDoktypes)) { $groupedData[$groupLabel][] = $doktypeData; } } } // render the HTML foreach ($groupedData as $groupLabel => $items) { $groupContent = ''; foreach ($items as $item) { $label = $this->getLanguageService()->sL($item[0], true); $value = $item[1]; $icon = !empty($item[2]) ? FormEngineUtility::getIconHtml($item[2], $label, $label) : ''; $groupContent .= '<option value="' . htmlspecialchars($value) . '" data-icon="' . htmlspecialchars($icon) . '">' . $label . '</option>'; } $groupLabel = $this->getLanguageService()->sL($groupLabel, true); $content .= '<optgroup label="' . $groupLabel . '">' . $groupContent . '</optgroup>'; } return $content; }
/** * Creates a checkbox list (renderMode = "checkbox") * * @param string $table See getSingleField_typeSelect() * @param string $field See getSingleField_typeSelect() * @param array $row See getSingleField_typeSelect() * @param array $parameterArray See getSingleField_typeSelect() * @param array $config (Redundant) content of $PA['fieldConf']['config'] (for convenience) * @param array $selItems Items available for selection * @param string $noMatchingLabel Label for no-matching-value * @return string The HTML code for the item */ protected function getSingleField_typeSelect_checkbox($table, $field, $row, $parameterArray, $config, $selItems, $noMatchingLabel) { if (empty($selItems)) { return ''; } // Get values in an array (and make unique, which is fine because there can be no duplicates anyway): $itemArray = array_flip(FormEngineUtility::extractValuesOnlyFromValueLabelList($parameterArray['itemFormElValue'])); $output = ''; // Disabled $disabled = 0; if ($this->isGlobalReadonly() || $config['readOnly']) { $disabled = 1; } // Traverse the Array of selector box items: $groups = array(); $currentGroup = 0; $c = 0; $sOnChange = ''; if (!$disabled) { $sOnChange = implode('', $parameterArray['fieldChangeFunc']); // Used to accumulate the JS needed to restore the original selection. foreach ($selItems as $p) { // Non-selectable element: if ($p[1] === '--div--') { $selIcon = ''; if (isset($p[2]) && $p[2] != 'empty-empty') { $selIcon = FormEngineUtility::getIconHtml($p[2]); } $currentGroup++; $groups[$currentGroup]['header'] = array('icon' => $selIcon, 'title' => htmlspecialchars($p[0])); } else { // Check if some help text is available // Since TYPO3 4.5 help text is expected to be an associative array // with two key, "title" and "description" // For the sake of backwards compatibility, we test if the help text // is a string and use it as a description (this could happen if items // are modified with an itemProcFunc) $hasHelp = FALSE; $help = ''; $helpArray = array(); if (!empty($p[3])) { $hasHelp = TRUE; if (is_array($p[3])) { $helpArray = $p[3]; } else { $helpArray['description'] = $p[3]; } } if ($hasHelp) { $help = BackendUtility::wrapInHelp('', '', '', $helpArray); } // Selected or not by default: $checked = 0; if (isset($itemArray[$p[1]])) { $checked = 1; unset($itemArray[$p[1]]); } // Build item array $groups[$currentGroup]['items'][] = array('id' => str_replace('.', '', uniqid('select_checkbox_row_', TRUE)), 'name' => $parameterArray['itemFormElName'] . '[' . $c . ']', 'value' => $p[1], 'checked' => $checked, 'disabled' => $disabled, 'class' => '', 'icon' => !empty($p[2]) ? FormEngineUtility::getIconHtml($p[2]) : IconUtility::getSpriteIcon('empty-empty'), 'title' => htmlspecialchars($p[0], ENT_COMPAT, 'UTF-8', FALSE), 'help' => $help); $c++; } } } // Remaining values (invalid): if (!empty($itemArray) && !$parameterArray['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) { $currentGroup++; foreach ($itemArray as $theNoMatchValue => $temp) { // Build item array $groups[$currentGroup]['items'][] = array('id' => str_replace('.', '', uniqid('select_checkbox_row_', TRUE)), 'name' => $parameterArray['itemFormElName'] . '[' . $c . ']', 'value' => $theNoMatchValue, 'checked' => 1, 'disabled' => $disabled, 'class' => 'danger', 'icon' => '', 'title' => htmlspecialchars(@sprintf($noMatchingLabel, $theNoMatchValue), ENT_COMPAT, 'UTF-8', FALSE), 'help' => ''); $c++; } } // Add an empty hidden field which will send a blank value if all items are unselected. $output .= '<input type="hidden" class="select-checkbox" name="' . htmlspecialchars($parameterArray['itemFormElName']) . '" value="" />'; // Building the checkboxes foreach ($groups as $groupKey => $group) { $groupId = htmlspecialchars($parameterArray['itemFormElID']) . '-group-' . $groupKey; $output .= '<div class="panel panel-default">'; if (is_array($group['header'])) { $output .= ' <div class="panel-heading"> <a data-toggle="collapse" href="#' . $groupId . '" aria-expanded="true" aria-controls="' . $groupId . '"> ' . $group['header']['icon'] . ' ' . $group['header']['title'] . ' </a> </div> '; } if (is_array($group['items']) && !empty($group['items'])) { $tableRows = ''; $checkGroup = array(); $uncheckGroup = array(); $resetGroup = array(); // Render rows foreach ($group['items'] as $item) { $tableRows .= ' <tr class="' . $item['class'] . '"> <td class="col-checkbox"> <input type="checkbox" id="' . $item['id'] . '" name="' . htmlspecialchars($item['name']) . '" value="' . htmlspecialchars($item['value']) . '" onclick="' . htmlspecialchars($sOnChange) . '" ' . ($item['checked'] ? ' checked=checked' : '') . ' ' . ($item['disabled'] ? ' disabled=disabled' : '') . ' ' . $parameterArray['onFocus'] . ' /> </td> <td class="col-icon"> <label class="label-block" for="' . $item['id'] . '">' . $item['icon'] . '</label> </td> <td class="col-title"> <label class="label-block" for="' . $item['id'] . '">' . $item['title'] . '</label> </td> <td>' . $item['help'] . '</td> </tr> '; $checkGroup[] = 'document.editform[' . GeneralUtility::quoteJSvalue($item['name']) . '].checked=1;'; $uncheckGroup[] = 'document.editform[' . GeneralUtility::quoteJSvalue($item['name']) . '].checked=0;'; $resetGroup[] = 'document.editform[' . GeneralUtility::quoteJSvalue($item['name']) . '].checked=' . $item['checked'] . ';'; } // Build toggle group checkbox $toggleGroupCheckbox = ''; if (!empty($resetGroup)) { $toggleGroupCheckbox = ' <input type="checkbox" class="checkbox" onclick="if (checked) {' . htmlspecialchars(implode('', $checkGroup) . '} else {' . implode('', $uncheckGroup)) . '}"> '; } // Build reset group button $resetGroupBtn = ''; if (!empty($resetGroup)) { $resetGroupBtn = ' <a href="#" class="btn btn-default" onclick="' . implode('', $resetGroup) . ' return false;' . '"> ' . IconUtility::getSpriteIcon('actions-edit-undo', array('title' => htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.revertSelection')))) . ' ' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.revertSelection') . ' </a> '; } $output .= ' <div id="' . $groupId . '" class="panel-collapse collapse in" role="tabpanel"> <div class="table-fit"> <table class="table table-transparent table-hover"> <thead> <tr> <th class="col-checkbox">' . $toggleGroupCheckbox . '</th> <th class="col-icon"></th> <th class="text-right" colspan="2">' . $resetGroupBtn . '</th> </tr> </thead> <tbody>' . $tableRows . '</tbody> </table> </div> </div> '; } $output .= '</div>'; } return $output; }
/** * Render single element * * @return array As defined in initializeResultArray() of AbstractNode */ public function render() { $table = $this->data['tableName']; $field = $this->data['fieldName']; $row = $this->data['databaseRow']; $parameterArray = $this->data['parameterArray']; $config = $parameterArray['fieldConf']['config']; $selectItems = $parameterArray['fieldConf']['config']['items']; // Check against inline uniqueness /** @var InlineStackProcessor $inlineStackProcessor */ $inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class); $inlineStackProcessor->initializeByGivenStructure($this->data['inlineStructure']); $uniqueIds = null; if ($this->data['isInlineChild'] && $this->data['inlineParentUid']) { $inlineObjectName = $inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($this->data['inlineFirstPid']); $inlineFormName = $inlineStackProcessor->getCurrentStructureFormPrefix(); if ($this->data['inlineParentConfig']['foreign_table'] === $table && $this->data['inlineParentConfig']['foreign_unique'] === $field) { $uniqueIds = $this->data['inlineData']['unique'][$inlineObjectName . '-' . $table]['used']; $parameterArray['fieldChangeFunc']['inlineUnique'] = 'inline.updateUnique(this,' . GeneralUtility::quoteJSvalue($inlineObjectName . '-' . $table) . ',' . GeneralUtility::quoteJSvalue($inlineFormName) . ',' . GeneralUtility::quoteJSvalue($row['uid']) . ');'; } // hide uid of parent record for symmetric relations if ($this->data['inlineParentConfig']['foreign_table'] === $table && ($this->data['inlineParentConfig']['foreign_field'] === $field || $this->data['inlineParentConfig']['symmetric_field'] === $field)) { $uniqueIds[] = $this->data['inlineParentUid']; } } // Initialization: $selectId = StringUtility::getUniqueId('tceforms-select-'); $selectedIcon = ''; $size = (int) $config['size']; // Style set on <select/> $options = ''; $disabled = false; if (!empty($config['readOnly'])) { $disabled = true; } // Prepare groups $selectItemCounter = 0; $selectItemGroupCount = 0; $selectItemGroups = array(); $selectIcons = array(); $selectedValue = ''; $hasIcons = false; if (!empty($parameterArray['itemFormElValue'])) { $selectedValue = (string) $parameterArray['itemFormElValue'][0]; } foreach ($selectItems as $item) { if ($item[1] === '--div--') { // IS OPTGROUP if ($selectItemCounter !== 0) { $selectItemGroupCount++; } $selectItemGroups[$selectItemGroupCount]['header'] = array('title' => $item[0]); } else { // IS ITEM $title = htmlspecialchars($item['0'], ENT_COMPAT, 'UTF-8', false); $icon = !empty($item[2]) ? FormEngineUtility::getIconHtml($item[2], $title, $title) : ''; $selected = $selectedValue === (string) $item[1]; if ($selected) { $selectedIcon = $icon; } $selectItemGroups[$selectItemGroupCount]['items'][] = array('title' => $title, 'value' => $item[1], 'icon' => $icon, 'selected' => $selected, 'index' => $selectItemCounter); // ICON if ($icon) { $selectIcons[] = array('title' => $title, 'icon' => $icon, 'index' => $selectItemCounter); } $selectItemCounter++; } } // Fallback icon // @todo: assign a special icon for non matching values? if (!$selectedIcon && $selectItemGroups[0]['items'][0]['icon']) { $selectedIcon = $selectItemGroups[0]['items'][0]['icon']; } // Process groups foreach ($selectItemGroups as $selectItemGroup) { // suppress groups without items if (empty($selectItemGroup['items'])) { continue; } $optionGroup = is_array($selectItemGroup['header']); $options .= $optionGroup ? '<optgroup label="' . htmlspecialchars($selectItemGroup['header']['title'], ENT_COMPAT, 'UTF-8', false) . '">' : ''; if (is_array($selectItemGroup['items'])) { foreach ($selectItemGroup['items'] as $item) { $options .= '<option value="' . htmlspecialchars($item['value']) . '" data-icon="' . htmlspecialchars($item['icon']) . '"' . ($item['selected'] ? ' selected="selected"' : '') . '>' . $item['title'] . '</option>'; } $hasIcons = !empty($item['icon']); } $options .= $optionGroup ? '</optgroup>' : ''; } // Build the element $html = ['<div class="form-control-wrap">']; if ($hasIcons) { $html[] = '<div class="input-group">'; $html[] = '<span class="input-group-addon input-group-icon">'; $html[] = $selectedIcon; $html[] = '</span>'; } $html[] = '<select' . ' id="' . $selectId . '"' . ' name="' . htmlspecialchars($parameterArray['itemFormElName']) . '"' . $this->getValidationDataAsDataAttribute($config) . ' class="form-control form-control-adapt"' . ($size ? ' size="' . $size . '"' : '') . ($disabled ? ' disabled="disabled"' : '') . '>'; $html[] = $options; $html[] = '</select>'; if ($hasIcons) { $html[] = '</div>'; } $html[] = '</div>'; // Create icon table: if (!empty($selectIcons) && !empty($config['showIconTable'])) { $selectIconColumns = (int) $config['selicon_cols']; if (!$selectIconColumns) { $selectIconColumns = count($selectIcons); } $selectIconColumns = $selectIconColumns > 12 ? 12 : $selectIconColumns; $selectIconRows = ceil(count($selectIcons) / $selectIconColumns); $selectIcons = array_pad($selectIcons, $selectIconRows * $selectIconColumns, ''); $html[] = '<div class="t3js-forms-select-single-icons table-icons table-fit table-fit-inline-block">'; $html[] = '<table class="table table-condensed table-white table-center">'; $html[] = '<tbody>'; $html[] = '<tr>'; foreach ($selectIcons as $i => $selectIcon) { if ($i % $selectIconColumns === 0 && $i !== 0) { $html[] = '</tr>'; $html[] = '<tr>'; } $html[] = '<td>'; if (is_array($selectIcon)) { $html[] = '<a href="#" title="' . $selectIcon['title'] . '" data-select-index="' . $selectIcon['index'] . '">'; $html[] = $selectIcon['icon']; $html[] = '</a>'; } $html[] = '</td>'; } $html[] = '</tr>'; $html[] = '</tbody>'; $html[] = '</table>'; $html[] = '</div>'; } $html = implode(LF, $html); // Wizards: if (!$disabled) { $html = $this->renderWizards(array($html), $config['wizards'], $table, $row, $field, $parameterArray, $parameterArray['itemFormElName'], BackendUtility::getSpecConfParts($parameterArray['fieldConf']['defaultExtras'])); } $resultArray = $this->initializeResultArray(); $resultArray['html'] = $html; $resultArray['requireJsModules'][] = ['TYPO3/CMS/Backend/FormEngine/Element/SelectSingleElement' => implode(LF, ['function(SelectSingleElement) {', 'SelectSingleElement.initialize(', GeneralUtility::quoteJSvalue('#' . $selectId) . ',', '{', 'onChange: function() {', implode('', $parameterArray['fieldChangeFunc']), '}', '}', ');', '}'])]; return $resultArray; }
/** * Render check boxes * * @return array As defined in initializeResultArray() of AbstractNode */ public function render() { $html = []; // Field configuration from TCA: $parameterArray = $this->data['parameterArray']; $config = $parameterArray['fieldConf']['config']; $disabled = !empty($config['readOnly']); $selItems = $config['items']; if (!empty($selItems)) { // Get values in an array (and make unique, which is fine because there can be no duplicates anyway): $itemArray = array_flip($parameterArray['itemFormElValue']); // Traverse the Array of selector box items: $groups = array(); $currentGroup = 0; $c = 0; $sOnChange = ''; if (!$disabled) { $sOnChange = implode('', $parameterArray['fieldChangeFunc']); // Used to accumulate the JS needed to restore the original selection. foreach ($selItems as $p) { // Non-selectable element: if ($p[1] === '--div--') { $selIcon = ''; if (isset($p[2]) && $p[2] != 'empty-empty') { $selIcon = FormEngineUtility::getIconHtml($p[2]); } $currentGroup++; $groups[$currentGroup]['header'] = array('icon' => $selIcon, 'title' => htmlspecialchars($p[0])); } else { // Check if some help text is available // Since TYPO3 4.5 help text is expected to be an associative array // with two key, "title" and "description" // For the sake of backwards compatibility, we test if the help text // is a string and use it as a description (this could happen if items // are modified with an itemProcFunc) $hasHelp = false; $help = ''; $helpArray = array(); if (!empty($p[3])) { $hasHelp = true; if (is_array($p[3])) { $helpArray = $p[3]; } else { $helpArray['description'] = $p[3]; } } if ($hasHelp) { $help = BackendUtility::wrapInHelp('', '', '', $helpArray); } // Selected or not by default: $checked = 0; if (isset($itemArray[$p[1]])) { $checked = 1; unset($itemArray[$p[1]]); } // Build item array $groups[$currentGroup]['items'][] = array('id' => StringUtility::getUniqueId('select_checkbox_row_'), 'name' => $parameterArray['itemFormElName'] . '[' . $c . ']', 'value' => $p[1], 'checked' => $checked, 'disabled' => false, 'class' => '', 'icon' => !empty($p[2]) ? FormEngineUtility::getIconHtml($p[2]) : $this->iconFactory->getIcon('empty-empty', Icon::SIZE_SMALL)->render(), 'title' => htmlspecialchars($p[0], ENT_COMPAT, 'UTF-8', false), 'help' => $help); $c++; } } } // Add an empty hidden field which will send a blank value if all items are unselected. $html[] = '<input type="hidden" class="select-checkbox" name="' . htmlspecialchars($parameterArray['itemFormElName']) . '" value="">'; // Building the checkboxes foreach ($groups as $groupKey => $group) { $groupId = htmlspecialchars($parameterArray['itemFormElID']) . '-group-' . $groupKey; $html[] = '<div class="panel panel-default">'; if (is_array($group['header'])) { $html[] = '<div class="panel-heading">'; $html[] = '<a data-toggle="collapse" href="#' . $groupId . '" aria-expanded="false" aria-controls="' . $groupId . '">'; $html[] = $group['header']['icon']; $html[] = $group['header']['title']; $html[] = '</a>'; $html[] = '</div>'; } if (is_array($group['items']) && !empty($group['items'])) { $tableRows = []; $checkGroup = array(); $uncheckGroup = array(); $resetGroup = array(); // Render rows foreach ($group['items'] as $item) { $tableRows[] = '<tr class="' . $item['class'] . '">'; $tableRows[] = '<td class="col-checkbox">'; $tableRows[] = '<input type="checkbox" ' . 'id="' . $item['id'] . '" ' . 'name="' . htmlspecialchars($item['name']) . '" ' . 'value="' . htmlspecialchars($item['value']) . '" ' . 'onclick="' . htmlspecialchars($sOnChange) . '" ' . ($item['checked'] ? 'checked=checked ' : '') . ($item['disabled'] ? 'disabled=disabled ' : '') . $parameterArray['onFocus'] . '>'; $tableRows[] = '</td>'; $tableRows[] = '<td class="col-icon">'; $tableRows[] = '<label class="label-block" for="' . $item['id'] . '">' . $item['icon'] . '</label>'; $tableRows[] = '</td>'; $tableRows[] = '<td class="col-title">'; $tableRows[] = '<label class="label-block" for="' . $item['id'] . '">' . $item['title'] . '</label>'; $tableRows[] = '</td>'; $tableRows[] = '<td>' . $item['help'] . '</td>'; $tableRows[] = '</tr>'; $checkGroup[] = 'document.editform[' . GeneralUtility::quoteJSvalue($item['name']) . '].checked=1;'; $uncheckGroup[] = 'document.editform[' . GeneralUtility::quoteJSvalue($item['name']) . '].checked=0;'; $resetGroup[] = 'document.editform[' . GeneralUtility::quoteJSvalue($item['name']) . '].checked=' . $item['checked'] . ';'; } // Build toggle group checkbox $toggleGroupCheckbox = ''; if (!empty($resetGroup)) { $toggleGroupCheckbox = '<input type="checkbox" ' . 'class="checkbox" ' . 'onclick="if (checked) {' . htmlspecialchars(implode('', $checkGroup) . '} else {' . implode('', $uncheckGroup)) . '}">'; } // Build reset group button $resetGroupBtn = ''; if (!empty($resetGroup)) { $title = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.revertSelection', true); $resetGroupBtn = '<a href="#" ' . 'class="btn btn-default" ' . 'onclick="' . implode('', $resetGroup) . ' return false;" ' . 'title="' . $title . '">' . $this->iconFactory->getIcon('actions-edit-undo', Icon::SIZE_SMALL)->render() . ' ' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.revertSelection') . '</a>'; } if (is_array($group['header'])) { $html[] = '<div id="' . $groupId . '" class="panel-collapse collapse" role="tabpanel">'; } $html[] = '<div class="table-fit">'; $html[] = '<table class="table table-transparent table-hover">'; $html[] = '<thead>'; $html[] = '<tr>'; $html[] = '<th class="col-checkbox">' . $toggleGroupCheckbox . '</th>'; $html[] = '<th class="col-icon"></th>'; $html[] = '<th class="text-right" colspan="2">' . $resetGroupBtn . '</th>'; $html[] = '</tr>'; $html[] = '</thead>'; $html[] = '<tbody>' . implode(LF, $tableRows) . '</tbody>'; $html[] = '</table>'; $html[] = '</div>'; if (is_array($group['header'])) { $html[] = '</div>'; } } $html[] = '</div>'; } } if (!$disabled) { $html = $this->renderWizards(array(implode(LF, $html)), $config['wizards'], $this->data['tableName'], $this->data['databaseRow'], $this->data['fieldName'], $parameterArray, $parameterArray['itemFormElName'], BackendUtility::getSpecConfParts($parameterArray['fieldConf']['defaultExtras'])); } $resultArray = $this->initializeResultArray(); $resultArray['html'] = $html; return $resultArray; }
/** * Rendering wizards for form fields. * * @param array $itemKinds Array with the real item in the first value, and an alternative item in the second value. * @param array $wizConf The "wizard" key from the config array for the field (from TCA) * @param string $table Table name * @param array $row The record array * @param string $field The field name * @param array $PA Additional configuration array. * @param string $itemName The field name * @param array $specConf Special configuration if available. * @param bool $RTE Whether the RTE could have been loaded. * @return string The new item value. */ protected function renderWizards($itemKinds, $wizConf, $table, $row, $field, $PA, $itemName, $specConf, $RTE = FALSE) { // Return not changed main item directly if wizards are disabled if (!is_array($wizConf) || $this->isWizardsDisabled()) { return $itemKinds[0]; } $languageService = $this->getLanguageService(); $fieldChangeFunc = $PA['fieldChangeFunc']; $item = $itemKinds[0]; $fName = '[' . $table . '][' . $row['uid'] . '][' . $field . ']'; $md5ID = 'ID' . GeneralUtility::shortmd5($itemName); $fieldConfig = $PA['fieldConf']['config']; $prefixOfFormElName = 'data[' . $table . '][' . $row['uid'] . '][' . $field . ']'; $flexFormPath = ''; if (GeneralUtility::isFirstPartOfStr($PA['itemFormElName'], $prefixOfFormElName)) { $flexFormPath = str_replace('][', '/', substr($PA['itemFormElName'], strlen($prefixOfFormElName) + 1, -1)); } // Manipulate the field name (to be the TRUE form field name) and remove // a suffix-value if the item is a selector box with renderMode "singlebox": $listFlag = '_list'; if ($PA['fieldConf']['config']['type'] == 'select') { // Single select situation: if ($PA['fieldConf']['config']['maxitems'] <= 1) { $listFlag = ''; } elseif ($PA['fieldConf']['config']['renderMode'] == 'singlebox') { $itemName .= '[]'; $listFlag = ''; } } // Contains wizard identifiers enabled for this record type, see "special configuration" docs $wizardsEnabledByType = $specConf['wizards']['parameters']; $buttonWizards = array(); $otherWizards = array(); foreach ($wizConf as $wizardIdentifier => $wizardConfiguration) { // If an identifier starts with "_", this is a configuration option like _POSITION and not a wizard if ($wizardIdentifier[0] === '_') { continue; } // Sanitize wizard type $wizardConfiguration['type'] = (string) $wizardConfiguration['type']; // Wizards can be shown based on selected "type" of record. If this is the case, the wizard configuration // is set to enableByTypeConfig = 1, and the wizardIdentifier is found in $wizardsEnabledByType $wizardIsEnabled = TRUE; if (isset($wizardConfiguration['enableByTypeConfig']) && (bool) $wizardConfiguration['enableByTypeConfig'] && (!is_array($wizardsEnabledByType) || !in_array($wizardIdentifier, $wizardsEnabledByType))) { $wizardIsEnabled = FALSE; } // Disable if wizard is for RTE fields only and the handled field is no RTE field or RTE can not be loaded if (isset($wizardConfiguration['RTEonly']) && (bool) $wizardConfiguration['RTEonly'] && !$RTE) { $wizardIsEnabled = FALSE; } // Disable if wizard is for not-new records only and we're handling a new record if (isset($wizardConfiguration['notNewRecords']) && $wizardConfiguration['notNewRecords'] && !MathUtility::canBeInterpretedAsInteger($row['uid'])) { $wizardIsEnabled = FALSE; } // Wizard types script, colorbox and popup must contain a module name configuration if (!isset($wizardConfiguration['module']['name']) && in_array($wizardConfiguration['type'], array('script', 'colorbox', 'popup'), TRUE)) { $wizardIsEnabled = FALSE; } if (!$wizardIsEnabled) { continue; } // Title / icon: $iTitle = htmlspecialchars($languageService->sL($wizardConfiguration['title'])); if (isset($wizardConfiguration['icon'])) { $icon = FormEngineUtility::getIconHtml($wizardConfiguration['icon'], $iTitle, $iTitle); } else { $icon = $iTitle; } switch ($wizardConfiguration['type']) { case 'userFunc': $params = array(); $params['fieldConfig'] = $fieldConfig; $params['params'] = $wizardConfiguration['params']; $params['exampleImg'] = $wizardConfiguration['exampleImg']; $params['table'] = $table; $params['uid'] = $row['uid']; $params['pid'] = $row['pid']; $params['field'] = $field; $params['flexFormPath'] = $flexFormPath; $params['md5ID'] = $md5ID; $params['returnUrl'] = $this->getReturnUrl(); $params['formName'] = 'editform'; $params['itemName'] = $itemName; $params['hmac'] = GeneralUtility::hmac($params['formName'] . $params['itemName'], 'wizard_js'); $params['fieldChangeFunc'] = $fieldChangeFunc; $params['fieldChangeFuncHash'] = GeneralUtility::hmac(serialize($fieldChangeFunc)); $params['item'] =& $item; $params['icon'] = $icon; $params['iTitle'] = $iTitle; $params['wConf'] = $wizardConfiguration; $params['row'] = $row; $formEngineDummy = new FormEngine(); $otherWizards[] = GeneralUtility::callUserFunction($wizardConfiguration['userFunc'], $params, $formEngineDummy); break; case 'script': $params = array(); // Including the full fieldConfig from TCA may produce too long an URL if ($wizardIdentifier != 'RTE') { $params['fieldConfig'] = $fieldConfig; } $params['params'] = $wizardConfiguration['params']; $params['exampleImg'] = $wizardConfiguration['exampleImg']; $params['table'] = $table; $params['uid'] = $row['uid']; $params['pid'] = $row['pid']; $params['field'] = $field; $params['flexFormPath'] = $flexFormPath; $params['md5ID'] = $md5ID; $params['returnUrl'] = $this->getReturnUrl(); // Resolving script filename and setting URL. $urlParameters = array(); if (isset($wizardConfiguration['module']['urlParameters']) && is_array($wizardConfiguration['module']['urlParameters'])) { $urlParameters = $wizardConfiguration['module']['urlParameters']; } $wScript = BackendUtility::getModuleUrl($wizardConfiguration['module']['name'], $urlParameters, ''); $url = $wScript . (strstr($wScript, '?') ? '' : '?') . GeneralUtility::implodeArrayForUrl('', array('P' => $params)); $buttonWizards[] = '<a class="btn btn-default" href="' . htmlspecialchars($url) . '" onclick="this.blur(); return !TBE_EDITOR.isFormChanged();">' . $icon . '</a>'; break; case 'popup': $params = array(); $params['fieldConfig'] = $fieldConfig; $params['params'] = $wizardConfiguration['params']; $params['exampleImg'] = $wizardConfiguration['exampleImg']; $params['table'] = $table; $params['uid'] = $row['uid']; $params['pid'] = $row['pid']; $params['field'] = $field; $params['flexFormPath'] = $flexFormPath; $params['md5ID'] = $md5ID; $params['returnUrl'] = $this->getReturnUrl(); $params['formName'] = 'editform'; $params['itemName'] = $itemName; $params['hmac'] = GeneralUtility::hmac($params['formName'] . $params['itemName'], 'wizard_js'); $params['fieldChangeFunc'] = $fieldChangeFunc; $params['fieldChangeFuncHash'] = GeneralUtility::hmac(serialize($fieldChangeFunc)); // Resolving script filename and setting URL. $urlParameters = array(); if (isset($wizardConfiguration['module']['urlParameters']) && is_array($wizardConfiguration['module']['urlParameters'])) { $urlParameters = $wizardConfiguration['module']['urlParameters']; } $wScript = BackendUtility::getModuleUrl($wizardConfiguration['module']['name'], $urlParameters, ''); $url = $wScript . (strstr($wScript, '?') ? '' : '?') . GeneralUtility::implodeArrayForUrl('', array('P' => $params)); $onlyIfSelectedJS = ''; if (isset($wizardConfiguration['popup_onlyOpenIfSelected']) && $wizardConfiguration['popup_onlyOpenIfSelected']) { $notSelectedText = $languageService->sL('LLL:EXT:lang/locallang_core.xlf:mess.noSelItemForEdit'); $onlyIfSelectedJS = 'if (!TBE_EDITOR.curSelected(' . GeneralUtility::quoteJSvalue($itemName . $listFlag) . ')){' . 'alert(' . GeneralUtility::quoteJSvalue($notSelectedText) . ');' . 'return false;' . '}'; } $aOnClick = 'this.blur();' . $onlyIfSelectedJS . 'vHWin=window.open(' . GeneralUtility::quoteJSvalue($url) . '+\'&P[currentValue]=\'+TBE_EDITOR.rawurlencode(' . 'document.editform[' . GeneralUtility::quoteJSvalue($itemName) . '].value,200' . ')' . '+\'&P[currentSelectedValues]=\'+TBE_EDITOR.curSelected(' . GeneralUtility::quoteJSvalue($itemName . $listFlag) . '),' . GeneralUtility::quoteJSvalue('popUp' . $md5ID) . ',' . GeneralUtility::quoteJSvalue($wizardConfiguration['JSopenParams']) . ');' . 'vHWin.focus();' . 'return false;'; $buttonWizards[] = '<a class="btn btn-default" href="#" onclick="' . htmlspecialchars($aOnClick) . '">' . $icon . '</a>'; break; case 'colorbox': $params = array(); $params['fieldConfig'] = $fieldConfig; $params['params'] = $wizardConfiguration['params']; $params['exampleImg'] = $wizardConfiguration['exampleImg']; $params['table'] = $table; $params['uid'] = $row['uid']; $params['pid'] = $row['pid']; $params['field'] = $field; $params['flexFormPath'] = $flexFormPath; $params['md5ID'] = $md5ID; $params['returnUrl'] = $this->getReturnUrl(); $params['formName'] = 'editform'; $params['itemName'] = $itemName; $params['hmac'] = GeneralUtility::hmac($params['formName'] . $params['itemName'], 'wizard_js'); $params['fieldChangeFunc'] = $fieldChangeFunc; $params['fieldChangeFuncHash'] = GeneralUtility::hmac(serialize($fieldChangeFunc)); // Resolving script filename and setting URL. $urlParameters = array(); if (isset($wizardConfiguration['module']['urlParameters']) && is_array($wizardConfiguration['module']['urlParameters'])) { $urlParameters = $wizardConfiguration['module']['urlParameters']; } $wScript = BackendUtility::getModuleUrl($wizardConfiguration['module']['name'], $urlParameters, ''); $url = $wScript . (strstr($wScript, '?') ? '' : '?') . GeneralUtility::implodeArrayForUrl('', array('P' => $params)); $aOnClick = 'this.blur();' . 'vHWin=window.open(' . GeneralUtility::quoteJSvalue($url) . '+\'&P[currentValue]=\'+TBE_EDITOR.rawurlencode(' . 'document.editform[' . GeneralUtility::quoteJSvalue($itemName) . '].value,200' . ')' . '+\'&P[currentSelectedValues]=\'+TBE_EDITOR.curSelected(' . GeneralUtility::quoteJSvalue($itemName . $listFlag) . '),' . GeneralUtility::quoteJSvalue('popUp' . $md5ID) . ',' . GeneralUtility::quoteJSvalue($wizardConfiguration['JSopenParams']) . ');' . 'vHWin.focus();' . 'return false;'; $otherWizards[] = '<a id="' . $md5ID . '" class="btn btn-default" href="#" onclick="' . htmlspecialchars($aOnClick) . '"><span class="t3-icon fa fa-eyedropper"></span></a>'; break; case 'slider': $params = array(); $params['fieldConfig'] = $fieldConfig; $params['field'] = $field; $params['flexFormPath'] = $flexFormPath; $params['md5ID'] = $md5ID; $params['itemName'] = $itemName; $params['fieldChangeFunc'] = $fieldChangeFunc; $params['wConf'] = $wizardConfiguration; $params['row'] = $row; /** @var ValueSliderWizard $wizard */ $wizard = GeneralUtility::makeInstance(ValueSliderWizard::class); $otherWizards[] = $wizard->renderWizard($params); break; case 'select': $fieldValue = array('config' => $wizardConfiguration); $TSconfig = FormEngineUtility::getTSconfigForTableRow($table, $row); $TSconfig[$field] = $TSconfig[$field]['wizards.'][$wizardIdentifier . '.']; $selItems = FormEngineUtility::addSelectOptionsToItemArray(FormEngineUtility::initItemArray($fieldValue), $fieldValue, $TSconfig, $field); // Process items by a user function: if (!empty($wizardConfiguration['itemsProcFunc'])) { $funcConfig = !empty($wizardConfiguration['itemsProcFunc.']) ? $wizardConfiguration['itemsProcFunc.'] : array(); $dataPreprocessor = GeneralUtility::makeInstance(DataPreprocessor::class); $selItems = $dataPreprocessor->procItems($selItems, $funcConfig, $wizardConfiguration, $table, $row, $field); } $options = array(); $options[] = '<option>' . $iTitle . '</option>'; foreach ($selItems as $p) { $options[] = '<option value="' . htmlspecialchars($p[1]) . '">' . htmlspecialchars($p[0]) . '</option>'; } if ($wizardConfiguration['mode'] == 'append') { $assignValue = 'document.editform[' . GeneralUtility::quoteJSvalue($itemName) . '].value=\'\'+this.options[this.selectedIndex].value+document.editform[' . GeneralUtility::quoteJSvalue($itemName) . '].value'; } elseif ($wizardConfiguration['mode'] == 'prepend') { $assignValue = 'document.editform[' . GeneralUtility::quoteJSvalue($itemName) . '].value+=\'\'+this.options[this.selectedIndex].value'; } else { $assignValue = 'document.editform[' . GeneralUtility::quoteJSvalue($itemName) . '].value=this.options[this.selectedIndex].value'; } $otherWizards[] = '<select' . ' id="' . str_replace('.', '', uniqid('tceforms-select-', TRUE)) . '"' . ' class="form-control tceforms-select tceforms-wizardselect"' . ' name="_WIZARD' . $fName . '"' . ' onchange="' . htmlspecialchars($assignValue . ';this.blur();this.selectedIndex=0;' . implode('', $fieldChangeFunc)) . '"' . '>' . implode('', $options) . '</select>'; break; case 'suggest': if (!empty($PA['fieldTSConfig']['suggest.']['default.']['hide'])) { break; } /** @var SuggestWizard $suggestWizard */ $suggestWizard = GeneralUtility::makeInstance(SuggestWizard::class); $otherWizards[] = $suggestWizard->renderSuggestSelector($PA['itemFormElName'], $table, $field, $row, $PA); break; } // Hide the real form element? if (is_array($wizardConfiguration['hideParent']) || $wizardConfiguration['hideParent']) { // Setting the item to a hidden-field. $item = $itemKinds[1]; if (is_array($wizardConfiguration['hideParent'])) { $options = $this->globalOptions; $options['parameterArray'] = array('fieldConf' => array('config' => $wizardConfiguration['hideParent']), 'itemFormElValue' => $PA['itemFormElValue']); $options['renderType'] = 'none'; /** @var NodeFactory $nodeFactory */ $nodeFactory = $this->globalOptions['nodeFactory']; $noneElementResult = $nodeFactory->create($options)->render(); $item .= $noneElementResult['html']; } } } // For each rendered wizard, put them together around the item. if (!empty($buttonWizards) || !empty($otherWizards)) { if ($wizConf['_HIDDENFIELD']) { $item = $itemKinds[1]; } $innerContent = ''; if (!empty($buttonWizards)) { $innerContent .= '<div class="btn-group' . ($wizConf['_VERTICAL'] ? ' btn-group-vertical' : '') . '">' . implode('', $buttonWizards) . '</div>'; } $innerContent .= implode(' ', $otherWizards); // Position $classes = array('form-wizards-wrap'); if ($wizConf['_POSITION'] === 'left') { $classes[] = 'form-wizards-aside'; $innerContent = '<div class="form-wizards-items">' . $innerContent . '</div><div class="form-wizards-element">' . $item . '</div>'; } elseif ($wizConf['_POSITION'] === 'top') { $classes[] = 'form-wizards-top'; $innerContent = '<div class="form-wizards-items">' . $innerContent . '</div><div class="form-wizards-element">' . $item . '</div>'; } elseif ($wizConf['_POSITION'] === 'bottom') { $classes[] = 'form-wizards-bottom'; $innerContent = '<div class="form-wizards-element">' . $item . '</div><div class="form-wizards-items">' . $innerContent . '</div>'; } else { $classes[] = 'form-wizards-aside'; $innerContent = '<div class="form-wizards-element">' . $item . '</div><div class="form-wizards-items">' . $innerContent . '</div>'; } $item = ' <div class="' . implode(' ', $classes) . '"> ' . $innerContent . ' </div>'; } return $item; }
/** * Creates a single-selector box * * @param string $table See getSingleField_typeSelect() * @param string $field See getSingleField_typeSelect() * @param array $row See getSingleField_typeSelect() * @param array $parameterArray See getSingleField_typeSelect() * @param array $config (Redundant) content of $PA['fieldConf']['config'] (for convenience) * @param array $selectItems Items available for selection * @param string $noMatchingLabel Label for no-matching-value * @return string The HTML code for the item */ protected function getSingleField_typeSelect_single($table, $field, $row, $parameterArray, $config, $selectItems, $noMatchingLabel) { // Check against inline uniqueness /** @var InlineStackProcessor $inlineStackProcessor */ $inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class); $inlineStackProcessor->initializeByGivenStructure($this->globalOptions['inlineStructure']); $inlineParent = $inlineStackProcessor->getStructureLevel(-1); $uniqueIds = NULL; if (is_array($inlineParent) && $inlineParent['uid']) { $inlineObjectName = $inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($this->globalOptions['inlineFirstPid']); $inlineFormName = $inlineStackProcessor->getCurrentStructureFormPrefix(); if ($inlineParent['config']['foreign_table'] == $table && $inlineParent['config']['foreign_unique'] == $field) { $uniqueIds = $this->globalOptions['inlineData']['unique'][$inlineObjectName . '-' . $table]['used']; $parameterArray['fieldChangeFunc']['inlineUnique'] = 'inline.updateUnique(this,' . GeneralUtility::quoteJSvalue($inlineObjectName . '-' . $table) . ',' . GeneralUtility::quoteJSvalue($inlineFormName) . ',' . GeneralUtility::quoteJSvalue($row['uid']) . ');'; } // hide uid of parent record for symmetric relations if ($inlineParent['config']['foreign_table'] == $table && ($inlineParent['config']['foreign_field'] == $field || $inlineParent['config']['symmetric_field'] == $field)) { $uniqueIds[] = $inlineParent['uid']; } } // Initialization: $selectId = str_replace('.', '', uniqid('tceforms-select-', TRUE)); $selectedIndex = 0; $selectedIcon = ''; $noMatchingValue = 1; $onlySelectedIconShown = 0; $size = (int) $config['size']; // Style set on <select/> $out = ''; $options = ''; $disabled = FALSE; if ($this->isGlobalReadonly() || $config['readOnly']) { $disabled = TRUE; $onlySelectedIconShown = 1; } // Icon configuration: if ($config['suppress_icons'] === 'IF_VALUE_FALSE') { $suppressIcons = !$parameterArray['itemFormElValue'] ? 1 : 0; } elseif ($config['suppress_icons'] === 'ONLY_SELECTED') { $suppressIcons = 0; $onlySelectedIconShown = 1; } elseif ($config['suppress_icons']) { $suppressIcons = 1; } else { $suppressIcons = 0; } // Prepare groups $selectItemCounter = 0; $selectItemGroupCount = 0; $selectItemGroups = array(); $selectIcons = array(); foreach ($selectItems as $item) { if ($item[1] === '--div--') { // IS OPTGROUP if ($selectItemCounter !== 0) { $selectItemGroupCount++; } $selectItemGroups[$selectItemGroupCount]['header'] = array('title' => $item[0], 'icon' => !empty($item[2]) ? FormEngineUtility::getIconHtml($item[2]) : ''); } else { // IS ITEM $title = htmlspecialchars($item['0'], ENT_COMPAT, 'UTF-8', FALSE); $icon = !empty($item[2]) ? FormEngineUtility::getIconHtml($item[2], $title, $title) : ''; $selected = (string) $parameterArray['itemFormElValue'] === (string) $item[1] ? 1 : 0; if ($selected) { $selectedIndex = $selectItemCounter; $selectedIcon = $icon; $noMatchingValue = 0; } $selectItemGroups[$selectItemGroupCount]['items'][] = array('title' => $title, 'value' => $item[1], 'icon' => $icon, 'selected' => $selected, 'index' => $selectItemCounter); // ICON if ($icon && !$suppressIcons && (!$onlySelectedIconShown || $selected)) { $onClick = 'document.editform[' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName']) . '].selectedIndex=' . $selectItemCounter . ';'; if ($config['iconsInOptionTags']) { $onClick .= 'document.getElementById(' . GeneralUtility::quoteJSvalue($selectId . '_icon') . ').innerHTML = ' . 'document.editform[' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName']) . ']' . '.options[' . $selectItemCounter . '].getAttribute(\'data-icon\'); '; } $onClick .= implode('', $parameterArray['fieldChangeFunc']); $onClick .= 'this.blur();return false;'; $selectIcons[] = array('title' => $title, 'icon' => $icon, 'index' => $selectItemCounter, 'onClick' => $onClick); } $selectItemCounter++; } } // No-matching-value: if ($parameterArray['itemFormElValue'] && $noMatchingValue && !$parameterArray['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) { $noMatchingLabel = @sprintf($noMatchingLabel, $parameterArray['itemFormElValue']); $options = '<option value="' . htmlspecialchars($parameterArray['itemFormElValue']) . '" selected="selected">' . htmlspecialchars($noMatchingLabel) . '</option>'; } elseif (!$selectedIcon && $selectItemGroups[0]['items'][0]['icon']) { $selectedIcon = $selectItemGroups[0]['items'][0]['icon']; } // Process groups foreach ($selectItemGroups as $selectItemGroup) { // suppress groups without items if (empty($selectItemGroup['items'])) { continue; } $optionGroup = is_array($selectItemGroup['header']); $options .= $optionGroup ? '<optgroup label="' . htmlspecialchars($selectItemGroup['header']['title'], ENT_COMPAT, 'UTF-8', FALSE) . '">' : ''; if (is_array($selectItemGroup['items'])) { foreach ($selectItemGroup['items'] as $item) { $options .= '<option value="' . htmlspecialchars($item['value']) . '" data-icon="' . htmlspecialchars($item['icon']) . '"' . ($item['selected'] ? ' selected="selected"' : '') . '>' . $item['title'] . '</option>'; } } $options .= $optionGroup ? '</optgroup>' : ''; } // Create item form fields: $sOnChange = 'if (this.options[this.selectedIndex].value==\'--div--\') {this.selectedIndex=' . $selectedIndex . ';} '; if ($config['iconsInOptionTags']) { $sOnChange .= 'document.getElementById(' . GeneralUtility::quoteJSvalue($selectId . '_icon') . ').innerHTML = this.options[this.selectedIndex].getAttribute(\'data-icon\'); '; } $sOnChange .= implode('', $parameterArray['fieldChangeFunc']); // Add icons in option tags $prepend = ''; $append = ''; if ($config['iconsInOptionTags']) { $prepend = '<div class="input-group"><div id="' . $selectId . '_icon" class="input-group-addon input-group-icon t3js-formengine-select-prepend">' . $selectedIcon . '</div>'; $append = '</div>'; } // Build the element $out .= ' <div class="form-control-wrap"> ' . $prepend . ' <select' . ' id="' . $selectId . '"' . ' name="' . htmlspecialchars($parameterArray['itemFormElName']) . '"' . $this->getValidationDataAsDataAttribute($config) . ' class="form-control form-control-adapt"' . ($size ? ' size="' . $size . '"' : '') . ' onchange="' . htmlspecialchars($sOnChange) . '"' . $parameterArray['onFocus'] . ($disabled ? ' disabled="disabled"' : '') . '> ' . $options . ' </select> ' . $append . ' </div>'; // Create icon table: if (!empty($selectIcons) && !$config['noIconsBelowSelect']) { $selectIconColumns = (int) $config['selicon_cols']; if (!$selectIconColumns) { $selectIconColumns = count($selectIcons); } $selectIconColumns = $selectIconColumns > 12 ? 12 : $selectIconColumns; $selectIconRows = ceil(count($selectIcons) / $selectIconColumns); $selectIcons = array_pad($selectIcons, $selectIconRows * $selectIconColumns, ''); $out .= '<div class="table-fit table-fit-inline-block"><table class="table table-condensed table-white table-center"><tbody><tr>'; $selectIconTotalCount = count($selectIcons); for ($selectIconCount = 0; $selectIconCount < $selectIconTotalCount; $selectIconCount++) { if ($selectIconCount % $selectIconColumns === 0 && $selectIconCount !== 0) { $out .= '</tr><tr>'; } $out .= '<td>'; if (is_array($selectIcons[$selectIconCount])) { $out .= !$onlySelectedIconShown ? '<a href="#" title="' . $selectIcons[$selectIconCount]['title'] . '" onClick="' . htmlspecialchars($selectIcons[$selectIconCount]['onClick']) . '">' : ''; $out .= $selectIcons[$selectIconCount]['icon']; $out .= !$onlySelectedIconShown ? '</a>' : ''; } $out .= '</td>'; } $out .= '</tr></tbody></table></div>'; } return $out; }