From 21d1fb5b11fe9cdcd76ef68125f4bbb64538827d Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Fri, 22 Apr 2016 14:19:56 +0200 Subject: [PATCH 001/102] [TASK] Changed version number to distinguish between TER version Change-Id: I1ebfa321a632791ad11b49e215652b2bce54ef02 Reviewed-on: https://review.typo3.org/47856 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- ext_emconf.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext_emconf.php b/ext_emconf.php index 1cda528..13758ce 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -13,7 +13,7 @@ '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' => '7.0.5', + 'version' => '7.0.6-dev', 'priority' => 'bottom', 'module' => '', 'state' => 'beta', From 87ffc6fa69ce20129d93aabda2e293a82cdfc4c7 Mon Sep 17 00:00:00 2001 From: Markus Klein Date: Tue, 12 Jul 2016 20:03:53 +0200 Subject: [PATCH 002/102] [BUGFIX] Fix composer.json for CMS 8 Change-Id: I640691904f9178b16ac5f110becad8e4bd670f57 Releases: 7-0 Reviewed-on: https://review.typo3.org/48941 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau (cherry picked from commit 27434632abaa5a61382c9f5539f25c35f04c965e) Reviewed-on: https://review.typo3.org/48945 --- composer.json | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index ec5b625..d8a7d0e 100644 --- a/composer.json +++ b/composer.json @@ -5,21 +5,19 @@ "keywords": ["TYPO3 CMS", "Grids", "Gridelements"], "homepage": "https://git.typo3.org/TYPO3CMS/Extensions/gridelements.git", "license": "GPL-2.0+", - "version": "7.0.5", "support": { "issues": "https://forge.typo3.org/" }, "require": { - "typo3/cms-core": ">=7.6.2,<8.0" + "typo3/cms-core": "~8.0" + }, + "replace": { + "gridelements": "*", + "typo3-ter/gridelements": "*" }, "autoload": { "psr-4": { "GridElementsTeam\\Gridelements\\": "Classes/" } - }, - "extra": { - "branch-alias": { - "dev-master": "7.0.5" - } } } \ No newline at end of file From d7c35a9b67362e0aa1c9bf91a5302cef089f9db5 Mon Sep 17 00:00:00 2001 From: Markus Klein Date: Tue, 12 Jul 2016 20:16:17 +0200 Subject: [PATCH 003/102] [BUGFIX] Fix various issues in DatabaseRecordList xclass Change-Id: I72537bdb993bc95fa040cf66aeb79da3232a9e92 Releases: 7-0, master Reviewed-on: https://review.typo3.org/48943 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau (cherry picked from commit 18dc773247742d2d9b521a18888a9394ce79c237) Reviewed-on: https://review.typo3.org/48944 --- Classes/Xclass/DatabaseRecordList.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Classes/Xclass/DatabaseRecordList.php b/Classes/Xclass/DatabaseRecordList.php index e245ca5..aa0982d 100644 --- a/Classes/Xclass/DatabaseRecordList.php +++ b/Classes/Xclass/DatabaseRecordList.php @@ -21,7 +21,9 @@ use TYPO3\CMS\Backend\Template\ModuleTemplate; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Backend\View\BackendLayoutView; +use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; use TYPO3\CMS\Core\Database\DatabaseConnection; +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 +31,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; @@ -1817,7 +1820,7 @@ public function renderListRow($table, $row, $cc, $titleCol, $thumbsCol, $indent } elseif ($fCol == '_REF_') { $theData[$fCol] = $this->createReferenceHtml($table, $row['uid']); } elseif ($fCol == '_CONTROL_') { - $theData[$fCol] = $this->makeControl($table, $row, $level); + $theData[$fCol] = $this->makeControl($table, $row); } elseif ($fCol == '_CLIPBOARD_') { $theData[$fCol] = $this->makeClip($table, $row); } elseif ($fCol == '_LOCALIZATION_') { @@ -2100,10 +2103,11 @@ public function addElement($h, $icon, $data, $rowParams = '', $_ = '', $_2 = '', */ public function pasteUrl($table, $uid, $setRedirect = true, array $update = null) { + $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) : '') . BackendUtility::getUrlToken('tceAction'); + $update) : '') . '&formToken=' . $formProtection->generateToken('tceAction'); } /** @@ -2612,7 +2616,7 @@ protected function getDocumentTemplate() } /** - * @return DocumentTemplate + * @return \int[] */ public function getExpandedGridelements() { From 340cdb50bd5ee9dd10f1af8fc49b74c9d4de77ef Mon Sep 17 00:00:00 2001 From: Markus Klein Date: Tue, 12 Jul 2016 19:11:08 +0200 Subject: [PATCH 004/102] [CLEANUP] Add missing use statements for phpdoc in DrawItem Also remove unused variable. Change-Id: I11ef43eb89c2ab4e1ea57bee3b4cb0f021f2f16b Releases: 7-0, master Reviewed-on: https://review.typo3.org/48936 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau (cherry picked from commit 53b4c7997bf0505b684bf9f5ced6d2f0c7efe361) Reviewed-on: https://review.typo3.org/48946 --- Classes/Hooks/DrawItem.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Classes/Hooks/DrawItem.php b/Classes/Hooks/DrawItem.php index bf3710c..ffb452a 100644 --- a/Classes/Hooks/DrawItem.php +++ b/Classes/Hooks/DrawItem.php @@ -21,9 +21,11 @@ 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\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; @@ -522,7 +524,6 @@ protected function renderSingleGridColumn(
' . $this->renderSingleElementHTML($parentObject, $itemRow) . '
'; - $url = ''; if ($this->getPageLayoutController()->pageIsNotLockedForEditors() && $this->getBackendUser()->doesUserHaveAccess($pageinfo, Permission::CONTENT_EDIT) && (!$this->checkIfTranslationsExistInLanguage($items, $row['sys_language_uid'], $parentObject)) From d3e39587433554403dbafb648feb1e0f08c04f04 Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Wed, 13 Jul 2016 10:43:43 +0200 Subject: [PATCH 005/102] Revert "[BUGFIX] Fix composer.json for CMS 8" This reverts commit 87ffc6fa69ce20129d93aabda2e293a82cdfc4c7. Change-Id: I6b71bf545d6a8f530c5339d3108f9aff1af6726a Reviewed-on: https://review.typo3.org/48954 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- composer.json | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index d8a7d0e..ec5b625 100644 --- a/composer.json +++ b/composer.json @@ -5,19 +5,21 @@ "keywords": ["TYPO3 CMS", "Grids", "Gridelements"], "homepage": "https://git.typo3.org/TYPO3CMS/Extensions/gridelements.git", "license": "GPL-2.0+", + "version": "7.0.5", "support": { "issues": "https://forge.typo3.org/" }, "require": { - "typo3/cms-core": "~8.0" - }, - "replace": { - "gridelements": "*", - "typo3-ter/gridelements": "*" + "typo3/cms-core": ">=7.6.2,<8.0" }, "autoload": { "psr-4": { "GridElementsTeam\\Gridelements\\": "Classes/" } + }, + "extra": { + "branch-alias": { + "dev-master": "7.0.5" + } } } \ No newline at end of file From 93aed80e09554b2346e7edb043ff6e791660603b Mon Sep 17 00:00:00 2001 From: Markus Klein Date: Fri, 5 Aug 2016 16:46:31 +0200 Subject: [PATCH 006/102] [CLEANUP] Streamline code in DataHandler code Change-Id: Idd9af1aa5be9ef8c352a166faa5ba72cc5739bee Releases: master, 7 Reviewed-on: https://review.typo3.org/49398 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/DataHandler/AbstractDataHandler.php | 101 ++++++++---------- .../DataHandler/AfterDatabaseOperations.php | 61 +++++------ Classes/DataHandler/PreProcessFieldArray.php | 43 ++++---- Classes/DataHandler/ProcessCmdmap.php | 41 ++++--- 4 files changed, 114 insertions(+), 132 deletions(-) diff --git a/Classes/DataHandler/AbstractDataHandler.php b/Classes/DataHandler/AbstractDataHandler.php index bddbde0..a3047b2 100644 --- a/Classes/DataHandler/AbstractDataHandler.php +++ b/Classes/DataHandler/AbstractDataHandler.php @@ -21,7 +21,6 @@ use GridElementsTeam\Gridelements\Backend\LayoutSetup; use GridElementsTeam\Gridelements\Helper\Helper; -use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Database\DatabaseConnection; use TYPO3\CMS\Core\DataHandling\DataHandler; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -35,9 +34,14 @@ */ abstract class AbstractDataHandler { - + /** + * @var string + */ protected $table; + /** + * @var int + */ protected $pageUid; /** @@ -59,8 +63,6 @@ abstract class AbstractDataHandler * inject layout setup * * @param LayoutSetup $layoutSetup - * - * @return void */ public function injectLayoutSetup(LayoutSetup $layoutSetup) { @@ -73,8 +75,6 @@ public function injectLayoutSetup(LayoutSetup $layoutSetup) * @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 DataHandler $dataHandler - * - * @return void */ public function init($table, $pageUid, DataHandler $dataHandler) { @@ -94,8 +94,6 @@ public function init($table, $pageUid, DataHandler $dataHandler) * setter for table * * @param string $table - * - * @return void */ public function setTable($table) { @@ -116,8 +114,6 @@ public function getTable() * setter for pageUid * * @param integer $pageUid - * - * @return void */ public function setPageUid($pageUid) { @@ -138,8 +134,6 @@ public function getPageUid() * setter for dataHandler object * * @param DataHandler $dataHandler - * - * @return void */ public function setTceMain(DataHandler $dataHandler) { @@ -160,8 +154,6 @@ public function getTceMain() * setter for databaseConnection object * * @param DatabaseConnection $databaseConnection - * - * @return void */ public function setDatabaseConnection(DatabaseConnection $databaseConnection) { @@ -182,8 +174,6 @@ public function getDatabaseConnection() * Function to handle record actions between different grid containers * * @param array $containerUpdateArray - * - * @return void */ public function doGridContainerUpdate($containerUpdateArray = array()) { @@ -205,48 +195,49 @@ public function doGridContainerUpdate($containerUpdateArray = array()) */ public function checkAndUpdateTranslatedElements($uid) { - if ($uid > 0) { - $translatedElements = $this->databaseConnection->exec_SELECTgetRows( - 'uid,tx_gridelements_container,tx_gridelements_columns,sys_language_uid,colPos,l18n_parent', - 'tt_content', 'l18n_parent=' . (int)$uid , '', '', '', 'uid' + if ($uid <= 0) { + return; + } + $translatedElements = $this->databaseConnection->exec_SELECTgetRows( + 'uid,tx_gridelements_container,tx_gridelements_columns,sys_language_uid,colPos,l18n_parent', + 'tt_content', 'l18n_parent=' . (int)$uid , '', '', '', 'uid' + ); + if (empty($translatedElements)) { + return; + } + $currentValues = $this->databaseConnection->exec_SELECTgetSingleRow( + 'tx_gridelements_container,tx_gridelements_columns,colPos', + 'tt_content', 'uid=' . (int)$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' ); - if (empty($translatedElements)) { - return; - } - $currentValues = $this->databaseConnection->exec_SELECTgetSingleRow( - 'tx_gridelements_container,tx_gridelements_columns,colPos', - 'tt_content', 'uid=' . (int)$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 ($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']); - } - } - if (!empty($containerUpdateArray)) { - $this->doGridContainerUpdate($containerUpdateArray); + + 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); + } } } diff --git a/Classes/DataHandler/AfterDatabaseOperations.php b/Classes/DataHandler/AfterDatabaseOperations.php index f065845..193fb7e 100644 --- a/Classes/DataHandler/AfterDatabaseOperations.php +++ b/Classes/DataHandler/AfterDatabaseOperations.php @@ -20,6 +20,8 @@ ***************************************************************/ use TYPO3\CMS\Backend\Utility\BackendUtility; +use TYPO3\CMS\Backend\View\BackendLayoutView; +use TYPO3\CMS\Core\DataHandling\DataHandler; use TYPO3\CMS\Core\Utility\GeneralUtility; /** @@ -31,7 +33,6 @@ */ class AfterDatabaseOperations extends AbstractDataHandler { - /** * Function to set the colPos of an element depending on * whether it is a child of a parent container or not @@ -41,14 +42,12 @@ class AfterDatabaseOperations extends AbstractDataHandler * -2 = non used elements column * changes are applied to the field array of the parent object by reference * - * @param array $fieldArray : The array of fields and values that have been saved to the datamap - * @param string $table : The name of the table the data should be saved to - * @param integer $uid : the ID of the record - * @param \TYPO3\CMS\Core\DataHandling\DataHandler $parentObj : The parent object that triggered this hook - * - * @return void + * @param array $fieldArray The array of fields and values that have been saved to the datamap + * @param string $table The name of the table the data should be saved to + * @param int $uid the ID of the record + * @param DataHandler $parentObj The parent object that triggered this hook */ - public function execute_afterDatabaseOperations(&$fieldArray, $table, $uid, &$parentObj) + public function execute_afterDatabaseOperations(array &$fieldArray, $table, $uid, DataHandler $parentObj) { if ($table === 'tt_content') { $this->init($table, $uid, $parentObj); @@ -65,13 +64,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,10 +79,9 @@ 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(); @@ -223,8 +222,7 @@ public function setUnusedElements(&$fieldArray) $subPageElementsInAvailableColumns = array(); } - $changedPageElements = array_merge($subPageElementsInUnavailableColumns, - $subPageElementsInAvailableColumns); + $changedPageElements = array_merge($subPageElementsInUnavailableColumns, $subPageElementsInAvailableColumns); $changedSubPageElements = array_merge($changedSubPageElements, $changedPageElements); } } @@ -242,16 +240,16 @@ 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 + * @param int $pageUid + * @param array $subpages */ - public function getSubpagesRecursively($pageUid, &$subpages) + public function getSubpagesRecursively($pageUid, array &$subpages) { - $childPages = $this->databaseConnection->exec_SELECTgetRows('uid, backend_layout, backend_layout_next_level', - 'pages', 'pid = ' . (int)$pageUid); + $childPages = $this->databaseConnection->exec_SELECTgetRows( + 'uid, backend_layout, backend_layout_next_level', + 'pages', + 'pid = ' . (int)$pageUid + ); if (!empty($childPages)) { foreach ($childPages as $page) { @@ -268,11 +266,11 @@ public function getSubpagesRecursively($pageUid, &$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) { @@ -281,8 +279,8 @@ public function getAvailableColumns($layout = '', $table = '', $id = 0) 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', + } elseif ($table === 'pages') { + $tcaColumns = GeneralUtility::callUserFunction(BackendLayoutView::class . '->getColPosListItemsParsed', $id, $this); $temp = array(); foreach ($tcaColumns AS $item) { @@ -296,5 +294,4 @@ public function getAvailableColumns($layout = '', $table = '', $id = 0) return $tcaColumns; } - -} \ No newline at end of file +} diff --git a/Classes/DataHandler/PreProcessFieldArray.php b/Classes/DataHandler/PreProcessFieldArray.php index 8bff2c3..34de0ed 100644 --- a/Classes/DataHandler/PreProcessFieldArray.php +++ b/Classes/DataHandler/PreProcessFieldArray.php @@ -22,7 +22,7 @@ use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; use TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools; -use TYPO3\CMS\Core\Utility\ArrayUtility; +use TYPO3\CMS\Core\DataHandling\DataHandler; use TYPO3\CMS\Core\Utility\GeneralUtility; /** @@ -34,9 +34,14 @@ */ class PreProcessFieldArray extends AbstractDataHandler { - + /** + * @var array + */ protected $definitionValues; + /** + * @var array + */ protected $overrideValues; /** @@ -48,14 +53,12 @@ class PreProcessFieldArray extends AbstractDataHandler * -2 = non used elements column * changes are applied to the field array of the parent object by reference * - * @param array $fieldArray : The array of fields and values that have been saved to the datamap - * @param string $table : The name of the table the data should be saved to - * @param integer $id : The parent uid of either the page or the container we are currently working on - * @param \TYPO3\CMS\Core\DataHandling\DataHandler $parentObj : The parent object that triggered this hook - * - * @return void + * @param array $fieldArray The array of fields and values that have been saved to the datamap + * @param string $table The name of the table the data should be saved to + * @param int $id The parent uid of either the page or the container we are currently working on + * @param DataHandler $parentObj The parent object that triggered this hook */ - public function execute_preProcessFieldArray(&$fieldArray, $table, $id, &$parentObj) + public function execute_preProcessFieldArray(array &$fieldArray, $table, $id, DataHandler $parentObj) { if ($table === 'tt_content') { $this->init($table, $id, $parentObj); @@ -89,11 +92,8 @@ 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: @@ -169,16 +169,13 @@ public function setDefaultFieldValues(&$fieldArray, $pid = 0) * 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,7 +187,6 @@ public function getDefaultFlexformValues(&$fieldArray) * * @return string $defaultData */ - public function extractDefaultDataFromDataStructure($dataStructure) { $returnXML = ''; @@ -277,7 +273,7 @@ public function setFieldEntriesForGridContainers(array &$fieldArray) $fieldArray['sys_language_uid'] = (int)$targetContainer['sys_language_uid']; } } - if ((int)$targetContainer['sys_language_uid'] === -1) { + 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 +285,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 { diff --git a/Classes/DataHandler/ProcessCmdmap.php b/Classes/DataHandler/ProcessCmdmap.php index e28037b..7163e18 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'); @@ -96,6 +94,5 @@ public function execute_processCmdmap( $containerUpdateArray[$originalContainer['tx_gridelements_container']] = -1; $this->doGridContainerUpdate($containerUpdateArray); } - } } \ No newline at end of file From 803b68beb7edb808d79af0991be13f1a780197ba Mon Sep 17 00:00:00 2001 From: Markus Klein Date: Fri, 5 Aug 2016 19:37:18 +0200 Subject: [PATCH 007/102] [CLEANUP] Backend Change-Id: I910a15280a57b3f558e1955bb0d7506ac833fbc1 Releases: master, 7 Reviewed-on: https://review.typo3.org/49401 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau (cherry picked from commit 8924a89ade0de97a38db44080ff706c22501bcfa) Reviewed-on: https://review.typo3.org/49462 --- Classes/Backend/ClickMenuOptions.php | 78 ++++--- .../ItemsProcFuncs/AbstractItemsProcFunc.php | 22 +- Classes/Backend/ItemsProcFuncs/CTypeList.php | 68 +++---- Classes/Backend/ItemsProcFuncs/ColPosList.php | 33 ++- .../ItemsProcFuncs/SysLanguageUidList.php | 36 ++-- Classes/Backend/LayoutSetup.php | 191 +++++++++--------- Classes/Backend/TtContent.php | 67 +++--- 7 files changed, 227 insertions(+), 268 deletions(-) diff --git a/Classes/Backend/ClickMenuOptions.php b/Classes/Backend/ClickMenuOptions.php index fabf61a..3681177 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,17 +89,17 @@ 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( @@ -115,22 +109,29 @@ public function DB_paste(&$backRef, $table, $uid, $type, $elInfo, $targetItem, $ ); $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..fcda9e1 100644 --- a/Classes/Backend/ItemsProcFuncs/AbstractItemsProcFunc.php +++ b/Classes/Backend/ItemsProcFuncs/AbstractItemsProcFunc.php @@ -21,6 +21,7 @@ ***************************************************************/ use TYPO3\CMS\Backend\Utility\BackendUtility; +use TYPO3\CMS\Backend\View\BackendLayoutView; use TYPO3\CMS\Core\Database\DatabaseConnection; use TYPO3\CMS\Core\Database\QueryGenerator; use TYPO3\CMS\Core\SingletonInterface; @@ -36,7 +37,6 @@ */ abstract class AbstractItemsProcFunc implements SingletonInterface { - /** * @var DatabaseConnection */ @@ -52,11 +52,6 @@ abstract class AbstractItemsProcFunc implements SingletonInterface */ protected $tree; - /** - * @var string - */ - protected $backPath = ''; - /** * initializes this class * @@ -71,22 +66,23 @@ 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); + $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 (count($backendLayoutData['__items']) > 0) { + 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']]; + $backendLayoutData['columns']['allowed'] .= $backendLayoutData['columns']['allowed'] + ? ',' . $backendLayoutData['columns'][$column['colPos']] + : $backendLayoutData['columns'][$column['colPos']]; } } } @@ -102,7 +98,7 @@ public function 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..fdcb205 100644 --- a/Classes/Backend/ItemsProcFuncs/CTypeList.php +++ b/Classes/Backend/ItemsProcFuncs/CTypeList.php @@ -21,6 +21,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 +47,7 @@ class CTypeList extends AbstractItemsProcFunc /** * injects layout setup * - * @param \GridElementsTeam\Gridelements\Backend\LayoutSetup $layoutSetup + * @param LayoutSetup $layoutSetup */ public function injectLayoutSetup(LayoutSetup $layoutSetup) { @@ -54,26 +55,37 @@ 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) { + if ($pageUid < 0) { + $pageUid = Helper::getInstance()->getPidFromNegativeUid($pageUid); + } + $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,15 +93,13 @@ 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; @@ -102,28 +112,10 @@ public function checkForAllowedCTypes(&$items, $pid, $pageColumn, $gridContainer } 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..6483f46 100644 --- a/Classes/Backend/LayoutSetup.php +++ b/Classes/Backend/LayoutSetup.php @@ -36,7 +36,6 @@ */ class LayoutSetup { - /** * @var DatabaseConnection */ @@ -65,12 +64,12 @@ 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']); @@ -93,7 +92,7 @@ public function init($pageId, $typoScriptSetup = array()) * * @param array $layoutSetup */ - public function setLayoutSetup($layoutSetup) + public function setLayoutSetup(array $layoutSetup) { $this->layoutSetup = $layoutSetup; } @@ -103,15 +102,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 +119,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 +138,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 +181,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 +200,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'] .= $availableColumns['allowedGridTypes'] + ? ',' . $availableGridColumns[$colPos] + : $availableGridColumns[$colPos]; } } } @@ -247,7 +246,7 @@ 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. * * @return array */ @@ -278,7 +277,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 +285,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,7 +309,7 @@ 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 @@ -316,7 +317,7 @@ public function getLayoutColumnsSelectItems($layoutId) * * @return array */ - public function getLayoutWizardItems($colPos, $excludeLayouts = array(), $allowedGridTypes = array()) + public function getLayoutWizardItems($colPos, array $excludeLayouts = array(), array $allowedGridTypes = array()) { $wizardItems = array(); $excludeLayouts = array_flip(explode(',', $excludeLayouts)); @@ -324,7 +325,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 +344,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 +355,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 +422,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(); @@ -484,8 +485,6 @@ protected function loadLayoutSetup($pageId) * setter for databaseConnection object * * @param DatabaseConnection $databaseConnection - * - * @return void */ public function setDatabaseConnection(DatabaseConnection $databaseConnection) { @@ -505,11 +504,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()) { diff --git a/Classes/Backend/TtContent.php b/Classes/Backend/TtContent.php index b1a9bed..4520077 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,9 +56,7 @@ public function injectLayoutSetup(LayoutSetup $layoutSetup) /** * initializes this class * - * @param integer $pageUid - * - * @return void + * @param int $pageUid */ public function init($pageUid) { @@ -77,14 +72,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 +88,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,11 +103,9 @@ 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']); $this->removesItemsFromListOfSelectableContainers($params, $possibleContainers); @@ -139,11 +132,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 +155,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 +163,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,11 +186,9 @@ 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']); @@ -211,17 +202,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 +236,6 @@ public function lookForChildContainersRecursively($containerIds, &$possibleConta * setter for databaseConnection object * * @param DatabaseConnection $databaseConnection - * - * @return void */ public function setDatabaseConnection(DatabaseConnection $databaseConnection) { @@ -261,5 +251,4 @@ public function getDatabaseConnection() { return $this->databaseConnection; } - } From 18ab54156bf567f2d416f7bd3d0244db05be718d Mon Sep 17 00:00:00 2001 From: Markus Klein Date: Fri, 5 Aug 2016 18:28:58 +0200 Subject: [PATCH 008/102] [CLEANUP] Plugin, Wizard and Xclass Change-Id: Ic4d81757d1de1c32a83ffda0d04f006e6e3952f9 Releases: master, 7 Reviewed-on: https://review.typo3.org/49399 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau (cherry picked from commit eb689c6bdea9e6919c7eac069cc06cf8e8dca0f9) Reviewed-on: https://review.typo3.org/49460 --- Classes/Plugin/Gridelements.php | 331 ++++--- .../Wizard/BackendLayoutWizardController.php | 17 +- Classes/Xclass/DatabaseRecordList.php | 804 +++++++++--------- 3 files changed, 568 insertions(+), 584 deletions(-) diff --git a/Classes/Plugin/Gridelements.php b/Classes/Plugin/Gridelements.php index e207915..4f2e83a 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,7 +87,7 @@ 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']; @@ -118,96 +135,88 @@ 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 string $csvColumns A list of available column IDs */ public function getChildren($element = 0, $csvColumns = '') { + if (!$element || $csvColumns === '') { + return; + } + $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) + )'; + + 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 ($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) - )'; - - 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 sys_language_uid IN (-1,' . $this->getTSFE()->sys_language_content . ') + AND l18n_parent = 0 + )'; + } + } else { + if ($element) { + $where .= ' OR ( + tx_gridelements_container = ' . (int)$element . $this->cObj->enableFields('tt_content') . ' 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 +245,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 +260,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 +280,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 +297,6 @@ public function renderChildrenIntoParentColumns($typoScriptSetup = array(), $sor } unset($parentGridData); unset($currentParentGrid); - } /** @@ -296,16 +307,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 +321,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 +335,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 +362,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 +372,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 +395,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 +456,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 +499,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 +516,6 @@ public function getFlexFormValue( */ public function getFlexFormValueFromSheetArray($sheetArray, $fieldNameArr, $value) { - $tempArr = $sheetArray; foreach ($fieldNameArr as $k => $v) { $checkedValue = MathUtility::canBeInterpretedAsInteger($v); @@ -596,16 +561,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 +593,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/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 aa0982d..53c639e 100644 --- a/Classes/Xclass/DatabaseRecordList.php +++ b/Classes/Xclass/DatabaseRecordList.php @@ -14,15 +14,12 @@ * 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\Authentication\BackendUserAuthentication; -use TYPO3\CMS\Core\Database\DatabaseConnection; use TYPO3\CMS\Core\FormProtection\FormProtectionFactory; use TYPO3\CMS\Core\Imaging\Icon; use TYPO3\CMS\Core\Imaging\IconFactory; @@ -40,7 +37,6 @@ */ class DatabaseRecordList extends \TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList { - /** * @var int */ @@ -312,17 +308,17 @@ public function getButtons() 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 @@ -330,53 +326,55 @@ 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() . ''; + $onClick = htmlspecialchars(('return ' . $this->clipObj->confirmMsg('pages', $this->pageRow, 'into', $elFromTable))); + $buttons['paste'] = '' + . $this->iconFactory->getIcon('actions-document-paste-after', 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() . ''; + $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() . ''; } } @@ -424,12 +422,16 @@ public function getDocHeaderButtons(ModuleTemplate $moduleTemplate) 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 @@ -438,7 +440,9 @@ 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 @@ -453,21 +457,33 @@ public function getDocHeaderButtons(ModuleTemplate $moduleTemplate) } } // 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)); + $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()) { @@ -488,8 +504,9 @@ 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) . ''; + $buttons['back'] = '' + . $this->iconFactory->getIcon('actions-view-go-back', Icon::SIZE_SMALL) . ''; } } } @@ -524,12 +541,14 @@ 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(); // title Column @@ -636,8 +655,10 @@ 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( + '$hookObject must implement interface ' . RecordListGetTableHookInterface::class, + 1195114460 + ); } $hookObject->getDBlistQuery($table, $id, $addWhere, $this->selFieldList, $this); } @@ -697,16 +718,18 @@ public function getTable($table, $id, $rowList = '') // Header line is drawn $theData = array(); 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]); @@ -715,11 +738,17 @@ 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; } @@ -812,17 +841,16 @@ public function getTable($table, $id, $rowList = '')
- ' . $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']) . ' '; } 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]) + && $row['colPos'] != $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 @@ -838,11 +866,18 @@ 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 .= ' - ' . ' [1 - ' . $countOnFirstPage . ($hasMore ? '+' : '') . '] + ' + . ' [1 - ' + . $countOnFirstPage . ($hasMore ? '+' : '') . '] '; } } @@ -914,8 +949,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; } @@ -943,22 +977,19 @@ public function renderListHeader($table, $currentIdList) // 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 @@ -975,14 +1006,13 @@ public function renderListHeader($table, $currentIdList) $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() . ''; + $onClick = htmlspecialchars('return ' . $this->clipObj->confirmMsg('pages', $this->pageRow, 'into', $elFromTable)); + $cells['pasteAfter'] = '' + . $this->iconFactory->getIcon('actions-document-paste-after', 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')); @@ -995,9 +1025,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(), @@ -1008,8 +1038,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'] = ''; } @@ -1036,9 +1067,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))); @@ -1059,29 +1089,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)); + $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)); $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: @@ -1090,17 +1121,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 @@ -1126,9 +1156,10 @@ 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() . ''; + $theData[$fCol] .= '' + . $this->iconFactory->getIcon('actions-document-duplicates-select', Icon::SIZE_SMALL)->render() . ''; } // If the table can be edited, add link for editing THIS field for all // listed records: @@ -1145,8 +1176,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] . '
'; @@ -1174,8 +1206,8 @@ 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( + '$hookObject must implement interface ' . RecordListHookInterface::class, 1195567855); } $theData = $hookObject->renderListHeader($table, $currentIdList, $theData, $this); } @@ -1183,23 +1215,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 * @@ -1223,34 +1242,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() . '
  • '; - } - $reload = '
  • ' - . $this->iconFactory->getIcon('actions-refresh', 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() . '
  • '; if ($renderPart === 'top') { // Add js to traverse a page select input to a pointer value $content = ' @@ -1270,20 +1286,26 @@ 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( @@ -1331,9 +1353,8 @@ public function makeControl($table, $row) ); // 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) @@ -1342,14 +1363,13 @@ public function makeControl($table, $row) && $this->calcPerms & Permission::CONTENT_EDIT; $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) @@ -1357,27 +1377,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)); + $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; @@ -1388,9 +1408,9 @@ public function makeControl($table, $row) // "Revert" link (history/undo) $moduleUrl = BackendUtility::getModuleUrl('record_history', array('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')) { @@ -1402,36 +1422,35 @@ public function makeControl($table, $row) 'table' => $table, 'uid' => $row['uid'] )); - $versionAction = '' . $this->iconFactory->getIcon('actions-version-open', - Icon::SIZE_SMALL)->render() . ''; + $versionAction = '' + . $this->iconFactory->getIcon('actions-version-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') - ) { + 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() . ''; + $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'); } } @@ -1441,10 +1460,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; } @@ -1453,52 +1472,64 @@ 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 ($permsEdit && $hiddenField && $GLOBALS['TCA'][$table]['columns'][$hiddenField] + && (!$GLOBALS['TCA'][$table]['columns'][$hiddenField]['exclude'] + || $this->getBackendUserAuthentication()->check('non_exclude_fields', $table . ':' . $hiddenField)) ) { if ($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)) { + 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" 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.xlf:labels.translationsOfRecord') + ); } if ($this->isRecordCurrentBackendUser($table, $row)) { @@ -1518,14 +1549,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) @@ -1534,10 +1565,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; } @@ -1576,8 +1607,10 @@ 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( + '$hookObject must implement interface ' . RecordListHookInterface::class, + 1195567840 + ); } $cells = $hookObject->makeControl($table, $row, $cells, $this); } @@ -1599,7 +1632,11 @@ public function makeControl($table, $row) foreach ($actions as $action) { $cellOutput .= $action; } - $output .= '
    ' . '' . $cellOutput . '' . '' . '
    '; + $output .= '
    ' . '' . $cellOutput . '' + . '' . '
    '; } else { $output .= '
    ' . implode('', $actions) . '
    '; } @@ -1626,7 +1663,7 @@ public function makeClip($table, $row) $cells = array(); $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: @@ -1647,7 +1684,7 @@ public function makeClip($table, $row) } $cells['copy'] = '' . $copyIcon->render() . ''; if (true) { @@ -1675,29 +1712,29 @@ 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 @@ -1710,8 +1747,10 @@ 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( + '$hookObject must implement interface ' . RecordListHookInterface::class, + 1195567845 + ); } $cells = $hookObject->makeClip($table, $row, $cells, $this); } @@ -1731,7 +1770,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 @@ -1768,10 +1807,9 @@ 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(); $localizationMarkerClass = ''; @@ -1783,11 +1821,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 @@ -1804,39 +1842,41 @@ 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); } - 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_') { + } elseif ($fCol === '_CONTROL_') { $theData[$fCol] = $this->makeControl($table, $row); - } elseif ($fCol == '_CLIPBOARD_') { + } 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 @@ -1874,7 +1914,10 @@ public function renderListRow($table, $row, $cc, $titleCol, $thumbsCol, $indent if ($table === 'tt_content') { $theData['tx_gridelements_container'] = $row['tx_gridelements_container']; } - if (isset($GLOBALS['TCA'][$table]['ctrl']['languageField']) && isset($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) && !isset($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable'])) { + 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']]; } $rowOutput .= $this->addElement(1, $theIcon, $theData, $row_bgColor, '', '', '', $level); @@ -1886,7 +1929,8 @@ public function renderListRow($table, $row, $cc, $titleCol, $thumbsCol, $indent // $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; } @@ -1903,55 +1947,53 @@ 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;' : ''; + $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']; } - 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 .= ' - - -
    - ' . $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']) . ' - - '; - } 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); + } + 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 .= ' + + +
    + ' . $this->getLanguageService()->sL('LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:list.columnName') + . ' ' . (int)$child['tx_gridelements_columns'] . ' + + '; + } else { + $this->showMoveUp = true; } - $this->showMoveUp = $originalMoveUp; - $this->showMoveDown = $originalMoveDown; + $this->showMoveDown = !isset($child['tx_gridelements_columns']) || !isset($theData['_CHILDREN_'][$key + 1]) + || $child['tx_gridelements_columns'] == $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: @@ -1962,12 +2004,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 * @param string $rowParams Is insert in the -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 * @@ -1981,7 +2023,8 @@ public function addElement($h, $icon, $data, $rowParams = '', $_ = '', $_2 = '', $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 . '>'; @@ -2053,7 +2096,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; @@ -2079,7 +2123,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 .= ' @@ -2104,10 +2149,12 @@ public function addElement($h, $icon, $data, $rowParams = '', $_ = '', $_2 = '', public function pasteUrl($table, $uid, $setRedirect = true, array $update = null) { $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'); + 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'); } /** @@ -2144,8 +2191,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)); } @@ -2176,10 +2227,14 @@ public function makeLocalizationPanel($table, $row) // 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'], @@ -2242,9 +2297,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[] = 'fieldArray[0] ? ' disabled="disabled"' : '') . '>' . ''; + $fieldLabel = is_array($GLOBALS['TCA'][$table]['columns'][$fieldName]) + ? rtrim($lang->sL($GLOBALS['TCA'][$table]['columns'][$fieldName]['label']), ':') + : ''; + $checkboxes[] = 'fieldArray[0] ? ' disabled="disabled"' : '') + . '>' . ''; } // Table with the field selector:: $content = $formElements[0] . ' @@ -2287,15 +2348,17 @@ public function fieldSelectBox($table, $formFields = true) */ 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();'; + $onClickEvent = 'document.dblistForm.cmd.value=' . GeneralUtility::quoteJSvalue($cmd) + . ';document.dblistForm.cmd_table.value=' . GeneralUtility::quoteJSvalue($table) + . ';document.dblistForm.submit();'; if ($warning) { $onClickEvent = 'if (confirm(' . GeneralUtility::quoteJSvalue($warning) . ')){' . $onClickEvent . '}'; } if ($title !== '') { $title = 'title="' . htmlspecialchars($title) . '" '; } - return '' . $string . ''; + return '' . $string . ''; } /** @@ -2305,7 +2368,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'; } /** @@ -2322,18 +2385,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 . ''; @@ -2372,8 +2436,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)); } /** @@ -2580,41 +2644,6 @@ protected function overlayEditLockPermissions($table, $row = array(), $editPermi return $editPermission; } - /** - * 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 \int[] */ @@ -2630,5 +2659,4 @@ protected function getBackendLayoutView() { return GeneralUtility::makeInstance(BackendLayoutView::class); } - } From 39dc564e74c8cc186de149a06dee3ff469cfd2e5 Mon Sep 17 00:00:00 2001 From: Markus Klein Date: Fri, 5 Aug 2016 18:57:56 +0200 Subject: [PATCH 009/102] [CLEANUP] Helper and Hooks Change-Id: I6aa92c7ecc1731b41379bb5355eeaa21c6a341a7 Releases: master, 7 Reviewed-on: https://review.typo3.org/49400 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau (cherry picked from commit 4679430490051af06d0facd7a412aaac57615548) Reviewed-on: https://review.typo3.org/49461 --- Classes/Helper/Helper.php | 61 ++--- Classes/Hooks/AbstractDatabaseRecordList.php | 11 +- Classes/Hooks/BackendUtilityGridelements.php | 14 +- Classes/Hooks/DataHandler.php | 28 +- Classes/Hooks/DatabaseRecordList.php | 63 ++--- Classes/Hooks/PageRenderer.php | 41 ++- Classes/Hooks/PreHeaderRenderHook.php | 7 +- Classes/Hooks/WizardItems.php | 260 +++++++++---------- 8 files changed, 211 insertions(+), 274 deletions(-) diff --git a/Classes/Helper/Helper.php b/Classes/Helper/Helper.php index 58efd4e..daab0c7 100644 --- a/Classes/Helper/Helper.php +++ b/Classes/Helper/Helper.php @@ -21,7 +21,6 @@ use TYPO3\CMS\Core\Database\DatabaseConnection; use TYPO3\CMS\Core\SingletonInterface; -use TYPO3\CMS\Core\Utility\DebugUtility; /** * Gridelements helper class @@ -32,12 +31,6 @@ */ class Helper implements SingletonInterface { - - /** - * @var DatabaseConnection - */ - protected static $databaseConnection; - /** * Local instance of the helper * @@ -45,18 +38,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,12 +62,10 @@ 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; } /** @@ -87,9 +82,7 @@ public function getChildren($table = '', $uid = 0, $sortingField = '', $sortRev $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 deleted = 0', ''); foreach ($children as $child) { if (trim($sortingField) && isset($child[$sortingField]) && $sortingField !== 'sorting') { @@ -97,8 +90,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; } @@ -123,22 +115,10 @@ public function getPidFromNegativeUid($negativeUid = 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($negativeUid)); + $pid = (int)$triggerElement['pid']; + return is_array($triggerElement) && $pid ? $pid : 0; } /** @@ -148,7 +128,7 @@ public function getDatabaseConnection() * * @param array $record Overlaid record data * - * @return integer + * @return int[] */ public function getSpecificIds(array $record) { @@ -164,6 +144,16 @@ public function getSpecificIds(array $record) return $specificIds; } + /** + * getter for databaseConnection + * + * @return DatabaseConnection databaseConnection + */ + public function getDatabaseConnection() + { + return $this->databaseConnection; + } + /** * Gets the current backend user. * @@ -173,5 +163,4 @@ public function getBackendUser() { return $GLOBALS['BE_USER']; } - } diff --git a/Classes/Hooks/AbstractDatabaseRecordList.php b/Classes/Hooks/AbstractDatabaseRecordList.php index f0ba78e..6e76b44 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 DatabaseRecordList $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, DatabaseRecordList $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..21698b9 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,9 +58,7 @@ public function injectLayoutSetup(LayoutSetup $layoutSetup) /** * initializes this class * - * @param integer $pageUid - * - * @return void + * @param int $pageUid */ public function init($pageUid) { @@ -85,10 +80,8 @@ public function init($pageUid) * @param array $row * @param string $table * @param string $fieldName - * - * @return void */ - public function getFlexFormDS_postProcessDS(&$dataStructureArray, $conf, $row, $table, $fieldName) + public function getFlexFormDS_postProcessDS(array &$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 +110,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..64cad9b 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 */ @@ -92,7 +91,7 @@ public function processDatamap_afterDatabaseOperations( \TYPO3\CMS\Core\DataHandling\DataHandler $parentObj ) { if (($table === 'tt_content' || $table === 'pages') && $status === 'update' && !$parentObj->isImporting) { - /** @var $hook AfterDatabaseOperations */ + /** @var AfterDatabaseOperations $hook */ $hook = GeneralUtility::makeInstance(AfterDatabaseOperations::class); $hook->execute_afterDatabaseOperations($fieldArray, $table, $id, $parentObj); } @@ -101,15 +100,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 +117,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 +128,6 @@ public function processCmdmap( * setter for databaseConnection object * * @param DatabaseConnection $databaseConnection - * - * @return void */ public function setDatabaseConnection(DatabaseConnection $databaseConnection) { @@ -148,5 +143,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..80f3f97 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,9 +127,9 @@ 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); @@ -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/PageRenderer.php b/Classes/Hooks/PageRenderer.php index aca2fd9..08f5742 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,20 @@ */ 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 (get_class($GLOBALS['SOBE']) === RecordList::class) { $pageRenderer->loadRequireJsModule('TYPO3/CMS/Gridelements/GridElementsOnReady'); return; } - if (get_class($GLOBALS['SOBE']) === 'TYPO3\CMS\Backend\Controller\PageLayoutController') { + if (get_class($GLOBALS['SOBE']) === PageLayoutController::class) { $iconFactory = GeneralUtility::makeInstance(IconFactory::class); $pageRenderer->loadRequireJsModule('TYPO3/CMS/Gridelements/GridElementsOnReady'); $pageRenderer->loadRequireJsModule('TYPO3/CMS/Gridelements/GridElementsDragDrop'); @@ -68,8 +68,7 @@ public function addJSCSS($parameters, &$pageRenderer) } // 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,10 @@ public function addJSCSS($parameters, &$pageRenderer) $allowedContentTypesClassesByColPos = array(); $allowedGridTypesClassesByColPos = array(); - $layoutSetup = GeneralUtility::callUserFunction('TYPO3\\CMS\\Backend\\View\\BackendLayoutView->getSelectedBackendLayout', - intval(GeneralUtility::_GP('id')), $this); + $params = [ + 'id' => (int)GeneralUtility::_GP('id') + ]; + $layoutSetup = GeneralUtility::callUserFunction(BackendLayoutView::class . '->getSelectedBackendLayout', $params, $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 +139,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,10 +151,8 @@ 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.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;"; @@ -167,11 +165,9 @@ public function addJSCSS($parameters, &$pageRenderer) } $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 +190,4 @@ public function getLanguageService() { return $GLOBALS['LANG']; } - } diff --git a/Classes/Hooks/PreHeaderRenderHook.php b/Classes/Hooks/PreHeaderRenderHook.php index 73fa500..3cf4aa1 100644 --- a/Classes/Hooks/PreHeaderRenderHook.php +++ b/Classes/Hooks/PreHeaderRenderHook.php @@ -29,14 +29,13 @@ */ class PreHeaderRenderHook implements SingletonInterface { - /** * @param array $arg */ - function main($arg) + function main(array $arg) { - /** @var $pagerenderer \TYPO3\CMS\Core\Page\PageRenderer */ + /** @var \TYPO3\CMS\Core\Page\PageRenderer $pagerenderer */ $pagerenderer = $arg['pageRenderer']; - $pagerenderer->addCssFile($GLOBALS['BACK_PATH'] . ExtensionManagementUtility::extRelPath('gridelements') . 'Resources/Public/Backend/Css/Skin/t3skin_override.css'); + $pagerenderer->addCssFile(ExtensionManagementUtility::extRelPath('gridelements') . 'Resources/Public/Backend/Css/Skin/t3skin_override.css'); } } diff --git a/Classes/Hooks/WizardItems.php b/Classes/Hooks/WizardItems.php index ace61ac..4f39748 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 */ @@ -75,57 +75,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 +141,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 +158,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 +200,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($icon)) { + 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'] + ), + ); + $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); } - $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']; + 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,12 +305,10 @@ 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']) { From fce4d9fcf7494cea3ede3af334ada16c4c303448 Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Fri, 12 Aug 2016 13:42:51 +0200 Subject: [PATCH 010/102] [BUGFIX] Exclude layouts are given as string not as array Change-Id: I0c0adcc2a3541f7dde100297fe161ea8e934779f Reviewed-on: https://review.typo3.org/49463 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Backend/LayoutSetup.php | 4 +-- Classes/DataHandler/PreProcessFieldArray.php | 27 ++++++++++---------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Classes/Backend/LayoutSetup.php b/Classes/Backend/LayoutSetup.php index 6483f46..45f4c8c 100644 --- a/Classes/Backend/LayoutSetup.php +++ b/Classes/Backend/LayoutSetup.php @@ -312,12 +312,12 @@ public function getLayoutColumnsSelectItems($layoutId) * 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, array $excludeLayouts = array(), array $allowedGridTypes = array()) + public function getLayoutWizardItems($colPos, $excludeLayouts = '', array $allowedGridTypes = array()) { $wizardItems = array(); $excludeLayouts = array_flip(explode(',', $excludeLayouts)); diff --git a/Classes/DataHandler/PreProcessFieldArray.php b/Classes/DataHandler/PreProcessFieldArray.php index 34de0ed..a29541c 100644 --- a/Classes/DataHandler/PreProcessFieldArray.php +++ b/Classes/DataHandler/PreProcessFieldArray.php @@ -146,19 +146,20 @@ public function setDefaultFieldValues(array &$fieldArray, $pid = 0) // Fetch default values if a previous record exists if ($pid < 0 && $GLOBALS['TCA']['tt_content']['ctrl']['useColumnsForDefaultValues']) { // Fetches the previous record: - $res = $this->databaseConnection->exec_SELECTquery('*', 'tt_content', - 'uid=' . abs($id) . BackendUtility::deleteClause('tt_content')); - if ($row = $this->databaseConnection->sql_fetch_assoc($res)) { - // Gets the list of fields to copy from the previous record. - $fArr = explode(',', $GLOBALS['TCA']['tt_content']['ctrl']['useColumnsForDefaultValues']); - foreach ($fArr as $theF) { - $theF = trim($theF); - if ($theF === '') { - continue; - } - if (isset($GLOBALS['TCA']['tt_content']['columns'][$theF])) { - $newRow[$theF] = $row[$theF]; - } + + } + $res = $this->databaseConnection->exec_SELECTquery('*', 'tt_content', + 'uid=' . abs($id) . BackendUtility::deleteClause('tt_content')); + if ($row = $this->databaseConnection->sql_fetch_assoc($res)) { + // Gets the list of fields to copy from the previous record. + $fArr = explode(',', $GLOBALS['TCA']['tt_content']['ctrl']['useColumnsForDefaultValues']); + foreach ($fArr as $theF) { + $theF = trim($theF); + if ($theF === '') { + continue; + } + if (isset($GLOBALS['TCA']['tt_content']['columns'][$theF])) { + $newRow[$theF] = $row[$theF]; } } } From f7981e51b096c8cf28acedf16caefd2faed841a7 Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Fri, 12 Aug 2016 13:51:55 +0200 Subject: [PATCH 011/102] [BUGFIX] Empty variable must be defined as array Change-Id: Ic4cdcb19a4121f1ed43453ba6d7e9ceab0ad5168 Reviewed-on: https://review.typo3.org/49465 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Backend/TtContent.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Classes/Backend/TtContent.php b/Classes/Backend/TtContent.php index 4520077..eca8792 100644 --- a/Classes/Backend/TtContent.php +++ b/Classes/Backend/TtContent.php @@ -108,6 +108,7 @@ public function columnsItemsProcFunc(array &$params) public function containerItemsProcFunc(array &$params) { $this->init($params['row']['pid']); + $possibleContainers = array(); $this->removesItemsFromListOfSelectableContainers($params, $possibleContainers); if (!empty($possibleContainers)) { From ac38e953467554b80c803b26a8da4e30e8ef1c3a Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Fri, 12 Aug 2016 13:55:03 +0200 Subject: [PATCH 012/102] [BUGFIX] Moved code back into if clause Change-Id: Ic191c1948cd98695cb9a4fcd96c03d335575b6e1 Reviewed-on: https://review.typo3.org/49467 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/DataHandler/PreProcessFieldArray.php | 27 ++++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/Classes/DataHandler/PreProcessFieldArray.php b/Classes/DataHandler/PreProcessFieldArray.php index a29541c..34de0ed 100644 --- a/Classes/DataHandler/PreProcessFieldArray.php +++ b/Classes/DataHandler/PreProcessFieldArray.php @@ -146,20 +146,19 @@ public function setDefaultFieldValues(array &$fieldArray, $pid = 0) // Fetch default values if a previous record exists if ($pid < 0 && $GLOBALS['TCA']['tt_content']['ctrl']['useColumnsForDefaultValues']) { // Fetches the previous record: - - } - $res = $this->databaseConnection->exec_SELECTquery('*', 'tt_content', - 'uid=' . abs($id) . BackendUtility::deleteClause('tt_content')); - if ($row = $this->databaseConnection->sql_fetch_assoc($res)) { - // Gets the list of fields to copy from the previous record. - $fArr = explode(',', $GLOBALS['TCA']['tt_content']['ctrl']['useColumnsForDefaultValues']); - foreach ($fArr as $theF) { - $theF = trim($theF); - if ($theF === '') { - continue; - } - if (isset($GLOBALS['TCA']['tt_content']['columns'][$theF])) { - $newRow[$theF] = $row[$theF]; + $res = $this->databaseConnection->exec_SELECTquery('*', 'tt_content', + 'uid=' . abs($id) . BackendUtility::deleteClause('tt_content')); + if ($row = $this->databaseConnection->sql_fetch_assoc($res)) { + // Gets the list of fields to copy from the previous record. + $fArr = explode(',', $GLOBALS['TCA']['tt_content']['ctrl']['useColumnsForDefaultValues']); + foreach ($fArr as $theF) { + $theF = trim($theF); + if ($theF === '') { + continue; + } + if (isset($GLOBALS['TCA']['tt_content']['columns'][$theF])) { + $newRow[$theF] = $row[$theF]; + } } } } From 80b6df849cad89b9c46e8d8017b632e76b615476 Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Fri, 12 Aug 2016 19:42:55 +0200 Subject: [PATCH 013/102] [BUGFIX] Second parameter of function call must be int not array Change-Id: I79096c5ada24911f35b19a9bc330653931b7b5a9 Reviewed-on: https://review.typo3.org/49471 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Hooks/PageRenderer.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Classes/Hooks/PageRenderer.php b/Classes/Hooks/PageRenderer.php index 08f5742..d50e91e 100644 --- a/Classes/Hooks/PageRenderer.php +++ b/Classes/Hooks/PageRenderer.php @@ -80,10 +80,8 @@ public function addJSCSS(array $parameters, \TYPO3\CMS\Core\Page\PageRenderer $p $allowedContentTypesClassesByColPos = array(); $allowedGridTypesClassesByColPos = array(); - $params = [ - 'id' => (int)GeneralUtility::_GP('id') - ]; - $layoutSetup = GeneralUtility::callUserFunction(BackendLayoutView::class . '->getSelectedBackendLayout', $params, $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) { From d22f311bd6e11dcf3121d292220a125c1ecfc8c1 Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Sat, 13 Aug 2016 00:35:59 +0200 Subject: [PATCH 014/102] [BUGFIX] Parent can have difference class instances Change-Id: If0c2de2711dc0a7bd0cf1bb8304b72d024718d46 Resolves: #77494 Releases: 7-0 Reviewed-on: https://review.typo3.org/49473 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Hooks/AbstractDatabaseRecordList.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/Hooks/AbstractDatabaseRecordList.php b/Classes/Hooks/AbstractDatabaseRecordList.php index 6e76b44..04e794b 100644 --- a/Classes/Hooks/AbstractDatabaseRecordList.php +++ b/Classes/Hooks/AbstractDatabaseRecordList.php @@ -37,10 +37,10 @@ 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 $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(array &$queryParts, DatabaseRecordList $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'); From 795723c31c52d1635b612d2c910511c74b3192ea Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Mon, 15 Aug 2016 19:32:45 +0200 Subject: [PATCH 015/102] [TASK] Missing change of DatabaseRecordList Change-Id: Ie12512acdeadf84108d886c1b6b0c0383ccd2921 Resolves: #77503 Releases: master, 7-0 Reviewed-on: https://review.typo3.org/49488 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau (cherry picked from commit 22e8df23db735ac9e378f5860901d4c9edf6541a) Reviewed-on: https://review.typo3.org/49489 --- Classes/Xclass/DatabaseRecordList.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Classes/Xclass/DatabaseRecordList.php b/Classes/Xclass/DatabaseRecordList.php index 53c639e..144dc1b 100644 --- a/Classes/Xclass/DatabaseRecordList.php +++ b/Classes/Xclass/DatabaseRecordList.php @@ -2220,7 +2220,12 @@ public function makeLocalizationPanel($table, $row) // 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']; From 20b124a21ce2ddf77a32e419fd40f1f5b48817c7 Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Fri, 19 Aug 2016 17:46:46 +0200 Subject: [PATCH 016/102] [BUGFIX] Correct container information directly while translating children Change-Id: I4f20441291ebcd29ae7d8544147e417aa96f399f Resolves: #77173 Releases: 7-0 Reviewed-on: https://review.typo3.org/49515 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/DataHandler/AbstractDataHandler.php | 18 ++++++++++++------ Classes/Hooks/DataHandler.php | 5 ++++- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/Classes/DataHandler/AbstractDataHandler.php b/Classes/DataHandler/AbstractDataHandler.php index a3047b2..0e65aaa 100644 --- a/Classes/DataHandler/AbstractDataHandler.php +++ b/Classes/DataHandler/AbstractDataHandler.php @@ -198,17 +198,23 @@ public function checkAndUpdateTranslatedElements($uid) if ($uid <= 0) { return; } + $currentValues = $this->databaseConnection->exec_SELECTgetSingleRow( + 'uid,tx_gridelements_container,tx_gridelements_columns,sys_language_uid,colPos,l18n_parent', + 'tt_content', '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', 'uid=' . (int)$currentValues['l18n_parent'] + ); + } $translatedElements = $this->databaseConnection->exec_SELECTgetRows( 'uid,tx_gridelements_container,tx_gridelements_columns,sys_language_uid,colPos,l18n_parent', - 'tt_content', 'l18n_parent=' . (int)$uid , '', '', '', 'uid' + 'tt_content', 'l18n_parent=' . (int)$currentValues['uid'] , '', '', '', 'uid' ); if (empty($translatedElements)) { return; } - $currentValues = $this->databaseConnection->exec_SELECTgetSingleRow( - 'tx_gridelements_container,tx_gridelements_columns,colPos', - 'tt_content', 'uid=' . (int)$uid - ); if ($currentValues['tx_gridelements_container'] > 0) { $translatedContainers = $this->databaseConnection->exec_SELECTgetRows( 'uid,sys_language_uid', @@ -226,7 +232,7 @@ public function checkAndUpdateTranslatedElements($uid) $this->databaseConnection->exec_UPDATEquery('tt_content', 'uid=' . (int)$translatedUid, $updateArray, - 'tx_gridelements_container,tx_gridelements_columns.colPos' + 'tx_gridelements_container,tx_gridelements_columns,colPos' ); if ($translatedElement['tx_gridelements_container'] !== $updateArray['tx_gridelements_container']) { diff --git a/Classes/Hooks/DataHandler.php b/Classes/Hooks/DataHandler.php index 64cad9b..e2dae8e 100644 --- a/Classes/Hooks/DataHandler.php +++ b/Classes/Hooks/DataHandler.php @@ -90,9 +90,12 @@ public function processDatamap_afterDatabaseOperations( &$fieldArray, \TYPO3\CMS\Core\DataHandling\DataHandler $parentObj ) { - if (($table === 'tt_content' || $table === 'pages') && $status === 'update' && !$parentObj->isImporting) { + 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); } } From 4a8ab9b7c47052995c8c6d97b61f6cf8cca3f845 Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Fri, 19 Aug 2016 16:07:37 +0200 Subject: [PATCH 017/102] [BUGFIX] copyFromAnotherPage sets clipboard copy mode Change-Id: Ie5856b021f029d8ed6bdfd0c7903b01dcf7dd84a Resolves: #72905 Releases: master, 7-0 Reviewed-on: https://review.typo3.org/49514 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau (cherry picked from commit f6f47eab4819f18d665019ef52bedd54310f0d2a) Reviewed-on: https://review.typo3.org/49944 --- Resources/Public/JavaScript/GridElementsDragDrop.js | 3 +++ Resources/Public/JavaScript/GridElementsOnReady.js | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Resources/Public/JavaScript/GridElementsDragDrop.js b/Resources/Public/JavaScript/GridElementsDragDrop.js index 2df2b9b..20d9ef9 100644 --- a/Resources/Public/JavaScript/GridElementsDragDrop.js +++ b/Resources/Public/JavaScript/GridElementsDragDrop.js @@ -261,6 +261,9 @@ 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; + } // fire the request, and show a message if it has failed require(['TYPO3/CMS/Backend/AjaxDataHandler'], function (DataHandler) { DataHandler.process(parameters).done(function (result) { diff --git a/Resources/Public/JavaScript/GridElementsOnReady.js b/Resources/Public/JavaScript/GridElementsOnReady.js index 66af745..d5d8ba5 100644 --- a/Resources/Public/JavaScript/GridElementsOnReady.js +++ b/Resources/Public/JavaScript/GridElementsOnReady.js @@ -274,7 +274,7 @@ define(['jquery', 'TYPO3/CMS/Backend/AjaxDataHandler', 'TYPO3/CMS/Backend/Storag } /** - * gives back the data form the popup window to the copy action + * gives back the data from the popup window to the copy action */ if (!$('.typo3-TCEforms').length) { OnReady.setSelectOptionFromExternalSource = setFormValueFromBrowseWin = function(elementId, tableUid){ From 4da7bcfa03eb4a1373d6175316db98efd663e242 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20Mar=C3=ADn?= Date: Tue, 2 Aug 2016 16:08:23 +0200 Subject: [PATCH 018/102] [TASK] replace deprecated language file paths in TCA Resolves: #78015 Change-Id: If5bca6fa17ba34d139041ef11f5a37db24efd3ac Reviewed-on: https://review.typo3.org/49982 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau (cherry picked from commit dcfdd5f500320d341e739a9bfac44c7a201c444a) Reviewed-on: https://review.typo3.org/49985 --- Configuration/TCA/Overrides/tt_content.php | 12 ++++++------ Configuration/TCA/tx_gridelements_backend_layout.php | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Configuration/TCA/Overrides/tt_content.php b/Configuration/TCA/Overrides/tt_content.php index 51d54d8..b71a423 100644 --- a/Configuration/TCA/Overrides/tt_content.php +++ b/Configuration/TCA/Overrides/tt_content.php @@ -103,17 +103,17 @@ $GLOBALS['TCA']['tt_content']['columns']['records']['config']['allowed'] .= ',pages'; $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, + --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.appearance, --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.frames;frames, 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, + --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.visibility;visibility, + --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 '; diff --git a/Configuration/TCA/tx_gridelements_backend_layout.php b/Configuration/TCA/tx_gridelements_backend_layout.php index 58b4d0f..990a51d 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', ), ), ), @@ -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 +); From a9c6926af203bcdfa236866bbb7d3147eebfe65f Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Wed, 21 Sep 2016 12:20:22 +0200 Subject: [PATCH 019/102] [TASK] Support MySQL strict mode Change-Id: Ib61f2106a20c9636514c4d125c2ba0ebebc72510 Resolves: #73087 Releases: master Reviewed-on: https://review.typo3.org/49990 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau (cherry picked from commit 29655368c81af043205860d9fa7d4c54dcb22901) Reviewed-on: https://review.typo3.org/49991 --- Classes/Backend/ClickMenuOptions.php | 4 ++-- Classes/Backend/ItemsProcFuncs/CTypeList.php | 2 +- Classes/DataHandler/PreProcessFieldArray.php | 3 ++- Classes/Hooks/WizardItems.php | 8 ++++---- Classes/Xclass/DatabaseRecordList.php | 2 +- Configuration/TCA/Overrides/tt_content.php | 4 +++- 6 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Classes/Backend/ClickMenuOptions.php b/Classes/Backend/ClickMenuOptions.php index 3681177..0eaed08 100644 --- a/Classes/Backend/ClickMenuOptions.php +++ b/Classes/Backend/ClickMenuOptions.php @@ -104,8 +104,8 @@ public function DB_paste(ClickMenu $backRef, $table, $uid, $type, array $elInfo, $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)) { diff --git a/Classes/Backend/ItemsProcFuncs/CTypeList.php b/Classes/Backend/ItemsProcFuncs/CTypeList.php index fdcb205..9656dad 100644 --- a/Classes/Backend/ItemsProcFuncs/CTypeList.php +++ b/Classes/Backend/ItemsProcFuncs/CTypeList.php @@ -106,7 +106,7 @@ public function checkForAllowedCTypes(array &$items, $pid, $pageColumn, $gridCon $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']); } diff --git a/Classes/DataHandler/PreProcessFieldArray.php b/Classes/DataHandler/PreProcessFieldArray.php index 34de0ed..5233504 100644 --- a/Classes/DataHandler/PreProcessFieldArray.php +++ b/Classes/DataHandler/PreProcessFieldArray.php @@ -238,7 +238,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; } } } @@ -266,6 +266,7 @@ public function setFieldEntriesForGridContainers(array &$fieldArray) } 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; + $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']); diff --git a/Classes/Hooks/WizardItems.php b/Classes/Hooks/WizardItems.php index 4f39748..a11da21 100644 --- a/Classes/Hooks/WizardItems.php +++ b/Classes/Hooks/WizardItems.php @@ -313,12 +313,12 @@ public function addGridValuesToWizardItems(array &$wizardItems, $container, $col 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; + $wizardItems[$key]['tt_content_defValues']['tx_gridelements_container'] = (int)$container; + $wizardItems[$key]['params'] .= '&defVals[tt_content][tx_gridelements_container]=' . (int)$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_columns'] = (int)$column; + $wizardItems[$key]['params'] .= '&defVals[tt_content][tx_gridelements_columns]=' . (int)$column; } } } diff --git a/Classes/Xclass/DatabaseRecordList.php b/Classes/Xclass/DatabaseRecordList.php index 144dc1b..af9ff3b 100644 --- a/Classes/Xclass/DatabaseRecordList.php +++ b/Classes/Xclass/DatabaseRecordList.php @@ -1912,7 +1912,7 @@ 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']) diff --git a/Configuration/TCA/Overrides/tt_content.php b/Configuration/TCA/Overrides/tt_content.php index b71a423..d947549 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, ) ), ); From 7902b688ff8d73010c1d665c29a9bc3e55e7152b Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Fri, 19 Aug 2016 15:52:37 +0200 Subject: [PATCH 020/102] [BUGFIX] Make pid of children identical to pid of parent container Change-Id: Ie4a17fd4c3eb696522fe2a85c7c7ea8d481e2d6d Resolves: #76243 Releases: master, 7-0, 3-0 Reviewed-on: https://review.typo3.org/49513 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau (cherry picked from commit eb482fe2e7b600f989d4f46f0b86218da015c073) Reviewed-on: https://review.typo3.org/49992 --- Classes/Helper/Helper.php | 8 ++++---- Classes/Hooks/DatabaseRecordList.php | 2 +- Classes/Plugin/Gridelements.php | 8 +++++--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Classes/Helper/Helper.php b/Classes/Helper/Helper.php index daab0c7..e8116dd 100644 --- a/Classes/Helper/Helper.php +++ b/Classes/Helper/Helper.php @@ -67,22 +67,22 @@ public function setDatabaseConnection(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') { diff --git a/Classes/Hooks/DatabaseRecordList.php b/Classes/Hooks/DatabaseRecordList.php index 80f3f97..250656f 100644 --- a/Classes/Hooks/DatabaseRecordList.php +++ b/Classes/Hooks/DatabaseRecordList.php @@ -132,7 +132,7 @@ public function renderListHeaderActions($table, $currentIdList, $cells, &$parent 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']; diff --git a/Classes/Plugin/Gridelements.php b/Classes/Plugin/Gridelements.php index 4f2e83a..46d1e1b 100644 --- a/Classes/Plugin/Gridelements.php +++ b/Classes/Plugin/Gridelements.php @@ -92,6 +92,7 @@ public function main($content = '', $conf = array()) } else { $element = $this->cObj->data['uid']; } + $pid = $this->cObj->data['pid']; $layout = $this->cObj->data['tx_gridelements_backend_layout']; /** @var LayoutSetup $layoutSetup */ @@ -100,7 +101,7 @@ public function main($content = '', $conf = array()) $availableColumns = $layoutSetup->getLayoutColumns($layout); $csvColumns = str_replace('-2,-1,', '', $availableColumns['CSV']); - $this->getChildren($element, $csvColumns); + $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); @@ -142,15 +143,16 @@ public function main($content = '', $conf = array()) * fetches all available children for a certain 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; } $where = '(tx_gridelements_container = ' . $element . $this->cObj->enableFields('tt_content') . ' AND colPos != -2 - AND pid > 0 + AND pid = ' . (int)$pid . ' AND tx_gridelements_columns IN (' . $csvColumns . ') AND sys_language_uid IN (-1,0) )'; From 8d2808a88c0788952b6227a3097c189a855c3522 Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Wed, 21 Sep 2016 13:35:46 +0200 Subject: [PATCH 021/102] [BUGFIX] Add 0 as a possible value for grid columns in new CE wizard Change-Id: Ie093af9ab96efc14c13df96a50abdc0f92d4cc3a Resolves: #76884 Releases: master, 7-0 Reviewed-on: https://review.typo3.org/49993 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau (cherry picked from commit 27aa0bab08d1d4a26621ab54c8ad1235f7749c8c) Reviewed-on: https://review.typo3.org/49994 --- Classes/Hooks/WizardItems.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Classes/Hooks/WizardItems.php b/Classes/Hooks/WizardItems.php index a11da21..72b9155 100644 --- a/Classes/Hooks/WizardItems.php +++ b/Classes/Hooks/WizardItems.php @@ -316,10 +316,8 @@ public function addGridValuesToWizardItems(array &$wizardItems, $container, $col $wizardItems[$key]['tt_content_defValues']['tx_gridelements_container'] = (int)$container; $wizardItems[$key]['params'] .= '&defVals[tt_content][tx_gridelements_container]=' . (int)$container; } - if ($column !== 0) { - $wizardItems[$key]['tt_content_defValues']['tx_gridelements_columns'] = (int)$column; - $wizardItems[$key]['params'] .= '&defVals[tt_content][tx_gridelements_columns]=' . (int)$column; - } + $wizardItems[$key]['tt_content_defValues']['tx_gridelements_columns'] = (int)$column; + $wizardItems[$key]['params'] .= '&defVals[tt_content][tx_gridelements_columns]=' . (int)$column; } } } From ab391cd1fedff77ad7c3e5fb4753e4f9aa27ee8b Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Wed, 21 Sep 2016 13:44:45 +0200 Subject: [PATCH 022/102] [BUGFIX] Set clipboard to copy mode for copy content from another page action Change-Id: I83134354d6d2928a5c14886558b3196958a03394 Resolves: #72906 Releases: master, 7-0 Reviewed-on: https://review.typo3.org/49995 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau (cherry picked from commit cd811768b69357156b8bedab098fba449cb10ae7) Reviewed-on: https://review.typo3.org/49996 --- Resources/Public/JavaScript/GridElementsDragDrop.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Public/JavaScript/GridElementsDragDrop.js b/Resources/Public/JavaScript/GridElementsDragDrop.js index 20d9ef9..4fdf267 100644 --- a/Resources/Public/JavaScript/GridElementsDragDrop.js +++ b/Resources/Public/JavaScript/GridElementsDragDrop.js @@ -262,7 +262,7 @@ define(['jquery', 'jquery-ui/sortable', 'jquery-ui/droppable'], function ($) { parameters['cmd']['tt_content'][contentElementUid]['copy']['update']['sys_language_uid'] = language; } if (evt === 'copyFromAnotherPage') { - parameters['CB']['setCopyMode'] = 1; + parameters['CB'] = {setCopyMode: 1}; } // fire the request, and show a message if it has failed require(['TYPO3/CMS/Backend/AjaxDataHandler'], function (DataHandler) { From 688631a4c4ae76af2a2192bfcd3bacd5742118a8 Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Wed, 21 Sep 2016 13:49:43 +0200 Subject: [PATCH 023/102] [BUGFIX] Check content not page permission before rendering grid columns Change-Id: Iff1dad1b40f3289cc61452504ad2857df87c2749 Resolves: #76572 Releases: master, 7-0 Reviewed-on: https://review.typo3.org/49997 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau (cherry picked from commit b995683c520b8c5923946b66b7ea7073646dccda) Reviewed-on: https://review.typo3.org/49998 --- Classes/Hooks/DrawItem.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/Hooks/DrawItem.php b/Classes/Hooks/DrawItem.php index ffb452a..7b24bf9 100644 --- a/Classes/Hooks/DrawItem.php +++ b/Classes/Hooks/DrawItem.php @@ -450,7 +450,7 @@ protected function renderSingleGridColumn( $url = ''; $pageinfo = BackendUtility::readPageAccess($parentObject->id, ''); if ($colPos < 32768) { - if ($this->getPageLayoutController()->pageIsNotLockedForEditors() + if ($this->getPageLayoutController()->contentIsNotLockedForEditors() && $this->getBackendUser()->doesUserHaveAccess($pageinfo, Permission::CONTENT_EDIT) && (!$this->checkIfTranslationsExistInLanguage($items, $row['sys_language_uid'], $parentObject)) ) { @@ -524,7 +524,7 @@ protected function renderSingleGridColumn(
    ' . $this->renderSingleElementHTML($parentObject, $itemRow) . '
    '; - if ($this->getPageLayoutController()->pageIsNotLockedForEditors() + if ($this->getPageLayoutController()->contentIsNotLockedForEditors() && $this->getBackendUser()->doesUserHaveAccess($pageinfo, Permission::CONTENT_EDIT) && (!$this->checkIfTranslationsExistInLanguage($items, $row['sys_language_uid'], $parentObject)) ) { From 198fdd83a564aba147a83955ad9b47ca00b3ed2b Mon Sep 17 00:00:00 2001 From: Simon Schaufelberger Date: Fri, 23 Sep 2016 13:23:04 +0200 Subject: [PATCH 024/102] [BUGFIX] Avoid phpstorm typoscript parsing error Typoscript parser does not allow comments at the end of line. Releases: master, 7-0, 3-0, 2-0 Change-Id: I646ab198e5e6071cd05188b1331d0c9deab4a67b Reviewed-on: https://review.typo3.org/50012 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau (cherry picked from commit 690c443bfeb6ed0a849f578e83640520bf692265) Reviewed-on: https://review.typo3.org/50013 --- Configuration/TypoScript/setup.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Configuration/TypoScript/setup.ts b/Configuration/TypoScript/setup.ts index 66f64d3..8a43333 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 From fcb4dd81ee29a4e357e9bccdd8e146aeac72356c Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Sat, 24 Sep 2016 11:11:35 +0200 Subject: [PATCH 025/102] [BUGFIX] Check for deleted records and don't assign 0 to GE fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I505db21fa65c372b0edcdfeac817666b1737fa8a Resolves: #77173 Releases: master, 7-0 Reviewed-on: https://review.typo3.org/50016 Tested-by: Jörg Wagner Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau (cherry picked from commit 97977294d95e827f1fc55620d9467b6a61f8cba4) Reviewed-on: https://review.typo3.org/50017 --- Classes/DataHandler/AbstractDataHandler.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Classes/DataHandler/AbstractDataHandler.php b/Classes/DataHandler/AbstractDataHandler.php index 0e65aaa..f12f733 100644 --- a/Classes/DataHandler/AbstractDataHandler.php +++ b/Classes/DataHandler/AbstractDataHandler.php @@ -200,17 +200,17 @@ public function checkAndUpdateTranslatedElements($uid) } $currentValues = $this->databaseConnection->exec_SELECTgetSingleRow( 'uid,tx_gridelements_container,tx_gridelements_columns,sys_language_uid,colPos,l18n_parent', - 'tt_content', 'uid=' . (int)$uid + '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', 'uid=' . (int)$currentValues['l18n_parent'] + 'tt_content', 'deleted = 0 AND uid=' . (int)$currentValues['l18n_parent'] ); } $translatedElements = $this->databaseConnection->exec_SELECTgetRows( 'uid,tx_gridelements_container,tx_gridelements_columns,sys_language_uid,colPos,l18n_parent', - 'tt_content', 'l18n_parent=' . (int)$currentValues['uid'] , '', '', '', 'uid' + 'tt_content', 'deleted = 0 AND l18n_parent=' . (int)$currentValues['uid'] , '', '', '', 'uid' ); if (empty($translatedElements)) { return; @@ -218,16 +218,16 @@ public function checkAndUpdateTranslatedElements($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' + 'tt_content', 'deleted = 0 AND 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; + 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']; + } $updateArray['colPos'] = (int)$currentValues['colPos']; $this->databaseConnection->exec_UPDATEquery('tt_content', 'uid=' . (int)$translatedUid, From 7b1036be5c94cc860c5e35c716448f1ccf3c7b19 Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Sat, 24 Sep 2016 17:32:53 +0200 Subject: [PATCH 026/102] [BUGFIX] Give child elements correct ID to jump back after editing Change-Id: Icf5200e72910881c0c4f7575693dc8343ac739fd Resolves: #73093 Releases: 7-0 Reviewed-on: https://review.typo3.org/50018 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Hooks/DrawItem.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/Hooks/DrawItem.php b/Classes/Hooks/DrawItem.php index 7b24bf9..84c5dcf 100644 --- a/Classes/Hooks/DrawItem.php +++ b/Classes/Hooks/DrawItem.php @@ -521,7 +521,7 @@ protected function renderSingleGridColumn( if (is_array($itemRow)) { $statusHidden = $parentObject->isDisabled('tt_content', $itemRow) ? ' t3-page-ce-hidden' : ''; $gridContent[$colPos] .= ' -
    ' . $this->renderSingleElementHTML($parentObject, $itemRow) . '
    '; if ($this->getPageLayoutController()->contentIsNotLockedForEditors() From 109005df5cc5d320387c3450d027e2fa898e05a1 Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Sat, 24 Sep 2016 17:43:16 +0200 Subject: [PATCH 027/102] [FEATURE] Allow svg as a file format for CE backend layout icons Change-Id: Ifd09192b97cc58278e13a698bec7d2d18ace5f1c Resolves: #77094 Releases: master, 7-0 Reviewed-on: https://review.typo3.org/50021 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Configuration/TCA/tx_gridelements_backend_layout.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Configuration/TCA/tx_gridelements_backend_layout.php b/Configuration/TCA/tx_gridelements_backend_layout.php index 990a51d..0823d38 100644 --- a/Configuration/TCA/tx_gridelements_backend_layout.php +++ b/Configuration/TCA/tx_gridelements_backend_layout.php @@ -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, From 4ae33a61c252a0fec6e11b6b1c6b3854ca41ca16 Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Mon, 22 Aug 2016 16:28:49 +0200 Subject: [PATCH 028/102] [BUGFIX] Make elements droppable when only allowedGridTypes is set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I126bd23423c0e9701ba751968cc4670e2fd5acc6 Resolves: #77582 Releases: master, 7-0 Reviewed-on: https://review.typo3.org/49539 Tested-by: Marvin Hübner Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Hooks/DrawItem.php | 6 +++--- .../Public/JavaScript/GridElementsDragDrop.js | 18 +++++++----------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/Classes/Hooks/DrawItem.php b/Classes/Hooks/DrawItem.php index 84c5dcf..43c054c 100644 --- a/Classes/Hooks/DrawItem.php +++ b/Classes/Hooks/DrawItem.php @@ -703,6 +703,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['*'])) { @@ -717,9 +718,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'; @@ -733,7 +733,7 @@ public function renderGridLayoutTable($layoutSetup, $row, $head, $gridContent) $expanded = $this->helper->getBackendUser()->uc['moduleData']['page']['gridelementsCollapsedColumns'][$row['uid'] . '_' . $columnKey] ? 'collapsed' : 'expanded'; $grid .= ''; $grid .= ($this->helper->getBackendUser()->uc['hideColumnHeaders'] ? '' : $head[$columnKey]) . $gridContent[$columnKey]; diff --git a/Resources/Public/JavaScript/GridElementsDragDrop.js b/Resources/Public/JavaScript/GridElementsDragDrop.js index 4fdf267..c80fc94 100644 --- a/Resources/Public/JavaScript/GridElementsDragDrop.js +++ b/Resources/Public/JavaScript/GridElementsDragDrop.js @@ -88,14 +88,14 @@ 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)) && $(this).parent().find('.icon-actions-document-new').length ) { $(this).addClass(DragDrop.validDropZoneClass); @@ -305,12 +305,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); } }); }); From 528c2051171e9a86ce3de559273e24f266c5a04b Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Sat, 1 Oct 2016 15:10:59 +0200 Subject: [PATCH 029/102] [BUGFIX] Assign container and grid column to new CE wizard default values Resolves: #78126 Releases: master, 7-0 Not needed for 3-0, since this is solved with copyAfterDuplFields there. Change-Id: Id38c41ba3b67b5a32ff6065d5575880f697af740 Reviewed-on: https://review.typo3.org/50078 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau (cherry picked from commit 0dd95b1f14886aa9b4183ab92f458384c373cf6a) Reviewed-on: https://review.typo3.org/50079 --- Classes/Hooks/DrawItem.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Classes/Hooks/DrawItem.php b/Classes/Hooks/DrawItem.php index 43c054c..60e5477 100644 --- a/Classes/Hooks/DrawItem.php +++ b/Classes/Hooks/DrawItem.php @@ -457,13 +457,13 @@ protected function renderSingleGridColumn( 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); @@ -476,12 +476,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') @@ -536,6 +536,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') @@ -551,9 +553,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') From 29ec99b746511a88e3988f1b5c2bb9d7b585b400 Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Tue, 18 Oct 2016 11:03:23 +0200 Subject: [PATCH 030/102] [BUGFIX] Assign correct ID to children of grid containers Change-Id: I7dbf71e5f35d04ea2266bef5e89dd5744459cdae Resolves: #78325 Releases: master, 7.0 Reviewed-on: https://review.typo3.org/50258 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Hooks/DrawItem.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/Hooks/DrawItem.php b/Classes/Hooks/DrawItem.php index 60e5477..1903a5c 100644 --- a/Classes/Hooks/DrawItem.php +++ b/Classes/Hooks/DrawItem.php @@ -151,7 +151,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 . '
    '; } /** From 589c59b80fc853809f7206ceb957344974ed47a4 Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Wed, 16 Nov 2016 16:43:09 +0100 Subject: [PATCH 031/102] [BUGFIX] Removed 100% width of outer table to avoid overlapping grids Change-Id: I7272eb6fd33e49d89f4c30c43a76afc2c51c8cbb --- Resources/Public/Backend/Css/Skin/t3skin_override.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Resources/Public/Backend/Css/Skin/t3skin_override.css b/Resources/Public/Backend/Css/Skin/t3skin_override.css index a1c48d4..886ffe7 100644 --- a/Resources/Public/Backend/Css/Skin/t3skin_override.css +++ b/Resources/Public/Backend/Css/Skin/t3skin_override.css @@ -24,6 +24,11 @@ .t3-page-columns { border-spacing: 10px !important; + width: auto; +} + +.t3-page-columns .t3-page-columns { + width: 100%; } .t3-page-ce:hover .t3-page-ce-header { From ef78aaa4a7054c82d022a6f5d0a9447dd3208c63 Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Wed, 16 Nov 2016 17:06:10 +0100 Subject: [PATCH 032/102] [BUGFIX] Adjusted table width to avoid overlapping grids Change-Id: Ic03f4866aaef20bc793089c936c079a34b3ba755 --- Resources/Public/Backend/Css/Skin/t3skin_override.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Public/Backend/Css/Skin/t3skin_override.css b/Resources/Public/Backend/Css/Skin/t3skin_override.css index 886ffe7..5e5c692 100644 --- a/Resources/Public/Backend/Css/Skin/t3skin_override.css +++ b/Resources/Public/Backend/Css/Skin/t3skin_override.css @@ -28,7 +28,7 @@ } .t3-page-columns .t3-page-columns { - width: 100%; + min-width: 100%; } .t3-page-ce:hover .t3-page-ce-header { From f0f4ee26eb2691c7d9f8d09c6e693dc56e0e2d0d Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Wed, 23 Nov 2016 12:32:12 +0100 Subject: [PATCH 033/102] [BUGFIX] column table uses at least the whole available view port Change-Id: Ic4de6b9f41a8d45538a0ef1d9428d8dbd9fff187 --- Resources/Public/Backend/Css/Skin/t3skin_override.css | 3 --- 1 file changed, 3 deletions(-) diff --git a/Resources/Public/Backend/Css/Skin/t3skin_override.css b/Resources/Public/Backend/Css/Skin/t3skin_override.css index 5e5c692..f624334 100644 --- a/Resources/Public/Backend/Css/Skin/t3skin_override.css +++ b/Resources/Public/Backend/Css/Skin/t3skin_override.css @@ -25,9 +25,6 @@ .t3-page-columns { border-spacing: 10px !important; width: auto; -} - -.t3-page-columns .t3-page-columns { min-width: 100%; } From ff92952d1206dfe9aa66be25c671b1165dacd489 Mon Sep 17 00:00:00 2001 From: Markus Klein Date: Thu, 22 Dec 2016 17:57:47 +0100 Subject: [PATCH 034/102] [BUGFIX] Adjust CSS for frame-rendering The CSS for all frames must be the same. Additionally fix "0px" specifications as those actually violate the standard. Change-Id: Ic58488d1727d197c00523cac44a38cf814a0e714 Releases: master, 7.6 Reviewed-on: https://review.typo3.org/51030 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau (cherry picked from commit bbe51a924fbf24f84b9cc46dfc027804d0d06359) Reviewed-on: https://review.typo3.org/51031 --- .../Public/Backend/Css/Skin/t3skin_override.css | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Resources/Public/Backend/Css/Skin/t3skin_override.css b/Resources/Public/Backend/Css/Skin/t3skin_override.css index f624334..8cbcd38 100644 --- a/Resources/Public/Backend/Css/Skin/t3skin_override.css +++ b/Resources/Public/Backend/Css/Skin/t3skin_override.css @@ -82,7 +82,7 @@ } .t3-grid-container { - margin: 0px -10px; + margin: 0 -10px; } .t3js-module-body .t3-grid-container-title-0 { @@ -97,7 +97,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 { @@ -211,7 +211,7 @@ } #new-element-drag-in-wizard.dragged .tab-content:hover { - min-height: 0px !important; + min-height: 0 !important; } #new-element-drag-in-wizard .media { @@ -243,7 +243,7 @@ } #new-element-drag-in-wizard.dragged .panel-tab:hover { - min-height: 0px !important; + min-height: 0 !important; } .t3js-module-body .exampleContent > .reference { @@ -259,8 +259,8 @@ .t3js-module-body .exampleContent > .reference .reference-overlay { position: absolute; - top: 0px; - left: 0px; + top: 0; + left: 0; width: 100%; height: 100%; background: #427BAB; From 3d8a7053d8e5ca3e3efdebd0f1f21eab24469811 Mon Sep 17 00:00:00 2001 From: Markus Klein Date: Thu, 22 Dec 2016 17:49:15 +0100 Subject: [PATCH 035/102] [BUGFIX] Fix deprecated label usage Change-Id: I6d63400f2b961695a72e00491d56141b8ab5d2d8 Releases: master, 7.6 Reviewed-on: https://review.typo3.org/51028 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau (cherry picked from commit 0d37cd901297d6a0c7dfe3efcac94c7a58324997) Reviewed-on: https://review.typo3.org/51032 --- Configuration/TCA/Overrides/tt_content.php | 2 +- Configuration/TCA/tx_gridelements_backend_layout.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Configuration/TCA/Overrides/tt_content.php b/Configuration/TCA/Overrides/tt_content.php index d947549..b2c393d 100644 --- a/Configuration/TCA/Overrides/tt_content.php +++ b/Configuration/TCA/Overrides/tt_content.php @@ -111,7 +111,7 @@ pi_flexform, tx_gridelements_children, --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.appearance, - --palette--;LLL:EXT:cms/locallang_ttc.xlf:palette.frames;frames, + --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.frames;frames, media, --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, diff --git a/Configuration/TCA/tx_gridelements_backend_layout.php b/Configuration/TCA/tx_gridelements_backend_layout.php index 0823d38..b3a9186 100644 --- a/Configuration/TCA/tx_gridelements_backend_layout.php +++ b/Configuration/TCA/tx_gridelements_backend_layout.php @@ -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( From 93221db9de026954f6b034bd59634a3c354c282b Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Mon, 13 Mar 2017 13:50:09 +0100 Subject: [PATCH 036/102] [TASK] Prepared upload of version 7.1.0 for CMS 7 LTS Change-Id: I66969b8b0e9699ad00c32d0181292ba26c224fc5 Reviewed-on: https://review.typo3.org/52028 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- ext_emconf.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext_emconf.php b/ext_emconf.php index ea522bd..7759a57 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -13,7 +13,7 @@ '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' => '7.0.6-dev', + 'version' => '7.1.0', 'priority' => 'bottom', 'module' => '', 'state' => 'beta', From 2956eb8c99dab9f40618c43fa378be8e746388fe Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Mon, 13 Mar 2017 13:52:51 +0100 Subject: [PATCH 037/102] [TASK] Adjusted composer.json Change-Id: Id9475ca1bf0c10c3d911fe14153f76f8ad97e959 Reviewed-on: https://review.typo3.org/52029 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index ec5b625..8c05279 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "keywords": ["TYPO3 CMS", "Grids", "Gridelements"], "homepage": "https://git.typo3.org/TYPO3CMS/Extensions/gridelements.git", "license": "GPL-2.0+", - "version": "7.0.5", + "version": "7.1.0", "support": { "issues": "https://forge.typo3.org/" }, @@ -19,7 +19,7 @@ }, "extra": { "branch-alias": { - "dev-master": "7.0.5" + "dev-master": "7.1.0" } } } \ No newline at end of file From 0c83b1a3a1287ec469a8754f4360549d74b58814 Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Mon, 13 Mar 2017 13:56:05 +0100 Subject: [PATCH 038/102] [TASK] Changelog points to Git repository Change-Id: I2d1e6151856a2117ea72ccc8aef3ebfbde0c412f Reviewed-on: https://review.typo3.org/52030 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) 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 From d6d017767e6641e1edfc18b1d115e1d5b56f9cc5 Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Wed, 22 Mar 2017 23:00:15 +0100 Subject: [PATCH 039/102] [TASK] Implement latest changes of the core to list module XCLASS Resolves: #80223 Releases: 7-0 Change-Id: Id78588281e6a0a8e52b69d894450c20bb2812842 Reviewed-on: https://review.typo3.org/52131 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Xclass/DatabaseRecordList.php | 366 +++++++++++++++----------- 1 file changed, 211 insertions(+), 155 deletions(-) diff --git a/Classes/Xclass/DatabaseRecordList.php b/Classes/Xclass/DatabaseRecordList.php index af9ff3b..82122a5 100644 --- a/Classes/Xclass/DatabaseRecordList.php +++ b/Classes/Xclass/DatabaseRecordList.php @@ -45,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 @@ -93,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 @@ -101,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 @@ -170,14 +170,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. @@ -198,14 +198,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 @@ -232,7 +232,7 @@ class DatabaseRecordList extends \TYPO3\CMS\Recordlist\RecordList\DatabaseRecord * * @var string[] */ - public $MOD_MENU; + public $MOD_MENU = []; /** * If defined the records are editable @@ -266,7 +266,7 @@ public function getButtons() $module = $this->getModule(); $this->backendUser = $this->getBackendUserAuthentication(); $lang = $this->getLanguageService(); - $buttons = array( + $buttons = [ 'csh' => '', 'view' => '', 'edit' => '', @@ -281,7 +281,7 @@ public function getButtons() 'back' => '', 'csv' => '', 'export' => '' - ); + ]; // Get users permissions for this page record: $localCalcPerms = $this->backendUser->calcPerms($this->pageRow); // CSH @@ -300,10 +300,10 @@ 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, '', @@ -334,11 +334,17 @@ public function getButtons() 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'] = 'id)) . '" title="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.export', true) . '">' @@ -413,10 +419,10 @@ 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()) { @@ -446,13 +452,20 @@ public function getDocHeaderButtons(ModuleTemplate $moduleTemplate) $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); } } @@ -472,7 +485,7 @@ public function getDocHeaderButtons(ModuleTemplate $moduleTemplate) $buttonBar->addButton($csvButton, ButtonBar::BUTTON_POSITION_LEFT, 40); // Export if (ExtensionManagementUtility::isLoaded('impexp')) { - $url = BackendUtility::getModuleUrl('xMOD_tximpexp', array('tx_impexp[action]' => 'export')); + $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')) @@ -503,7 +516,7 @@ public function getDocHeaderButtons(ModuleTemplate $moduleTemplate) } // Back if ($this->returnUrl) { - $href = htmlspecialchars(GeneralUtility::linkThisUrl($this->returnUrl, array('id' => $this->id))); + $href = htmlspecialchars(GeneralUtility::linkThisUrl($this->returnUrl, ['id' => $this->id])); $buttons['back'] = '' . $this->iconFactory->getIcon('actions-view-go-back', Icon::SIZE_SMALL) . ''; @@ -550,7 +563,7 @@ public function getTable($table, $id, $rowList = '') $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; @@ -574,11 +587,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)); @@ -613,7 +629,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]; } @@ -655,10 +671,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); } @@ -673,12 +686,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 @@ -716,7 +729,7 @@ 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 . ')'; @@ -754,7 +767,7 @@ public function getTable($table, $id, $rowList = '') } // 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']; @@ -781,7 +794,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; @@ -792,7 +806,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)) { @@ -824,8 +838,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 = ''; @@ -852,8 +866,8 @@ public function getTable($table, $id, $rowList = '') $this->showMoveDown = !isset($row['colPos']) && isset($accRows[$key + 1]) && $row['colPos'] != $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: @@ -972,7 +986,7 @@ public function renderListHeader($table, $currentIdList) { $lang = $this->getLanguageService(); // Init: - $theData = array(); + $theData = []; $icon = ''; // Traverse the fields: foreach ($this->fieldArray as $fCol) { @@ -1000,16 +1014,21 @@ 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') { @@ -1055,8 +1074,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); } @@ -1089,10 +1107,10 @@ 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() . ''; @@ -1157,9 +1175,9 @@ class="btn btn-default t3js-toggle-gridelements-all" href="#t3-gridelements-expa // 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() . ''; + . htmlspecialchars($this->listURL('', '-1') . '&duplicateField=' . $fCol) + . '" title="' . $lang->getLL('clip_duplicates', true) . '">' + . $this->iconFactory->getIcon('actions-document-duplicates-select', Icon::SIZE_SMALL)->render() . ''; } // If the table can be edited, add link for editing THIS field for all // listed records: @@ -1206,8 +1224,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); } @@ -1262,10 +1279,10 @@ protected function renderListNavigation($renderPart = 'top') $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 = '
  • ' + $reload = '
  • ' . $this->iconFactory->getIcon('actions-refresh', Icon::SIZE_SMALL)->render() . '
  • '; if ($renderPart === 'top') { // Add js to traverse a page select input to a pointer value @@ -1286,10 +1303,10 @@ function calculatePointer(page) { '; } $pageNumberInput = ' - - '; + + '; $pageIndicatorText = sprintf( $this->getLanguageService()->sL('LLL:EXT:lang/locallang_mod_web_list.xlf:pageIndicator'), $pageNumberInput, @@ -1308,7 +1325,7 @@ function calculatePointer(page) { ) . ''; $titleColumn = $this->fieldArray[0]; - $data = array( + $data = [ $titleColumn => $content . ' ' - ); + ]; return $this->addElement(1, '', $data); } @@ -1347,10 +1364,10 @@ 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') { @@ -1360,7 +1377,8 @@ public function makeControl($table, $row) && $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; @@ -1393,7 +1411,7 @@ public function makeControl($table, $row) $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'] . '\');'; + $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) @@ -1406,7 +1424,7 @@ 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 = '' @@ -1418,10 +1436,10 @@ 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() . ''; @@ -1430,7 +1448,7 @@ public function makeControl($table, $row) } // "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'; + $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() . ''; @@ -1484,11 +1502,11 @@ public function makeControl($table, $row) // "Hide/Unhide" links: $hiddenField = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled']; - if ($permsEdit && $hiddenField && $GLOBALS['TCA'][$table]['columns'][$hiddenField] - && (!$GLOBALS['TCA'][$table]['columns'][$hiddenField]['exclude'] + 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); @@ -1511,10 +1529,9 @@ public function makeControl($table, $row) $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 = ''; @@ -1528,7 +1545,7 @@ public function makeControl($table, $row) ) . BackendUtility::translationCount( $table, $row['uid'], - ' ' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.translationsOfRecord') + ' ' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlflabels.translationsOfRecord') ); } @@ -1583,7 +1600,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); } @@ -1607,10 +1624,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); } @@ -1660,7 +1674,7 @@ 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; @@ -1684,16 +1698,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 { + $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 { - $cells['cut'] = $this->spaceIcon; + if ($table !== 'pages' && $this->calcPerms & Permission::CONTENT_EDIT) { + $cells['cut'] = '' + . $cutIcon->render() . ''; + } else { + $cells['cut'] = $this->spaceIcon; + } } } } else { @@ -1723,18 +1760,24 @@ public function makeClip($table, $row) // 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() . ''; + : '' + . $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() . ''; + $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 @@ -1747,10 +1790,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); } @@ -1811,7 +1851,7 @@ public function renderListRow($table, $row, $cc, $titleCol, $thumbsCol, $indent . $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) { @@ -1845,7 +1885,9 @@ public function renderListRow($table, $row, $cc, $titleCol, $thumbsCol, $indent 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']] @@ -1918,11 +1960,11 @@ public function renderListRow($table, $row, $cc, $titleCol, $thumbsCol, $indent && isset($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) && !isset($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable']) ) { - $theData['parent'] = $row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']]; + $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) { @@ -2211,12 +2253,12 @@ 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']]); @@ -2273,15 +2315,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 @@ -2291,7 +2330,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 @@ -2347,23 +2386,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 . ''; } /** @@ -2488,10 +2541,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); } @@ -2502,17 +2558,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)); } @@ -2562,15 +2618,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', @@ -2581,8 +2637,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]); @@ -2632,7 +2688,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") From a60a8b55305d89e8b33ab3493d2ec003e74ebff7 Mon Sep 17 00:00:00 2001 From: Markus Klein Date: Thu, 6 Apr 2017 16:11:21 +0200 Subject: [PATCH 040/102] [BUGFIX] Fix wrong condition for list module moveDown button With one of the last cleanups the condition has been negated, but in a wrong way. Fix this to make the condition correct again. Change-Id: I0b06e1226c5fd7c8c1c125536a2d4b80ae1c83f5 Releases: master, 7 Resolves: #80729 Reviewed-on: https://review.typo3.org/52376 Reviewed-by: Sven Juergens Tested-by: Sven Juergens Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Xclass/DatabaseRecordList.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/Xclass/DatabaseRecordList.php b/Classes/Xclass/DatabaseRecordList.php index 82122a5..dbf9a06 100644 --- a/Classes/Xclass/DatabaseRecordList.php +++ b/Classes/Xclass/DatabaseRecordList.php @@ -863,8 +863,8 @@ public function getTable($table, $id, $rowList = '') } else { $this->showMoveUp = true; } - $this->showMoveDown = !isset($row['colPos']) && isset($accRows[$key + 1]) - && $row['colPos'] != $accRows[$key + 1]['colPos']; + $this->showMoveDown = !isset($row['colPos']) || !isset($accRows[$key + 1]) + || $row['colPos'] == $accRows[$key + 1]['colPos']; $rowOutput .= $this->renderListRow($table, $row, $cc, $titleCol, $thumbsCol); // 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 From 10d123d99400f7f669ae537ce41e5fd975e2b0f9 Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Fri, 14 Apr 2017 10:36:52 +0200 Subject: [PATCH 041/102] [BUGFIX] Check for possible XCLASS of original classes Change-Id: I9cd382d2bc37739b780755fcf4b7c8264223c6e2 Resolves: #80824 Releases: master, 7-0 Reviewed-on: https://review.typo3.org/52444 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Hooks/PageRenderer.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/Hooks/PageRenderer.php b/Classes/Hooks/PageRenderer.php index d50e91e..fffc0a1 100644 --- a/Classes/Hooks/PageRenderer.php +++ b/Classes/Hooks/PageRenderer.php @@ -48,11 +48,11 @@ class PageRenderer implements SingletonInterface 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']) === RecordList::class) { + if (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']) === PageLayoutController::class) { + if (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'); From d46f4cb92ef673523a6bbb8b7809fee5a6da1866 Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Thu, 13 Apr 2017 17:28:32 +0200 Subject: [PATCH 042/102] [TASK] check for l18n_parent records before setting translated elements Otherwise actions to repair broken data structures might use records with l18n_parent = 0 as translated elements. Change-Id: Ibef83f8de45cc665f8526e71dec63b8b5da65723 Resolves: #80838 Releases: master, 7-0 Reviewed-on: https://review.typo3.org/52440 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/DataHandler/AbstractDataHandler.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Classes/DataHandler/AbstractDataHandler.php b/Classes/DataHandler/AbstractDataHandler.php index f12f733..30ba225 100644 --- a/Classes/DataHandler/AbstractDataHandler.php +++ b/Classes/DataHandler/AbstractDataHandler.php @@ -1,4 +1,5 @@ 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' + 'tt_content', 'deleted = 0 AND l18n_parent=' . (int)$currentValues['uid'], '', '', '', 'uid' ); if (empty($translatedElements)) { return; @@ -218,7 +222,8 @@ public function checkAndUpdateTranslatedElements($uid) 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' + 'tt_content', 'deleted = 0 AND l18n_parent=' . (int)$currentValues['tx_gridelements_container'], '', '', + '', 'sys_language_uid' ); } $containerUpdateArray = array(); From 0ce0a056b88ce495050cf3ac646f80819e0d28dc Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Fri, 14 Apr 2017 17:37:57 +0200 Subject: [PATCH 043/102] [TASK] Use forge instead of git as the homepage wihtin composer.json Change-Id: Ie1dd2ff25f66b1b671cbf77d57bb1d319b7fe186 Resolves: #77850 Releases: master, 7-0 Reviewed-on: https://review.typo3.org/52447 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 8c05279..8260f33 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "description": "This extension integrates the grid layout concept to regular content elements.", "type": "typo3-cms-extension", "keywords": ["TYPO3 CMS", "Grids", "Gridelements"], - "homepage": "https://git.typo3.org/TYPO3CMS/Extensions/gridelements.git", + "homepage": "https://forge.typo3.org/projects/extension-gridelements2", "license": "GPL-2.0+", "version": "7.1.0", "support": { From 2af838c487bd0451f0b7d1aa66490544dc9cf680 Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Fri, 14 Apr 2017 18:20:52 +0200 Subject: [PATCH 044/102] [BUGFIX] use largeIcon instead of icon for the check Change-Id: I365b74c85177d5037401d0f99626f89784128af1 Resolves: #80291 Releases: master, 7-0 Reviewed-on: https://review.typo3.org/52451 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Hooks/WizardItems.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/Hooks/WizardItems.php b/Classes/Hooks/WizardItems.php index 72b9155..bc7179f 100644 --- a/Classes/Hooks/WizardItems.php +++ b/Classes/Hooks/WizardItems.php @@ -233,7 +233,7 @@ public function addGridItemsToWizard(array &$gridItems, array &$wizardItems) ) { $largeIcon = GeneralUtility::resolveBackPath($item['icon'][1]); } - if (!empty($icon)) { + if (!empty($largeIcon)) { if (StringUtility::endsWith($largeIcon, '.svg')) { $iconRegistry->registerIcon($item['iconIdentifierLarge'], SvgIconProvider::class, array( 'source' => $largeIcon From 8ca7b888151a4c2608873616844f8bff82c66ae0 Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Fri, 14 Apr 2017 18:38:26 +0200 Subject: [PATCH 045/102] [BUGFIX] Reenable horizontal positioning of child elements Change-Id: I4015e13284b02a7a0954226f62eb8e322bba54a8 Resolves: #80476 Releases: 7-0 Reviewed-on: https://review.typo3.org/52452 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Resources/Public/Backend/Css/Skin/t3skin_override.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Resources/Public/Backend/Css/Skin/t3skin_override.css b/Resources/Public/Backend/Css/Skin/t3skin_override.css index 8cbcd38..5a05975 100644 --- a/Resources/Public/Backend/Css/Skin/t3skin_override.css +++ b/Resources/Public/Backend/Css/Skin/t3skin_override.css @@ -387,3 +387,6 @@ display: block; } +.t3-grid-cell-horizontal > .t3js-sortable > .t3js-page-ce-sortable { + display: inline-block; +} \ No newline at end of file From fb4bd92eed6b5cd45c30865b30b7bb9081122a9b Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Fri, 14 Apr 2017 18:13:05 +0200 Subject: [PATCH 046/102] [BUGFIX|] Use original tt_content_drawFooter method to generate footer Change-Id: I3853894212c368e436b674c584037a3bf9dc7d91 Resolves: #80162 Releases: 7-0 Reviewed-on: https://review.typo3.org/52449 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Hooks/DrawItem.php | 52 ++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/Classes/Hooks/DrawItem.php b/Classes/Hooks/DrawItem.php index 1903a5c..b40ea1c 100644 --- a/Classes/Hooks/DrawItem.php +++ b/Classes/Hooks/DrawItem.php @@ -24,6 +24,7 @@ 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; @@ -827,23 +828,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; } /** From 59b9be5fd8435f19a161915e5e0caab8c4ed49b0 Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Fri, 14 Apr 2017 20:32:55 +0200 Subject: [PATCH 047/102] [BUGFIX] Have Drag&Drop sorting respect AuthMode Change-Id: Ia5174e17a2cd88e5451baa2c649df038ae008a54 Resolves: #73548 Releases: 7-0 Reviewed-on: https://review.typo3.org/52454 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Resources/Public/JavaScript/GridElementsDragDrop.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Resources/Public/JavaScript/GridElementsDragDrop.js b/Resources/Public/JavaScript/GridElementsDragDrop.js index c80fc94..f023313 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', From 6f0e7737af3a1761365054f2334886253d5e877f Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Mon, 24 Apr 2017 09:26:44 +0200 Subject: [PATCH 048/102] [TASK] Top align horizontally arranged children and remove line wrapping Change-Id: I02b44d49a0c041a4da7f3f0115202773637e6add Resolves: #80476 Releases: master, 7-0 Reviewed-on: https://review.typo3.org/52563 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Resources/Public/Backend/Css/Skin/t3skin_override.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Resources/Public/Backend/Css/Skin/t3skin_override.css b/Resources/Public/Backend/Css/Skin/t3skin_override.css index 5a05975..8ec3af5 100644 --- a/Resources/Public/Backend/Css/Skin/t3skin_override.css +++ b/Resources/Public/Backend/Css/Skin/t3skin_override.css @@ -387,6 +387,11 @@ display: block; } +.t3-grid-cell-horizontal { + white-space: nowrap; +} + .t3-grid-cell-horizontal > .t3js-sortable > .t3js-page-ce-sortable { display: inline-block; + vertical-align: top; } \ No newline at end of file From ee94d55b5238754eaf48680cd86cabc6d7dfb9d1 Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Tue, 25 Apr 2017 20:42:31 +0200 Subject: [PATCH 049/102] [TASK] Use post processing hook to add to TCA types after other ext Change-Id: I8cf4e4048e2ccec80067026a8ac5e496f1782c74 Resolves: #81012 Releases: 7-0 Reviewed-on: https://review.typo3.org/52608 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- .../ExtTablesInclusionPostProcessing.php | 43 +++++++++++++++++++ Configuration/TCA/Overrides/tt_content.php | 3 -- ext_localconf.php | 2 + 3 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 Classes/Hooks/ExtTablesInclusionPostProcessing.php diff --git a/Classes/Hooks/ExtTablesInclusionPostProcessing.php b/Classes/Hooks/ExtTablesInclusionPostProcessing.php new file mode 100644 index 0000000..3fd17ef --- /dev/null +++ b/Classes/Hooks/ExtTablesInclusionPostProcessing.php @@ -0,0 +1,43 @@ + + * 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\Database\TableConfigurationPostProcessingHookInterface; +use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; + +/** + * Class ExtTablesInclusionPostProcessing + * + * @package GridElementsTeam\Gridelements\Hooks + */ +class ExtTablesInclusionPostProcessing implements TableConfigurationPostProcessingHookInterface +{ + /** + * Function which may process data created / registered by extTables + * scripts (f.e. modifying TCA data of all extensions) + * + * @return void + */ + function processData() + { + 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/Configuration/TCA/Overrides/tt_content.php b/Configuration/TCA/Overrides/tt_content.php index b2c393d..597535a 100644 --- a/Configuration/TCA/Overrides/tt_content.php +++ b/Configuration/TCA/Overrides/tt_content.php @@ -119,6 +119,3 @@ --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/ext_localconf.php b/ext_localconf.php index ccdfc08..a109973 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -12,6 +12,8 @@ \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPItoST43($_EXTKEY, 'Classes/Plugin/Gridelements.php', '_pi1', 'CType', 1); +$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['extTablesInclusion-PostProcessing'][] = 'GridElementsTeam\\Gridelements\\Hooks\\ExtTablesInclusionPostProcessing'; + // XCLASS if ($_EXTCONF['nestingInListModule']) { $GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects']['TYPO3\\CMS\\Recordlist\\RecordList\\DatabaseRecordList'] = array('className' => 'GridElementsTeam\\Gridelements\\Xclass\\DatabaseRecordList',); From b7db294cf7572906f3a8ac2fa1b6579a4d0e6ef4 Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Thu, 13 Apr 2017 19:32:45 +0200 Subject: [PATCH 050/102] [BUGFIX] Make grid children sortable in list module again Change-Id: Ic14eaf94e784b399feeec5dd44a7efc796aab1b0 Resolves: #79979 Releases: 7-0 Reviewed-on: https://review.typo3.org/52442 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Xclass/DatabaseRecordList.php | 50 +++++++++---------- .../Backend/Css/Skin/t3skin_override.css | 4 ++ 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/Classes/Xclass/DatabaseRecordList.php b/Classes/Xclass/DatabaseRecordList.php index dbf9a06..dd22ba1 100644 --- a/Classes/Xclass/DatabaseRecordList.php +++ b/Classes/Xclass/DatabaseRecordList.php @@ -864,7 +864,7 @@ public function getTable($table, $id, $rowList = '') $this->showMoveUp = true; } $this->showMoveDown = !isset($row['colPos']) || !isset($accRows[$key + 1]) - || $row['colPos'] == $accRows[$key + 1]['colPos']; + || (int)$row['colPos'] === (int)$accRows[$key + 1]['colPos']; $rowOutput .= $this->renderListRow($table, $row, $cc, $titleCol, $thumbsCol); // 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 @@ -1991,47 +1991,48 @@ public function renderListRow($table, $row, $cc, $titleCol, $thumbsCol, $indent if ($theData['_EXPANDABLE_'] && $level < 8 && ($row['l18n_parent'] == 0 || !$this->localizationView) && !empty($theData['_CHILDREN_'])) { $expanded = $this->expandedGridelements[$row['uid']] ? '" style="display: table-row;' : ''; - $lastGridColumn = ''; + $previousGridColumn = ''; $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 (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']; + } + 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']; } } + $previousGridColumn = ''; foreach ($theData['_CHILDREN_'] as $key => $child) { - if (isset($child['tx_gridelements_columns']) && ($child['tx_gridelements_columns'] != $lastGridColumn)) { - $lastGridColumn = $child['tx_gridelements_columns']; + if (isset($child['tx_gridelements_columns']) && ($child['tx_gridelements_columns'] !== $previousGridColumn)) { + $previousGridColumn = $child['tx_gridelements_columns']; $this->showMoveUp = false; $rowOutput .= ' - - + . ($this->localizationView && $row['l18n_parent'] ? $row['l18n_parent'] : $row['uid']) + . $expanded . '" data-grid-container="' . $row['uid'] . '"> + +
    ' . $this->getLanguageService()->sL('LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:list.columnName') - . ' ' . (int)$child['tx_gridelements_columns'] . ' + . ' ' . (int)$child['tx_gridelements_columns'] . ' '; } else { $this->showMoveUp = true; } $this->showMoveDown = !isset($child['tx_gridelements_columns']) || !isset($theData['_CHILDREN_'][$key + 1]) - || $child['tx_gridelements_columns'] == $theData['_CHILDREN_'][$key + 1]['tx_gridelements_columns']; + || (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; + . ($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; @@ -2099,7 +2100,7 @@ public function addElement($h, $icon, $data, $rowParams = '', $_ = '', $_2 = '', // Show icon and lines if ($this->showIcon) { $out .= ' - <' . $colType . ' nowrap="nowrap" class="col-icon"' . ($colType === 'th' ? ' colspan="' . ($this->maxDepth - $level) . '"' : '') . '>'; + <' . $colType . ' nowrap="nowrap" class="col-icon"' . ($colType === 'th' ? ' colspan="' . ($this->maxDepth - $level) . '"' : ' colspan="' . ($this->maxDepth - $level - 1) . '"') . '>'; if (!$h) { $out .= ' '; } else { @@ -2128,9 +2129,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) { @@ -2154,7 +2152,7 @@ public function addElement($h, $icon, $data, $rowParams = '', $_ = '', $_2 = '', $c++; } if ($c > 1) { - $colsp = ' colspan="' . ($c + $this->maxDepth) . '"'; + $colsp = ' colspan="2"'; } else { $colsp = ''; } diff --git a/Resources/Public/Backend/Css/Skin/t3skin_override.css b/Resources/Public/Backend/Css/Skin/t3skin_override.css index 8ec3af5..4bcee75 100644 --- a/Resources/Public/Backend/Css/Skin/t3skin_override.css +++ b/Resources/Public/Backend/Css/Skin/t3skin_override.css @@ -319,6 +319,10 @@ #recordlist-tt_content .col-icon { position: relative; + text-align: right; +} + +#recordlist-tt_content th.col-icon { text-align: left; } From c439367b398023bb685095d239a979014356638f Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Thu, 4 May 2017 13:54:52 +0200 Subject: [PATCH 051/102] [BUGFIX] Don't convert relative path of icons anymore Change-Id: I72179b025c21cccae6ea7a80695b8cba5995276f Resolves: #79612 Releases: 7-0 Reviewed-on: https://review.typo3.org/52706 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Backend/LayoutSetup.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Classes/Backend/LayoutSetup.php b/Classes/Backend/LayoutSetup.php index 45f4c8c..3386f85 100644 --- a/Classes/Backend/LayoutSetup.php +++ b/Classes/Backend/LayoutSetup.php @@ -24,7 +24,6 @@ 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; /** @@ -266,9 +265,6 @@ public function getLayoutSelectItems($colPos) } else { $icon = $item['icon']; } - if (!StringUtility::beginsWith($icon, '../')) { - $icon = '../' . $icon; - } } $selectItems[] = array($this->languageService->sL($item['title']), $layoutId, $icon); } From 2bcb1ae0041bffbbf4e8886d888371dd8682c24f Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Tue, 16 May 2017 16:34:38 +0200 Subject: [PATCH 052/102] [TASK] Speed up the FE execution by using the TCA building slot Change-Id: I511fe38f8ddfc997a4c6423e1a3b43c787cf4eda Resolves: #81212 Releases: 7-0 Reviewed-on: https://review.typo3.org/52807 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- .../ExtTablesInclusionPostProcessing.php | 51 +++++++++++++++++++ ext_localconf.php | 5 +- 2 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 Classes/Slots/ExtTablesInclusionPostProcessing.php diff --git a/Classes/Slots/ExtTablesInclusionPostProcessing.php b/Classes/Slots/ExtTablesInclusionPostProcessing.php new file mode 100644 index 0000000..983cb52 --- /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 + */ + 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/ext_localconf.php b/ext_localconf.php index a109973..5b6c72c 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -12,9 +12,10 @@ \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPItoST43($_EXTKEY, 'Classes/Plugin/Gridelements.php', '_pi1', 'CType', 1); -$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['extTablesInclusion-PostProcessing'][] = 'GridElementsTeam\\Gridelements\\Hooks\\ExtTablesInclusionPostProcessing'; - // 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'); From a66c4c2310d630b8306251657a0ba1fa0d5f9f3d Mon Sep 17 00:00:00 2001 From: Jo Hasenau Date: Tue, 25 Apr 2017 19:59:28 +0200 Subject: [PATCH 053/102] [BUGFIX] Skip empty values when merging layout setups Change-Id: Ia75d623e0fc5c37e60a089b6c3c8f041bd4ef5d6 Resolves: #80433 Releases: master, 7-0 Reviewed-on: https://review.typo3.org/52606 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Backend/LayoutSetup.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/Backend/LayoutSetup.php b/Classes/Backend/LayoutSetup.php index 3386f85..5e25e9f 100644 --- a/Classes/Backend/LayoutSetup.php +++ b/Classes/Backend/LayoutSetup.php @@ -469,10 +469,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); } } From f42b0afb59449fb072e2492546f9000ab615ddec Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Tue, 30 May 2017 21:21:14 +0200 Subject: [PATCH 054/102] [BUGFIX] Make paste as reference aware of shortcut restrictions Change-Id: Iffbabd31b2cb373b4d0e6144e102a5bacb1758f2 Resolves: #58571 Releases: 7-0 Reviewed-on: https://review.typo3.org/52972 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Resources/Public/JavaScript/GridElementsOnReady.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Public/JavaScript/GridElementsOnReady.js b/Resources/Public/JavaScript/GridElementsOnReady.js index d5d8ba5..1f083b3 100644 --- a/Resources/Public/JavaScript/GridElementsOnReady.js +++ b/Resources/Public/JavaScript/GridElementsOnReady.js @@ -229,7 +229,7 @@ define(['jquery', 'TYPO3/CMS/Backend/AjaxDataHandler', 'TYPO3/CMS/Backend/Storag } } ]; - if(top.pasteReferencesAllowed !== true) { + if(top.pasteReferenceAllowed !== true) { buttons.pop(); } } else { From 8f62947a29f1d52c16f332619d6fbe39db697601 Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Thu, 8 Jun 2017 12:25:47 +0200 Subject: [PATCH 055/102] [BUGFIX] Assign proper visibility to stay compatible to PHP 7 Change-Id: I5762d913f0709a22886f02d60788815ad647ea29 Resolves: #81511 Releases: master, 7-0 Reviewed-on: https://review.typo3.org/53169 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Slots/ExtTablesInclusionPostProcessing.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/Slots/ExtTablesInclusionPostProcessing.php b/Classes/Slots/ExtTablesInclusionPostProcessing.php index 983cb52..bf60871 100644 --- a/Classes/Slots/ExtTablesInclusionPostProcessing.php +++ b/Classes/Slots/ExtTablesInclusionPostProcessing.php @@ -37,7 +37,7 @@ class ExtTablesInclusionPostProcessing * * @return void */ - function processData($tca) + public function processData($tca) { // Move the local $tca to global variable to use general modification functions like addToAllTCAtypes $GLOBALS['TCA'] = $tca; From 92a2b677e1e8deb012046437c6240cffe743208b Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Thu, 15 Jun 2017 17:52:29 +0200 Subject: [PATCH 056/102] [BUGFIX] Empty remap stack and register DB list to avoid copying references Change-Id: I35c442015ad0cc07cb2da5f1fd0295ac782c1a26 Resolves: #80255 Releases: master, 7-0 Reviewed-on: https://review.typo3.org/53223 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/DataHandler/ProcessCmdmap.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Classes/DataHandler/ProcessCmdmap.php b/Classes/DataHandler/ProcessCmdmap.php index 7163e18..4eb2bca 100644 --- a/Classes/DataHandler/ProcessCmdmap.php +++ b/Classes/DataHandler/ProcessCmdmap.php @@ -83,6 +83,8 @@ public function execute_processCmdmap( $this->getTceMain()->start($data, array()); $this->getTceMain()->process_datamap(); + $parentObj->registerDBList = null; + $parentObj->remapStack = null; $commandIsProcessed = true; } From baac7d52ad35f68b7ce61bcd4d05a18edd0085c9 Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Tue, 11 Jul 2017 14:37:25 +0200 Subject: [PATCH 057/102] [TASK] Adjust composer.json due to packagist error messages Change-Id: I8f625cba789095c5c9ce024970fc533277fce02f Reviewed-on: https://review.typo3.org/53442 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- composer.json | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 8260f33..96a25df 100644 --- a/composer.json +++ b/composer.json @@ -17,9 +17,8 @@ "GridElementsTeam\\Gridelements\\": "Classes/" } }, - "extra": { - "branch-alias": { - "dev-master": "7.1.0" - } + "replace": { + "gridelements": "self.version", + "typo3-ter/gridelements": "self.version" } } \ No newline at end of file From 45df565f37a0554968fbaa8a5990cb86e3e53590 Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Tue, 11 Jul 2017 17:19:04 +0200 Subject: [PATCH 058/102] [TASK] Changed readme to contain branch specific information Change-Id: Ie3960493a65659cc148c33793b4dfe30e6421592 Reviewed-on: https://review.typo3.org/53446 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- README.md | 14 +++----------- README.txt | 2 -- 2 files changed, 3 insertions(+), 13 deletions(-) delete mode 100644 README.txt 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. From e013d8ad64d2af4ecda0aee427a9af7be91f8f0c Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Fri, 14 Jul 2017 22:08:23 +0200 Subject: [PATCH 059/102] [BUGFIX] Use correct icon identifier for history icon Change-Id: Ia8a35997bedde19294a22d9f75e775a5006c0e4c Resolves: Releases: 7-0 Reviewed-on: https://review.typo3.org/53486 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Xclass/DatabaseRecordList.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/Xclass/DatabaseRecordList.php b/Classes/Xclass/DatabaseRecordList.php index dd22ba1..3d316d1 100644 --- a/Classes/Xclass/DatabaseRecordList.php +++ b/Classes/Xclass/DatabaseRecordList.php @@ -1442,7 +1442,7 @@ public function makeControl($table, $row) ]); $versionAction = '' - . $this->iconFactory->getIcon('actions-version-open', Icon::SIZE_SMALL)->render() . ''; + . $this->iconFactory->getIcon('actions-version-page-open', Icon::SIZE_SMALL)->render() . ''; $this->addActionToCellGroup($cells, $versionAction, 'version'); } } From 82a00d27c974c29925bc59552301b2616db767c6 Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Tue, 18 Jul 2017 17:53:42 +0200 Subject: [PATCH 060/102] [TASK] Adjust d&d classes to match current state of the core Change-Id: Ic9cb70082db4665ee0f1aa39cb6a09433a4e0820 Reviewed-on: https://review.typo3.org/53541 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Resources/Public/JavaScript/GridElementsDragInWizard.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Public/JavaScript/GridElementsDragInWizard.js b/Resources/Public/JavaScript/GridElementsDragInWizard.js index 8e71b28..110f0bb 100644 --- a/Resources/Public/JavaScript/GridElementsDragInWizard.js +++ b/Resources/Public/JavaScript/GridElementsDragInWizard.js @@ -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(); }; From 7041a33adba0cc785e3d6573613aa2651db6f1c6 Mon Sep 17 00:00:00 2001 From: Markus Klein Date: Mon, 28 Aug 2017 10:53:38 +0200 Subject: [PATCH 061/102] [BUGFIX] Make sure the layout field for the CE is visible In case FSC is used the layout field has to be added directly to TCA as the 'frames' palette of CSC is not present, which usually adds the layout field. Change-Id: Ib6c5ce2d8f4e20bfb518a66398d5b722c30a9e0b Releases: 7-0 Resolves: #82224 Reviewed-on: https://review.typo3.org/53818 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Configuration/TCA/Overrides/tt_content.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Configuration/TCA/Overrides/tt_content.php b/Configuration/TCA/Overrides/tt_content.php index 597535a..74ddbd7 100644 --- a/Configuration/TCA/Overrides/tt_content.php +++ b/Configuration/TCA/Overrides/tt_content.php @@ -104,6 +104,10 @@ $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:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.general;general, --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.header;header, @@ -111,7 +115,7 @@ pi_flexform, tx_gridelements_children, --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.appearance, - --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.frames;frames, + ' . $frames . ', media, --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, From 1308820a28e3c23b836a8611fdbb2cb9754a9f74 Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Sun, 3 Dec 2017 17:39:54 +0100 Subject: [PATCH 062/102] Make sure SOBE is page layout controller before using particular methods Releases: master, 8-0, 7-0 Resolves: #81938 Change-Id: Idbe36ab0b57996f3c75f7100871621ba5f68f0ba Reviewed-on: https://review.typo3.org/54919 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Hooks/DrawItem.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Classes/Hooks/DrawItem.php b/Classes/Hooks/DrawItem.php index b40ea1c..a8bc4f3 100644 --- a/Classes/Hooks/DrawItem.php +++ b/Classes/Hooks/DrawItem.php @@ -450,8 +450,13 @@ 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()->contentIsNotLockedForEditors() + if ($contentIsNotLockedForEditors && $this->getBackendUser()->doesUserHaveAccess($pageinfo, Permission::CONTENT_EDIT) && (!$this->checkIfTranslationsExistInLanguage($items, $row['sys_language_uid'], $parentObject)) ) { @@ -525,7 +530,7 @@ protected function renderSingleGridColumn(
    ' . $this->renderSingleElementHTML($parentObject, $itemRow) . '
    '; - if ($this->getPageLayoutController()->contentIsNotLockedForEditors() + if ($contentIsNotLockedForEditors && $this->getBackendUser()->doesUserHaveAccess($pageinfo, Permission::CONTENT_EDIT) && (!$this->checkIfTranslationsExistInLanguage($items, $row['sys_language_uid'], $parentObject)) ) { From 676b3ee0c22a130148180a7b3bf3a95e99eb7360 Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Sat, 16 Dec 2017 14:13:29 +0100 Subject: [PATCH 063/102] [BUGFIX] Adjust colspan of pagination cells to match colgroup columns Change-Id: I44184b6b26b24b843208a9b4215882e407607411 Resolves: #82961 Releases: 7-0 Reviewed-on: https://review.typo3.org/55118 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Xclass/DatabaseRecordList.php | 31 +++++++++++++++++++++------ 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/Classes/Xclass/DatabaseRecordList.php b/Classes/Xclass/DatabaseRecordList.php index 3d316d1..b953a07 100644 --- a/Classes/Xclass/DatabaseRecordList.php +++ b/Classes/Xclass/DatabaseRecordList.php @@ -147,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 * @@ -873,6 +880,8 @@ public function getTable($table, $id, $rowList = '') // 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) { @@ -895,8 +904,6 @@ public function getTable($table, $id, $rowList = '') '; } } - // The header row for the table is now created: - $out .= $this->renderListHeader($table, $this->currentIdList); } $collapseClass = $tableCollapsed && !$this->table ? 'collapse' : 'collapse in'; @@ -1205,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 { @@ -1341,7 +1349,7 @@ function calculatePointer(page) { ' ]; - return $this->addElement(1, '', $data); + return $this->addElement(1, '', $data, '', '', '', 'pagination'); } /********************************* @@ -2060,7 +2068,12 @@ 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; @@ -2100,7 +2113,7 @@ public function addElement($h, $icon, $data, $rowParams = '', $_ = '', $_2 = '', // Show icon and lines if ($this->showIcon) { $out .= ' - <' . $colType . ' nowrap="nowrap" class="col-icon"' . ($colType === 'th' ? ' colspan="' . ($this->maxDepth - $level) . '"' : ' colspan="' . ($this->maxDepth - $level - 1) . '"') . '>'; + <' . $colType . ' nowrap="nowrap" class="col-icon"' . ($colType === 'th' ? ' colspan="' . ($this->maxDepth - $level) . '"' : '') . '>'; if (!$h) { $out .= ' '; } else { @@ -2151,8 +2164,12 @@ public function addElement($h, $icon, $data, $rowParams = '', $_ = '', $_2 = '', if (count($data) == 1) { $c++; } - if ($c > 1) { + 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 = ''; } From 5606cfb0469da789868d476e0850b310ca92333f Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Sat, 16 Dec 2017 14:45:45 +0100 Subject: [PATCH 064/102] [BUGFIX] Make sure to use both array and integer depending on context Change-Id: Ic7d13e24279b58078bc0825015d61f8384a122c3 Resolves: #79917 Releases: 7-0 Reviewed-on: https://review.typo3.org/55120 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Backend/TtContent.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Classes/Backend/TtContent.php b/Classes/Backend/TtContent.php index eca8792..9afe399 100644 --- a/Classes/Backend/TtContent.php +++ b/Classes/Backend/TtContent.php @@ -192,8 +192,7 @@ public function deleteUnallowedContainer(array &$params, $itemUidList = '') public function layoutItemsProcFunc(array &$params) { $this->init($params['row']['pid']); - $layoutSelectItems = $this->layoutSetup->getLayoutSelectItems($params['row']['colPos']); - + $layoutSelectItems = $this->layoutSetup->getLayoutSelectItems($params['row']['colPos'][0] ?: $params['row']['colPos']); $params['items'] = ArrayUtility::keepItemsInArray($layoutSelectItems, $params['items'], true); } From c2b2cc32167ea0b8e09edeb3b66d3efa4e68b62d Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Tue, 19 Dec 2017 16:31:21 +0100 Subject: [PATCH 065/102] [BUGFIX] Respect containers with language set to "all" Change-Id: I4dbdbfa9d673366886367097cd6d51ce8d0fbbe9 Resolves: #83310 Releases: 7-0 Reviewed-on: https://review.typo3.org/55161 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/DataHandler/AbstractDataHandler.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Classes/DataHandler/AbstractDataHandler.php b/Classes/DataHandler/AbstractDataHandler.php index 30ba225..c127cb1 100644 --- a/Classes/DataHandler/AbstractDataHandler.php +++ b/Classes/DataHandler/AbstractDataHandler.php @@ -232,9 +232,11 @@ public function checkAndUpdateTranslatedElements($uid) 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']; } $updateArray['colPos'] = (int)$currentValues['colPos']; - $this->databaseConnection->exec_UPDATEquery('tt_content', 'uid=' . (int)$translatedUid, $updateArray, 'tx_gridelements_container,tx_gridelements_columns,colPos' From e949da6c619f4b8c59c1e1788b02ee7b132cb84c Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Fri, 22 Dec 2017 10:50:50 +0100 Subject: [PATCH 066/102] [BUGFIX] Check for original container before trying to do container update Change-Id: I221ff32f2752206316023c99a63ca0b24a015e2c --- Classes/DataHandler/ProcessCmdmap.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Classes/DataHandler/ProcessCmdmap.php b/Classes/DataHandler/ProcessCmdmap.php index 4eb2bca..6bb9076 100644 --- a/Classes/DataHandler/ProcessCmdmap.php +++ b/Classes/DataHandler/ProcessCmdmap.php @@ -93,8 +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 From 3b6cf4188d008be6a16eeda1d2dc3caad2ae3f76 Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Fri, 22 Dec 2017 16:24:15 +0100 Subject: [PATCH 067/102] [BUGFIX] Make sure allowed gridelements_pi1 works when set without gridtype Change-Id: Ic38d5454d0c0fa17542d4c48547232f5bbf45280 Resolves: #78141 Releases: 7-0 Reviewed-on: https://review.typo3.org/55200 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Resources/Public/JavaScript/GridElementsDragDrop.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Resources/Public/JavaScript/GridElementsDragDrop.js b/Resources/Public/JavaScript/GridElementsDragDrop.js index f023313..cc31919 100644 --- a/Resources/Public/JavaScript/GridElementsDragDrop.js +++ b/Resources/Public/JavaScript/GridElementsDragDrop.js @@ -96,7 +96,8 @@ define(['jquery', 'jquery-ui/sortable', 'jquery-ui/droppable'], function ($) { 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-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); From 01786f5e6e142aaff6d32e3dbe58f0f2c1f47a05 Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Fri, 22 Dec 2017 16:37:36 +0100 Subject: [PATCH 068/102] [BUGFIX] fetch CType and gridType when dragging in elements via wizard Change-Id: I64280c48dbfe45847f1bb869631e214fd7b3a0e6 Resolves: #79611 Releases: 7-0 Reviewed-on: https://review.typo3.org/55201 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- .../Public/JavaScript/GridElementsDragInWizard.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Resources/Public/JavaScript/GridElementsDragInWizard.js b/Resources/Public/JavaScript/GridElementsDragInWizard.js index 110f0bb..a202e78 100644 --- a/Resources/Public/JavaScript/GridElementsDragInWizard.js +++ b/Resources/Public/JavaScript/GridElementsDragInWizard.js @@ -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() From bf59ee5ebd93b3effe201547e7a1308d0bdb205b Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Fri, 22 Dec 2017 10:31:10 +0100 Subject: [PATCH 069/102] [TASK] Make sure that child elements of containers get correct colPos Change-Id: I981dfd46d6ad402398fb79d225cd937e43dcd3ca Resolves: #80838 Releases: 7-0 Reviewed-on: https://review.typo3.org/55195 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/DataHandler/AfterDatabaseOperations.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Classes/DataHandler/AfterDatabaseOperations.php b/Classes/DataHandler/AfterDatabaseOperations.php index 193fb7e..fb75912 100644 --- a/Classes/DataHandler/AfterDatabaseOperations.php +++ b/Classes/DataHandler/AfterDatabaseOperations.php @@ -49,7 +49,7 @@ class AfterDatabaseOperations extends AbstractDataHandler */ public function execute_afterDatabaseOperations(array &$fieldArray, $table, $uid, DataHandler $parentObj) { - if ($table === 'tt_content') { + if ($table === 'tt_content' || $table === 'pages') { $this->init($table, $uid, $parentObj); if (!$this->getTceMain()->isImporting) { $this->saveCleanedUpFieldArray($fieldArray); @@ -95,7 +95,7 @@ public function setUnusedElements(array &$fieldArray) $this->getPageUid()); 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->getPageUid() . ' AND tx_gridelements_columns NOT IN (' . $availableColumns . ')', '', '', '', 'uid')); if (!empty($childElementsInUnavailableColumns)) { $this->databaseConnection->sql_query(' @@ -107,7 +107,7 @@ public function setUnusedElements(array &$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->getPageUid() . ' AND tx_gridelements_columns IN (' . $availableColumns . ')', '', '', '', 'uid')); if (!empty($childElementsInAvailableColumns)) { $this->databaseConnection->sql_query(' @@ -274,11 +274,11 @@ public function getSubpagesRecursively($pageUid, array &$subpages) */ public function getAvailableColumns($layout = '', $table = '', $id = 0) { - $tcaColumns = array(); + $tcaColumns = ''; if ($layout && $table === 'tt_content') { $tcaColumns = $this->layoutSetup->getLayoutColumns($layout); - $tcaColumns = $tcaColumns['CSV']; + $tcaColumns = '-2,-1,' . $tcaColumns['CSV']; } elseif ($table === 'pages') { $tcaColumns = GeneralUtility::callUserFunction(BackendLayoutView::class . '->getColPosListItemsParsed', $id, $this); From 0a0f847666bd5685077ad698f9a8d330dd2b25eb Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Sat, 23 Dec 2017 18:06:31 +0100 Subject: [PATCH 070/102] [TASK] Adjust documentaion and increase version number before release Change-Id: Iaa6bd9014c3da1237b582bd5343a3739bf702ea7 --- Documentation/Chapters/Faq/Index.rst | 3 +- Documentation/Chapters/GridTsSyntax/Index.rst | 2 +- Documentation/Chapters/Installation/Index.rst | 2 +- Documentation/Chapters/Introduction/Index.rst | 8 +- Documentation/Chapters/Tsconfig/Index.rst | 32 +++++++- Documentation/Chapters/Typoscript/Index.rst | 5 +- .../Chapters/Typoscript/Reference/Index.rst | 76 ++++++++++++++++--- Documentation/Index.rst | 59 +++++++------- .../Public/JavaScript/GridElementsDragDrop.js | 1 + .../Public/JavaScript/GridElementsOnReady.js | 2 +- composer.json | 2 +- ext_emconf.php | 2 +- 12 files changed, 133 insertions(+), 61 deletions(-) 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/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/Index.rst b/Documentation/Index.rst index cb85579..21d141f 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,52 @@ 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/Notes/Index diff --git a/Resources/Public/JavaScript/GridElementsDragDrop.js b/Resources/Public/JavaScript/GridElementsDragDrop.js index cc31919..83913b1 100644 --- a/Resources/Public/JavaScript/GridElementsDragDrop.js +++ b/Resources/Public/JavaScript/GridElementsDragDrop.js @@ -265,6 +265,7 @@ define(['jquery', 'jquery-ui/sortable', 'jquery-ui/droppable'], function ($) { } 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) { diff --git a/Resources/Public/JavaScript/GridElementsOnReady.js b/Resources/Public/JavaScript/GridElementsOnReady.js index 1f083b3..314d9b0 100644 --- a/Resources/Public/JavaScript/GridElementsOnReady.js +++ b/Resources/Public/JavaScript/GridElementsOnReady.js @@ -266,7 +266,7 @@ define(['jquery', 'TYPO3/CMS/Backend/AjaxDataHandler', 'TYPO3/CMS/Backend/Storag * 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 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'); diff --git a/composer.json b/composer.json index 96a25df..f12886c 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "keywords": ["TYPO3 CMS", "Grids", "Gridelements"], "homepage": "https://forge.typo3.org/projects/extension-gridelements2", "license": "GPL-2.0+", - "version": "7.1.0", + "version": "7.2.0", "support": { "issues": "https://forge.typo3.org/" }, diff --git a/ext_emconf.php b/ext_emconf.php index 7759a57..bbc40fb 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -13,7 +13,7 @@ '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' => '7.1.0', + 'version' => '7.2.0', 'priority' => 'bottom', 'module' => '', 'state' => 'beta', From 2750145f5950c435d98227e507dcc9edca949ab3 Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Sat, 23 Dec 2017 18:19:16 +0100 Subject: [PATCH 071/102] [TASK] Prepare maintenance release for issue 80838 Change-Id: I9d82b8bbd8dfc0d48da31f5ec3f0279dec7fabdf --- composer.json | 2 +- ext_emconf.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index f12886c..6ed58d1 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "keywords": ["TYPO3 CMS", "Grids", "Gridelements"], "homepage": "https://forge.typo3.org/projects/extension-gridelements2", "license": "GPL-2.0+", - "version": "7.2.0", + "version": "7.2.1", "support": { "issues": "https://forge.typo3.org/" }, diff --git a/ext_emconf.php b/ext_emconf.php index bbc40fb..01c11a0 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -13,7 +13,7 @@ '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' => '7.2.0', + 'version' => '7.2.1', 'priority' => 'bottom', 'module' => '', 'state' => 'beta', From 0d6f028f4af6b36e514e9d38076b9b217b59181a Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Thu, 28 Dec 2017 13:31:12 +0100 Subject: [PATCH 072/102] [TASK] Enable alphanumeric frame values for extension like t3ddy Change-Id: I249dc54443bd944f3cf8d3659f3d4da8c7f9427d Resolves: #83441 Releases: 7-0 Reviewed-on: https://review.typo3.org/55228 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Hooks/DrawItem.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/Hooks/DrawItem.php b/Classes/Hooks/DrawItem.php index a8bc4f3..53c6dac 100644 --- a/Classes/Hooks/DrawItem.php +++ b/Classes/Hooks/DrawItem.php @@ -672,9 +672,9 @@ public function renderGridLayoutTable($layoutSetup, $row, $head, $gridContent) { $specificIds = $this->helper->getSpecificIds($row); - $grid = '
    '; + $grid = '
    '; if ($layoutSetup['frame'] || $this->helper->getBackendUser()->uc['showGridInformation'] === 1) { - $grid .= '

    ' . BackendUtility::wrapInHelp('tx_gridelements_backend_layouts', + $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']) From 9edcd953038c2832966b8b39713a316e82ec514d Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Thu, 28 Dec 2017 13:20:09 +0100 Subject: [PATCH 073/102] [BUGFIX] Adjust translations to match columns and container of l18n_parent Change-Id: I6853b1d3f98b683f3fd2f8bd543cada2da37a786 Resolves: #83411 Releases: 7-0 Reviewed-on: https://review.typo3.org/55226 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/DataHandler/AbstractDataHandler.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Classes/DataHandler/AbstractDataHandler.php b/Classes/DataHandler/AbstractDataHandler.php index c127cb1..2d3679f 100644 --- a/Classes/DataHandler/AbstractDataHandler.php +++ b/Classes/DataHandler/AbstractDataHandler.php @@ -235,6 +235,9 @@ public function checkAndUpdateTranslatedElements($uid) } 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; } $updateArray['colPos'] = (int)$currentValues['colPos']; $this->databaseConnection->exec_UPDATEquery('tt_content', 'uid=' . (int)$translatedUid, From 68951d169ac411959f1ac33ff5663561c2383e1a Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Tue, 9 Jan 2018 12:12:20 +0100 Subject: [PATCH 074/102] [BUGFIX] Remove trailing or leading comma from CSV list of columns Resolves: #83514 Releases: 7-0 Change-Id: If154c64f884376f356238909f671caf27204aff4 Reviewed-on: https://review.typo3.org/55304 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/DataHandler/AfterDatabaseOperations.php | 4 ++-- Classes/Plugin/Gridelements.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Classes/DataHandler/AfterDatabaseOperations.php b/Classes/DataHandler/AfterDatabaseOperations.php index fb75912..1d3f8fb 100644 --- a/Classes/DataHandler/AfterDatabaseOperations.php +++ b/Classes/DataHandler/AfterDatabaseOperations.php @@ -278,7 +278,7 @@ public function getAvailableColumns($layout = '', $table = '', $id = 0) if ($layout && $table === 'tt_content') { $tcaColumns = $this->layoutSetup->getLayoutColumns($layout); - $tcaColumns = '-2,-1,' . $tcaColumns['CSV']; + $tcaColumns = rtrim('-2,-1,' . $tcaColumns['CSV'], ','); } elseif ($table === 'pages') { $tcaColumns = GeneralUtility::callUserFunction(BackendLayoutView::class . '->getColPosListItemsParsed', $id, $this); @@ -289,7 +289,7 @@ public function getAvailableColumns($layout = '', $table = '', $id = 0) } } // Implode into a CSV string as BackendLayoutView->getColPosListItemsParsed returns an array - $tcaColumns = '-2,-1,' . implode(',', $temp); + $tcaColumns = rtrim('-2,-1,' . implode(',', $temp), ','); } return $tcaColumns; diff --git a/Classes/Plugin/Gridelements.php b/Classes/Plugin/Gridelements.php index 46d1e1b..633eb08 100644 --- a/Classes/Plugin/Gridelements.php +++ b/Classes/Plugin/Gridelements.php @@ -100,7 +100,7 @@ public function main($content = '', $conf = array()) $layoutSetup->init($this->cObj->data['pid'], $conf); $availableColumns = $layoutSetup->getLayoutColumns($layout); - $csvColumns = str_replace('-2,-1,', '', $availableColumns['CSV']); + $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 From b06152ec0f16e783571097644400b471e0435697 Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Wed, 10 Jan 2018 16:28:52 +0100 Subject: [PATCH 075/102] [TASK] Remove superfluous leading -2,-1, from CSV values Change-Id: I1f45fd41f03898a8670bd88f93126f54cfa1b65c Reviewed-on: https://review.typo3.org/55324 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/DataHandler/AfterDatabaseOperations.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/DataHandler/AfterDatabaseOperations.php b/Classes/DataHandler/AfterDatabaseOperations.php index 1d3f8fb..3635046 100644 --- a/Classes/DataHandler/AfterDatabaseOperations.php +++ b/Classes/DataHandler/AfterDatabaseOperations.php @@ -278,7 +278,7 @@ public function getAvailableColumns($layout = '', $table = '', $id = 0) if ($layout && $table === 'tt_content') { $tcaColumns = $this->layoutSetup->getLayoutColumns($layout); - $tcaColumns = rtrim('-2,-1,' . $tcaColumns['CSV'], ','); + $tcaColumns = $tcaColumns['CSV']; } elseif ($table === 'pages') { $tcaColumns = GeneralUtility::callUserFunction(BackendLayoutView::class . '->getColPosListItemsParsed', $id, $this); From 6f1651ef87b67899d71f71844614832090b88a6f Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Wed, 10 Jan 2018 21:34:48 +0100 Subject: [PATCH 076/102] [BUGFIX] Switch horizontal grids from inline-block to table-cell Change-Id: I00e2df442ea66ec0e8e495b7f817ef5547f20a22 Resolves: #83530 Releases: 7-0 Reviewed-on: https://review.typo3.org/55330 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- .../Backend/Css/Skin/t3skin_override.css | 39 +++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/Resources/Public/Backend/Css/Skin/t3skin_override.css b/Resources/Public/Backend/Css/Skin/t3skin_override.css index 4bcee75..408f26c 100644 --- a/Resources/Public/Backend/Css/Skin/t3skin_override.css +++ b/Resources/Public/Backend/Css/Skin/t3skin_override.css @@ -391,11 +391,44 @@ display: block; } -.t3-grid-cell-horizontal { - white-space: nowrap; +.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: inline-block; + 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 From ccd28f1136fe3959aaf454c7003d2e579a444a1e Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Wed, 10 Jan 2018 14:54:08 +0100 Subject: [PATCH 077/102] [BUGFIX] Remove superfluous addCssFile calls in favor of TBE_STYLES Change-Id: I4b69d0c9ce3da8f0315e9a82e0ba018432756c26 Resolves: #83515 Releases: 7-0 Reviewed-on: https://review.typo3.org/55323 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Hooks/PageRenderer.php | 1 - Classes/Hooks/PreHeaderRenderHook.php | 41 -------------- ext_tables.php | 79 +++++++++++++-------------- 3 files changed, 39 insertions(+), 82 deletions(-) delete mode 100644 Classes/Hooks/PreHeaderRenderHook.php diff --git a/Classes/Hooks/PageRenderer.php b/Classes/Hooks/PageRenderer.php index fffc0a1..a63b66d 100644 --- a/Classes/Hooks/PageRenderer.php +++ b/Classes/Hooks/PageRenderer.php @@ -47,7 +47,6 @@ class PageRenderer implements SingletonInterface */ 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']) === RecordList::class || is_subclass_of($GLOBALS['SOBE'], RecordList::class)) { $pageRenderer->loadRequireJsModule('TYPO3/CMS/Gridelements/GridElementsOnReady'); return; diff --git a/Classes/Hooks/PreHeaderRenderHook.php b/Classes/Hooks/PreHeaderRenderHook.php deleted file mode 100644 index 3cf4aa1..0000000 --- a/Classes/Hooks/PreHeaderRenderHook.php +++ /dev/null @@ -1,41 +0,0 @@ - - * 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\SingletonInterface; -use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; - -/** - * Class PreHeaderRenderHook - * - * @package GridElementsTeam\Gridelements\Hooks - */ -class PreHeaderRenderHook implements SingletonInterface -{ - /** - * @param array $arg - */ - function main(array $arg) - { - /** @var \TYPO3\CMS\Core\Page\PageRenderer $pagerenderer */ - $pagerenderer = $arg['pageRenderer']; - $pagerenderer->addCssFile(ExtensionManagementUtility::extRelPath('gridelements') . 'Resources/Public/Backend/Css/Skin/t3skin_override.css'); - } -} diff --git a/ext_tables.php b/ext_tables.php index a67ac78..7a6eb4b 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,57 +15,61 @@ 'gridelements-default' ), 'CType'); -// 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'; +if (TYPO3_MODE == 'BE') { + + \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_gridelements_backend_layout'); + include_once(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('gridelements') . 'Classes/Backend/TtContent.php'); + // 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_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']['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; + $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_USER_SETTINGS']['columns']['dragAndDropHideNewElementWizardInfoOverlay'] = array( + 'type' => 'check', + 'label' => 'LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:dragAndDropHideNewElementWizardInfoOverlay' + ); -$GLOBALS['TYPO3_USER_SETTINGS']['columns']['dragAndDropHideNewElementWizardInfoOverlay'] = array( - 'type' => 'check', - 'label' => 'LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:dragAndDropHideNewElementWizardInfoOverlay' -); + $GLOBALS['TYPO3_USER_SETTINGS']['columns']['hideColumnHeaders'] = array( + 'type' => 'check', + 'label' => 'LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:hideColumnHeaders' + ); -$GLOBALS['TYPO3_USER_SETTINGS']['columns']['hideColumnHeaders'] = array( - 'type' => 'check', - 'label' => 'LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:hideColumnHeaders' -); + $GLOBALS['TYPO3_USER_SETTINGS']['columns']['hideContentPreview'] = array( + 'type' => 'check', + 'label' => 'LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:hideContentPreview' + ); -$GLOBALS['TYPO3_USER_SETTINGS']['columns']['hideContentPreview'] = array( - 'type' => 'check', - 'label' => 'LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:hideContentPreview' -); + $GLOBALS['TYPO3_USER_SETTINGS']['columns']['showGridInformation'] = array( + 'type' => 'check', + 'label' => 'LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:showGridInformation' + ); -$GLOBALS['TYPO3_USER_SETTINGS']['columns']['showGridInformation'] = array( - 'type' => 'check', - 'label' => 'LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:showGridInformation' -); + $GLOBALS['TYPO3_USER_SETTINGS']['showitem'] .= ',--div--;LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:gridElements,dragAndDropHideNewElementWizardInfoOverlay,hideColumnHeaders,hideContentPreview,showGridInformation'; -$GLOBALS['TYPO3_USER_SETTINGS']['showitem'] .= ',--div--;LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:gridElements,dragAndDropHideNewElementWizardInfoOverlay,hideColumnHeaders,hideContentPreview,showGridInformation'; + $GLOBALS['TBE_STYLES']['skins']['gridelements']['name'] = 'gridelements'; + $GLOBALS['TBE_STYLES']['skins']['gridelements']['stylesheetDirectories']['structure'] = 'EXT:' . ($_EXTKEY) . '/Resources/Public/Backend/Css/Skin/'; -$TBE_STYLES['skins']['gridelements']['name'] = 'gridelements'; -$TBE_STYLES['skins']['gridelements']['stylesheetDirectories']['structure'] = 'EXT:' . ($_EXTKEY) . '/Resources/Public/Backend/Css/Skin/'; + $GLOBALS['TBE_MODULES_EXT']['xMOD_alt_clickmenu']['extendCMclasses'][] = array('name' => 'GridElementsTeam\\Gridelements\\Backend\\ClickMenuOptions',); -$GLOBALS['TBE_MODULES_EXT']['xMOD_alt_clickmenu']['extendCMclasses'][] = array('name' => 'GridElementsTeam\\Gridelements\\Backend\\ClickMenuOptions',); +} -$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preHeaderRenderHook'][] = 'GridElementsTeam\\Gridelements\\Hooks\\PreHeaderRenderHook->main'; +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'; +} $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( From 2d6547cfc2ab2108eecd472369a5908f0f0d855f Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Mon, 29 Jan 2018 18:57:27 +0100 Subject: [PATCH 078/102] [TASK] replace deprecated SPDX license identifier for packagist Change-Id: I8d49ddbd21b80ff2ba13e8442a49d0d86e34a01c --- Resources/Public/Backend/Css/grideditor.css | 220 -------------------- composer.json | 2 +- 2 files changed, 1 insertion(+), 221 deletions(-) delete mode 100644 Resources/Public/Backend/Css/grideditor.css diff --git a/Resources/Public/Backend/Css/grideditor.css b/Resources/Public/Backend/Css/grideditor.css deleted file mode 100644 index 85108ec..0000000 --- a/Resources/Public/Backend/Css/grideditor.css +++ /dev/null @@ -1,220 +0,0 @@ -* { - padding: 0; - margin: 0; - position: relative; -} - -body { - padding: 10px; -} - -table#outer_container td, table#editor td { - vertical-align: middle; - padding: 0px 10px 10px 0px; -} - -table#outer_container td.editor_cell { - height: 100%; -} - -table.editor { - border-right: 1px gray dashed; - border-bottom: 1px gray dashed; -} - -table.editor td { - border-top: 1px gray dashed; - border-left: 1px gray dashed; - text-align: center; - z-index: 2000; - background-color: white; - min-height: 100px; -} - -div#editor { - height: 100%; -} - -div.cell_container { - width: 60px; - height: 60px; - position: relative; - left: 50%; - margin-left: -30px; - opacity: 0.3; -} - -div.cell_container:hover { - opacity: 1; -} - -.link_expand_right, .link_shrink_left, .link_expand_down, .link_shrink_up, .link_editor { - display: block; - position: absolute; - width: 14px; - height: 32px; - z-index: 1100; -} - -.link_expand_down, .link_shrink_up { - width: 32px; - height: 14px; -} - -.link_expand_right { - left: 46px; - top: 14px; -} - -.link_expand_right:hover { -} - -.link_shrink_left { - left: 0px; - top: 14px; -} - -.link_shrink_left:hover { -} - -.link_expand_down { - left: 14px; - top: 46px; -} - -.link_expand_down:hover { -} - -.link_shrink_up { - left: 14px; - top: 0px; -} - -.link_shrink_up:hover { -} - -.link_editor { - width: 32px; - height: 32px; - left: 14px; - top: 14px; -} - -.link_editor:hover { -} - -.question { -} - -.save { -} - -.cancel { -} - -table#outer_container td, table#editor td { - vertical-align: middle; -} - -table#outer_container td.editor_cell { - height: 100%; -} - -table.editor { - border-right: 1px gray dashed; - border-bottom: 1px gray dashed; -} - -table.editor td { - border-top: 1px gray dashed; - border-left: 1px gray dashed; - text-align: center; - z-index: 2000; - background-color: white; - min-height: 100px; -} - -div#editor { - height: 100%; -} - -div.cell_container { - width: 60px; - height: 60px; - position: relative; - left: 50%; - margin-left: -30px; - opacity: 0.3; -} - -div.cell_container:hover { - opacity: 1; -} - -.link_expand_right, .link_shrink_left, .link_expand_down, .link_shrink_up, .link_editor { - display: block; - position: absolute; - width: 14px; - height: 32px; - z-index: 1100; -} - -.link_expand_down, .link_shrink_up { - width: 32px; - height: 14px; -} - -.link_expand_right { - left: 46px; - top: 14px; -} - -.link_expand_right:hover { -} - -.link_shrink_left { - left: 0px; - top: 14px; -} - -.link_shrink_left:hover { -} - -.link_expand_down { - left: 14px; - top: 46px; -} - -.link_expand_down:hover { -} - -.link_shrink_up { - left: 14px; - top: 0px; -} - -.link_shrink_up:hover { -} - -.link_editor { - width: 32px; - height: 32px; - left: 14px; - top: 14px; -} - -.link_editor:hover { -} - -.question { -} - -.save { -} - -.cancel { -} - -.x-fieldset-body { - padding-bottom: 50px; -} \ No newline at end of file diff --git a/composer.json b/composer.json index 6ed58d1..89ba69f 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "type": "typo3-cms-extension", "keywords": ["TYPO3 CMS", "Grids", "Gridelements"], "homepage": "https://forge.typo3.org/projects/extension-gridelements2", - "license": "GPL-2.0+", + "license": "GPL-2.0-or-later", "version": "7.2.1", "support": { "issues": "https://forge.typo3.org/" From eb0f7abec58dd991e7b94f0cbaa9bc0c6d1f9363 Mon Sep 17 00:00:00 2001 From: Xavier Perseguers Date: Thu, 1 Mar 2018 10:54:45 +0100 Subject: [PATCH 079/102] [BUGFIX] Check for NULL before accessing class to avoid errors w PHP 7.2 Change-Id: Ic0881a0247544e55ebc249954e5cc175386d8366 Resolves: #83587 Releases: master, 8-0, 7-0 Reviewed-on: https://review.typo3.org/55962 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Hooks/PageRenderer.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Classes/Hooks/PageRenderer.php b/Classes/Hooks/PageRenderer.php index a63b66d..48a3b93 100644 --- a/Classes/Hooks/PageRenderer.php +++ b/Classes/Hooks/PageRenderer.php @@ -47,11 +47,13 @@ class PageRenderer implements SingletonInterface */ public function addJSCSS(array $parameters, \TYPO3\CMS\Core\Page\PageRenderer $pageRenderer) { - if (get_class($GLOBALS['SOBE']) === RecordList::class || is_subclass_of($GLOBALS['SOBE'], RecordList::class)) { + 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']) === PageLayoutController::class || is_subclass_of($GLOBALS['SOBE'], PageLayoutController::class)) { + 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'); From 4cfd6b880cf550083929037bff5e5600091d8cdf Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Fri, 16 Mar 2018 14:16:30 +0100 Subject: [PATCH 080/102] [FEATURE] Restrict referenced content to column language if configured Change-Id: Ied25fa92f45eb263580934449a741126e11a42bd Resolves: #84246 Release: 7-0 Reviewed-on: https://review.typo3.org/56223 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Hooks/DrawItem.php | 31 ++++++++++++++++++++---- Resources/Private/Language/locallang.xlf | 3 +++ ext_conf_template.txt | 3 +++ ext_tables.php | 6 +++-- 4 files changed, 36 insertions(+), 7 deletions(-) diff --git a/Classes/Hooks/DrawItem.php b/Classes/Hooks/DrawItem.php index 53c6dac..5efd168 100644 --- a/Classes/Hooks/DrawItem.php +++ b/Classes/Hooks/DrawItem.php @@ -50,6 +50,11 @@ class DrawItem implements PageLayoutViewDrawItemHookInterface, SingletonInterface { + /** + * @var array + */ + protected $extentensionConfiguration; + /** * @var Helper */ @@ -89,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(); @@ -240,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)) { @@ -765,6 +771,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 */ @@ -774,7 +781,8 @@ public function collectContentDataFromPages( $recursive = 0, &$showHidden, &$deleteClause, - $parentUid + $parentUid, + $language = 0 ) { $itemList = str_replace('pages_', '', $shortcutItem); if ($recursive) { @@ -785,8 +793,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); } @@ -803,15 +817,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); } 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/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_tables.php b/ext_tables.php index 7a6eb4b..97ee7a6 100644 --- a/ext_tables.php +++ b/ext_tables.php @@ -59,8 +59,10 @@ $GLOBALS['TYPO3_USER_SETTINGS']['showitem'] .= ',--div--;LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:gridElements,dragAndDropHideNewElementWizardInfoOverlay,hideColumnHeaders,hideContentPreview,showGridInformation'; $GLOBALS['TBE_STYLES']['skins']['gridelements']['name'] = 'gridelements'; - $GLOBALS['TBE_STYLES']['skins']['gridelements']['stylesheetDirectories']['structure'] = 'EXT:' . ($_EXTKEY) . '/Resources/Public/Backend/Css/Skin/'; - + $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',); } From b4e22df7429eb9c8e9ca316f2274b8fa951d9e83 Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Fri, 16 Mar 2018 17:50:37 +0100 Subject: [PATCH 081/102] [BUGFIX] Use label for unassigned columns Change-Id: I612dd7c26db3e7cce7ede1f471860f05760255c4 Resolves: #84049 Release: 7-0 Reviewed-on: https://review.typo3.org/56244 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Hooks/DrawItem.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Classes/Hooks/DrawItem.php b/Classes/Hooks/DrawItem.php index 5efd168..a599d6c 100644 --- a/Classes/Hooks/DrawItem.php +++ b/Classes/Hooks/DrawItem.php @@ -215,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 .= ''; @@ -671,10 +671,11 @@ 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); @@ -747,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 .= ''; From e63b18fdfb9a717f97f303e35581781d597165ef Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Mon, 19 Mar 2018 21:41:32 +0100 Subject: [PATCH 082/102] [BUGFIX] Fix shortcut rendering for shortcuts to page(s) Change-Id: I531c9292b876beb1c0de15fff1c36446b9c91474 Resolves: #84489 Releases: master, 8-0, 7-0 Reviewed-on: https://review.typo3.org/56374 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Configuration/TypoScript/setup.ts | 78 +++++++++++++++++++------------ 1 file changed, 49 insertions(+), 29 deletions(-) diff --git a/Configuration/TypoScript/setup.ts b/Configuration/TypoScript/setup.ts index 8a43333..efe9c11 100644 --- a/Configuration/TypoScript/setup.ts +++ b/Configuration/TypoScript/setup.ts @@ -25,52 +25,72 @@ lib.gridelements.defaultGridSetup { # or tx_gridelements_view_child_123 (123 is the UID of the child) } +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 + } + } + } +} + +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] From 7ffa726c6dac217663b070ca7c759a9e504e14d4 Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Wed, 21 Mar 2018 11:58:33 +0100 Subject: [PATCH 083/102] [BUGFIX] Set proper CSS styles for neutral frame headers Change-Id: I45a23f5968a534c53e8720b1100b7f1457c8159f Releases: master, 8-0, 7-0 Reviewed-on: https://review.typo3.org/56399 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Resources/Public/Backend/Css/Skin/t3skin_override.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Resources/Public/Backend/Css/Skin/t3skin_override.css b/Resources/Public/Backend/Css/Skin/t3skin_override.css index 408f26c..fd6edc8 100644 --- a/Resources/Public/Backend/Css/Skin/t3skin_override.css +++ b/Resources/Public/Backend/Css/Skin/t3skin_override.css @@ -85,7 +85,8 @@ 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; From bb3c68b20264702222e24887c04a194bc0eb5afc Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Wed, 21 Mar 2018 11:07:08 +0100 Subject: [PATCH 084/102] [BUGFIX] Consider allowed settings for first level CE backend layouts Change-Id: I78f213592e8496fb55157fbd047f66b738708313 Resolves: #84504 Releases: 7-0 Reviewed-on: https://review.typo3.org/56391 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- .../ItemsProcFuncs/AbstractItemsProcFunc.php | 25 +- Classes/Backend/LayoutSetup.php | 32 ++- Classes/Backend/TtContent.php | 3 +- Classes/Helper/Helper.php | 35 +++ Resources/Public/Backend/Css/grideditor.css | 220 ++++++++++++++++++ 5 files changed, 288 insertions(+), 27 deletions(-) create mode 100644 Resources/Public/Backend/Css/grideditor.css diff --git a/Classes/Backend/ItemsProcFuncs/AbstractItemsProcFunc.php b/Classes/Backend/ItemsProcFuncs/AbstractItemsProcFunc.php index fcda9e1..26d0fea 100644 --- a/Classes/Backend/ItemsProcFuncs/AbstractItemsProcFunc.php +++ b/Classes/Backend/ItemsProcFuncs/AbstractItemsProcFunc.php @@ -20,12 +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\Backend\View\BackendLayoutView; 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; /** @@ -72,27 +71,7 @@ public function init($pageUid = 0) */ 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']]; - } - } - } - } - foreach ($backendLayoutData['__items'] as $key => $item) { - $backendLayoutData['__items'][$key][3] = $backendLayoutData['columns'][$item[1]]; - } - }; - - return $backendLayoutData; + return Helper::getInstance()->getSelectedBackendLayout($id); } /** diff --git a/Classes/Backend/LayoutSetup.php b/Classes/Backend/LayoutSetup.php index 5e25e9f..3febddc 100644 --- a/Classes/Backend/LayoutSetup.php +++ b/Classes/Backend/LayoutSetup.php @@ -25,6 +25,7 @@ use TYPO3\CMS\Core\Utility\ArrayUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Lang\LanguageService; +use GridElementsTeam\Gridelements\Helper\Helper; /** * Utilities for gridelements. @@ -231,7 +232,7 @@ public function getLayoutColumns($layoutId) ? ',' . $availableColumns[$colPos] : $availableColumns[$colPos]; if (!empty($availableGridColumns[$colPos])) { - $availableColumns['allowedGridTypes'] .= $availableColumns['allowedGridTypes'] + $availableColumns['allowedGridTypes'][$colPos] .= $availableColumns['allowedGridTypes'][$colPos] ? ',' . $availableGridColumns[$colPos] : $availableGridColumns[$colPos]; } @@ -246,14 +247,39 @@ public function getLayoutColumns($layoutId) * Returns the item array for form field selection. * * @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]; + } + } + $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'; diff --git a/Classes/Backend/TtContent.php b/Classes/Backend/TtContent.php index 9afe399..390290d 100644 --- a/Classes/Backend/TtContent.php +++ b/Classes/Backend/TtContent.php @@ -192,7 +192,8 @@ public function deleteUnallowedContainer(array &$params, $itemUidList = '') public function layoutItemsProcFunc(array &$params) { $this->init($params['row']['pid']); - $layoutSelectItems = $this->layoutSetup->getLayoutSelectItems($params['row']['colPos'][0] ?: $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'], $params['row']['pid']); $params['items'] = ArrayUtility::keepItemsInArray($layoutSelectItems, $params['items'], true); } diff --git a/Classes/Helper/Helper.php b/Classes/Helper/Helper.php index e8116dd..c51bc7b 100644 --- a/Classes/Helper/Helper.php +++ b/Classes/Helper/Helper.php @@ -21,6 +21,8 @@ use TYPO3\CMS\Core\Database\DatabaseConnection; use TYPO3\CMS\Core\SingletonInterface; +use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Backend\View\BackendLayoutView; /** * Gridelements helper class @@ -144,6 +146,39 @@ 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 * diff --git a/Resources/Public/Backend/Css/grideditor.css b/Resources/Public/Backend/Css/grideditor.css new file mode 100644 index 0000000..85108ec --- /dev/null +++ b/Resources/Public/Backend/Css/grideditor.css @@ -0,0 +1,220 @@ +* { + padding: 0; + margin: 0; + position: relative; +} + +body { + padding: 10px; +} + +table#outer_container td, table#editor td { + vertical-align: middle; + padding: 0px 10px 10px 0px; +} + +table#outer_container td.editor_cell { + height: 100%; +} + +table.editor { + border-right: 1px gray dashed; + border-bottom: 1px gray dashed; +} + +table.editor td { + border-top: 1px gray dashed; + border-left: 1px gray dashed; + text-align: center; + z-index: 2000; + background-color: white; + min-height: 100px; +} + +div#editor { + height: 100%; +} + +div.cell_container { + width: 60px; + height: 60px; + position: relative; + left: 50%; + margin-left: -30px; + opacity: 0.3; +} + +div.cell_container:hover { + opacity: 1; +} + +.link_expand_right, .link_shrink_left, .link_expand_down, .link_shrink_up, .link_editor { + display: block; + position: absolute; + width: 14px; + height: 32px; + z-index: 1100; +} + +.link_expand_down, .link_shrink_up { + width: 32px; + height: 14px; +} + +.link_expand_right { + left: 46px; + top: 14px; +} + +.link_expand_right:hover { +} + +.link_shrink_left { + left: 0px; + top: 14px; +} + +.link_shrink_left:hover { +} + +.link_expand_down { + left: 14px; + top: 46px; +} + +.link_expand_down:hover { +} + +.link_shrink_up { + left: 14px; + top: 0px; +} + +.link_shrink_up:hover { +} + +.link_editor { + width: 32px; + height: 32px; + left: 14px; + top: 14px; +} + +.link_editor:hover { +} + +.question { +} + +.save { +} + +.cancel { +} + +table#outer_container td, table#editor td { + vertical-align: middle; +} + +table#outer_container td.editor_cell { + height: 100%; +} + +table.editor { + border-right: 1px gray dashed; + border-bottom: 1px gray dashed; +} + +table.editor td { + border-top: 1px gray dashed; + border-left: 1px gray dashed; + text-align: center; + z-index: 2000; + background-color: white; + min-height: 100px; +} + +div#editor { + height: 100%; +} + +div.cell_container { + width: 60px; + height: 60px; + position: relative; + left: 50%; + margin-left: -30px; + opacity: 0.3; +} + +div.cell_container:hover { + opacity: 1; +} + +.link_expand_right, .link_shrink_left, .link_expand_down, .link_shrink_up, .link_editor { + display: block; + position: absolute; + width: 14px; + height: 32px; + z-index: 1100; +} + +.link_expand_down, .link_shrink_up { + width: 32px; + height: 14px; +} + +.link_expand_right { + left: 46px; + top: 14px; +} + +.link_expand_right:hover { +} + +.link_shrink_left { + left: 0px; + top: 14px; +} + +.link_shrink_left:hover { +} + +.link_expand_down { + left: 14px; + top: 46px; +} + +.link_expand_down:hover { +} + +.link_shrink_up { + left: 14px; + top: 0px; +} + +.link_shrink_up:hover { +} + +.link_editor { + width: 32px; + height: 32px; + left: 14px; + top: 14px; +} + +.link_editor:hover { +} + +.question { +} + +.save { +} + +.cancel { +} + +.x-fieldset-body { + padding-bottom: 50px; +} \ No newline at end of file From 95bf57f44fcd8f706ea360cfdd721fb09a652ab2 Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Wed, 21 Mar 2018 14:06:14 +0100 Subject: [PATCH 085/102] [BUGFIX] Use proper palettes to get fields with CSC and FSC Change-Id: Ibfc3e0b953a52a31f0d004f534faeb9e9eb192c2 Resolves: #83728 Release: 7-0 Reviewed-on: https://review.typo3.org/56406 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Configuration/TCA/Overrides/tt_content.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Configuration/TCA/Overrides/tt_content.php b/Configuration/TCA/Overrides/tt_content.php index 74ddbd7..c7c7b6e 100644 --- a/Configuration/TCA/Overrides/tt_content.php +++ b/Configuration/TCA/Overrides/tt_content.php @@ -116,9 +116,10 @@ tx_gridelements_children, --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:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.access, - --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.visibility;visibility, + 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 From 482a85c59133a4af78b9c1d5989f453ac2d8da89 Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Wed, 21 Mar 2018 14:16:41 +0100 Subject: [PATCH 086/102] [BUGFIX] use proper pid values to fetch available layout columns Change-Id: I275731bc39583852cd94ab417730773040e41237 Resolves: #83963 Releases: 7-0 Reviewed-on: https://review.typo3.org/56405 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Backend/ItemsProcFuncs/CTypeList.php | 3 --- Classes/Backend/TtContent.php | 3 --- Classes/DataHandler/AbstractDataHandler.php | 14 +++++++------- Classes/DataHandler/AfterDatabaseOperations.php | 2 +- Classes/Helper/Helper.php | 11 ++++------- Classes/Hooks/BackendUtilityGridelements.php | 3 --- Classes/Hooks/WizardItems.php | 3 --- composer.json | 2 +- ext_emconf.php | 2 +- 9 files changed, 14 insertions(+), 29 deletions(-) diff --git a/Classes/Backend/ItemsProcFuncs/CTypeList.php b/Classes/Backend/ItemsProcFuncs/CTypeList.php index 9656dad..8b1b5ba 100644 --- a/Classes/Backend/ItemsProcFuncs/CTypeList.php +++ b/Classes/Backend/ItemsProcFuncs/CTypeList.php @@ -63,9 +63,6 @@ public function init($pageUid = 0) { parent::init(); if (!$this->layoutSetup) { - if ($pageUid < 0) { - $pageUid = Helper::getInstance()->getPidFromNegativeUid($pageUid); - } $this->injectLayoutSetup(GeneralUtility::makeInstance(LayoutSetup::class)->init($pageUid)); } } diff --git a/Classes/Backend/TtContent.php b/Classes/Backend/TtContent.php index 390290d..a37840c 100644 --- a/Classes/Backend/TtContent.php +++ b/Classes/Backend/TtContent.php @@ -62,9 +62,6 @@ 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)); } } diff --git a/Classes/DataHandler/AbstractDataHandler.php b/Classes/DataHandler/AbstractDataHandler.php index 2d3679f..3e5d073 100644 --- a/Classes/DataHandler/AbstractDataHandler.php +++ b/Classes/DataHandler/AbstractDataHandler.php @@ -74,20 +74,20 @@ public function injectLayoutSetup(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 */ - public function init($table, $pageUid, DataHandler $dataHandler) + public function init($table, $uidPid, DataHandler $dataHandler) { $this->setTable($table); - $this->setPageUid($pageUid); + if ($table === 'tt_content') { + $uidPid = Helper::getInstance()->getPidFromUid($uidPid); + } + $this->setPageUid($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($uidPid)); } } diff --git a/Classes/DataHandler/AfterDatabaseOperations.php b/Classes/DataHandler/AfterDatabaseOperations.php index 3635046..8a0f709 100644 --- a/Classes/DataHandler/AfterDatabaseOperations.php +++ b/Classes/DataHandler/AfterDatabaseOperations.php @@ -278,7 +278,7 @@ public function getAvailableColumns($layout = '', $table = '', $id = 0) if ($layout && $table === 'tt_content') { $tcaColumns = $this->layoutSetup->getLayoutColumns($layout); - $tcaColumns = $tcaColumns['CSV']; + $tcaColumns = '-2,-1,' . $tcaColumns['CSV']; } elseif ($table === 'pages') { $tcaColumns = GeneralUtility::callUserFunction(BackendLayoutView::class . '->getColPosListItemsParsed', $id, $this); diff --git a/Classes/Helper/Helper.php b/Classes/Helper/Helper.php index c51bc7b..356a6f4 100644 --- a/Classes/Helper/Helper.php +++ b/Classes/Helper/Helper.php @@ -107,18 +107,15 @@ public function getChildren($table = '', $uid = 0, $pid = 0, $sortingField = '', } /** - * 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; - } - $triggerElement = $this->databaseConnection->exec_SELECTgetSingleRow('pid', 'tt_content', 'uid = ' . abs($negativeUid)); + $triggerElement = $this->databaseConnection->exec_SELECTgetSingleRow('pid', 'tt_content', 'uid = ' . abs($uid)); $pid = (int)$triggerElement['pid']; return is_array($triggerElement) && $pid ? $pid : 0; } diff --git a/Classes/Hooks/BackendUtilityGridelements.php b/Classes/Hooks/BackendUtilityGridelements.php index 21698b9..721f0b2 100644 --- a/Classes/Hooks/BackendUtilityGridelements.php +++ b/Classes/Hooks/BackendUtilityGridelements.php @@ -64,9 +64,6 @@ 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)); } } diff --git a/Classes/Hooks/WizardItems.php b/Classes/Hooks/WizardItems.php index bc7179f..f9b2694 100644 --- a/Classes/Hooks/WizardItems.php +++ b/Classes/Hooks/WizardItems.php @@ -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); } } diff --git a/composer.json b/composer.json index 89ba69f..9079938 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "keywords": ["TYPO3 CMS", "Grids", "Gridelements"], "homepage": "https://forge.typo3.org/projects/extension-gridelements2", "license": "GPL-2.0-or-later", - "version": "7.2.1", + "version": "7.3.0", "support": { "issues": "https://forge.typo3.org/" }, diff --git a/ext_emconf.php b/ext_emconf.php index 01c11a0..3424346 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -13,7 +13,7 @@ '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' => '7.2.1', + 'version' => '7.3.0', 'priority' => 'bottom', 'module' => '', 'state' => 'beta', From 0be4d7b5b612c68b01f2c7437a72e64c9934a82b Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Mon, 26 Mar 2018 21:56:16 +0200 Subject: [PATCH 087/102] [BUGFIX] convert negative uid values to pid before fetching BE layouts Change-Id: I0099300c3a979703e3981a615365fe2c9e2f285b Resolves: #84526 Releases: 7-0 Reviewed-on: https://review.typo3.org/56456 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Backend/ItemsProcFuncs/CTypeList.php | 2 +- Classes/Backend/LayoutSetup.php | 24 +++++++++++++++++++- Classes/Backend/TtContent.php | 2 +- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/Classes/Backend/ItemsProcFuncs/CTypeList.php b/Classes/Backend/ItemsProcFuncs/CTypeList.php index 8b1b5ba..95fcb12 100644 --- a/Classes/Backend/ItemsProcFuncs/CTypeList.php +++ b/Classes/Backend/ItemsProcFuncs/CTypeList.php @@ -77,7 +77,7 @@ 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']); } else { - $this->init((int)$params['row']['pid']); + $this->init(); // 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'])); diff --git a/Classes/Backend/LayoutSetup.php b/Classes/Backend/LayoutSetup.php index 3febddc..852b678 100644 --- a/Classes/Backend/LayoutSetup.php +++ b/Classes/Backend/LayoutSetup.php @@ -56,6 +56,11 @@ class LayoutSetup */ protected $typoScriptSetup; + /** + * @var int + */ + protected $realPid; + /** * @var string */ @@ -74,6 +79,10 @@ 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); @@ -269,7 +278,10 @@ public function getLayoutSelectItems($colPos, $gridColPos = 0, $containerId = 0, $allowed = $pageLayout['columns']['allowedGridTypes'][(int)$colPos]; } } - $allowed = array_flip(GeneralUtility::trimExplode(',', $allowed)); + + if (!empty($allowed)) { + $allowed = array_flip(GeneralUtility::trimExplode(',', $allowed)); + } foreach ($this->layoutSetup as $layoutId => $item) { if (( (int)$colPos === -1 && @@ -556,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 a37840c..ecf4e5e 100644 --- a/Classes/Backend/TtContent.php +++ b/Classes/Backend/TtContent.php @@ -190,7 +190,7 @@ public function layoutItemsProcFunc(array &$params) { $this->init($params['row']['pid']); $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'], $params['row']['pid']); + $params['row']['tx_gridelements_columns'], $params['row']['tx_gridelements_container'], $this->layoutSetup->getRealPid()); $params['items'] = ArrayUtility::keepItemsInArray($layoutSelectItems, $params['items'], true); } From b31e023c9dc6b306ec53503ea623f89a2693f96f Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Sat, 31 Mar 2018 11:48:41 +0200 Subject: [PATCH 088/102] [BUGFIX] remove hardcoded path from drag in wizard url Change-Id: I43a08f75282e742cd87e3b1c50267a1df3c78907 Resolves: #84540 Releases: master, 8-0, 7-0 Reviewed-on: https://review.typo3.org/56497 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Resources/Public/JavaScript/GridElementsDragInWizard.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Public/JavaScript/GridElementsDragInWizard.js b/Resources/Public/JavaScript/GridElementsDragInWizard.js index a202e78..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]; } }; From 8714b01a299aa440a0ec319fc3dfd73de98b4326 Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Sun, 1 Apr 2018 17:35:14 +0200 Subject: [PATCH 089/102] [BUGFIX] make paste icons aware of allowed and disallowed settings Change-Id: I127c3ef02f58302de1e0e62761a74f24ee1e8606 Resolves: #78216 Releases: 7-0 Reviewed-on: https://review.typo3.org/56508 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Hooks/PageRenderer.php | 6 +- .../Public/JavaScript/GridElementsOnReady.js | 724 +++++++++--------- 2 files changed, 384 insertions(+), 346 deletions(-) diff --git a/Classes/Hooks/PageRenderer.php b/Classes/Hooks/PageRenderer.php index 48a3b93..8fd91a9 100644 --- a/Classes/Hooks/PageRenderer.php +++ b/Classes/Hooks/PageRenderer.php @@ -63,7 +63,6 @@ public function addJSCSS(array $parameters, \TYPO3\CMS\Core\Page\PageRenderer $p $clipObj = GeneralUtility::makeInstance(Clipboard::class); // Start clipboard $clipObj->initializeClipboard(); $clipObj->lockToNormal(); - if (!$pageRenderer->getCharSet()) { $pageRenderer->setCharSet($GLOBALS['LANG']->charSet ? $GLOBALS['LANG']->charSet : 'utf-8'); } @@ -150,15 +149,18 @@ public function addJSCSS(array $parameters, \TYPO3\CMS\Core\Page\PageRenderer $p $pasteTitle = $pasteRecord['header'] ? $pasteRecord['header'] : $pasteItem; $copyMode = $clipObj->clipData['normal']['mode'] ? '-' . $clipObj->clipData['normal']['mode'] : ''; $pAddExtOnReadyCode .= " + 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 = '';"; } diff --git a/Resources/Public/JavaScript/GridElementsOnReady.js b/Resources/Public/JavaScript/GridElementsOnReady.js index 314d9b0..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.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; + 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; }); From 91a1197820295bbc43d4bb5bd7c958bf3f737312 Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Sun, 1 Apr 2018 17:46:30 +0200 Subject: [PATCH 090/102] [TASK] add sponsoring chapter to documentation Change-Id: I3213d063955e19554ee3cd1fd56b98cb8736377a --- Documentation/Chapters/Sponsoring/Index.rst | 85 ++++++++++++++++++ .../Images/Sponsoring/AmazonLogo.png | Bin 0 -> 13708 bytes .../Images/Sponsoring/CodersCareLogo.png | Bin 0 -> 6912 bytes .../Images/Sponsoring/FlattrLogo.png | Bin 0 -> 3341 bytes .../Images/Sponsoring/PatreonLogo.png | Bin 0 -> 4861 bytes .../Images/Sponsoring/PaypalLogo.png | Bin 0 -> 4593 bytes Documentation/Images/Sponsoring/Why.jpg | Bin 0 -> 71346 bytes Documentation/Index.rst | 1 + 8 files changed, 86 insertions(+) create mode 100644 Documentation/Chapters/Sponsoring/Index.rst create mode 100644 Documentation/Images/Sponsoring/AmazonLogo.png create mode 100644 Documentation/Images/Sponsoring/CodersCareLogo.png create mode 100644 Documentation/Images/Sponsoring/FlattrLogo.png create mode 100644 Documentation/Images/Sponsoring/PatreonLogo.png create mode 100644 Documentation/Images/Sponsoring/PaypalLogo.png create mode 100644 Documentation/Images/Sponsoring/Why.jpg 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/Images/Sponsoring/AmazonLogo.png b/Documentation/Images/Sponsoring/AmazonLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..a76c7da8fdb3bbfbab02d1ad3a5b0be6790ee47f GIT binary patch literal 13708 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 literal 0 HcmV?d00001 diff --git a/Documentation/Images/Sponsoring/CodersCareLogo.png b/Documentation/Images/Sponsoring/CodersCareLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..29dc775dda284761b9608ee021d81c1e550510b3 GIT binary patch literal 6912 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⁢_{eCX}yj4*<9x;MhtahemV7eGo^ULG9HbtRi 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 NBYiWyIvv;8{{duAqn-c& literal 0 HcmV?d00001 diff --git a/Documentation/Images/Sponsoring/Why.jpg b/Documentation/Images/Sponsoring/Why.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bee517179dfa294120cebda969758933085eaef9 GIT binary patch literal 71346 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 literal 0 HcmV?d00001 diff --git a/Documentation/Index.rst b/Documentation/Index.rst index 21d141f..04eca61 100644 --- a/Documentation/Index.rst +++ b/Documentation/Index.rst @@ -66,4 +66,5 @@ Table Of Content Chapters/Tsconfig/Index Chapters/Typoscript/Index Chapters/Faq/Index + Chapters/Sponsoring/Index Chapters/Notes/Index From 52bb355c3d05b686698ae57100b5529a4ede94cd Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Tue, 3 Apr 2018 18:15:50 +0200 Subject: [PATCH 091/102] [TASK] Make Gridelements available for frontend editing Change-Id: Icc0b86732e7f7a089d8f1d0ddafeb60c3082174e Reviewed-on: https://review.typo3.org/56526 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- ext_tables.php | 72 ++++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 38 deletions(-) diff --git a/ext_tables.php b/ext_tables.php index 97ee7a6..a55e1e0 100644 --- a/ext_tables.php +++ b/ext_tables.php @@ -15,48 +15,11 @@ 'gridelements-default' ), 'CType'); +\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_gridelements_backend_layout'); if (TYPO3_MODE == 'BE') { - \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_gridelements_backend_layout'); include_once(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('gridelements') . 'Classes/Backend/TtContent.php'); - // 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; - - $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', - 'label' => 'LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:dragAndDropHideNewElementWizardInfoOverlay' - ); - - $GLOBALS['TYPO3_USER_SETTINGS']['columns']['hideColumnHeaders'] = array( - 'type' => 'check', - 'label' => 'LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:hideColumnHeaders' - ); - - $GLOBALS['TYPO3_USER_SETTINGS']['columns']['hideContentPreview'] = array( - 'type' => 'check', - 'label' => 'LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:hideContentPreview' - ); - - $GLOBALS['TYPO3_USER_SETTINGS']['columns']['showGridInformation'] = array( - 'type' => 'check', - 'label' => 'LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:showGridInformation' - ); - - $GLOBALS['TYPO3_USER_SETTINGS']['showitem'] .= ',--div--;LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:gridElements,dragAndDropHideNewElementWizardInfoOverlay,hideColumnHeaders,hideContentPreview,showGridInformation'; $GLOBALS['TBE_STYLES']['skins']['gridelements']['name'] = 'gridelements'; $GLOBALS['TBE_STYLES']['skins']['gridelements']['stylesheetDirectories']['gridelements_structure'] = 'EXT:' . ($_EXTKEY) . '/Resources/Public/Backend/Css/Skin/'; @@ -67,12 +30,45 @@ } +// 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; +$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', + 'label' => 'LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:dragAndDropHideNewElementWizardInfoOverlay' +); + +$GLOBALS['TYPO3_USER_SETTINGS']['columns']['hideColumnHeaders'] = array( + 'type' => 'check', + 'label' => 'LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:hideColumnHeaders' +); + +$GLOBALS['TYPO3_USER_SETTINGS']['columns']['hideContentPreview'] = array( + 'type' => 'check', + 'label' => 'LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:hideContentPreview' +); + +$GLOBALS['TYPO3_USER_SETTINGS']['columns']['showGridInformation'] = array( + 'type' => 'check', + 'label' => 'LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:showGridInformation' +); + +$GLOBALS['TYPO3_USER_SETTINGS']['showitem'] .= ',--div--;LLL:EXT:gridelements/Resources/Private/Language/locallang_db.xml:gridElements,dragAndDropHideNewElementWizardInfoOverlay,hideColumnHeaders,hideContentPreview,showGridInformation'; + 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'; } + $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( 'source' => 'EXT:gridelements/Resources/Public/Icons/gridelements.svg' From 9e511279f067fda7646a86ebfd3a3334fd813308 Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Tue, 3 Apr 2018 18:18:26 +0200 Subject: [PATCH 092/102] [TASK] Raise version numbers before releasing to TER Change-Id: I61eb9384df408c9df823e709e2232a32e54f13de Reviewed-on: https://review.typo3.org/56527 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- composer.json | 2 +- ext_emconf.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 9079938..0c9950a 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "keywords": ["TYPO3 CMS", "Grids", "Gridelements"], "homepage": "https://forge.typo3.org/projects/extension-gridelements2", "license": "GPL-2.0-or-later", - "version": "7.3.0", + "version": "7.4.0", "support": { "issues": "https://forge.typo3.org/" }, diff --git a/ext_emconf.php b/ext_emconf.php index 3424346..cbc33d5 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -13,7 +13,7 @@ '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' => '7.3.0', + 'version' => '7.4.0', 'priority' => 'bottom', 'module' => '', 'state' => 'beta', From 978f8fe72e09f0b16a7cff7492972ea7775b5d46 Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Thu, 5 Apr 2018 17:02:45 +0200 Subject: [PATCH 093/102] [BUGFIX] initialize layout setups with negative uidPid value Change-Id: Ibdc466842a4152bfbbe4a393cba9b7aa197a728c Resolves: #84526 Releases: 7-0 Reviewed-on: https://review.typo3.org/56569 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Backend/ItemsProcFuncs/CTypeList.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Classes/Backend/ItemsProcFuncs/CTypeList.php b/Classes/Backend/ItemsProcFuncs/CTypeList.php index 95fcb12..385cc22 100644 --- a/Classes/Backend/ItemsProcFuncs/CTypeList.php +++ b/Classes/Backend/ItemsProcFuncs/CTypeList.php @@ -20,7 +20,6 @@ ***************************************************************/ use GridElementsTeam\Gridelements\Backend\LayoutSetup; -use GridElementsTeam\Gridelements\Helper\Helper; use TYPO3\CMS\Core\Database\DatabaseConnection; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -77,7 +76,7 @@ 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']); } else { - $this->init(); + $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'])); From b9c88a31ce4f36b17b75c90ebde111551b9a39cc Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Thu, 3 May 2018 12:46:37 +0200 Subject: [PATCH 094/102] [BUGFIX] Make sure values are integers for strict comparison Change-Id: I4ad77284dd17893855dc5b64efb783355250339d Resolves: #84837 Release: 7-0 Reviewed-on: https://review.typo3.org/56847 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Hooks/DrawItem.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/Hooks/DrawItem.php b/Classes/Hooks/DrawItem.php index a599d6c..9908cf8 100644 --- a/Classes/Hooks/DrawItem.php +++ b/Classes/Hooks/DrawItem.php @@ -680,7 +680,7 @@ public function renderGridLayoutTable($layoutSetup, $row, $head, $gridContent, P $specificIds = $this->helper->getSpecificIds($row); $grid = '
    '; - if ($layoutSetup['frame'] || $this->helper->getBackendUser()->uc['showGridInformation'] === 1) { + 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']), From 848042ec3148ecfb705cfbf17ea3c00a163f0121 Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Thu, 3 May 2018 16:01:14 +0200 Subject: [PATCH 095/102] [BUGFIX] Get default language only when sys_language_content is not set Change-Id: I19adae96a5a8e3cfb2461c07327ae0d72a488868 Resolves: #84748 Releases: 7-0 Reviewed-on: https://review.typo3.org/56851 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Plugin/Gridelements.php | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Classes/Plugin/Gridelements.php b/Classes/Plugin/Gridelements.php index 633eb08..3575de2 100644 --- a/Classes/Plugin/Gridelements.php +++ b/Classes/Plugin/Gridelements.php @@ -151,6 +151,7 @@ public function getChildren($element = 0, $pid = 0, $csvColumns = '') if (!$element || $csvColumns === '') { return; } + $where = '(tx_gridelements_container = ' . $element . $this->cObj->enableFields('tt_content') . ' AND colPos != -2 AND pid = ' . (int)$pid . ' AND tx_gridelements_columns IN (' . $csvColumns . ') @@ -164,16 +165,20 @@ public function getChildren($element = 0, $pid = 0, $csvColumns = '') } if ($element) { - $where .= ' OR ( - tx_gridelements_container = ' . $element . $this->cObj->enableFields('tt_content') . ' AND sys_language_uid IN (-1,' . $this->getTSFE()->sys_language_content . ') + $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,' . $this->getTSFE()->sys_language_content . ') AND l18n_parent = 0 - )'; + )'; } } else { if ($element) { - $where .= ' OR ( - tx_gridelements_container = ' . (int)$element . $this->cObj->enableFields('tt_content') . ' AND sys_language_uid IN (-1,' . $this->getTSFE()->sys_language_content . ') - )'; + $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,' . $this->getTSFE()->sys_language_content . ') + )'; } } } From 8b430f52a2306bf839b84fdd8aeac31a0dc66e56 Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Mon, 18 Jun 2018 10:29:26 +0200 Subject: [PATCH 096/102] [TASK] Raise version numbers before releasin to TER Change-Id: I43d2dfa6e3ee193305b8de68c05423640993e2cc Reviewed-on: https://review.typo3.org/57255 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- composer.json | 2 +- ext_emconf.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 0c9950a..e31462d 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "keywords": ["TYPO3 CMS", "Grids", "Gridelements"], "homepage": "https://forge.typo3.org/projects/extension-gridelements2", "license": "GPL-2.0-or-later", - "version": "7.4.0", + "version": "7.4.1", "support": { "issues": "https://forge.typo3.org/" }, diff --git a/ext_emconf.php b/ext_emconf.php index cbc33d5..2eef57a 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -13,7 +13,7 @@ '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' => '7.4.0', + 'version' => '7.4.1', 'priority' => 'bottom', 'module' => '', 'state' => 'beta', From 46b6c0cdbd5b4b6b337182942ab20a1844dc5af8 Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Mon, 18 Jun 2018 18:18:06 +0200 Subject: [PATCH 097/102] [BUGFIX] Fetch children of translated containers regardless of l18n_parent Change-Id: I16122559aa63eab141f9b647691c444d3c2936a3 Resolves: #85303 Releases: 7-0 Reviewed-on: https://review.typo3.org/57263 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Plugin/Gridelements.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Classes/Plugin/Gridelements.php b/Classes/Plugin/Gridelements.php index 3575de2..ef3957c 100644 --- a/Classes/Plugin/Gridelements.php +++ b/Classes/Plugin/Gridelements.php @@ -152,7 +152,8 @@ public function getChildren($element = 0, $pid = 0, $csvColumns = '') return; } - $where = '(tx_gridelements_container = ' . $element . $this->cObj->enableFields('tt_content') . ' AND colPos != -2 + $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) @@ -165,7 +166,8 @@ public function getChildren($element = 0, $pid = 0, $csvColumns = '') } if ($element) { - $where = '(tx_gridelements_container = ' . $element . $this->cObj->enableFields('tt_content') . ' AND colPos != -2 + $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 . ') @@ -174,7 +176,8 @@ public function getChildren($element = 0, $pid = 0, $csvColumns = '') } } else { if ($element) { - $where = '(tx_gridelements_container = ' . $element . $this->cObj->enableFields('tt_content') . ' AND colPos != -2 + $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 . ') From 293792393a99d8c454777f5ec801d67d7afb7aac Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Mon, 18 Jun 2018 20:26:35 +0200 Subject: [PATCH 098/102] [TASK] Raise version number before releasing to TER Change-Id: I639c24bfa3c698acf078dfccce8738c8e03ebb50 Reviewed-on: https://review.typo3.org/57269 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- composer.json | 2 +- ext_emconf.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index e31462d..b5af35d 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "keywords": ["TYPO3 CMS", "Grids", "Gridelements"], "homepage": "https://forge.typo3.org/projects/extension-gridelements2", "license": "GPL-2.0-or-later", - "version": "7.4.1", + "version": "7.4.2", "support": { "issues": "https://forge.typo3.org/" }, diff --git a/ext_emconf.php b/ext_emconf.php index 2eef57a..ba10a50 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -13,7 +13,7 @@ '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' => '7.4.1', + 'version' => '7.4.2', 'priority' => 'bottom', 'module' => '', 'state' => 'beta', From ff416b6fbf14429d6e3dba81ba7dcca10489fb0b Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Mon, 25 Jun 2018 11:32:54 +0200 Subject: [PATCH 099/102] [TASK] Add dependencies to make sure those are loaded before GE Change-Id: Ie5b0d2d134fa4733fd48a147cf94881e2d588179 Resolves: #85314 Releases: 7-0 Reviewed-on: https://review.typo3.org/57365 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- composer.json | 26 +++++++++++++++++--------- ext_emconf.php | 28 ++++++++++++++++------------ 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/composer.json b/composer.json index b5af35d..d947eb4 100644 --- a/composer.json +++ b/composer.json @@ -1,24 +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://forge.typo3.org/projects/extension-gridelements2", "license": "GPL-2.0-or-later", - "version": "7.4.2", "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" }, - "autoload": { - "psr-4": { - "GridElementsTeam\\Gridelements\\": "Classes/" - } + "conflict": { + "templavoila": "*", + "jfmulticontent": "*" }, "replace": { "gridelements": "self.version", "typo3-ter/gridelements": "self.version" + }, + "autoload": { + "psr-4": { + "GridElementsTeam\\Gridelements\\": "Classes/" + } } } \ No newline at end of file diff --git a/ext_emconf.php b/ext_emconf.php index ba10a50..6b65261 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -8,7 +8,7 @@ * 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.', @@ -16,7 +16,7 @@ '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' => '7.6.0-7.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' => [], + ], +]; From 3f002332460e5db9e590b2908640db6884183be7 Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Mon, 9 Jul 2018 10:08:54 +0200 Subject: [PATCH 100/102] [BUGFIX] Introduce contentUid for DataHandler hooks Change-Id: I9c563ab70bb561bf71def8de338fe8f904745f1f Resolves: #85511 Releases: 7-0 Reviewed-on: https://review.typo3.org/57506 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/DataHandler/AbstractDataHandler.php | 150 +++++++++++------- .../DataHandler/AfterDatabaseOperations.php | 109 +++++++------ Classes/DataHandler/PreProcessFieldArray.php | 51 +++--- 3 files changed, 177 insertions(+), 133 deletions(-) diff --git a/Classes/DataHandler/AbstractDataHandler.php b/Classes/DataHandler/AbstractDataHandler.php index 3e5d073..c07f181 100644 --- a/Classes/DataHandler/AbstractDataHandler.php +++ b/Classes/DataHandler/AbstractDataHandler.php @@ -45,6 +45,11 @@ abstract class AbstractDataHandler */ protected $pageUid; + /** + * @var int + */ + protected $contentUid = 0; + /** * @var DataHandler */ @@ -60,16 +65,6 @@ abstract class AbstractDataHandler */ protected $layoutSetup; - /** - * inject layout setup - * - * @param LayoutSetup $layoutSetup - */ - public function injectLayoutSetup(LayoutSetup $layoutSetup) - { - $this->layoutSetup = $layoutSetup; - } - /** * initializes this class * @@ -80,85 +75,98 @@ public function injectLayoutSetup(LayoutSetup $layoutSetup) public function init($table, $uidPid, DataHandler $dataHandler) { $this->setTable($table); - if ($table === 'tt_content') { - $uidPid = Helper::getInstance()->getPidFromUid($uidPid); + 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->setPageUid($uidPid); $this->setTceMain($dataHandler); $this->setDatabaseConnection($GLOBALS['TYPO3_DB']); if (!$this->layoutSetup instanceof LayoutSetup) { - $this->injectLayoutSetup(GeneralUtility::makeInstance(LayoutSetup::class)->init($uidPid)); + $this->injectLayoutSetup(GeneralUtility::makeInstance(LayoutSetup::class)->init($this->getPageUid())); } } /** - * setter for table + * getter for contentUid * - * @param string $table + * @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 + * setter for dataHandler object * - * @param integer $pageUid + * @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 + * getter for table * - * @param DataHandler $dataHandler + * @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 setDatabaseConnection(DatabaseConnection $databaseConnection) + public function getPageUid() { - $this->databaseConnection = $databaseConnection; + return $this->pageUid; + } + + /** + * setter for pageUid + * + * @param integer $pageUid + */ + public function setPageUid($pageUid) + { + $this->pageUid = $pageUid; } /** @@ -172,20 +180,13 @@ public function getDatabaseConnection() } /** - * Function to handle record actions between different grid containers + * setter for databaseConnection object * - * @param array $containerUpdateArray + * @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; } /** @@ -226,18 +227,20 @@ public function checkAndUpdateTranslatedElements($uid) '', 'sys_language_uid' ); } - $containerUpdateArray = array(); + $containerUpdateArray = []; foreach ($translatedElements as $translatedUid => $translatedElement) { - $updateArray = array(); + $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 ($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; + } } $updateArray['colPos'] = (int)$currentValues['colPos']; $this->databaseConnection->exec_UPDATEquery('tt_content', 'uid=' . (int)$translatedUid, @@ -256,4 +259,31 @@ public function checkAndUpdateTranslatedElements($uid) $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 8a0f709..00cf2c1 100644 --- a/Classes/DataHandler/AfterDatabaseOperations.php +++ b/Classes/DataHandler/AfterDatabaseOperations.php @@ -1,4 +1,5 @@ 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 > 0 AND 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(' @@ -107,7 +108,8 @@ public function setUnusedElements(array &$fieldArray) } $childElementsInAvailableColumns = array_keys($this->databaseConnection->exec_SELECTgetRows('uid', - 'tt_content', 'tx_gridelements_container > 0 AND 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(' @@ -140,13 +142,17 @@ public function setUnusedElements(array &$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; + } + } } } @@ -163,7 +169,7 @@ public function setUnusedElements(array &$fieldArray) '); array_flip($elementsInUnavailableColumns); } else { - $elementsInUnavailableColumns = array(); + $elementsInUnavailableColumns = []; } $elementsInAvailableColumns = array_keys($this->databaseConnection->exec_SELECTgetRows('uid', @@ -179,7 +185,7 @@ public function setUnusedElements(array &$fieldArray) '); array_flip($elementsInAvailableColumns); } else { - $elementsInAvailableColumns = array(); + $elementsInAvailableColumns = []; } $changedElements = array_merge($elementsInUnavailableColumns, $elementsInAvailableColumns); @@ -187,10 +193,10 @@ public function setUnusedElements(array &$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', @@ -204,7 +210,7 @@ public function setUnusedElements(array &$fieldArray) '); array_flip($subPageElementsInUnavailableColumns); } else { - $subPageElementsInUnavailableColumns = array(); + $subPageElementsInUnavailableColumns = []; } $subPageElementsInAvailableColumns = array_keys($this->databaseConnection->exec_SELECTgetRows('uid', @@ -219,10 +225,11 @@ public function setUnusedElements(array &$fieldArray) '); array_flip($subPageElementsInAvailableColumns); } else { - $subPageElementsInAvailableColumns = array(); + $subPageElementsInAvailableColumns = []; } - $changedPageElements = array_merge($subPageElementsInUnavailableColumns, $subPageElementsInAvailableColumns); + $changedPageElements = array_merge($subPageElementsInUnavailableColumns, + $subPageElementsInAvailableColumns); $changedSubPageElements = array_merge($changedSubPageElements, $changedPageElements); } } @@ -237,32 +244,6 @@ public function setUnusedElements(array &$fieldArray) } } - /** - * 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); - } - } - } - } - /** * fetches all available columns for a certain grid container based on TCA settings and layout records * @@ -282,7 +263,7 @@ public function getAvailableColumns($layout = '', $table = '', $id = 0) } 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]; @@ -294,4 +275,30 @@ public function getAvailableColumns($layout = '', $table = '', $id = 0) return $tcaColumns; } + + /** + * 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 5233504..c5b258d 100644 --- a/Classes/DataHandler/PreProcessFieldArray.php +++ b/Classes/DataHandler/PreProcessFieldArray.php @@ -1,4 +1,5 @@ getBackendUser()->getTSConfigProp('TCAdefaults'); @@ -165,6 +166,14 @@ public function setDefaultFieldValues(array &$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 * @@ -190,7 +199,7 @@ public function getDefaultFlexformValues(array &$fieldArray) public function extractDefaultDataFromDataStructure($dataStructure) { $returnXML = ''; - $sheetArray = array(); + $sheetArray = []; if ($dataStructure) { $structureArray = GeneralUtility::xml2array($dataStructure); if (!isset($structureArray['sheets']) && isset($structureArray['ROOT'])) { @@ -200,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']; @@ -229,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; @@ -263,19 +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; - $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']; + } 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 (isset($targetContainer) && (int)$targetContainer['sys_language_uid'] === -1) { - $list = array_flip(GeneralUtility::trimExplode(',', $GLOBALS['TCA']['tt_content']['ctrl']['copyAfterDuplFields'], true)); + $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)); } @@ -303,12 +318,4 @@ public function checkForRootColumn($contentId) return $colPos; } - - /** - * @return BackendUserAuthentication - */ - public function getBackendUser() - { - return $GLOBALS['BE_USER']; - } } From b256d4f7b913c33d56e2ad2dd15b9d459d503017 Mon Sep 17 00:00:00 2001 From: Cybercraft Date: Mon, 13 Aug 2018 10:42:40 +0200 Subject: [PATCH 101/102] [BUGFIX] Core might provide strings as dataStructureArray too Resolves: #85823 Releases: 7-0 Already fixed in master and 8-0 Change-Id: I2510ae48f74e5565f6019a919f7ad9d4f81a4626 Reviewed-on: https://review.typo3.org/57882 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Classes/Hooks/BackendUtilityGridelements.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/Hooks/BackendUtilityGridelements.php b/Classes/Hooks/BackendUtilityGridelements.php index 721f0b2..adb183d 100644 --- a/Classes/Hooks/BackendUtilityGridelements.php +++ b/Classes/Hooks/BackendUtilityGridelements.php @@ -72,13 +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 */ - public function getFlexFormDS_postProcessDS(array &$dataStructureArray, array $conf, array $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']); From a53b288a793d6735f244fda24246d73467179add Mon Sep 17 00:00:00 2001 From: cybercraft Date: Tue, 1 Jan 2019 14:26:47 +0100 Subject: [PATCH 102/102] [TASK] Remove superfluous plugin configuration Change-Id: I8e69baf6d41471397bde54b020039d12601c436e Reviewed-on: https://review.typo3.org/59316 Reviewed-by: Jo Hasenau Tested-by: Jo Hasenau --- Configuration/TypoScript/setup.ts | 2 -- ext_localconf.php | 3 --- 2 files changed, 5 deletions(-) diff --git a/Configuration/TypoScript/setup.ts b/Configuration/TypoScript/setup.ts index efe9c11..26211f6 100644 --- a/Configuration/TypoScript/setup.ts +++ b/Configuration/TypoScript/setup.ts @@ -25,8 +25,6 @@ lib.gridelements.defaultGridSetup { # or tx_gridelements_view_child_123 (123 is the UID of the child) } -plugin.tx_gridelements_pi1 > -tt_content.gridelements_pi1 > tt_content.gridelements_pi1 = COA tt_content.gridelements_pi1 { #10 =< lib.stdheader diff --git a/ext_localconf.php b/ext_localconf.php index 5b6c72c..75d08f4 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -9,9 +9,6 @@ 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',);

    '; - $grid .= ($this->helper->getBackendUser()->uc['hideColumnHeaders'] ? '' : $head[$columnKey]) . $gridContent[$columnKey]; + $grid .= ($this->helper->getBackendUser()->uc['hideColumnHeaders'] ? '' : $columnHead) . $gridContent[$columnKey]; $grid .= '