/** * Save the expanded/collapsed state of a child record in the BE_USER->uc. * * @param string $expand Whether this record is expanded. * @param string $collapse Whether this record is collapsed. * @return void */ protected function setInlineExpandedCollapsedState($expand, $collapse) { $backendUser = $this->getBackendUserAuthentication(); // The current table - for this table we should add/import records $currentTable = $this->inlineStackProcessor->getUnstableStructure(); $currentTable = $currentTable['table']; // The top parent table - this table embeds the current table $top = $this->inlineStackProcessor->getStructureLevel(0); $topTable = $top['table']; $topUid = $top['uid']; $inlineView = $this->getInlineExpandCollapseStateArray(); // Only do some action if the top record and the current record were saved before if (MathUtility::canBeInterpretedAsInteger($topUid)) { $expandUids = GeneralUtility::trimExplode(',', $expand); $collapseUids = GeneralUtility::trimExplode(',', $collapse); // Set records to be expanded foreach ($expandUids as $uid) { $inlineView[$topTable][$topUid][$currentTable][] = $uid; } // Set records to be collapsed foreach ($collapseUids as $uid) { $inlineView[$topTable][$topUid][$currentTable] = $this->removeFromArray($uid, $inlineView[$topTable][$topUid][$currentTable]); } // Save states back to database if (is_array($inlineView[$topTable][$topUid][$currentTable])) { $inlineView[$topTable][$topUid][$currentTable] = array_unique($inlineView[$topTable][$topUid][$currentTable]); $backendUser->uc['inlineView'] = serialize($inlineView); $backendUser->writeUC(); } } }
/** * Entry method * * @return array As defined in initializeResultArray() of AbstractNode * @throws AccessDeniedContentEditException */ public function render() { $this->inlineData = $this->data['inlineData']; /** @var InlineStackProcessor $inlineStackProcessor */ $inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class); $this->inlineStackProcessor = $inlineStackProcessor; $inlineStackProcessor->initializeByGivenStructure($this->data['inlineStructure']); $this->initHookObjects(); $parentUid = $this->data['inlineParentUid']; $record = $this->data['databaseRow']; $config = $this->data['inlineParentConfig']; $foreign_table = $config['foreign_table']; $foreign_selector = $config['foreign_selector']; $resultArray = $this->initializeResultArray(); // Send a mapping information to the browser via JSON: // e.g. data[<curTable>][<curId>][<curField>] => data-<pid>-<parentTable>-<parentId>-<parentField>-<curTable>-<curId>-<curField> $formPrefix = $inlineStackProcessor->getCurrentStructureFormPrefix(); $domObjectId = $inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($this->data['inlineFirstPid']); $this->inlineData['map'][$formPrefix] = $domObjectId; $resultArray['inlineData'] = $this->inlineData; // Set this variable if we handle a brand new unsaved record: $isNewRecord = !MathUtility::canBeInterpretedAsInteger($record['uid']); // Set this variable if the only the default language record and inline child has not been localized yet $isDefaultLanguageRecord = $this->data['inlineIsDefaultLanguage']; // If there is a selector field, normalize it: if ($foreign_selector) { $valueToNormalize = $record[$foreign_selector]; if (is_array($record[$foreign_selector])) { // @todo: this can be kicked again if always prepared rows are handled here $valueToNormalize = implode(',', $record[$foreign_selector]); } $record[$foreign_selector] = $this->normalizeUid($valueToNormalize); } // Get the current naming scheme for DOM name/id attributes: $appendFormFieldNames = '[' . $foreign_table . '][' . $record['uid'] . ']'; $objectId = $domObjectId . '-' . $foreign_table . '-' . $record['uid']; $class = ''; $html = ''; $combinationHtml = ''; if (!$isDefaultLanguageRecord) { // Get configuration: $collapseAll = isset($config['appearance']['collapseAll']) && $config['appearance']['collapseAll']; $expandAll = isset($config['appearance']['collapseAll']) && !$config['appearance']['collapseAll']; $ajaxLoad = !isset($config['appearance']['ajaxLoad']) || $config['appearance']['ajaxLoad']; if ($isNewRecord) { // Show this record expanded or collapsed $isExpanded = $expandAll || (!$collapseAll ? 1 : 0); } else { $isExpanded = $config['renderFieldsOnly'] || !$collapseAll && $this->getExpandedCollapsedState($foreign_table, $record['uid']) || $expandAll; } // Render full content ONLY IF this is an AJAX request, a new record, the record is not collapsed or AJAX loading is explicitly turned off if ($isNewRecord || $isExpanded || !$ajaxLoad) { $combinationHtml = ''; if (isset($this->data['combinationChild'])) { $combinationChild = $this->renderCombinationChild($this->data, $appendFormFieldNames); $combinationHtml = $combinationChild['html']; $combinationChild['html'] = ''; $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $combinationChild); } $childArray = $this->renderChild($this->data); $html = $childArray['html']; $childArray['html'] = ''; $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $childArray); } else { // This string is the marker for the JS-function to check if the full content has already been loaded $html = '<!--notloaded-->'; } if ($isNewRecord) { // Get the top parent table $top = $this->inlineStackProcessor->getStructureLevel(0); $ucFieldName = 'uc[inlineView][' . $top['table'] . '][' . $top['uid'] . ']' . $appendFormFieldNames; // Set additional fields for processing for saving $html .= '<input type="hidden" name="data' . $appendFormFieldNames . '[pid]" value="' . $record['pid'] . '"/>'; $html .= '<input type="hidden" name="' . $ucFieldName . '" value="' . $isExpanded . '" />'; } else { // Set additional field for processing for saving $html .= '<input type="hidden" name="cmd' . $appendFormFieldNames . '[delete]" value="1" disabled="disabled" />'; if (!$isExpanded && !empty($GLOBALS['TCA'][$foreign_table]['ctrl']['enablecolumns']['disabled']) && $ajaxLoad) { $checked = !empty($record['hidden']) ? ' checked="checked"' : ''; $html .= '<input type="checkbox" name="data' . $appendFormFieldNames . '[hidden]_0" value="1"' . $checked . ' />'; $html .= '<input type="input" name="data' . $appendFormFieldNames . '[hidden]" value="' . $record['hidden'] . '" />'; } } // If this record should be shown collapsed $class = $isExpanded ? 'panel-visible' : 'panel-collapsed'; } if ($config['renderFieldsOnly']) { $html = $html . $combinationHtml; } else { // Set the record container with data for output if ($isDefaultLanguageRecord) { $class .= ' t3-form-field-container-inline-placeHolder'; } if (isset($record['hidden']) && (int) $record['hidden']) { $class .= ' t3-form-field-container-inline-hidden'; } $class .= $isNewRecord ? ' inlineIsNewRecord' : ''; $html = ' <div class="panel panel-default panel-condensed ' . trim($class) . '" id="' . $objectId . '_div"> <div class="panel-heading" data-toggle="formengine-inline" id="' . $objectId . '_header" data-expandSingle="' . ($config['appearance']['expandSingle'] ? 1 : 0) . '"> <div class="form-irre-header"> <div class="form-irre-header-cell form-irre-header-icon"> <span class="caret"></span> </div> ' . $this->renderForeignRecordHeader($parentUid, $foreign_table, $this->data, $config, $isDefaultLanguageRecord) . ' </div> </div> <div class="panel-collapse" id="' . $objectId . '_fields" data-expandSingle="' . ($config['appearance']['expandSingle'] ? 1 : 0) . '" data-returnURL="' . htmlspecialchars(GeneralUtility::getIndpEnv('REQUEST_URI')) . '">' . $html . $combinationHtml . '</div> </div>'; } $resultArray['html'] = $html; return $resultArray; }
/** * Entry method * * @return array As defined in initializeResultArray() of AbstractNode */ public function render() { $this->inlineData = $this->globalOptions['inlineData']; /** @var InlineStackProcessor $inlineStackProcessor */ $inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class); $this->inlineStackProcessor = $inlineStackProcessor; $inlineStackProcessor->initializeByGivenStructure($this->globalOptions['inlineStructure']); $this->initHookObjects(); $row = $this->globalOptions['databaseRow']; $parentUid = $row['uid']; $record = $this->globalOptions['inlineRelatedRecordToRender']; $config = $this->globalOptions['inlineRelatedRecordConfig']; $foreign_table = $config['foreign_table']; $foreign_selector = $config['foreign_selector']; $resultArray = $this->initializeResultArray(); $html = ''; // Send a mapping information to the browser via JSON: // e.g. data[<curTable>][<curId>][<curField>] => data-<pid>-<parentTable>-<parentId>-<parentField>-<curTable>-<curId>-<curField> $formPrefix = $inlineStackProcessor->getCurrentStructureFormPrefix(); $domObjectId = $inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($this->globalOptions['inlineFirstPid']); $this->inlineData['map'][$formPrefix] = $domObjectId; $resultArray['inlineData'] = $this->inlineData; // Set this variable if we handle a brand new unsaved record: $isNewRecord = !MathUtility::canBeInterpretedAsInteger($record['uid']); // Set this variable if the record is virtual and only show with header and not editable fields: $isVirtualRecord = isset($record['__virtual']) && $record['__virtual']; // If there is a selector field, normalize it: if ($foreign_selector) { $record[$foreign_selector] = $this->normalizeUid($record[$foreign_selector]); } if (!$this->checkAccess($isNewRecord ? 'new' : 'edit', $foreign_table, $record['uid'])) { // @todo: Suddenly returning something different than the usual return array is not a cool thing ... // @todo: Inline ajax relies on this at the moment, though. return FALSE; } // Get the current naming scheme for DOM name/id attributes: $appendFormFieldNames = '[' . $foreign_table . '][' . $record['uid'] . ']'; $objectId = $domObjectId . '-' . $foreign_table . '-' . $record['uid']; $class = ''; $html = ''; $combinationHtml = ''; if (!$isVirtualRecord) { // Get configuration: $collapseAll = isset($config['appearance']['collapseAll']) && $config['appearance']['collapseAll']; $expandAll = isset($config['appearance']['collapseAll']) && !$config['appearance']['collapseAll']; $ajaxLoad = !isset($config['appearance']['ajaxLoad']) || $config['appearance']['ajaxLoad']; if ($isNewRecord) { // Show this record expanded or collapsed $isExpanded = $expandAll || (!$collapseAll ? 1 : 0); } else { $isExpanded = $config['renderFieldsOnly'] || !$collapseAll && $this->getExpandedCollapsedState($foreign_table, $record['uid']) || $expandAll; } // Render full content ONLY IF this is a AJAX-request, a new record, the record is not collapsed or AJAX-loading is explicitly turned off if ($isNewRecord || $isExpanded || !$ajaxLoad) { $combinationChildArray = $this->renderCombinationTable($record, $appendFormFieldNames, $config); $combinationHtml = $combinationChildArray['html']; $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $combinationChildArray); $overruleTypesArray = isset($config['foreign_types']) ? $config['foreign_types'] : array(); $childArray = $this->renderRecord($foreign_table, $record, $overruleTypesArray); $html = $childArray['html']; $childArray['html'] = ''; $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $childArray); // Replace returnUrl in Wizard-Code, if this is an AJAX call $ajaxArguments = GeneralUtility::_GP('ajax'); if (isset($ajaxArguments[2]) && trim($ajaxArguments[2]) != '') { $html = str_replace('P[returnUrl]=%2F' . rawurlencode(TYPO3_mainDir) . 'ajax.php', 'P[returnUrl]=' . rawurlencode($ajaxArguments[2]), $html); } } else { // This string is the marker for the JS-function to check if the full content has already been loaded $html = '<!--notloaded-->'; } if ($isNewRecord) { // Get the top parent table $top = $this->inlineStackProcessor->getStructureLevel(0); $ucFieldName = 'uc[inlineView][' . $top['table'] . '][' . $top['uid'] . ']' . $appendFormFieldNames; // Set additional fields for processing for saving $html .= '<input type="hidden" name="data' . $appendFormFieldNames . '[pid]" value="' . $record['pid'] . '"/>'; $html .= '<input type="hidden" name="' . $ucFieldName . '" value="' . $isExpanded . '" />'; } else { // Set additional field for processing for saving $html .= '<input type="hidden" name="cmd' . $appendFormFieldNames . '[delete]" value="1" disabled="disabled" />'; if (!$isExpanded && !empty($GLOBALS['TCA'][$foreign_table]['ctrl']['enablecolumns']['disabled']) && $ajaxLoad) { $checked = !empty($record['hidden']) ? ' checked="checked"' : ''; $html .= '<input type="checkbox" name="data' . $appendFormFieldNames . '[hidden]_0" value="1"' . $checked . ' />'; $html .= '<input type="input" name="data' . $appendFormFieldNames . '[hidden]" value="' . $record['hidden'] . '" />'; } } // If this record should be shown collapsed $class = $isExpanded ? 'panel-visible' : 'panel-collapsed'; } if ($config['renderFieldsOnly']) { $html = $html . $combinationHtml; } else { // Set the record container with data for output if ($isVirtualRecord) { $class .= ' t3-form-field-container-inline-placeHolder'; } if (isset($record['hidden']) && (int) $record['hidden']) { $class .= ' t3-form-field-container-inline-hidden'; } $class .= $isNewRecord ? ' inlineIsNewRecord' : ''; $html = ' <div class="panel panel-default panel-condensed ' . trim($class) . '" id="' . $objectId . '_div"> <div class="panel-heading" data-toggle="formengine-inline" id="' . $objectId . '_header" data-expandSingle="' . ($config['appearance']['expandSingle'] ? 1 : 0) . '"> <div class="form-irre-header"> <div class="form-irre-header-cell form-irre-header-icon"> <span class="caret"></span> </div> ' . $this->renderForeignRecordHeader($parentUid, $foreign_table, $record, $config, $isVirtualRecord) . ' </div> </div> <div class="panel-collapse" id="' . $objectId . '_fields" data-expandSingle="' . ($config['appearance']['expandSingle'] ? 1 : 0) . '" data-returnURL="' . htmlspecialchars(GeneralUtility::getIndpEnv('REQUEST_URI')) . '">' . $html . $combinationHtml . '</div> </div>'; } $resultArray['html'] = $html; return $resultArray; }