From 8482d77f609e8ea22ca72dd425d9fb75cc8aafd0 Mon Sep 17 00:00:00 2001 From: Jochen Roth <jochen.roth@b13.com> Date: Tue, 6 Jul 2021 13:32:07 +0200 Subject: [PATCH] [BUGFIX] Set fallback for undefined array key in php8 After reset user preferences in settings module the Configuration Module shows undefined array key warning. An empty array has been added as fallback to workaround this issue and improved scrollTo behavior when the user opens a node in the configuration tree. Also extended tests to cover such issues in the future. Resolves: #94487 Releases: master Change-Id: I3e907a2618765d314ff1ad8bcab74f1af46765c0 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/69724 Tested-by: core-ci <typo3@b13.com> Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de> Tested-by: Benni Mack <benni@typo3.org> Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de> Reviewed-by: crell <larry@garfieldtech.com> Reviewed-by: Benni Mack <benni@typo3.org> --- .../Public/TypeScript/ConfigurationView.ts | 10 ++++- .../ConfigurationModuleProviderCest.php | 44 +++++++++++++++++++ .../Controller/ConfigurationController.php | 2 +- .../Public/JavaScript/ConfigurationView.js | 2 +- 4 files changed, 55 insertions(+), 3 deletions(-) diff --git a/Build/Sources/TypeScript/lowlevel/Resources/Public/TypeScript/ConfigurationView.ts b/Build/Sources/TypeScript/lowlevel/Resources/Public/TypeScript/ConfigurationView.ts index 1dd4f53ea257..14b7af246130 100644 --- a/Build/Sources/TypeScript/lowlevel/Resources/Public/TypeScript/ConfigurationView.ts +++ b/Build/Sources/TypeScript/lowlevel/Resources/Public/TypeScript/ConfigurationView.ts @@ -35,7 +35,15 @@ class ConfigurationView { if (self.location.hash) { // scroll page down, so the just opened subtree is visible after reload and not hidden by doc header - $('html, body').scrollTop((document.documentElement.scrollTop || document.body.scrollTop) - 80); + // Determine scrollTo position, either first ".active" (search) or latest clicked element + let scrollElement = document.querySelector(self.location.hash); + if(document.querySelector('.list-tree .active ')) { + scrollElement = document.querySelector('.list-tree .active '); + } else { + document.querySelector(self.location.hash).parentElement.parentElement.classList.add('active'); + } + + scrollElement.scrollIntoView({ block: 'center' }); } } } diff --git a/typo3/sysext/core/Tests/Acceptance/Backend/ConfigurationModule/ConfigurationModuleProviderCest.php b/typo3/sysext/core/Tests/Acceptance/Backend/ConfigurationModule/ConfigurationModuleProviderCest.php index b008d7e29205..b2fbdb2bcd97 100644 --- a/typo3/sysext/core/Tests/Acceptance/Backend/ConfigurationModule/ConfigurationModuleProviderCest.php +++ b/typo3/sysext/core/Tests/Acceptance/Backend/ConfigurationModule/ConfigurationModuleProviderCest.php @@ -68,4 +68,48 @@ class ConfigurationModuleProviderCest $I->seeCheckboxIsChecked('#lowlevel-regexSearch'); $I->seeElement('li.active'); } + + /** + * @param BackendTester $I + */ + public function canOpenTreeNodeAndScrollTo(BackendTester $I): void + { + $I->selectOption('select[name=tree]', '$GLOBALS[\'TYPO3_CONF_VARS\'] (Global Configuration)'); + $I->click('.list-tree > li:first-child .list-tree-control'); + $I->see('checkStoredRecordsLoose', '.list-tree-group'); + $I->see('BE', '.active > .list-tree-group'); + } + + /** + * @param BackendTester $I + */ + public function seeAllPagesInDropDown(BackendTester $I): void + { + foreach ($this->dropDownPagesDataProvider() as $item) { + $I->selectOption('select[name=tree]', $item); + $I->see($item, 'h2'); + } + } + + protected function dropDownPagesDataProvider(): array + { + return [ + '$GLOBALS[\'TYPO3_CONF_VARS\'] (Global Configuration)', + '$GLOBALS[\'TCA\'] (Table configuration array)', + '$GLOBALS[\'TCA_DESCR\'] (Table Help Description)', + '$GLOBALS[\'T3_SERVICES\'] (Registered Services)', + '$GLOBALS[\'TBE_MODULES\'] (BE Modules)', + '$GLOBALS[\'TBE_MODULES_EXT\'] (BE Modules Extensions)', + '$GLOBALS[\'TBE_STYLES\'] (Skinning Styles)', + '$GLOBALS[\'TYPO3_USER_SETTINGS\'] (User Settings Configuration)', + '$GLOBALS[\'PAGES_TYPES\'] (Table permissions by page type)', + '$GLOBALS[\'BE_USER\']->uc (User Settings)', + '$GLOBALS[\'BE_USER\']->getTSConfig() (User TSconfig)', + 'Backend Routes', + 'HTTP Middlewares (PSR-15)', + 'Site Configuration', + 'Event Listeners (PSR-14)', + 'MFA providers' + ]; + } } diff --git a/typo3/sysext/lowlevel/Classes/Controller/ConfigurationController.php b/typo3/sysext/lowlevel/Classes/Controller/ConfigurationController.php index 01b3262e8761..87dd045277b8 100644 --- a/typo3/sysext/lowlevel/Classes/Controller/ConfigurationController.php +++ b/typo3/sysext/lowlevel/Classes/Controller/ConfigurationController.php @@ -101,7 +101,7 @@ class ConfigurationController if ($searchString) { $arrayBrowser->depthKeys = $arrayBrowser->getSearchKeys($configurationArray, '', $searchString, []); } elseif (is_array($node)) { - $newExpandCollapse = $arrayBrowser->depthKeys($node, $moduleState['node_' . $configurationProviderIdentifier]); + $newExpandCollapse = $arrayBrowser->depthKeys($node, $moduleState['node_' . $configurationProviderIdentifier] ?? []); $arrayBrowser->depthKeys = $newExpandCollapse; $moduleState['node_' . $configurationProviderIdentifier] = $newExpandCollapse; } else { diff --git a/typo3/sysext/lowlevel/Resources/Public/JavaScript/ConfigurationView.js b/typo3/sysext/lowlevel/Resources/Public/JavaScript/ConfigurationView.js index 4660883c3145..6b79a9b67ef7 100644 --- a/typo3/sysext/lowlevel/Resources/Public/JavaScript/ConfigurationView.js +++ b/typo3/sysext/lowlevel/Resources/Public/JavaScript/ConfigurationView.js @@ -10,4 +10,4 @@ * * The TYPO3 project - inspiring people to share! */ -define(["require","exports","TYPO3/CMS/Core/DocumentService","TYPO3/CMS/Core/Event/RegularEvent"],(function(e,r,t,s){"use strict";return new class{constructor(){this.searchForm=document.querySelector("#ConfigurationView"),this.searchField=this.searchForm.querySelector('input[name="searchString"]'),this.searchResultShown=""!==this.searchField.value,t.ready().then(()=>{new s("search",()=>{""===this.searchField.value&&this.searchResultShown&&this.searchForm.submit()}).bindTo(this.searchField)}),self.location.hash&&$("html, body").scrollTop((document.documentElement.scrollTop||document.body.scrollTop)-80)}}})); \ No newline at end of file +define(["require","exports","TYPO3/CMS/Core/DocumentService","TYPO3/CMS/Core/Event/RegularEvent"],(function(e,t,r,s){"use strict";return new class{constructor(){if(this.searchForm=document.querySelector("#ConfigurationView"),this.searchField=this.searchForm.querySelector('input[name="searchString"]'),this.searchResultShown=""!==this.searchField.value,r.ready().then(()=>{new s("search",()=>{""===this.searchField.value&&this.searchResultShown&&this.searchForm.submit()}).bindTo(this.searchField)}),self.location.hash){let e=document.querySelector(self.location.hash);document.querySelector(".list-tree .active ")?e=document.querySelector(".list-tree .active "):document.querySelector(self.location.hash).parentElement.parentElement.classList.add("active"),e.scrollIntoView({block:"center"})}}}})); \ No newline at end of file -- GitLab