/** * Convert the DOM object-id of an inline container to an array. * The object-id could look like 'data-parentPageId-tx_mmftest_company-1-employees'. * This initializes $this->inlineStructure - used by AJAX entry points * There are two keys: * - 'stable': Containing full qualified identifiers (table, uid and field) * - 'unstable': Containing partly filled data (e.g. only table and possibly field) * * @param string $domObjectId The DOM object-id * @param bool $loadConfig Load the TCA configuration for that level (default: TRUE) * @return void */ public function initializeByParsingDomObjectIdString($domObjectId, $loadConfig = TRUE) { $unstable = array(); $vector = array('table', 'uid', 'field'); // Substitute FlexForm addition and make parsing a bit easier $domObjectId = str_replace('---', ':', $domObjectId); // The starting pattern of an object identifier (e.g. "data-<firstPidValue>-<anything>) $pattern = '/^data' . '-' . '(.+?)' . '-' . '(.+)$/'; if (preg_match($pattern, $domObjectId, $match)) { $inlineFirstPid = $match[1]; $parts = explode('-', $match[2]); $partsCnt = count($parts); for ($i = 0; $i < $partsCnt; $i++) { if ($i > 0 && $i % 3 == 0) { // Load the TCA configuration of the table field and store it in the stack if ($loadConfig) { $unstable['config'] = $GLOBALS['TCA'][$unstable['table']]['columns'][$unstable['field']]['config']; // Fetch TSconfig: $TSconfig = FormEngineUtility::getTSconfigForTableRow($unstable['table'], array('uid' => $unstable['uid'], 'pid' => $inlineFirstPid), $unstable['field']); // Override TCA field config by TSconfig: if (!$TSconfig['disabled']) { $unstable['config'] = FormEngineUtility::overrideFieldConf($unstable['config'], $TSconfig); } $unstable['localizationMode'] = BackendUtility::getInlineLocalizationMode($unstable['table'], $unstable['config']); } // Extract FlexForm from field part (if any) if (strpos($unstable['field'], ':') !== FALSE) { $fieldParts = GeneralUtility::trimExplode(':', $unstable['field']); $unstable['field'] = array_shift($fieldParts); // FlexForm parts start with data: if (count($fieldParts) > 0 && $fieldParts[0] === 'data') { $unstable['flexform'] = $fieldParts; } } $this->inlineStructure['stable'][] = $unstable; $unstable = array(); } $unstable[$vector[$i % 3]] = $parts[$i]; } if (count($unstable)) { $this->inlineStructure['unstable'] = $unstable; } } }
/** * Get a selector as used for the select type, to select from all available * records and to create a relation to the embedding record (e.g. like MM). * * @param array $selItems Array of all possible records * @param array $conf TCA configuration of the parent(!) field * @param array $PA An array with additional configuration options * @param array $uniqueIds The uids that have already been used and should be unique * @return string A HTML <select> box with all possible records */ protected function renderPossibleRecordsSelectorTypeSelect($selItems, $conf, &$PA, $uniqueIds = array()) { $foreign_table = $conf['foreign_table']; $foreign_selector = $conf['foreign_selector']; $PA = array(); $PA['fieldConf'] = $GLOBALS['TCA'][$foreign_table]['columns'][$foreign_selector]; $PA['fieldTSConfig'] = FormEngineUtility::getTSconfigForTableRow($foreign_table, array(), $foreign_selector); $config = $PA['fieldConf']['config']; $item = ''; // @todo $disabled is not present - should be read from config? $disabled = false; if (!$disabled) { $nameObject = $this->inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($this->data['inlineFirstPid']); // Create option tags: $opt = array(); foreach ($selItems as $p) { if (!in_array($p[1], $uniqueIds)) { $opt[] = '<option value="' . htmlspecialchars($p[1]) . '">' . htmlspecialchars($p[0]) . '</option>'; } } // Put together the selector box: $itemListStyle = isset($config['itemListStyle']) ? ' style="' . htmlspecialchars($config['itemListStyle']) . '"' : ''; $size = (int) $conf['size']; $size = $conf['autoSizeMax'] ? MathUtility::forceIntegerInRange(count($selItems) + 1, MathUtility::forceIntegerInRange($size, 1), $conf['autoSizeMax']) : $size; $onChange = 'return inline.importNewRecord(' . GeneralUtility::quoteJSvalue($nameObject . '-' . $conf['foreign_table']) . ')'; $item = ' <select id="' . $nameObject . '-' . $conf['foreign_table'] . '_selector" class="form-control"' . ($size ? ' size="' . $size . '"' : '') . ' onchange="' . htmlspecialchars($onChange) . '"' . $PA['onFocus'] . $itemListStyle . ($conf['foreign_unique'] ? ' isunique="isunique"' : '') . '> ' . implode('', $opt) . ' </select>'; if ($size <= 1) { // Add a "Create new relation" link for adding new relations // This is necessary, if the size of the selector is "1" or if // there is only one record item in the select-box, that is selected by default // The selector-box creates a new relation on using an onChange event (see some line above) if (!empty($conf['appearance']['createNewRelationLinkTitle'])) { $createNewRelationText = $this->getLanguageService()->sL($conf['appearance']['createNewRelationLinkTitle'], true); } else { $createNewRelationText = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:cm.createNewRelation', true); } $item .= ' <span class="input-group-btn"> <a href="#" class="btn btn-default" onclick="' . htmlspecialchars($onChange) . '" title="' . $createNewRelationText . '"> ' . $this->iconFactory->getIcon('actions-document-new', Icon::SIZE_SMALL)->render() . $createNewRelationText . ' </a> </span>'; } else { $item .= ' <span class="input-group-btn btn"></span>'; } // Wrap the selector and add a spacer to the bottom $item = '<div class="input-group form-group t3js-formengine-validation-marker ' . $this->inlineData['config'][$nameObject]['md5'] . '">' . $item . '</div>'; } return $item; }
/** * Determine the configuration and the type of a record selector. * This is a helper method for inline / IRRE handling * * @param array $conf TCA configuration of the parent(!) field * @param string $field Field name * @return array Associative array with the keys 'PA' and 'type', both are FALSE if the selector was not valid. * @internal */ public static function getInlinePossibleRecordsSelectorConfig($conf, $field = '') { $foreign_table = $conf['foreign_table']; $foreign_selector = $conf['foreign_selector']; $PA = false; $type = false; $table = false; $selector = false; if ($field) { $PA = array(); $PA['fieldConf'] = $GLOBALS['TCA'][$foreign_table]['columns'][$field]; if ($PA['fieldConf'] && $conf['foreign_selector_fieldTcaOverride']) { ArrayUtility::mergeRecursiveWithOverrule($PA['fieldConf'], $conf['foreign_selector_fieldTcaOverride']); } $PA['fieldTSConfig'] = FormEngineUtility::getTSconfigForTableRow($foreign_table, array(), $field); $config = $PA['fieldConf']['config']; // Determine type of Selector: $type = static::getInlinePossibleRecordsSelectorType($config); // Return table on this level: $table = $type === 'select' ? $config['foreign_table'] : $config['allowed']; // Return type of the selector if foreign_selector is defined and points to the same field as in $field: if ($foreign_selector && $foreign_selector == $field && $type) { $selector = $type; } } return array('PA' => $PA, 'type' => $type, 'table' => $table, 'selector' => $selector); }
/** * Determine label of a single field (not a palette label) * * @param string $fieldName The field name to calculate the label for * @param string $labelFromShowItem Given label, typically from show item configuration * @return string Field label */ protected function getSingleFieldLabel($fieldName, $labelFromShowItem) { $languageService = $this->getLanguageService(); $table = $this->globalOptions['table']; $label = $labelFromShowItem; if (!empty($GLOBALS['TCA'][$table]['columns'][$fieldName]['label'])) { $label = $GLOBALS['TCA'][$table]['columns'][$fieldName]['label']; } if (!empty($labelFromShowItem)) { $label = $labelFromShowItem; } $fieldTSConfig = FormEngineUtility::getTSconfigForTableRow($table, $this->globalOptions['databaseRow'], $fieldName); if (!empty($fieldTSConfig['label'])) { $label = $fieldTSConfig['label']; } if (!empty($fieldTSConfig['label.'][$languageService->lang])) { $label = $fieldTSConfig['label.'][$languageService->lang]; } return $languageService->sL($label); }
/** * Modify a single FlexForm sheet according to given configuration * * @param array $sheet Flexform sheet to manipulate * @param string $table The table name * @param string $tableField The field name * @param array $tableRow The record data * @param array $sheetConf Sheet configuration * @param array $nonExcludeFields Non-exclude-fields for this sheet * @return array Modified sheet * @see \TYPO3\CMS\Backend\Form\FlexFormsHelper::modifyFlexFormDS() */ public function modifySingleFlexFormSheet(array $sheet, $table, $tableField, array $tableRow, array $sheetConf, array $nonExcludeFields) { if (empty($sheet) || empty($table) || empty($tableField) || empty($tableRow)) { return $sheet; } // Modify fields foreach ($sheet as $fieldName => $field) { // Remove excluded fields if (!$GLOBALS['BE_USER']->isAdmin() && !empty($field['TCEforms']['exclude']) && empty($nonExcludeFields[$fieldName])) { unset($sheet[$fieldName]); continue; } // Stop here if no TSConfig was found for this field if (empty($sheetConf[$fieldName]) || !is_array($sheetConf[$fieldName])) { continue; } // Remove disabled fields if (!empty($sheetConf[$fieldName]['disabled'])) { unset($sheet[$fieldName]); continue; } $fieldConf = $sheetConf[$fieldName]; $removeItems = !empty($fieldConf['removeItems']) ? GeneralUtility::trimExplode(',', $fieldConf['removeItems'], TRUE) : array(); $keepItems = !empty($fieldConf['keepItems']) ? GeneralUtility::trimExplode(',', $fieldConf['keepItems'], TRUE) : array(); $renameItems = !empty($fieldConf['altLabels']) && is_array($fieldConf['altLabels']) ? $fieldConf['altLabels'] : array(); $changeIcons = !empty($fieldConf['altIcons']) && is_array($fieldConf['altIcons']) ? $fieldConf['altIcons'] : array(); $addItems = !empty($fieldConf['addItems']) && is_array($fieldConf['addItems']) ? $fieldConf['addItems'] : array(); unset($fieldConf['removeItems']); unset($fieldConf['keepItems']); unset($fieldConf['altLabels']); unset($fieldConf['altIcons']); unset($fieldConf['addItems']); // Manipulate field if (!empty($field['TCEforms']) && is_array($field['TCEforms'])) { $sheet[$fieldName]['TCEforms'] = $field['TCEforms']; ArrayUtility::mergeRecursiveWithOverrule($sheet[$fieldName]['TCEforms'], $fieldConf); } // Manipulate only select fields, other field types will stop here if (empty($field['TCEforms']['config']['type']) || $field['TCEforms']['config']['type'] != 'select' || $field['TCEforms']['config']['renderMode'] === 'tree') { continue; } // Getting the selector box items from system $selItems = FormEngineUtility::addSelectOptionsToItemArray(FormEngineUtility::initItemArray($field['TCEforms']), $field['TCEforms'], FormEngineUtility::getTSconfigForTableRow($table, $tableRow), $tableField); // Possibly filter some items $selItems = ArrayUtility::keepItemsInArray($selItems, $keepItems, function ($value) { return $value[1]; }); // Possibly add some items $selItems = FormEngineUtility::addItems($selItems, $addItems); // Process items by a user function if (!empty($field['TCEforms']['config']['itemsProcFunc'])) { $dataPreprocessor = GeneralUtility::makeInstance(DataPreprocessor::class); $selItems = $dataPreprocessor->procItems($selItems, $fieldConf['config'], $field['TCEforms']['config'], $table, $tableRow, $tableField); } // Remove special configuration options after creating items to prevent double parsing foreach ($this->removeSelectConfig as $option) { unset($sheet[$fieldName]['TCEforms']['config'][$option]); } // Rename and remove items or change item icon in select if ((!empty($removeItems) || !empty($renameItems) || !empty($changeIcons)) && !empty($selItems) && is_array($selItems)) { foreach ($selItems as $itemKey => $itemConf) { // Option has no key, no manipulation possible if (!isset($itemConf[1])) { continue; } // Remove foreach ($removeItems as $removeKey => $removeValue) { if (strcasecmp($removeValue, $itemConf[1]) == 0) { unset($selItems[$itemKey]); unset($removeItems[$removeKey]); } } // Rename foreach ($renameItems as $renameKey => $renameValue) { if (strcasecmp($renameKey, $itemConf[1]) == 0) { $selItems[$itemKey][0] = htmlspecialchars($renameValue); unset($renameItems[$renameKey]); } } // Change icon foreach ($changeIcons as $iconKey => $iconValue) { if (strcasecmp($iconKey, $itemConf[1]) == 0) { $selItems[$itemKey][2] = $iconValue; unset($changeIcons[$iconKey]); } } } } $sheet[$fieldName]['TCEforms']['config']['items'] = $selItems; } return $sheet; }
/** * Main function, rendering the document with the iFrame with the RTE in. * * @return void */ public function main() { // Translate id to the workspace version: if ($versionedRecord = BackendUtility::getWorkspaceVersionOfRecord($this->getBackendUserAuthentication()->workspace, $this->P['table'], $this->P['uid'], 'uid')) { $this->P['uid'] = $versionedRecord['uid']; } // If all parameters are available: if ($this->P['table'] && $this->P['field'] && $this->P['uid'] && $this->checkEditAccess($this->P['table'], $this->P['uid'])) { // Getting the raw record (we need only the pid-value from here...) $rawRecord = BackendUtility::getRecord($this->P['table'], $this->P['uid']); BackendUtility::fixVersioningPid($this->P['table'], $rawRecord); // override the default jumpToUrl $this->doc->JScodeArray['jumpToUrl'] = ' function jumpToUrl(URL,formEl) { if (document.editform) { if (!TBE_EDITOR.isFormChanged()) { window.location.href = URL; } else if (formEl) { if (formEl.type=="checkbox") formEl.checked = formEl.checked ? 0 : 1; } } else { window.location.href = URL; } } '; // Setting JavaScript of the pid value for viewing: if ($this->popView) { $this->doc->JScode = $this->doc->wrapScriptTags(BackendUtility::viewOnClick($rawRecord['pid'], '', BackendUtility::BEgetRootLine($rawRecord['pid']))); } // Initialize FormEngine - for rendering the field: /** @var FormEngine $formEngine */ $formEngine = GeneralUtility::makeInstance(FormEngine::class); // SPECIAL: Disables all wizards - we are NOT going to need them. $formEngine->disableWizards = 1; // Fetching content of record: /** @var DataPreprocessor $dataPreprocessor */ $dataPreprocessor = GeneralUtility::makeInstance(DataPreprocessor::class); $dataPreprocessor->lockRecords = 1; $dataPreprocessor->fetchRecord($this->P['table'], $this->P['uid'], ''); // Getting the processed record content out: $processedRecord = reset($dataPreprocessor->regTableItems_data); $processedRecord['uid'] = $this->P['uid']; $processedRecord['pid'] = $rawRecord['pid']; // TSconfig, setting width: $fieldTSConfig = FormEngineUtility::getTSconfigForTableRow($this->P['table'], $processedRecord, $this->P['field']); if ((string) $fieldTSConfig['RTEfullScreenWidth'] !== '') { $width = $fieldTSConfig['RTEfullScreenWidth']; } else { $width = '100%'; } // Get the form field and wrap it in the table with the buttons: $formContent = $formEngine->getSoloField($this->P['table'], $processedRecord, $this->P['field']); $formContent = ' <!-- RTE wizard: --> <table border="0" cellpadding="0" cellspacing="0" width="' . $width . '" id="typo3-rtewizard"> <tr> <td width="' . $width . '" colspan="2" id="c-formContent">' . $formContent . '</td> <td></td> </tr> </table>'; // Adding hidden fields: $formContent .= '<input type="hidden" name="redirect" value="' . htmlspecialchars($this->R_URI) . '" /> <input type="hidden" name="_serialNumber" value="' . md5(microtime()) . '" />' . FormEngine::getHiddenTokenField('tceAction'); // Finally, add the whole setup: $this->content .= $formEngine->printNeededJSFunctions_top() . $formContent . $formEngine->printNeededJSFunctions(); } else { // ERROR: $this->content .= $this->doc->section($this->getLanguageService()->getLL('forms_title'), '<span class="text-danger">' . $this->getLanguageService()->getLL('table_noData', TRUE) . '</span>', 0, 1); } // Setting up the buttons and markers for docHeader $docHeaderButtons = $this->getButtons(); $markers['CONTENT'] = $this->content; // Build the <body> for the module $this->content = $this->doc->startPage(''); $this->content .= $this->doc->moduleBody(array(), $docHeaderButtons, $markers); $this->content .= $this->doc->endPage(); $this->content = $this->doc->insertStylesAndJS($this->content); }
/** * Entry method * * @return array As defined in initializeResultArray() of AbstractNode */ public function render() { $backendUser = $this->getBackendUserAuthentication(); $languageService = $this->getLanguageService(); $resultArray = $this->initializeResultArray(); $table = $this->globalOptions['table']; $row = $this->globalOptions['databaseRow']; $fieldName = $this->globalOptions['fieldName']; if (!is_array($GLOBALS['TCA'][$table]['columns'][$fieldName])) { return $resultArray; } $parameterArray = array(); $parameterArray['fieldConf'] = $GLOBALS['TCA'][$table]['columns'][$fieldName]; // Overlay fieldConf with possible defined columnsOverrides of given record type $recordTypeValue = $this->globalOptions['recordTypeValue']; // Hint: 0 is a valid $recordTypeValue, !empty() does not work here if (trim($recordTypeValue) !== '' && is_array($GLOBALS['TCA'][$table]['types'][$recordTypeValue]['columnsOverrides'][$fieldName])) { // Merge columnsOverrides of this field over existing field configuration ArrayUtility::mergeRecursiveWithOverrule($parameterArray['fieldConf'], $GLOBALS['TCA'][$table]['types'][$recordTypeValue]['columnsOverrides'][$fieldName]); } // A couple of early returns in case the field should not be rendered // Check if this field is configured and editable according to exclude fields and other configuration if ($parameterArray['fieldConf']['exclude'] && !$backendUser->check('non_exclude_fields', $table . ':' . $fieldName) || $parameterArray['fieldConf']['config']['type'] === 'passthrough' || !$backendUser->isRTE() && $parameterArray['fieldConf']['config']['showIfRTE'] || $GLOBALS['TCA'][$table]['ctrl']['languageField'] && !$parameterArray['fieldConf']['l10n_display'] && $parameterArray['fieldConf']['l10n_mode'] === 'exclude' && $row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] > 0 || $GLOBALS['TCA'][$table]['ctrl']['languageField'] && $this->globalOptions['localizationMode'] && $this->globalOptions['localizationMode'] !== $parameterArray['fieldConf']['l10n_cat'] || $this->inlineFieldShouldBeSkipped()) { return $resultArray; } // Evaluate display condition if ($parameterArray['fieldConf']['displayCond'] && is_array($row)) { // @todo: isn't $row = array() safe somewhere above already? /** @var $elementConditionMatcher ElementConditionMatcher */ $elementConditionMatcher = GeneralUtility::makeInstance(ElementConditionMatcher::class); if (!$elementConditionMatcher->match($parameterArray['fieldConf']['displayCond'], $row)) { return $resultArray; } } // Fetching the TSconfig for the current table/field. This includes the $row which means that $parameterArray['fieldTSConfig'] = FormEngineUtility::getTSconfigForTableRow($table, $row, $fieldName); if ($parameterArray['fieldTSConfig']['disabled']) { return $resultArray; } // Override fieldConf by fieldTSconfig: $parameterArray['fieldConf']['config'] = FormEngineUtility::overrideFieldConf($parameterArray['fieldConf']['config'], $parameterArray['fieldTSConfig']); $parameterArray['itemFormElName'] = 'data[' . $table . '][' . $row['uid'] . '][' . $fieldName . ']'; $parameterArray['itemFormElID'] = 'data_' . $table . '_' . $row['uid'] . '_' . $fieldName; $newElementBaseName = $this->globalOptions['elementBaseName'] . '[' . $table . '][' . $row['uid'] . '][' . $fieldName . ']'; // The value to show in the form field. $parameterArray['itemFormElValue'] = $row[$fieldName]; // Set field to read-only if configured for translated records to show default language content as readonly if ($parameterArray['fieldConf']['l10n_display'] && GeneralUtility::inList($parameterArray['fieldConf']['l10n_display'], 'defaultAsReadonly') && $row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] > 0) { $parameterArray['fieldConf']['config']['readOnly'] = TRUE; $parameterArray['itemFormElValue'] = $this->globalOptions['defaultLanguageData'][$table . ':' . $row['uid']][$fieldName]; } if (strpos($GLOBALS['TCA'][$table]['ctrl']['type'], ':') === FALSE) { $typeField = $GLOBALS['TCA'][$table]['ctrl']['type']; } else { $typeField = substr($GLOBALS['TCA'][$table]['ctrl']['type'], 0, strpos($GLOBALS['TCA'][$table]['ctrl']['type'], ':')); } // Create a JavaScript code line which will ask the user to save/update the form due to changing the element. // This is used for eg. "type" fields and others configured with "requestUpdate" if (!empty($GLOBALS['TCA'][$table]['ctrl']['type']) && $fieldName === $typeField || !empty($GLOBALS['TCA'][$table]['ctrl']['requestUpdate']) && GeneralUtility::inList(str_replace(' ', '', $GLOBALS['TCA'][$table]['ctrl']['requestUpdate']), $fieldName)) { if ($backendUser->jsConfirmation(1)) { $alertMsgOnChange = 'if (confirm(TBE_EDITOR.labels.onChangeAlert) && TBE_EDITOR.checkSubmit(-1)){ TBE_EDITOR.submitForm() };'; } else { $alertMsgOnChange = 'if (TBE_EDITOR.checkSubmit(-1)){ TBE_EDITOR.submitForm() };'; } } else { $alertMsgOnChange = ''; } if (in_array($fieldName, $this->globalOptions['hiddenFieldListArray'], TRUE)) { // Render as a hidden field if this field had a forced value in overrideVals // @todo: This is an ugly concept ... search for overrideVals and defVals for a full picture of this madness $resultArray = $this->initializeResultArray(); // This hidden field can not just be returned as casual html since upper containers will then render a label and wrapping stuff - this is not wanted here $resultArray['additionalHiddenFields'][] = '<input type="hidden" name="' . $parameterArray['itemFormElName'] . '" value="' . htmlspecialchars($parameterArray['itemFormElValue']) . '" />'; } else { // JavaScript code for event handlers: $parameterArray['fieldChangeFunc'] = array(); $parameterArray['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] = 'TBE_EDITOR.fieldChanged(' . GeneralUtility::quoteJSvalue($table) . ',' . GeneralUtility::quoteJSvalue($row['uid']) . ',' . GeneralUtility::quoteJSvalue($fieldName) . ',' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName']) . ');'; $parameterArray['fieldChangeFunc']['alert'] = $alertMsgOnChange; // If this is the child of an inline type and it is the field creating the label if ($this->isInlineChildAndLabelField($table, $fieldName)) { /** @var InlineStackProcessor $inlineStackProcessor */ $inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class); $inlineStackProcessor->initializeByGivenStructure($this->globalOptions['inlineStructure']); $inlineDomObjectId = $inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($this->globalOptions['inlineFirstPid']); $inlineObjectId = implode('-', array($inlineDomObjectId, $table, $row['uid'])); $parameterArray['fieldChangeFunc']['inline'] = 'inline.handleChangedField(' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName']) . ',' . GeneralUtility::quoteJSvalue($inlineObjectId) . ');'; } // Based on the type of the item, call a render function on a child element $options = $this->globalOptions; $options['parameterArray'] = $parameterArray; $options['elementBaseName'] = $newElementBaseName; if (!empty($parameterArray['fieldConf']['config']['renderType'])) { $options['renderType'] = $parameterArray['fieldConf']['config']['renderType']; } else { // Fallback to type if no renderType is given $options['renderType'] = $parameterArray['fieldConf']['config']['type']; } /** @var NodeFactory $nodeFactory */ $nodeFactory = $this->globalOptions['nodeFactory']; $resultArray = $nodeFactory->create($options)->render(); $html = $resultArray['html']; // @todo: the language handling, the null and the placeholder stuff should be embedded in the single // @todo: element classes. Basically, this method should return here and have the element classes // @todo: decide on language stuff and other wraps already. // Add language + diff $renderLanguageDiff = TRUE; if ($parameterArray['fieldConf']['l10n_display'] && (GeneralUtility::inList($parameterArray['fieldConf']['l10n_display'], 'hideDiff') || GeneralUtility::inList($parameterArray['fieldConf']['l10n_display'], 'defaultAsReadonly'))) { $renderLanguageDiff = FALSE; } if ($renderLanguageDiff) { $html = $this->renderDefaultLanguageContent($table, $fieldName, $row, $html); $html = $this->renderDefaultLanguageDiff($table, $fieldName, $row, $html); } $fieldItemClasses = array('t3js-formengine-field-item'); // NULL value and placeholder handling $nullControlNameAttribute = ' name="' . htmlspecialchars('control[active][' . $table . '][' . $row['uid'] . '][' . $fieldName . ']') . '"'; if (!empty($parameterArray['fieldConf']['config']['eval']) && GeneralUtility::inList($parameterArray['fieldConf']['config']['eval'], 'null') && (empty($parameterArray['fieldConf']['config']['mode']) || $parameterArray['fieldConf']['config']['mode'] !== 'useOrOverridePlaceholder')) { // This field has eval=null set, but has no useOverridePlaceholder defined. // Goal is to have a field that can distinct between NULL and empty string in the database. // A checkbox and an additional hidden field will be created, both with the same name // and prefixed with "control[active]". If the checkbox is set (value 1), the value from the casual // input field will be written to the database. If the checkbox is not set, the hidden field // transfers value=0 to DataHandler, the value of the input field will then be reset to NULL by the // DataHandler at an early point in processing, so NULL will be written to DB as field value. // If the value of the field *is* NULL at the moment, an additional class is set // @todo: This does not work well at the moment, but is kept for now. see input_14 of ext:styleguide as example $checked = ' checked="checked"'; if ($this->globalOptions['databaseRow'][$fieldName] === NULL) { $fieldItemClasses[] = 'disabled'; $checked = ''; } $formElementName = 'data[' . $table . '][' . $row['uid'] . '][' . $fieldName . ']'; $onChange = htmlspecialchars('typo3form.fieldSetNull(' . GeneralUtility::quoteJSvalue($formElementName) . ', !this.checked)'); $nullValueWrap = array(); $nullValueWrap[] = '<div class="' . implode(' ', $fieldItemClasses) . '">'; $nullValueWrap[] = '<div class="t3-form-field-disable"></div>'; $nullValueWrap[] = '<div class="checkbox">'; $nullValueWrap[] = '<label>'; $nullValueWrap[] = '<input type="hidden"' . $nullControlNameAttribute . ' value="0" />'; $nullValueWrap[] = '<input type="checkbox"' . $nullControlNameAttribute . ' value="1" onchange="' . $onChange . '"' . $checked . ' /> '; $nullValueWrap[] = '</label>'; $nullValueWrap[] = $html; $nullValueWrap[] = '</div>'; $nullValueWrap[] = '</div>'; $html = implode(LF, $nullValueWrap); } elseif (isset($parameterArray['fieldConf']['config']['mode']) && $parameterArray['fieldConf']['config']['mode'] === 'useOrOverridePlaceholder') { // This field has useOverridePlaceholder set. // Here, a value from a deeper DB structure can be "fetched up" as value, and can also be overridden by a // local value. This is used in FAL, where eg. the "title" field can have the default value from sys_file_metadata, // the title field of sys_file_reference is then set to NULL. Or the "override" checkbox is set, and a string // or an empty string is then written to the field of sys_file_reference. // The situation is similar to the NULL handling above, but additionally a "default" value should be shown. // To achieve this, again a hidden control[hidden] field is added together with a checkbox with the same name // to transfer the information whether the default value should be used or not: Checkbox checked transfers 1 as // value in control[active], meaning the overridden value should be used. // Additionally to the casual input field, a second field is added containing the "placeholder" value. This // field has no name attribute and is not transferred at all. Those two are then hidden / shown depending // on the state of the above checkbox in via JS. $placeholder = $this->getPlaceholderValue($table, $parameterArray['fieldConf']['config'], $row); $onChange = 'typo3form.fieldTogglePlaceholder(' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName']) . ', !this.checked)'; $checked = $parameterArray['itemFormElValue'] === NULL ? '' : ' checked="checked"'; $resultArray['additionalJavaScriptPost'][] = 'typo3form.fieldTogglePlaceholder(' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName']) . ', ' . ($checked ? 'false' : 'true') . ');'; // Renders a input or textarea field depending on type of "parent" $options = array(); $options['databaseRow'] = array(); $options['table'] = ''; $options['parameterArray'] = $parameterArray; $options['parameterArray']['itemFormElValue'] = GeneralUtility::fixed_lgd_cs($placeholder, 30); $options['renderType'] = 'none'; /** @var NodeFactory $nodeFactory */ $nodeFactory = $this->globalOptions['nodeFactory']; $noneElementResult = $nodeFactory->create($options)->render(); $noneElementHtml = $noneElementResult['html']; $placeholderWrap = array(); $placeholderWrap[] = '<div class="' . implode(' ', $fieldItemClasses) . '">'; $placeholderWrap[] = '<div class="t3-form-field-disable"></div>'; $placeholderWrap[] = '<div class="checkbox">'; $placeholderWrap[] = '<label>'; $placeholderWrap[] = '<input type="hidden"' . $nullControlNameAttribute . ' value="0" />'; $placeholderWrap[] = '<input type="checkbox"' . $nullControlNameAttribute . ' value="1" id="tce-forms-textfield-use-override-' . $fieldName . '-' . $row['uid'] . '" onchange="' . htmlspecialchars($onChange) . '"' . $checked . ' />'; $placeholderWrap[] = sprintf($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.placeholder.override'), BackendUtility::getRecordTitlePrep($placeholder, 20)); $placeholderWrap[] = '</label>'; $placeholderWrap[] = '</div>'; $placeholderWrap[] = '<div class="t3js-formengine-placeholder-placeholder">'; $placeholderWrap[] = $noneElementHtml; $placeholderWrap[] = '</div>'; $placeholderWrap[] = '<div class="t3js-formengine-placeholder-formfield">'; $placeholderWrap[] = $html; $placeholderWrap[] = '</div>'; $placeholderWrap[] = '</div>'; $html = implode(LF, $placeholderWrap); } elseif ($parameterArray['fieldConf']['config']['type'] !== 'user' || empty($parameterArray['fieldConf']['config']['noTableWrapping'])) { // Add a casual wrap if the field is not of type user with no wrap requested. $standardWrap = array(); $standardWrap[] = '<div class="' . implode(' ', $fieldItemClasses) . '">'; $standardWrap[] = '<div class="t3-form-field-disable"></div>'; $standardWrap[] = $html; $standardWrap[] = '</div>'; $html = implode(LF, $standardWrap); } $resultArray['html'] = $html; } return $resultArray; }
/** * If the select field is build by a foreign_table the related UIDs * will be returned. * * Otherwise the label of the currently selected value will be written * to the alternativeFieldValue class property. * * @param array $fieldConfig The "config" section of the TCA for the current select field. * @param string $fieldName The name of the select field. * @param string $value The current value in the local record, usually a comma separated list of selected values. * @return array Array of related UIDs. */ protected function getRelatedSelectFieldUids(array $fieldConfig, $fieldName, $value) { $relatedUids = array(); $isTraversable = FALSE; if (isset($fieldConfig['foreign_table'])) { $isTraversable = TRUE; // if a foreign_table is used we pre-filter the records for performance $fieldConfig['foreign_table_where'] .= ' AND ' . $fieldConfig['foreign_table'] . '.uid IN (' . $value . ')'; } $PA = array(); $PA['fieldConf']['config'] = $fieldConfig; $PA['fieldTSConfig'] = FormEngineUtility::getTSconfigForTableRow($this->currentTable, $this->currentRow, $fieldName); $PA['fieldConf']['config'] = FormEngineUtility::overrideFieldConf($PA['fieldConf']['config'], $PA['fieldTSConfig']); $selectItemArray = FormEngineUtility::getSelectItems($this->currentTable, $fieldName, $this->currentRow, $PA); if ($isTraversable && !empty($selectItemArray)) { $this->currentTable = $fieldConfig['foreign_table']; $relatedUids = $this->getSelectedValuesFromSelectItemArray($selectItemArray, $value); } else { $selectedLabels = $this->getSelectedValuesFromSelectItemArray($selectItemArray, $value, 1, TRUE); if (count($selectedLabels) === 1) { $this->alternativeFieldValue = $selectedLabels[0]; $this->forceAlternativeFieldValueUse = TRUE; } } return $relatedUids; }
/** * 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; }