[TASK] Revert "Limit amount of data fetched by the page tree" 00/65200/2
authorBenni Mack <benni@typo3.org>
Fri, 7 Aug 2020 11:46:31 +0000 (13:46 +0200)
committerBenni Mack <benni@typo3.org>
Fri, 7 Aug 2020 15:11:36 +0000 (17:11 +0200)
This reverts commit fb61db41d5fec1c791c3541567ae97c11006ae45
as it contained various regressions, which should be fixed in the
next iteration.

Change-Id: I03b6ff9e63a1425fae3745f70bbd9b8a2a94c081
Releases: master, 10.4, 9.5
Resolves: #91949
Reverts: #88943
Reverts: #88098
Reverts: #88259
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/65200
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Frank Nägler <frank.naegler@typo3.org>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Frank Nägler <frank.naegler@typo3.org>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Benni Mack <benni@typo3.org>
typo3/sysext/backend/Classes/Controller/Page/TreeController.php
typo3/sysext/backend/Classes/Tree/Repository/PageTreeRepository.php
typo3/sysext/backend/Configuration/Backend/AjaxRoutes.php
typo3/sysext/backend/Resources/Public/JavaScript/PageTree/PageTree.js
typo3/sysext/backend/Resources/Public/JavaScript/PageTree/PageTreeElement.js
typo3/sysext/backend/Resources/Public/JavaScript/PageTree/PageTreeToolbar.js
typo3/sysext/backend/Tests/Functional/Controller/Page/TreeControllerTest.php
typo3/sysext/core/Resources/Private/Language/locallang_core.xlf

index b035eca..464181a 100644 (file)
@@ -103,46 +103,12 @@ class TreeController
     protected $iconFactory;
 
     /**
-     * Number of tree levels which should be returned on the first page tree load
-     *
-     * @var int
-     */
-    protected $levelsToFetch = 2;
-
-    /**
-     * When set to true all nodes returend by API will be expanded
-     * @var bool
-     */
-    protected $expandAllNodes = false;
-
-    /**
      * Constructor to set up common objects needed in various places.
      */
     public function __construct()
     {
         $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
-    }
-
-    protected function initializeConfiguration()
-    {
-        $userTsConfig = $this->getBackendUser()->getTSConfig();
-        $this->hiddenRecords = GeneralUtility::intExplode(
-            ',',
-            $userTsConfig['options.']['hideRecords.']['pages'] ?? '',
-            true
-        );
-        $this->backgroundColors = $userTsConfig['options.']['pageTree.']['backgroundColor.'] ?? [];
-        $this->addIdAsPrefix = (bool)($userTsConfig['options.']['pageTree.']['showPageIdWithTitle'] ?? false);
-        $this->addDomainName = (bool)($userTsConfig['options.']['pageTree.']['showDomainNameWithTitle'] ?? false);
-        $this->useNavTitle = (bool)($userTsConfig['options.']['pageTree.']['showNavTitle'] ?? false);
-        $this->showMountPathAboveMounts = (bool)($userTsConfig['options.']['pageTree.']['showPathAboveMounts'] ?? false);
-        $backendUserConfiguration = GeneralUtility::makeInstance(BackendUserConfiguration::class);
-        $this->expandedState = $backendUserConfiguration->get('BackendComponents.States.Pagetree');
-        if (is_object($this->expandedState) && is_object($this->expandedState->stateHash)) {
-            $this->expandedState = (array)$this->expandedState->stateHash;
-        } else {
-            $this->expandedState = $this->expandedState['stateHash'] ?: [];
-        }
+        $this->useNavTitle = (bool)($this->getBackendUser()->getTSConfig()['options.']['pageTree.']['showNavTitle'] ?? false);
     }
 
     /**
@@ -212,51 +178,29 @@ class TreeController
      */
     public function fetchDataAction(ServerRequestInterface $request): ResponseInterface
     {
-        $this->initializeConfiguration();
+        $userTsConfig = $this->getBackendUser()->getTSConfig();
+        $this->hiddenRecords = GeneralUtility::intExplode(',', $userTsConfig['options.']['hideRecords.']['pages'] ?? '', true);
+        $this->backgroundColors = $userTsConfig['options.']['pageTree.']['backgroundColor.'] ?? [];
+        $this->addIdAsPrefix = (bool)($userTsConfig['options.']['pageTree.']['showPageIdWithTitle'] ?? false);
+        $this->addDomainName = (bool)($userTsConfig['options.']['pageTree.']['showDomainNameWithTitle'] ?? false);
+        $this->showMountPathAboveMounts = (bool)($userTsConfig['options.']['pageTree.']['showPathAboveMounts'] ?? false);
+        $backendUserConfiguration = GeneralUtility::makeInstance(BackendUserConfiguration::class);
+        $this->expandedState = $backendUserConfiguration->get('BackendComponents.States.Pagetree');
+        if (is_object($this->expandedState) && is_object($this->expandedState->stateHash)) {
+            $this->expandedState = (array)$this->expandedState->stateHash;
+        } else {
+            $this->expandedState = $this->expandedState['stateHash'] ?: [];
+        }
 
-        $items = [];
+        // Fetching a part of a pagetree
         if (!empty($request->getQueryParams()['pid'])) {
-            // Fetching a part of a page tree
-            $entryPoints = $this->getAllEntryPointPageTrees((int)$request->getQueryParams()['pid']);
-            $mountPid = (int)($request->getQueryParams()['mount'] ?? 0);
-            $parentDepth = (int)($request->getQueryParams()['pidDepth'] ?? 0);
-            $this->levelsToFetch = $parentDepth + $this->levelsToFetch;
-            foreach ($entryPoints as $page) {
-                $items = array_merge($items, $this->pagesToFlatArray($page, $mountPid, $parentDepth));
-            }
+            $entryPoints = [(int)$request->getQueryParams()['pid']];
         } else {
             $entryPoints = $this->getAllEntryPointPageTrees();
-            foreach ($entryPoints as $page) {
-                $items = array_merge($items, $this->pagesToFlatArray($page, (int)$page['uid']));
-            }
-        }
-
-        return new JsonResponse($items);
-    }
-
-    /**
-     * Returns JSON representing page tree filtered by keyword
-     *
-     * @param ServerRequestInterface $request
-     * @return ResponseInterface
-     */
-    public function filterDataAction(ServerRequestInterface $request): ResponseInterface
-    {
-        $searchQuery = $request->getQueryParams()['q'] ?? '';
-        if (trim($searchQuery) === '') {
-            return new JsonResponse([]);
         }
-
-        $this->initializeConfiguration();
-        $this->expandAllNodes = true;
-
         $items = [];
-        $entryPoints = $this->getAllEntryPointPageTrees(0, $searchQuery);
-
         foreach ($entryPoints as $page) {
-            if (!empty($page)) {
-                $items = array_merge($items, $this->pagesToFlatArray($page, (int)$page['uid']));
-            }
+            $items = array_merge($items, $this->pagesToFlatArray($page, (int)$page['uid']));
         }
 
         return new JsonResponse($items);
@@ -310,10 +254,7 @@ class TreeController
 
         $stopPageTree = !empty($page['php_tree_stop']) && $depth > 0;
         $identifier = $entryPoint . '_' . $pageId;
-        $expanded = !empty($page['expanded'])
-            || (isset($this->expandedState[$identifier]) && $this->expandedState[$identifier])
-            || $this->expandAllNodes;
-
+        $expanded = !empty($page['expanded']) || (isset($this->expandedState[$identifier]) && $this->expandedState[$identifier]);
         $backgroundColor = !empty($this->backgroundColors[$pageId]) ? $this->backgroundColors[$pageId] : ($inheritedData['backgroundColor'] ?? '');
 
         $suffix = '';
@@ -368,11 +309,8 @@ class TreeController
                 && $backendUser->checkLanguageAccess(0)
         ];
 
