diff --git a/ChangeLog b/ChangeLog index b4730c8..581feb1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,5 @@ +7.1.0 > See https://forge.typo3.org/projects/extension-gridelements2/repository/show?rev=7-0 + 7.0.5 > 2016-01-29 Jo Hasenau Done: Task #60220 Escaped variables in SQL queries Added: Feature #47294 Make PAGE_TSCONFIG_ID aware of CSV lists of IDs diff --git a/Classes/Backend/ClickMenuOptions.php b/Classes/Backend/ClickMenuOptions.php index fabf61a..0eaed08 100644 --- a/Classes/Backend/ClickMenuOptions.php +++ b/Classes/Backend/ClickMenuOptions.php @@ -37,7 +37,6 @@ */ class ClickMenuOptions implements SingletonInterface { - /** * @var LanguageService */ @@ -51,41 +50,36 @@ class ClickMenuOptions implements SingletonInterface /** * Main method * - * @param CLickMenu $backRef + * @param ClickMenu $backRef * @param array $menuItems * @param string $table * @param int $uid * * @return array */ - public function main($backRef, array $menuItems, $table = '', $uid = 0) + public function main(ClickMenu $backRef, array $menuItems, $table = '', $uid = 0) { + if ($table !== 'tt_content') { + return $menuItems; + } - if ($table === 'tt_content') { - $this->setLanguageService($GLOBALS['LANG']); + $this->setLanguageService($GLOBALS['LANG']); - // add "paste reference after" if user is allowed to use CType shortcut - if ($this->getBackendUser()->checkAuthMode('tt_content', 'CType', 'shortcut', $GLOBALS['TYPO3_CONF_VARS']['BE']['explicitADmode'])) { - if ($menuItems['pasteafter']) { - unset($menuItems['pasteafter']); - $selItem = $backRef->clipObj->getSelectedRecord(); - $targetItem = BackendUtility::getRecordRaw('tt_content', 'uid = ' . $uid, - 'colPos,tx_gridelements_container,tx_gridelements_columns'); - $elInfo = array( - GeneralUtility::fixed_lgd_cs($selItem['_RECORD_TITLE'], - $this->getBackendUser()->uc['titleLen']), - $backRef->root ? $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] : GeneralUtility::fixed_lgd_cs(BackendUtility::getRecordTitle($table, - $backRef->rec), $this->getBackendUser()->uc['titleLen']), - $backRef->clipObj->currentMode() - ); - $menuItems['pasteafter'] = $this->DB_paste($backRef, $table, -$uid, 'after', $elInfo, $targetItem, - false); - if ($backRef->clipObj->currentMode() === 'copy') { - $menuItems['pastereference'] = $this->DB_paste($backRef, $table, -$uid, 'after', $elInfo, - $targetItem, true); - } - } + // add "paste reference after" if user is allowed to use CType shortcut + if ($menuItems['pasteafter'] && $this->getBackendUser()->checkAuthMode('tt_content', 'CType', 'shortcut', $GLOBALS['TYPO3_CONF_VARS']['BE']['explicitADmode'])) { + unset($menuItems['pasteafter']); + $selItem = $backRef->clipObj->getSelectedRecord(); + $targetItem = BackendUtility::getRecordRaw('tt_content', 'uid = ' . $uid, 'colPos,tx_gridelements_container,tx_gridelements_columns'); + $elInfo = array( + GeneralUtility::fixed_lgd_cs($selItem['_RECORD_TITLE'], $this->getBackendUser()->uc['titleLen']), + GeneralUtility::fixed_lgd_cs(BackendUtility::getRecordTitle($table, $backRef->rec), $this->getBackendUser()->uc['titleLen']), + $backRef->clipObj->currentMode() + ); + $menuItems['pasteafter'] = $this->DB_paste($backRef, $table, -$uid, 'after', $elInfo, $targetItem, false); + if ($backRef->clipObj->currentMode() === 'copy') { + $menuItems['pastereference'] = $this->DB_paste($backRef, $table, -$uid, 'after', $elInfo, $targetItem, true); } + } return $menuItems; @@ -95,42 +89,49 @@ public function main($backRef, array $menuItems, $table = '', $uid = 0) * Adding CM element for Clipboard "paste into"/"paste after" * NOTICE: $table and $uid should follow the special syntax for paste, see clipboard-class :: pasteUrl(); * - * @param CLickMenu $backRef + * @param ClickMenu $backRef * @param string $table Table name * @param int $uid UID for the current record. NOTICE: Special syntax! - * @param string $type Type: "into" or "after + * @param string $type Type "into" or "after * @param array $elInfo Contains instructions about whether to copy or cut an element. * @param array $targetItem * @param bool $reference * * @return array Item array, element in $menuItems */ - public function DB_paste(&$backRef, $table, $uid, $type, $elInfo, $targetItem, $reference) + public function DB_paste(ClickMenu $backRef, $table, $uid, $type, array $elInfo, array $targetItem, $reference) { $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class); $updateArray = array( 'colPos' => $targetItem['colPos'], - 'tx_gridelements_container' => $targetItem['tx_gridelements_container'], - 'tx_gridelements_columns' => $targetItem['tx_gridelements_columns'] + 'tx_gridelements_container' => (int)$targetItem['tx_gridelements_container'], + 'tx_gridelements_columns' => (int)$targetItem['tx_gridelements_columns'] ); $loc = 'top.content.list_frame'; if ($this->getBackendUser()->jsConfirmation(JsConfirmation::COPY_MOVE_PASTE)) { - $conf = $loc . ' && confirm(' . GeneralUtility::quoteJSvalue(sprintf($this->getLanguageService()->sL(('LLL:EXT:lang/locallang_core.xlf:mess.' . ($elInfo[2] === 'copy' ? 'copy' : 'move') . '_' . $type)), - $elInfo[0], $elInfo[1])) . ')'; + $conf = $loc . ' && confirm(' . GeneralUtility::quoteJSvalue( + sprintf($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:mess.' . ($elInfo[2] === 'copy' ? 'copy' : 'move') . '_' . $type), $elInfo[0], $elInfo[1]) + ) . ')'; } else { $conf = $loc; } - $editOnClick = 'if(' . $conf . '){' . $loc . '.location.href=' . GeneralUtility::quoteJSvalue($backRef->clipObj->pasteUrl($table, - $uid, 0, - $updateArray) . ($reference ? '&reference=1' : '') . '&redirect=') . '+top.rawurlencode(' . $backRef->frameLocation(($loc . '.document')) . '.pathname+' . $backRef->frameLocation(($loc . '.document')) . '.search);}'; + $editOnClick = 'if(' . $conf . '){' . $loc . '.location.href=' + . GeneralUtility::quoteJSvalue($backRef->clipObj->pasteUrl($table, $uid, 0, $updateArray) + . ($reference ? '&reference=1' : '') . '&redirect=') . '+top.rawurlencode(' + . $backRef->frameLocation(($loc . '.document')) . '.pathname+' + . $backRef->frameLocation(($loc . '.document')) . '.search);}'; - return $backRef->linkItem($reference ? $this->getLanguageService()->sL('LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:tx_gridelements_clickmenu_pastereference') : $backRef->label('paste' . $type), + return $backRef->linkItem( + $reference + ? $this->getLanguageService()->sL('LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:tx_gridelements_ClickMenu_pastereference') + : $backRef->label('paste' . $type), $this->iconFactory->getIcon('actions-document-paste-' . $type, Icon::SIZE_SMALL)->render(), - $editOnClick . 'return false;'); + $editOnClick . 'return false;' + ); } /** - * Gets the current backend user. + * Gets the current backend user * * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication */ @@ -153,12 +154,9 @@ public function getLanguageService() * setter for databaseConnection object * * @param LanguageService $languageService - * - * @return void */ public function setLanguageService(LanguageService $languageService) { $this->languageService = $languageService; } - } diff --git a/Classes/Backend/ItemsProcFuncs/AbstractItemsProcFunc.php b/Classes/Backend/ItemsProcFuncs/AbstractItemsProcFunc.php index d8afb17..26d0fea 100644 --- a/Classes/Backend/ItemsProcFuncs/AbstractItemsProcFunc.php +++ b/Classes/Backend/ItemsProcFuncs/AbstractItemsProcFunc.php @@ -20,11 +20,11 @@ * This copyright notice MUST APPEAR in all copies of the script! ***************************************************************/ +use GridElementsTeam\Gridelements\Helper\Helper; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Database\DatabaseConnection; use TYPO3\CMS\Core\Database\QueryGenerator; use TYPO3\CMS\Core\SingletonInterface; -use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Lang\LanguageService; /** @@ -36,7 +36,6 @@ */ abstract class AbstractItemsProcFunc implements SingletonInterface { - /** * @var DatabaseConnection */ @@ -52,11 +51,6 @@ abstract class AbstractItemsProcFunc implements SingletonInterface */ protected $tree; - /** - * @var string - */ - protected $backPath = ''; - /** * initializes this class * @@ -71,38 +65,19 @@ public function init($pageUid = 0) /** * Gets the selected backend layout * - * @param int $id : The uid of the page we are currently working on + * @param int $id The uid of the page we are currently working on * - * @return array|null $backendLayout : An array containing the data of the selected backend layout as well as a parsed version of the layout configuration + * @return array|null An array containing the data of the selected backend layout as well as a parsed version of the layout configuration */ public function getSelectedBackendLayout($id) { - $backendLayoutData = GeneralUtility::callUserFunction('TYPO3\\CMS\\Backend\\View\\BackendLayoutView->getSelectedBackendLayout', - $id, $this); - // add allowed CTypes to the columns, since this is not done by the native core methods - if (count($backendLayoutData['__items']) > 0) { - if (!empty($backendLayoutData['__config']['backend_layout.']['rows.'])) { - foreach ($backendLayoutData['__config']['backend_layout.']['rows.'] as $row) { - if (!empty($row['columns.'])) { - foreach ($row['columns.'] as $column) { - $backendLayoutData['columns'][$column['colPos']] = $column['allowed'] ? $column['allowed'] : '*'; - $backendLayoutData['columns']['allowed'] .= $backendLayoutData['columns']['allowed'] ? ',' . $backendLayoutData['columns'][$column['colPos']] : $backendLayoutData['columns'][$column['colPos']]; - } - } - } - } - foreach ($backendLayoutData['__items'] as $key => $item) { - $backendLayoutData['__items'][$key][3] = $backendLayoutData['columns'][$item[1]]; - } - }; - - return $backendLayoutData; + return Helper::getInstance()->getSelectedBackendLayout($id); } /** * This method is a wrapper for unitTests because of the static method * - * @param $pageUid + * @param int $pageUid * * @return array */ diff --git a/Classes/Backend/ItemsProcFuncs/CTypeList.php b/Classes/Backend/ItemsProcFuncs/CTypeList.php index 1189789..385cc22 100644 --- a/Classes/Backend/ItemsProcFuncs/CTypeList.php +++ b/Classes/Backend/ItemsProcFuncs/CTypeList.php @@ -20,7 +20,7 @@ ***************************************************************/ use GridElementsTeam\Gridelements\Backend\LayoutSetup; -use GridElementsTeam\Gridelements\Helper\Helper; +use TYPO3\CMS\Core\Database\DatabaseConnection; use TYPO3\CMS\Core\Utility\GeneralUtility; /** @@ -46,7 +46,7 @@ class CTypeList extends AbstractItemsProcFunc /** * injects layout setup * - * @param \GridElementsTeam\Gridelements\Backend\LayoutSetup $layoutSetup + * @param LayoutSetup $layoutSetup */ public function injectLayoutSetup(LayoutSetup $layoutSetup) { @@ -54,26 +54,34 @@ public function injectLayoutSetup(LayoutSetup $layoutSetup) } /** - * ItemProcFunc for CType items + * initializes this class * - * @param array $params : The array of parameters that is used to render the item list + * @param int $pageUid + */ + public function init($pageUid = 0) + { + parent::init(); + if (!$this->layoutSetup) { + $this->injectLayoutSetup(GeneralUtility::makeInstance(LayoutSetup::class)->init($pageUid)); + } + } + + /** + * ItemProcFunc for CType items * - * @return void + * @param array $params The array of parameters that is used to render the item list */ - public function itemsProcFunc(&$params) + public function itemsProcFunc(array &$params) { if ((int)$params['row']['pid'] > 0) { - $this->checkForAllowedCTypes($params['items'], $params['row']['pid'], $params['row']['colPos'], - $params['row']['tx_gridelements_container'], $params['row']['tx_gridelements_columns']); + $this->checkForAllowedCTypes($params['items'], $params['row']['pid'], $params['row']['colPos'], $params['row']['tx_gridelements_container'], $params['row']['tx_gridelements_columns']); } else { $this->init((int)$params['row']['pid']); // negative uid_pid values indicate that the element has been inserted after an existing element // so there is no pid to get the backendLayout for and we have to get that first - $existingElement = $this->databaseConnection->exec_SELECTgetSingleRow('pid, CType, colPos, tx_gridelements_container, tx_gridelements_columns', - 'tt_content', 'uid=' . -((int)$params['row']['pid'])); + $existingElement = $this->databaseConnection->exec_SELECTgetSingleRow('pid, CType, colPos, tx_gridelements_container, tx_gridelements_columns', 'tt_content', 'uid=' . -((int)$params['row']['pid'])); if ((int)$existingElement['pid'] > 0) { - $this->checkForAllowedCTypes($params['items'], $existingElement['pid'], $existingElement['colPos'], - $existingElement['tx_gridelements_container'], $existingElement['tx_gridelements_columns']); + $this->checkForAllowedCTypes($params['items'], $existingElement['pid'], $existingElement['colPos'], $existingElement['tx_gridelements_container'], $existingElement['tx_gridelements_columns']); } } } @@ -81,49 +89,29 @@ public function itemsProcFunc(&$params) /** * Checks if a CType is allowed in this particular page or grid column - only this one column defines the allowed CTypes regardless of any parent column * - * @param array $items : The items of the current CType list - * @param integer $pid : The id of the page we are currhently working on - * @param integer $pageColumn : The page column the element is a child of - * @param integer $gridContainerId : The ID of the current container - * @param integer $gridColumn : The grid column the element is a child of - * - * @return array|null $backendLayout: An array containing the data of the selected backend layout as well as a parsed version of the layout configuration + * @param array $items The items of the current CType list + * @param int $pid The id of the page we are currently working on + * @param int $pageColumn The page column the element is a child of + * @param int $gridContainerId The ID of the current container + * @param int $gridColumn The grid column the element is a child of */ - public function checkForAllowedCTypes(&$items, $pid, $pageColumn, $gridContainerId, $gridColumn) + public function checkForAllowedCTypes(array &$items, $pid, $pageColumn, $gridContainerId, $gridColumn) { if ((int)$pageColumn >= 0 || (int)$pageColumn === -2) { $column = $pageColumn ? $pageColumn : 0; $backendLayout = $this->getSelectedBackendLayout($pid); } else { $this->init($pid); - $column = $gridColumn ? $gridColumn : 0; + $column = $gridColumn ? (int)$gridColumn : 0; $gridElement = $this->layoutSetup->cacheCurrentParent($gridContainerId, true); $backendLayout = $this->layoutSetup->getLayoutSetup($gridElement['tx_gridelements_backend_layout']); } if (isset($backendLayout)) { foreach ($items as $key => $item) { - if (!(GeneralUtility::inList($backendLayout['columns'][$column], - $item[1]) || GeneralUtility::inList($backendLayout['columns'][$column], '*')) - ) { + if (!GeneralUtility::inList($backendLayout['columns'][$column], $item[1]) && !GeneralUtility::inList($backendLayout['columns'][$column], '*')) { unset($items[$key]); } } } } - - /** - * initializes this class - * - * @param int $pageUid - */ - public function init($pageUid = 0) - { - parent::init(); - if (!$this->layoutSetup instanceof LayoutSetup) { - if ($pageUid < 0) { - $pageUid = Helper::getInstance()->getPidFromNegativeUid($pageUid); - } - $this->injectLayoutSetup(GeneralUtility::makeInstance(LayoutSetup::class)->init($pageUid)); - } - } } diff --git a/Classes/Backend/ItemsProcFuncs/ColPosList.php b/Classes/Backend/ItemsProcFuncs/ColPosList.php index 4f6fe0a..52672a5 100644 --- a/Classes/Backend/ItemsProcFuncs/ColPosList.php +++ b/Classes/Backend/ItemsProcFuncs/ColPosList.php @@ -30,29 +30,23 @@ */ class ColPosList extends AbstractItemsProcFunc { - /** * ItemProcFunc for colpos items * - * @param array $params : The array of parameters that is used to render the item list - * - * @return void + * @param array $params The array of parameters that is used to render the item list */ - public function itemsProcFunc(&$params) + public function itemsProcFunc(array &$params) { - parent::init(); + $this->init(); if ($params['row']['pid'] > 0) { $ContentType = is_array($params['row']['CType']) ? $params['row']['CType'][0] : $params['row']['CType']; - $params['items'] = $this->addColPosListLayoutItems($params['row']['pid'], $params['items'], $ContentType, - $params['row']['tx_gridelements_container']); + $params['items'] = $this->addColPosListLayoutItems($params['row']['pid'], $params['items'], $ContentType, $params['row']['tx_gridelements_container']); } else { // negative uid_pid values indicate that the element has been inserted after an existing element // so there is no pid to get the backendLayout for and we have to get that first - $existingElement = $this->databaseConnection->exec_SELECTgetSingleRow('pid, CType, tx_gridelements_container', 'tt_content', - 'uid=' . -((int)$params['row']['pid'])); + $existingElement = $this->databaseConnection->exec_SELECTgetSingleRow('pid, CType, tx_gridelements_container', 'tt_content', 'uid=' . -((int)$params['row']['pid'])); if ($existingElement['pid'] > 0) { - $params['items'] = $this->addColPosListLayoutItems($existingElement['pid'], $params['items'], - $existingElement['CType'], $existingElement['tx_gridelements_container']); + $params['items'] = $this->addColPosListLayoutItems($existingElement['pid'], $params['items'], $existingElement['CType'], $existingElement['tx_gridelements_container']); } } } @@ -60,12 +54,12 @@ public function itemsProcFunc(&$params) /** * Adds items to a colpos list * - * @param integer $pageId : The uid of the page we are currently working on - * @param array $items : The array of items before the action - * @param string $CType : The content type of the item holding the colPosList - * @param integer $container + * @param int $pageId The uid of the page we are currently working on + * @param array $items The array of items before the action + * @param string $CType The content type of the item holding the colPosList + * @param int $container * - * @return array $items: The ready made array of items + * @return array $items The ready made array of items */ protected function addColPosListLayoutItems($pageId, array $items, $CType = '', $container = 0) { @@ -75,9 +69,7 @@ protected function addColPosListLayoutItems($pageId, array $items, $CType = '', if ($layout) { if ($CType !== '' && !empty($layout['__items'])) { foreach ($layout['__items'] as $itemKey => $itemArray) { - if ($itemArray[3] !== '' && !GeneralUtility::inList($itemArray[3], - $CType) && !GeneralUtility::inList($itemArray[3], '*') - ) { + if ($itemArray[3] !== '' && !GeneralUtility::inList($itemArray[3], $CType) && !GeneralUtility::inList($itemArray[3], '*')) { unset($layout['__items'][$itemKey]); } } @@ -98,5 +90,4 @@ protected function addColPosListLayoutItems($pageId, array $items, $CType = '', return $items; } - } diff --git a/Classes/Backend/ItemsProcFuncs/SysLanguageUidList.php b/Classes/Backend/ItemsProcFuncs/SysLanguageUidList.php index f7dbf38..c2a5fa8 100644 --- a/Classes/Backend/ItemsProcFuncs/SysLanguageUidList.php +++ b/Classes/Backend/ItemsProcFuncs/SysLanguageUidList.php @@ -30,17 +30,14 @@ */ class SysLanguageUidList extends AbstractItemsProcFunc { - /** * ItemProcFunc for CType items * - * @param array $params : The array of parameters that is used to render the item list - * - * @return void + * @param array $params The array of parameters that is used to render the item list */ - public function itemsProcFunc(&$params) + public function itemsProcFunc(array &$params) { - if ((int)$params['row']['pid'] > 0 && (int)$params['row']['tx_gridelements_container'] > 0) { + if ((int)$params['row']['pid'] > 0 && (int)$params['row']['tx_gridelements_container'] > 0 && isset($params['items'])) { $this->checkForAllowedLanguages($params['items'], $params['row']['tx_gridelements_container']); } } @@ -48,22 +45,21 @@ public function itemsProcFunc(&$params) /** * Checks if a language is allowed in this particular container - only this one container defines the allowed languages regardless of any parent * - * @param array $items : The items of the current language list - * @param integer $gridContainerId : The ID of the current container - * - * @return void + * @param array $items The items of the current language list + * @param int $gridContainerId The ID of the current container */ - public function checkForAllowedLanguages(&$items, $gridContainerId) + public function checkForAllowedLanguages(array &$items, $gridContainerId) { - if ((int)$gridContainerId > 0) { - $parentContainer = BackendUtility::getRecordWSOL('tt_content', $gridContainerId); - if (is_array($items) && !empty($items) && (int)$parentContainer['uid'] > 0) { - foreach ($items as $item => $valueArray) { - if ((int)$parentContainer['sys_language_uid'] > -1 && (int)$valueArray[1] !== (int)$parentContainer['sys_language_uid']) { - unset($items[$item]); - } - } - }; + if (!$gridContainerId) { + return; } + $parentContainer = BackendUtility::getRecordWSOL('tt_content', $gridContainerId); + if (!empty($items) && (int)$parentContainer['uid'] > 0) { + foreach ($items as $item => $valueArray) { + if ((int)$parentContainer['sys_language_uid'] > -1 && (int)$valueArray[1] !== (int)$parentContainer['sys_language_uid']) { + unset($items[$item]); + } + } + }; } } diff --git a/Classes/Backend/LayoutSetup.php b/Classes/Backend/LayoutSetup.php index b9eff50..852b678 100644 --- a/Classes/Backend/LayoutSetup.php +++ b/Classes/Backend/LayoutSetup.php @@ -24,8 +24,8 @@ use TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser; use TYPO3\CMS\Core\Utility\ArrayUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; -use TYPO3\CMS\Core\Utility\StringUtility; use TYPO3\CMS\Lang\LanguageService; +use GridElementsTeam\Gridelements\Helper\Helper; /** * Utilities for gridelements. @@ -36,7 +36,6 @@ */ class LayoutSetup { - /** * @var DatabaseConnection */ @@ -57,6 +56,11 @@ class LayoutSetup */ protected $typoScriptSetup; + /** + * @var int + */ + protected $realPid; + /** * @var string */ @@ -65,16 +69,20 @@ class LayoutSetup /** * Load page TSconfig * - * @param integer $pageId : The current page ID - * @param array $typoScriptSetup : The PlugIn configuration + * @param int $pageId The current page ID + * @param array $typoScriptSetup The PlugIn configuration * - * @return \GridElementsTeam\Gridelements\Backend\LayoutSetup + * @return LayoutSetup */ - public function init($pageId, $typoScriptSetup = array()) + public function init($pageId, array $typoScriptSetup = array()) { $this->setDatabaseConnection($GLOBALS['TYPO3_DB']); $this->setLanguageService($GLOBALS['LANG']); $pageId = (strpos($pageId, 'NEW') === 0) ? 0 : (int)$pageId; + if ((int)$pageId < 0) { + $pageId = Helper::getInstance()->getPidFromUid($pageId); + } + $this->realPid = $pageId; $this->loadLayoutSetup($pageId); foreach ($this->layoutSetup as $key => $setup) { $columns = $this->getLayoutColumns($key); @@ -93,7 +101,7 @@ public function init($pageId, $typoScriptSetup = array()) * * @param array $layoutSetup */ - public function setLayoutSetup($layoutSetup) + public function setLayoutSetup(array $layoutSetup) { $this->layoutSetup = $layoutSetup; } @@ -103,15 +111,15 @@ public function setLayoutSetup($layoutSetup) * * @param array $typoScriptSetup */ - public function setTypoScriptSetup($typoScriptSetup) + public function setTypoScriptSetup(array $typoScriptSetup) { $this->typoScriptSetup = $typoScriptSetup; } /** - * Returns the grid layout setup. + * Returns the grid layout setup * - * @param string $layoutId : If set only requested layout setup, else all layout setups will be returned. + * @param string $layoutId If set only requested layout setup, else all layout setups will be returned. * * @return array */ @@ -120,19 +128,18 @@ public function getLayoutSetup($layoutId = '') // Continue only if setup for given layout ID found. if (isset($this->layoutSetup[$layoutId])) { return $this->layoutSetup[$layoutId]; - } else { - return $this->layoutSetup; } + + return $this->layoutSetup; } /** * fetches the setup for each of the columns * assigns a default setup if there is none available * - * @param string $layoutId : The selected backend layout of the grid container + * @param string $layoutId The selected backend layout of the grid container * - * @return array $setup: The adjusted TypoScript setup for the container or a default setup - * @author Jo Hasenau + * @return array The adjusted TypoScript setup for the container or a default setup */ public function getTypoScriptSetup($layoutId) { @@ -140,9 +147,9 @@ public function getTypoScriptSetup($layoutId) if ($layoutId == '0' && isset($this->typoScriptSetup['setup.']['default.'])) { $typoScriptSetup = $this->typoScriptSetup['setup.']['default.']; - } else if ($layoutId && isset($this->typoScriptSetup['setup.'][$layoutId . '.'])) { + } elseif ($layoutId && isset($this->typoScriptSetup['setup.'][$layoutId . '.'])) { $typoScriptSetup = $this->typoScriptSetup['setup.'][$layoutId . '.']; - } else if ($layoutId) { + } elseif ($layoutId) { $typoScriptSetup = $this->typoScriptSetup['setup.']['default.']; } @@ -183,14 +190,13 @@ public function getFlexformConfigurationPathAndFileName() * @param int $gridContainerId The ID of the current grid container * @param bool $doReturn * - * @return NULL | array + * @return null|array */ public function cacheCurrentParent($gridContainerId = 0, $doReturn = false) { if ($gridContainerId > 0) { if (empty($GLOBALS['tx_gridelements']['parentElement'][$gridContainerId])) { - $GLOBALS['tx_gridelements']['parentElement'][$gridContainerId] = BackendUtility::getRecordWSOL('tt_content', - $gridContainerId); + $GLOBALS['tx_gridelements']['parentElement'][$gridContainerId] = BackendUtility::getRecordWSOL('tt_content', $gridContainerId); } } if ($doReturn) { @@ -203,39 +209,41 @@ public function cacheCurrentParent($gridContainerId = 0, $doReturn = false) /** * fetches all available columns for a certain grid container * - * @param string $layoutId : The selected backend layout of the grid container + * @param string $layoutId The selected backend layout of the grid container * - * @return array $availableColumns: first key is 'CSV' The columns available for the selected layout as CSV list and the allowed elements for each of the columns + * @return array first key is 'CSV' The columns available for the selected layout as CSV list and the allowed elements for each of the columns */ public function getLayoutColumns($layoutId) { - $availableColumns = array(); - if (isset($this->layoutSetup[$layoutId])) { + if (!isset($this->layoutSetup[$layoutId])) { + return []; + } - $availableColumns['CSV'] = '-2,-1'; - $setup = $this->layoutSetup[$layoutId]; - - if (isset($setup['config']) && $setup['config']) { - - // create colPosList - if ($setup['config']['rows.']) { - foreach ($setup['config']['rows.'] as $row) { - if (isset($row['columns.']) && is_array($row['columns.'])) { - foreach ($row['columns.'] as $column) { - if (isset($column['colPos'])) { - $colPos = (int)$column['colPos']; - $availableColumns['CSV'] .= ',' . $colPos; - $availableColumns[$colPos] = $column['allowed'] ? $column['allowed'] : '*'; - if ($column['allowedGridTypes']) { - $availableGridColumns[$colPos] = $column['allowedGridTypes']; - } - $availableColumns['allowed'] .= $availableColumns['allowed'] ? ',' . $availableColumns[$colPos] : $availableColumns[$colPos]; - if ($availableGridColumns[$colPos]) { - $availableColumns['allowedGridTypes'] .= $availableColumns['allowedGridTypes'] ? ',' . $availableGridColumns[$colPos] : $availableGridColumns[$colPos]; - } - } - } - } + // create colPosList + $availableColumns = ['CSV' => '-2,-1']; + if (!empty($this->layoutSetup[$layoutId]['config']['rows.'])) { + foreach ($this->layoutSetup[$layoutId]['config']['rows.'] as $row) { + if (!isset($row['columns.']) || !is_array($row['columns.'])) { + continue; + } + foreach ($row['columns.'] as $column) { + if (!isset($column['colPos'])) { + continue; + } + $colPos = (int)$column['colPos']; + $availableColumns['CSV'] .= ',' . $colPos; + $availableColumns[$colPos] = $column['allowed'] ? $column['allowed'] : '*'; + $availableGridColumns = []; + if ($column['allowedGridTypes']) { + $availableGridColumns[$colPos] = $column['allowedGridTypes']; + } + $availableColumns['allowed'] .= $availableColumns['allowed'] + ? ',' . $availableColumns[$colPos] + : $availableColumns[$colPos]; + if (!empty($availableGridColumns[$colPos])) { + $availableColumns['allowedGridTypes'][$colPos] .= $availableColumns['allowedGridTypes'][$colPos] + ? ',' . $availableGridColumns[$colPos] + : $availableGridColumns[$colPos]; } } } @@ -247,15 +255,43 @@ public function getLayoutColumns($layoutId) /** * Returns the item array for form field selection. * - * @param integer $colPos : The selected content column position. + * @param int $colPos The selected content column position. + * @param int $gridColPos + * @param int $containerId + * @param int $pageId * * @return array */ - public function getLayoutSelectItems($colPos) + public function getLayoutSelectItems($colPos, $gridColPos = 0, $containerId = 0, $pageId = 0) { + $allowed = '*'; $selectItems = array(); + if ($containerId > 0) { + $container = $this->cacheCurrentParent((int)$containerId, true); + if (!empty($container)) { + $containerLayout = $this->layoutSetup[$container['tx_gridelements_backend_layout']]; + $allowed = $containerLayout['columns']['allowedGridTypes'][$gridColPos]; + } + } elseif ($pageId > 0) { + $pageLayout = Helper::getInstance()->getSelectedBackendLayout($pageId); + if (!empty($pageLayout)) { + $allowed = $pageLayout['columns']['allowedGridTypes'][(int)$colPos]; + } + } + + if (!empty($allowed)) { + $allowed = array_flip(GeneralUtility::trimExplode(',', $allowed)); + } foreach ($this->layoutSetup as $layoutId => $item) { - if ((int)$colPos === -1 && $item['top_level_layout']) { + if (( + (int)$colPos === -1 && + $item['top_level_layout'] + ) || + ( + !empty($allowed) && + !isset($allowed['*']) && + !isset($allowed[$layoutId]) + )) { continue; } $icon = 'gridelements-default'; @@ -267,9 +303,6 @@ public function getLayoutSelectItems($colPos) } else { $icon = $item['icon']; } - if (!StringUtility::beginsWith($icon, '../')) { - $icon = '../' . $icon; - } } $selectItems[] = array($this->languageService->sL($item['title']), $layoutId, $icon); } @@ -278,7 +311,7 @@ public function getLayoutSelectItems($colPos) } /** - * Returns the item array for form field selection. + * Returns the item array for form field selection * * @param string $layoutId : The selected layout ID of the grid container * @@ -286,21 +319,23 @@ public function getLayoutSelectItems($colPos) */ public function getLayoutColumnsSelectItems($layoutId) { - $selectItems = array(); $setup = $this->getLayoutSetup($layoutId); + if (empty($setup['config']['rows.'])) { + return []; + } - if ($setup['config']['rows.']) { - foreach ($setup['config']['rows.'] as $row) { - if (isset($row['columns.']) && is_array($row['columns.'])) { - foreach ($row['columns.'] as $column) { - $selectItems[] = array( - $this->languageService->sL($column['name']), - $column['colPos'], - null, - $column['allowed'] ? $column['allowed'] : '*' - ); - } - } + $selectItems = []; + foreach ($setup['config']['rows.'] as $row) { + if (empty($row['columns.'])) { + continue; + } + foreach ($row['columns.'] as $column) { + $selectItems[] = array( + $this->languageService->sL($column['name']), + $column['colPos'], + null, + $column['allowed'] ? $column['allowed'] : '*' + ); } } @@ -308,15 +343,15 @@ public function getLayoutColumnsSelectItems($layoutId) } /** - * Returns the item array for form field selection. + * Returns the item array for form field selection * * @param int $colPos - * @param array $excludeLayouts + * @param string $excludeLayouts * @param array $allowedGridTypes * * @return array */ - public function getLayoutWizardItems($colPos, $excludeLayouts = array(), $allowedGridTypes = array()) + public function getLayoutWizardItems($colPos, $excludeLayouts = '', array $allowedGridTypes = array()) { $wizardItems = array(); $excludeLayouts = array_flip(explode(',', $excludeLayouts)); @@ -324,7 +359,7 @@ public function getLayoutWizardItems($colPos, $excludeLayouts = array(), $allowe if (!empty($allowedGridTypes) && !isset($allowedGridTypes[$layoutId])) { continue; } - if (((int)$colPos === -1 && $item['top_level_layout']) || isset($excludeLayouts[$item['uid']])) { + if (isset($excludeLayouts[$item['uid']]) || (int)$colPos === -1 && $item['top_level_layout']) { continue; } @@ -343,9 +378,9 @@ public function getLayoutWizardItems($colPos, $excludeLayouts = array(), $allowe } /** - * Returns the FlexForm configuration of a grid layout. + * Returns the FlexForm configuration of a grid layout * - * @param string $layoutId : The current layout ID of the grid container + * @param string $layoutId The current layout ID of the grid container * * @return string */ @@ -354,40 +389,37 @@ public function getFlexformConfiguration($layoutId) $layoutSetup = $this->getLayoutSetup($layoutId); // Get flexform file from pi_flexform_ds if pi_flexform_ds_file not set and "FILE:" found in pi_flexform_ds for backward compatibility. if ($layoutSetup['pi_flexform_ds_file']) { - $flexformConfiguration = GeneralUtility::getURL(GeneralUtility::getFileAbsFileName($layoutSetup['pi_flexform_ds_file'])); - } else if (strpos($layoutSetup['pi_flexform_ds'], 'FILE:') === 0) { - $flexformConfiguration = GeneralUtility::getURL(GeneralUtility::getFileAbsFileName(substr($layoutSetup['pi_flexform_ds'], - 5))); - } else if ($layoutSetup['pi_flexform_ds']) { + $flexformConfiguration = GeneralUtility::getUrl(GeneralUtility::getFileAbsFileName($layoutSetup['pi_flexform_ds_file'])); + } elseif (strpos($layoutSetup['pi_flexform_ds'], 'FILE:') === 0) { + $flexformConfiguration = GeneralUtility::getUrl(GeneralUtility::getFileAbsFileName(substr($layoutSetup['pi_flexform_ds'], 5))); + } elseif ($layoutSetup['pi_flexform_ds']) { $flexformConfiguration = $layoutSetup['pi_flexform_ds']; } else { - $flexformConfiguration = GeneralUtility::getURL(GeneralUtility::getFileAbsFileName($this->flexformConfigurationPathAndFileName)); + $flexformConfiguration = GeneralUtility::getUrl(GeneralUtility::getFileAbsFileName($this->flexformConfigurationPathAndFileName)); } return $flexformConfiguration; } /** - * Returns the page TSconfig merged with the grid layout records. + * Returns the page TSconfig merged with the grid layout records * - * @param integer $pageId : The uid of the page we are currently working on - * - * @return void + * @param int $pageId The uid of the page we are currently working on */ protected function loadLayoutSetup($pageId) { // Load page TSconfig. $pageTSconfig = BackendUtility::getPagesTSconfig($pageId); - $excludeLayoutIds = isset($pageTSconfig['tx_gridelements.']['excludeLayoutIds']) && !empty($pageTSconfig['tx_gridelements.']['excludeLayoutIds']) ? array_flip(GeneralUtility::trimExplode(',', - $pageTSconfig['tx_gridelements.']['excludeLayoutIds'])) : array(); + $excludeLayoutIds = !empty($pageTSconfig['tx_gridelements.']['excludeLayoutIds']) + ? array_flip(GeneralUtility::trimExplode(',', $pageTSconfig['tx_gridelements.']['excludeLayoutIds'])) + : array(); - $overruleRecords = (isset($pageTSconfig['tx_gridelements.']['overruleRecords']) && (int)$pageTSconfig['tx_gridelements.']['overruleRecords'] === 1); + $overruleRecords = isset($pageTSconfig['tx_gridelements.']['overruleRecords']) + && (int)$pageTSconfig['tx_gridelements.']['overruleRecords'] === 1; $gridLayoutConfig = array(); - - if (isset($pageTSconfig['tx_gridelements.']['setup.'])) { - + if (!empty($pageTSconfig['tx_gridelements.']['setup.'])) { foreach ($pageTSconfig['tx_gridelements.']['setup.'] as $layoutId => $item) { // remove tailing dot of layout ID $layoutId = rtrim($layoutId, '.'); @@ -424,19 +456,22 @@ protected function loadLayoutSetup($pageId) unset($item['flexformDS']); $gridLayoutConfig[$layoutId] = $item; - } } - $storagePid = isset($pageTSconfig['TCEFORM.']['pages.']['_STORAGE_PID']) ? - (int)$pageTSconfig['TCEFORM.']['pages.']['_STORAGE_PID'] : 0; - $pageTSconfigId = isset($pageTSconfig['TCEFORM.']['tt_content.']['tx_gridelements_backend_layout.']['PAGE_TSCONFIG_ID']) ? - implode(',', GeneralUtility::intExplode(',', $pageTSconfig['TCEFORM.']['tt_content.']['tx_gridelements_backend_layout.']['PAGE_TSCONFIG_ID'])) : 0; + $storagePid = isset($pageTSconfig['TCEFORM.']['pages.']['_STORAGE_PID']) + ? (int)$pageTSconfig['TCEFORM.']['pages.']['_STORAGE_PID'] + : 0; + $pageTSconfigId = isset($pageTSconfig['TCEFORM.']['tt_content.']['tx_gridelements_backend_layout.']['PAGE_TSCONFIG_ID']) + ? implode(',', GeneralUtility::intExplode(',', $pageTSconfig['TCEFORM.']['tt_content.']['tx_gridelements_backend_layout.']['PAGE_TSCONFIG_ID'])) + : 0; // Load records. - $result = $this->databaseConnection->exec_SELECTgetRows('*', 'tx_gridelements_backend_layout', - '(( ' . $pageTSconfigId . ' = 0 AND ' . $storagePid . ' = 0 ) OR ( tx_gridelements_backend_layout.pid IN (' . $pageTSconfigId . ') OR tx_gridelements_backend_layout.pid = ' . $storagePid . ' ) OR ( ' . $pageTSconfigId . ' = 0 AND tx_gridelements_backend_layout.pid = ' . (int)$pageId . ' )) AND tx_gridelements_backend_layout.hidden = 0 AND tx_gridelements_backend_layout.deleted = 0', - '', 'sorting ASC', '', 'uid'); + $where_clause = '(( ' . $pageTSconfigId . ' = 0 AND ' . $storagePid . ' = 0 )' + . ' OR ( tx_gridelements_backend_layout.pid IN (' . $pageTSconfigId . ') OR tx_gridelements_backend_layout.pid = ' . $storagePid . ' ) ' + . ' OR ( ' . $pageTSconfigId . ' = 0 AND tx_gridelements_backend_layout.pid = ' . (int)$pageId . ' ))' + . ' AND tx_gridelements_backend_layout.hidden = 0 AND tx_gridelements_backend_layout.deleted = 0'; + $result = $this->databaseConnection->exec_SELECTgetRows('*', 'tx_gridelements_backend_layout', $where_clause, '', 'sorting ASC', '', 'uid'); $gridLayoutRecords = array(); @@ -472,10 +507,10 @@ protected function loadLayoutSetup($pageId) } if ($overruleRecords === true) { - ArrayUtility::mergeRecursiveWithOverrule($gridLayoutRecords, $gridLayoutConfig); + ArrayUtility::mergeRecursiveWithOverrule($gridLayoutRecords, $gridLayoutConfig, true, false); $this->setLayoutSetup($gridLayoutRecords); } else { - ArrayUtility::mergeRecursiveWithOverrule($gridLayoutConfig, $gridLayoutRecords); + ArrayUtility::mergeRecursiveWithOverrule($gridLayoutConfig, $gridLayoutRecords, true, false); $this->setLayoutSetup($gridLayoutConfig); } } @@ -484,8 +519,6 @@ protected function loadLayoutSetup($pageId) * setter for databaseConnection object * * @param DatabaseConnection $databaseConnection - * - * @return void */ public function setDatabaseConnection(DatabaseConnection $databaseConnection) { @@ -505,11 +538,9 @@ public function getLanguageService() /** * setter for databaseConnection object * - * @param mixed $languageService - * - * @return void + * @param LanguageService $languageService */ - public function setLanguageService($languageService) + public function setLanguageService(LanguageService $languageService = null) { $this->languageService = $languageService instanceof LanguageService ? $languageService : GeneralUtility::makeInstance(LanguageService::class); if ($this->getBackendUser()) { @@ -537,4 +568,14 @@ public function getBackendUser() return $GLOBALS['BE_USER']; } + /** + * Gets the current real pid. + * + * @return int + */ + public function getRealPid() + { + return $this->realPid; + } + } diff --git a/Classes/Backend/TtContent.php b/Classes/Backend/TtContent.php index b1a9bed..ecf4e5e 100644 --- a/Classes/Backend/TtContent.php +++ b/Classes/Backend/TtContent.php @@ -33,14 +33,13 @@ */ class TtContent { - /** * @var DatabaseConnection */ protected $databaseConnection; /** - * @var \GridElementsTeam\Gridelements\Backend\LayoutSetup + * @var LayoutSetup */ protected $layoutSetup; @@ -48,8 +47,6 @@ class TtContent * inject layout setup * * @param LayoutSetup $layoutSetup - * - * @return void */ public function injectLayoutSetup(LayoutSetup $layoutSetup) { @@ -59,17 +56,12 @@ public function injectLayoutSetup(LayoutSetup $layoutSetup) /** * initializes this class * - * @param integer $pageUid - * - * @return void + * @param int $pageUid */ public function init($pageUid) { $this->setDatabaseConnection($GLOBALS['TYPO3_DB']); if (!$this->layoutSetup instanceof LayoutSetup) { - if ($pageUid < 0) { - $pageUid = Helper::getInstance()->getPidFromNegativeUid($pageUid); - } $this->injectLayoutSetup(GeneralUtility::makeInstance(LayoutSetup::class)->init($pageUid)); } } @@ -77,14 +69,14 @@ public function init($pageUid) /** * ItemProcFunc for columns items * - * @param array $params : An array containing the items and parameters for the list of items - * - * @return void + * @param array $params An array containing the items and parameters for the list of items */ - public function columnsItemsProcFunc(&$params) + public function columnsItemsProcFunc(array &$params) { $this->init($params['row']['pid']); - $gridContainerId = is_array($params['row']['tx_gridelements_container']) ? (int)$params['row']['tx_gridelements_container'][0] : (int)$params['row']['tx_gridelements_container']; + $gridContainerId = is_array($params['row']['tx_gridelements_container']) + ? (int)$params['row']['tx_gridelements_container'][0] + : (int)$params['row']['tx_gridelements_container']; if ($gridContainerId > 0) { $gridElement = $this->layoutSetup->cacheCurrentParent($gridContainerId, true); @@ -93,8 +85,8 @@ public function columnsItemsProcFunc(&$params) $ContentType = is_array($params['row']['CType']) ? $params['row']['CType'][0] : $params['row']['CType']; if ($ContentType !== '' && is_array($params['items'])) { foreach ($params['items'] as $itemKey => $itemArray) { - if ($itemArray[3] !== '' && $itemArray[3] !== '*' && !GeneralUtility::inList($itemArray[3], - $ContentType) + if ($itemArray[3] !== '' && $itemArray[3] !== '*' + && !GeneralUtility::inList($itemArray[3], $ContentType) ) { unset($params['items'][$itemKey]); } @@ -108,13 +100,12 @@ public function columnsItemsProcFunc(&$params) * removes items of the children chain from the list of selectable containers * if the element itself already is a container * - * @param array $params : An array containing the items and parameters for the list of items - * - * @return void + * @param array $params An array containing the items and parameters for the list of items */ - public function containerItemsProcFunc(&$params) + public function containerItemsProcFunc(array &$params) { $this->init($params['row']['pid']); + $possibleContainers = array(); $this->removesItemsFromListOfSelectableContainers($params, $possibleContainers); if (!empty($possibleContainers)) { @@ -139,11 +130,9 @@ public function containerItemsProcFunc(&$params) * removes items of the children chain from the list of selectable containers * * @param array $params - * @param $possibleContainers - * - * @return void + * @param array $possibleContainers */ - public function removesItemsFromListOfSelectableContainers(array &$params, &$possibleContainers) + public function removesItemsFromListOfSelectableContainers(array &$params, array &$possibleContainers) { $ContentType = is_array($params['row']['CType']) ? $params['row']['CType'][0] : $params['row']['CType']; if ($ContentType === 'gridelements_pi1' && count($params['items']) > 1) { @@ -164,9 +153,7 @@ public function removesItemsFromListOfSelectableContainers(array &$params, &$pos * delete containers from params which are not allowed * * @param array $params - * @param string $itemUidList comma seperated list of uids - * - * @return void + * @param string $itemUidList comma separated list of uids */ public function deleteUnallowedContainer(array &$params, $itemUidList = '') { @@ -174,8 +161,12 @@ public function deleteUnallowedContainer(array &$params, $itemUidList = '') $layoutSetups = $this->layoutSetup->getLayoutSetup(); if ($itemUidList) { $itemUidList = implode(',', GeneralUtility::intExplode(',', $itemUidList)); - $containerRecords = $this->databaseConnection->exec_SELECTgetRows('uid,tx_gridelements_backend_layout', - 'tt_content', 'uid IN (' . $itemUidList . ')', '', '', '', 'uid'); + $containerRecords = $this->databaseConnection->exec_SELECTgetRows( + 'uid,tx_gridelements_backend_layout', + 'tt_content', + 'uid IN (' . $itemUidList . ')', + '', '', '', 'uid' + ); foreach ($params['items'] as $key => $container) { $allowed = $layoutSetups[$containerRecords[$container[1]]['tx_gridelements_backend_layout']]['allowed']; @@ -193,15 +184,13 @@ public function deleteUnallowedContainer(array &$params, $itemUidList = '') * removes items that are available for grid boxes on the first level only * and items that are excluded for a certain branch or user * - * @param array $params : An array containing the items and parameters for the list of items - * - * @return void + * @param array $params An array containing the items and parameters for the list of items */ - public function layoutItemsProcFunc(&$params) + public function layoutItemsProcFunc(array &$params) { $this->init($params['row']['pid']); - $layoutSelectItems = $this->layoutSetup->getLayoutSelectItems($params['row']['colPos']); - + $layoutSelectItems = $this->layoutSetup->getLayoutSelectItems(isset($params['row']['colPos'][0]) ? $params['row']['colPos'][0] : $params['row']['colPos'], + $params['row']['tx_gridelements_columns'], $params['row']['tx_gridelements_container'], $this->layoutSetup->getRealPid()); $params['items'] = ArrayUtility::keepItemsInArray($layoutSelectItems, $params['items'], true); } @@ -211,17 +200,18 @@ public function layoutItemsProcFunc(&$params) * * @param string $containerIds : A list determining containers that should be checked * @param array $possibleContainers : The result list containing the remaining containers after the check - * - * @return void */ - public function lookForChildContainersRecursively($containerIds, &$possibleContainers) + public function lookForChildContainersRecursively($containerIds, array &$possibleContainers) { if (!$containerIds) { return; } $containerIds = implode(',', GeneralUtility::intExplode(',', $containerIds)); - $childrenOnNextLevel = $this->databaseConnection->exec_SELECTgetRows('uid, tx_gridelements_container', - 'tt_content', 'CType=\'gridelements_pi1\' AND tx_gridelements_container IN (' . $containerIds . ')'); + $childrenOnNextLevel = $this->databaseConnection->exec_SELECTgetRows( + 'uid, tx_gridelements_container', + 'tt_content', + 'CType=\'gridelements_pi1\' AND tx_gridelements_container IN (' . $containerIds . ')' + ); if (!empty($childrenOnNextLevel) && !empty($possibleContainers)) { $containerIds = ''; @@ -244,8 +234,6 @@ public function lookForChildContainersRecursively($containerIds, &$possibleConta * setter for databaseConnection object * * @param DatabaseConnection $databaseConnection - * - * @return void */ public function setDatabaseConnection(DatabaseConnection $databaseConnection) { @@ -261,5 +249,4 @@ public function getDatabaseConnection() { return $this->databaseConnection; } - } diff --git a/Classes/DataHandler/AbstractDataHandler.php b/Classes/DataHandler/AbstractDataHandler.php index bddbde0..c07f181 100644 --- a/Classes/DataHandler/AbstractDataHandler.php +++ b/Classes/DataHandler/AbstractDataHandler.php @@ -1,4 +1,5 @@ layoutSetup = $layoutSetup; - } - /** * initializes this class * * @param string $table : The name of the table the data should be saved to - * @param integer $pageUid : The uid of the page we are currently working on + * @param integer $uidPid : The uid of the record or page we are currently working on * @param DataHandler $dataHandler - * - * @return void */ - public function init($table, $pageUid, DataHandler $dataHandler) + public function init($table, $uidPid, DataHandler $dataHandler) { $this->setTable($table); - $this->setPageUid($pageUid); + if ($table === 'tt_content' && (int)$uidPid < 0) { + $this->setContentUid(abs($uidPid)); + $pageUid = Helper::getInstance()->getPidFromUid($this->getContentUid()); + $this->setPageUid($pageUid); + } else { + $this->setPageUid((int)$uidPid); + } $this->setTceMain($dataHandler); $this->setDatabaseConnection($GLOBALS['TYPO3_DB']); if (!$this->layoutSetup instanceof LayoutSetup) { - if ($pageUid < 0) { - $pageUid = Helper::getInstance()->getPidFromNegativeUid($pageUid); - } - $this->injectLayoutSetup(GeneralUtility::makeInstance(LayoutSetup::class)->init($pageUid)); + $this->injectLayoutSetup(GeneralUtility::makeInstance(LayoutSetup::class)->init($this->getPageUid())); } } /** - * setter for table - * - * @param string $table + * getter for contentUid * - * @return void + * @return integer contentUid */ - public function setTable($table) + public function getContentUid() { - $this->table = $table; + return $this->contentUid; } /** - * getter for table + * setter for contentUid * - * @return string table + * @param integer $contentUid */ - public function getTable() + public function setContentUid($contentUid) { - return $this->table; + $this->contentUid = $contentUid; } /** - * setter for pageUid - * - * @param integer $pageUid + * setter for dataHandler object * - * @return void + * @param DataHandler $dataHandler */ - public function setPageUid($pageUid) + public function setTceMain(DataHandler $dataHandler) { - $this->pageUid = $pageUid; + $this->dataHandler = $dataHandler; } /** - * getter for pageUid + * inject layout setup * - * @return integer pageUid + * @param LayoutSetup $layoutSetup */ - public function getPageUid() + public function injectLayoutSetup(LayoutSetup $layoutSetup) { - return $this->pageUid; + $this->layoutSetup = $layoutSetup; } /** - * setter for dataHandler object - * - * @param DataHandler $dataHandler + * getter for table * - * @return void + * @return string table */ - public function setTceMain(DataHandler $dataHandler) + public function getTable() { - $this->dataHandler = $dataHandler; + return $this->table; } /** - * getter for dataHandler + * setter for table * - * @return DataHandler dataHandler + * @param string $table */ - public function getTceMain() + public function setTable($table) { - return $this->dataHandler; + $this->table = $table; } /** - * setter for databaseConnection object + * getter for pageUid * - * @param DatabaseConnection $databaseConnection + * @return integer pageUid + */ + public function getPageUid() + { + return $this->pageUid; + } + + /** + * setter for pageUid * - * @return void + * @param integer $pageUid */ - public function setDatabaseConnection(DatabaseConnection $databaseConnection) + public function setPageUid($pageUid) { - $this->databaseConnection = $databaseConnection; + $this->pageUid = $pageUid; } /** @@ -179,22 +180,13 @@ public function getDatabaseConnection() } /** - * Function to handle record actions between different grid containers - * - * @param array $containerUpdateArray + * setter for databaseConnection object * - * @return void + * @param DatabaseConnection $databaseConnection */ - public function doGridContainerUpdate($containerUpdateArray = array()) + public function setDatabaseConnection(DatabaseConnection $databaseConnection) { - if (is_array($containerUpdateArray) && !empty($containerUpdateArray)) { - foreach ($containerUpdateArray as $containerUid => $newElement) { - $fieldArray = array('tx_gridelements_children' => 'tx_gridelements_children + ' . (int)$newElement); - $this->databaseConnection->exec_UPDATEquery('tt_content', 'uid=' . (int)$containerUid, $fieldArray, - 'tx_gridelements_children'); - $this->getTceMain()->updateRefIndex('tt_content', (int)$containerUid); - } - } + $this->databaseConnection = $databaseConnection; } /** @@ -205,47 +197,92 @@ public function doGridContainerUpdate($containerUpdateArray = array()) */ public function checkAndUpdateTranslatedElements($uid) { - if ($uid > 0) { - $translatedElements = $this->databaseConnection->exec_SELECTgetRows( + if ($uid <= 0) { + return; + } + $currentValues = $this->databaseConnection->exec_SELECTgetSingleRow( + 'uid,tx_gridelements_container,tx_gridelements_columns,sys_language_uid,colPos,l18n_parent', + 'tt_content', 'deleted = 0 AND uid=' . (int)$uid + ); + if (!empty($currentValues['l18n_parent'])) { + $currentValues = $this->databaseConnection->exec_SELECTgetSingleRow( 'uid,tx_gridelements_container,tx_gridelements_columns,sys_language_uid,colPos,l18n_parent', - 'tt_content', 'l18n_parent=' . (int)$uid , '', '', '', 'uid' + 'tt_content', 'deleted = 0 AND uid=' . (int)$currentValues['l18n_parent'] ); - if (empty($translatedElements)) { - return; - } - $currentValues = $this->databaseConnection->exec_SELECTgetSingleRow( - 'tx_gridelements_container,tx_gridelements_columns,colPos', - 'tt_content', 'uid=' . (int)$uid + } + if (empty($currentValues['uid'])) { + return; + } + $translatedElements = $this->databaseConnection->exec_SELECTgetRows( + 'uid,tx_gridelements_container,tx_gridelements_columns,sys_language_uid,colPos,l18n_parent', + 'tt_content', 'deleted = 0 AND l18n_parent=' . (int)$currentValues['uid'], '', '', '', 'uid' + ); + if (empty($translatedElements)) { + return; + } + if ($currentValues['tx_gridelements_container'] > 0) { + $translatedContainers = $this->databaseConnection->exec_SELECTgetRows( + 'uid,sys_language_uid', + 'tt_content', 'deleted = 0 AND l18n_parent=' . (int)$currentValues['tx_gridelements_container'], '', '', + '', 'sys_language_uid' ); - if ($currentValues['tx_gridelements_container'] > 0) { - $translatedContainers = $this->databaseConnection->exec_SELECTgetRows( - 'uid,sys_language_uid', - 'tt_content', 'l18n_parent=' . (int)$currentValues['tx_gridelements_container'], '', '', '', 'sys_language_uid' - ); - } - $containerUpdateArray = array(); - foreach ($translatedElements as $translatedUid => $translatedElement) { - $updateArray = array(); - $updateArray['tx_gridelements_container'] = isset($translatedContainers[$translatedElement['sys_language_uid']]) ? - (int)$translatedContainers[$translatedElement['sys_language_uid']]['uid'] : 0; - $updateArray['tx_gridelements_columns'] = isset($translatedContainers[$translatedElement['sys_language_uid']]) ? - (int)$currentValues['tx_gridelements_columns'] : 0; - $updateArray['colPos'] = (int)$currentValues['colPos']; - - $this->databaseConnection->exec_UPDATEquery('tt_content', 'uid=' . (int)$translatedUid, - $updateArray, - 'tx_gridelements_container,tx_gridelements_columns.colPos'); - - if ($translatedElement['tx_gridelements_container'] !== $updateArray['tx_gridelements_container']) { - $containerUpdateArray[$translatedElement['tx_gridelements_container']] -= 1; - $containerUpdateArray[$updateArray['tx_gridelements_container']] += 1; - $this->getTceMain()->updateRefIndex('tt_content', - $translatedElement['tx_gridelements_container']); - $this->getTceMain()->updateRefIndex('tt_content', $updateArray['tx_gridelements_container']); + } + $containerUpdateArray = []; + foreach ($translatedElements as $translatedUid => $translatedElement) { + $updateArray = []; + if (isset($translatedContainers[$translatedElement['sys_language_uid']])) { + $updateArray['tx_gridelements_container'] = (int)$translatedContainers[$translatedElement['sys_language_uid']]['uid']; + $updateArray['tx_gridelements_columns'] = (int)$currentValues['tx_gridelements_columns']; + } else { + if ($translatedElement['tx_gridelements_container'] == $currentValues['tx_gridelements_container']) { + $updateArray['tx_gridelements_container'] = (int)$currentValues['tx_gridelements_container']; + $updateArray['tx_gridelements_columns'] = (int)$currentValues['tx_gridelements_columns']; + } else { + $updateArray['tx_gridelements_container'] = 0; + $updateArray['tx_gridelements_columns'] = 0; } } - if (!empty($containerUpdateArray)) { - $this->doGridContainerUpdate($containerUpdateArray); + $updateArray['colPos'] = (int)$currentValues['colPos']; + $this->databaseConnection->exec_UPDATEquery('tt_content', 'uid=' . (int)$translatedUid, + $updateArray, + 'tx_gridelements_container,tx_gridelements_columns,colPos' + ); + + if ($translatedElement['tx_gridelements_container'] !== $updateArray['tx_gridelements_container']) { + $containerUpdateArray[$translatedElement['tx_gridelements_container']] -= 1; + $containerUpdateArray[$updateArray['tx_gridelements_container']] += 1; + $this->getTceMain()->updateRefIndex('tt_content', $translatedElement['tx_gridelements_container']); + $this->getTceMain()->updateRefIndex('tt_content', $updateArray['tx_gridelements_container']); + } + } + if (!empty($containerUpdateArray)) { + $this->doGridContainerUpdate($containerUpdateArray); + } + } + + /** + * getter for dataHandler + * + * @return DataHandler dataHandler + */ + public function getTceMain() + { + return $this->dataHandler; + } + + /** + * Function to handle record actions between different grid containers + * + * @param array $containerUpdateArray + */ + public function doGridContainerUpdate($containerUpdateArray = []) + { + if (is_array($containerUpdateArray) && !empty($containerUpdateArray)) { + foreach ($containerUpdateArray as $containerUid => $newElement) { + $fieldArray = ['tx_gridelements_children' => 'tx_gridelements_children + ' . (int)$newElement]; + $this->databaseConnection->exec_UPDATEquery('tt_content', 'uid=' . (int)$containerUid, $fieldArray, + 'tx_gridelements_children'); + $this->getTceMain()->updateRefIndex('tt_content', (int)$containerUid); } } } diff --git a/Classes/DataHandler/AfterDatabaseOperations.php b/Classes/DataHandler/AfterDatabaseOperations.php index f065845..00cf2c1 100644 --- a/Classes/DataHandler/AfterDatabaseOperations.php +++ b/Classes/DataHandler/AfterDatabaseOperations.php @@ -1,4 +1,5 @@ init($table, $uid, $parentObj); if (!$this->getTceMain()->isImporting) { $this->saveCleanedUpFieldArray($fieldArray); @@ -65,13 +65,14 @@ public function execute_afterDatabaseOperations(&$fieldArray, $table, $uid, &$pa * save cleaned up field array * * @param array $changedFieldArray - * - * @return array cleaned up field array */ public function saveCleanedUpFieldArray(array $changedFieldArray) { unset($changedFieldArray['pi_flexform']); - if ((isset($changedFieldArray['tx_gridelements_backend_layout']) && $this->getTable() === 'tt_content') || (isset($changedFieldArray['backend_layout']) && $this->getTable() == 'pages') || (isset($changedFieldArray['backend_layout_next_level']) && $this->getTable() == 'pages')) { + if (isset($changedFieldArray['tx_gridelements_backend_layout']) && $this->getTable() === 'tt_content' + || isset($changedFieldArray['backend_layout']) && $this->getTable() === 'pages' + || isset($changedFieldArray['backend_layout_next_level']) && $this->getTable() === 'pages' + ) { $this->setUnusedElements($changedFieldArray); } } @@ -79,24 +80,23 @@ public function saveCleanedUpFieldArray(array $changedFieldArray) /** * Function to move elements to/from the unused elements column while changing the layout of a page or a grid element * - * @param array $fieldArray : The array of fields and values that have been saved to the datamap - * return void + * @param array $fieldArray The array of fields and values that have been saved to the datamap */ - public function setUnusedElements(&$fieldArray) + public function setUnusedElements(array &$fieldArray) { - $changedGridElements = array(); - $changedElements = array(); - $changedSubPageElements = array(); + $changedGridElements = []; + $changedElements = []; + $changedSubPageElements = []; if ($this->getTable() === 'tt_content') { - $changedGridElements[$this->getPageUid()] = true; - $childElementsInUnavailableColumns = array(); - $childElementsInAvailableColumns = array(); - $availableColumns = $this->getAvailableColumns($fieldArray['tx_gridelements_backend_layout'], 'tt_content', - $this->getPageUid()); + $changedGridElements[$this->getContentUid()] = true; + $childElementsInUnavailableColumns = []; + $childElementsInAvailableColumns = []; + $availableColumns = $this->getAvailableColumns($fieldArray['tx_gridelements_backend_layout'], 'tt_content'); if (!empty($availableColumns) || $availableColumns === '0') { $childElementsInUnavailableColumns = array_keys($this->databaseConnection->exec_SELECTgetRows('uid', - 'tt_content', 'tx_gridelements_container = ' . $this->getPageUid() . ' + 'tt_content', + 'tx_gridelements_container > 0 AND tx_gridelements_container = ' . $this->getContentUid() . ' AND tx_gridelements_columns NOT IN (' . $availableColumns . ')', '', '', '', 'uid')); if (!empty($childElementsInUnavailableColumns)) { $this->databaseConnection->sql_query(' @@ -108,7 +108,8 @@ public function setUnusedElements(&$fieldArray) } $childElementsInAvailableColumns = array_keys($this->databaseConnection->exec_SELECTgetRows('uid', - 'tt_content', 'tx_gridelements_container = ' . $this->getPageUid() . ' + 'tt_content', + 'tx_gridelements_container > 0 AND tx_gridelements_container = ' . $this->getContentUid() . ' AND tx_gridelements_columns IN (' . $availableColumns . ')', '', '', '', 'uid')); if (!empty($childElementsInAvailableColumns)) { $this->databaseConnection->sql_query(' @@ -141,13 +142,17 @@ public function setUnusedElements(&$fieldArray) $backendLayoutUid = $fieldArray['backend_layout']; break; } - } else if ($selectedBackendLayoutNextLevel === -1 && $page['uid'] !== $this->getPageUid()) { - // Some previous page in our rootline sets layout_next to "None" - break; - } else if ($selectedBackendLayoutNextLevel > 0 && $page['uid'] !== $this->getPageUid()) { - // Some previous page in our rootline sets some backend_layout, use it - $backendLayoutUid = $selectedBackendLayoutNextLevel; - break; + } else { + if ($selectedBackendLayoutNextLevel === -1 && $page['uid'] !== $this->getPageUid()) { + // Some previous page in our rootline sets layout_next to "None" + break; + } else { + if ($selectedBackendLayoutNextLevel > 0 && $page['uid'] !== $this->getPageUid()) { + // Some previous page in our rootline sets some backend_layout, use it + $backendLayoutUid = $selectedBackendLayoutNextLevel; + break; + } + } } } @@ -164,7 +169,7 @@ public function setUnusedElements(&$fieldArray) '); array_flip($elementsInUnavailableColumns); } else { - $elementsInUnavailableColumns = array(); + $elementsInUnavailableColumns = []; } $elementsInAvailableColumns = array_keys($this->databaseConnection->exec_SELECTgetRows('uid', @@ -180,7 +185,7 @@ public function setUnusedElements(&$fieldArray) '); array_flip($elementsInAvailableColumns); } else { - $elementsInAvailableColumns = array(); + $elementsInAvailableColumns = []; } $changedElements = array_merge($elementsInUnavailableColumns, $elementsInAvailableColumns); @@ -188,10 +193,10 @@ public function setUnusedElements(&$fieldArray) if (isset($fieldArray['backend_layout_next_level'])) { $backendLayoutUid = $backendLayoutNextLevelUid ? $backendLayoutNextLevelUid : $backendLayoutUid; - $subpages = array(); + $subpages = []; $this->getSubpagesRecursively($this->getPageUid(), $subpages); if (!empty($subpages)) { - $changedSubPageElements = array(); + $changedSubPageElements = []; foreach ($subpages as $page) { $availableColumns = $this->getAvailableColumns($backendLayoutUid, 'pages', $page['uid']); $subPageElementsInUnavailableColumns = array_keys($this->databaseConnection->exec_SELECTgetRows('uid', @@ -205,7 +210,7 @@ public function setUnusedElements(&$fieldArray) '); array_flip($subPageElementsInUnavailableColumns); } else { - $subPageElementsInUnavailableColumns = array(); + $subPageElementsInUnavailableColumns = []; } $subPageElementsInAvailableColumns = array_keys($this->databaseConnection->exec_SELECTgetRows('uid', @@ -220,7 +225,7 @@ public function setUnusedElements(&$fieldArray) '); array_flip($subPageElementsInAvailableColumns); } else { - $subPageElementsInAvailableColumns = array(); + $subPageElementsInAvailableColumns = []; } $changedPageElements = array_merge($subPageElementsInUnavailableColumns, @@ -239,62 +244,61 @@ public function setUnusedElements(&$fieldArray) } } - /** - * gets all subpages of the current page and traverses recursively unless backend_layout_next_level is set or unset (!= 0) - * - * @param $pageUid - * @param $subpages - * - * @internal param int $id : the uid of the parent page - * @return array $subpages : Reference to a list of all subpages - */ - public function getSubpagesRecursively($pageUid, &$subpages) - { - $childPages = $this->databaseConnection->exec_SELECTgetRows('uid, backend_layout, backend_layout_next_level', - 'pages', 'pid = ' . (int)$pageUid); - - if (!empty($childPages)) { - foreach ($childPages as $page) { - if (empty($page['backend_layout'])) { - $subpages[] = $page; - } - if (empty($page['backend_layout_next_level'])) { - $this->getSubpagesRecursively($page['uid'], $subpages); - } - } - } - } - /** * fetches all available columns for a certain grid container based on TCA settings and layout records * - * @param string $layout : The selected backend layout of the grid container or the page - * @param string $table : The name of the table to get the layout for - * @param int $id : the uid of the parent container - being the page id for the table "pages" + * @param string $layout The selected backend layout of the grid container or the page + * @param string $table The name of the table to get the layout for + * @param int $id he uid of the parent container - being the page id for the table "pages" * - * @return string $tcaColumns : The columns available for the selected layout as CSV list + * @return string The columns available for the selected layout as CSV list */ public function getAvailableColumns($layout = '', $table = '', $id = 0) { - $tcaColumns = array(); + $tcaColumns = ''; if ($layout && $table === 'tt_content') { $tcaColumns = $this->layoutSetup->getLayoutColumns($layout); - $tcaColumns = $tcaColumns['CSV']; - } else if ($table === 'pages') { - $tcaColumns = GeneralUtility::callUserFunction('TYPO3\\CMS\\Backend\\View\\BackendLayoutView->getColPosListItemsParsed', + $tcaColumns = '-2,-1,' . $tcaColumns['CSV']; + } elseif ($table === 'pages') { + $tcaColumns = GeneralUtility::callUserFunction(BackendLayoutView::class . '->getColPosListItemsParsed', $id, $this); - $temp = array(); + $temp = []; foreach ($tcaColumns AS $item) { if (trim($item[1]) !== '') { $temp[] = (int)$item[1]; } } // Implode into a CSV string as BackendLayoutView->getColPosListItemsParsed returns an array - $tcaColumns = '-2,-1,' . implode(',', $temp); + $tcaColumns = rtrim('-2,-1,' . implode(',', $temp), ','); } return $tcaColumns; } -} \ No newline at end of file + /** + * gets all subpages of the current page and traverses recursively unless backend_layout_next_level is set or unset (!= 0) + * + * @param int $pageUid + * @param array $subpages + */ + public function getSubpagesRecursively($pageUid, array &$subpages) + { + $childPages = $this->databaseConnection->exec_SELECTgetRows( + 'uid, backend_layout, backend_layout_next_level', + 'pages', + 'pid = ' . (int)$pageUid + ); + + if (!empty($childPages)) { + foreach ($childPages as $page) { + if (empty($page['backend_layout'])) { + $subpages[] = $page; + } + if (empty($page['backend_layout_next_level'])) { + $this->getSubpagesRecursively($page['uid'], $subpages); + } + } + } + } +} diff --git a/Classes/DataHandler/PreProcessFieldArray.php b/Classes/DataHandler/PreProcessFieldArray.php index 8bff2c3..c5b258d 100644 --- a/Classes/DataHandler/PreProcessFieldArray.php +++ b/Classes/DataHandler/PreProcessFieldArray.php @@ -1,4 +1,5 @@ init($table, $id, $parentObj); @@ -89,14 +93,11 @@ public function processFieldArrayForTtContent(array &$fieldArray, $id = 0) * * @param array $fieldArray * @param int $pid - * - * @return void */ - - public function setDefaultFieldValues(&$fieldArray, $pid = 0) + public function setDefaultFieldValues(array &$fieldArray, $pid = 0) { // Default values: - $newRow = array(); // Used to store default values as found here: + $newRow = []; // Used to store default values as found here: // Default values as set in userTS: $TCAdefaultOverride = $this->getBackendUser()->getTSConfigProp('TCAdefaults'); @@ -165,20 +166,25 @@ public function setDefaultFieldValues(&$fieldArray, $pid = 0) $fieldArray = array_merge($newRow, $fieldArray); } + /** + * @return BackendUserAuthentication + */ + public function getBackendUser() + { + return $GLOBALS['BE_USER']; + } + /** * checks for default flexform values for new records and sets them accordingly * * @param array $fieldArray - * - * @return void */ - - public function getDefaultFlexformValues(&$fieldArray) + public function getDefaultFlexformValues(array &$fieldArray) { foreach ($GLOBALS['TCA']['tt_content']['columns']['pi_flexform']['config']['ds'] as $key => $dataStructure) { $types = GeneralUtility::trimExplode(',', $key); if (($types[0] === $fieldArray['list_type'] || $types[0] === '*') && ($types[1] === $fieldArray['CType'] || $types[1] === '*')) { - $fieldArray['pi_flexform'] = $this->extractDefaultDataFromDatastructure($dataStructure); + $fieldArray['pi_flexform'] = $this->extractDefaultDataFromDataStructure($dataStructure); } } } @@ -190,11 +196,10 @@ public function getDefaultFlexformValues(&$fieldArray) * * @return string $defaultData */ - public function extractDefaultDataFromDataStructure($dataStructure) { $returnXML = ''; - $sheetArray = array(); + $sheetArray = []; if ($dataStructure) { $structureArray = GeneralUtility::xml2array($dataStructure); if (!isset($structureArray['sheets']) && isset($structureArray['ROOT'])) { @@ -204,7 +209,7 @@ public function extractDefaultDataFromDataStructure($dataStructure) if (isset($structureArray['sheets']) && !empty($structureArray['sheets'])) { foreach ($structureArray['sheets'] as $sheetName => $sheet) { if (is_array($sheet['ROOT']['el']) && !empty($sheet['ROOT']['el'])) { - $elArray = array(); + $elArray = []; foreach ($sheet['ROOT']['el'] as $elName => $elConf) { $config = $elConf['TCEforms']['config']; $elArray[$elName]['vDEF'] = $config['default']; @@ -233,7 +238,7 @@ public function extractDefaultDataFromDataStructure($dataStructure) */ public function setFieldEntries(array &$fieldArray, $id = 0) { - $containerUpdateArray = array(); + $containerUpdateArray = []; if (isset($fieldArray['tx_gridelements_container'])) { if ((int)$fieldArray['tx_gridelements_container'] > 0) { $containerUpdateArray[(int)$fieldArray['tx_gridelements_container']] = 1; @@ -242,7 +247,7 @@ public function setFieldEntries(array &$fieldArray, $id = 0) $originalContainer = $this->databaseConnection->exec_SELECTgetSingleRow('tx_gridelements_container, sys_language_uid', 'tt_content', 'uid=' . (int)$id); if (!empty($originalContainer)) { - $containerUpdateArray[$originalContainer['tx_gridelements_container']] = -1; + $containerUpdateArray[(int)$originalContainer['tx_gridelements_container']] = -1; } } } @@ -267,18 +272,25 @@ public function setFieldEntriesForGridContainers(array &$fieldArray) if ((int)$targetContainer['sys_language_uid'] > -1) { $fieldArray['sys_language_uid'] = (int)$targetContainer['sys_language_uid']; } - } else if (isset($fieldArray['tx_gridelements_container']) && (int)$fieldArray['tx_gridelements_container'] === 0 && (int)$fieldArray['colPos'] === -1) { - $fieldArray['colPos'] = $this->checkForRootColumn((int)$this->getPageUid()); - $fieldArray['tx_gridelements_columns'] = 0; - } else if (!isset($fieldArray['sys_language_uid']) && isset($fieldArray['tx_gridelements_container']) && (int)$fieldArray['tx_gridelements_container'] > 0 && (int)$fieldArray['colPos'] === -1) { - $targetContainer = $this->databaseConnection->exec_SELECTgetSingleRow('sys_language_uid', 'tt_content', - 'uid=' . (int)$fieldArray['tx_gridelements_container']); - if ((int)$targetContainer['sys_language_uid'] > -1) { - $fieldArray['sys_language_uid'] = (int)$targetContainer['sys_language_uid']; + } else { + if (isset($fieldArray['tx_gridelements_container']) && (int)$fieldArray['tx_gridelements_container'] === 0 && (int)$fieldArray['colPos'] === -1) { + $fieldArray['colPos'] = $this->checkForRootColumn((int)$this->getContentUid()); + $fieldArray['tx_gridelements_columns'] = 0; + $fieldArray['tx_gridelements_container'] = 0; + } else { + if (!isset($fieldArray['sys_language_uid']) && isset($fieldArray['tx_gridelements_container']) && (int)$fieldArray['tx_gridelements_container'] > 0 && (int)$fieldArray['colPos'] === -1) { + $targetContainer = $this->databaseConnection->exec_SELECTgetSingleRow('sys_language_uid', + 'tt_content', + 'uid=' . (int)$fieldArray['tx_gridelements_container']); + if ((int)$targetContainer['sys_language_uid'] > -1) { + $fieldArray['sys_language_uid'] = (int)$targetContainer['sys_language_uid']; + } + } } } - if ((int)$targetContainer['sys_language_uid'] === -1) { - $list = array_flip(GeneralUtility::trimExplode(',', $GLOBALS['TCA']['tt_content']['ctrl']['copyAfterDuplFields'], true)); + if (isset($targetContainer) && (int)$targetContainer['sys_language_uid'] === -1) { + $list = array_flip(GeneralUtility::trimExplode(',', + $GLOBALS['TCA']['tt_content']['ctrl']['copyAfterDuplFields'], true)); unset($list['sys_language_uid']); $GLOBALS['TCA']['tt_content']['ctrl']['copyAfterDuplFields'] = implode(',', array_flip($list)); } @@ -289,14 +301,15 @@ public function setFieldEntriesForGridContainers(array &$fieldArray) * so that an element that has been removed from any container * will still remain in the same major page column * - * @param integer $contentId : The uid of the current content element + * @param int $contentId The uid of the current content element * - * @return integer $colPos: The new column of this content element + * @return int The new column of this content element */ public function checkForRootColumn($contentId) { $parent = $this->databaseConnection->exec_SELECTgetSingleRow('t1.colPos, t1.tx_gridelements_container', - 'tt_content AS t1, tt_content AS t2', 't1.uid=t2.tx_gridelements_container AND t2.uid=' . (int)$contentId); + 'tt_content AS t1, tt_content AS t2', 't1.uid=t2.tx_gridelements_container AND t2.uid=' . (int)$contentId + ); if (!empty($parent) && $parent['tx_gridelements_container'] > 0) { $colPos = $this->checkForRootColumn($parent['tx_gridelements_container']); } else { @@ -305,12 +318,4 @@ public function checkForRootColumn($contentId) return $colPos; } - - /** - * @return BackendUserAuthentication - */ - public function getBackendUser() - { - return $GLOBALS['BE_USER']; - } } diff --git a/Classes/DataHandler/ProcessCmdmap.php b/Classes/DataHandler/ProcessCmdmap.php index e28037b..6bb9076 100644 --- a/Classes/DataHandler/ProcessCmdmap.php +++ b/Classes/DataHandler/ProcessCmdmap.php @@ -1,15 +1,6 @@ - * @package TYPO3 - * @subpackage tx_gridelements - */ -use TYPO3\CMS\Core\Utility\GeneralUtility; - /*************************************************************** * Copyright notice * (c) 2013 Jo Hasenau @@ -28,21 +19,29 @@ * GNU General Public License for more details. * This copyright notice MUST APPEAR in all copies of the script! ***************************************************************/ + +use TYPO3\CMS\Core\DataHandling\DataHandler; +use TYPO3\CMS\Core\Utility\GeneralUtility; + +/** + * Class/Function which offers TCE main hook functions. + * + * @author Jo Hasenau + * @package TYPO3 + * @subpackage tx_gridelements + */ class ProcessCmdmap extends AbstractDataHandler { - /** * Function to process the drag & drop copy action * - * @param string $command : The command to be handled by the command map - * @param string $table : The name of the table we are working on - * @param int $id : The id of the record that is going to be copied - * @param string $value : The value that has been sent with the copy command - * @param boolean $commandIsProcessed : A switch to tell the parent object, if the record has been copied - * @param \TYPO3\CMS\Core\DataHandling\DataHandler $parentObj : The parent object that triggered this hook - * @param array|boolean $pasteUpdate : Values to be updated after the record is pasted - * - * @return void + * @param string $command The command to be handled by the command map + * @param string $table The name of the table we are working on + * @param int $id The id of the record that is going to be copied + * @param string $value The value that has been sent with the copy command + * @param bool $commandIsProcessed A switch to tell the parent object, if the record has been copied + * @param DataHandler $parentObj The parent object that triggered this hook + * @param array|bool $pasteUpdate Values to be updated after the record is pasted */ public function execute_processCmdmap( $command, @@ -50,10 +49,9 @@ public function execute_processCmdmap( $id, $value, &$commandIsProcessed, - \TYPO3\CMS\Core\DataHandling\DataHandler &$parentObj = null, + DataHandler $parentObj = null, $pasteUpdate ) { - $this->init($table, $id, $parentObj); $reference = (int)GeneralUtility::_GET('reference'); @@ -85,6 +83,8 @@ public function execute_processCmdmap( $this->getTceMain()->start($data, array()); $this->getTceMain()->process_datamap(); + $parentObj->registerDBList = null; + $parentObj->remapStack = null; $commandIsProcessed = true; } @@ -93,9 +93,10 @@ public function execute_processCmdmap( $containerUpdateArray = array(); $originalContainer = $this->databaseConnection->exec_SELECTgetSingleRow('tx_gridelements_container, sys_language_uid', 'tt_content', 'uid=' . $id); - $containerUpdateArray[$originalContainer['tx_gridelements_container']] = -1; - $this->doGridContainerUpdate($containerUpdateArray); + if (!empty($originalContainer)) { + $containerUpdateArray[$originalContainer['tx_gridelements_container']] = -1; + $this->doGridContainerUpdate($containerUpdateArray); + } } - } } \ No newline at end of file diff --git a/Classes/Helper/Helper.php b/Classes/Helper/Helper.php index 58efd4e..356a6f4 100644 --- a/Classes/Helper/Helper.php +++ b/Classes/Helper/Helper.php @@ -21,7 +21,8 @@ use TYPO3\CMS\Core\Database\DatabaseConnection; use TYPO3\CMS\Core\SingletonInterface; -use TYPO3\CMS\Core\Utility\DebugUtility; +use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Backend\View\BackendLayoutView; /** * Gridelements helper class @@ -32,12 +33,6 @@ */ class Helper implements SingletonInterface { - - /** - * @var DatabaseConnection - */ - protected static $databaseConnection; - /** * Local instance of the helper * @@ -45,18 +40,22 @@ class Helper implements SingletonInterface */ protected static $instance = null; + /** + * @var DatabaseConnection + */ + protected $databaseConnection; + /** * Get instance from the class. * - * @static - * @return Helper + * @return Helper */ public static function getInstance() { if (!self::$instance instanceof Helper) { self::$instance = new self(); + self::$instance->setDatabaseConnection($GLOBALS['TYPO3_DB']); } - self::setDatabaseConnection($GLOBALS['TYPO3_DB']); return self::$instance; } @@ -65,31 +64,27 @@ public static function getInstance() * setter for databaseConnection object * * @param DatabaseConnection $databaseConnection - * - * @return void */ - public static function setDatabaseConnection(DatabaseConnection $databaseConnection) + public function setDatabaseConnection(DatabaseConnection $databaseConnection) { - self::$databaseConnection = $databaseConnection; + $this->databaseConnection = $databaseConnection; } - + /** * @param string $table * @param int $uid + * @param int $pid * @param string $sortingField * @param int $sortRev * @param string $selectFieldList - * * @return array */ - public function getChildren($table = '', $uid = 0, $sortingField = '', $sortRev = 0, $selectFieldList) + public function getChildren($table = '', $uid = 0, $pid = 0, $sortingField = '', $sortRev = 0, $selectFieldList) { $retVal = array(); if (trim($table) === 'tt_content' && $uid > 0) { - - $children = self::getDatabaseConnection()->exec_SELECTgetRows($selectFieldList, 'tt_content', - 'tx_gridelements_container = ' . (int)$uid . ' AND deleted = 0', ''); + $children = self::getDatabaseConnection()->exec_SELECTgetRows($selectFieldList, 'tt_content', 'tx_gridelements_container = ' . (int)$uid . ' AND pid = ' . (int)$pid . ' AND deleted = 0', ''); foreach ($children as $child) { if (trim($sortingField) && isset($child[$sortingField]) && $sortingField !== 'sorting') { @@ -97,8 +92,7 @@ public function getChildren($table = '', $uid = 0, $sortingField = '', $sortRev } else { $sortField = sprintf('%1$011d', $child['sorting']); } - $sortKey = sprintf('%1$011d', - $child['tx_gridelements_columns']) . '.' . $sortField . ':' . sprintf('%1$011d', $child['uid']); + $sortKey = sprintf('%1$011d', $child['tx_gridelements_columns']) . '.' . $sortField . ':' . sprintf('%1$011d', $child['uid']); $retVal[$sortKey] = $child; } @@ -113,32 +107,17 @@ public function getChildren($table = '', $uid = 0, $sortingField = '', $sortRev } /** - * converts a negative tt_content uid into a positive pid + * converts a tt_content uid into a pid * - * @param int $negativeUid the negative uid value of a tt_content record + * @param int $uid the uid value of a tt_content record * * @return int */ - public function getPidFromNegativeUid($negativeUid = 0) + public function getPidFromUid($uid = 0) { - if ($negativeUid >= 0) { - return $negativeUid; - } else { - $triggerElement = self::$databaseConnection->exec_SELECTgetSingleRow('pid', 'tt_content', - 'uid = ' . abs($negativeUid)); - $pid = (int)$triggerElement['pid']; - return is_array($triggerElement) && $pid ? $pid : 0; - } - } - - /** - * getter for databaseConnection - * - * @return DatabaseConnection databaseConnection - */ - public function getDatabaseConnection() - { - return self::$databaseConnection; + $triggerElement = $this->databaseConnection->exec_SELECTgetSingleRow('pid', 'tt_content', 'uid = ' . abs($uid)); + $pid = (int)$triggerElement['pid']; + return is_array($triggerElement) && $pid ? $pid : 0; } /** @@ -148,7 +127,7 @@ public function getDatabaseConnection() * * @param array $record Overlaid record data * - * @return integer + * @return int[] */ public function getSpecificIds(array $record) { @@ -164,6 +143,49 @@ public function getSpecificIds(array $record) return $specificIds; } + /** + * @param $id + * @return mixed + */ + public function getSelectedBackendLayout($id) { + $backendLayoutData = GeneralUtility::callUserFunction(BackendLayoutView::class . '->getSelectedBackendLayout', $id, $this); + // add allowed CTypes to the columns, since this is not done by the native core methods + if (!empty($backendLayoutData['__items'])) { + if (!empty($backendLayoutData['__config']['backend_layout.']['rows.'])) { + foreach ($backendLayoutData['__config']['backend_layout.']['rows.'] as $row) { + if (!empty($row['columns.'])) { + foreach ($row['columns.'] as $column) { + $backendLayoutData['columns'][$column['colPos']] = $column['allowed'] ? $column['allowed'] : '*'; + $backendLayoutData['columns']['allowed'] .= $backendLayoutData['columns']['allowed'] + ? ',' . $backendLayoutData['columns'][$column['colPos']] + : $backendLayoutData['columns'][$column['colPos']]; + if ($column['allowedGridTypes']) { + $backendLayoutData['columns']['allowedGridTypes'][$column['colPos']] .= $backendLayoutData['columns']['allowedGridTypes'][$column['colPos']] + ? ',' . $column['allowedGridTypes'] + : $column['allowedGridTypes']; + } + } + } + } + } + foreach ($backendLayoutData['__items'] as $key => $item) { + $backendLayoutData['__items'][$key][3] = $backendLayoutData['columns'][$item[1]]; + } + }; + + return $backendLayoutData; + } + + /** + * getter for databaseConnection + * + * @return DatabaseConnection databaseConnection + */ + public function getDatabaseConnection() + { + return $this->databaseConnection; + } + /** * Gets the current backend user. * @@ -173,5 +195,4 @@ public function getBackendUser() { return $GLOBALS['BE_USER']; } - } diff --git a/Classes/Hooks/AbstractDatabaseRecordList.php b/Classes/Hooks/AbstractDatabaseRecordList.php index f0ba78e..04e794b 100644 --- a/Classes/Hooks/AbstractDatabaseRecordList.php +++ b/Classes/Hooks/AbstractDatabaseRecordList.php @@ -33,17 +33,14 @@ */ class AbstractDatabaseRecordList implements SingletonInterface { - /** * ItemProcFunc for columns items * - * @param array $queryParts : The array containing the parts to build the query from - * @param DatabaseRecordList $parent : The parent object that triggered this hook - * @param string $table : The name of the table we are currently working on - * - * @return void + * @param array $queryParts The array containing the parts to build the query from + * @param $parent The parent object that triggered this hook + * @param string $table The name of the table we are currently working on */ - public function makeQueryArray_post(&$queryParts, &$parent, $table) + public function makeQueryArray_post(array &$queryParts, $parent, $table) { if ($table === 'tt_content' && $parent instanceof \GridElementsTeam\Gridelements\Xclass\DatabaseRecordList) { $queryParts['ORDERBY'] = $this->addValueToList($queryParts['ORDERBY'], 'colPos'); diff --git a/Classes/Hooks/BackendUtilityGridelements.php b/Classes/Hooks/BackendUtilityGridelements.php index e1cc483..adb183d 100644 --- a/Classes/Hooks/BackendUtilityGridelements.php +++ b/Classes/Hooks/BackendUtilityGridelements.php @@ -35,7 +35,6 @@ */ class BackendUtilityGridelements { - /** * @var DatabaseConnection */ @@ -50,8 +49,6 @@ class BackendUtilityGridelements * inject layout setup * * @param LayoutSetup $layoutSetup - * - * @return void */ public function injectLayoutSetup(LayoutSetup $layoutSetup) { @@ -61,17 +58,12 @@ public function injectLayoutSetup(LayoutSetup $layoutSetup) /** * initializes this class * - * @param integer $pageUid - * - * @return void + * @param int $pageUid */ public function init($pageUid) { $this->setDatabaseConnection($GLOBALS['TYPO3_DB']); if (!$this->layoutSetup instanceof LayoutSetup) { - if ($pageUid < 0) { - $pageUid = Helper::getInstance()->getPidFromNegativeUid($pageUid); - } $this->injectLayoutSetup(GeneralUtility::makeInstance(LayoutSetup::class)->init($pageUid)); } } @@ -80,15 +72,13 @@ public function init($pageUid) * Overwrites the data structure of a given tt_content::pi_flexform by * by the one matching the gridelements layout. * - * @param array $dataStructureArray The incoming data structure. This might be the default one. + * @param array|string $dataStructureArray The incoming data structure. This might be the default one. * @param array $conf * @param array $row * @param string $table * @param string $fieldName - * - * @return void */ - public function getFlexFormDS_postProcessDS(&$dataStructureArray, $conf, $row, $table, $fieldName) + public function getFlexFormDS_postProcessDS(&$dataStructureArray, array $conf, array $row, $table, $fieldName) { if ($table === 'tt_content' && $fieldName === 'pi_flexform' && $row['CType'] === 'gridelements_pi1' && $row['tx_gridelements_backend_layout']) { $this->init($row['pid']); @@ -117,5 +107,4 @@ public function getDatabaseConnection() { return $this->databaseConnection; } - -} \ No newline at end of file +} diff --git a/Classes/Hooks/DataHandler.php b/Classes/Hooks/DataHandler.php index 79c719a..e2dae8e 100644 --- a/Classes/Hooks/DataHandler.php +++ b/Classes/Hooks/DataHandler.php @@ -20,8 +20,8 @@ ***************************************************************/ use GridElementsTeam\Gridelements\DataHandler\AfterDatabaseOperations; -use GridElementsTeam\Gridelements\DataHandler\MoveRecord; use GridElementsTeam\Gridelements\DataHandler\PreProcessFieldArray; +use GridElementsTeam\Gridelements\DataHandler\ProcessCmdmap; use TYPO3\CMS\Core\Database\DatabaseConnection; use TYPO3\CMS\Core\SingletonInterface; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -35,7 +35,6 @@ */ class DataHandler implements SingletonInterface { - /** * @var DatabaseConnection */ @@ -91,9 +90,12 @@ public function processDatamap_afterDatabaseOperations( &$fieldArray, \TYPO3\CMS\Core\DataHandling\DataHandler $parentObj ) { - if (($table === 'tt_content' || $table === 'pages') && $status === 'update' && !$parentObj->isImporting) { - /** @var $hook AfterDatabaseOperations */ + if (($table === 'tt_content' || $table === 'pages') && !$parentObj->isImporting) { + /** @var AfterDatabaseOperations $hook */ $hook = GeneralUtility::makeInstance(AfterDatabaseOperations::class); + if (strpos($id, 'NEW') !== false) { + $id = $parentObj->substNEWwithIDs[$id]; + }; $hook->execute_afterDatabaseOperations($fieldArray, $table, $id, $parentObj); } } @@ -101,15 +103,13 @@ public function processDatamap_afterDatabaseOperations( /** * Function to process the drag & drop copy action * - * @param string $command : The command to be handled by the command map - * @param string $table : The name of the table we are working on - * @param int $id : The id of the record that is going to be copied - * @param string $value : The value that has been sent with the copy command - * @param boolean $commandIsProcessed : A switch to tell the parent object, if the record has been copied - * @param \TYPO3\CMS\Core\DataHandling\DataHandler $parentObj : The parent object that triggered this hook - * @param array|boolean $pasteUpdate : Values to be updated after the record is pasted - * - * @return void + * @param string $command The command to be handled by the command map + * @param string $table The name of the table we are working on + * @param int $id The id of the record that is going to be copied + * @param string $value The value that has been sent with the copy command + * @param boolean $commandIsProcessed A switch to tell the parent object, if the record has been copied + * @param \TYPO3\CMS\Core\DataHandling\DataHandler $parentObj The parent object that triggered this hook + * @param array|bool $pasteUpdate Values to be updated after the record is pasted */ public function processCmdmap( $command, @@ -120,9 +120,9 @@ public function processCmdmap( \TYPO3\CMS\Core\DataHandling\DataHandler &$parentObj, $pasteUpdate ) { - /** @var $hook \GridElementsTeam\Gridelements\DataHandler\ProcessCmdmap */ if (!$parentObj->isImporting) { - $hook = GeneralUtility::makeInstance('GridElementsTeam\\Gridelements\\DataHandler\\ProcessCmdmap'); + /** @var ProcessCmdmap $hook */ + $hook = GeneralUtility::makeInstance(ProcessCmdmap::class); $hook->execute_processCmdmap($command, $table, $id, $value, $commandIsProcessed, $parentObj, $pasteUpdate); } } @@ -131,8 +131,6 @@ public function processCmdmap( * setter for databaseConnection object * * @param DatabaseConnection $databaseConnection - * - * @return void */ public function setDatabaseConnection(DatabaseConnection $databaseConnection) { @@ -148,5 +146,4 @@ public function getDatabaseConnection() { return $this->databaseConnection; } - } \ No newline at end of file diff --git a/Classes/Hooks/DatabaseRecordList.php b/Classes/Hooks/DatabaseRecordList.php index bb134e1..250656f 100644 --- a/Classes/Hooks/DatabaseRecordList.php +++ b/Classes/Hooks/DatabaseRecordList.php @@ -20,6 +20,7 @@ ***************************************************************/ use GridElementsTeam\Gridelements\Helper\Helper; +use GridElementsTeam\Gridelements\Xclass\DatabaseRecordList as DatabaseRecordListXclass; use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; use TYPO3\CMS\Core\Imaging\IconFactory; use TYPO3\CMS\Core\SingletonInterface; @@ -37,7 +38,6 @@ */ class DatabaseRecordList implements RecordListHookInterface, SingletonInterface { - /** * @var Iconfactory */ @@ -48,31 +48,26 @@ class DatabaseRecordList implements RecordListHookInterface, SingletonInterface */ protected $languageService; + /** + * DatabaseRecordList constructor. + */ public function __construct() { $this->setLanguageService($GLOBALS['LANG']); } - /** * modifies Web>List clip icons (copy, cut, paste, etc.) of a displayed row * * @param string $table the current database table * @param array $row the current record row * @param array $cells the default clip-icons to get modified - * @param object $parentObject Instance of calling object + * @param DatabaseRecordList $parentObject Instance of calling object (by ref due to interface) * * @return array the modified clip-icons */ public function makeClip($table, $row, $cells, &$parentObject) { - - /*if ($table == 'tt_content' && get_class($parentObject) == 'localRecordList') { - if((int)$row['colPos'] < 0)) { - $cells['pasteInto'] = $parentObject->spaceIcon; - $cells['pasteAfter'] = $parentObject->spaceIcon; - } - }*/ if ($table === 'tt_content') { $cells['moveUp'] = ''; } @@ -86,21 +81,12 @@ public function makeClip($table, $row, $cells, &$parentObject) * @param string $table the current database table * @param array $row the current record row * @param array $cells the default control-icons to get modified - * @param object $parentObject Instance of calling object + * @param DatabaseRecordList $parentObject Instance of calling object (by ref due to interface) * * @return array the modified control-icons */ public function makeControl($table, $row, $cells, &$parentObject) { - /*if ($table == 'tt_content' && get_class($parentObject) == 'localRecordList') { - if((int)$row['colPos'] < 0) { - $cells['move'] = $parentObject->spaceIcon; - $cells['new'] = $parentObject->spaceIcon; - $cells['moveUp'] = $parentObject->spaceIcon; - $cells['moveDown'] = $parentObject->spaceIcon; - } - }*/ - return $cells; } @@ -110,7 +96,7 @@ public function makeControl($table, $row, $cells, &$parentObject) * @param string $table the current database table * @param array $currentIdList Array of the currently displayed uids of the table * @param array $headerColumns An array of rendered cells/columns - * @param object $parentObject Instance of calling (parent) object + * @param DatabaseRecordList $parentObject Instance of calling object (by ref due to interface) * * @return array Array of modified cells/columns */ @@ -125,7 +111,7 @@ public function renderListHeader($table, $currentIdList, $headerColumns, &$paren * @param string $table the current database table * @param array $currentIdList Array of the currently displayed uids of the table * @param array $cells An array of the current clipboard/action icons - * @param object $parentObject Instance of calling (parent) object + * @param DatabaseRecordList $parentObject Instance of calling object (by ref due to interface) * * @return array Array of modified clipboard/action icons */ @@ -141,12 +127,12 @@ public function renderListHeaderActions($table, $currentIdList, $cells, &$parent * @param array $row * @param int $level * @param array $theData - * @param \GridElementsTeam\Gridelements\Xclass\DatabaseRecordList $parentObj + * @param DatabaseRecordListXclass $parentObj */ - public function checkChildren($table, $row, $level, &$theData, $parentObj) + public function checkChildren($table, array $row, $level, array &$theData, DatabaseRecordListXclass $parentObj) { if ($table === 'tt_content' && $row['CType'] === 'gridelements_pi1') { - $elementChildren = Helper::getInstance()->getChildren($table, $row['uid'], '', 0, $parentObj->selFieldList); + $elementChildren = Helper::getInstance()->getChildren($table, $row['uid'], $row['pid'], '', 0, $parentObj->selFieldList); if (!empty($elementChildren)) { $theData['_EXPANDABLE_'] = true; $theData['_EXPAND_ID_'] = $table . ':' . $row['uid']; @@ -164,9 +150,9 @@ public function checkChildren($table, $row, $level, &$theData, $parentObj) * @param string $sortField * @param int $level * @param string $contentCollapseIcon - * @param DatabaseRecordList $parentObj + * @param DatabaseRecordListXclass $parentObj */ - public function contentCollapseIcon(&$data, $sortField, $level, &$contentCollapseIcon, $parentObj) + public function contentCollapseIcon(array &$data, $sortField, $level, &$contentCollapseIcon, DatabaseRecordListXclass $parentObj) { if ($data['_EXPAND_TABLE_'] === 'tt_content') { $expandTitle = $this->languageService->sL('LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xlf:list.expandElement'); @@ -174,20 +160,18 @@ public function contentCollapseIcon(&$data, $sortField, $level, &$contentCollaps $expandedGridelements = $parentObj->getExpandedGridelements(); if ($expandedGridelements[$data['uid']]) { $href = htmlspecialchars(($parentObj->listURL() . '&gridelementsExpand[' . (int)$data['uid'] . ']=0')); - $contentCollapseIcon = '' . $this->getIconFactory()->getIcon('actions-view-list-expand', - 'small')->render() . $this->getIconFactory()->getIcon('actions-view-list-collapse', - 'small')->render() . ''; + $contentCollapseIcon = '' + . $this->getIconFactory()->getIcon('actions-view-list-expand', 'small')->render() + . $this->getIconFactory()->getIcon('actions-view-list-collapse', 'small')->render() . ''; } else { $href = htmlspecialchars(($parentObj->listURL() . '&gridelementsExpand[' . (int)$data['uid'] . ']=1')); - $contentCollapseIcon = '' . $this->getIconFactory()->getIcon('actions-view-list-expand', - 'small')->render() . $this->getIconFactory()->getIcon('actions-view-list-collapse', - 'small')->render() . ''; + $contentCollapseIcon = '' + . $this->getIconFactory()->getIcon('actions-view-list-expand', 'small')->render() + . $this->getIconFactory()->getIcon('actions-view-list-collapse', 'small')->render() . ''; } } } @@ -206,8 +190,6 @@ public function getLanguageService() * setter for databaseConnection object * * @param LanguageService $languageService - * - * @return void */ public function setLanguageService(LanguageService $languageService) @@ -234,5 +216,4 @@ public function getIconFactory() return $this->iconFactory; } - } diff --git a/Classes/Hooks/DrawItem.php b/Classes/Hooks/DrawItem.php index bf3710c..9908cf8 100644 --- a/Classes/Hooks/DrawItem.php +++ b/Classes/Hooks/DrawItem.php @@ -21,9 +21,12 @@ use GridElementsTeam\Gridelements\Backend\LayoutSetup; use GridElementsTeam\Gridelements\Helper\Helper; +use TYPO3\CMS\Backend\Controller\PageLayoutController; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Backend\View\PageLayoutView; +use TYPO3\CMS\Backend\View\PageLayoutViewDrawFooterHookInterface; use TYPO3\CMS\Backend\View\PageLayoutViewDrawItemHookInterface; +use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; use TYPO3\CMS\Core\Database\DatabaseConnection; use TYPO3\CMS\Core\Database\QueryGenerator; use TYPO3\CMS\Core\Database\ReferenceIndex; @@ -47,6 +50,11 @@ class DrawItem implements PageLayoutViewDrawItemHookInterface, SingletonInterface { + /** + * @var array + */ + protected $extentensionConfiguration; + /** * @var Helper */ @@ -86,6 +94,7 @@ class DrawItem implements PageLayoutViewDrawItemHookInterface, SingletonInterfac public function __construct() { + $this->extentensionConfiguration = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['gridelements']); $this->setDatabaseConnection($GLOBALS['TYPO3_DB']); $this->setLanguageService($GLOBALS['LANG']); $this->helper = Helper::getInstance(); @@ -149,7 +158,7 @@ public function preProcess(PageLayoutView &$parentObject, &$drawItem, &$headerCo } } $gridType = $row['tx_gridelements_backend_layout'] ? ' data-gridtype="' . $row['tx_gridelements_backend_layout'] . '"' : ''; - $headerContent = '
' . $headerContent . '
'; + $headerContent = '
' . $headerContent . '
'; } /** @@ -206,7 +215,7 @@ public function renderCTypeGridelements(PageLayoutView $parentObject, &$row, &$s // if we got a selected backend layout, we have to create the layout table now if ($layoutUid && isset($layout['config'])) { - $itemContent = $this->renderGridLayoutTable($layout, $gridElement, $head, $gridContent); + $itemContent = $this->renderGridLayoutTable($layout, $gridElement, $head, $gridContent, $parentObject); } else { $itemContent = '
'; $itemContent .= ''; @@ -237,9 +246,9 @@ public function renderCTypeShortcut(PageLayoutView $parentObject, &$row, &$showH $shortcutItem = trim($shortcutItem); if (strpos($shortcutItem, 'pages_') !== false) { $this->collectContentDataFromPages($shortcutItem, $collectedItems, $row['recursive'], $showHidden, - $deleteClause, $row['uid']); + $deleteClause, $row['uid'], $row['sys_language_uid']); } else if (strpos($shortcutItem, '_') === false || strpos($shortcutItem, 'tt_content_') !== false) { - $this->collectContentData($shortcutItem, $collectedItems, $showHidden, $deleteClause, $row['uid']); + $this->collectContentData($shortcutItem, $collectedItems, $showHidden, $deleteClause, $row['uid'], $row['sys_language_uid']); } } if (!empty($collectedItems)) { @@ -447,21 +456,26 @@ protected function renderSingleGridColumn( $url = ''; $pageinfo = BackendUtility::readPageAccess($parentObject->id, ''); + if (get_class($this->getPageLayoutController()) === PageLayoutController::class) { + $contentIsNotLockedForEditors = $this->getPageLayoutController()->contentIsNotLockedForEditors(); + } else { + $contentIsNotLockedForEditors = true; + } if ($colPos < 32768) { - if ($this->getPageLayoutController()->pageIsNotLockedForEditors() + if ($contentIsNotLockedForEditors && $this->getBackendUser()->doesUserHaveAccess($pageinfo, Permission::CONTENT_EDIT) && (!$this->checkIfTranslationsExistInLanguage($items, $row['sys_language_uid'], $parentObject)) ) { if ($parentObject->option_newWizard) { $urlParameters = [ 'id' => $parentObject->id, - 'colPos' => -1, + 'sys_language_uid' => $row['sys_language_uid'], 'tx_gridelements_allowed' => $values['allowed'], 'tx_gridelements_allowed_grid_types' => $values['allowedGridTypes'], 'tx_gridelements_container' => $specificIds['uid'], 'tx_gridelements_columns' => $colPos, + 'colPos' => -1, 'uid_pid' => $parentObject->id, - 'sys_language_uid' => $row['sys_language_uid'], 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI') ]; $url = BackendUtility::getModuleUrl('new_content_element', $urlParameters); @@ -474,12 +488,12 @@ protected function renderSingleGridColumn( ], 'defVals' => [ 'tt_content' => [ - 'colPos' => -1, + 'sys_language_uid' => $row['sys_language_uid'], 'tx_gridelements_allowed' => $values['allowed'], 'tx_gridelements_allowed_grid_types' => $values['allowedGridTypes'], 'tx_gridelements_container' => $specificIds['uid'], 'tx_gridelements_columns' => $colPos, - 'sys_language_uid' => $row['sys_language_uid'] + 'colPos' => -1 ] ], 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI') @@ -519,11 +533,10 @@ protected function renderSingleGridColumn( if (is_array($itemRow)) { $statusHidden = $parentObject->isDisabled('tt_content', $itemRow) ? ' t3-page-ce-hidden' : ''; $gridContent[$colPos] .= ' -
' . $this->renderSingleElementHTML($parentObject, $itemRow) . '
'; - $url = ''; - if ($this->getPageLayoutController()->pageIsNotLockedForEditors() + if ($contentIsNotLockedForEditors && $this->getBackendUser()->doesUserHaveAccess($pageinfo, Permission::CONTENT_EDIT) && (!$this->checkIfTranslationsExistInLanguage($items, $row['sys_language_uid'], $parentObject)) ) { @@ -535,6 +548,8 @@ protected function renderSingleGridColumn( 'sys_language_uid' => $itemRow['sys_language_uid'], 'tx_gridelements_allowed' => $values['allowed'], 'tx_gridelements_allowed_grid_types' => $values['allowedGridTypes'], + 'tx_gridelements_container' => $itemRow['tx_gridelements_container'], + 'tx_gridelements_columns' => $itemRow['tx_gridelements_columns'], 'colPos' => -1, 'uid_pid' => -$specificIds['uid'], 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI') @@ -550,9 +565,11 @@ protected function renderSingleGridColumn( 'defVals' => [ 'tt_content' => [ 'sys_language_uid' => $itemRow['sys_language_uid'], - 'colPos' => -1, 'tx_gridelements_allowed' => $values['allowed'], - 'tx_gridelements_allowed_grid_types' => $values['allowedGridTypes'] + 'tx_gridelements_allowed_grid_types' => $values['allowedGridTypes'], + 'tx_gridelements_container' => $itemRow['tx_gridelements_container'], + 'tx_gridelements_columns' => $itemRow['tx_gridelements_columns'], + 'colPos' => -1 ] ], 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI') @@ -654,16 +671,17 @@ public function tt_content_drawColHeader($colName, $editParams, PageLayoutView $ * @param array $row : The current data row for the container item * @param array $head : The data for the column headers of the grid we are going to render * @param array $gridContent : The content data of the grid we are going to render + * @param PageLayoutView $parentObject * * @return string */ - public function renderGridLayoutTable($layoutSetup, $row, $head, $gridContent) + public function renderGridLayoutTable($layoutSetup, $row, $head, $gridContent, PageLayoutView $parentObject) { $specificIds = $this->helper->getSpecificIds($row); - $grid = '
'; - if ($layoutSetup['frame'] || $this->helper->getBackendUser()->uc['showGridInformation'] === 1) { - $grid .= '

' . BackendUtility::wrapInHelp('tx_gridelements_backend_layouts', + $grid = '
'; + if ($layoutSetup['frame'] || (int)$this->helper->getBackendUser()->uc['showGridInformation'] === 1) { + $grid .= '

' . BackendUtility::wrapInHelp('tx_gridelements_backend_layouts', 'title', $this->languageService->sL($layoutSetup['title']), array( 'title' => $this->languageService->sL($layoutSetup['title']), 'description' => $this->languageService->sL($layoutSetup['description']) @@ -702,6 +720,7 @@ public function renderGridLayoutTable($layoutSetup, $row, $head, $gridContent) $columnKey = isset($columnConfig['colPos']) && $columnConfig['colPos'] !== '' ? (int)$columnConfig['colPos'] : 32768; // allowed CTypes $allowedContentTypes = array(); + $allowedGridTypes = array(); if (!empty($columnConfig['allowed'])) { $allowedContentTypes = array_flip(GeneralUtility::trimExplode(',', $columnConfig['allowed'])); if (!isset($allowedContentTypes['*'])) { @@ -716,9 +735,8 @@ public function renderGridLayoutTable($layoutSetup, $row, $head, $gridContent) $allowedGridTypes = array_flip(GeneralUtility::trimExplode(',', $columnConfig['allowedGridTypes'])); if (!isset($allowedGridTypes['*']) && !empty($allowedGridTypes)) { foreach ($allowedGridTypes as $gridType => &$gridTypeClass) { - $gridTypeClass = 't3-allow-gridtype t3-allow-gridtype-' . $gridType; + $gridTypeClass = 't3-allow-gridtype-' . $gridType; } - $allowedContentTypes['gridelements_pi1'] = 't3-allow-gridelements_pi1'; } else { if (!empty($allowedContentTypes)) { $allowedContentTypes['gridelements_pi1'] = 't3-allow-gridelements_pi1'; @@ -730,12 +748,17 @@ public function renderGridLayoutTable($layoutSetup, $row, $head, $gridContent) $colSpan = (int)$columnConfig['colspan']; $rowSpan = (int)$columnConfig['rowspan']; $expanded = $this->helper->getBackendUser()->uc['moduleData']['page']['gridelementsCollapsedColumns'][$row['uid'] . '_' . $columnKey] ? 'collapsed' : 'expanded'; + if (!empty($columnConfig['name']) && $columnKey === 32768) { + $columnHead = $this->tt_content_drawColHeader(htmlspecialchars($columnConfig['name']) . ' (' . $this->languageService->getLL('notAssigned') . ')', '', $parentObject); + } else { + $columnHead = $head[$columnKey]; + } $grid .= '

'; } $grid .= ''; @@ -754,6 +777,7 @@ class="t3-grid-cell t3js-page-column t3-page-column t3-page-column-' . $columnKe * @param string $showHidden : query String containing enable fields * @param string $deleteClause : query String to check for deleted items * @param int $parentUid : uid of the referencing tt_content record + * @param int $language : sys_language_uid of the referencing tt_content record * * @return void */ @@ -763,7 +787,8 @@ public function collectContentDataFromPages( $recursive = 0, &$showHidden, &$deleteClause, - $parentUid + $parentUid, + $language = 0 ) { $itemList = str_replace('pages_', '', $shortcutItem); if ($recursive) { @@ -774,8 +799,14 @@ public function collectContentDataFromPages( } $itemRows = $this->databaseConnection->exec_SELECTgetRows('*', 'tt_content', 'uid != ' . (int)$parentUid . ' AND pid IN (' . $itemList . ') AND colPos >= 0 ' . $showHidden . $deleteClause, - '', 'FIND_IN_SET(pid, \'' . $itemList . '\'),colPos,sorting'); + '', 'sys_language_uid IN (0,-1) AND FIND_IN_SET(pid, \'' . $itemList . '\'),colPos,sorting'); foreach ($itemRows as $itemRow) { + if (!empty($this->extentensionConfiguration['overlayShortcutTranslation']) && $language > 0) { + $translatedItem = BackendUtility::getRecordLocalization('tt_content', $itemRow['uid'], $language); + if (!empty($translatedItem)) { + $itemRow = array_shift($translatedItem); + } + } if ($this->helper->getBackendUser()->workspace > 0) { BackendUtility::workspaceOL('tt_content', $itemRow, $this->helper->getBackendUser()->workspace); } @@ -792,15 +823,22 @@ public function collectContentDataFromPages( * @param string $showHidden : query String containing enable fields * @param string $deleteClause : query String to check for deleted items * @param int $parentUid : uid of the referencing tt_content record + * @param int $language : sys_language_uid of the referencing tt_content record * * @return void */ - public function collectContentData($shortcutItem, &$collectedItems, &$showHidden, &$deleteClause, $parentUid) + public function collectContentData($shortcutItem, &$collectedItems, &$showHidden, &$deleteClause, $parentUid, $language = 0) { $shortcutItem = str_replace('tt_content_', '', $shortcutItem); if ((int)$shortcutItem !== (int)$parentUid) { $itemRow = $this->databaseConnection->exec_SELECTgetSingleRow('*', 'tt_content', 'uid=' . (int)$shortcutItem . $showHidden . $deleteClause); + if (!empty($this->extentensionConfiguration['overlayShortcutTranslation']) && $language > 0) { + $translatedItem = BackendUtility::getRecordLocalization('tt_content', $itemRow['uid'], $language); + if (!empty($translatedItem)) { + $itemRow = array_shift($translatedItem); + } + } if ($this->helper->getBackendUser()->workspace > 0) { BackendUtility::workspaceOL('tt_content', $itemRow, $this->helper->getBackendUser()->workspace); } @@ -822,23 +860,54 @@ public function renderSingleElementHTML(PageLayoutView $parentObject, $itemRow) $singleElementHTML = $parentObject->tt_content_drawHeader($itemRow, $parentObject->tt_contentConfig['showInfo'] ? 15 : 5, $parentObject->defLangBinding, true, true); $singleElementHTML .= '
' . $parentObject->tt_content_drawItem($itemRow) . '
'; - $footerContent = ''; + $singleElementHTML .= $this->tt_content_drawFooter($parentObject, $itemRow); + + return $singleElementHTML; + } + + /** + * Draw the footer for a single tt_content element + * + * @param PageLayoutView $parentObject : The parent object that triggered this hook + * @param array $row Record array + * @return string HTML of the footer + * @throws \UnexpectedValueException + */ + protected function tt_content_drawFooter(PageLayoutView $parentObject, array $row) + { + $content = ''; // Get processed values: - $info = array(); - $parentObject->getProcessedValue('tt_content', 'starttime,endtime,fe_group,spaceBefore,spaceAfter', $itemRow, - $info); + $info = []; + $parentObject->getProcessedValue('tt_content', 'starttime,endtime,fe_group,spaceBefore,spaceAfter', $row, $info); + + // Content element annotation + if (!empty($GLOBALS['TCA']['tt_content']['ctrl']['descriptionColumn'])) { + $info[] = htmlspecialchars($row[$GLOBALS['TCA']['tt_content']['ctrl']['descriptionColumn']]); + } + + // Call drawFooter hooks + $drawFooterHooks = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/class.tx_cms_layout.php']['tt_content_drawFooter']; + if (is_array($drawFooterHooks)) { + foreach ($drawFooterHooks as $hookClass) { + $hookObject = GeneralUtility::getUserObj($hookClass); + if (!$hookObject instanceof PageLayoutViewDrawFooterHookInterface) { + throw new \UnexpectedValueException($hookClass . ' must implement interface ' . PageLayoutViewDrawFooterHookInterface::class, 1404378171); + } + $hookObject->preProcess($parentObject, $info, $row); + } + } + // Display info from records fields: if (!empty($info)) { - $footerContent = '
- ' . implode('
', $info) . ' + $content = '
+ ' . implode('
', $info) . '
'; } // Wrap it - if (!empty($footerContent)) { - $singleElementHTML .= ''; + if (!empty($content)) { + $content = ''; } - - return $singleElementHTML; + return $content; } /** diff --git a/Classes/Hooks/PreHeaderRenderHook.php b/Classes/Hooks/ExtTablesInclusionPostProcessing.php similarity index 61% rename from Classes/Hooks/PreHeaderRenderHook.php rename to Classes/Hooks/ExtTablesInclusionPostProcessing.php index 73fa500..3fd17ef 100644 --- a/Classes/Hooks/PreHeaderRenderHook.php +++ b/Classes/Hooks/ExtTablesInclusionPostProcessing.php @@ -19,24 +19,25 @@ * This copyright notice MUST APPEAR in all copies of the script! ***************************************************************/ -use TYPO3\CMS\Core\SingletonInterface; +use TYPO3\CMS\Core\Database\TableConfigurationPostProcessingHookInterface; use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; /** - * Class PreHeaderRenderHook + * Class ExtTablesInclusionPostProcessing * * @package GridElementsTeam\Gridelements\Hooks */ -class PreHeaderRenderHook implements SingletonInterface +class ExtTablesInclusionPostProcessing implements TableConfigurationPostProcessingHookInterface { - /** - * @param array $arg + * Function which may process data created / registered by extTables + * scripts (f.e. modifying TCA data of all extensions) + * + * @return void */ - function main($arg) + function processData() { - /** @var $pagerenderer \TYPO3\CMS\Core\Page\PageRenderer */ - $pagerenderer = $arg['pageRenderer']; - $pagerenderer->addCssFile($GLOBALS['BACK_PATH'] . ExtensionManagementUtility::extRelPath('gridelements') . 'Resources/Public/Backend/Css/Skin/t3skin_override.css'); + ExtensionManagementUtility::addToAllTCAtypes('tt_content', 'recursive', 'shortcut', 'after:records'); + ExtensionManagementUtility::addToAllTCAtypes('tt_content', '--div--;LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xlf:gridElements, tx_gridelements_container, tx_gridelements_columns'); } } diff --git a/Classes/Hooks/PageRenderer.php b/Classes/Hooks/PageRenderer.php index aca2fd9..8fd91a9 100644 --- a/Classes/Hooks/PageRenderer.php +++ b/Classes/Hooks/PageRenderer.php @@ -20,12 +20,15 @@ ***************************************************************/ use TYPO3\CMS\Backend\Clipboard\Clipboard; +use TYPO3\CMS\Backend\Controller\PageLayoutController; use TYPO3\CMS\Backend\Utility\BackendUtility; +use TYPO3\CMS\Backend\View\BackendLayoutView; use TYPO3\CMS\Core\Imaging\Icon; use TYPO3\CMS\Core\Imaging\IconFactory; use TYPO3\CMS\Core\SingletonInterface; use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Recordlist\RecordList; /** * Class/Function which adds the necessary ExtJS and pure JS stuff for the grid elements. @@ -36,23 +39,21 @@ */ class PageRenderer implements SingletonInterface { - /** * wrapper function called by hook (\TYPO3\CMS\Core\Page\PageRenderer->render-preProcess) * - * @param array $parameters : An array of available parameters - * @param \TYPO3\CMS\Core\Page\PageRenderer $pageRenderer : The parent object that triggered this hook - * - * @return void + * @param array $parameters An array of available parameters + * @param \TYPO3\CMS\Core\Page\PageRenderer $pageRenderer The parent object that triggered this hook */ - public function addJSCSS($parameters, &$pageRenderer) + public function addJSCSS(array $parameters, \TYPO3\CMS\Core\Page\PageRenderer $pageRenderer) { - $pageRenderer->addCssFile(ExtensionManagementUtility::extRelPath('gridelements') . 'Resources/Public/Backend/Css/Skin/t3skin_override.css'); - if (get_class($GLOBALS['SOBE']) === 'TYPO3\CMS\Recordlist\RecordList') { + if (!empty($GLOBALS['SOBE']) && (get_class($GLOBALS['SOBE']) === RecordList::class || is_subclass_of($GLOBALS['SOBE'], + RecordList::class))) { $pageRenderer->loadRequireJsModule('TYPO3/CMS/Gridelements/GridElementsOnReady'); return; } - if (get_class($GLOBALS['SOBE']) === 'TYPO3\CMS\Backend\Controller\PageLayoutController') { + if (!empty($GLOBALS['SOBE']) && (get_class($GLOBALS['SOBE']) === PageLayoutController::class || is_subclass_of($GLOBALS['SOBE'], + PageLayoutController::class))) { $iconFactory = GeneralUtility::makeInstance(IconFactory::class); $pageRenderer->loadRequireJsModule('TYPO3/CMS/Gridelements/GridElementsOnReady'); $pageRenderer->loadRequireJsModule('TYPO3/CMS/Gridelements/GridElementsDragDrop'); @@ -62,14 +63,12 @@ public function addJSCSS($parameters, &$pageRenderer) $clipObj = GeneralUtility::makeInstance(Clipboard::class); // Start clipboard $clipObj->initializeClipboard(); $clipObj->lockToNormal(); - if (!$pageRenderer->getCharSet()) { $pageRenderer->setCharSet($GLOBALS['LANG']->charSet ? $GLOBALS['LANG']->charSet : 'utf-8'); } // pull locallang_db.xml to JS side - only the tx_gridelements_js-prefixed keys - $pageRenderer->addInlineLanguageLabelFile('EXT:gridelements/Resources/Private/Language/locallang_db.xml', - 'tx_gridelements_js'); + $pageRenderer->addInlineLanguageLabelFile('EXT:gridelements/Resources/Private/Language/locallang_db.xml', 'tx_gridelements_js'); $pAddExtOnReadyCode = ' TYPO3.l10n = { @@ -81,8 +80,8 @@ public function addJSCSS($parameters, &$pageRenderer) $allowedContentTypesClassesByColPos = array(); $allowedGridTypesClassesByColPos = array(); - $layoutSetup = GeneralUtility::callUserFunction('TYPO3\\CMS\\Backend\\View\\BackendLayoutView->getSelectedBackendLayout', - intval(GeneralUtility::_GP('id')), $this); + $id = (int)GeneralUtility::_GP('id'); + $layoutSetup = GeneralUtility::callUserFunction(BackendLayoutView::class . '->getSelectedBackendLayout', $id, $this); if (is_array($layoutSetup) && !empty($layoutSetup['__config']['backend_layout.']['rows.'])) { foreach ($layoutSetup['__config']['backend_layout.']['rows.'] as $rows) { foreach ($rows as $row) { @@ -138,8 +137,7 @@ public function addJSCSS($parameters, &$pageRenderer) $pAddExtOnReadyCode .= " top.pageColumnsAllowedCTypes = " . json_encode($allowedContentTypesClassesByColPos) . "; top.pageColumnsAllowedGridTypes = " . json_encode($allowedGridTypesClassesByColPos) . "; - top.pasteReferenceAllowed = " . ($this->getBackendUser()->checkAuthMode('tt_content', 'CType', 'shortcut', - $GLOBALS['TYPO3_CONF_VARS']['BE']['explicitADmode']) ? 'true' : 'false') . "; + top.pasteReferenceAllowed = " . ($this->getBackendUser()->checkAuthMode('tt_content', 'CType', 'shortcut', $GLOBALS['TYPO3_CONF_VARS']['BE']['explicitADmode']) ? 'true' : 'false') . "; top.skipDraggableDetails = " . ($this->getBackendUser()->uc['dragAndDropHideNewElementWizardInfoOverlay'] ? 'true' : 'false') . "; top.backPath = '" . $GLOBALS['BACK_PATH'] . "'; top.browserUrl = '" . BackendUtility::getModuleUrl('wizard_element_browser') . "'"; @@ -151,27 +149,26 @@ public function addJSCSS($parameters, &$pageRenderer) $pasteTitle = $pasteRecord['header'] ? $pasteRecord['header'] : $pasteItem; $copyMode = $clipObj->clipData['normal']['mode'] ? '-' . $clipObj->clipData['normal']['mode'] : ''; $pAddExtOnReadyCode .= " - top.pasteIntoLinkTemplate = " . json_encode('' . $iconFactory->getIcon('actions-document-paste-into', - Icon::SIZE_SMALL)->render() . '') . "; - top.pasteAfterLinkTemplate = " . json_encode('' . $iconFactory->getIcon('actions-document-paste-into', - Icon::SIZE_SMALL)->render() . '') . ";"; + top.clipBoardElementCType = '" . $pasteRecord['CType'] . "'; + top.clipBoardElementGridType = '" . $pasteRecord['tx_gridelements_backend_layout'] . "'; + top.pasteIntoLinkTemplate = " . json_encode('' . $iconFactory->getIcon('actions-document-paste-into', Icon::SIZE_SMALL)->render() . '') . "; + top.pasteAfterLinkTemplate = " . json_encode('' . $iconFactory->getIcon('actions-document-paste-into', Icon::SIZE_SMALL)->render() . '') . ";"; if ($this->getBackendUser()->checkAuthMode('tt_content', 'CType', 'shortcut', $GLOBALS['TYPO3_CONF_VARS']['BE']['explicitADmode'])) { $pAddExtOnReadyCode .= " top.pasteReferencesAllowed = true;"; } - } else { $pAddExtOnReadyCode .= " + top.clipBoardElementCType = ''; + top.clipBoardElementGridType = ''; top.pasteIntoLinkTemplate = ''; top.pasteAfterLinkTemplate = '';"; } $pAddExtOnReadyCode .= " - top.copyFromAnotherPageLinkTemplate = " . json_encode('' . $iconFactory->getIcon('actions-insert-reference', - Icon::SIZE_SMALL)->render() . '') . ";"; + top.copyFromAnotherPageLinkTemplate = " . json_encode('' . $iconFactory->getIcon('actions-insert-reference', Icon::SIZE_SMALL)->render() . '') . ";"; - $pageRenderer->addJsInlineCode(// add some more JS here - 'gridelementsExtOnReady', $pAddExtOnReadyCode); + $pageRenderer->addJsInlineCode('gridelementsExtOnReady', $pAddExtOnReadyCode); } } @@ -194,5 +191,4 @@ public function getLanguageService() { return $GLOBALS['LANG']; } - } diff --git a/Classes/Hooks/WizardItems.php b/Classes/Hooks/WizardItems.php index ace61ac..f9b2694 100644 --- a/Classes/Hooks/WizardItems.php +++ b/Classes/Hooks/WizardItems.php @@ -21,6 +21,7 @@ use GridElementsTeam\Gridelements\Backend\LayoutSetup; use GridElementsTeam\Gridelements\Helper\Helper; +use TYPO3\CMS\Backend\Controller\ContentElement\NewContentElementController; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Backend\Wizard\NewContentElementWizardHookInterface; use TYPO3\CMS\Core\Database\DatabaseConnection; @@ -40,7 +41,6 @@ */ class WizardItems implements NewContentElementWizardHookInterface { - /** * @var LayoutSetup */ @@ -64,9 +64,6 @@ public function injectLayoutSetup(LayoutSetup $layoutSetup) public function init($pageUid) { if (!$this->layoutSetup instanceof LayoutSetup) { - if ($pageUid < 0) { - $pageUid = Helper::getInstance()->getPidFromNegativeUid($pageUid); - } $this->layoutSetup = GeneralUtility::makeInstance(LayoutSetup::class)->init($pageUid); } } @@ -75,57 +72,50 @@ public function init($pageUid) * Processes the items of the new content element wizard * and inserts necessary default values for items created within a grid * - * @param array $wizardItems : The array containing the current status of the wizard item list before rendering - * @param \TYPO3\CMS\Backend\Controller\ContentElement\NewContentElementController $parentObject : The parent object that triggered this hook - * - * @return void + * @param array $wizardItems The array containing the current status of the wizard item list before rendering + * @param NewContentElementController $parentObject The parent object that triggered this hook */ public function manipulateWizardItems(&$wizardItems, &$parentObject) { - if (!GeneralUtility::inList($GLOBALS['BE_USER']->groupData['explicit_allowdeny'], - 'tt_content:CType:gridelements_pi1:DENY') - ) { - $pageID = $parentObject->id; - $this->init($pageID); - - $container = (int)GeneralUtility::_GP('tx_gridelements_container'); - $column = (int)GeneralUtility::_GP('tx_gridelements_columns'); - $allowed_GP = GeneralUtility::_GP('tx_gridelements_allowed'); - if (!empty($allowed_GP)) { - $allowed = array_flip(explode(',', $allowed_GP)); - $allowedGridTypes_GP = GeneralUtility::_GP('tx_gridelements_allowed_grid_types'); - if (!empty($allowedGridTypes_GP)) { - $allowed['gridelements_pi1'] = 1; - } - $this->removeDisallowedWizardItems($allowed, $wizardItems); - } else { - $allowed = null; + if (GeneralUtility::inList($GLOBALS['BE_USER']->groupData['explicit_allowdeny'], 'tt_content:CType:gridelements_pi1:DENY')) { + return; + } + $pageID = $parentObject->id; + $this->init($pageID); + + $container = (int)GeneralUtility::_GP('tx_gridelements_container'); + $column = (int)GeneralUtility::_GP('tx_gridelements_columns'); + $allowed_GP = GeneralUtility::_GP('tx_gridelements_allowed'); + if (!empty($allowed_GP)) { + $allowed = array_flip(explode(',', $allowed_GP)); + $allowedGridTypes_GP = GeneralUtility::_GP('tx_gridelements_allowed_grid_types'); + if (!empty($allowedGridTypes_GP)) { + $allowed['gridelements_pi1'] = 1; } + $this->removeDisallowedWizardItems($allowed, $wizardItems); + } else { + $allowed = null; + } - if (empty($allowed) || isset($allowed['gridelements_pi1'])) { - $allowedGridTypes = array_flip(GeneralUtility::trimExplode(',', - GeneralUtility::_GP('tx_gridelements_allowed_grid_types'), true)); - $excludeLayouts = $this->getExcludeLayouts($container, $parentObject); + if (empty($allowed) || isset($allowed['gridelements_pi1'])) { + $allowedGridTypes = array_flip(GeneralUtility::trimExplode(',', GeneralUtility::_GP('tx_gridelements_allowed_grid_types'), true)); + $excludeLayouts = $this->getExcludeLayouts($container, $parentObject); - $gridItems = $this->layoutSetup->getLayoutWizardItems($parentObject->colPos, $excludeLayouts, - $allowedGridTypes); - $this->addGridItemsToWizard($gridItems, $wizardItems); - } + $gridItems = $this->layoutSetup->getLayoutWizardItems($parentObject->colPos, $excludeLayouts, $allowedGridTypes); + $this->addGridItemsToWizard($gridItems, $wizardItems); + } - $this->addGridValuesToWizardItems($wizardItems, $container, $column); + $this->addGridValuesToWizardItems($wizardItems, $container, $column); - $this->removeEmptyHeadersFromWizard($wizardItems); - } + $this->removeEmptyHeadersFromWizard($wizardItems); } /** * remove unnecessary headers from wizard items * * @param array $wizardItems - * - * @return void */ - public function removeEmptyHeadersFromWizard(&$wizardItems) + public function removeEmptyHeadersFromWizard(array &$wizardItems) { $headersWithElements = array(); foreach ($wizardItems as $key => $wizardItem) { @@ -148,10 +138,8 @@ public function removeEmptyHeadersFromWizard(&$wizardItems) * * @param array $allowed * @param array $wizardItems - * - * @return void */ - public function removeDisallowedWizardItems($allowed, &$wizardItems) + public function removeDisallowedWizardItems(array $allowed, array &$wizardItems) { if (!isset($allowed['*'])) { foreach ($wizardItems as $key => $wizardItem) { @@ -167,12 +155,12 @@ public function removeDisallowedWizardItems($allowed, &$wizardItems) /** * retrieve layouts to exclude from pageTSconfig * - * @param integer $container - * @param \TYPO3\CMS\Backend\Controller\ContentElement\NewContentElementController $parentObject : The parent object that triggered this hook + * @param int $container + * @param NewContentElementController $parentObject The parent object that triggered this hook * * @return array */ - public function getExcludeLayouts($container, &$parentObject) + public function getExcludeLayouts($container, NewContentElementController $parentObject) { $excludeLayouts = 0; $excludeArray = array(); @@ -209,102 +197,103 @@ public function getExcludeLayouts($container, &$parentObject) * * @param array $gridItems * @param array $wizardItems - * - * @return void */ - public function addGridItemsToWizard(&$gridItems, &$wizardItems) + public function addGridItemsToWizard(array &$gridItems, array &$wizardItems) { - // we have grid elements to add - if (!empty($gridItems)) { - - // create gridelements node - $wizardItems['gridelements'] = array(); - - // set header label - $wizardItems['gridelements']['header'] = $this->getLanguageService()->sL('LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:tx_gridelements_backend_layout_wizard_label'); - - $iconRegistry = GeneralUtility::makeInstance(IconRegistry::class); - - // traverse the gridelements and create wizard item for each gridelement - foreach ($gridItems as $key => $item) { - if (empty($item['iconIdentifierLarge'])) { - if (is_array($item['icon']) && isset($item['icon'][1])) { - $item['iconIdentifierLarge'] = 'gridelements-large-' . $key; - $largeIcon = $item['icon'][1]; - if (StringUtility::beginsWith($largeIcon, '../typo3conf/ext/')) { - $largeIcon = str_replace('../typo3conf/ext/', 'EXT:', $largeIcon); - } - if (StringUtility::beginsWith($largeIcon, '../uploads/tx_gridelements/')) { - $largeIcon = str_replace('../', '', $largeIcon); - } else if (!StringUtility::beginsWith($largeIcon, 'EXT:') && strpos($largeIcon, - '/') === false - ) { - $largeIcon = GeneralUtility::resolveBackPath($item['icon'][1]); - } - if (!empty($icon)) { - if (StringUtility::endsWith($largeIcon, '.svg')) { - $iconRegistry->registerIcon($item['iconIdentifierLarge'], SvgIconProvider::class, array( + if (empty($gridItems)) { + return; + } + // create gridelements node + $wizardItems['gridelements'] = array(); + + // set header label + $wizardItems['gridelements']['header'] = $this->getLanguageService()->sL( + 'LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:tx_gridelements_backend_layout_wizard_label' + ); + + $iconRegistry = GeneralUtility::makeInstance(IconRegistry::class); + + // traverse the gridelements and create wizard item for each gridelement + foreach ($gridItems as $key => $item) { + $largeIcon = ''; + if (empty($item['iconIdentifierLarge'])) { + if (is_array($item['icon']) && isset($item['icon'][1])) { + $item['iconIdentifierLarge'] = 'gridelements-large-' . $key; + $largeIcon = $item['icon'][1]; + if (StringUtility::beginsWith($largeIcon, '../typo3conf/ext/')) { + $largeIcon = str_replace('../typo3conf/ext/', 'EXT:', $largeIcon); + } + if (StringUtility::beginsWith($largeIcon, '../uploads/tx_gridelements/')) { + $largeIcon = str_replace('../', '', $largeIcon); + } else if (!StringUtility::beginsWith($largeIcon, 'EXT:') && strpos($largeIcon, + '/') === false + ) { + $largeIcon = GeneralUtility::resolveBackPath($item['icon'][1]); + } + if (!empty($largeIcon)) { + if (StringUtility::endsWith($largeIcon, '.svg')) { + $iconRegistry->registerIcon($item['iconIdentifierLarge'], SvgIconProvider::class, array( + 'source' => $largeIcon + )); + } else { + $iconRegistry->registerIcon($item['iconIdentifierLarge'], BitmapIconProvider::class, + array( 'source' => $largeIcon )); - } else { - $iconRegistry->registerIcon($item['iconIdentifierLarge'], BitmapIconProvider::class, - array( - 'source' => $largeIcon - )); - } } - } else { - $item['iconIdentifierLarge'] = 'gridelements-large-' . $key; - $iconRegistry->registerIcon($item['iconIdentifierLarge'], SvgIconProvider::class, array( - 'source' => 'EXT:gridelements/Resources/Public/Icons/gridelements.svg' - )); } + } else { + $item['iconIdentifierLarge'] = 'gridelements-large-' . $key; + $iconRegistry->registerIcon($item['iconIdentifierLarge'], SvgIconProvider::class, array( + 'source' => 'EXT:gridelements/Resources/Public/Icons/gridelements.svg' + )); } - $itemIdentifier = $item['alias'] ? $item['alias'] : $item['uid']; - $wizardItems['gridelements_' . $itemIdentifier] = array( - 'title' => $item['title'], - 'description' => $item['description'], - 'params' => ($largeIcon ? '&largeIconImage=' . $largeIcon : '') . '&defVals[tt_content][CType]=gridelements_pi1&defVals[tt_content][tx_gridelements_backend_layout]=' . $item['uid'] . ($item['tll'] ? '&isTopLevelLayout' : ''), - 'tt_content_defValues' => array( - 'CType' => 'gridelements_pi1', - 'tx_gridelements_backend_layout' => $item['uid'] - ), - ); - if ($item['iconIdentifier']) { - $wizardItems['gridelements_' . $itemIdentifier]['iconIdentifier'] = $item['iconIdentifier']; + } + $itemIdentifier = $item['alias'] ? $item['alias'] : $item['uid']; + $wizardItems['gridelements_' . $itemIdentifier] = array( + 'title' => $item['title'], + 'description' => $item['description'], + 'params' => ($largeIcon ? '&largeIconImage=' . $largeIcon : '') + . '&defVals[tt_content][CType]=gridelements_pi1&defVals[tt_content][tx_gridelements_backend_layout]=' . $item['uid'] + . ($item['tll'] ? '&isTopLevelLayout' : ''), + 'tt_content_defValues' => array( + 'CType' => 'gridelements_pi1', + 'tx_gridelements_backend_layout' => $item['uid'] + ), + ); + $icon = ''; + if ($item['iconIdentifier']) { + $wizardItems['gridelements_' . $itemIdentifier]['iconIdentifier'] = $item['iconIdentifier']; + } elseif (is_array($item['icon']) && isset($item['icon'][0])) { + $item['iconIdentifier'] = 'gridelements-' . $key; + $icon = $item['icon'][0]; + if (StringUtility::beginsWith($icon, '../typo3conf/ext/')) { + $icon = str_replace('../typo3conf/ext/', 'EXT:', $icon); + } + if (StringUtility::beginsWith($icon, '../uploads/tx_gridelements/')) { + $icon = str_replace('../', '', $icon); + } else if (!StringUtility::beginsWith($icon, 'EXT:') && strpos($icon, '/') !== false) { + $icon = GeneralUtility::resolveBackPath($item['icon'][0]); + } + if (StringUtility::endsWith($icon, '.svg')) { + $iconRegistry->registerIcon($item['iconIdentifier'], SvgIconProvider::class, array( + 'source' => $icon + )); } else { - if (is_array($item['icon']) && isset($item['icon'][0])) { - $item['iconIdentifier'] = 'gridelements-' . $key; - $icon = $item['icon'][0]; - if (StringUtility::beginsWith($icon, '../typo3conf/ext/')) { - $icon = str_replace('../typo3conf/ext/', 'EXT:', $icon); - } - if (StringUtility::beginsWith($icon, '../uploads/tx_gridelements/')) { - $icon = str_replace('../', '', $icon); - } else if (!StringUtility::beginsWith($icon, 'EXT:') && strpos($icon, '/') !== false) { - $icon = GeneralUtility::resolveBackPath($item['icon'][0]); - } - if (StringUtility::endsWith($icon, '.svg')) { - $iconRegistry->registerIcon($item['iconIdentifier'], SvgIconProvider::class, array( - 'source' => $icon - )); - } else { - $iconRegistry->registerIcon($item['iconIdentifier'], BitmapIconProvider::class, array( - 'source' => $icon - )); - } - } else { - $item['iconIdentifier'] = 'gridelements-' . $key; - $iconRegistry->registerIcon($item['iconIdentifier'], SvgIconProvider::class, array( - 'source' => 'EXT:gridelements/Resources/Public/Icons/gridelements.svg' - )); - } - if ($icon && !isset($wizardItems['gridelements_' . $itemIdentifier]['iconIdentifier'])) { - $wizardItems['gridelements_' . $itemIdentifier]['iconIdentifier'] = 'gridelements-' . $key; - } else if (!isset($wizardItems['gridelements_' . $itemIdentifier]['iconIdentifier'])) { - $wizardItems['gridelements_' . $itemIdentifier]['iconIdentifier'] = 'gridelements-default'; - } + $iconRegistry->registerIcon($item['iconIdentifier'], BitmapIconProvider::class, array( + 'source' => $icon + )); } + } else { + $item['iconIdentifier'] = 'gridelements-' . $key; + $iconRegistry->registerIcon($item['iconIdentifier'], SvgIconProvider::class, array( + 'source' => 'EXT:gridelements/Resources/Public/Icons/gridelements.svg' + )); + } + if ($icon && !isset($wizardItems['gridelements_' . $itemIdentifier]['iconIdentifier'])) { + $wizardItems['gridelements_' . $itemIdentifier]['iconIdentifier'] = 'gridelements-' . $key; + } else if (!isset($wizardItems['gridelements_' . $itemIdentifier]['iconIdentifier'])) { + $wizardItems['gridelements_' . $itemIdentifier]['iconIdentifier'] = 'gridelements-default'; } } } @@ -313,23 +302,19 @@ public function addGridItemsToWizard(&$gridItems, &$wizardItems) * initializes wizard items * * @param array $wizardItems - * @param integer $container - * @param integer $column - * - * @return void + * @param int $container + * @param int $column */ - public function addGridValuesToWizardItems(&$wizardItems, $container, $column) + public function addGridValuesToWizardItems(array &$wizardItems, $container, $column) { foreach ($wizardItems as $key => $wizardItem) { if (!$wizardItems[$key]['header']) { if ($container !== 0) { - $wizardItems[$key]['tt_content_defValues']['tx_gridelements_container'] = $container; - $wizardItems[$key]['params'] .= '&defVals[tt_content][tx_gridelements_container]=' . $container; - } - if ($column !== 0) { - $wizardItems[$key]['tt_content_defValues']['tx_gridelements_columns'] = $column; - $wizardItems[$key]['params'] .= '&defVals[tt_content][tx_gridelements_columns]=' . $column; + $wizardItems[$key]['tt_content_defValues']['tx_gridelements_container'] = (int)$container; + $wizardItems[$key]['params'] .= '&defVals[tt_content][tx_gridelements_container]=' . (int)$container; } + $wizardItems[$key]['tt_content_defValues']['tx_gridelements_columns'] = (int)$column; + $wizardItems[$key]['params'] .= '&defVals[tt_content][tx_gridelements_columns]=' . (int)$column; } } } diff --git a/Classes/Plugin/Gridelements.php b/Classes/Plugin/Gridelements.php index e207915..ef3957c 100644 --- a/Classes/Plugin/Gridelements.php +++ b/Classes/Plugin/Gridelements.php @@ -25,6 +25,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\MathUtility; use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; +use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController; /** * Plugin 'Grid Element' for the 'gridelements' extension. @@ -46,21 +47,37 @@ class Gridelements extends ContentObjectRenderer */ protected $pageRenderer; - public $prefixId = 'Gridelements'; // Same as class name - public $scriptRelPath = 'Classes/Plugin/Gridelements.php'; // Path to this script relative to the extension dir. - public $extKey = 'gridelements'; // The extension key. + /** + * Same as class name + * + * @var string + */ + public $prefixId = 'Gridelements'; + + /** + * Path to this script relative to the extension dir + * + * @var string + */ + public $scriptRelPath = 'Classes/Plugin/Gridelements.php'; + + /** + * The extension key + * + * @var string + */ + public $extKey = 'gridelements'; /** * The main method of the PlugIn * - * @param string $content : The PlugIn content - * @param array $conf : The PlugIn configuration + * @param string $content The PlugIn content + * @param array $conf The PlugIn configuration * * @return string The content that is displayed on the website */ public function main($content = '', $conf = array()) { - // first we have to take care of possible flexform values containing additional information // that is not available via DB relations. It will be added as "virtual" key to the existing data Array // so that you can easily get the values with TypoScript @@ -70,11 +87,12 @@ public function main($content = '', $conf = array()) // now we have to find the children of this grid container regardless of their column // so we can get them within a single DB query instead of doing a query per column // but we will only fetch those columns that are used by the current grid layout - if ($GLOBALS['TSFE']->sys_language_contentOL && $this->cObj->data['l18n_parent']) { + if ($this->getTSFE()->sys_language_contentOL && $this->cObj->data['l18n_parent']) { $element = $this->cObj->data['l18n_parent']; } else { $element = $this->cObj->data['uid']; } + $pid = $this->cObj->data['pid']; $layout = $this->cObj->data['tx_gridelements_backend_layout']; /** @var LayoutSetup $layoutSetup */ @@ -82,8 +100,8 @@ public function main($content = '', $conf = array()) $layoutSetup->init($this->cObj->data['pid'], $conf); $availableColumns = $layoutSetup->getLayoutColumns($layout); - $csvColumns = str_replace('-2,-1,', '', $availableColumns['CSV']); - $this->getChildren($element, $csvColumns); + $csvColumns = ltrim(str_replace('-2,-1', '', $availableColumns['CSV']), ','); + $this->getChildren($element, $pid, $csvColumns); // and we have to determine the frontend setup related to the backend layout record which is assigned to this container $typoScriptSetup = $layoutSetup->getTypoScriptSetup($layout); @@ -118,96 +136,97 @@ public function main($content = '', $conf = array()) // before returning the content unset($typoScriptSetup['columns.']); - $content = !empty($typoScriptSetup) ? $this->cObj->stdWrap($content, $typoScriptSetup) : $content; - - return $content; - + return !empty($typoScriptSetup) ? $this->cObj->stdWrap($content, $typoScriptSetup) : $content; } /** * fetches all available children for a certain grid container * - * @param int $element : The uid of the grid container - * @param string $csvColumns : A list of available column IDs - * - * @return array $children: The child elements of this grid container + * @param int $element The uid of the grid container + * @param int $pid + * @param string $csvColumns A list of available column IDs */ - public function getChildren($element = 0, $csvColumns = '') + public function getChildren($element = 0, $pid = 0, $csvColumns = '') { + if (!$element || $csvColumns === '') { + return; + } - if ($element && $csvColumns !== '') { - - $where = '(tx_gridelements_container = ' . $element . $this->cObj->enableFields('tt_content') . ' AND colPos != -2 - AND pid > 0 - AND tx_gridelements_columns IN (' . $csvColumns . ') - AND sys_language_uid IN (-1,0) - )'; + $where = '( + tx_gridelements_container = ' . $element . $this->cObj->enableFields('tt_content') . ' AND colPos != -2 + AND pid = ' . (int)$pid . ' + AND tx_gridelements_columns IN (' . $csvColumns . ') + AND sys_language_uid IN (-1,0) + )'; + + if ($this->getTSFE()->sys_language_content > 0) { + if ($this->getTSFE()->sys_language_contentOL) { + if (isset($this->cObj->data['_LOCALIZED_UID']) && $this->cObj->data['_LOCALIZED_UID'] !== 0) { + $element = (int)$this->cObj->data['_LOCALIZED_UID']; + } - if ($GLOBALS['TSFE']->sys_language_content > 0) { - if ($GLOBALS['TSFE']->sys_language_contentOL) { - if (isset($this->cObj->data['_LOCALIZED_UID']) && $this->cObj->data['_LOCALIZED_UID'] !== 0) { - $element = (int)$this->cObj->data['_LOCALIZED_UID']; - } + if ($element) { + $where .= ' OR ( + tx_gridelements_container = ' . $element . $this->cObj->enableFields('tt_content') . ' AND colPos != -2 + AND pid = ' . (int)$pid . ' + AND tx_gridelements_columns IN (' . $csvColumns . ') + AND sys_language_uid IN (-1,' . $this->getTSFE()->sys_language_content . ') + AND l18n_parent = 0 + )'; + } + } else { + if ($element) { + $where .= ' OR ( + tx_gridelements_container = ' . $element . $this->cObj->enableFields('tt_content') . ' AND colPos != -2 + AND pid = ' . (int)$pid . ' + AND tx_gridelements_columns IN (' . $csvColumns . ') + AND sys_language_uid IN (-1,' . $this->getTSFE()->sys_language_content . ') + )'; + } + } + } - if ($element) { - $where .= ' OR ( - tx_gridelements_container = ' . $element . $this->cObj->enableFields('tt_content') . ' AND sys_language_uid IN (-1,' . $GLOBALS['TSFE']->sys_language_content . ') - AND l18n_parent = 0 - )'; + $res = $this->getDatabaseConnection()->exec_SELECTquery('*', 'tt_content', $where, '', 'sorting ASC'); + + if (!$this->getDatabaseConnection()->sql_error()) { + $this->cObj->data['tx_gridelements_view_children'] = array(); + while ($child = $this->getDatabaseConnection()->sql_fetch_assoc($res)) { + // Versioning preview: + $sorting = $child['sorting']; + $this->getTSFE()->sys_page->versionOL('tt_content', $child, true); + + // Language overlay: + if (is_array($child)) { + $child['sorting'] = $sorting; + if ($this->getTSFE()->sys_language_contentOL) { + $child = $this->getTSFE()->sys_page->getRecordOverlay('tt_content', $child, + $this->getTSFE()->sys_language_content, $this->getTSFE()->sys_language_contentOL); } - } else { - if ($element) { - $where .= ' OR ( - tx_gridelements_container = ' . (int)$element . $this->cObj->enableFields('tt_content') . ' AND sys_language_uid IN (-1,' . $GLOBALS['TSFE']->sys_language_content . ') - )'; + if (!empty($child)) { + $this->cObj->data['tx_gridelements_view_children'][] = $child; + unset($child); } } } - $res = $this->getDatabaseConnection()->exec_SELECTquery('*', 'tt_content', $where, '', 'sorting ASC'); - - if (!$this->getDatabaseConnection()->sql_error()) { - $this->cObj->data['tx_gridelements_view_children'] = array(); - while ($child = $this->getDatabaseConnection()->sql_fetch_assoc($res)) { - // Versioning preview: - $sorting = $child['sorting']; - $GLOBALS['TSFE']->sys_page->versionOL('tt_content', $child, true); - - // Language overlay: - if (is_array($child)) { - $child['sorting'] = $sorting; - if ($GLOBALS['TSFE']->sys_language_contentOL) { - $child = $GLOBALS['TSFE']->sys_page->getRecordOverlay('tt_content', $child, - $GLOBALS['TSFE']->sys_language_content, $GLOBALS['TSFE']->sys_language_contentOL); - } - if (!empty($child)) { - $this->cObj->data['tx_gridelements_view_children'][] = $child; - unset($child); - } - } + $compareFunction = function ($child_a, $child_b) { + if ($child_a['sorting'] > $child_b['sorting']) { + return 1; + } elseif ($child_a['sorting'] === $child_b['sorting']) { + return 0; + } else { + return -1; } + }; - $compareFunction = function ($child_a, $child_b) { - if ($child_a['sorting'] > $child_b['sorting']) { - return 1; - } elseif ($child_a['sorting'] === $child_b['sorting']) { - return 0; - } else { - return -1; - } - }; - - usort($this->cObj->data['tx_gridelements_view_children'], $compareFunction); + usort($this->cObj->data['tx_gridelements_view_children'], $compareFunction); - $this->getDatabaseConnection()->sql_free_result($res); - } + $this->getDatabaseConnection()->sql_free_result($res); } } /** * fetches values from the grid flexform and assigns them to virtual fields in the data array - * - * @return void */ public function getPluginFlexFormData() { @@ -236,7 +255,7 @@ public function getPluginFlexFormData() * puts them into their respective columns * * @param array $typoScriptSetup - * @param array $sortColumns : An Array of column positions within the grid container in the order they got in the grid setup + * @param array $sortColumns An Array of column positions within the grid container in the order they got in the grid setup */ public function renderChildrenIntoParentColumns($typoScriptSetup = array(), $sortColumns = array()) { @@ -251,7 +270,7 @@ public function renderChildrenIntoParentColumns($typoScriptSetup = array(), $sor $counter = !empty($this->cObj->data['tx_gridelements_view_children']); $parentRecordNumbers = array(); - $GLOBALS['TSFE']->cObjectDepthCounter += $counter; + $this->getTSFE()->cObjectDepthCounter += $counter; // each of the children will now be rendered separately and the output will be added to it's particular column $rawColumns = array(); @@ -271,9 +290,12 @@ public function renderChildrenIntoParentColumns($typoScriptSetup = array(), $sor // it will just contain the additional tx_gridelements_view section with the prerendered elements // it is important to do this before any stdWrap functions are applied to the grid container // since they will depend on the original data - $GLOBALS['TSFE']->cObjectDepthCounter -= $counter; + $this->getTSFE()->cObjectDepthCounter -= $counter; + + $this->cObj->currentRecord = $currentParentGrid['record']; + $this->cObj->data = $currentParentGrid['data']; + $this->cObj->parentRecordNumber = $currentParentGrid['parentRecordNumber']; - $this->resetCurrentParentGrid($currentParentGrid); if (!empty($sortColumns)) { $this->cObj->data['tx_gridelements_view_columns'] = array(); foreach ($sortColumns as $sortKey) { @@ -285,7 +307,6 @@ public function renderChildrenIntoParentColumns($typoScriptSetup = array(), $sor } unset($parentGridData); unset($currentParentGrid); - } /** @@ -296,16 +317,12 @@ public function renderChildrenIntoParentColumns($typoScriptSetup = array(), $sor public function getUsedColumns($sortColumns = array()) { $columns = array(); - // we need the array values as keys if (!empty($sortColumns)) { foreach ($sortColumns as $column_number) { $columns[$column_number] = ''; } } - - unset($sortColumns); - return $columns; } @@ -314,29 +331,11 @@ public function getUsedColumns($sortColumns = array()) */ public function copyCurrentParentGrid() { - - $data['record'] = $this->cObj->currentRecord; - $data['data'] = $this->cObj->data; - $data['parentRecordNumber'] = $this->cObj->parentRecordNumber; - - return $data; - - } - - /** - * @param $data - * - * @return array - */ - public function resetCurrentParentGrid($data = array()) - { - - $this->cObj->currentRecord = $data['record']; - $this->cObj->data = $data['data']; - - $this->cObj->parentRecordNumber = $data['parentRecordNumber']; - - unset($data); + return [ + 'record' => $this->cObj->currentRecord, + 'data' => $this->cObj->data, + 'parentRecordNumber' => $this->cObj->parentRecordNumber + ]; } /** @@ -346,7 +345,6 @@ public function resetCurrentParentGrid($data = array()) */ public function getParentGridData($data = array()) { - // filter out existing superfluous keys to reduce memory load // String comparisons are way too expensive, so we go for unset within some loops if (!empty($data['tx_gridelements_view_children'])) { @@ -374,11 +372,7 @@ public function getParentGridData($data = array()) } // Set parentgrid data for the first time - $parentGridData = $this->setParentGridData($data); - - unset($data); - - return $parentGridData; + return $this->setParentGridData($data); } /** @@ -388,27 +382,21 @@ public function getParentGridData($data = array()) */ public function setParentGridData($data = array()) { - $parentGridData = array(); foreach ($data as $key => $value) { $parentGridData['parentgrid_' . $key] = $value; } - - unset($data); - return $parentGridData; } /** * renders the columns of the grid container and returns the actual content * - * @param $columns + * @param array $columns * @param array $child * @param array $parentGridData * @param array $parentRecordNumbers * @param array $typoScriptSetup - * - * @return void */ public function renderChildIntoParentColumn( $columns, @@ -417,71 +405,60 @@ public function renderChildIntoParentColumn( &$parentRecordNumbers, $typoScriptSetup = array() ) { - $column_number = (int)$child['tx_gridelements_columns']; $columnKey = $column_number . '.'; + $columnSetupKey = isset($typoScriptSetup['columns.'][$columnKey]) ? $columnKey : 'default.'; - if (!isset($typoScriptSetup['columns.'][$columnKey])) { - $columnSetupKey = 'default.'; - } else { - $columnSetupKey = $columnKey; + if ($child['uid'] <= 0) { + return; } - - if ($child['uid'] > 0) { - - // update SYS_LASTCHANGED if necessary - - $this->cObj->lastChanged($child['tstamp']); - - $this->cObj->start(array_merge($child, $parentGridData), 'tt_content'); - - $parentRecordNumbers[$columnKey]++; - $this->cObj->parentRecordNumber = $parentRecordNumbers[$columnKey]; - - // we render each child into the children key to provide them prerendered for usage with your own templating - $child = $this->cObj->cObjGetSingle($typoScriptSetup['columns.'][$columnSetupKey]['renderObj'], - $typoScriptSetup['columns.'][$columnSetupKey]['renderObj.']); - // then we assign the prerendered child to the appropriate column - if (isset($columns[$column_number])) { - $parentGridData['tx_gridelements_view_columns'][$column_number] .= $child; - } - unset($columns); + // update SYS_LASTCHANGED if necessary + $this->cObj->lastChanged($child['tstamp']); + $this->cObj->start(array_merge($child, $parentGridData), 'tt_content'); + + $parentRecordNumbers[$columnKey]++; + $this->cObj->parentRecordNumber = $parentRecordNumbers[$columnKey]; + + // we render each child into the children key to provide them prerendered for usage with your own templating + $child = $this->cObj->cObjGetSingle( + $typoScriptSetup['columns.'][$columnSetupKey]['renderObj'], + $typoScriptSetup['columns.'][$columnSetupKey]['renderObj.'] + ); + // then we assign the prerendered child to the appropriate column + if (isset($columns[$column_number])) { + $parentGridData['tx_gridelements_view_columns'][$column_number] .= $child; } - - unset($typoScriptSetup); } /** * renders the columns of the grid container and returns the actual content * - * @param array $setup : The adjusted setup of the grid container + * @param array $setup The adjusted setup of the grid container * - * @return array $content: The raw HTML output of the grid container before stdWrap functions will be applied to it + * @return array $content The raw HTML output of the grid container before stdWrap functions will be applied to it */ public function renderColumnsIntoParentGrid($setup = array()) { - + if (empty($this->cObj->data['tx_gridelements_view_columns'])) { + return ''; + } $content = ''; - - if (!empty($this->cObj->data['tx_gridelements_view_columns'])) { - foreach ($this->cObj->data['tx_gridelements_view_columns'] as $column => $columnContent) { - // if there are any columns available, we have to determine the corresponding TS setup - // and if there is none we are going to use the default setup - $tempSetup = isset($setup['columns.'][$column . '.']) ? $setup['columns.'][$column . '.'] : $setup['columns.']['default.']; - // now we just have to unset the renderObj - // before applying the rest of the keys via the usual stdWrap operations - unset($tempSetup['renderObj']); - unset($tempSetup['renderObj.']); - - // we render each column into the column key to provide them prerendered for usage with your own templating - $this->cObj->data['tx_gridelements_view_column_' . $column] = !empty($tempSetup) ? $this->cObj->stdWrap($columnContent, - $tempSetup) : $columnContent; - $content .= $this->cObj->data['tx_gridelements_view_column_' . $column]; - } + foreach ($this->cObj->data['tx_gridelements_view_columns'] as $column => $columnContent) { + // if there are any columns available, we have to determine the corresponding TS setup + // and if there is none we are going to use the default setup + $tempSetup = isset($setup['columns.'][$column . '.']) ? $setup['columns.'][$column . '.'] : $setup['columns.']['default.']; + // now we just have to unset the renderObj + // before applying the rest of the keys via the usual stdWrap operations + unset($tempSetup['renderObj']); + unset($tempSetup['renderObj.']); + + // we render each column into the column key to provide them prerendered for usage with your own templating + $this->cObj->data['tx_gridelements_view_column_' . $column] = empty($tempSetup) + ? $columnContent + : $this->cObj->stdWrap($columnContent, $tempSetup); + $content .= $this->cObj->data['tx_gridelements_view_column_' . $column]; } - return $content; - } /** @@ -489,16 +466,16 @@ public function renderColumnsIntoParentGrid($setup = array()) */ public function user_getTreeList() { - $GLOBALS['TSFE']->register['pidInList'] = trim(($this->cObj->data['uid'] . ',' . ($GLOBALS['TSFE']->register['tt_content_shortcut_recursive'] ? $this->cObj->getTreeList($this->cObj->data['uid'], - $GLOBALS['TSFE']->register['tt_content_shortcut_recursive']) : '')), ','); + $pidList = $this->getTSFE()->register['tt_content_shortcut_recursive'] + ? $this->cObj->getTreeList($this->cObj->data['uid'], $this->getTSFE()->register['tt_content_shortcut_recursive']) + : ''; + $this->getTSFE()->register['pidInList'] = trim($this->cObj->data['uid'] . ',' . $pidList, ','); } /** * Converts $this->cObj->data['pi_flexform'] from XML string to flexForm array. * * @param string $field Field name to convert - * - * @return void */ public function initPluginFlexForm($field = 'pi_flexform') { @@ -532,9 +509,8 @@ public function getFlexFormValue( $sheetArray = is_array($T3FlexForm_array) ? $T3FlexForm_array['data'][$sheet][$language] : ''; if (is_array($sheetArray)) { return $this->getFlexFormValueFromSheetArray($sheetArray, explode('/', $fieldName), $value); - } else { - return ''; } + return ''; } /** @@ -550,7 +526,6 @@ public function getFlexFormValue( */ public function getFlexFormValueFromSheetArray($sheetArray, $fieldNameArr, $value) { - $tempArr = $sheetArray; foreach ($fieldNameArr as $k => $v) { $checkedValue = MathUtility::canBeInterpretedAsInteger($v); @@ -596,16 +571,22 @@ public function getFlexformSectionsRecursively($dataArr, $valueKey = 'vDEF') $out[$k] = $this->getFlexformSectionsRecursively($el['el']); } elseif (is_array($el) && is_array($el['data']['el'])) { $out[] = $this->getFlexformSectionsRecursively($el['data']['el']); - } else { - if (isset($el[$valueKey])) { - $out[$k] = $el[$valueKey]; - } + } elseif (isset($el[$valueKey])) { + $out[$k] = $el[$valueKey]; } } return $out; } + /** + * @return TypoScriptFrontendController + */ + public function getTSFE() + { + return $GLOBALS['TSFE']; + } + /** * @return DatabaseConnection */ @@ -622,8 +603,6 @@ public function getPageRenderer() if ($this->pageRenderer === null) { $this->pageRenderer = GeneralUtility::makeInstance(PageRenderer::class); } - return $this->pageRenderer; } - -} \ No newline at end of file +} diff --git a/Classes/Slots/ExtTablesInclusionPostProcessing.php b/Classes/Slots/ExtTablesInclusionPostProcessing.php new file mode 100644 index 0000000..bf60871 --- /dev/null +++ b/Classes/Slots/ExtTablesInclusionPostProcessing.php @@ -0,0 +1,51 @@ + + * All rights reserved + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; + +/** + * Class ExtTablesInclusionPostProcessing + * + * @package GridElementsTeam\Gridelements\Hooks + */ +class ExtTablesInclusionPostProcessing +{ + /** + * Function which may process data created / registered by extTables + * scripts (f.e. modifying TCA data of all extensions) + * + * @param array $tca + * + * @return void + */ + public function processData($tca) + { + // Move the local $tca to global variable to use general modification functions like addToAllTCAtypes + $GLOBALS['TCA'] = $tca; + + ExtensionManagementUtility::addToAllTCAtypes('tt_content', 'recursive', 'shortcut', 'after:records'); + ExtensionManagementUtility::addToAllTCAtypes('tt_content', '--div--;LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xlf:gridElements,tx_gridelements_container,tx_gridelements_columns'); + + // return the modified global TCA definition + return [$GLOBALS['TCA']]; + } +} diff --git a/Classes/Wizard/BackendLayoutWizardController.php b/Classes/Wizard/BackendLayoutWizardController.php index ccdcaca..05384c4 100644 --- a/Classes/Wizard/BackendLayoutWizardController.php +++ b/Classes/Wizard/BackendLayoutWizardController.php @@ -19,8 +19,6 @@ * This copyright notice MUST APPEAR in all copies of the script! ***************************************************************/ -use Psr\Http\Message\ResponseInterface; -use Psr\Http\Message\ServerRequestInterface; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Imaging\IconFactory; use TYPO3\CMS\Core\Page\PageRenderer; @@ -33,7 +31,6 @@ */ class BackendLayoutWizardController extends \TYPO3\CMS\Backend\Controller\BackendLayoutWizardController { - /** * @var string */ @@ -56,7 +53,6 @@ public function __construct() /** * Initialises the Class * - * @return void * @throws \InvalidArgumentException */ public function init() @@ -140,7 +136,8 @@ function storeData(data) { // select record $record = $this->getDatabaseConnection()->exec_SELECTgetRows($this->P['field'], $this->P['table'], - 'uid=' . (int)$this->P['uid']); + 'uid=' . (int)$this->P['uid'] + ); if (trim($record[0][$this->P['field']]) == '') { $rows = array(array(array('colspan' => 1, 'rowspan' => 1, 'spanned' => false, 'name' => ''))); $colCount = 1; @@ -241,14 +238,4 @@ public function getIconFactory() { return $this->iconFactory; } - - /** - * Gets the current backend user. - * - * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication - */ - public function getBackendUser() - { - return $GLOBALS['BE_USER']; - } } diff --git a/Classes/Xclass/DatabaseRecordList.php b/Classes/Xclass/DatabaseRecordList.php index e245ca5..b953a07 100644 --- a/Classes/Xclass/DatabaseRecordList.php +++ b/Classes/Xclass/DatabaseRecordList.php @@ -14,14 +14,13 @@ * The TYPO3 project - inspiring people to share! */ -use TYPO3\CMS\Backend\Module\BaseScriptClass; use TYPO3\CMS\Backend\RecordList\RecordListGetTableHookInterface; use TYPO3\CMS\Backend\Template\Components\ButtonBar; -use TYPO3\CMS\Backend\Template\DocumentTemplate; use TYPO3\CMS\Backend\Template\ModuleTemplate; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Backend\View\BackendLayoutView; -use TYPO3\CMS\Core\Database\DatabaseConnection; +use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; +use TYPO3\CMS\Core\FormProtection\FormProtectionFactory; use TYPO3\CMS\Core\Imaging\Icon; use TYPO3\CMS\Core\Imaging\IconFactory; use TYPO3\CMS\Core\Messaging\FlashMessage; @@ -29,6 +28,7 @@ use TYPO3\CMS\Core\Type\Bitmask\Permission; use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Core\Utility\HttpUtility; use TYPO3\CMS\Frontend\Page\PageRepository; use TYPO3\CMS\Recordlist\RecordList\RecordListHookInterface; @@ -37,7 +37,6 @@ */ class DatabaseRecordList extends \TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList { - /** * @var int */ @@ -46,17 +45,17 @@ class DatabaseRecordList extends \TYPO3\CMS\Recordlist\RecordList\DatabaseRecord /** * @var int[] */ - protected $expandedGridelements = array(); + protected $expandedGridelements = []; /** * @var int[] */ - protected $currentIdList = array(); + protected $currentIdList = []; /** * @var int[] */ - protected $currentContainerIdList = array(); + protected $currentContainerIdList = []; /** * @var bool @@ -94,7 +93,7 @@ class DatabaseRecordList extends \TYPO3\CMS\Recordlist\RecordList\DatabaseRecord * * @var string[] */ - public $allowedNewTables = array(); + public $allowedNewTables = []; /** * Used to indicate which tables (values in the array) that cannot have a @@ -102,7 +101,7 @@ class DatabaseRecordList extends \TYPO3\CMS\Recordlist\RecordList\DatabaseRecord * * @var string[] */ - public $deniedNewTables = array(); + public $deniedNewTables = []; /** * If TRUE, the control panel will contain links to the create-new wizards for @@ -148,6 +147,13 @@ class DatabaseRecordList extends \TYPO3\CMS\Recordlist\RecordList\DatabaseRecord */ public $totalRowCount; + /** + * Count of record rows in view + * + * @var int + */ + public $totalColumnCount; + /** * Space icon used for alignment * @@ -171,14 +177,14 @@ class DatabaseRecordList extends \TYPO3\CMS\Recordlist\RecordList\DatabaseRecord * * @var string[] */ - public $pageRow = array(); + public $pageRow = []; /** * Used to accumulate CSV lines for CSV export. * * @var string[] */ - protected $csvLines = array(); + protected $csvLines = []; /** * If set, the listing is returned as CSV instead. @@ -199,14 +205,14 @@ class DatabaseRecordList extends \TYPO3\CMS\Recordlist\RecordList\DatabaseRecord * * @var string[] */ - public $CBnames = array(); + public $CBnames = []; /** * [$tablename][$uid] = number of references to this record * * @var int[][] */ - protected $referenceCount = array(); + protected $referenceCount = []; /** * Translations of the current record @@ -233,7 +239,7 @@ class DatabaseRecordList extends \TYPO3\CMS\Recordlist\RecordList\DatabaseRecord * * @var string[] */ - public $MOD_MENU; + public $MOD_MENU = []; /** * If defined the records are editable @@ -267,7 +273,7 @@ public function getButtons() $module = $this->getModule(); $this->backendUser = $this->getBackendUserAuthentication(); $lang = $this->getLanguageService(); - $buttons = array( + $buttons = [ 'csh' => '', 'view' => '', 'edit' => '', @@ -282,7 +288,7 @@ public function getButtons() 'back' => '', 'csv' => '', 'export' => '' - ); + ]; // Get users permissions for this page record: $localCalcPerms = $this->backendUser->calcPerms($this->pageRow); // CSH @@ -301,25 +307,25 @@ public function getButtons() $module->modTSconfig['properties']['noViewWithDokTypes'], true); } else { //default exclusion: doktype 254 (folder), 255 (recycler) - $noViewDokTypes = array( + $noViewDokTypes = [ PageRepository::DOKTYPE_SYSFOLDER, PageRepository::DOKTYPE_RECYCLER - ); + ]; } if (!in_array($this->pageRow['doktype'], $noViewDokTypes)) { $onClick = htmlspecialchars(BackendUtility::viewOnClick($this->id, '', BackendUtility::BEgetRootLine($this->id))); - $buttons['view'] = '' . $this->iconFactory->getIcon('actions-document-view', - Icon::SIZE_SMALL)->render() . ''; + $buttons['view'] = '' + . $this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL)->render() . ''; } // New record on pages that are not locked by editlock if (!$module->modTSconfig['properties']['noCreateRecordsLink'] && $this->editLockPermissions()) { - $onClick = htmlspecialchars('return jumpExt(' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('db_new', - ['id' => $this->id])) . ');'); - $buttons['new_record'] = '' . $this->iconFactory->getIcon('actions-document-new', - Icon::SIZE_SMALL)->render() . ''; + $onClick = htmlspecialchars('return jumpExt(' . + GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('db_new', ['id' => $this->id])) . ');'); + $buttons['new_record'] = '' + . $this->iconFactory->getIcon('actions-document-new', Icon::SIZE_SMALL)->render() . ''; } // If edit permissions are set, see // \TYPO3\CMS\Core\Authentication\BackendUserAuthentication @@ -327,53 +333,61 @@ public function getButtons() // Edit $params = '&edit[pages][' . $this->pageRow['uid'] . ']=edit'; $onClick = htmlspecialchars(BackendUtility::editOnClick($params, '', -1)); - $buttons['edit'] = '' . $this->iconFactory->getIcon('actions-page-open', - Icon::SIZE_SMALL)->render() . ''; + $buttons['edit'] = '' + . $this->iconFactory->getIcon('actions-page-open', Icon::SIZE_SMALL)->render() . ''; } // Paste if ($this->showClipboard && ($localCalcPerms & Permission::PAGE_NEW || $localCalcPerms & Permission::CONTENT_EDIT) && $this->editLockPermissions()) { $elFromTable = $this->clipObj->elFromTable(''); if (!empty($elFromTable)) { - $onClick = htmlspecialchars(('return ' . $this->clipObj->confirmMsg('pages', $this->pageRow, 'into', - $elFromTable))); - $buttons['paste'] = '' . $this->iconFactory->getIcon('actions-document-paste-after', - Icon::SIZE_SMALL)->render() . ''; - } + $confirmText = $this->clipObj->confirmMsgText('pages', $this->pageRow, 'into', $elFromTable); + $buttons['paste'] = '' + . $this->iconFactory->getIcon('actions-document-paste-into', Icon::SIZE_SMALL)->render() + . ''; } } // Cache - $buttons['cache'] = '' . $this->iconFactory->getIcon('actions-system-cache-clear', - Icon::SIZE_SMALL)->render() . ''; + $buttons['cache'] = '' + . $this->iconFactory->getIcon('actions-system-cache-clear', Icon::SIZE_SMALL)->render() . ''; if ($this->table && (!isset($module->modTSconfig['properties']['noExportRecordsLinks']) || (isset($module->modTSconfig['properties']['noExportRecordsLinks']) && !$module->modTSconfig['properties']['noExportRecordsLinks']))) { // CSV - $buttons['csv'] = '' . $this->iconFactory->getIcon('actions-document-export-csv', - Icon::SIZE_SMALL)->render() . ''; + $buttons['csv'] = '' + . $this->iconFactory->getIcon('actions-document-export-csv', Icon::SIZE_SMALL)->render() . ''; // Export if (ExtensionManagementUtility::isLoaded('impexp')) { - $url = BackendUtility::getModuleUrl('xMOD_tximpexp', array('tx_impexp[action]' => 'export')); - $buttons['export'] = '' . $this->iconFactory->getIcon('actions-document-export-t3d', - Icon::SIZE_SMALL)->render() . ''; + $url = BackendUtility::getModuleUrl('xMOD_tximpexp', ['tx_impexp[action]' => 'export']); + $buttons['export'] = '' + . $this->iconFactory->getIcon('actions-document-export-t3d', Icon::SIZE_SMALL)->render() . ''; } } // Reload - $buttons['reload'] = '' . $this->iconFactory->getIcon('actions-refresh', Icon::SIZE_SMALL)->render() . ''; + $buttons['reload'] = '' + . $this->iconFactory->getIcon('actions-refresh', Icon::SIZE_SMALL)->render() . ''; // Shortcut if ($this->backendUser->mayMakeShortcut()) { - $buttons['shortcut'] = $this->getDocumentTemplate()->makeShortcutIcon('id, M, imagemode, pointer, table, search_field, search_levels, showLimit, sortField, sortRev', - implode(',', array_keys($this->MOD_MENU)), 'web_list'); + $buttons['shortcut'] = $this->getDocumentTemplate()->makeShortcutIcon( + 'id, M, imagemode, pointer, table, search_field, search_levels, showLimit, sortField, sortRev', + implode(',', array_keys($this->MOD_MENU)), 'web_list' + ); } // Back if ($this->returnUrl) { $href = htmlspecialchars(GeneralUtility::linkThisUrl($this->returnUrl, array('id' => $this->id))); - $buttons['back'] = '' . $this->iconFactory->getIcon('actions-view-go-back', - Icon::SIZE_SMALL)->render() . ''; + $buttons['back'] = '' + . $this->iconFactory->getIcon('actions-view-go-back', Icon::SIZE_SMALL)->render() . ''; } } @@ -412,21 +426,25 @@ public function getDocHeaderButtons(ModuleTemplate $moduleTemplate) $module->modTSconfig['properties']['noViewWithDokTypes'], true); } else { //default exclusion: doktype 254 (folder), 255 (recycler) - $noViewDokTypes = array( + $noViewDokTypes = [ PageRepository::DOKTYPE_SYSFOLDER, PageRepository::DOKTYPE_RECYCLER - ); + ]; } // New record on pages that are not locked by editlock if (!$module->modTSconfig['properties']['noCreateRecordsLink'] && $this->editLockPermissions()) { $onClick = 'return jumpExt(' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('db_new', ['id' => $this->id])) . ');'; - $newRecordButton = $buttonBar->makeLinkButton()->setHref('#')->setOnClick($onClick)->setTitle($lang->getLL('newRecordGeneral'))->setIcon($this->iconFactory->getIcon('actions-document-new', Icon::SIZE_SMALL)); + $newRecordButton = $buttonBar->makeLinkButton()->setHref('#')->setOnClick($onClick) + ->setTitle($lang->getLL('newRecordGeneral')) + ->setIcon($this->iconFactory->getIcon('actions-document-new', Icon::SIZE_SMALL)); $buttonBar->addButton($newRecordButton, ButtonBar::BUTTON_POSITION_LEFT, 10); } if (!in_array($this->pageRow['doktype'], $noViewDokTypes)) { $onClick = BackendUtility::viewOnClick($this->id, '', BackendUtility::BEgetRootLine($this->id)); - $viewButton = $buttonBar->makeLinkButton()->setHref('#')->setOnClick($onClick)->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.showPage'))->setIcon($this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL)); + $viewButton = $buttonBar->makeLinkButton()->setHref('#')->setOnClick($onClick) + ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.showPage')) + ->setIcon($this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL)); $buttonBar->addButton($viewButton, ButtonBar::BUTTON_POSITION_LEFT, 20); } // If edit permissions are set, see @@ -435,36 +453,57 @@ public function getDocHeaderButtons(ModuleTemplate $moduleTemplate) // Edit $params = '&edit[pages][' . $this->pageRow['uid'] . ']=edit'; $onClick = BackendUtility::editOnClick($params, '', -1); - $editButton = $buttonBar->makeLinkButton()->setHref('#')->setOnClick($onClick)->setTitle($lang->getLL('editPage'))->setIcon($this->iconFactory->getIcon('actions-page-open', Icon::SIZE_SMALL)); + $editButton = $buttonBar->makeLinkButton()->setHref('#')->setOnClick($onClick) + ->setTitle($lang->getLL('editPage')) + ->setIcon($this->iconFactory->getIcon('actions-page-open', Icon::SIZE_SMALL)); $buttonBar->addButton($editButton, ButtonBar::BUTTON_POSITION_LEFT, 20); } // Paste - if (($localCalcPerms & Permission::PAGE_NEW || $localCalcPerms & Permission::CONTENT_EDIT) && $this->editLockPermissions()) { + if ($this->showClipboard && ($localCalcPerms & Permission::PAGE_NEW || $localCalcPerms & Permission::CONTENT_EDIT) && $this->editLockPermissions()) { $elFromTable = $this->clipObj->elFromTable(''); if (!empty($elFromTable)) { - $onClick = 'return ' . $this->clipObj->confirmMsg('pages', $this->pageRow, 'into', $elFromTable); - $pasteButton = $buttonBar->makeLinkButton()->setHref($this->clipObj->pasteUrl('', - $this->id))->setOnClick($onClick)->setTitle($lang->getLL('clip_paste', - true))->setIcon($this->iconFactory->getIcon('actions-document-paste-after', Icon::SIZE_SMALL)); + $confirmMessage = $this->clipObj->confirmMsgText('pages', $this->pageRow, 'into', $elFromTable); + $pasteButton = $buttonBar->makeLinkButton() + ->setHref($this->clipObj->pasteUrl('', $this->id)) + ->setTitle($lang->getLL('clip_paste')) + ->setClasses('t3js-modal-trigger') + ->setDataAttributes([ + 'severity' => 'warning', + 'content' => $confirmMessage, + 'title' => $lang->getLL('clip_paste') + ]) + ->setIcon($this->iconFactory->getIcon('actions-document-paste-into', Icon::SIZE_SMALL)); $buttonBar->addButton($pasteButton, ButtonBar::BUTTON_POSITION_LEFT, 40); } } // Cache - $clearCacheButton = $buttonBar->makeLinkButton()->setHref($this->listURL() . '&clear_cache=1')->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.clear_cache'))->setIcon($this->iconFactory->getIcon('actions-system-cache-clear', Icon::SIZE_SMALL)); + $clearCacheButton = $buttonBar->makeLinkButton()->setHref($this->listURL() . '&clear_cache=1') + ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.clear_cache')) + ->setIcon($this->iconFactory->getIcon('actions-system-cache-clear', Icon::SIZE_SMALL)); $buttonBar->addButton($clearCacheButton, ButtonBar::BUTTON_POSITION_RIGHT); - if ($this->table && (!isset($module->modTSconfig['properties']['noExportRecordsLinks']) || (isset($module->modTSconfig['properties']['noExportRecordsLinks']) && !$module->modTSconfig['properties']['noExportRecordsLinks']))) { + if ($this->table + && (!isset($module->modTSconfig['properties']['noExportRecordsLinks']) + || !$module->modTSconfig['properties']['noExportRecordsLinks']) + ) { // CSV - $csvButton = $buttonBar->makeLinkButton()->setHref($this->listURL() . '&csv=1')->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.csv'))->setIcon($this->iconFactory->getIcon('actions-document-export-csv', Icon::SIZE_SMALL)); + $csvButton = $buttonBar->makeLinkButton()->setHref($this->listURL() . '&csv=1') + ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.csv')) + ->setIcon($this->iconFactory->getIcon('actions-document-export-csv', Icon::SIZE_SMALL)); $buttonBar->addButton($csvButton, ButtonBar::BUTTON_POSITION_LEFT, 40); // Export if (ExtensionManagementUtility::isLoaded('impexp')) { - $url = BackendUtility::getModuleUrl('xMOD_tximpexp', array('tx_impexp[action]' => 'export')); - $exportButton = $buttonBar->makeLinkButton()->setHref($url . '&tx_impexp[list][]=' . rawurlencode($this->table . ':' . $this->id))->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.export'))->setIcon($this->iconFactory->getIcon('actions-document-export-t3d', Icon::SIZE_SMALL)); + $url = BackendUtility::getModuleUrl('xMOD_tximpexp', ['tx_impexp[action]' => 'export']); + $exportButton = $buttonBar->makeLinkButton() + ->setHref($url . '&tx_impexp[list][]=' . rawurlencode($this->table . ':' . $this->id)) + ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.export')) + ->setIcon($this->iconFactory->getIcon('actions-document-export-t3d', Icon::SIZE_SMALL)); $buttonBar->addButton($exportButton, ButtonBar::BUTTON_POSITION_LEFT, 40); } } // Reload - $reloadButton = $buttonBar->makeLinkButton()->setHref($this->listURL())->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.reload'))->setIcon($this->iconFactory->getIcon('actions-refresh', Icon::SIZE_SMALL)); + $reloadButton = $buttonBar->makeLinkButton()->setHref($this->listURL()) + ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.reload')) + ->setIcon($this->iconFactory->getIcon('actions-refresh', Icon::SIZE_SMALL)); $buttonBar->addButton($reloadButton, ButtonBar::BUTTON_POSITION_RIGHT); // Shortcut if ($this->backendUser->mayMakeShortcut()) { @@ -484,9 +523,10 @@ public function getDocHeaderButtons(ModuleTemplate $moduleTemplate) } // Back if ($this->returnUrl) { - $href = htmlspecialchars(GeneralUtility::linkThisUrl($this->returnUrl, array('id' => $this->id))); - $buttons['back'] = '' . $this->iconFactory->getIcon('actions-view-go-back', Icon::SIZE_SMALL) . ''; + $href = htmlspecialchars(GeneralUtility::linkThisUrl($this->returnUrl, ['id' => $this->id])); + $buttons['back'] = '' + . $this->iconFactory->getIcon('actions-view-go-back', Icon::SIZE_SMALL) . ''; } } } @@ -521,14 +561,16 @@ public function getTable($table, $id, $rowList = '') // Init $addWhere = ''; $titleCol = $GLOBALS['TCA'][$table]['ctrl']['label']; - $thumbsCol = $GLOBALS['TCA'][$table]['ctrl']['thumbnail']; - $this->l10nEnabled = $GLOBALS['TCA'][$table]['ctrl']['languageField'] && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] && !$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable']; + $thumbsCol = !empty($GLOBALS['TCA'][$table]['ctrl']['thumbnail']) ? $GLOBALS['TCA'][$table]['ctrl']['thumbnail'] : ''; + $this->l10nEnabled = !empty($GLOBALS['TCA'][$table]['ctrl']['languageField']) + && !empty($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) + && empty($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable']); $tableCollapsed = (bool)$this->tablesCollapsed[$table]; // prepare space icon - $this->spaceIcon = '' . $this->iconFactory->getIcon('empty-empty', - Icon::SIZE_SMALL)->render() . ''; + $this->spaceIcon = '' + . $this->iconFactory->getIcon('empty-empty', Icon::SIZE_SMALL)->render() . ''; // Cleaning rowlist for duplicates and place the $titleCol as the first column always! - $this->fieldArray = array(); + $this->fieldArray = []; // title Column // Add title column $this->fieldArray[] = $titleCol; @@ -552,11 +594,14 @@ public function getTable($table, $id, $rowList = '') if ($this->localizationView && $this->l10nEnabled) { $this->fieldArray[] = '_LOCALIZATION_'; $this->fieldArray[] = '_LOCALIZATION_b'; - $addWhere .= ' AND ( - ' . $GLOBALS['TCA'][$table]['ctrl']['languageField'] . '<=0 - OR - ' . $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] . ' = 0 - )'; + // Only restrict to the default language if no search request is in place + if ($this->searchString === '') { + $addWhere .= ' AND ( + ' . $GLOBALS['TCA'][$table]['ctrl']['languageField'] . '<=0 + OR + ' . $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] . ' = 0 + )'; + } } // Cleaning up: $this->fieldArray = array_unique(array_merge($this->fieldArray, $rowListArray)); @@ -591,7 +636,7 @@ public function getTable($table, $id, $rowList = '') if (is_array($GLOBALS['TCA'][$table]['ctrl']['enablecolumns'])) { $selectFields = array_merge($selectFields, $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']); } - foreach (array('type', 'typeicon_column', 'editlock') as $field) { + foreach (['type', 'typeicon_column', 'editlock'] as $field) { if ($GLOBALS['TCA'][$table]['ctrl'][$field]) { $selectFields[] = $GLOBALS['TCA'][$table]['ctrl'][$field]; } @@ -633,8 +678,7 @@ public function getTable($table, $id, $rowList = '') foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['getTable'] as $classData) { $hookObject = GeneralUtility::getUserObj($classData); if (!$hookObject instanceof RecordListGetTableHookInterface) { - throw new \UnexpectedValueException('$hookObject must implement interface ' . RecordListGetTableHookInterface::class, - 1195114460); + throw new \UnexpectedValueException($classData . ' must implement interface ' . RecordListGetTableHookInterface::class, 1195114460); } $hookObject->getDBlistQuery($table, $id, $addWhere, $this->selFieldList, $this); } @@ -649,12 +693,12 @@ public function getTable($table, $id, $rowList = '') $this->firstElementNumber = $this->firstElementNumber - 2; $this->iLimit = $this->iLimit + 2; // (API function from TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRecordList) - $queryParts = $this->makeQueryArray($table, $id, $addWhere, $this->selFieldList); + $queryParts = $this->makeQueryArray($table, $id, $addWhere); $this->firstElementNumber = $this->firstElementNumber + 2; $this->iLimit = $this->iLimit - 2; } else { // (API function from TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRecordList) - $queryParts = $this->makeQueryArray($table, $id, $addWhere, $this->selFieldList); + $queryParts = $this->makeQueryArray($table, $id, $addWhere); } // Finding the total amount of records on the page @@ -692,18 +736,20 @@ public function getTable($table, $id, $rowList = '') $tableTitle = $table; } // Header line is drawn - $theData = array(); + $theData = []; if ($this->disableSingleTableView) { - $theData[$titleCol] = '' . BackendUtility::wrapInHelp($table, '', - $tableTitle) . ' (' . $this->totalItems . ')'; + $theData[$titleCol] = '' . BackendUtility::wrapInHelp($table, '', $tableTitle) + . ' (' . $this->totalItems . ')'; } else { - $icon = $this->table ? '' . $this->iconFactory->getIcon('actions-view-table-collapse', - Icon::SIZE_SMALL)->render() . '' : '' . $this->iconFactory->getIcon('actions-view-table-expand', - Icon::SIZE_SMALL)->render() . ''; - $theData[$titleCol] = $this->linkWrapTable($table, - $tableTitle . ' (' . $this->totalItems . ') ' . $icon); + $icon = $this->table + ? '' + . $this->iconFactory->getIcon('actions-view-table-collapse', Icon::SIZE_SMALL)->render() . '' + : '' + . $this->iconFactory->getIcon('actions-view-table-expand', Icon::SIZE_SMALL)->render() . ''; + $theData[$titleCol] = $this->linkWrapTable( + $table, + $tableTitle . ' (' . $this->totalItems . ') ' . $icon + ); } if ($listOnlyInSingleTableMode) { $tableHeader .= BackendUtility::wrapInHelp($table, '', $theData[$titleCol]); @@ -712,17 +758,23 @@ public function getTable($table, $id, $rowList = '') $collapseIcon = ''; if (!$this->table) { $href = htmlspecialchars(($this->listURL() . '&collapse[' . $table . ']=' . ($tableCollapsed ? '0' : '1'))); - $title = $tableCollapsed ? $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.expandTable', - true) : $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.collapseTable', true); - $icon = '' . $this->iconFactory->getIcon(($tableCollapsed ? 'actions-view-list-expand' : 'actions-view-list-collapse'), - Icon::SIZE_SMALL)->render() . ''; - $collapseIcon = '' . $icon . ''; + $title = $tableCollapsed + ? $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.expandTable', true) + : $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.collapseTable', true); + $icon = '' . $this->iconFactory->getIcon( + $tableCollapsed ? 'actions-view-list-expand' : 'actions-view-list-collapse', + Icon::SIZE_SMALL + )->render() . ''; + $collapseIcon = '' . $icon . ''; } $tableHeader .= $theData[$titleCol] . $collapseIcon; } // Check if gridelements containers are expanded or collapsed if ($table === 'tt_content') { - $this->expandedGridelements = array(); + $this->expandedGridelements = []; $backendUser = $this->getBackendUserAuthentication(); if (is_array($backendUser->uc['moduleData']['list']['gridelementsExpanded'])) { $this->expandedGridelements = $backendUser->uc['moduleData']['list']['gridelementsExpanded']; @@ -749,7 +801,8 @@ public function getTable($table, $id, $rowList = '') $rowOutput = ''; if (!$listOnlyInSingleTableMode || $this->table) { // Fixing an order table for sortby tables - $this->currentTable = array(); + $this->currentTable = []; + $this->currentIdList = []; $doSort = $GLOBALS['TCA'][$table]['ctrl']['sortby'] && !$this->sortField; $prevUid = 0; $prevPrevUid = 0; @@ -760,7 +813,7 @@ public function getTable($table, $id, $rowList = '') $row = $db->sql_fetch_assoc($result); $prevUid = $row['uid']; } - $accRows = array(); + $accRows = []; // Accumulate rows here while ($row = $db->sql_fetch_assoc($result)) { if (!$this->isRowListingConditionFulfilled($table, $row)) { @@ -792,8 +845,8 @@ public function getTable($table, $id, $rowList = '') $this->initCSV(); } // Render items: - $this->CBnames = array(); - $this->duplicateStack = array(); + $this->CBnames = []; + $this->duplicateStack = []; $this->eCounter = $this->firstElementNumber; $cc = 0; $lastColPos = ''; @@ -809,25 +862,26 @@ public function getTable($table, $id, $rowList = '')
'; } else { $this->showMoveUp = true; } - if (isset($row['colPos']) && isset($accRows[$key + 1]) && $row['colPos'] != $accRows[$key + 1]['colPos']) { - $this->showMoveDown = false; - } else { - $this->showMoveDown = true; - } + $this->showMoveDown = !isset($row['colPos']) || !isset($accRows[$key + 1]) + || (int)$row['colPos'] === (int)$accRows[$key + 1]['colPos']; $rowOutput .= $this->renderListRow($table, $row, $cc, $titleCol, $thumbsCol); - // If localization view is enabled it means that the selected records are - // either default or All language and here we will not select translations + // If localization view is enabled and no search happened it means that the selected + // records are either default or All language and here we will not select translations // which point to the main record: } // Counter of total rows incremented: $this->eCounter++; } + // The header row for the table is now created: + $out .= $this->renderListHeader($table, $this->currentIdList); // Record navigation is added to the beginning and end of the table if in single // table mode if ($this->table) { @@ -835,16 +889,21 @@ public function getTable($table, $id, $rowList = '') } else { // Show that there are more records than shown if ($this->totalItems > $this->itemsLimitPerTable) { - $countOnFirstPage = $this->totalItems > $this->itemsLimitSingleTable ? $this->itemsLimitSingleTable : $this->totalItems; + $countOnFirstPage = $this->totalItems > $this->itemsLimitSingleTable + ? $this->itemsLimitSingleTable + : $this->totalItems; $hasMore = $this->totalItems > $this->itemsLimitSingleTable; - $colspan = $this->showIcon ? count($this->fieldArray) + 1 + $this->maxDepth : count($this->fieldArray); + $colspan = $this->showIcon + ? count($this->fieldArray) + 1 + $this->maxDepth + : count($this->fieldArray); $rowOutput .= ''; } } - // The header row for the table is now created: - $out .= $this->renderListHeader($table, $this->currentIdList); } $collapseClass = $tableCollapsed && !$this->table ? 'collapse' : 'collapse in'; @@ -911,8 +970,7 @@ protected function getReferenceCount($tableName, $uid) { $db = $this->getDatabaseConnection(); if (!isset($this->referenceCount[$tableName][$uid])) { - $where = 'ref_table = ' . $db->fullQuoteStr($tableName, - 'sys_refindex') . ' AND ref_uid = ' . $uid . ' AND deleted = 0'; + $where = 'ref_table = ' . $db->fullQuoteStr($tableName, 'sys_refindex') . ' AND ref_uid = ' . $uid . ' AND deleted = 0'; $numberOfReferences = $db->exec_SELECTcountRows('*', 'sys_refindex', $where); $this->referenceCount[$tableName][$uid] = $numberOfReferences; } @@ -935,27 +993,24 @@ public function renderListHeader($table, $currentIdList) { $lang = $this->getLanguageService(); // Init: - $theData = array(); + $theData = []; $icon = ''; // Traverse the fields: foreach ($this->fieldArray as $fCol) { // Calculate users permissions to edit records in the table: - $permsEdit = $this->calcPerms & ($table == 'pages' ? 2 : 16) && $this->overlayEditLockPermissions($table); + $permsEdit = $this->calcPerms & ($table === 'pages' ? 2 : 16) && $this->overlayEditLockPermissions($table); switch ((string)$fCol) { case '_PATH_': // Path - $theData[$fCol] = '[' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels._PATH_', - true) . ']'; + $theData[$fCol] = '[' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels._PATH_', true) . ']'; break; case '_REF_': // References - $theData[$fCol] = '[' . $lang->sL('LLL:EXT:lang/locallang_mod_file_list.xlf:c__REF_', - true) . ']'; + $theData[$fCol] = '[' . $lang->sL('LLL:EXT:lang/locallang_mod_file_list.xlf:c__REF_', true) . ']'; break; case '_LOCALIZATION_': // Path - $theData[$fCol] = '[' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels._LOCALIZATION_', - true) . ']'; + $theData[$fCol] = '[' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels._LOCALIZATION_', true) . ']'; break; case '_LOCALIZATION_b': // Path @@ -966,20 +1021,24 @@ public function renderListHeader($table, $currentIdList) break; } // Clipboard: - $cells = array(); + $cells = []; // If there are elements on the clipboard for this table, and the parent page is not locked by editlock // then display the "paste into" icon: $elFromTable = $this->clipObj->elFromTable($table); if (!empty($elFromTable) && $this->overlayEditLockPermissions($table)) { $href = htmlspecialchars($this->clipObj->pasteUrl($table, $this->id)); - $onClick = htmlspecialchars('return ' . $this->clipObj->confirmMsg('pages', $this->pageRow, - 'into', $elFromTable)); - $cells['pasteAfter'] = '' . $this->iconFactory->getIcon('actions-document-paste-after', - Icon::SIZE_SMALL)->render() . ''; + $confirmMessage = $this->clipObj->confirmMsgText('pages', $this->pageRow, 'into', $elFromTable); + $cells['pasteAfter'] = '' + . $this->iconFactory->getIcon('actions-document-paste-into', Icon::SIZE_SMALL)->render() + . ''; } // If the numeric clipboard pads are enabled, display the control icons for that: - if ($this->clipObj->current != 'normal') { + if ($this->clipObj->current !== 'normal') { // The "select" link: $spriteIcon = $this->iconFactory->getIcon('actions-edit-copy', Icon::SIZE_SMALL)->render(); $cells['copyMarked'] = $this->linkClipboardHeaderIcon($spriteIcon, $table, 'setCB', '', $lang->getLL('clip_selectMarked')); @@ -992,9 +1051,9 @@ public function renderListHeader($table, $currentIdList) $lastElement = array_pop($onClickArray); array_push($onClickArray, $params . '&' . $lastElement); $onClick = implode('?', $onClickArray); - $cells['edit'] = '' . $this->iconFactory->getIcon('actions-document-open', - Icon::SIZE_SMALL)->render() . ''; + $cells['edit'] = '' + . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render() . ''; // The "Delete marked" link: $cells['delete'] = $this->linkClipboardHeaderIcon( $this->iconFactory->getIcon('actions-edit-delete', Icon::SIZE_SMALL)->render(), @@ -1005,8 +1064,9 @@ public function renderListHeader($table, $currentIdList) ); // The "Select all" link: $onClick = htmlspecialchars(('checkOffCB(' . GeneralUtility::quoteJSvalue(implode(',', $this->CBnames)) . ', this); return false;')); - $cells['markAll'] = '' - . $this->iconFactory->getIcon('actions-document-select', Icon::SIZE_SMALL)->render() . ''; + $cells['markAll'] = '' + . $this->iconFactory->getIcon('actions-document-select', Icon::SIZE_SMALL)->render() . ''; } else { $cells['empty'] = ''; } @@ -1021,8 +1081,7 @@ public function renderListHeader($table, $currentIdList) foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'] as $classData) { $hookObject = GeneralUtility::getUserObj($classData); if (!$hookObject instanceof RecordListHookInterface) { - throw new \UnexpectedValueException('$hookObject must implement interface ' . RecordListHookInterface::class, - 1195567850); + throw new \UnexpectedValueException($classData . ' must implement interface ' . RecordListHookInterface::class, 1195567850); } $cells = $hookObject->renderListHeaderActions($table, $currentIdList, $cells, $this); } @@ -1033,9 +1092,8 @@ public function renderListHeader($table, $currentIdList) // Control panel: if ($this->isEditable($table)) { // If new records can be created on this page, add links: - $permsAdditional = ($table === 'pages' ? 8 : 16); + $permsAdditional = $table === 'pages' ? 8 : 16; if ($table === 'tt_content') { - $expandTitle = $lang->sL('LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xlf:list.expandAllElements'); $collapseTitle = $lang->sL('LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xlf:list.collapseAllElements'); $containerIds = implode(',', array_flip(array_flip($this->currentContainerIdList))); @@ -1056,29 +1114,30 @@ class="btn btn-default t3js-toggle-gridelements-all" href="#t3-gridelements-expa // If mod.web_list.newContentWiz.overrideWithExtension is set, use that extension's create new content wizard instead: $tmpTSc = BackendUtility::getModTSconfig($this->pageinfo['uid'], 'mod.web_list'); $tmpTSc = $tmpTSc['properties']['newContentWiz.']['overrideWithExtension']; - $newContentWizScriptPath = ExtensionManagementUtility::isLoaded($tmpTSc) ? ExtensionManagementUtility::extRelPath($tmpTSc) . 'mod1/db_new_content_el.php?id=' . $this->id : BackendUtility::getModuleUrl('new_content_element', - array('id' => $this->id)); - + $newContentElementWizard = isset($tmpTSc['properties']['newContentElementWizard.']['override']) + ? $tmpTSc['properties']['newContentElementWizard.']['override'] + : 'new_content_element'; + $newContentWizScriptPath = BackendUtility::getModuleUrl($newContentElementWizard, ['id' => $this->id]); $onClick = 'return jumpExt(' . GeneralUtility::quoteJSvalue($newContentWizScriptPath) . ');'; - $icon = '' . $spriteIcon->render() . ''; - } elseif ($table == 'pages' && $this->newWizards) { + $icon = '' . $spriteIcon->render() . ''; + } elseif ($table === 'pages' && $this->newWizards) { $parameters = [ 'id' => $this->id, 'pagesOnly' => 1, 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI') ]; $href = BackendUtility::getModuleUrl('db_new', $parameters); - $icon .= '' . $spriteIcon->render() . ''; + $icon .= '' . $spriteIcon->render() . ''; } else { $params = '&edit[' . $table . '][' . $this->id . ']=new'; - if ($table == 'pages_language_overlay') { + if ($table === 'pages_language_overlay') { $params .= '&overrideVals[pages_language_overlay][doktype]=' . (int)$this->pageRow['doktype']; } - $icon .= '' . $spriteIcon->render() . ''; + $icon .= '' . $spriteIcon->render() . ''; } } // If the table can be edited, add link for editing ALL SHOWN fields for all listed records: @@ -1087,17 +1146,16 @@ class="btn btn-default t3js-toggle-gridelements-all" href="#t3-gridelements-expa if ($this->clipNumPane()) { $editIdList = '\'+editList(' . GeneralUtility::quoteJSvalue($table) . ',' . GeneralUtility::quoteJSvalue($editIdList) . ')+\''; } - $params = 'edit[' . $table . '][' . $editIdList . ']=edit&columnsOnly=' . implode(',', - $this->fieldArray); + $params = 'edit[' . $table . '][' . $editIdList . ']=edit&columnsOnly=' . implode(',', $this->fieldArray); // we need to build this uri differently, otherwise GeneralUtility::quoteJSvalue messes up the edit list function $onClick = BackendUtility::editOnClick('', '', -1); $onClickArray = explode('?', $onClick, 2); $lastElement = array_pop($onClickArray); array_push($onClickArray, $params . '&' . $lastElement); $onClick = implode('?', $onClickArray); - $icon .= '' . $this->iconFactory->getIcon('actions-document-open', - Icon::SIZE_SMALL)->render() . ''; + $icon .= '' + . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render() . ''; $icon = '
' . $icon . '
'; } // Add an empty entry, so column count fits again after moving this into $icon @@ -1123,7 +1181,8 @@ class="btn btn-default t3js-toggle-gridelements-all" href="#t3-gridelements-expa if ($this->table && is_array($currentIdList)) { // If the numeric clipboard pads are selected, show duplicate sorting link: if ($this->clipNumPane()) { - $theData[$fCol] .= '' . $this->iconFactory->getIcon('actions-document-duplicates-select', Icon::SIZE_SMALL)->render() . ''; } @@ -1142,8 +1201,9 @@ class="btn btn-default t3js-toggle-gridelements-all" href="#t3-gridelements-expa array_push($onClickArray, $params . '&' . $lastElement); $onClick = implode('?', $onClickArray); $iTitle = sprintf($lang->getLL('editThisColumn'), $sortLabel); - $theData[$fCol] .= '' . $this->iconFactory->getIcon('actions-document-open', - Icon::SIZE_SMALL)->render() . ''; + $theData[$fCol] .= '' + . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render() . ''; } if (strlen($theData[$fCol]) > 0) { $theData[$fCol] = '
' . $theData[$fCol] . '
'; @@ -1152,8 +1212,9 @@ class="btn btn-default t3js-toggle-gridelements-all" href="#t3-gridelements-expa $theData[$fCol] .= $this->addSortLink($sortLabel, $fCol, $table); } } + $this->totalColumnCount = 10 + count($theData); $headerOutput = ''; - for ($i = -11; $i < count($theData); $i++) { + for ($i = -10; $i < count($theData); $i++) { if ($i < -1) { $headerOutput .= ''; } else { @@ -1171,8 +1232,7 @@ class="btn btn-default t3js-toggle-gridelements-all" href="#t3-gridelements-expa foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'] as $classData) { $hookObject = GeneralUtility::getUserObj($classData); if (!$hookObject instanceof RecordListHookInterface) { - throw new \UnexpectedValueException('$hookObject must implement interface ' . RecordListHookInterface::class, - 1195567855); + throw new \UnexpectedValueException($classData . ' must implement interface ' . RecordListHookInterface::class, 1195567855); } $theData = $hookObject->renderListHeader($table, $currentIdList, $theData, $this); } @@ -1180,23 +1240,10 @@ class="btn btn-default t3js-toggle-gridelements-all" href="#t3-gridelements-expa $headerOutput .= '' . $this->addElement(1, $icon, $theData, '', '', '', 'th') . ''; - // Create and return header table row: return $headerOutput; } - /** - * Get pointer for first element on the page - * - * @param int $page Page number starting with 1 - * - * @return int Pointer to first element on the page (starting with 0) - */ - protected function getPointerForPage($page) - { - return ($page - 1) * $this->iLimit; - } - /** * Creates a page browser for tables with many records * @@ -1220,34 +1267,31 @@ protected function renderListNavigation($renderPart = 'top') if ($currentPage > 1) { $labelFirst = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_common.xlf:first', true); $labelPrevious = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_common.xlf:previous', true); - $first = '
  • ' . $this->iconFactory->getIcon('actions-view-paging-first', - Icon::SIZE_SMALL)->render() . '
  • '; - $previous = '
  • ' . $this->iconFactory->getIcon('actions-view-paging-previous', - Icon::SIZE_SMALL)->render() . '
  • '; + $first = '
  • ' + . $this->iconFactory->getIcon('actions-view-paging-first', Icon::SIZE_SMALL)->render() . '
  • '; + $previous = '
  • ' + . $this->iconFactory->getIcon('actions-view-paging-previous', Icon::SIZE_SMALL)->render() . '
  • '; } else { - $first = '
  • ' . $this->iconFactory->getIcon('actions-view-paging-first', - Icon::SIZE_SMALL)->render() . '
  • '; - $previous = '
  • ' . $this->iconFactory->getIcon('actions-view-paging-previous', - Icon::SIZE_SMALL)->render() . '
  • '; + $first = '
  • ' . $this->iconFactory->getIcon('actions-view-paging-first', Icon::SIZE_SMALL)->render() . '
  • '; + $previous = '
  • ' . $this->iconFactory->getIcon('actions-view-paging-previous', Icon::SIZE_SMALL)->render() . '
  • '; } if ($currentPage < $totalPages) { $labelNext = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_common.xlf:next', true); $labelLast = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_common.xlf:last', true); - $next = '
  • ' . $this->iconFactory->getIcon('actions-view-paging-next', - Icon::SIZE_SMALL)->render() . '
  • '; - $last = '
  • ' . $this->iconFactory->getIcon('actions-view-paging-last', - Icon::SIZE_SMALL)->render() . '
  • '; + $next = '
  • ' + . $this->iconFactory->getIcon('actions-view-paging-next', Icon::SIZE_SMALL)->render() . '
  • '; + $last = '
  • ' + . $this->iconFactory->getIcon('actions-view-paging-last', Icon::SIZE_SMALL)->render() . '
  • '; } else { - $next = '
  • ' . $this->iconFactory->getIcon('actions-view-paging-next', - Icon::SIZE_SMALL)->render() . '
  • '; - $last = '
  • ' . $this->iconFactory->getIcon('actions-view-paging-last', - Icon::SIZE_SMALL)->render() . '
  • '; + $next = '
  • ' . $this->iconFactory->getIcon('actions-view-paging-next', Icon::SIZE_SMALL)->render() . '
  • '; + $last = '
  • ' . $this->iconFactory->getIcon('actions-view-paging-last', Icon::SIZE_SMALL)->render() . '
  • '; } $reload = '
  • ' - . $this->iconFactory->getIcon('actions-refresh', Icon::SIZE_SMALL)->render() . '
  • '; + . $this->iconFactory->getIcon('actions-refresh', Icon::SIZE_SMALL)->render() . ''; if ($renderPart === 'top') { // Add js to traverse a page select input to a pointer value $content = ' @@ -1267,23 +1311,29 @@ function calculatePointer(page) { '; } $pageNumberInput = ' - - '; - $pageIndicatorText = sprintf($this->getLanguageService()->sL('LLL:EXT:lang/locallang_mod_web_list.xlf:pageIndicator'), - $pageNumberInput, $totalPages); + '; + $pageIndicatorText = sprintf( + $this->getLanguageService()->sL('LLL:EXT:lang/locallang_mod_web_list.xlf:pageIndicator'), + $pageNumberInput, + $totalPages + ); $pageIndicator = '
  • ' . $pageIndicatorText . '
  • '; if ($this->totalItems > $this->firstElementNumber + $this->iLimit) { $lastElementNumber = $this->firstElementNumber + $this->iLimit; } else { $lastElementNumber = $this->totalItems; } - $rangeIndicator = '
  • ' . sprintf($this->getLanguageService()->sL('LLL:EXT:lang/locallang_mod_web_list.xlf:rangeIndicator'), - ($this->firstElementNumber + 1), $lastElementNumber) . '
  • '; + $rangeIndicator = '
  • ' . sprintf( + $this->getLanguageService()->sL('LLL:EXT:lang/locallang_mod_web_list.xlf:rangeIndicator'), + $this->firstElementNumber + 1, + $lastElementNumber + ) . '
  • '; $titleColumn = $this->fieldArray[0]; - $data = array( + $data = [ $titleColumn => $content . ' ' - ); + ]; - return $this->addElement(1, '', $data); + return $this->addElement(1, '', $data, '', '', '', 'pagination'); } /********************************* @@ -1322,31 +1372,30 @@ public function makeControl($table, $row) if (ExtensionManagementUtility::isLoaded('version') && isset($row['_ORIG_uid'])) { $rowUid = $row['_ORIG_uid']; } - $cells = array( - 'primary' => array(), - 'secondary' => array() - ); + $cells = [ + 'primary' => [], + 'secondary' => [] + ]; // If the listed table is 'pages' we have to request the permission settings for each page: $localCalcPerms = 0; - if ($table == 'pages') { - $localCalcPerms = $this->getBackendUserAuthentication()->calcPerms(BackendUtility::getRecord('pages', - $row['uid'])); + if ($table === 'pages') { + $localCalcPerms = $this->getBackendUserAuthentication()->calcPerms(BackendUtility::getRecord('pages', $row['uid'])); } $permsEdit = $table === 'pages' && $this->getBackendUserAuthentication()->checkLanguageAccess(0) && $localCalcPerms & Permission::PAGE_EDIT || $table !== 'pages' - && $this->calcPerms & Permission::CONTENT_EDIT; + && $this->calcPerms & Permission::CONTENT_EDIT + && $this->getBackendUserAuthentication()->recordEditAccessInternals($table, $row); $permsEdit = $this->overlayEditLockPermissions($table, $row, $permsEdit); // hides the move, copy, cut and paste icons for localized records - doesn't make much sense to perform these options for them - $isL10nOverlay = $table != 'pages_language_overlay' && $row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] != 0; + $isL10nOverlay = $table !== 'pages_language_overlay' && $row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] != 0; // "Show" link (only pages and tt_content elements) - if ($table == 'pages' || $table == 'tt_content') { - $viewAction = '' . $this->iconFactory->getIcon('actions-document-view', - Icon::SIZE_SMALL)->render() . ''; + if ($table === 'pages' || $table === 'tt_content') { + $viewAction = '' + . $this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL)->render() . ''; $this->addActionToCellGroup($cells, $viewAction, 'view'); } // "Edit" link: ( Only if permissions to edit the page-record of the content of the parent page ($this->id) @@ -1354,27 +1403,27 @@ public function makeControl($table, $row) $params = '&edit[' . $table . '][' . $row['uid'] . ']=edit'; $iconIdentifier = 'actions-document-open'; $overlayIdentifier = !$this->isEditable($table) ? 'overlay-readonly' : null; - $editAction = '' . $this->iconFactory->getIcon($iconIdentifier, Icon::SIZE_SMALL, - $overlayIdentifier)->render() . ''; + $editAction = '' + . $this->iconFactory->getIcon($iconIdentifier, Icon::SIZE_SMALL, $overlayIdentifier)->render() . ''; } else { $editAction = $this->spaceIcon; } $this->addActionToCellGroup($cells, $editAction, 'edit'); // "Info": (All records) $onClick = 'top.launchView(' . GeneralUtility::quoteJSvalue($table) . ', ' . (int)$row['uid'] . '); return false;'; - $viewBigAction = '' . $this->iconFactory->getIcon('actions-document-info', - Icon::SIZE_SMALL)->render() . ''; + $viewBigAction = '' + . $this->iconFactory->getIcon('actions-document-info', Icon::SIZE_SMALL)->render() . ''; $this->addActionToCellGroup($cells, $viewBigAction, 'viewBig'); // "Move" wizard link for pages/tt_content elements: if ($permsEdit && ($table === 'tt_content' || $table === 'pages') && !$isL10nOverlay) { - $onClick = 'return jumpExt(\'' . BackendUtility::getModuleUrl('move_element') . '&table=' . $table . '&uid=' . $row['uid'] . '\');'; - $linkTitleLL = $this->getLanguageService()->getLL('move_' . ($table === 'tt_content' ? 'record' : 'page'), - true); - $icon = ($table == 'pages' ? $this->iconFactory->getIcon('actions-page-move', - Icon::SIZE_SMALL) : $this->iconFactory->getIcon('actions-document-move', Icon::SIZE_SMALL)); + $onClick = 'return jumpExt(' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('move_element') . '&table=' . $table . '&uid=' . $row['uid']) . ');'; + $linkTitleLL = $this->getLanguageService()->getLL('move_' . ($table === 'tt_content' ? 'record' : 'page'), true); + $icon = $table === 'pages' + ? $this->iconFactory->getIcon('actions-page-move', Icon::SIZE_SMALL) + : $this->iconFactory->getIcon('actions-document-move', Icon::SIZE_SMALL); $moveAction = '' . $icon->render() . ''; } else { $moveAction = $this->spaceIcon; @@ -1383,11 +1432,11 @@ public function makeControl($table, $row) // If the table is NOT a read-only table, then show these links: if ($this->isEditable($table)) { // "Revert" link (history/undo) - $moduleUrl = BackendUtility::getModuleUrl('record_history', array('element' => $table . ':' . $row['uid'])); + $moduleUrl = BackendUtility::getModuleUrl('record_history', ['element' => $table . ':' . $row['uid']]); $onClick = 'return jumpExt(' . GeneralUtility::quoteJSvalue($moduleUrl) . ',\'#latest\');'; - $historyAction = '' . $this->iconFactory->getIcon('actions-document-history-open', - Icon::SIZE_SMALL)->render() . ''; + $historyAction = '' + . $this->iconFactory->getIcon('actions-document-history-open', Icon::SIZE_SMALL)->render() . ''; $this->addActionToCellGroup($cells, $historyAction, 'history'); // Versioning: if (ExtensionManagementUtility::isLoaded('version') && !ExtensionManagementUtility::isLoaded('workspaces')) { @@ -1395,40 +1444,39 @@ public function makeControl($table, $row) $this->getBackendUserAuthentication()->workspace, false, $row); // If table can be versionized. if (is_array($vers)) { - $href = BackendUtility::getModuleUrl('web_txversionM1', array( + $href = BackendUtility::getModuleUrl('web_txversionM1', [ 'table' => $table, 'uid' => $row['uid'] - )); - $versionAction = '' . $this->iconFactory->getIcon('actions-version-open', - Icon::SIZE_SMALL)->render() . ''; + ]); + $versionAction = '' + . $this->iconFactory->getIcon('actions-version-page-open', Icon::SIZE_SMALL)->render() . ''; $this->addActionToCellGroup($cells, $versionAction, 'version'); } } // "Edit Perms" link: - if ($table === 'pages' && $this->getBackendUserAuthentication()->check('modules', - 'system_BeuserTxPermission') && ExtensionManagementUtility::isLoaded('beuser') - ) { - $href = BackendUtility::getModuleUrl('system_BeuserTxPermission') . '&id=' . $row['uid'] . '&return_id=' . $row['uid'] . '&edit=1'; - $permsAction = '' . $this->iconFactory->getIcon('status-status-locked', - Icon::SIZE_SMALL)->render() . ''; + if ($table === 'pages' && $this->getBackendUserAuthentication()->check('modules', 'system_BeuserTxPermission') && ExtensionManagementUtility::isLoaded('beuser')) { + $href = BackendUtility::getModuleUrl('system_BeuserTxPermission') . '&id=' . $row['uid'] . '&returnId=' . $row['uid'] . '&tx_beuser_system_beusertxpermission[action]=edit'; + $permsAction = '' + . $this->iconFactory->getIcon('status-status-locked', Icon::SIZE_SMALL)->render() . ''; $this->addActionToCellGroup($cells, $permsAction, 'perms'); } // "New record after" link (ONLY if the records in the table are sorted by a "sortby"-row // or if default values can depend on previous record): - if (($GLOBALS['TCA'][$table]['ctrl']['sortby'] || $GLOBALS['TCA'][$table]['ctrl']['useColumnsForDefaultValues']) && $permsEdit) { - if ($table !== 'pages' && $this->calcPerms & Permission::CONTENT_EDIT || $table === 'pages' && $this->calcPerms & Permission::PAGE_NEW) { + if ($permsEdit && (!empty($GLOBALS['TCA'][$table]['ctrl']['sortby']) || !empty($GLOBALS['TCA'][$table]['ctrl']['useColumnsForDefaultValues']))) { + if ($table !== 'pages' && $this->calcPerms & Permission::CONTENT_EDIT + || $table === 'pages' && $this->calcPerms & Permission::PAGE_NEW + ) { if ($this->showNewRecLink($table)) { $params = '&edit[' . $table . '][' . -($row['_MOVE_PLH'] ? $row['_MOVE_PLH_uid'] : $row['uid']) . ']=new'; - $icon = ($table == 'pages' ? $this->iconFactory->getIcon('actions-page-new', Icon::SIZE_SMALL) : $this->iconFactory->getIcon('actions-add', Icon::SIZE_SMALL)); + $icon = ($table === 'pages' ? $this->iconFactory->getIcon('actions-page-new', Icon::SIZE_SMALL) : $this->iconFactory->getIcon('actions-add', Icon::SIZE_SMALL)); $titleLabel = 'new'; if ($GLOBALS['TCA'][$table]['ctrl']['sortby']) { $titleLabel .= ($table === 'pages' ? 'Page' : 'Record'); } $newAction = '' - . $icon->render() . ''; + . '" title="' . htmlspecialchars($this->getLanguageService()->getLL($titleLabel)) . '">' . $icon->render() . ''; $this->addActionToCellGroup($cells, $newAction, 'new'); } } @@ -1438,10 +1486,10 @@ public function makeControl($table, $row) if (isset($this->currentTable['prev'][$row['uid']]) && $this->showMoveUp === true && !$isL10nOverlay) { // Up $params = '&cmd[' . $table . '][' . $row['uid'] . '][move]=' . $this->currentTable['prev'][$row['uid']]; - $moveUpAction = '' . $this->iconFactory->getIcon('actions-move-up', - Icon::SIZE_SMALL)->render() . ''; + $moveUpAction = '' + . $this->iconFactory->getIcon('actions-move-up', Icon::SIZE_SMALL)->render() . ''; } else { $moveUpAction = $this->spaceIcon; } @@ -1450,52 +1498,63 @@ public function makeControl($table, $row) if ($this->currentTable['next'][$row['uid']] && $this->showMoveDown === true && !$isL10nOverlay) { // Down $params = '&cmd[' . $table . '][' . $row['uid'] . '][move]=' . $this->currentTable['next'][$row['uid']]; - $moveDownAction = '' . $this->iconFactory->getIcon('actions-move-down', - Icon::SIZE_SMALL)->render() . ''; + $moveDownAction = '' + . $this->iconFactory->getIcon('actions-move-down', Icon::SIZE_SMALL)->render() . ''; } else { $moveDownAction = $this->spaceIcon; } $this->addActionToCellGroup($cells, $moveDownAction, 'moveDown'); } + // "Hide/Unhide" links: $hiddenField = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled']; - - if ($permsEdit && $hiddenField && $GLOBALS['TCA'][$table]['columns'][$hiddenField] && (!$GLOBALS['TCA'][$table]['columns'][$hiddenField]['exclude'] || $this->getBackendUserAuthentication()->check('non_exclude_fields', - $table . ':' . $hiddenField)) + if (!empty($GLOBALS['TCA'][$table]['columns'][$hiddenField]) + && (empty($GLOBALS['TCA'][$table]['columns'][$hiddenField]['exclude']) + || $this->getBackendUserAuthentication()->check('non_exclude_fields', $table . ':' . $hiddenField)) ) { - if ($this->isRecordCurrentBackendUser($table, $row)) { + if (!$permsEdit || $this->isRecordCurrentBackendUser($table, $row)) { $hideAction = $this->spaceIcon; } else { - $hideTitle = $this->getLanguageService()->getLL('hide' . ($table == 'pages' ? 'Page' : ''), true); - $unhideTitle = $this->getLanguageService()->getLL('unHide' . ($table == 'pages' ? 'Page' : ''), + $hideTitle = $this->getLanguageService()->getLL('hide' . ($table === 'pages' ? 'Page' : ''), true); + $unhideTitle = $this->getLanguageService()->getLL('unHide' . ($table === 'pages' ? 'Page' : ''), true); if ($row[$hiddenField]) { $params = 'data[' . $table . '][' . $rowUid . '][' . $hiddenField . ']=0'; - $hideAction = '' . $this->iconFactory->getIcon('actions-edit-unhide', - Icon::SIZE_SMALL)->render() . ''; + $hideAction = '' + . $this->iconFactory->getIcon('actions-edit-unhide', Icon::SIZE_SMALL)->render() . ''; } else { $params = 'data[' . $table . '][' . $rowUid . '][' . $hiddenField . ']=1'; - $hideAction = '' . $this->iconFactory->getIcon('actions-edit-hide', - Icon::SIZE_SMALL)->render() . ''; + $hideAction = '' + . $this->iconFactory->getIcon('actions-edit-hide', Icon::SIZE_SMALL)->render() . ''; } } $this->addActionToCellGroup($cells, $hideAction, 'hide'); } // "Delete" link: - if ($permsEdit && ($table === 'pages' && $localCalcPerms & Permission::PAGE_DELETE || $table !== 'pages' && $this->calcPerms & Permission::CONTENT_EDIT)) { - // Check if the record version is in "deleted" state, because that will switch the action to "restore" + $disableDeleteTS = $this->getBackendUserAuthentication()->getTSConfig('options.disableDelete'); + $disableDelete = (bool) trim(isset($disableDeleteTS['properties'][$table]) ? $disableDeleteTS['properties'][$table] : $disableDeleteTS['value']); + if ($permsEdit && !$disableDelete && ($table === 'pages' && $localCalcPerms & Permission::PAGE_DELETE || $table !== 'pages' && $this->calcPerms & Permission::CONTENT_EDIT)) { // Check if the record version is in "deleted" state, because that will switch the action to "restore" if ($this->getBackendUserAuthentication()->workspace > 0 && isset($row['t3ver_state']) && (int)$row['t3ver_state'] === 2) { $actionName = 'restore'; $refCountMsg = ''; } else { $actionName = 'delete'; - $refCountMsg = BackendUtility::referenceCount($table, $row['uid'], - ' ' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.referencesToRecord'), - $this->getReferenceCount($table, $row['uid'])) . BackendUtility::translationCount($table, - $row['uid'], - ' ' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.translationsOfRecord')); + $refCountMsg = BackendUtility::referenceCount( + $table, + $row['uid'], + ' ' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.referencesToRecord'), + $this->getReferenceCount($table, $row['uid']) + ) . BackendUtility::translationCount( + $table, + $row['uid'], + ' ' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlflabels.translationsOfRecord') + ); } if ($this->isRecordCurrentBackendUser($table, $row)) { @@ -1515,14 +1574,14 @@ public function makeControl($table, $row) } $this->addActionToCellGroup($cells, $deleteAction, 'delete'); // "Levels" links: Moving pages into new levels... - if ($permsEdit && $table == 'pages' && !$this->searchLevels) { + if ($permsEdit && $table === 'pages' && !$this->searchLevels) { // Up (Paste as the page right after the current parent page) if ($this->calcPerms & Permission::PAGE_NEW) { $params = '&cmd[' . $table . '][' . $row['uid'] . '][move]=' . -$this->id; - $moveLeftAction = '' . $this->iconFactory->getIcon('actions-move-left', - Icon::SIZE_SMALL)->render() . ''; + $moveLeftAction = '' + . $this->iconFactory->getIcon('actions-move-left', Icon::SIZE_SMALL)->render() . ''; $this->addActionToCellGroup($cells, $moveLeftAction, 'moveLeft'); } // Down (Paste as subpage to the page right above) @@ -1531,10 +1590,10 @@ public function makeControl($table, $row) $this->currentTable['prevUid'][$row['uid']])); if ($localCalcPerms & Permission::PAGE_NEW) { $params = '&cmd[' . $table . '][' . $row['uid'] . '][move]=' . $this->currentTable['prevUid'][$row['uid']]; - $moveRightAction = '' . $this->iconFactory->getIcon('actions-move-right', - Icon::SIZE_SMALL)->render() . ''; + $moveRightAction = '' + . $this->iconFactory->getIcon('actions-move-right', Icon::SIZE_SMALL)->render() . ''; } else { $moveRightAction = $this->spaceIcon; } @@ -1549,7 +1608,7 @@ public function makeControl($table, $row) */ if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['recStatInfoHooks'])) { $stat = ''; - $_params = array($table, $row['uid']); + $_params = [$table, $row['uid']]; foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['recStatInfoHooks'] as $_funcRef) { $stat .= GeneralUtility::callUserFunction($_funcRef, $_params, $this); } @@ -1573,8 +1632,7 @@ public function makeControl($table, $row) foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'] as $classData) { $hookObject = GeneralUtility::getUserObj($classData); if (!$hookObject instanceof RecordListHookInterface) { - throw new \UnexpectedValueException('$hookObject must implement interface ' . RecordListHookInterface::class, - 1195567840); + throw new \UnexpectedValueException($classData . ' must implement interface ' . RecordListHookInterface::class, 1195567840); } $cells = $hookObject->makeControl($table, $row, $cells, $this); } @@ -1596,7 +1654,11 @@ public function makeControl($table, $row) foreach ($actions as $action) { $cellOutput .= $action; } - $output .= '
    ' . '' . $cellOutput . '' . '' . '
    '; + $output .= '
    ' . '' . $cellOutput . '' + . '' . '
    '; } else { $output .= '
    ' . implode('', $actions) . '
    '; } @@ -1620,10 +1682,10 @@ public function makeClip($table, $row) if (!$this->getModule()->MOD_SETTINGS['clipBoard']) { return ''; } - $cells = array(); + $cells = []; $cells['pasteAfter'] = ($cells['pasteInto'] = $this->spaceIcon); // hides the move, copy, cut and paste icons for localized records - doesn't make much sense to perform these options for them - $isL10nOverlay = $table != 'pages_language_overlay' && $row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] != 0; + $isL10nOverlay = $table !== 'pages_language_overlay' && $row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] != 0; // Return blank, if disabled: // Whether a numeric clipboard pad is active or the normal pad we will see different content of the panel: // For the "Normal" pad: @@ -1644,16 +1706,39 @@ public function makeClip($table, $row) } $cells['copy'] = '' . $copyIcon->render() . ''; - if (true) { - $cells['cut'] = '' - . $cutIcon->render() . ''; + // Check permission to cut page or content + if ($table == 'pages') { + $localCalcPerms = $this->getBackendUserAuthentication()->calcPerms(BackendUtility::getRecord('pages', $row['uid'])); + $permsEdit = $localCalcPerms & Permission::PAGE_EDIT; } else { - $cells['cut'] = $this->spaceIcon; + $permsEdit = $this->calcPerms & Permission::CONTENT_EDIT; + } + $permsEdit = $this->overlayEditLockPermissions($table, $row, $permsEdit); + + // If the listed table is 'pages' we have to request the permission settings for each page: + if ($table == 'pages') { + if ($permsEdit) { + $cells['cut'] = '' + . $cutIcon->render() . ''; + } else { + $cells['cut'] = $this->spaceIcon; + } + } else { + if ($table !== 'pages' && $this->calcPerms & Permission::CONTENT_EDIT) { + $cells['cut'] = '' + . $cutIcon->render() . ''; + } else { + $cells['cut'] = $this->spaceIcon; + } } } } else { @@ -1672,29 +1757,35 @@ public function makeClip($table, $row) $this->duplicateStack[] = $row[$this->duplicateField]; } // Adding the checkbox to the panel: - $cells['select'] = $isL10nOverlay ? $this->spaceIcon : ''; + $cells['select'] = $isL10nOverlay + ? $this->spaceIcon + : ''; } // Now, looking for selected elements from the current table: $elFromTable = $this->clipObj->elFromTable($table); if (!empty($elFromTable) && $GLOBALS['TCA'][$table]['ctrl']['sortby']) { // IF elements are found, they can be individually ordered and are not locked by editlock, then add a "paste after" icon: - $cells['pasteAfter'] = $isL10nOverlay || !$this->overlayEditLockPermissions($table, - $row) ? $this->spaceIcon : '' . $this->iconFactory->getIcon('actions-document-paste-after', - Icon::SIZE_SMALL)->render() . ''; + $cells['pasteAfter'] = $isL10nOverlay || !$this->overlayEditLockPermissions($table, $row) + ? $this->spaceIcon + : '' + . $this->iconFactory->getIcon('actions-document-paste-after', Icon::SIZE_SMALL)->render() . ''; } // Now, looking for elements in general: $elFromTable = $this->clipObj->elFromTable(''); - if ($table == 'pages' && !empty($elFromTable)) { - $cells['pasteInto'] = '' . $this->iconFactory->getIcon('actions-document-paste-into', - Icon::SIZE_SMALL)->render() . ''; + if ($table === 'pages' && !empty($elFromTable)) { + $cells['pasteInto'] = '' + . $this->iconFactory->getIcon('actions-document-paste-into', Icon::SIZE_SMALL)->render() . ''; } /** * @hook makeClip: Allows to change clip-icons of records in list-module @@ -1707,8 +1798,7 @@ public function makeClip($table, $row) foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'] as $classData) { $hookObject = GeneralUtility::getUserObj($classData); if (!$hookObject instanceof RecordListHookInterface) { - throw new \UnexpectedValueException('$hookObject must implement interface ' . RecordListHookInterface::class, - 1195567845); + throw new \UnexpectedValueException($classData . ' must implement interface ' . RecordListHookInterface::class, 1195567845); } $cells = $hookObject->makeClip($table, $row, $cells, $this); } @@ -1728,7 +1818,7 @@ public function makeClip($table, $row) * @param string $titleCol Table field (column) where header value is found * @param string $thumbsCol Table field (column) where (possible) thumbnails can be found * @param int $indent Indent from left. - * @param integer $level + * @param int $level * @param string $expanded * * @return string Table row for the element @@ -1765,12 +1855,11 @@ public function renderListRow($table, $row, $cc, $titleCol, $thumbsCol, $indent // The icon with link $altText = BackendUtility::getRecordIconAltText($row, $table); $additionalStyle = $indent ? ' style="margin-left: ' . $indent . 'px;"' : ''; - $iconImg = '' . $this->iconFactory->getIconForRecord($table, - $row, Icon::SIZE_SMALL)->render() . ''; - $theIcon = $this->clickMenuEnabled ? BackendUtility::wrapClickMenuOnIcon($iconImg, $table, - $row['uid']) : $iconImg; + $iconImg = '' + . $this->iconFactory->getIconForRecord($table, $row, Icon::SIZE_SMALL)->render() . ''; + $theIcon = $this->clickMenuEnabled ? BackendUtility::wrapClickMenuOnIcon($iconImg, $table, $row['uid']) : $iconImg; // Preparing and getting the data-array - $theData = array(); + $theData = []; $localizationMarkerClass = ''; $lC2 = ''; foreach ($this->fieldArray as $fCol) { @@ -1780,11 +1869,11 @@ public function renderListRow($table, $row, $cc, $titleCol, $thumbsCol, $indent // If the record is edit-locked by another user, we will show a little warning sign: $lockInfo = BackendUtility::isRecordLocked($table, $row['uid']); if ($lockInfo) { - $warning = '' . $this->iconFactory->getIcon('status-warning-in-use', - Icon::SIZE_SMALL)->render() . ''; + $warning = '' + . $this->iconFactory->getIcon('status-warning-in-use', Icon::SIZE_SMALL)->render() . ''; } - $theData[$fCol] = $theData['__label'] = $warning . $this->linkWrapItems($table, $row['uid'], $recTitle, - $row); + $theData[$fCol] = $theData['__label'] = $warning . $this->linkWrapItems($table, $row['uid'], $recTitle, $row); // Render thumbnails, if: // - a thumbnail column exists // - there is content in it @@ -1801,39 +1890,43 @@ public function renderListRow($table, $row, $cc, $titleCol, $thumbsCol, $indent } $visibleColumns = $GLOBALS['TCA'][$table]['types'][$type]['showitem']; - if ($this->thumbs && trim($row[$thumbsCol]) && preg_match('/(^|(.*(;|,)?))' . $thumbsCol . '(((;|,).*)|$)/', - $visibleColumns) === 1 + if ($this->thumbs && trim($row[$thumbsCol]) + && preg_match('/(^|(.*(;|,)?))' . $thumbsCol . '(((;|,).*)|$)/', $visibleColumns) === 1 ) { - $theData[$fCol] .= '
    ' . $this->thumbCode($row, $table, $thumbsCol); + $thumbCode = '
    ' . $this->thumbCode($row, $table, $thumbsCol); + $theData[$fCol] .= $thumbCode; + $theData['__label'] .= $thumbCode; } - if (isset($GLOBALS['TCA'][$table]['ctrl']['languageField']) && $row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] != 0 && $row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] != 0) { + if (isset($GLOBALS['TCA'][$table]['ctrl']['languageField']) + && $row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] + && $row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] + ) { // It's a translated record with a language parent $localizationMarkerClass = ' localization'; } - } elseif ($fCol == 'pid') { + } elseif ($fCol === 'pid') { $theData[$fCol] = $row[$fCol]; - } elseif ($fCol == '_PATH_') { + } elseif ($fCol === '_PATH_') { $theData[$fCol] = $this->recPath($row['pid']); - } elseif ($fCol == '_REF_') { + } elseif ($fCol === '_REF_') { $theData[$fCol] = $this->createReferenceHtml($table, $row['uid']); - } elseif ($fCol == '_CONTROL_') { - $theData[$fCol] = $this->makeControl($table, $row, $level); - } elseif ($fCol == '_CLIPBOARD_') { + } elseif ($fCol === '_CONTROL_') { + $theData[$fCol] = $this->makeControl($table, $row); + } elseif ($fCol === '_CLIPBOARD_') { $theData[$fCol] = $this->makeClip($table, $row); - } elseif ($fCol == '_LOCALIZATION_') { + } elseif ($fCol === '_LOCALIZATION_') { list($lC1, $lC2) = $this->makeLocalizationPanel($table, $row); $theData[$fCol] = $lC1; - } elseif ($fCol != '_LOCALIZATION_b') { + } elseif ($fCol !== '_LOCALIZATION_b') { $tmpProc = BackendUtility::getProcessedValueExtra($table, $fCol, $row[$fCol], 100, $row['uid']); $theData[$fCol] = $this->linkUrlMail(htmlspecialchars($tmpProc), $row[$fCol]); if ($this->csvOutput) { $row[$fCol] = BackendUtility::getProcessedValueExtra($table, $fCol, $row[$fCol], 0, $row['uid']); } - } elseif ($fCol == '_LOCALIZATION_b') { + } elseif ($fCol === '_LOCALIZATION_b') { $theData[$fCol] = $lC2; } else { - $theData[$fCol] = htmlspecialchars(BackendUtility::getProcessedValueExtra($table, $fCol, $row[$fCol], 0, - $row['uid'])); + $theData[$fCol] = htmlspecialchars(BackendUtility::getProcessedValueExtra($table, $fCol, $row[$fCol], 0, $row['uid'])); } } // Reset the ID if it was overwritten @@ -1869,21 +1962,25 @@ public function renderListRow($table, $row, $cc, $titleCol, $thumbsCol, $indent // Create element in table cells: $theData['uid'] = $row['uid']; if ($table === 'tt_content') { - $theData['tx_gridelements_container'] = $row['tx_gridelements_container']; + $theData['tx_gridelements_container'] = (int)$row['tx_gridelements_container']; } - if (isset($GLOBALS['TCA'][$table]['ctrl']['languageField']) && isset($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) && !isset($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable'])) { - $theData['parent'] = $row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']]; + if (isset($GLOBALS['TCA'][$table]['ctrl']['languageField']) + && isset($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) + && !isset($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable']) + ) { + $theData['_l10nparent_'] = $row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']]; } $rowOutput .= $this->addElement(1, $theIcon, $theData, $row_bgColor, '', '', '', $level); - if ($this->localizationView && $this->l10nEnabled) { + if ($this->localizationView && $this->l10nEnabled && $this->searchString === '') { // For each available translation, render the record: if (is_array($this->translations)) { foreach ($this->translations as $lRow) { // $lRow isn't always what we want - if record was moved we've to work with the // placeholder records otherwise the list is messed up a bit if ($row['_MOVE_PLH_uid'] && $row['_MOVE_PLH_pid']) { - $where = 't3ver_move_id="' . (int)$lRow['uid'] . '" AND pid="' . $row['_MOVE_PLH_pid'] . '" AND t3ver_wsid=' . $row['t3ver_wsid'] . BackendUtility::deleteClause($table); + $where = 't3ver_move_id="' . (int)$lRow['uid'] . '" AND pid="' . $row['_MOVE_PLH_pid'] + . '" AND t3ver_wsid=' . $row['t3ver_wsid'] . BackendUtility::deleteClause($table); $tmpRow = BackendUtility::getRecordRaw($table, $where, $this->selFieldList); $lRow = is_array($tmpRow) ? $tmpRow : $lRow; } @@ -1900,55 +1997,54 @@ public function renderListRow($table, $row, $cc, $titleCol, $thumbsCol, $indent } } - if ($theData['_EXPANDABLE_'] && $level < 8 && ($row['l18n_parent'] == 0 || !$this->localizationView)) { - if (!empty($theData['_CHILDREN_'])) { - $expanded = $this->expandedGridelements[$row['uid']] ? '" style="display: table-row;' : ''; - $lastGridColumn = ''; - $originalMoveUp = $this->showMoveUp; - $originalMoveDown = $this->showMoveDown; - $prevPrevUid = (int)$theData['_CHILDREN_'][0]['uid']; - $prevUid = (int)$theData['_CHILDREN_'][1]['uid']; - foreach ($theData['_CHILDREN_'] as $key => $child) { - if ($key > 1) { - if ($prevUid) { - $this->currentTable['prev'][$child['uid']] = $prevPrevUid; - $this->currentTable['next'][$prevUid] = -(int)$child['uid']; - $this->currentTable['prevUid'][$child['uid']] = $prevUid; - } - $prevPrevUid = isset($this->currentTable['prev'][$child['uid']]) ? -$prevUid : $row['pid']; - $prevUid = $child['uid']; - } + if ($theData['_EXPANDABLE_'] && $level < 8 && ($row['l18n_parent'] == 0 || !$this->localizationView) && !empty($theData['_CHILDREN_'])) { + $expanded = $this->expandedGridelements[$row['uid']] ? '" style="display: table-row;' : ''; + $previousGridColumn = ''; + $originalMoveUp = $this->showMoveUp; + $originalMoveDown = $this->showMoveDown; + foreach ($theData['_CHILDREN_'] as $key => $child) { + if (isset($child['tx_gridelements_columns']) && ($child['tx_gridelements_columns'] !== $previousGridColumn)) { + $previousGridColumn = $child['tx_gridelements_columns']; + $this->currentTable['prev'][$child['uid']] = (int)$row['pid']; + } else if (isset($theData['_CHILDREN_'][$key-2]) && $theData['_CHILDREN_'][$key-2]['tx_gridelements_columns'] === $child['tx_gridelements_columns']) { + $this->currentTable['prev'][$child['uid']] = -(int)$theData['_CHILDREN_'][$key-2]['uid']; + } else { + $this->currentTable['prev'][$child['uid']] = (int)$row['pid']; } - foreach ($theData['_CHILDREN_'] as $key => $child) { - if (isset($child['tx_gridelements_columns']) && ($child['tx_gridelements_columns'] != $lastGridColumn)) { - $lastGridColumn = $child['tx_gridelements_columns']; - $this->showMoveUp = false; - $rowOutput .= ' - - - '; - } else { - $this->showMoveUp = true; - } - if (isset($child['tx_gridelements_columns']) && isset($theData['_CHILDREN_'][$key + 1]) && $child['tx_gridelements_columns'] != $theData['_CHILDREN_'][$key + 1]['tx_gridelements_columns']) { - $this->showMoveDown = false; - } else { - $this->showMoveDown = true; - } - $this->currentIdList[] = $child['uid']; - if ($row['CType'] === 'gridelements_pi1') { - $this->currentContainerIdList[] = $row['uid']; - } - $child['_CSSCLASS'] = 't3-gridelements-child" data-trigger-container="' . ($this->localizationView && $row['l18n_parent'] ? $row['l18n_parent'] : $row['uid']) . $expanded; - $rowOutput .= $this->renderListRow($table, $child, $cc, $titleCol, $thumbsCol, 0, $level + 1, - $expanded); + if (isset($theData['_CHILDREN_'][$key+1]) && $theData['_CHILDREN_'][$key+1]['tx_gridelements_columns'] === $child['tx_gridelements_columns']) { + $this->currentTable['next'][$child['uid']] = -(int)$theData['_CHILDREN_'][$key+1]['uid']; } - $this->showMoveUp = $originalMoveUp; - $this->showMoveDown = $originalMoveDown; } + $previousGridColumn = ''; + foreach ($theData['_CHILDREN_'] as $key => $child) { + if (isset($child['tx_gridelements_columns']) && ($child['tx_gridelements_columns'] !== $previousGridColumn)) { + $previousGridColumn = $child['tx_gridelements_columns']; + $this->showMoveUp = false; + $rowOutput .= ' + + + '; + } else { + $this->showMoveUp = true; + } + $this->showMoveDown = !isset($child['tx_gridelements_columns']) || !isset($theData['_CHILDREN_'][$key + 1]) + || (int)$child['tx_gridelements_columns'] === (int)$theData['_CHILDREN_'][$key + 1]['tx_gridelements_columns']; + $this->currentIdList[] = $child['uid']; + if ($row['CType'] === 'gridelements_pi1') { + $this->currentContainerIdList[] = $row['uid']; + } + $child['_CSSCLASS'] = 't3-gridelements-child" data-trigger-container="' + . ($this->localizationView && $row['l18n_parent'] ? $row['l18n_parent'] : $row['uid']) . $expanded; + $rowOutput .= $this->renderListRow($table, $child, $cc, $titleCol, $thumbsCol, 0, $level + 1, $expanded); + } + $this->showMoveUp = $originalMoveUp; + $this->showMoveDown = $originalMoveDown; } // Finally, return table row element: @@ -1959,12 +2055,12 @@ public function renderListRow($table, $row, $cc, $titleCol, $thumbsCol, $indent * Returns a table-row with the content from the fields in the input data array. * OBS: $this->fieldArray MUST be set! (represents the list of fields to display) * - * @param int $h Is an integer >=0 and denotes how tall an element is. Set to '0' makes a halv line, -1 = full line, set to 1 makes a 'join' and above makes 'line' + * @param int $h Is an int >=0 and denotes how tall an element is. Set to '0' makes a halv line, -1 = full line, set to 1 makes a 'join' and above makes 'line' * @param string $icon Is the + of the record. If not supplied the first 'join'-icon will be a 'line' instead * @param array $data Is the dataarray, record with the fields. Notice: These fields are (currently) NOT htmlspecialchar'ed before being wrapped in -tags. Must carry a ' ' as first character * @param string $_ OBSOLETE - NOT USED ANYMORE. $lMargin is the leftMargin (int) - * @param string $_ OBSOLETE - NOT USED ANYMORE. Is the HTML -tag for an alternative 'gfx/ol/line.gif'-icon (used in the top) + * @param string $_2 OBSOLETE - NOT USED ANYMORE. Is the HTML -tag for an alternative 'gfx/ol/line.gif'-icon (used in the top) * @param string $colType Defines the tag being used for the columns. Default is td. * @param int $level * @@ -1972,13 +2068,19 @@ public function renderListRow($table, $row, $cc, $titleCol, $thumbsCol, $indent */ public function addElement($h, $icon, $data, $rowParams = '', $_ = '', $_2 = '', $colType = 'td', $level = 0) { - $colType = ($colType === 'th') ? 'th' : 'td'; + if ($colType === 'pagination') { + $colType = 'td'; + $pagination = true; + } else { + $colType = ($colType === 'th') ? 'th' : 'td'; + } $noWrap = $this->no_noWrap ? '' : ' nowrap="nowrap"'; // Start up: $parent = isset($data['parent']) ? (int)$data['parent'] : 0; $out = ' - 0 ? ' data-grid-container="' . $data['tx_gridelements_container'] . '"' : '') . '>'; + 0 ? ' data-grid-container="' . $data['tx_gridelements_container'] . '"' : '') . '>'; if (count($data) > 1) { for ($i = 0; $i < $level; $i++) { $out .= '<' . $colType . '>'; @@ -2040,9 +2142,6 @@ public function addElement($h, $icon, $data, $rowParams = '', $_ = '', $_2 = '', // Traverse field array which contains the data to present: foreach ($fields as $vKey) { if (isset($data[$vKey])) { - if ($ccount == 1) { - $colsp = $colType === 'td' ? ' colspan="' . ($this->maxDepth - $level) . '"' : ' colspan="2"'; - } if ($lastKey) { $cssClass = $this->addElement_tdCssClass[$lastKey]; if ($this->oddColumnsCssClass && $ccount % 2 == 0) { @@ -2050,7 +2149,8 @@ public function addElement($h, $icon, $data, $rowParams = '', $_ = '', $_2 = '', array($this->addElement_tdCssClass[$lastKey], $this->oddColumnsCssClass)); } $out .= ' - <' . $colType . $noWrap . ' class="' . $cssClass . '"' . $colsp . $this->addElement_tdParams[$lastKey] . '>' . $data[$lastKey] . ''; + <' . $colType . $noWrap . ' class="' . $cssClass . '"' . $colsp + . $this->addElement_tdParams[$lastKey] . '>' . $data[$lastKey] . ''; } $lastKey = $vKey; $c = 1; @@ -2064,8 +2164,12 @@ public function addElement($h, $icon, $data, $rowParams = '', $_ = '', $_2 = '', if (count($data) == 1) { $c++; } - if ($c > 1) { - $colsp = ' colspan="' . ($c + $this->maxDepth) . '"'; + if ($pagination) { + $colsp = ' colspan="' . ($this->totalColumnCount - 1) . '"'; + } else if ($c > 1) { + $colsp = ' colspan="2"'; + } else if ($ccount === 1 && $colType === 'td') { + $colsp = ' colspan="' . ($this->maxDepth - $level - 1) . '"'; } else { $colsp = ''; } @@ -2076,7 +2180,8 @@ public function addElement($h, $icon, $data, $rowParams = '', $_ = '', $_2 = '', $cssClass = implode(' ', array($this->addElement_tdCssClass[$lastKey], $this->oddColumnsCssClass)); } $out .= ' - <' . $colType . $noWrap . ' class="' . $cssClass . '"' . $colsp . $this->addElement_tdParams[$lastKey] . '>' . $data[$lastKey] . ''; + <' . $colType . $noWrap . ' class="' . $cssClass . '"' . $colsp + . $this->addElement_tdParams[$lastKey] . '>' . $data[$lastKey] . ''; } // End row $out .= ' @@ -2100,10 +2205,13 @@ public function addElement($h, $icon, $data, $rowParams = '', $_ = '', $_2 = '', */ public function pasteUrl($table, $uid, $setRedirect = true, array $update = null) { - return ($table == '_FILE' ? BackendUtility::getModuleUrl('tce_file', - array()) : BackendUtility::getModuleUrl('tce_db', - array())) . ($setRedirect ? '&redirect=' . rawurlencode(GeneralUtility::linkThisScript(array('CB' => ''))) : '') . '&vC=' . $this->getBackendUserAuthentication()->veriCode() . '&prErr=1&uPT=1' . '&CB[paste]=' . rawurlencode($table . '|' . $uid) . '&CB[pad]=' . $this->clipObj->current . (is_array($update) ? GeneralUtility::implodeArrayForUrl('CB[update]', - $update) : '') . BackendUtility::getUrlToken('tceAction'); + $formProtection = FormProtectionFactory::get(); + return ($table === '_FILE' ? BackendUtility::getModuleUrl('tce_file', array()) : BackendUtility::getModuleUrl('tce_db', array())) + . ($setRedirect ? '&redirect=' . rawurlencode(GeneralUtility::linkThisScript(array('CB' => ''))) : '') + . '&vC=' . $this->getBackendUserAuthentication()->veriCode() . '&prErr=1&uPT=1' . '&CB[paste]=' + . rawurlencode($table . '|' . $uid) . '&CB[pad]=' . $this->clipObj->current + . (is_array($update) ? GeneralUtility::implodeArrayForUrl('CB[update]', $update) : '') + . '&formToken=' . $formProtection->generateToken('tceAction'); } /** @@ -2140,8 +2248,12 @@ public function selUrlDB($table, $uid, $copy = false, $deselect = false, $baseAr protected function createReferenceHtml($tableName, $uid) { $db = $this->getDatabaseConnection(); - $referenceCount = $db->exec_SELECTcountRows('*', 'sys_refindex', 'ref_table = ' . $db->fullQuoteStr($tableName, - 'sys_refindex') . ' AND ref_uid = ' . $uid . ' AND deleted = 0'); + $referenceCount = $db->exec_SELECTcountRows( + '*', + 'sys_refindex', + 'ref_table = ' . $db->fullQuoteStr($tableName, 'sys_refindex') + . ' AND ref_uid = ' . $uid . ' AND deleted = 0' + ); return $this->generateReferenceToolTip($referenceCount, GeneralUtility::quoteJSvalue($tableName) . ', ' . GeneralUtility::quoteJSvalue($uid)); } @@ -2156,26 +2268,35 @@ protected function createReferenceHtml($tableName, $uid) */ public function makeLocalizationPanel($table, $row) { - $out = array( + $out = [ 0 => '', 1 => '' - ); + ]; // Reset translations - $this->translations = array(); + $this->translations = []; // Language title and icon: $out[0] = $this->languageFlag($row[$GLOBALS['TCA'][$table]['ctrl']['languageField']]); - + // Guard clause so we can quickly return if a record is localized to "all languages" + // It should only be possible to localize a record off default (uid 0) + // Reasoning: The Parent is for ALL languages... why overlay with a localization? + if ((int)$row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] === -1) { + return $out; + } $translations = $this->translateTools->translationInfo($table, $row['uid'], 0, $row, $this->selFieldList); if (is_array($translations)) { $this->translations = $translations['translations']; // Traverse page translations and add icon for each language that does NOT yet exist: $lNew = ''; foreach ($this->pageOverlays as $lUid_OnPage => $lsysRec) { - if ($this->isEditable($table) && !isset($translations['translations'][$lUid_OnPage]) && $this->getBackendUserAuthentication()->checkLanguageAccess($lUid_OnPage)) { + if ($this->isEditable($table) && !isset($translations['translations'][$lUid_OnPage]) + && $this->getBackendUserAuthentication()->checkLanguageAccess($lUid_OnPage) + ) { $url = $this->listURL(); - $href = BackendUtility::getLinkToDataHandlerAction('&cmd[' . $table . '][' . $row['uid'] . '][localize]=' . $lUid_OnPage, - $url . '&justLocalized=' . rawurlencode($table . ':' . $row['uid'] . ':' . $lUid_OnPage)); + $href = BackendUtility::getLinkToDataHandlerAction( + '&cmd[' . $table . '][' . $row['uid'] . '][localize]=' . $lUid_OnPage, + $url . '&justLocalized=' . rawurlencode($table . ':' . $row['uid'] . ':' . $lUid_OnPage) + ); $language = BackendUtility::getRecord('sys_language', $lUid_OnPage, 'title'); if ($this->languageIconTitles[$lUid_OnPage]['flagIcon']) { $lC = $this->iconFactory->getIcon($this->languageIconTitles[$lUid_OnPage]['flagIcon'], @@ -2209,15 +2330,12 @@ public function fieldSelectBox($table, $formFields = true) { $lang = $this->getLanguageService(); // Init: - $formElements = array('', ''); + $formElements = ['', '']; if ($formFields) { - $formElements = array( - '
    ', - '' - ); + $formElements = ['
    ', '']; } // Load already selected fields, if any: - $setFields = is_array($this->setFields[$table]) ? $this->setFields[$table] : array(); + $setFields = is_array($this->setFields[$table]) ? $this->setFields[$table] : []; // Request fields from table: $fields = $this->makeFieldList($table, false, true); // Add pseudo "control" fields @@ -2227,7 +2345,7 @@ public function fieldSelectBox($table, $formFields = true) $fields[] = '_CONTROL_'; $fields[] = '_CLIPBOARD_'; // Create a checkbox for each field: - $checkboxes = array(); + $checkboxes = []; $checkAllChecked = true; foreach ($fields as $fieldName) { // Determine, if checkbox should be checked @@ -2238,9 +2356,15 @@ public function fieldSelectBox($table, $formFields = true) $checked = ''; } // Field label - $fieldLabel = is_array($GLOBALS['TCA'][$table]['columns'][$fieldName]) ? rtrim($lang->sL($GLOBALS['TCA'][$table]['columns'][$fieldName]['label']), - ':') : ''; - $checkboxes[] = '
    '; + $fieldLabel = is_array($GLOBALS['TCA'][$table]['columns'][$fieldName]) + ? rtrim($lang->sL($GLOBALS['TCA'][$table]['columns'][$fieldName]['label']), ':') + : ''; + $checkboxes[] = ''; } // Table with the field selector:: $content = $formElements[0] . ' @@ -2277,21 +2401,37 @@ public function fieldSelectBox($table, $formFields = true) * @param string $string The HTML content to link (image/text) * @param string $table Table name * @param string $cmd Clipboard command (eg. "setCB" or "delete") - * @param string $warning Warning text, if any ("delete" uses this for confirmation + * @param string $warning Warning text, if any ("delete" uses this for confirmation) * @param string $title title attribute for the anchor * @return string tag wrapped link. */ public function linkClipboardHeaderIcon($string, $table, $cmd, $warning = '', $title = '') { - $onClickEvent = 'document.dblistForm.cmd.value=' . GeneralUtility::quoteJSvalue($cmd) . ';document.dblistForm.cmd_table.value=' - . GeneralUtility::quoteJSvalue($table) . ';document.dblistForm.submit();'; + $jsCode = 'document.dblistForm.cmd.value=' . GeneralUtility::quoteJSvalue($cmd) + . ';document.dblistForm.cmd_table.value=' + . GeneralUtility::quoteJSvalue($table) + . ';document.dblistForm.submit();'; + + $attributes = []; + if ($title !== '') { + $attributes['title'] = $title; + } if ($warning) { - $onClickEvent = 'if (confirm(' . GeneralUtility::quoteJSvalue($warning) . ')){' . $onClickEvent . '}'; + $attributes['class'] = 'btn btn-default t3js-modal-trigger'; + $attributes['data-href'] = 'javascript:' . $jsCode; + $attributes['data-severity'] = 'warning'; + $attributes['data-title'] = $title; + $attributes['data-content'] = $warning; + } else { + $attributes['class'] = 'btn btn-default'; + $attributes['onclick'] = $jsCode . 'return false;'; } - if ($title !== '') { - $title = 'title="' . htmlspecialchars($title) . '" '; + + $attributesString = ''; + foreach ($attributes as $key => $value) { + $attributesString .= ' ' . $key . '="' . htmlspecialchars($value) . '"'; } - return '' . $string . ''; + return '' . $string . ''; } /** @@ -2301,7 +2441,7 @@ public function linkClipboardHeaderIcon($string, $table, $cmd, $warning = '', $t */ public function clipNumPane() { - return in_array('_CLIPBOARD_', $this->fieldArray) && $this->clipObj->current != 'normal'; + return in_array('_CLIPBOARD_', $this->fieldArray) && $this->clipObj->current !== 'normal'; } /** @@ -2318,18 +2458,19 @@ public function clipNumPane() public function addSortLink($code, $field, $table) { // Certain circumstances just return string right away (no links): - if ($field == '_CONTROL_' || $field == '_LOCALIZATION_' || $field == '_CLIPBOARD_' || $field == '_REF_' || $this->disableSingleTableView) { + if ($field === '_CONTROL_' || $field === '_LOCALIZATION_' || $field === '_CLIPBOARD_' || $field === '_REF_' || $this->disableSingleTableView) { return $code; } // If "_PATH_" (showing record path) is selected, force sorting by pid field (will at least group the records!) - if ($field == '_PATH_') { + if ($field === '_PATH_') { $field = 'pid'; } // Create the sort link: $sortUrl = $this->listURL('', '-1', 'sortField,sortRev,table,firstElementNumber') . '&table=' . $table - . '&sortField=' . $field . '&sortRev=' . ($this->sortRev || $this->sortField != $field ? 0 : 1); - $sortArrow = $this->sortField === $field ? $this->iconFactory->getIcon('status-status-sorting-' . ($this->sortRev ? 'desc' : 'asc'), - Icon::SIZE_SMALL)->render() : ''; + . '&sortField=' . $field . '&sortRev=' . ($this->sortRev || $this->sortField != $field ? 0 : 1); + $sortArrow = $this->sortField === $field + ? $this->iconFactory->getIcon('status-status-sorting-' . ($this->sortRev ? 'desc' : 'asc'), Icon::SIZE_SMALL)->render() + : ''; // Return linked field: return '' . $code . $sortArrow . ''; @@ -2368,8 +2509,8 @@ public function showNewRecLink($table) return true; } - return !in_array($table, $this->deniedNewTables) && (empty($this->allowedNewTables) || in_array($table, - $this->allowedNewTables)); + return !in_array($table, $this->deniedNewTables) + && (empty($this->allowedNewTables) || in_array($table, $this->allowedNewTables)); } /** @@ -2415,10 +2556,13 @@ protected function addHeaderRowToCSV() * * @return void */ - protected function addToCSV(array $row = array()) + protected function addToCSV(array $row = []) { $rowReducedByControlFields = self::removeControlFieldsFromFieldRow($row); - $rowReducedToSelectedColumns = array_intersect_key($rowReducedByControlFields, array_flip($this->fieldArray)); + // Get an field array without control fields but in the expected order + $fieldArray = array_intersect_key(array_flip($this->fieldArray), $rowReducedByControlFields); + // Overwrite fieldArray to keep the order with an array of needed fields + $rowReducedToSelectedColumns = array_replace($fieldArray, array_intersect_key($rowReducedByControlFields, $fieldArray)); $this->setCsvRow($rowReducedToSelectedColumns); } @@ -2429,17 +2573,17 @@ protected function addToCSV(array $row = array()) * * @return mixed[] Input array reduces by control fields */ - protected static function removeControlFieldsFromFieldRow(array $row = array()) + protected static function removeControlFieldsFromFieldRow(array $row = []) { // Possible control fields in a list row - $controlFields = array( + $controlFields = [ '_PATH_', '_REF_', '_CONTROL_', '_CLIPBOARD_', '_LOCALIZATION_', '_LOCALIZATION_b' - ); + ]; return array_diff_key($row, array_flip($controlFields)); } @@ -2489,15 +2633,15 @@ public function outputCSV($prefix) */ public function addActionToCellGroup(&$cells, $action, $actionKey) { - $cellsMap = array( - 'primary' => array( + $cellsMap = [ + 'primary' => [ 'view', 'edit', 'hide', 'delete', 'stat' - ), - 'secondary' => array( + ], + 'secondary' => [ 'viewBig', 'history', 'perms', @@ -2508,8 +2652,8 @@ public function addActionToCellGroup(&$cells, $action, $actionKey) 'moveLeft', 'moveRight', 'version' - ) - ); + ] + ]; $classification = in_array($actionKey, $cellsMap['primary']) ? 'primary' : 'secondary'; $cells[$classification][$actionKey] = $action; unset($cells[$actionKey]); @@ -2559,7 +2703,7 @@ public function isEditable($table) * * @return bool */ - protected function overlayEditLockPermissions($table, $row = array(), $editPermission = true) + protected function overlayEditLockPermissions($table, $row = [], $editPermission = true) { if ($editPermission && !$this->getBackendUserAuthentication()->isAdmin()) { // If no $row is submitted we only check for general edit lock of current page (except for table "pages") @@ -2577,42 +2721,7 @@ protected function overlayEditLockPermissions($table, $row = array(), $editPermi } /** - * Check whether or not the current backend user is an admin or the current page is - * locked by editlock. - * - * @return bool - */ - protected function editLockPermissions() - { - return $this->getBackendUserAuthentication()->isAdmin() || !$this->pageRow['editlock']; - } - - /** - * @return DatabaseConnection - */ - protected function getDatabaseConnection() - { - return $GLOBALS['TYPO3_DB']; - } - - /** - * @return BaseScriptClass - */ - protected function getModule() - { - return $GLOBALS['SOBE']; - } - - /** - * @return DocumentTemplate - */ - protected function getDocumentTemplate() - { - return $GLOBALS['TBE_TEMPLATE']; - } - - /** - * @return DocumentTemplate + * @return \int[] */ public function getExpandedGridelements() { @@ -2626,5 +2735,4 @@ protected function getBackendLayoutView() { return GeneralUtility::makeInstance(BackendLayoutView::class); } - } diff --git a/Configuration/TCA/Overrides/tt_content.php b/Configuration/TCA/Overrides/tt_content.php index 51d54d8..c7c7b6e 100644 --- a/Configuration/TCA/Overrides/tt_content.php +++ b/Configuration/TCA/Overrides/tt_content.php @@ -12,7 +12,7 @@ 'size' => 1, 'selicon_cols' => 9, 'maxitems' => 1, - 'default' => '', + 'default' => 0, 'showIconTable' => true ) ), @@ -66,6 +66,7 @@ 0 ), ), + 'default' => 0, 'foreign_table' => 'tt_content', 'foreign_table_where' => 'AND (tt_content.sys_language_uid = ###REC_FIELD_sys_language_uid### OR tt_content.sys_language_uid = -1) AND tt_content.pid=###CURRENT_PID### AND tt_content.CType=\'gridelements_pi1\' AND (tt_content.uid != ###THIS_UID###) AND (tt_content.tx_gridelements_container != ###THIS_UID### OR tt_content.tx_gridelements_container=0) ORDER BY tt_content.header, tt_content.uid', 'dontRemapTablesOnCopy' => 'tt_content', @@ -84,6 +85,7 @@ 'itemsProcFunc' => 'GridElementsTeam\Gridelements\Backend\TtContent->columnsItemsProcFunc', 'size' => 1, 'maxitems' => 1, + 'default' => 0, ) ), ); @@ -102,21 +104,23 @@ $GLOBALS['TCA']['tt_content']['columns']['pi_flexform']['config']['ds']['*,gridelements_pi1'] = ''; $GLOBALS['TCA']['tt_content']['columns']['records']['config']['allowed'] .= ',pages'; +$frames = isset($GLOBALS['TCA']['tt_content']['palettes']['frames']) + ? '--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.frames;frames' + : 'layout;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:layout_formlabel'; + $GLOBALS['TCA']['tt_content']['types']['gridelements_pi1']['showitem'] = ' - --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.general;general, - --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.header;header, + --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.general;general, + --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.header;header, tx_gridelements_backend_layout, pi_flexform, tx_gridelements_children, - --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.appearance, - --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.frames;frames, + --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.appearance, + ' . $frames . ', + --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.appearanceLinks;appearanceLinks, media, - --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.access, - --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.visibility;visibility, - --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.access;access, + --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.access, + hidden;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:field.default.hidden, + --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.access;access, --div--;LLL:EXT:lang/locallang_tca.xlf:sys_category.tabs.category, categories '; -\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes('tt_content', 'recursive', 'shortcut', - 'after:records'); -\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes('tt_content', '--div--;LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xlf:gridElements, tx_gridelements_container, tx_gridelements_columns'); diff --git a/Configuration/TCA/tx_gridelements_backend_layout.php b/Configuration/TCA/tx_gridelements_backend_layout.php index 58b4d0f..b3a9186 100644 --- a/Configuration/TCA/tx_gridelements_backend_layout.php +++ b/Configuration/TCA/tx_gridelements_backend_layout.php @@ -42,7 +42,7 @@ 'type' => 'check', 'items' => array( '1' => array( - '0' => 'LLL:EXT:cms/locallang_ttc.xml:hidden.I.0', + '0' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:hidden.I.0', ), ), ), @@ -93,7 +93,7 @@ 'config' => array( 'type' => 'group', 'internal_type' => 'file', - 'allowed' => 'jpg,gif,png', + 'allowed' => 'jpg,gif,png,svg', 'uploadfolder' => 'uploads/tx_gridelements', 'show_thumbs' => 1, 'size' => 5, @@ -155,7 +155,7 @@ 'wizards' => array( '_PADDING' => 4, '0' => array( - 'title' => 'LLL:EXT:cms/locallang_tca.xml:backend_layout.wizard', + 'title' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:backend_layout.wizard', 'type' => 'popup', 'icon' => 'EXT:frontend/Resources/Public/Images/wizard_backend_layout.png', 'module' => array( @@ -212,9 +212,9 @@ --palette--;' . $l10n . ':tx_gridelements_backend_layout.palette.appearance;appearance, --div--;' . $l10n . ':tx_gridelements_backend_layout.div.configuration, top_level_layout, alias, config, --palette--;' . $l10n . ':tx_gridelements_backend_layout.ce_configuration;flexform, - --div--;LLL:EXT:cms/locallang_ttc.xml:tabs.access,--palette--;LLL:EXT:cms/locallang_ttc.xml:palette.visibility;visibility' + --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.access,--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.visibility;visibility' ), ), -); \ No newline at end of file +); diff --git a/Configuration/TypoScript/setup.ts b/Configuration/TypoScript/setup.ts index 66f64d3..26211f6 100644 --- a/Configuration/TypoScript/setup.ts +++ b/Configuration/TypoScript/setup.ts @@ -1,4 +1,5 @@ -lib.gridelements.defaultGridSetup { // stdWrap functions being applied to each element +// stdWrap functions being applied to each element +lib.gridelements.defaultGridSetup { columns { default { renderObj = COA @@ -24,52 +25,70 @@ lib.gridelements.defaultGridSetup { // stdWrap functions being applied to each e # or tx_gridelements_view_child_123 (123 is the UID of the child) } +tt_content.gridelements_pi1 = COA +tt_content.gridelements_pi1 { + #10 =< lib.stdheader + 20 = COA + 20 { + 10 = USER + 10 { + userFunc = GridElementsTeam\Gridelements\Plugin\Gridelements->main + setup { + default < lib.gridelements.defaultGridSetup + } + } + } +} + +tt_content.gridelements_view < tt_content.gridelements_pi1 + lib.tt_content.shortcut.pages = COA lib.tt_content.shortcut.pages { 10 = USER 10 { userFunc = GridElementsTeam\Gridelements\Plugin\Gridelements->user_getTreeList - } + } 20 = CONTENT 20 { table = tt_content select { pidInList.data = register:pidInList + selectFields.dataWrap = *,FIND_IN_SET(pid,{register:pidInList}) AS gridelements_shortcut_page_order_by where = colPos >= 0 languageField = sys_language_uid - orderBy = colPos,sorting - orderBy.dataWrap = FIND_IN_SET(pid,'{register:pidInList}'),| + orderBy = gridelements_shortcut_page_order_by,colPos,sorting } } } -tt_content.shortcut { - 5 = LOAD_REGISTER - 5 { - tt_content_shortcut_recursive.field = recursive - } - 20 { - tables := addToList(pages) - conf.pages < lib.tt_content.shortcut.pages +[userFunc = TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('fluid_styled_content')] + lib.shortcuts = COA + lib.shortcuts { + 5 = LOAD_REGISTER + 5 { + tt_content_shortcut_recursive.field = recursive + } + 20 < tt_content.shortcut.variables.shortcuts + 20 { + tables := addToList(pages) + conf.pages < lib.tt_content.shortcut.pages + } + 30 = RESTORE_REGISTER } - 30 = RESTORE_REGISTER -} + tt_content.shortcut.variables.shortcuts > + tt_content.shortcut.variables.shortcuts < lib.shortcuts +[global] -plugin.tx_gridelements_pi1 > -tt_content.gridelements_pi1 > -tt_content.gridelements_pi1 = COA -tt_content.gridelements_pi1 { - #10 =< lib.stdheader - 20 = COA - 20 { - 10 = USER - 10 { - userFunc = GridElementsTeam\Gridelements\Plugin\Gridelements->main - setup { - default < lib.gridelements.defaultGridSetup - } +[userFunc = TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('css_styled_content')] + tt_content.shortcut { + 5 = LOAD_REGISTER + 5 { + tt_content_shortcut_recursive.field = recursive } + 20 { + tables := addToList(pages) + conf.pages < lib.tt_content.shortcut.pages + } + 30 = RESTORE_REGISTER } -} - -tt_content.gridelements_view < tt_content.gridelements_pi1 +[global] diff --git a/Documentation/Chapters/Faq/Index.rst b/Documentation/Chapters/Faq/Index.rst index cae37a4..009610d 100644 --- a/Documentation/Chapters/Faq/Index.rst +++ b/Documentation/Chapters/Faq/Index.rst @@ -1,5 +1,4 @@ - .. ================================================== .. FOR YOUR INFORMATION .. -------------------------------------------------- @@ -57,7 +56,7 @@ individual input fields then?** **Answer:** It's very easy to provide a new CType for the tt\_content table with the TYPO3 API since this table already offers you lots of different fields to make use of. Just create the TCA structure and add -a new content type via an extension or maybe via extTables.php, +a new content type via an extension, provide some TypoScript for the frontend output and – voila – here you go with a new content element. diff --git a/Documentation/Chapters/GridTsSyntax/Index.rst b/Documentation/Chapters/GridTsSyntax/Index.rst index bda9526..bf3d4e7 100644 --- a/Documentation/Chapters/GridTsSyntax/Index.rst +++ b/Documentation/Chapters/GridTsSyntax/Index.rst @@ -99,7 +99,7 @@ The values for **colspan** , **rowspan**, **allowed** and The **allowed** feature is used to determine those content element types the user will be allowed to use within this column. You -can use a comma separated list of Ctype values here and as soon as +can use a comma separated list of CType values here and as soon as this contains at least one value, any other element type will be forbidden. diff --git a/Documentation/Chapters/Installation/Index.rst b/Documentation/Chapters/Installation/Index.rst index 38c58b8..cb26481 100644 --- a/Documentation/Chapters/Installation/Index.rst +++ b/Documentation/Chapters/Installation/Index.rst @@ -42,7 +42,7 @@ When the Extension Manager is asking you for permission to add and/or modify some of the database tables, you should give your OK, so the necessary fields will be available. -.. figure:: ../../Images/Installation/UpdateDatabase.png +.. figure:: ../../../Images/Installation/UpdateDatabase.png :alt: Update database :width: 800 .. :align: center diff --git a/Documentation/Chapters/Introduction/Index.rst b/Documentation/Chapters/Introduction/Index.rst index 1593644..91faa61 100644 --- a/Documentation/Chapters/Introduction/Index.rst +++ b/Documentation/Chapters/Introduction/Index.rst @@ -1,5 +1,4 @@ - .. ================================================== .. FOR YOUR INFORMATION .. -------------------------------------------------- @@ -25,11 +24,10 @@ Since version 4.5 the TYPO3 core offers the so called **grid view**, a feature developed during the user experience week, that gives backend users some nice options to get a more **user friendly backend layout**. You can create your own table based backend layout records, -fill in as many columns as you like with either a wizard or a -*TSconfig* like code and arrange these columns to match your desired +fill in as many columns as you like with either a wizard or a *TSconfig* like code and arrange these columns to match your desired layout, so backend users will easily recognize where to put their content. Each record can get an icon that will be used as with the -layout selector box. +layout selector box. Code can be stored and versioned in files as well. Grid Elements are pushing these features to the next level, namely content elements. @@ -98,7 +96,7 @@ A short roundup of the features and advantages - Referenced content visible in the preview section of the reference element -- Completely TypoScript based frontend output +- Completely TypoScript or Fluid based frontend output - Flexform field values automatically added to the data set diff --git a/Documentation/Chapters/Sponsoring/Index.rst b/Documentation/Chapters/Sponsoring/Index.rst new file mode 100644 index 0000000..d2965f5 --- /dev/null +++ b/Documentation/Chapters/Sponsoring/Index.rst @@ -0,0 +1,85 @@ +.. ================================================== +.. FOR YOUR INFORMATION +.. -------------------------------------------------- +.. -*- coding: utf-8 -*- with BOM. + +.. ================================================== +.. DEFINE SOME TEXTROLES +.. -------------------------------------------------- +.. role:: underline +.. role:: typoscript(code) +.. role:: ts(typoscript) + :class: typoscript +.. role:: php(code) +Sponsoring +^^^^^^^^^^ +Inspiring people to share +------------------------- +We strongly believe in the principles of Open-source software, which is why we share this TYPO3 extension with you completely free of charge. + +Still even contributors to Open-source projects have to make a living somehow, so even though you are not obliged to do so, you should consider sharing a small part of the money you might be earning with this extension in return. This way we can make sure to still provide the TYPO3 community with better extensions and services in the future. + +Thanks in advance for your support. + +How to support our efforts? +--------------------------- + +.. |logo0| image:: ../../Images/Sponsoring/CodersCareLogo.png + :target: https://coders.care + :width: 300px + :align: middle +.. |logo1| image:: ../../Images/Sponsoring/PatreonLogo.png + :target: https://www.patreon.com/cybercraft + :width: 200px + :align: middle +.. |logo2| image:: ../../Images/Sponsoring/FlattrLogo.png + :target: https://www.flattr.com/@Cybercraft + :width: 200px + :align: middle +.. |logo3| image:: ../../Images/Sponsoring/PaypalLogo.png + :target: https://www.paypal.me/cybercraftsponsoring/50 + :width: 200px + :align: middle +.. |logo4| image:: ../../Images/Sponsoring/AmazonLogo.png + :target: https://www.amazon.de/gp/registry/wishlist/2I80GX9ZSMYXX + :width: 200px + :align: middle +.. |text0| replace:: Get yourself one of the Service Level Agreements we offer together with our fellow coders. This way you make sure Gridelements and other extensions live long and prosper and you will get a hotline with a defined response time in case of emergency. +.. |text1| replace:: A Service which allows you to become one of our Patrons on a monthly basis. You might even get a shoutout on twitter, get mentioned personally in the next release or even make a feature request depending on the amount you pick. +.. |text2| replace:: Pay any amount monthly on this service and it gets spread even around the people you want to support! We would be Flattr'ed to have you. +.. |text3| replace:: You don't want to sponsor monthly? Dont worry you can also support us via Paypal with any desired amount you find reasonable. +.. |text4| replace:: Sometimes you want to give it a personal touch. When you want to thank Joey and Petra with a nice Single Malt you should take a look here. Slàinte mhath! ++-------+-------------------+ ++-------+-------------------+ +||logo0|||text0| | ++-------+-------------------+ ++-------+-------------------+ +||logo1|||text1| | ++-------+-------------------+ ++-------+-------------------+ +||logo2|||text2| | ++-------+-------------------+ ++-------+-------------------+ +||logo3|||text3| | ++-------+-------------------+ ++-------+-------------------+ +||logo4|||text4| | ++-------+-------------------+ ++-------+-------------------+ +The Agreement +------------- +Excerpt from the coders.care blog post `Service Level Agreements for TYPO3 Extensions `_ + +.. image:: ../../Images/Sponsoring/Why.jpg + :width: 480px +Enabling companies, developers and the community to join forces and thrive +========================================================================== +There is one particular thing, that should be different to most of the variants of service level agreements provided by other open-source projects though. Having to buy a so called "enterprise" or "professional" edition of the extensions or TYPO3 itself just to become entitled for an SLA is a No-Go, since it will create two classes in the community and contradict the principles of free software implied by the GPL. + +The benefit for the people agreeing to a certain service level should be defined by reliability and responsiveness, not by getting access to something, that is unavailable for the rest of the community. So there must be an agreement to still share the improved public extensions with everybody in the community while getting a personal early or immediate access depending on the level and the priority you paid for. + +For developers there is the need for another agreement: They have to accept and publish fixes and changes to their extensions up to a certain degree, so the whole pool of developers can take care of the extensions covered by the SLAs. This will avoid forks. + +There are several nice side effects of these agreements. For example it would reduce the number of extensions which are maintained by a single person and therefor the risk of loss when using these extensions. Due to the four-eyes principle this would increase the quality of each extension in the approved pool and at the same time reduce the amount of "me too" extensions in the TER. + +There would be a powerful team of developers backing the service levels, so it would be easy to keep the approved extensions on a level with upcoming versions of the TYPO3 core. And since this would be done in close collaboration with the TYPO3 core team and the security team, core bugs and security holes affecting extension behaviour could be fixed and published much more easily as well. \ No newline at end of file diff --git a/Documentation/Chapters/Tsconfig/Index.rst b/Documentation/Chapters/Tsconfig/Index.rst index e02d6aa..60ed4c2 100644 --- a/Documentation/Chapters/Tsconfig/Index.rst +++ b/Documentation/Chapters/Tsconfig/Index.rst @@ -33,10 +33,21 @@ Grid Elements completely without grid records: .. ### BEGIN~OF~TABLE ### +.. _tsconfig: + +tx\_gridelements +^^^^^^^^ + + +.. _tsconfig-tx-gridelements-setup: + +tx\_gridelements.setup +"""""""""""""""" + .. container:: table-row Property - tx\_gridelements.setup + setup Data type Grid TS structure @@ -47,6 +58,10 @@ Grid Elements completely without grid records: Default N/A +.. _tsconfig-tx-gridelements-setup-123: + +tx\_gridelements.setup.123 +"""""""""""""""" .. container:: table-row @@ -64,6 +79,10 @@ Grid Elements completely without grid records: Default N/A +.. _tsconfig-tx-gridelements-overrulerecords: + +tx\_gridelements.overruleRecords +"""""""""""""""" .. container:: table-row @@ -80,6 +99,10 @@ Grid Elements completely without grid records: Default 0 +.. _tsconfig-tx-gridelements-excludelayoutids: + +tx\_gridelements.excludeLayoutIds +"""""""""""""""" .. container:: table-row @@ -96,12 +119,15 @@ Grid Elements completely without grid records: Default N/A +.. _tsconfig-TCEFORM-tt-content-tx-gridelements-backend-layout-PAGE-TSCONFIG-ID: + +TCEFORM.tt\_content.tx\_gridelements\_backend\_layout.PAGE\_TSCONFIG\_ID +"""""""""""""""" .. container:: table-row Property - TCEFORM.tt\_content.tx\_gridelements\_backend\_layout.PAGE\_TSCONFIG\_ - ID + TCEFORM.tt\_content.tx\_gridelements\_backend\_layout.PAGE\_TSCONFIG\_ID Data type Integer diff --git a/Documentation/Chapters/Typoscript/Index.rst b/Documentation/Chapters/Typoscript/Index.rst index cf40c65..69c3844 100644 --- a/Documentation/Chapters/Typoscript/Index.rst +++ b/Documentation/Chapters/Typoscript/Index.rst @@ -1,5 +1,3 @@ - - .. ================================================== .. FOR YOUR INFORMATION .. -------------------------------------------------- @@ -114,6 +112,9 @@ As described in the commented part, you will find some additional virtual fields in your data, that will contain stuff that has been used during the rendering process. These come in handy, when you want to use a TEMPLATE or FLUIDTEMPLATE element to produce your output. +Just use the the debug viewhelper in your template to get an overview of the available fields. +:: + {_all} Any of the internal keys and the default settings will of course be passed to the stdWrap method, so you can assign almost anything to any diff --git a/Documentation/Chapters/Typoscript/Reference/Index.rst b/Documentation/Chapters/Typoscript/Reference/Index.rst index 143ee6f..de1f672 100644 --- a/Documentation/Chapters/Typoscript/Reference/Index.rst +++ b/Documentation/Chapters/Typoscript/Reference/Index.rst @@ -1,5 +1,3 @@ - - .. ================================================== .. FOR YOUR INFORMATION .. -------------------------------------------------- @@ -20,20 +18,17 @@ Reference .. ### BEGIN~OF~TABLE ### -.. container:: table-row - Property - Property: +.. _typoscript: - Data type - Data type: +TypoScript +^^^^^^^^ - Description - Description: - Default - Default: +.. _typoscript-setup: +setup +"""""""""""""""" .. container:: table-row @@ -51,6 +46,11 @@ Reference N/A +.. _typoscript-setup-default: + +setup.default +"""""""""""""""" + .. container:: table-row Property @@ -72,6 +72,11 @@ Reference N/A +.. _typoscript-setup-123: + +setup.123 +"""""""""""""""" + .. container:: table-row Property @@ -88,6 +93,11 @@ Reference N/A +.. _typoscript-columns: + +columns +"""""""""""""""" + .. container:: table-row Property @@ -105,6 +115,11 @@ Reference N/A +.. _typoscript-columns-default: + +columns.default +"""""""""""""""" + .. container:: table-row Property @@ -121,6 +136,11 @@ Reference N/A +.. _typoscript-columns-123: + +columns.123 +"""""""""""""""" + .. container:: table-row Property @@ -136,6 +156,11 @@ Reference N/A +.. _typoscript-renderObj: + +renderObj +"""""""""""""""" + .. container:: table-row Property @@ -151,6 +176,11 @@ Reference COA +.. _typoscript-flexform-fieldname: + +flexform\_fieldname +"""""""""""""""" + .. container:: table-row Property @@ -167,6 +197,11 @@ Reference N/A +.. _typoscript-parentgrid-fieldname: + +parentgrid\_fieldname +"""""""""""""""" + .. container:: table-row Property @@ -182,6 +217,11 @@ Reference N/A +.. _typoscript-tx-gridelements-view-children: + +tx\_gridelements\_view\_children +"""""""""""""""" + .. container:: table-row Property @@ -196,6 +236,10 @@ Reference Default N/A +.. _typoscript-tx-gridelements-view-columns: + +tx\_gridelements\_view\_columns +"""""""""""""""" .. container:: table-row @@ -212,6 +256,11 @@ Reference N/A +.. _typoscript-tx-gridelements-view-column-123: + +tx\_gridelements\_view\_column\_123 +"""""""""""""""" + .. container:: table-row Property @@ -227,6 +276,11 @@ Reference N/A +.. _typoscript-tx-gridelements-view-child-123: + +tx\_gridelements\_view\_child\_123 +"""""""""""""""" + .. container:: table-row Property diff --git a/Documentation/Images/Sponsoring/AmazonLogo.png b/Documentation/Images/Sponsoring/AmazonLogo.png new file mode 100644 index 0000000..a76c7da Binary files /dev/null and b/Documentation/Images/Sponsoring/AmazonLogo.png differ diff --git a/Documentation/Images/Sponsoring/CodersCareLogo.png b/Documentation/Images/Sponsoring/CodersCareLogo.png new file mode 100644 index 0000000..29dc775 Binary files /dev/null and b/Documentation/Images/Sponsoring/CodersCareLogo.png differ diff --git a/Documentation/Images/Sponsoring/FlattrLogo.png b/Documentation/Images/Sponsoring/FlattrLogo.png new file mode 100644 index 0000000..fd2b4a0 Binary files /dev/null and b/Documentation/Images/Sponsoring/FlattrLogo.png differ diff --git a/Documentation/Images/Sponsoring/PatreonLogo.png b/Documentation/Images/Sponsoring/PatreonLogo.png new file mode 100644 index 0000000..0c9b637 Binary files /dev/null and b/Documentation/Images/Sponsoring/PatreonLogo.png differ diff --git a/Documentation/Images/Sponsoring/PaypalLogo.png b/Documentation/Images/Sponsoring/PaypalLogo.png new file mode 100644 index 0000000..79ce33e Binary files /dev/null and b/Documentation/Images/Sponsoring/PaypalLogo.png differ diff --git a/Documentation/Images/Sponsoring/Why.jpg b/Documentation/Images/Sponsoring/Why.jpg new file mode 100644 index 0000000..bee5171 Binary files /dev/null and b/Documentation/Images/Sponsoring/Why.jpg differ diff --git a/Documentation/Index.rst b/Documentation/Index.rst index cb85579..04eca61 100644 --- a/Documentation/Index.rst +++ b/Documentation/Index.rst @@ -9,7 +9,7 @@ .. role:: underline .. role:: typoscript(code) .. role:: ts(typoscript) - :class: typoscript + :class: typoscript .. role:: php(code) @@ -18,59 +18,53 @@ Grid Elements ============= :Extension key: - gridelements + gridelements :Version: - 4.0.0 + 7.2.0 :Language: - en + en :Description: - This extension integrates the grid layout concept to regular content - elements. + This extension integrates the backend layout concept of pages to regular content + elements. :Keywords: - grid elements, backend, layout + grid elements, backend, layout :Copyright: - Jo Hasenau, Cybercraft Media Manufactory + Jo Hasenau, Cybercraft Media Manufactory :Author: - The Grid Elements Team + The Grid Elements Team :License: - GNU General Public License, either version 2 of the License or any - later version. + GNU General Public License, either version 2 of the License or any + later version. :Rendered: - |today| + |today| | -This project aims to integrate the grid layout concept also to regular -content elements - the grid elements. This approach is an alternative -to TemplaVoila storing relations normalized in the database without -using XML and offers a lot of comfortable features for an improved -experience of the backend user. It's development has been financed by -T-Systems, Cybercraft and via a crowd funding project @ -http://www.startnext.de/en/typo3-grid-elements-2-0 with sponsoring of -99 Supporters +This project aims to integrate the backend layout concept of pages also to regular content elements - the grid elements. This approach is an alternative to TemplaVoila storing relations normalized in the database without using XML and offers a lot of comfortable features for an improved experience of the backend user. It's development has been financed by T-Systems, Cybercraft and via a crowd funding project @ +http://www.startnext.de/en/typo3-grid-elements-2-0 with sponsoring of 99 Supporters. Table Of Content ^^^^^^^^^^^^^^^^ .. toctree:: - :maxdepth: 5 - :titlesonly: - :glob: - - Chapters/Introduction/Index - Chapters/Installation/Index - Chapters/GridTsSyntax/Index - Chapters/GridWizard/Index - Chapters/Flexform/Index - Chapters/Tsconfig/Index - Chapters/Typoscript/Index - Chapters/Faq/Index - Chapters/Notes/Index + :titlesonly: + :glob: + + Chapters/Introduction/Index + Chapters/Installation/Index + Chapters/GridTsSyntax/Index + Chapters/GridWizard/Index + Chapters/Flexform/Index + Chapters/Tsconfig/Index + Chapters/Typoscript/Index + Chapters/Faq/Index + Chapters/Sponsoring/Index + Chapters/Notes/Index diff --git a/README.md b/README.md index bd78c67..549424e 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,5 @@ -gridelements2 +Gridelements ============= -Gridelements2 Code-Sprint Repo - - -The branch 7-4-0-compatibility has some fixes for TYPO3 7.4: - -- breaks clipboard in page module -- new element wizard doesn't show grid elements -- new element drag+drop wizard doesn't show description on icon hover - -Might work with 7.x \ No newline at end of file +Branch for 7.x.x versions of Gridelements. +Compatible to TYPO3 CMS 7 LTS only. \ No newline at end of file diff --git a/README.txt b/README.txt deleted file mode 100644 index a90c69b..0000000 --- a/README.txt +++ /dev/null @@ -1,2 +0,0 @@ -Commit Test -Feel free to add some documentation or simply add a link to the online manual. diff --git a/Resources/Private/Language/locallang.xlf b/Resources/Private/Language/locallang.xlf index f930e78..8deccd6 100644 --- a/Resources/Private/Language/locallang.xlf +++ b/Resources/Private/Language/locallang.xlf @@ -9,6 +9,9 @@ Enable nesting in list module + + Use language overlay for content and page records referenced in shortcut elements. + \ No newline at end of file diff --git a/Resources/Public/Backend/Css/Skin/t3skin_override.css b/Resources/Public/Backend/Css/Skin/t3skin_override.css index a1c48d4..fd6edc8 100644 --- a/Resources/Public/Backend/Css/Skin/t3skin_override.css +++ b/Resources/Public/Backend/Css/Skin/t3skin_override.css @@ -24,6 +24,8 @@ .t3-page-columns { border-spacing: 10px !important; + width: auto; + min-width: 100%; } .t3-page-ce:hover .t3-page-ce-header { @@ -80,10 +82,11 @@ } .t3-grid-container { - margin: 0px -10px; + margin: 0 -10px; } -.t3js-module-body .t3-grid-container-title-0 { +.t3js-module-body .t3-grid-container-title-0, +.t3js-module-body .t3-grid-container-title--1 { font-size: 12px; font-weight: normal; color: #999999; @@ -95,7 +98,7 @@ border-style: solid; border-width: 1px; border-color: #B48062; - margin: 5px -11px -11px -11px; + margin: 2px 0 0 0; } .t3js-module-body .t3-grid-container-title-1 { @@ -209,7 +212,7 @@ } #new-element-drag-in-wizard.dragged .tab-content:hover { - min-height: 0px !important; + min-height: 0 !important; } #new-element-drag-in-wizard .media { @@ -241,7 +244,7 @@ } #new-element-drag-in-wizard.dragged .panel-tab:hover { - min-height: 0px !important; + min-height: 0 !important; } .t3js-module-body .exampleContent > .reference { @@ -257,8 +260,8 @@ .t3js-module-body .exampleContent > .reference .reference-overlay { position: absolute; - top: 0px; - left: 0px; + top: 0; + left: 0; width: 100%; height: 100%; background: #427BAB; @@ -317,6 +320,10 @@ #recordlist-tt_content .col-icon { position: relative; + text-align: right; +} + +#recordlist-tt_content th.col-icon { text-align: left; } @@ -385,3 +392,44 @@ display: block; } +.t3-grid-cell-horizontal > .t3js-sortable { + display: table; + vertical-align: top; + width: 100%; +} + +.t3-grid-cell-horizontal > .t3js-sortable > .t3js-page-ce { + display: table-row; +} + +.t3-grid-cell-horizontal > .t3js-sortable > .t3js-page-ce > .ui-droppable { + margin: 10px; +} + +.t3-grid-cell-horizontal > .t3js-sortable > .t3js-page-ce > .t3js-page-new-ce { + display: table-cell; + padding: 10px; +} + +.t3-grid-cell-horizontal > .t3js-sortable > .t3js-page-ce-sortable > .t3js-page-new-ce { + display: block; + padding: 0!important; +} + +.t3-grid-cell-horizontal > .t3js-sortable > .t3js-page-ce-sortable { + display: table-cell; + padding: 0px 10px 0px; + vertical-align: top; +} + +.t3-grid-cell-horizontal > .t3js-sortable > .t3js-page-ce > .t3-page-ce-dropzone-possible { + margin: -28px 0 -27px 0!important; +} + +.t3-grid-cell-horizontal > .t3js-sortable > .t3js-page-ce-sortable > .t3-page-ce-dropzone-available { + margin: 10px 0!important; +} + +.t3-grid-cell-horizontal > .t3js-sortable > .t3js-page-ce-sortable > .t3-page-ce-dropzone-possible { + margin: -38px 0 -37px 0!important; +} \ No newline at end of file diff --git a/Resources/Public/JavaScript/GridElementsDragDrop.js b/Resources/Public/JavaScript/GridElementsDragDrop.js index 2df2b9b..83913b1 100644 --- a/Resources/Public/JavaScript/GridElementsDragDrop.js +++ b/Resources/Public/JavaScript/GridElementsDragDrop.js @@ -20,6 +20,7 @@ define(['jquery', 'jquery-ui/sortable', 'jquery-ui/droppable'], function ($) { var DragDrop = { contentIdentifier: '.t3js-page-ce', + draggableIdentifier: '.t3js-page-ce:has(.t3-page-ce-header-draggable)', dragIdentifier: '.t3-page-ce-dragitem', dragHeaderIdentifier: '.t3js-page-ce-draghandle', dropZoneIdentifier: '.t3js-page-ce-dropzone-available', @@ -37,7 +38,7 @@ define(['jquery', 'jquery-ui/sortable', 'jquery-ui/droppable'], function ($) { * initializes Drag+Drop for all content elements on the page */ DragDrop.initialize = function () { - $(DragDrop.contentIdentifier).draggable({ + $(DragDrop.draggableIdentifier).draggable({ handle: this.dragHeaderIdentifier, scope: 'tt_content', cursor: 'move', @@ -88,14 +89,15 @@ define(['jquery', 'jquery-ui/sortable', 'jquery-ui/droppable'], function ($) { // make the drop zones visible (all except the previous one in the current list) var $previousDropZone = $element.prev().children(DragDrop.dropZoneIdentifier); - var allowedElementMimeType = $element.find('.t3-ctype-identifier').data('ctype'); - var allowedGridType = $element.find('.t3-ctype-identifier').data('gridtype'); + var currentMimeType = $element.find('.t3-ctype-identifier').data('ctype'); + var currentGridType = $element.find('.t3-ctype-identifier').data('gridtype'); $(DragDrop.dropZoneIdentifier).not($previousDropZone).each(function () { var $closestColumn = $(this).closest(DragDrop.columnIdentifier); - if (($closestColumn.hasClass('t3-allow-all') || - !allowedGridType && $closestColumn.hasClass('t3-allow-' + allowedElementMimeType) || - $closestColumn.hasClass('t3-allow-gridelements_pi1') && $closestColumn.hasClass('t3-allow-gridtype-' + allowedGridType) || - allowedElementMimeType === 'gridelements_pi1' && $closestColumn.hasClass('t3-allow-gridelements_pi1') && !$closestColumn.hasClass('t3-allow-gridtype')) && + if (($closestColumn.hasClass('t3-allow-all') && (!currentGridType || !$closestColumn.hasClass('t3-allow-gridtype')) || + !currentGridType && $closestColumn.hasClass('t3-allow-' + currentMimeType) || + $closestColumn.hasClass('t3-allow-gridelements_pi1') && $closestColumn.hasClass('t3-allow-gridtype-' + currentGridType) || + currentMimeType === 'gridelements_pi1' && $closestColumn.hasClass('t3-allow-gridtype') && $closestColumn.hasClass('t3-allow-gridtype-' + currentGridType) || + currentMimeType === 'gridelements_pi1' && !$closestColumn.hasClass('t3-allow-gridtype') && $closestColumn.hasClass('t3-allow-gridelements_pi1')) && $(this).parent().find('.icon-actions-document-new').length ) { $(this).addClass(DragDrop.validDropZoneClass); @@ -261,6 +263,10 @@ define(['jquery', 'jquery-ui/sortable', 'jquery-ui/droppable'], function ($) { if (language > -1) { parameters['cmd']['tt_content'][contentElementUid]['copy']['update']['sys_language_uid'] = language; } + if (evt === 'copyFromAnotherPage') { + parameters['CB'] = {setCopyMode: 1}; + alert(parameters); + } // fire the request, and show a message if it has failed require(['TYPO3/CMS/Backend/AjaxDataHandler'], function (DataHandler) { DataHandler.process(parameters).done(function (result) { @@ -302,12 +308,8 @@ define(['jquery', 'jquery-ui/sortable', 'jquery-ui/droppable'], function ($) { $draggableElement.detach().css({top: 0, left: 0}) .insertAfter($droppableElement.closest(DragDrop.contentIdentifier)); } - if ($('.t3js-page-lang-column').length) { - self.location.reload(true); - } - } else { - self.location.reload(true); } + self.location.reload(true); } }); }); diff --git a/Resources/Public/JavaScript/GridElementsDragInWizard.js b/Resources/Public/JavaScript/GridElementsDragInWizard.js index 8e71b28..a80bff6 100644 --- a/Resources/Public/JavaScript/GridElementsDragInWizard.js +++ b/Resources/Public/JavaScript/GridElementsDragInWizard.js @@ -47,7 +47,7 @@ define(['jquery', 'TYPO3/CMS/Gridelements/GridElementsDragDrop', 'jquery-ui/sort originalWizardUrl = $newCeLink.attr('href').split('\&', 4); } if (typeof originalWizardUrl !== 'undefined') { - DragInWizard.wizardUrl = '\/typo3\/index.php?route=%2Frecord%2Fcontent%2Fnew&' + originalWizardUrl[1] + '&' + originalWizardUrl[2]; + DragInWizard.wizardUrl = originalWizardUrl[0] + '&' + originalWizardUrl[1] + '&' + originalWizardUrl[2]; } }; @@ -95,7 +95,7 @@ define(['jquery', 'TYPO3/CMS/Gridelements/GridElementsDragDrop', 'jquery-ui/sort * make wizard items sortable so they can be dragged into content columns */ DragInWizard.makeItemsSortable = function () { - $('#' + DragInWizard.wizardIdentifier + ' .panel-body .media').attr('language-uid', 0).find('.media-left img').addClass('t3js-page-ce-draghandle').parent().addClass('t3-page-ce-dragitem').closest('.media').addClass('t3js-page-ce t3js-page-ce-sortable'); + $('#' + DragInWizard.wizardIdentifier + ' .panel-body .media').attr('language-uid', 0).find('.media-left img').addClass('t3js-page-ce-draghandle').parent().addClass('t3-page-ce-dragitem t3-page-ce-header-draggable').closest('.media').addClass('t3js-page-ce t3js-page-ce-sortable'); DragDrop.initialize(); }; @@ -105,10 +105,18 @@ define(['jquery', 'TYPO3/CMS/Gridelements/GridElementsDragDrop', 'jquery-ui/sort DragInWizard.rearrangeItems = function () { var panel = $('#' + DragInWizard.wizardIdentifier + ' .t3js-tabs'); var CType; - var listType; $('#' + DragInWizard.wizardIdentifier + ' .media').each(function () { - $(this).find('.media-left').addClass('t3-ctype-identifier'); - var description = $(this).find('.media-body'); + var CTypeCheck = $(this).find('input').attr('value').match(/^([^_]*?)_(.*)$/); + CTypeCheck.shift(); + if (CTypeCheck[0] === 'gridelements') { + CType = 'gridelements_pi1'; + var txGridelementsBackendLayout = CTypeCheck[1]; + $(this).find('.media-left').addClass('t3-ctype-identifier').attr('data-gridtype', txGridelementsBackendLayout); + } else { + CType = CTypeCheck[1]; + } + $(this).find('.media-left').addClass('t3-ctype-identifier').attr('data-ctype', CType); + var description = $(this).find('.media-body'); description = description.appendTo($(this).parent()).hide(); $(this).find('.media-left').on('mouseenter', function () { description.show() diff --git a/Resources/Public/JavaScript/GridElementsOnReady.js b/Resources/Public/JavaScript/GridElementsOnReady.js index 66af745..b1a01c3 100644 --- a/Resources/Public/JavaScript/GridElementsOnReady.js +++ b/Resources/Public/JavaScript/GridElementsOnReady.js @@ -18,348 +18,384 @@ define(['jquery', 'TYPO3/CMS/Backend/AjaxDataHandler', 'TYPO3/CMS/Backend/Storage', 'TYPO3/CMS/Gridelements/GridElementsDragDrop', 'TYPO3/CMS/Backend/Modal'], function ($, AjaxDataHandler, Storage, DragDrop, Modal) { - var OnReady = { - openedPopupWindow: [] - }; - - - AjaxDataHandler.identifier.allGridelementsToggle = '.t3js-toggle-gridelements-all'; - AjaxDataHandler.identifier.gridelementToggle = '.t3js-toggle-gridelements-list'; - AjaxDataHandler.identifier.allGridelementsColumnsToggle = '.t3js-toggle-gridelements-columns-all'; - AjaxDataHandler.identifier.gridelementColumnToggle = '.t3js-toggle-gridelements-column'; - - /** - * initializes Drag+Drop for all content elements on the page - */ - OnReady.initialize = function () { - if ($('#recordlist-tt_content').length) { - OnReady.activateAllGridExpander(); - } - if ($('.t3js-page-columns').length) { - OnReady.setAllowedClasses(); - OnReady.activateAllCollapseIcons(); - OnReady.activatePasteIcons(); - } - }; - - /** - * sets the classes for allowed element types to the cells of the original page module - */ - OnReady.setAllowedClasses = function () { - $('table.t3js-page-columns > tbody > tr > td').each(function () { - var colPos = $(this).data('colpos') ? $(this).data('colpos') : $(this).find('> .t3-page-ce-wrapper').data('colpos'); - if (typeof colPos !== 'undefined') { - $(this).addClass(top.pageColumnsAllowedCTypes[colPos]); - $(this).addClass(top.pageColumnsAllowedGridTypes[colPos]); - OnReady.setAllowedParameters($(this), colPos); - } - }); - }; - - /** - * sets the parameters for allowed element types to the add new content links of the original page module - */ - OnReady.setAllowedParameters = function (pageColumn, colPos) { - var allowedCTypes = top.pageColumnsAllowedCTypes[colPos].replace(/ t3-allow-/g, ',').substring(1); - var allowedGridTypes = top.pageColumnsAllowedGridTypes[colPos].replace(/ t3-allow-gridtype-/g, ',').substring(1); - if (allowedCTypes !== '' && allowedCTypes !== 'all' || allowedGridTypes !== '') { - pageColumn.find('.t3js-page-new-ce:not(".t3js-page-new-ce-allowed") a').each(function () { - if(typeof $(this).attr('href') !== 'undefined') { - $(this).attr('href', $(this).attr('href').replace( - '&uid_pid', - ( allowedCTypes ? '&tx_gridelements_allowed=' + allowedCTypes : '') + - ( allowedGridTypes ? '&tx_gridelements_allowed_grid_types=' + allowedGridTypes : '' ) + - '&uid_pid' - )); - } - }); - } - }; - - /** - * activates the arrow icons to show/hide content previews within a certain grid column - */ - OnReady.activateAllCollapseIcons = function () { - OnReady.activateCollapseIcons(); - var lastIcon = $('.module-docheader-bar-column-left .btn-group .icon').last().parent(); - var addNewIcon = $('.t3js-toggle-gridelements-column').first(); - var newIcon = addNewIcon.clone().attr('class', 'btn btn-default btn-sm t3js-gridcolumn-toggle t3js-gridcolumn-expand').insertAfter(lastIcon); - newIcon.contents().filter(function () { - return (this.nodeType == 3); - }).remove(); - newIcon.find('.icon-actions-view-list-collapse').remove(); - newIcon.removeAttr('onclick').attr('title', 'Expand all grid columns'); - var newIcon = addNewIcon.clone().attr('class', 'btn btn-default btn-sm t3js-gridcolumn-toggle').insertAfter(lastIcon); - newIcon.contents().filter(function () { - return (this.nodeType == 3); - }).remove(); - newIcon.find('.icon-actions-view-list-expand').remove(); - newIcon.removeAttr('onclick').attr('title', 'Collapse all grid columns'); - $(document).on('click', '.t3js-gridcolumn-toggle', function (evt) { - evt.preventDefault(); - - var $me = $(this), - collapsed = $me.hasClass('t3js-gridcolumn-expand') ? 0 : 1; - - // Store collapse state in UC - var storedModuleDataPage = {}; - - if (Storage.Persistent.isset('moduleData.page.gridelementsCollapsedColumns')) { - storedModuleDataPage = Storage.Persistent.get('moduleData.list.gridelementsExpanded'); - } - - var collapseConfig = {}; - $('[data-columnkey]').each(function () { - collapseConfig[$(this).data('columnkey')] = collapsed; - $(this).removeClass('collapsed','expanded'); - $(this).addClass(collapsed ? 'collapsed' : 'expanded'); - }); - - storedModuleDataPage = $.extend(true, storedModuleDataPage, collapseConfig); - Storage.Persistent.set('moduleData.page.gridelementsCollapsedColumns', storedModuleDataPage); - - }); - } - - /** - * activates the arrow icons to show/hide content previews within a certain grid column - */ - OnReady.activateCollapseIcons = function () { - $(document).on('click', AjaxDataHandler.identifier.gridelementColumnToggle, function (evt) { - evt.preventDefault(); - - var $me = $(this), - column = $me.closest('.t3js-page-column').data('colpos'), - columnKey = $me.closest('.t3js-page-column').data('columnkey'), - isExpanded = $me.data('state') === 'expanded'; - - // Store collapse state in UC - var storedModuleDataPage = {}; - - if (Storage.Persistent.isset('moduleData.page.gridelementsCollapsedColumns')) { - storedModuleDataPage = Storage.Persistent.get('moduleData.page.gridelementsCollapsedColumns'); - } - - var expandConfig = {}; - expandConfig[columnKey] = isExpanded ? 1 : 0; - - storedModuleDataPage = $.extend(true, storedModuleDataPage, expandConfig); - Storage.Persistent.set('moduleData.page.gridelementsCollapsedColumns', storedModuleDataPage).done(function () { - $me.data('state', isExpanded ? 'collapsed' : 'expanded'); - }); - - $me.closest('.t3-grid-cell').toggleClass('collapsed','expanded'); - var originalTitle = $me.attr('title'); - $me.attr('title', $me.attr('data-toggle-title')); - $me.attr('data-toggle-title', originalTitle); - $me.blur(); - - }); - - $('.t3-page-column-header-icons').each(function () { - $(this).addClass('btn-group btn-group-sm'); - $(this).find('a').addClass('btn btn-default'); - }); - } - - /** - * activates the paste into / paste after and fetch copy from another page icons outside of the context menus - */ - OnReady.activatePasteIcons = function () { - $('.icon-actions-document-paste-into').parent().remove(); - $('.t3-page-ce-wrapper-new-ce').each(function () { - if(!$(this).find('.icon-actions-document-new').length) { - return true; - } - $(this).addClass('btn-group btn-group-sm'); - $('.t3js-page-lang-column .t3-page-ce > .t3-page-ce').removeClass('t3js-page-ce'); - if (top.pasteAfterLinkTemplate && top.pasteIntoLinkTemplate) { - var parent = $(this).parent(); - if (parent.data('page') || (parent.data('container') && !parent.data('uid'))) { - $(this).append(top.pasteIntoLinkTemplate); - } else { - $(this).append(top.pasteAfterLinkTemplate); - } - $(this).find('.t3js-paste').on('click', function (evt) { - evt.preventDefault(); - OnReady.activatePasteModal($(this)); - }); - } - $(this).append(top.copyFromAnotherPageLinkTemplate); - $(this).find('.t3js-paste-new').on('click', function (evt) { - evt.preventDefault(); - OnReady.copyFromAnotherPage($(this)); - }); - }); - } - - /** - * generates the paste into / paste after modal - */ - OnReady.activatePasteModal = function (element) { - var $element = $(element); - var url = $element.data('url') || null; - var title = (TYPO3.lang['tx_gridelements_js.modal.title.paste'] || 'Paste record') + ': "' + $element.data('pastetitle') + '"'; - var severity = (typeof top.TYPO3.Severity[$element.data('severity')] !== 'undefined') ? top.TYPO3.Severity[$element.data('severity')] : top.TYPO3.Severity.info; - if ($element.hasClass('t3js-paste-copy')) { - var content = TYPO3.lang['tx_gridelements_js.modal.pastecopy'] || '1 How do you want to paste that clipboard content here?'; - var buttons = [ - { - text: TYPO3.lang['tx_gridelements_js.modal.button.cancel'] || 'Cancel', - active: true, - btnClass: 'btn-default', - trigger: function () { - Modal.currentModal.trigger('modal-dismiss'); - } - }, - { - text: TYPO3.lang['tx_gridelements_js.modal.button.pastecopy'] || 'Paste as copy', - btnClass: 'btn-' + Modal.getSeverityClass(severity), - trigger: function () { - Modal.currentModal.trigger('modal-dismiss'); - DragDrop.onDrop($element.data('pasteitem'), $element, null); - } - }, - { - text: TYPO3.lang['tx_gridelements_js.modal.button.pastereference'] || 'Paste as reference', - btnClass: 'btn-' + Modal.getSeverityClass(severity), - trigger: function () { - Modal.currentModal.trigger('modal-dismiss'); - DragDrop.onDrop($element.data('pasteitem'), $element, 'reference'); - } - } - ]; - if(top.pasteReferencesAllowed !== true) { - buttons.pop(); - } - } else { - var content = TYPO3.lang['tx_gridelements_js.modal.paste'] || 'Do you want to paste that clipboard content here?'; - var buttons = [ - { - text: TYPO3.lang['tx_gridelements_js.modal.button.cancel'] || 'Cancel', - active: true, - btnClass: 'btn-default', - trigger: function () { - Modal.currentModal.trigger('modal-dismiss'); - } - }, - { - text: TYPO3.lang['tx_gridelements_js.modal.button.paste'] || 'Paste', - btnClass: 'btn-' + Modal.getSeverityClass(severity), - trigger: function () { - Modal.currentModal.trigger('modal-dismiss'); - DragDrop.onDrop($element.data('pasteitem'), $element, null); - } - } - ]; - } - if (url !== null) { - var separator = (url.indexOf('?') > -1) ? '&' : '?'; - var params = $.param({data: $element.data()}); - Modal.loadUrl(title, severity, buttons, url + separator + params); - } else { - Modal.show(title, content, severity, buttons); - } - } - - /** - * generates the paste into / paste after modal - */ - OnReady.copyFromAnotherPage = function (element) { - var url = top.backPath + top.browserUrl + '&mode=db&bparams=' + element.parent().attr('id') + '|||tt_content|'; - var width = top.TYPO3.configuration.PopupWindow.width; - var height = top.TYPO3.configuration.PopupWindow.height; - OnReady.openedPopupWindow = window.open(url, 'Typo3WinBrowser', 'height=' + height + ',width=' + width + ',status=0,menubar=0,resizable=1,scrollbars=1'); - OnReady.openedPopupWindow.focus(); - } - - /** - * gives back the data form the popup window to the copy action - */ - if (!$('.typo3-TCEforms').length) { - OnReady.setSelectOptionFromExternalSource = setFormValueFromBrowseWin = function(elementId, tableUid){ - tableUid = tableUid.replace('tt_content_', '') * 1; - DragDrop.onDrop(tableUid, $('#' + elementId).find('.t3js-paste-new'), 'copyFromAnotherPage'); - } - } - - /** - * activates the toggle icons to open listings of nested grid container structure in the list module - */ - OnReady.activateAllGridExpander = function () { - OnReady.activateGridExpander(); - $(document).on('click', AjaxDataHandler.identifier.allGridelementsToggle, function (evt) { - evt.preventDefault(); - - var $me = $(this), - container = '0,' + $me.data('container-ids'), - isExpanded = this.id === 't3-gridelements-expand-all' ? 1 : 0; - - // Store collapse state in UC - var storedModuleDataList = {}; - - if (Storage.Persistent.isset('moduleData.list.gridelementsExpanded')) { - storedModuleDataList = Storage.Persistent.get('moduleData.list.gridelementsExpanded'); - } - - var expandConfig = {}; - $(container.split(',')).each(function (el, id) { - if (id > 0) { - expandConfig[id] = isExpanded; - if (isExpanded === 1) { - $('[data-uid=' + id + ']').find('.t3js-toggle-gridelements-list').addClass('open-gridelements-container'); - $('[data-trigger-container=' + id + ']').show(); - } else { - $('[data-uid=' + id + ']').find('.t3js-toggle-gridelements-list').removeClass('open-gridelements-container'); - $('[data-trigger-container=' + id + ']').hide(); - } - } - }); - - storedModuleDataList = $.extend(true, storedModuleDataList, expandConfig); - Storage.Persistent.set('moduleData.list.gridelementsExpanded', storedModuleDataList); - - }); - - }; - - /** - * activates the toggle icons to open listings of nested grid container structure in the list module - */ - OnReady.activateGridExpander = function () { - $(document).on('click', AjaxDataHandler.identifier.gridelementToggle, function (evt) { - evt.preventDefault(); - - var $me = $(this), - container = $me.closest('tr').data('uid'), - isExpanded = $me.data('state') === 'expanded'; - - // Store collapse state in UC - var storedModuleDataList = {}; - - if (Storage.Persistent.isset('moduleData.list.gridelementsExpanded')) { - storedModuleDataList = Storage.Persistent.get('moduleData.list.gridelementsExpanded'); - } - - var expandConfig = {}; - expandConfig[container] = isExpanded ? 0 : 1; - - storedModuleDataList = $.extend(true, storedModuleDataList, expandConfig); - Storage.Persistent.set('moduleData.list.gridelementsExpanded', storedModuleDataList).done(function () { - $me.data('state', isExpanded ? 'collapsed' : 'expanded'); - }); - - $(this).toggleClass('open-gridelements-container'); - var originalTitle = $(this).attr('data-original-title'); - $(this).attr('data-original-title', $(this).attr('data-toggle-title')); - $(this).attr('data-toggle-title', originalTitle); - $(this).blur(); - - $('[data-trigger-container=' + $(this).closest('tr').data('uid') + ']').toggle().find('.open-gridelements-container').click(); - }); - - }; - - $(OnReady.initialize); - return OnReady; + var OnReady = { + openedPopupWindow: [] + }; + + + AjaxDataHandler.identifier.allGridelementsToggle = '.t3js-toggle-gridelements-all'; + AjaxDataHandler.identifier.gridelementToggle = '.t3js-toggle-gridelements-list'; + AjaxDataHandler.identifier.allGridelementsColumnsToggle = '.t3js-toggle-gridelements-columns-all'; + AjaxDataHandler.identifier.gridelementColumnToggle = '.t3js-toggle-gridelements-column'; + + /** + * initializes Drag+Drop for all content elements on the page + */ + OnReady.initialize = function () { + if ($('#recordlist-tt_content').length) { + OnReady.activateAllGridExpander(); + } + if ($('.t3js-page-columns').length) { + OnReady.setAllowedClasses(); + OnReady.activateAllCollapseIcons(); + OnReady.activatePasteIcons(); + } + }; + + /** + * sets the classes for allowed element types to the cells of the original page module + */ + OnReady.setAllowedClasses = function () { + $('table.t3js-page-columns > tbody > tr > td').each(function () { + var colPos = $(this).data('colpos') ? $(this).data('colpos') : $(this).find('> .t3-page-ce-wrapper').data('colpos'); + if (typeof colPos !== 'undefined') { + $(this).addClass(top.pageColumnsAllowedCTypes[colPos]); + $(this).addClass(top.pageColumnsAllowedGridTypes[colPos]); + OnReady.setAllowedParameters($(this), colPos); + } + }); + }; + + /** + * sets the parameters for allowed element types to the add new content links of the original page module + */ + OnReady.setAllowedParameters = function (pageColumn, colPos) { + var allowedCTypes = top.pageColumnsAllowedCTypes[colPos].replace(/ t3-allow-/g, ',').substring(1); + var allowedGridTypes = top.pageColumnsAllowedGridTypes[colPos].replace(/ t3-allow-gridtype-/g, ',').substring(1); + if (allowedCTypes !== '' && allowedCTypes !== 'all' || allowedGridTypes !== '') { + pageColumn.find('.t3js-page-new-ce:not(".t3js-page-new-ce-allowed") a').each(function () { + if (typeof $(this).attr('href') !== 'undefined') { + $(this).attr('href', $(this).attr('href').replace( + '&uid_pid', + (allowedCTypes ? '&tx_gridelements_allowed=' + allowedCTypes : '') + + (allowedGridTypes ? '&tx_gridelements_allowed_grid_types=' + allowedGridTypes : '') + + '&uid_pid' + )); + } + }); + } + }; + + /** + * activates the arrow icons to show/hide content previews within a certain grid column + */ + OnReady.activateAllCollapseIcons = function () { + OnReady.activateCollapseIcons(); + var lastIcon = $('.module-docheader-bar-column-left .btn-group .icon').last().parent(); + var addNewIcon = $('.t3js-toggle-gridelements-column').first(); + var newIcon = addNewIcon.clone().attr('class', 'btn btn-default btn-sm t3js-gridcolumn-toggle t3js-gridcolumn-expand').insertAfter(lastIcon); + newIcon.contents().filter(function () { + return (this.nodeType == 3); + }).remove(); + newIcon.find('.icon-actions-view-list-collapse').remove(); + newIcon.removeAttr('onclick').attr('title', 'Expand all grid columns'); + var newIcon = addNewIcon.clone().attr('class', 'btn btn-default btn-sm t3js-gridcolumn-toggle').insertAfter(lastIcon); + newIcon.contents().filter(function () { + return (this.nodeType == 3); + }).remove(); + newIcon.find('.icon-actions-view-list-expand').remove(); + newIcon.removeAttr('onclick').attr('title', 'Collapse all grid columns'); + $(document).on('click', '.t3js-gridcolumn-toggle', function (evt) { + evt.preventDefault(); + + var $me = $(this), + collapsed = $me.hasClass('t3js-gridcolumn-expand') ? 0 : 1; + + // Store collapse state in UC + var storedModuleDataPage = {}; + + if (Storage.Persistent.isset('moduleData.page.gridelementsCollapsedColumns')) { + storedModuleDataPage = Storage.Persistent.get('moduleData.list.gridelementsExpanded'); + } + + var collapseConfig = {}; + $('[data-columnkey]').each(function () { + collapseConfig[$(this).data('columnkey')] = collapsed; + $(this).removeClass('collapsed', 'expanded'); + $(this).addClass(collapsed ? 'collapsed' : 'expanded'); + }); + + storedModuleDataPage = $.extend(true, storedModuleDataPage, collapseConfig); + Storage.Persistent.set('moduleData.page.gridelementsCollapsedColumns', storedModuleDataPage); + + }); + } + + /** + * activates the arrow icons to show/hide content previews within a certain grid column + */ + OnReady.activateCollapseIcons = function () { + $(document).on('click', AjaxDataHandler.identifier.gridelementColumnToggle, function (evt) { + evt.preventDefault(); + + var $me = $(this), + column = $me.closest('.t3js-page-column').data('colpos'), + columnKey = $me.closest('.t3js-page-column').data('columnkey'), + isExpanded = $me.data('state') === 'expanded'; + + // Store collapse state in UC + var storedModuleDataPage = {}; + + if (Storage.Persistent.isset('moduleData.page.gridelementsCollapsedColumns')) { + storedModuleDataPage = Storage.Persistent.get('moduleData.page.gridelementsCollapsedColumns'); + } + + var expandConfig = {}; + expandConfig[columnKey] = isExpanded ? 1 : 0; + + storedModuleDataPage = $.extend(true, storedModuleDataPage, expandConfig); + Storage.Persistent.set('moduleData.page.gridelementsCollapsedColumns', storedModuleDataPage).done(function () { + $me.data('state', isExpanded ? 'collapsed' : 'expanded'); + }); + + $me.closest('.t3-grid-cell').toggleClass('collapsed', 'expanded'); + var originalTitle = $me.attr('title'); + $me.attr('title', $me.attr('data-toggle-title')); + $me.attr('data-toggle-title', originalTitle); + $me.blur(); + + }); + + $('.t3-page-column-header-icons').each(function () { + $(this).addClass('btn-group btn-group-sm'); + $(this).find('a').addClass('btn btn-default'); + }); + } + + /** + * activates the paste into / paste after and fetch copy from another page icons outside of the context menus + */ + OnReady.activatePasteIcons = function () { + $('.icon-actions-document-paste-into').parent().remove(); + $('.t3-page-ce-wrapper-new-ce').each(function () { + if (!$(this).find('.icon-actions-document-new').length) { + return true; + } + $(this).addClass('btn-group btn-group-sm'); + $('.t3js-page-lang-column .t3-page-ce > .t3-page-ce').removeClass('t3js-page-ce'); + var gridCell = $(this).closest('.t3-grid-cell'); + if (typeof(gridCell.data('allowed')) === 'undefined') { + gridCell.data('allowedCType', false); + gridCell.data('allowedGridType', false); + if (top.clipBoardElementCType.toString() !== '0') { + if ( + gridCell.hasClass('t3-allow-' + top.clipBoardElementCType) + || gridCell.hasClass('t3-allow-all') + ) { + gridCell.data('allowedCType', true); + } + } else { + gridCell.data('allowedCType', true); + } + if (top.clipBoardElementGridType.toString() !== '0') { + if ( + ( + !gridCell.hasClass('t3-allow-gridtype') + && ( + gridCell.hasClass('t3-allow-gridelement_pi1') + || gridCell.hasClass('t3-allow-all') + ) + ) + || ( + gridCell.hasClass('t3-allow-gridtype') + && gridCell.hasClass('t3-allow-gridtype-' + top.clipBoardElementGridType) + ) + + ) { + gridCell.data('allowedGridType', true); + } + } else { + gridCell.data('allowedGridType', true); + } + gridCell.data('allowed', (gridCell.data('allowedCType') && gridCell.data('allowedGridType'))); + } + if (top.pasteAfterLinkTemplate && top.pasteIntoLinkTemplate && gridCell.data('allowed')) { + var parent = $(this).parent(); + if (parent.data('page') || (parent.data('container') && !parent.data('uid'))) { + $(this).append(top.pasteIntoLinkTemplate); + } else { + $(this).append(top.pasteAfterLinkTemplate); + } + $(this).find('.t3js-paste').on('click', function (evt) { + evt.preventDefault(); + OnReady.activatePasteModal($(this)); + }); + } + $(this).append(top.copyFromAnotherPageLinkTemplate); + $(this).find('.t3js-paste-new').on('click', function (evt) { + evt.preventDefault(); + OnReady.copyFromAnotherPage($(this)); + }); + }); + } + + /** + * generates the paste into / paste after modal + */ + OnReady.activatePasteModal = function (element) { + var $element = $(element); + var url = $element.data('url') || null; + var title = (TYPO3.lang['tx_gridelements_js.modal.title.paste'] || 'Paste record') + ': "' + $element.data('pastetitle') + '"'; + var severity = (typeof top.TYPO3.Severity[$element.data('severity')] !== 'undefined') ? top.TYPO3.Severity[$element.data('severity')] : top.TYPO3.Severity.info; + if ($element.hasClass('t3js-paste-copy')) { + var content = TYPO3.lang['tx_gridelements_js.modal.pastecopy'] || '1 How do you want to paste that clipboard content here?'; + var buttons = [ + { + text: TYPO3.lang['tx_gridelements_js.modal.button.cancel'] || 'Cancel', + active: true, + btnClass: 'btn-default', + trigger: function () { + Modal.currentModal.trigger('modal-dismiss'); + } + }, + { + text: TYPO3.lang['tx_gridelements_js.modal.button.pastecopy'] || 'Paste as copy', + btnClass: 'btn-' + Modal.getSeverityClass(severity), + trigger: function () { + Modal.currentModal.trigger('modal-dismiss'); + DragDrop.onDrop($element.data('pasteitem'), $element, null); + } + }, + { + text: TYPO3.lang['tx_gridelements_js.modal.button.pastereference'] || 'Paste as reference', + btnClass: 'btn-' + Modal.getSeverityClass(severity), + trigger: function () { + Modal.currentModal.trigger('modal-dismiss'); + DragDrop.onDrop($element.data('pasteitem'), $element, 'reference'); + } + } + ]; + if (top.pasteReferenceAllowed !== true) { + buttons.pop(); + } + } else { + var content = TYPO3.lang['tx_gridelements_js.modal.paste'] || 'Do you want to paste that clipboard content here?'; + var buttons = [ + { + text: TYPO3.lang['tx_gridelements_js.modal.button.cancel'] || 'Cancel', + active: true, + btnClass: 'btn-default', + trigger: function () { + Modal.currentModal.trigger('modal-dismiss'); + } + }, + { + text: TYPO3.lang['tx_gridelements_js.modal.button.paste'] || 'Paste', + btnClass: 'btn-' + Modal.getSeverityClass(severity), + trigger: function () { + Modal.currentModal.trigger('modal-dismiss'); + DragDrop.onDrop($element.data('pasteitem'), $element, null); + } + } + ]; + } + if (url !== null) { + var separator = (url.indexOf('?') > -1) ? '&' : '?'; + var params = $.param({data: $element.data()}); + Modal.loadUrl(title, severity, buttons, url + separator + params); + } else { + Modal.show(title, content, severity, buttons); + } + } + + /** + * generates the paste into / paste after modal + */ + OnReady.copyFromAnotherPage = function (element) { + var url = top.backPath + top.browserUrl + '&mode=db&search_field=gridelements_pi1&bparams=' + element.parent().attr('id') + '|||tt_content|'; + var width = top.TYPO3.configuration.PopupWindow.width; + var height = top.TYPO3.configuration.PopupWindow.height; + OnReady.openedPopupWindow = window.open(url, 'Typo3WinBrowser', 'height=' + height + ',width=' + width + ',status=0,menubar=0,resizable=1,scrollbars=1'); + OnReady.openedPopupWindow.focus(); + } + + /** + * gives back the data from the popup window to the copy action + */ + if (!$('.typo3-TCEforms').length) { + OnReady.setSelectOptionFromExternalSource = setFormValueFromBrowseWin = function (elementId, tableUid) { + tableUid = tableUid.replace('tt_content_', '') * 1; + DragDrop.onDrop(tableUid, $('#' + elementId).find('.t3js-paste-new'), 'copyFromAnotherPage'); + } + } + + /** + * activates the toggle icons to open listings of nested grid container structure in the list module + */ + OnReady.activateAllGridExpander = function () { + OnReady.activateGridExpander(); + $(document).on('click', AjaxDataHandler.identifier.allGridelementsToggle, function (evt) { + evt.preventDefault(); + + var $me = $(this), + container = '0,' + $me.data('container-ids'), + isExpanded = this.id === 't3-gridelements-expand-all' ? 1 : 0; + + // Store collapse state in UC + var storedModuleDataList = {}; + + if (Storage.Persistent.isset('moduleData.list.gridelementsExpanded')) { + storedModuleDataList = Storage.Persistent.get('moduleData.list.gridelementsExpanded'); + } + + var expandConfig = {}; + $(container.split(',')).each(function (el, id) { + if (id > 0) { + expandConfig[id] = isExpanded; + if (isExpanded === 1) { + $('[data-uid=' + id + ']').find('.t3js-toggle-gridelements-list').addClass('open-gridelements-container'); + $('[data-trigger-container=' + id + ']').show(); + } else { + $('[data-uid=' + id + ']').find('.t3js-toggle-gridelements-list').removeClass('open-gridelements-container'); + $('[data-trigger-container=' + id + ']').hide(); + } + } + }); + + storedModuleDataList = $.extend(true, storedModuleDataList, expandConfig); + Storage.Persistent.set('moduleData.list.gridelementsExpanded', storedModuleDataList); + + }); + + }; + + /** + * activates the toggle icons to open listings of nested grid container structure in the list module + */ + OnReady.activateGridExpander = function () { + $(document).on('click', AjaxDataHandler.identifier.gridelementToggle, function (evt) { + evt.preventDefault(); + + var $me = $(this), + container = $me.closest('tr').data('uid'), + isExpanded = $me.data('state') === 'expanded'; + + // Store collapse state in UC + var storedModuleDataList = {}; + + if (Storage.Persistent.isset('moduleData.list.gridelementsExpanded')) { + storedModuleDataList = Storage.Persistent.get('moduleData.list.gridelementsExpanded'); + } + + var expandConfig = {}; + expandConfig[container] = isExpanded ? 0 : 1; + + storedModuleDataList = $.extend(true, storedModuleDataList, expandConfig); + Storage.Persistent.set('moduleData.list.gridelementsExpanded', storedModuleDataList).done(function () { + $me.data('state', isExpanded ? 'collapsed' : 'expanded'); + }); + + $(this).toggleClass('open-gridelements-container'); + var originalTitle = $(this).attr('data-original-title'); + $(this).attr('data-original-title', $(this).attr('data-toggle-title')); + $(this).attr('data-toggle-title', originalTitle); + $(this).blur(); + + $('[data-trigger-container=' + $(this).closest('tr').data('uid') + ']').toggle().find('.open-gridelements-container').click(); + }); + + }; + + $(OnReady.initialize); + return OnReady; }); diff --git a/composer.json b/composer.json index ec5b625..d947eb4 100644 --- a/composer.json +++ b/composer.json @@ -1,25 +1,32 @@ { - "name": "GridElementsTeam/Gridelements", - "description": "This extension integrates the grid layout concept to regular content elements.", + "name": "gridelementsteam/gridelements", + "description": "This extension integrates the grid layout concept also to regular content elements - the grid elements. It offers a lot of new features like advanced drag & drop or real references, that improve the usability of the page and list module to speed up the daily work with the backend.", "type": "typo3-cms-extension", + "version": "7.4.2", "keywords": ["TYPO3 CMS", "Grids", "Gridelements"], - "homepage": "https://git.typo3.org/TYPO3CMS/Extensions/gridelements.git", - "license": "GPL-2.0+", - "version": "7.0.5", + "homepage": "https://forge.typo3.org/projects/extension-gridelements2", + "license": "GPL-2.0-or-later", "support": { - "issues": "https://forge.typo3.org/" + "issues": "https://forge.typo3.org/projects/extension-gridelements2/issues" }, "require": { - "typo3/cms-core": ">=7.6.2,<8.0" + "typo3/cms-core": "^7.6", + "typo3/cms-backend": "^7.6", + "typo3/cms-recordlist": "^7.6", + "typo3/cms-frontend": "^7.6", + "typo3/cms-lang": "^7.6" + }, + "conflict": { + "templavoila": "*", + "jfmulticontent": "*" + }, + "replace": { + "gridelements": "self.version", + "typo3-ter/gridelements": "self.version" }, "autoload": { "psr-4": { "GridElementsTeam\\Gridelements\\": "Classes/" } - }, - "extra": { - "branch-alias": { - "dev-master": "7.0.5" - } } } \ No newline at end of file diff --git a/ext_conf_template.txt b/ext_conf_template.txt index 15b1771..fad99e3 100644 --- a/ext_conf_template.txt +++ b/ext_conf_template.txt @@ -3,3 +3,6 @@ additionalStylesheet = # cat=basic; type=boolean; label=LLL:EXT:gridelements/Resources/Private/Language/locallang.xlf:nestingInListModule nestingInListModule = 0 + +# cat=basic; type=boolean; label=LLL:EXT:gridelements/Resources/Private/Language/locallang.xlf:overlayShortcutTranslation +overlayShortcutTranslation = 0 \ No newline at end of file diff --git a/ext_emconf.php b/ext_emconf.php index add19d9..6b65261 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -8,15 +8,15 @@ * writing. "version" and "dependencies" must not be touched! ***************************************************************/ -$EM_CONF[$_EXTKEY] = array( +$EM_CONF[$_EXTKEY] = [ 'title' => 'Grid Elements', 'description' => 'This extension integrates the grid layout concept also to regular content elements - the grid elements. It offers a lot of new features like advanced drag & drop or real references, that improve the usability of the page and list module to speed up the daily work with the backend.', 'category' => 'be', - 'version' => '8.0.0-dev', + 'version' => '7.4.2', 'priority' => 'bottom', 'module' => '', - 'state' => 'beta', + 'state' => 'stable', 'uploadfolder' => true, 'createDirs' => '', 'modify_tables' => 'tt_content', @@ -24,14 +24,18 @@ 'author' => 'Grid Elements Team', 'author_email' => 'info@cybercraft.de', 'author_company' => '', - 'constraints' => array( - 'depends' => array( - 'typo3' => '8.0.0-8.99.99', - ), - 'conflicts' => array( + 'constraints' => [ + 'depends' => [ + 'typo3' => '7.6.0-7.6.99', + 'backend' => '7.6.0-7.6.99', + 'recordlist' => '7.6.0-7.6.99', + 'frontend' => '7.6.0-7.6.99', + 'lang' => '7.6.0-7.6.99', + ], + 'conflicts' => [ 'templavoila' => '', - 'jfmulticontent' => '', - ), - 'suggests' => array(), - ), -); + 'jfmulticontent' => '' + ], + 'suggests' => [], + ], +]; diff --git a/ext_localconf.php b/ext_localconf.php index ccdfc08..75d08f4 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -9,10 +9,10 @@ options.saveDocNew.tx_gridelements_backend_layout=1 '); -\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPItoST43($_EXTKEY, 'Classes/Plugin/Gridelements.php', '_pi1', - 'CType', 1); - // XCLASS if ($_EXTCONF['nestingInListModule']) { $GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects']['TYPO3\\CMS\\Recordlist\\RecordList\\DatabaseRecordList'] = array('className' => 'GridElementsTeam\\Gridelements\\Xclass\\DatabaseRecordList',); } + +$signalSlotDispatcher = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class); +$signalSlotDispatcher->connect(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::class, 'tcaIsBeingBuilt', \GridElementsTeam\Gridelements\Slots\ExtTablesInclusionPostProcessing::class, 'processData'); diff --git a/ext_tables.php b/ext_tables.php index a67ac78..a55e1e0 100644 --- a/ext_tables.php +++ b/ext_tables.php @@ -5,11 +5,6 @@ $_EXTCONF = unserialize($_EXTCONF); -\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_gridelements_backend_layout'); - -if (TYPO3_MODE === 'BE') { - include_once(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('gridelements') . 'Classes/Backend/TtContent.php'); -} \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile($_EXTKEY, 'Configuration/TypoScript/', 'Gridelements'); @@ -20,28 +15,30 @@ 'gridelements-default' ), 'CType'); +\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_gridelements_backend_layout'); + +if (TYPO3_MODE == 'BE') { + + include_once(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('gridelements') . 'Classes/Backend/TtContent.php'); + + $GLOBALS['TBE_STYLES']['skins']['gridelements']['name'] = 'gridelements'; + $GLOBALS['TBE_STYLES']['skins']['gridelements']['stylesheetDirectories']['gridelements_structure'] = 'EXT:' . ($_EXTKEY) . '/Resources/Public/Backend/Css/Skin/'; + if ($_EXTCONF['additionalStylesheet'] && \TYPO3\CMS\Core\Utility\GeneralUtility::validPathStr($_EXTCONF['additionalStylesheet'])) { + $GLOBALS['TBE_STYLES']['skins']['gridelements']['stylesheetDirectories']['gridelements_additional'] = $_EXTCONF['additionalStylesheet']; + } + $GLOBALS['TBE_MODULES_EXT']['xMOD_alt_clickmenu']['extendCMclasses'][] = array('name' => 'GridElementsTeam\\Gridelements\\Backend\\ClickMenuOptions',); + +} + // Hooks $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/class.tx_cms_layout.php']['tt_content_drawItem'][] = 'EXT:gridelements/Classes/Hooks/DrawItem.php:GridElementsTeam\\Gridelements\\Hooks\\DrawItem'; - $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms']['db_new_content_el']['wizardItemsHook'][] = 'EXT:gridelements/Classes/Hooks/WizardItems.php:GridElementsTeam\\Gridelements\\Hooks\\WizardItems'; - $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processCmdmapClass'][] = 'EXT:gridelements/Classes/Hooks/DataHandler.php:GridElementsTeam\\Gridelements\\Hooks\\DataHandler'; $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][] = 'EXT:gridelements/Classes/Hooks/DataHandler.php:GridElementsTeam\\Gridelements\\Hooks\\DataHandler'; $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['moveRecordClass'][] = 'EXT:gridelements/Classes/Hooks/DataHandler.php:GridElementsTeam\\Gridelements\\Hooks\\DataHandler'; - $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['getFlexFormDSClass'][] = 'EXT:gridelements/Classes/Hooks/BackendUtilityGridelements.php:GridElementsTeam\\Gridelements\\Hooks\\BackendUtilityGridelements'; - $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tx_templavoila_api']['apiIsRunningTCEmain'] = true; - -if (TYPO3_MODE == 'BE') { - $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-preProcess'][] = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY) . 'Classes/Hooks/PageRenderer.php:GridElementsTeam\\Gridelements\\Hooks\\PageRenderer->addJSCSS'; -} - -if ($_EXTCONF['nestingInListModule']) { - $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list.inc']['makeQueryArray'][] = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY) . 'Classes/Hooks/AbstractDatabaseRecordList.php:GridElementsTeam\\Gridelements\\Hooks\\AbstractDatabaseRecordList'; - - $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'][] = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY) . 'Classes/Hooks/DatabaseRecordList.php:GridElementsTeam\\Gridelements\\Hooks\\DatabaseRecordList'; -} +$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-preProcess'][] = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY) . 'Classes/Hooks/PageRenderer.php:GridElementsTeam\\Gridelements\\Hooks\\PageRenderer->addJSCSS'; $GLOBALS['TYPO3_USER_SETTINGS']['columns']['dragAndDropHideNewElementWizardInfoOverlay'] = array( 'type' => 'check', @@ -65,12 +62,12 @@ $GLOBALS['TYPO3_USER_SETTINGS']['showitem'] .= ',--div--;LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:gridElements,dragAndDropHideNewElementWizardInfoOverlay,hideColumnHeaders,hideContentPreview,showGridInformation'; -$TBE_STYLES['skins']['gridelements']['name'] = 'gridelements'; -$TBE_STYLES['skins']['gridelements']['stylesheetDirectories']['structure'] = 'EXT:' . ($_EXTKEY) . '/Resources/Public/Backend/Css/Skin/'; +if ($_EXTCONF['nestingInListModule']) { + $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list.inc']['makeQueryArray'][] = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY) . 'Classes/Hooks/AbstractDatabaseRecordList.php:GridElementsTeam\\Gridelements\\Hooks\\AbstractDatabaseRecordList'; -$GLOBALS['TBE_MODULES_EXT']['xMOD_alt_clickmenu']['extendCMclasses'][] = array('name' => 'GridElementsTeam\\Gridelements\\Backend\\ClickMenuOptions',); + $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'][] = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY) . 'Classes/Hooks/DatabaseRecordList.php:GridElementsTeam\\Gridelements\\Hooks\\DatabaseRecordList'; +} -$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preHeaderRenderHook'][] = 'GridElementsTeam\\Gridelements\\Hooks\\PreHeaderRenderHook->main'; $iconRegistry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Imaging\IconRegistry::class); $iconRegistry->registerIcon('gridelements-default', \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class, array(
    '; - $grid .= ($this->helper->getBackendUser()->uc['hideColumnHeaders'] ? '' : $head[$columnKey]) . $gridContent[$columnKey]; + $grid .= ($this->helper->getBackendUser()->uc['hideColumnHeaders'] ? '' : $columnHead) . $gridContent[$columnKey]; $grid .= '

    - ' . $this->getLanguageService()->sL('LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:list.columnName') . ' ' . ($backendLayoutColumns[$row['colPos']] ? $backendLayoutColumns[$row['colPos']] : (int)$row['colPos']) . ' + ' + . $this->getLanguageService()->sL('LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:list.columnName') + . ' ' . ($backendLayoutColumns[$row['colPos']] ? $backendLayoutColumns[$row['colPos']] : (int)$row['colPos']) . '
    - ' . ' [1 - ' . $countOnFirstPage . ($hasMore ? '+' : '') . '] + ' + . ' [1 - ' + . $countOnFirstPage . ($hasMore ? '+' : '') . ']
    -
    - ' . $this->getLanguageService()->sL('LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:list.columnName') . ' ' . ($backendLayoutColumns[$child['tx_gridelements_columns']] ? $backendLayoutColumns[$child['tx_gridelements_columns']] : (int)$child['tx_gridelements_columns']) . ' -
    +
    + ' . $this->getLanguageService()->sL('LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:list.columnName') + . ' ' . (int)$child['tx_gridelements_columns'] . ' +
    -tags * @param string $rowParams Is insert in the
    fieldArray[0] ? ' disabled="disabled"' : '') . '>' . '
    fieldArray[0] ? ' disabled="disabled"' : '') + . '>' . '