/** * Creates a multiple-selector box (two boxes, side-by-side) * * @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_multiple($table, $field, $row, $parameterArray, $config, $selItems, $noMatchingLabel) { $languageService = $this->getLanguageService(); $item = ''; $disabled = ''; if ($this->isGlobalReadonly() || $config['readOnly']) { $disabled = ' disabled="disabled"'; } // Setting this hidden field (as a flag that JavaScript can read out) if (!$disabled) { $item .= '<input type="hidden" name="' . $parameterArray['itemFormElName'] . '_mul" value="' . ($config['multiple'] ? 1 : 0) . '" />'; } // Set max and min items: $maxitems = MathUtility::forceIntegerInRange($config['maxitems'], 0); if (!$maxitems) { $maxitems = 100000; } // Get "removeItems": $removeItems = GeneralUtility::trimExplode(',', $parameterArray['fieldTSConfig']['removeItems'], TRUE); // Get the array with selected items: $itemArray = GeneralUtility::trimExplode(',', $parameterArray['itemFormElValue'], TRUE); // Possibly filter some items: $itemArray = ArrayUtility::keepItemsInArray($itemArray, $parameterArray['fieldTSConfig']['keepItems'], function ($value) { $parts = explode('|', $value, 2); return rawurldecode($parts[0]); }); // Perform modification of the selected items array: foreach ($itemArray as $tk => $tv) { $tvP = explode('|', $tv, 2); $evalValue = $tvP[0]; $isRemoved = in_array($evalValue, $removeItems) || $config['type'] == 'select' && $config['authMode'] && !$this->getBackendUserAuthentication()->checkAuthMode($table, $field, $evalValue, $config['authMode']); if ($isRemoved && !$parameterArray['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) { $tvP[1] = rawurlencode(@sprintf($noMatchingLabel, $evalValue)); } else { if (isset($parameterArray['fieldTSConfig']['altLabels.'][$evalValue])) { $tvP[1] = rawurlencode($languageService->sL($parameterArray['fieldTSConfig']['altLabels.'][$evalValue])); } if (isset($parameterArray['fieldTSConfig']['altIcons.'][$evalValue])) { $tvP[2] = $parameterArray['fieldTSConfig']['altIcons.'][$evalValue]; } } if ($tvP[1] == '') { // Case: flexform, default values supplied, no label provided (bug #9795) foreach ($selItems as $selItem) { if ($selItem[1] == $tvP[0]) { $tvP[1] = html_entity_decode($selItem[0]); break; } } } $itemArray[$tk] = implode('|', $tvP); } // size must be at least two, as there are always maxitems > 1 (see parent function) if (isset($config['size'])) { $size = (int) $config['size']; } else { $size = 2; } $size = $config['autoSizeMax'] ? MathUtility::forceIntegerInRange(count($itemArray) + 1, MathUtility::forceIntegerInRange($size, 1), $config['autoSizeMax']) : $size; $itemsToSelect = ''; $filterTextfield = ''; $filterSelectbox = ''; if (!$disabled) { // Create option tags: $opt = array(); $styleAttrValue = ''; foreach ($selItems as $p) { if ($config['iconsInOptionTags']) { $styleAttrValue = FormEngineUtility::optionTagStyle($p[2]); } $opt[] = '<option value="' . htmlspecialchars($p[1]) . '"' . ($styleAttrValue ? ' style="' . htmlspecialchars($styleAttrValue) . '"' : '') . ' title="' . $p[0] . '">' . $p[0] . '</option>'; } // Put together the selector box: $selector_itemListStyle = isset($config['itemListStyle']) ? ' style="' . htmlspecialchars($config['itemListStyle']) . '"' : ''; $sOnChange = implode('', $parameterArray['fieldChangeFunc']); $multiSelectId = str_replace('.', '', uniqid('tceforms-multiselect-', TRUE)); $itemsToSelect = ' <select data-relatedfieldname="' . htmlspecialchars($parameterArray['itemFormElName']) . '" data-exclusivevalues="' . htmlspecialchars($config['exclusiveKeys']) . '" id="' . $multiSelectId . '" name="' . htmlspecialchars($parameterArray['itemFormElName']) . '_sel" ' . ' class="form-control t3js-formengine-select-itemstoselect" ' . ($size ? ' size="' . $size . '"' : '') . ' onchange="' . htmlspecialchars($sOnChange) . '"' . $parameterArray['onFocus'] . $this->getValidationDataAsDataAttribute($config) . $selector_itemListStyle . '> ' . implode(' ', $opt) . ' </select>'; // enable filter functionality via a text field if ($config['enableMultiSelectFilterTextfield']) { $filterTextfield = ' <span class="input-group input-group-sm"> <span class="input-group-addon"> <span class="fa fa-filter"></span> </span> <input class="t3js-formengine-multiselect-filter-textfield form-control" value="" /> </span>'; } // enable filter functionality via a select if (isset($config['multiSelectFilterItems']) && is_array($config['multiSelectFilterItems']) && count($config['multiSelectFilterItems']) > 1) { $filterDropDownOptions = array(); foreach ($config['multiSelectFilterItems'] as $optionElement) { $optionValue = $languageService->sL(isset($optionElement[1]) && $optionElement[1] != '' ? $optionElement[1] : $optionElement[0]); $filterDropDownOptions[] = '<option value="' . htmlspecialchars($languageService->sL($optionElement[0])) . '">' . htmlspecialchars($optionValue) . '</option>'; } $filterSelectbox = '<select class="form-control input-sm t3js-formengine-multiselect-filter-dropdown"> ' . implode(' ', $filterDropDownOptions) . ' </select>'; } } if (!empty(trim($filterSelectbox)) && !empty(trim($filterTextfield))) { $filterSelectbox = '<div class="form-multigroup-item form-multigroup-element">' . $filterSelectbox . '</div>'; $filterTextfield = '<div class="form-multigroup-item form-multigroup-element">' . $filterTextfield . '</div>'; $selectBoxFilterContents = '<div class="t3js-formengine-multiselect-filter-container form-multigroup-wrap">' . $filterSelectbox . $filterTextfield . '</div>'; } else { $selectBoxFilterContents = trim($filterSelectbox . ' ' . $filterTextfield); } // Pass to "dbFileIcons" function: $params = array('size' => $size, 'autoSizeMax' => MathUtility::forceIntegerInRange($config['autoSizeMax'], 0), 'style' => isset($config['selectedListStyle']) ? ' style="' . htmlspecialchars($config['selectedListStyle']) . '"' : '', 'dontShowMoveIcons' => $maxitems <= 1, 'maxitems' => $maxitems, 'info' => '', 'headers' => array('selector' => $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.selected'), 'items' => $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.items'), 'selectorbox' => $selectBoxFilterContents), 'noBrowser' => 1, 'rightbox' => $itemsToSelect, 'readOnly' => $disabled); $item .= $this->dbFileIcons($parameterArray['itemFormElName'], '', '', $itemArray, '', $params, $parameterArray['onFocus']); return $item; }
/** * Creates a selectorbox list (renderMode = "singlebox") * * @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_singlebox($table, $field, $row, $parameterArray, $config, $selItems, $noMatchingLabel) { $languageService = $this->getLanguageService(); // 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'])); $item = ''; $disabled = ''; if ($this->isGlobalReadonly() || $config['readOnly']) { $disabled = ' disabled="disabled"'; } // Traverse the Array of selector box items: $opt = array(); // Used to accumulate the JS needed to restore the original selection. $restoreCmd = array(); $c = 0; foreach ($selItems as $p) { // Selected or not by default: $sM = ''; if (isset($itemArray[$p[1]])) { $sM = ' selected="selected"'; $restoreCmd[] = 'document.editform[' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName'] . '[]') . '].options[' . $c . '].selected=1;'; unset($itemArray[$p[1]]); } // Non-selectable element: $nonSel = ''; if ((string) $p[1] === '--div--') { $nonSel = ' onclick="this.selected=0;" class="formcontrol-select-divider"'; } // Icon style for option tag: $styleAttrValue = ''; if ($config['iconsInOptionTags']) { $styleAttrValue = FormEngineUtility::optionTagStyle($p[2]); } // Compile <option> tag: $opt[] = '<option value="' . htmlspecialchars($p[1]) . '"' . $sM . $nonSel . ($styleAttrValue ? ' style="' . htmlspecialchars($styleAttrValue) . '"' : '') . '>' . htmlspecialchars($p[0], ENT_COMPAT, 'UTF-8', FALSE) . '</option>'; $c++; } // Remaining values: if (!empty($itemArray) && !$parameterArray['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) { foreach ($itemArray as $theNoMatchValue => $temp) { // Compile <option> tag: array_unshift($opt, '<option value="' . htmlspecialchars($theNoMatchValue) . '" selected="selected">' . htmlspecialchars(@sprintf($noMatchingLabel, $theNoMatchValue), ENT_COMPAT, 'UTF-8', FALSE) . '</option>'); } } // Compile selector box: $sOnChange = implode('', $parameterArray['fieldChangeFunc']); $selector_itemListStyle = isset($config['itemListStyle']) ? ' style="' . htmlspecialchars($config['itemListStyle']) . '"' : ''; $size = (int) $config['size']; $cssPrefix = $size === 1 ? 'tceforms-select' : 'tceforms-multiselect'; $size = $config['autoSizeMax'] ? MathUtility::forceIntegerInRange(count($selItems) + 1, MathUtility::forceIntegerInRange($size, 1), $config['autoSizeMax']) : $size; $selectBox = '<select id="' . str_replace('.', '', uniqid($cssPrefix, TRUE)) . '" name="' . htmlspecialchars($parameterArray['itemFormElName']) . '[]" ' . 'class="form-control ' . $cssPrefix . '"' . ($size ? ' size="' . $size . '" ' : '') . ' multiple="multiple" onchange="' . htmlspecialchars($sOnChange) . '"' . $parameterArray['onFocus'] . ' ' . $this->getValidationDataAsDataAttribute($config) . $selector_itemListStyle . $disabled . '> ' . implode(' ', $opt) . ' </select>'; // Add an empty hidden field which will send a blank value if all items are unselected. if (!$disabled) { $item .= '<input type="hidden" name="' . htmlspecialchars($parameterArray['itemFormElName']) . '" value="" />'; } // Put it all into a table: $onClick = htmlspecialchars('document.editform[' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName'] . '[]') . '].selectedIndex=-1;' . implode('', $restoreCmd) . ' return false;'); $width = $this->formMaxWidth($this->defaultInputWidth); $item .= ' <div class="form-control-wrap" ' . ($width ? ' style="max-width: ' . $width . 'px"' : '') . '> <div class="form-wizards-wrap form-wizards-aside"> <div class="form-wizards-element"> ' . $selectBox . ' </div> <div class="form-wizards-items"> <a href="#" class="btn btn-default" onclick="' . $onClick . '" title="' . htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.revertSelection')) . '">' . IconUtility::getSpriteIcon('actions-edit-undo') . '</a> </div> </div> </div> <p> <em>' . htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.holdDownCTRL')) . '</em> </p> '; return $item; }
/** * 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->globalOptions['inlineFirstPid']); // Create option tags: $opt = array(); $styleAttrValue = ''; foreach ($selItems as $p) { if ($config['iconsInOptionTags']) { $styleAttrValue = FormEngineUtility::optionTagStyle($p[2]); } if (!in_array($p[1], $uniqueIds)) { $opt[] = '<option value="' . htmlspecialchars($p[1]) . '"' . ($styleAttrValue ? ' style="' . htmlspecialchars($styleAttrValue) . '"' : '') . '>' . 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 a 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) . '"> ' . IconUtility::getSpriteIcon('actions-document-new', array('title' => $createNewRelationText)) . $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; }