-        if (!empty($page['_children']) || $this->getPageTreeRepository()->hasChildren($pageId)) {
+        if (!empty($page['_children'])) {
             $item['hasChildren'] = true;
-            if ($depth >= $this->levelsToFetch) {
-                $page = $this->getPageTreeRepository()->getTreeLevels($page, 1);
-            }
         }
         if (!empty($prefix)) {
             $item['prefix'] = htmlspecialchars($prefix);
@@ -386,7 +324,7 @@ class TreeController
         if ($icon->getOverlayIcon()) {
             $item['overlayIcon'] = $icon->getOverlayIcon()->getIdentifier();
         }
-        if ($expanded && is_array($page['_children']) && !empty($page['_children'])) {
+        if ($expanded) {
             $item['expanded'] = $expanded;
         }
         if ($backgroundColor) {
@@ -408,10 +346,9 @@ class TreeController
         }
 
         $items[] = $item;
-        if (!$stopPageTree && is_array($page['_children']) && !empty($page['_children']) && ($depth < $this->levelsToFetch || $expanded)) {
+        if (!$stopPageTree && is_array($page['_children'])) {
             $siblingsCount = count($page['_children']);
             $siblingsPosition = 0;
-            $items[key($items)]['loaded'] = true;
             foreach ($page['_children'] as $child) {
                 $child['siblingsCount'] = $siblingsCount;
                 $child['siblingsPosition'] = ++$siblingsPosition;
@@ -421,7 +358,12 @@ class TreeController
         return $items;
     }
 
-    protected function getPageTreeRepository(): PageTreeRepository
+    /**
+     * Fetches all entry points for the page tree that the user is allowed to see
+     *
+     * @return array
+     */
+    protected function getAllEntryPointPageTrees(): array
     {
         $backendUser = $this->getBackendUser();
         $userTsConfig = $backendUser->getTSConfig();
@@ -433,94 +375,57 @@ class TreeController
         }
         $additionalQueryRestrictions[] = GeneralUtility::makeInstance(PagePermissionRestriction::class, GeneralUtility::makeInstance(Context::class)->getAspect('backend.user'), Permission::PAGE_SHOW);
 
-        return GeneralUtility::makeInstance(
+        $repository = GeneralUtility::makeInstance(
             PageTreeRepository::class,
             (int)$backendUser->workspace,
             [],
             $additionalQueryRestrictions
         );
-    }
 
-    /**
-     * Fetches all pages for all tree entry points the user is allowed to see
-     *
-     * @param int $startPid
-     * @param string $query The search query can either be a string to be found in the title or the nav_title of a page or the uid of a page.
-     * @return array
-     */
-    protected function getAllEntryPointPageTrees(int $startPid = 0, string $query = ''): array
-    {
-        $backendUser = $this->getBackendUser();
-        $entryPointId = $startPid > 0 ? $startPid : (int)($backendUser->uc['pageTree_temporaryMountPoint'] ?? 0);
-        if ($entryPointId > 0) {
-            $entryPointIds = [$entryPointId];
+        $entryPoints = (int)($backendUser->uc['pageTree_temporaryMountPoint'] ?? 0);
+        if ($entryPoints > 0) {
+            $entryPoints = [$entryPoints];
         } else {
-            //watch out for deleted pages returned as webmount
-            $entryPointIds = array_map('intval', $backendUser->returnWebmounts());
-            $entryPointIds = array_unique($entryPointIds);
-            if (empty($entryPointIds)) {
+            $entryPoints = array_map('intval', $backendUser->returnWebmounts());
+            $entryPoints = array_unique($entryPoints);
+            if (empty($entryPoints)) {
                 // use a virtual root
                 // the real mount points will be fetched in getNodes() then
                 // since those will be the "sub pages" of the virtual root
-                $entryPointIds = [0];
+                $entryPoints = [0];
             }
         }
-        if (empty($entryPointIds)) {
+        if (empty($entryPoints)) {
             return [];
         }
-        $repository = $this->getPageTreeRepository();
-
-        if ($query !== '') {
-            $this->levelsToFetch = 999;
-            $repository->fetchFilteredTree($query);
-        }
 
-        $entryPointRecords = [];
-        foreach ($entryPointIds as $k => $entryPointId) {
-            if (in_array($entryPointId, $this->hiddenRecords, true)) {
+        foreach ($entryPoints as $k => &$entryPoint) {
+            if (in_array($entryPoint, $this->hiddenRecords, true)) {
+                unset($entryPoints[$k]);
                 continue;
             }
 
             if (!empty($this->backgroundColors) && is_array($this->backgroundColors)) {
                 try {
-                    $entryPointRootLine = GeneralUtility::makeInstance(RootlineUtility::class, $entryPointId)->get();
+                    $entryPointRootLine = GeneralUtility::makeInstance(RootlineUtility::class, $entryPoint)->get();
                 } catch (RootLineException $e) {
                     $entryPointRootLine = [];
                 }
                 foreach ($entryPointRootLine as $rootLineEntry) {
                     $parentUid = $rootLineEntry['uid'];
-                    if (!empty($this->backgroundColors[$parentUid]) && empty($this->backgroundColors[$entryPointId])) {
-                        $this->backgroundColors[$entryPointId] = $this->backgroundColors[$parentUid];
+                    if (!empty($this->backgroundColors[$parentUid]) && empty($this->backgroundColors[$entryPoint])) {
+                        $this->backgroundColors[$entryPoint] = $this->backgroundColors[$parentUid];
                     }
                 }
             }
-            if ($entryPointId === 0) {
-                $entryPointRecord = [
-                    'uid' => 0,
-                    'title' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] ?: 'TYPO3'
-                ];
-            } else {
-                $permClause = $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW);
-                $entryPointRecord = BackendUtility::getRecord('pages', $entryPointId, '*', $permClause);
-
-                if ($entryPointRecord !== null && !$this->getBackendUser()->isInWebMount($entryPointId)) {
-                    $entryPointRecord = null;
-                }
-            }
-            if ($entryPointRecord) {
-                if ($query === '') {
-                    $entryPointRecord = $repository->getTreeLevels($entryPointRecord, $this->levelsToFetch);
-                } else {
-                    $entryPointRecord = $repository->getTree($entryPointRecord['uid'], null, $entryPointIds);
-                }
-            }
 
-            if (is_array($entryPointRecord) && !empty($entryPointRecord)) {
-                $entryPointRecords[$k] = $entryPointRecord;
+            $entryPoint = $repository->getTree($entryPoint, null, $entryPoints);
+            if (!is_array($entryPoint)) {
+                unset($entryPoints[$k]);
             }
         }
 
-        return $entryPointRecords;
+        return $entryPoints;
     }
 
     /**
index 723008c..6928346 100644 (file)
@@ -17,15 +17,11 @@ declare(strict_types=1);
 
 namespace TYPO3\CMS\Backend\Tree\Repository;
 
-use Doctrine\DBAL\Connection;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
-use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Database\ConnectionPool;
-use TYPO3\CMS\Core\Database\Query\QueryHelper;
 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
 use TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction;
 use TYPO3\CMS\Core\DataHandling\PlainDataResolver;
-use TYPO3\CMS\Core\Type\Bitmask\Permission;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Versioning\VersionState;
 
@@ -122,7 +118,6 @@ class PageTreeRepository
      *
      * @param int $entryPoint the page ID to fetch the tree for
      * @param callable $callback a callback to be used to check for permissions and filter out pages not to be included.
-     * @param array $dbMounts
      * @return array
      */
     public function getTree(int $entryPoint, callable $callback = null, array $dbMounts = []): array
@@ -160,133 +155,6 @@ class PageTreeRepository
     }
 
     /**
-     * Get the page tree based on a given page record and a given depth
-     *
-     * @param array $pageTree The page record of the top level page you want to get the page tree of
-     * @param int $depth Number of levels to fetch
-     * @return array An array with page records and their children
-     */
-    public function getTreeLevels(array $pageTree, int $depth): array
-    {
-        $parentPageIds = [$pageTree['uid']];
-        $groupedAndSortedPagesByPid = [];
-        for ($i = 0; $i < $depth; $i++) {
-            if (empty($parentPageIds)) {
-                break;
-            }
-            $pageRecords = $this->getChildPages($parentPageIds);
-
-            $groupedAndSortedPagesByPid = $this->groupAndSortPages($pageRecords, $groupedAndSortedPagesByPid);
-
-            $parentPageIds = array_column($pageRecords, 'uid');
-        }
-        $this->addChildrenToPage($pageTree, $groupedAndSortedPagesByPid);
-        return $pageTree;
-    }
-
-    /**
-     * Get the child pages from the given parent pages
-     *
-     * @param array $parentPageIds
-     * @return array
-     */
-    protected function getChildPages(array $parentPageIds): array
-    {
-        $pageRecords = $this->getChildPageRecords($parentPageIds);
-
-        foreach ($pageRecords as &$pageRecord) {
-            $pageRecord['uid'] = (int)$pageRecord['uid'];
-
-            if ($this->currentWorkspace > 0) {
-                if ((int)$pageRecord['t3ver_state'] === VersionState::MOVE_PLACEHOLDER) {
-                    $liveRecord = BackendUtility::getRecord('pages', $pageRecord['t3ver_move_id']);
-                    $pageRecord['uid'] = (int)$pageRecord['t3ver_move_id'];
-                    $pageRecord['title'] = $liveRecord['title'];
-                }
-
-                if ((int)$pageRecord['t3ver_oid'] > 0) {
-                    $liveRecord = BackendUtility::getRecord('pages', $pageRecord['t3ver_oid']);
-
-                    $pageRecord['uid'] = (int)$pageRecord['t3ver_oid'];
-                    $pageRecord['pid'] = (int)$liveRecord['pid'];
-                }
-            }
-        }
-        unset($pageRecord);
-
-        return $pageRecords;
-    }
-
-    /**
-     * Retrieve the page records based on the given parent page ids
-     *
-     * @param array $parentPageIds
-     * @return array
-     */
-    protected function getChildPageRecords(array $parentPageIds): array
-    {
-        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
-            ->getQueryBuilderForTable('pages');
-        $queryBuilder->getRestrictions()
-            ->removeAll()
-            ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
-            ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, $this->currentWorkspace));
-
-        if (!empty($this->additionalQueryRestrictions)) {
-            foreach ($this->additionalQueryRestrictions as $additionalQueryRestriction) {
-                $queryBuilder->getRestrictions()->add($additionalQueryRestriction);
-            }
-        }
-
-        $pageRecords = $queryBuilder
-            ->select(...$this->fields)
-            ->from('pages')
-            ->where(
-                $queryBuilder->expr()->eq('sys_language_uid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)),
-                $queryBuilder->expr()->in('pid', $queryBuilder->createNamedParameter($parentPageIds, Connection::PARAM_INT_ARRAY))
-            )
-            ->execute()
-            ->fetchAll();
-
-        // This is necessary to resolve all IDs in a workspace
-        if ($this->currentWorkspace !== 0 && !empty($pageRecords)) {
-            $livePageIds = array_column($pageRecords, 'uid');
-            // Resolve placeholders of workspace versions
-            $resolver = GeneralUtility::makeInstance(
-                PlainDataResolver::class,
-                'pages',
-                $livePageIds
-            );
-            $resolver->setWorkspaceId($this->currentWorkspace);
-            $resolver->setKeepDeletePlaceholder(false);
-            $resolver->setKeepMovePlaceholder(false);
-            $resolver->setKeepLiveIds(false);
-            $recordIds = $resolver->get();
-
-            if (!empty($recordIds)) {
-                $queryBuilder->getRestrictions()->removeAll();
-                $pageRecords = $queryBuilder
-                    ->select(...$this->fields)
-                    ->from('pages')
-                    ->where(
-                        $queryBuilder->expr()->in('uid', $queryBuilder->createNamedParameter($recordIds, Connection::PARAM_INT_ARRAY))
-                    )
-                    ->execute()
-                    ->fetchAll();
-            }
-        }
-
-        return $pageRecords;
-    }
-
-    public function hasChildren(int $pid): bool
-    {
-        $pageRecords = $this->getChildPageRecords([$pid]);
-
-        return !empty($pageRecords);
-    }
-
-    /**
      * Fetch all non-deleted pages, regardless of permissions. That's why it's internal.
      *
      * @return array the full page tree of the whole installation
@@ -444,210 +312,4 @@ class PageTreeRepository
         }
         return [];
     }
-
-    /**
-     * Retrieve the page tree based on the given search filter
-     *
-     * @param string $searchFilter
-     * @return array
-     */
-    public function fetchFilteredTree(string $searchFilter): array
-    {
-        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
-            ->getQueryBuilderForTable('pages');
-        $queryBuilder->getRestrictions()
-            ->removeAll()
-            ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
-
-        if ($this->getBackendUser()->workspace === 0) {
-            $queryBuilder->getRestrictions()->add(GeneralUtility::makeInstance(WorkspaceRestriction::class));
-        }
-
-        if (!empty($this->additionalQueryRestrictions)) {
-            foreach ($this->additionalQueryRestrictions as $additionalQueryRestriction) {
-                $queryBuilder->getRestrictions()->add($additionalQueryRestriction);
-            }
-        }
-
-        $expressionBuilder = $queryBuilder->expr();
-
-        $queryBuilder = $queryBuilder
-            ->select(...$this->fields)
-            ->from('pages')
-            ->where(
-                // Only show records in default language
-                $expressionBuilder->eq('sys_language_uid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT))
-            );
-
-        $queryBuilder->where(
-            QueryHelper::stripLogicalOperatorPrefix($this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW))
-        );
-        $searchParts = $expressionBuilder->orX();
-        if (is_numeric($searchFilter) && $searchFilter > 0) {
-            $searchParts->add(
-                $expressionBuilder->eq('uid', $queryBuilder->createNamedParameter($searchFilter, \PDO::PARAM_INT))
-            );
-        }
-        $searchFilter = '%' . $queryBuilder->escapeLikeWildcards($searchFilter) . '%';
-
-        $searchWhereAlias = $expressionBuilder->orX(
-            $expressionBuilder->like(
-                'nav_title',
-                $queryBuilder->createNamedParameter($searchFilter, \PDO::PARAM_STR)
-            ),
-            $expressionBuilder->like(
-                'title',
-                $queryBuilder->createNamedParameter($searchFilter, \PDO::PARAM_STR)
-            )
-        );
-        $searchParts->add($searchWhereAlias);
-
-        $queryBuilder->andWhere($searchParts);
-        $pageRecords = $queryBuilder->execute()
-            ->fetchAll();
-
-        $pages = [];
-        foreach ($pageRecords as $page) {
-            $pages[$page['uid']] = $page;
-        }
-
-        if ($this->getBackendUser()->workspace !== 0) {
-            foreach (array_unique(array_column($pages, 't3ver_oid')) as $t3verOid) {
-                if ($t3verOid !== 0) {
-                    unset($pages[$t3verOid]);
-                }
-            }
-        }
-        unset($pageRecords);
-
-        $pages = $this->filterPagesOnMountPoints($pages, $this->getAllowedMountPoints());
-
-        $groupedAndSortedPagesByPid = $this->groupAndSortPages($pages);
-
-        $this->fullPageTree = [
-            'uid' => 0,
-            'title' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] ?: 'TYPO3'
-        ];
-        $this->addChildrenToPage($this->fullPageTree, $groupedAndSortedPagesByPid);
-
-        return $this->fullPageTree;
-    }
-
-    /**
-     * Filter all records outside of the allowed mount points
-     *
-     * @param array $pages
-     * @param array $mountPoints
-     * @return array
-     */
-    protected function filterPagesOnMountPoints(array $pages, array $mountPoints): array
-    {
-        foreach ($pages as $key => $pageRecord) {
-            $rootline = BackendUtility::BEgetRootLine(
-                $pageRecord['uid'],
-                '',
-                $this->getBackendUser()->workspace != 0,
-                $this->fields
-            );
-            $rootline = array_reverse($rootline);
-            if (!in_array(0, $mountPoints, true)) {
-                $isInsideMountPoints = false;
-                foreach ($rootline as $rootlineElement) {
-                    if (in_array((int)$rootlineElement['uid'], $mountPoints, true)) {
-                        $isInsideMountPoints = true;
-                        break;
-                    }
-                }
-                if (!$isInsideMountPoints) {
-                    unset($pages[$key]);
-                    //skip records outside of the allowed mount points
-                    continue;
-                }
-            }
-
-            $inFilteredRootline = false;
-            $amountOfRootlineElements = count($rootline);
-            for ($i = 0; $i < $amountOfRootlineElements; ++$i) {
-                $rootlineElement = $rootline[$i];
-                $rootlineElement['uid'] = (int)$rootlineElement['uid'];
-                $isInWebMount = false;
-                if ($rootlineElement['uid'] > 0) {
-                    $isInWebMount = (int)$this->getBackendUser()->isInWebMount($rootlineElement);
-                }
-
-                if (!$isInWebMount
-                    || ($rootlineElement['uid'] === (int)$mountPoints[0]
-                        && $rootlineElement['uid'] !== $isInWebMount)
-                ) {
-                    continue;
-                }
-                if ($this->getBackendUser()->isAdmin() ||($rootlineElement['uid'] === $isInWebMount
-                        && in_array($rootlineElement['uid'], $mountPoints, true))
-                ) {
-                    $inFilteredRootline = true;
-                }
-                if (!$inFilteredRootline) {
-                    continue;
-                }
-
-                if (!isset($pages[$rootlineElement['uid']])) {
-                    $pages[$rootlineElement['uid']] = $rootlineElement;
-                }
-            }
-        }
-        // Make sure the mountpoints show up in page tree even when parent pages are not accessible pages
-        foreach ($mountPoints as $mountPoint) {
-            if ($mountPoint !== 0) {
-                if (!array_key_exists($mountPoint, $pages)) {
-                    $pages[$mountPoint] = BackendUtility::getRecord('pages', $mountPoint);
-                }
-                $pages[$mountPoint]['pid'] = 0;
-            }
-        }
-
-        return $pages;
-    }
-
-    /**
-     * Group pages by parent page and sort pages based on sorting property
-     *
-     * @param array $pages
-     * @param array $groupedAndSortedPagesByPid
-     * @return array
-     */
-    protected function groupAndSortPages(array $pages, $groupedAndSortedPagesByPid = []): array
-    {
-        foreach ($pages as $key => $pageRecord) {
-            $parentPageId = (int)$pageRecord['pid'];
-            $sorting = (int)$pageRecord['sorting'];
-            while (isset($groupedAndSortedPagesByPid[$parentPageId][$sorting])) {
-                $sorting++;
-            }
-            $groupedAndSortedPagesByPid[$parentPageId][$sorting] = $pageRecord;
-        }
-
-        return $groupedAndSortedPagesByPid;
-    }
-
-    /**
-     * Get allowed mountpoints. Returns temporary mountpoint when temporary mountpoint is used
-     * @return array
-     */
-    protected function getAllowedMountPoints(): array
-    {
-        $mountPoints = (int)($this->getBackendUser()->uc['pageTree_temporaryMountPoint'] ?? 0);
-        if (!$mountPoints) {
-            $mountPoints = array_map('intval', $this->getBackendUser()->returnWebmounts());
-            return array_unique($mountPoints);
-        }
-        return [$mountPoints];
-    }
-
-    /**
-     * @return BackendUserAuthentication
-     */
-    protected function getBackendUser(): BackendUserAuthentication
-    {
-        return $GLOBALS['BE_USER'];
-    }
 }
index 37053a5..a3955dc 100644 (file)
@@ -95,12 +95,6 @@ return [
         'target' => Controller\Page\TreeController::class . '::fetchDataAction'
     ],
 
-    // Get data for page tree
-    'page_tree_filter' => [
-        'path' => '/page/tree/filterData',
-        'target' => Controller\Page\TreeController::class . '::filterDataAction'
-    ],
-
     // Get page tree configuration
     'page_tree_configuration' => [
         'path' => '/page/tree/fetchConfiguration',
index 9ce08e2..bd7c8da 100644 (file)
@@ -32,14 +32,12 @@ define(['jquery',
      */
     var PageTree = function() {
       SvgTree.call(this);
-      this.originalNodes = [];
       this.settings.defaultProperties = {
         hasChildren: false,
         nameSourceField: 'title',
         prefix: '',
         suffix: '',
         locked: false,
-        loaded: false,
         overlayIcon: '',
         selectable: true,
         expanded: false,
@@ -53,7 +51,6 @@ define(['jquery',
     };
 
     PageTree.prototype = Object.create(SvgTree.prototype);
-
     var _super_ = SvgTree.prototype;
 
     /**
@@ -208,16 +205,6 @@ define(['jquery',
     };
 
     /**
-     * Finds node by its stateIdentifier (e.g. "0_360")
-     * @return {Node}
-     */
-    PageTree.prototype.getNodeByIdentifier = function(identifier) {
-      return this.nodes.find(function (node) {
-        return node.stateIdentifier === identifier;
-      });
-    };
-
-    /**
      * Observer for the selectedNode event
      *
      * @param {Node} node
@@ -295,59 +282,10 @@ define(['jquery',
     };
 
     PageTree.prototype.showChildren = function(node) {
-      this.loadChildrenOfNode(node);
       _super_.showChildren(node);
       Persistent.set('BackendComponents.States.Pagetree.stateHash.' + node.stateIdentifier, 1);
     };
 
-    /**
-     * Loads child nodes via Ajax (used when expanding a collapesed node)
-     *
-     * @param parentNode
-     * @return {boolean}
-     */
-    PageTree.prototype.loadChildrenOfNode = function(parentNode) {
-      if (parentNode.loaded) {
-        return;
-      }
-      var _this = this;
-      _this.nodesAddPlaceholder();
-      d3.json(_this.settings.dataUrl + '&pid=' + parentNode.identifier + '&mount=' + parentNode.mountPoint + '&pidDepth=' + parentNode.depth, function(error, json) {
-          if (error) {
-            var title = TYPO3.lang.pagetree_networkErrorTitle;
-            var desc = TYPO3.lang.pagetree_networkErrorDesc;
-
-            if (error && error.target && (error.target.status || error.target.statusText)) {
-              title += ' - ' + (error.target.status || '') + ' ' + (error.target.statusText || '');
-            }
-
-            Notification.error(
-              title,
-              desc);
-
-            _this.nodesRemovePlaceholder();
-            throw error;
-          }
-
-          var nodes = Array.isArray(json) ? json : [];
-          //first element is a parent
-          nodes.shift();
-          var index = _this.nodes.indexOf(parentNode) + 1;
-          //adding fetched node after parent
-          nodes.forEach(function (node, offset) {
-            _this.nodes.splice(index + offset, 0, node);
-          });
-
-          parentNode.loaded = true;
-          _this.setParametersNode();
-          _this.prepareDataForVisibleNodes();
-          _this.update();
-          _this.nodesRemovePlaceholder();
-          _this.switchFocusNode(parentNode);
-        });
-
-    };
-
     PageTree.prototype.updateNodeBgClass = function(nodeBg) {
       return _super_.updateNodeBgClass.call(this, nodeBg).call(this.dragDrop.drag());
     };
@@ -450,51 +388,6 @@ define(['jquery',
         });
     };
 
-    PageTree.prototype.filterTree = function(searchQuery) {
-      var _this = this;
-      _this.nodesAddPlaceholder();
-
-      d3.json(_this.settings.filterUrl + '&q=' + searchQuery, function(error, json) {
-        if (error) {
-          var title = TYPO3.lang.pagetree_networkErrorTitle;
-          var desc = TYPO3.lang.pagetree_networkErrorDesc;
-
-          if (error && error.target && (error.target.status || error.target.statusText)) {
-            title += ' - ' + (error.target.status || '') + ' ' + (error.target.statusText || '');
-          }
-
-          Notification.error(
-            title,
-            desc);
-
-          _this.nodesRemovePlaceholder();
-          throw error;
-        }
-
-        var nodes = Array.isArray(json) ? json : [];
-        if (nodes.length > 0) {
-          if (_this.originalNodes.length === 0) {
-            _this.originalNodes = JSON.stringify(_this.nodes);
-          }
-          _this.replaceData(nodes);
-        }
-        _this.nodesRemovePlaceholder();
-      });
-    };
-
-    PageTree.prototype.resetFilter = function() {
-        if (this.originalNodes.length > 0) {
-          var currentlySelected = this.getSelectedNodes()[0];
-          this.nodes = JSON.parse(this.originalNodes);
-          this.originalNodes = '';
-          if (currentlySelected) {
-            this.selectNode(this.getNodeByIdentifier(currentlySelected.stateIdentifier));
-          }
-        } else {
-          this.refreshTree();
-        }
-    };
-
     PageTree.prototype.setTemporaryMountPoint = function(pid) {
       var params = 'pid=' + pid;
       var _this = this;
index 3ca16ec..56b0f31 100644 (file)
@@ -71,14 +71,11 @@ define(['jquery',
         });
 
         var dataUrl = top.TYPO3.settings.ajaxUrls.page_tree_data;
-        var filterUrl = top.TYPO3.settings.ajaxUrls.page_tree_filter;
-
         var configurationUrl = top.TYPO3.settings.ajaxUrls.page_tree_configuration;
 
         $.ajax({url: configurationUrl}).done(function(configuration) {
           tree.initialize($element.find('#typo3-pagetree-tree'), $.extend(configuration, {
             dataUrl: dataUrl,
-            filterUrl: filterUrl,
             showIcons: true
           }));
 
index 5a6185c..83cb935 100644 (file)
@@ -66,6 +66,13 @@ define(['jquery',
        * @type {jQuery}
        */
       this.template = null;
+
+      /**
+       * Nodes stored encoded before tree gets filtered
+       *
+       * @type {string}
+       */
+      this.originalNodes = '';
     };
 
     /**
@@ -175,9 +182,7 @@ define(['jquery',
           if (input) {
             input.clearable({
               onClear: function (input) {
-                _this.tree.resetFilter();
-                _this.tree.prepareDataForVisibleNodes();
-                _this.tree.update();
+                $(input).trigger('input');
               }
             });
           }
@@ -199,10 +204,8 @@ define(['jquery',
         }
       });
 
-      $toolbar.find(this.settings.searchInput).on('keypress', function(e) {
-        if(e.keyCode === 13 || e.which === 13) {
-          _this.search.call(_this, this);
-        }
+      $toolbar.find(this.settings.searchInput).on('input', function() {
+        _this.search.call(_this, this);
       });
 
       $toolbar.find('[data-toggle="tooltip"]').tooltip();
@@ -229,11 +232,29 @@ define(['jquery',
     TreeToolbar.prototype.search = function(input) {
       var _this = this;
       var name = $(input).val().trim();
+
       if (name !== '') {
-        _this.tree.filterTree(name);
+        if (this.originalNodes.length === 0) {
+          this.originalNodes = JSON.stringify(this.tree.nodes);
+        }
+
+        this.tree.nodes[0].expanded = false;
+        this.tree.nodes.forEach(function (node) {
+          var regex = new RegExp(name, 'i');
+          if (node.identifier.toString() === name || regex.test(node.name) || regex.test(node.alias || '')) {
+            _this.showParents(node);
+            node.expanded = true;
+            node.hidden = false;
+          } else if (node.depth !== 0) {
+            node.hidden = true;
+            node.expanded = false;
+          }
+        });
       } else {
-        _this.tree.resetFilter();
+        this.tree.nodes = JSON.parse(this.originalNodes);
+        this.originalNodes = '';
       }
+
       this.tree.prepareDataForVisibleNodes();
       this.tree.update();
     };
index f7e3282..e066862 100644 (file)
@@ -160,7 +160,26 @@ class TreeControllerTest extends FunctionalTestCase
                             [
                                 'uid' => 1520,
                                 'title' => 'Forecasts',
-                                '_children' => [],
+                                '_children' => [
+                                    [
+                                        'uid' => 1521,
+                                        'title' => 'Current Year',
+                                        '_children' => [
+                                        ],
+                                    ],
+                                    [
+                                        'uid' => 1522,
+                                        'title' => 'Next Year',
+                                        '_children' => [
+                                        ],
+                                    ],
+                                    [
+                                        'uid' => 1523,
+                                        'title' => 'Five Years',
+                                        '_children' => [
+                                        ],
+                                    ],
+                                ],
                             ],
                             [
                                 'uid' => 1530,
@@ -214,67 +233,6 @@ class TreeControllerTest extends FunctionalTestCase
     /**
      * @test
      */
-    public function getSubtreeForAccessiblePage()
-    {
-        $actual = $this->subject->_call('getAllEntryPointPageTrees', 1200);
-        $keepProperties = array_flip(['uid', 'title', '_children']);
-        $actual = $this->sortTreeArray($actual);
-        $actual = $this->normalizeTreeArray($actual, $keepProperties);
-
-        $expected = [
-            [
-                'uid' => 1200,
-                'title' => 'EN: Features',
-                '_children' => [
-                    [
-                        'uid' => 1210,
-                        'title' => 'EN: Frontend Editing',
-                        '_children' => [
-                        ],
-                    ],
-                    [
-                        'uid' => 1230,
-                        'title' => 'EN: Managing content',
-                        '_children' => [
-                        ],
-                    ],
-                ],
-            ],
-        ];
-        self::assertEquals($expected, $actual);
-    }
-
-    /**
-     * @test
-     */
-    public function getSubtreeForNonAccessiblePage()
-    {
-        $actual = $this->subject->_call('getAllEntryPointPageTrees', 1510);
-        $keepProperties = array_flip(['uid', 'title', '_children']);
-        $actual = $this->sortTreeArray($actual);
-        $actual = $this->normalizeTreeArray($actual, $keepProperties);
-
-        $expected = [];
-        self::assertEquals($expected, $actual);
-    }
-
-    /**
-     * @test
-     */
-    public function getSubtreeForPageOutsideMountPoint()
-    {
-        $actual = $this->subject->_call('getAllEntryPointPageTrees', 7000);
-        $keepProperties = array_flip(['uid', 'title', '_children']);
-        $actual = $this->sortTreeArray($actual);
-        $actual = $this->normalizeTreeArray($actual, $keepProperties);
-
-        $expected = [];
-        self::assertEquals($expected, $actual);
-    }
-
-    /**
-     * @test
-     */
     public function getAllEntryPointPageTreesInWorkspace()
     {
         $this->setWorkspace(1);
@@ -313,7 +271,14 @@ class TreeControllerTest extends FunctionalTestCase
                             [
                                 'uid' => 1240,
                                 'title' => 'EN: Managing data',
-                                '_children' => [],
+                                '_children' => [
+                                    [
+                                        'uid' => 124010,
+                                        'title' => 'EN: Managing complex data',
+                                        '_children' => [
+                                        ],
+                                    ],
+                                ],
                             ],
                             [
                                 'uid' => 1210,
@@ -348,7 +313,26 @@ class TreeControllerTest extends FunctionalTestCase
                             [
                                 'uid' => 1520,
                                 'title' => 'Forecasts',
-                                '_children' => [],
+                                '_children' => [
+                                    [
+                                        'uid' => 1521,
+                                        'title' => 'Current Year',
+                                        '_children' => [
+                                        ],
+                                    ],
+                                    [
+                                        'uid' => 1522,
+                                        'title' => 'Next Year',
+                                        '_children' => [
+                                        ],
+                                    ],
+                                    [
+                                        'uid' => 1523,
+                                        'title' => 'Five Years',
+                                        '_children' => [
+                                        ],
+                                    ],
+                                ],
                             ],
                             [
                                 'uid' => 1530,
@@ -367,7 +351,13 @@ class TreeControllerTest extends FunctionalTestCase
                                 // from pid 1510 (missing permissions) to pid 1700 (visible now)
                                 'uid' => 1511,
                                 'title' => 'Products',
-                                '_children' => [],
+                                '_children' => [
+                                    [
+                                        'uid' => 151110,
+                                        'title' => 'Product 1',
+                                        '_children' => [],
+                                    ]
+                                ],
                             ],
                         ],
                     ],
@@ -407,39 +397,6 @@ class TreeControllerTest extends FunctionalTestCase
     }
 
     /**
-     * @test
-     */
-    public function getSubtreeForAccessiblePageInWorkspace()
-    {
-        $actual = $this->subject->_call('getAllEntryPointPageTrees', 1200);
-        $keepProperties = array_flip(['uid', 'title', '_children']);
-        $actual = $this->sortTreeArray($actual);
-        $actual = $this->normalizeTreeArray($actual, $keepProperties);
-
-        $expected = [
-            [
-                'uid' => 1200,
-                'title' => 'EN: Features',
-                '_children' => [
-                    [
-                        'uid' => 1210,
-                        'title' => 'EN: Frontend Editing',
-                        '_children' => [
-                        ],
-                    ],
-                    [
-                        'uid' => 1230,
-                        'title' => 'EN: Managing content',
-                        '_children' => [
-                        ],
-                    ],
-                ],
-            ],
-        ];
-        self::assertEquals($expected, $actual);
-    }
-
-    /**
      * @param int $workspaceId
      */
     private function setWorkspace(int $workspaceId)
index 9527969..bca830f 100644 (file)
@@ -1072,7 +1072,7 @@ Do you want to refresh it now?</source>
                                <source>Filter tree</source>
                        </trans-unit>
                        <trans-unit id="tree.searchTermInfo" resname="tree.searchTermInfo">
-                               <source>Enter search term and hit enter</source>
+                               <source>Enter search term</source>
                        </trans-unit>
                        <trans-unit id="warning.install_password" resname="warning.install_password">
                                <source>The Install Tool is still using the default password "joh316". Update this within the %sAbout section%s of the Install Tool.</source>