diff --git a/Classes/Typo3/Hook/HappyFeetLinkWizzard.php b/Classes/Typo3/Hook/HappyFeetLinkWizzard.php new file mode 100644 index 0000000..28d984a --- /dev/null +++ b/Classes/Typo3/Hook/HappyFeetLinkWizzard.php @@ -0,0 +1,282 @@ +.configuration) + */ + private array $configuration = []; + + /** + * Parts of the current link + */ + private array $linkParts = []; + + private int $expandPage = 0; + + public function __construct( + private readonly ElementBrowserRecordList $elementBrowserRecordList, + private readonly RecordSearchBoxComponent $recordSearchBoxComponent, + private readonly LinkService $linkService, + ) { + parent::__construct(); + } + + public function initialize(AbstractLinkBrowserController $linkBrowser, $identifier, array $configuration): void + { + parent::initialize($linkBrowser, $identifier, $configuration); + $this->identifier = $identifier; + if (empty($configuration['table'])) { + throw new \LogicException( + 'Page TSconfig TCEMAIN.linkHandler.' . $identifier . '.configuration.table is mandatory and must be set to a table name.', + 1657960610 + ); + } + + $this->configuration = $configuration; + } + + /** + * Checks if this is the right handler for the given link. + * Also stores information locally about currently linked record. + * + * @param array $linkParts Link parts as returned from TypoLinkCodecService + */ + public function canHandleLink(array $linkParts): bool + { + if (isset($linkParts['type']) && ($linkParts['type'] == null || strcmp($linkParts['type'], 'happy_feet') !== 0)) { + return false; + } + + if (!$linkParts['url']) { + return false; + } + + $data = $linkParts['url']; + + // Get the related record + $table = $this->configuration['table']; + $record = BackendUtility::getRecord($table, $data['uid']); + if ($record === null) { + $linkParts['title'] = $this->getLanguageService()->sL( + 'LLL:EXT:backend/Resources/Private/Language/locallang_browse_links.xlf:recordNotFound' + ); + } else { + $linkParts['pid'] = (int) $record['pid']; + $linkParts['title'] = empty($linkParts['title']) ? BackendUtility::getRecordTitle($table, $record) : $linkParts['title']; + } + + $linkParts['tableName'] = $this->getLanguageService()->sL($GLOBALS['TCA'][$table]['ctrl']['title']); + $linkParts['url']['type'] = $linkParts['type']; + $this->linkParts = $linkParts; + + return true; + } + + /** + * Formats information for the current record for HTML output. + */ + public function formatCurrentUrl(): string + { + return sprintf( + '%s: %s [uid: %d]', + $this->linkParts['tableName'], + $this->linkParts['title'], + $this->linkParts['url']['uid'] + ); + } + + /** + * Renders the link handler. + */ + public function render(ServerRequestInterface $request): string + { + $this->pageRenderer->loadJavaScriptModule('@typo3/backend/record-link-handler.js'); + $this->pageRenderer->loadJavaScriptModule('@typo3/backend/record-search.js'); + $this->pageRenderer->loadJavaScriptModule('@typo3/backend/viewport/resizable-navigation.js'); + $this->pageRenderer->loadJavaScriptModule('@typo3/backend/column-selector-button.js'); + $this->pageRenderer->loadJavaScriptModule('@typo3/backend/tree/page-browser.js'); + $this->getBackendUser() + ->initializeWebmountsForElementBrowser(); + + // Define the current page + if (isset($request->getQueryParams()['expandPage'])) { + $this->expandPage = (int) $request->getQueryParams()['expandPage']; + } elseif (isset($this->configuration['storagePid'])) { + $this->expandPage = (int) $this->configuration['storagePid']; + } elseif (isset($this->linkParts['pid'])) { + $this->expandPage = (int) $this->linkParts['pid']; + } + + $pageTreeMountPoints = (string) ($this->configuration['pageTreeMountPoints'] ?? ''); + $this->view->assignMultiple([ + 'treeEnabled' => (bool) ($this->configuration['hidePageTree'] ?? false) === false, + 'pageTreeMountPoints' => GeneralUtility::intExplode(',', $pageTreeMountPoints, true), + 'recordList' => $this->renderTableRecords($request), + 'initialNavigationWidth' => $this->getBackendUser() + ->uc['selector']['navigation']['width'] ?? 250, + 'treeActions' => ['link'], + ]); + + return $this->view->render('LinkBrowser/Record'); + } + + /** + * Returns attributes for the body tag. + * + * @return string[] Array of body-tag attributes + */ + public function getBodyTagAttributes(): array + { + $attributes = [ + 'data-linkbrowser-identifier' => 't3://happy_feet?uid=', + ]; + if ($this->linkParts !== []) { + $attributes['data-linkbrowser-current-link'] = $this->linkService->asString($this->linkParts['url']); + } + + return $attributes; + } + + /** + * Returns all parameters needed to build a URL with all the necessary information. + * + * @param array $values Array of values to include into the parameters or which might influence the parameters + * @return string[] Array of parameters which have to be added to URLs + */ + public function getUrlParameters(array $values): array + { + $pid = isset($values['pid']) ? (int) $values['pid'] : $this->expandPage; + $parameters = [ + 'expandPage' => $pid, + ]; + + return array_merge( + $this->linkBrowser->getUrlParameters($values), + ['P' => $this->linkBrowser->getParameters()], + $parameters + ); + } + + /** + * Checks if the submitted page matches the current page. + * + * @param array $values Values to be checked + * @return bool Returns TRUE if the given values match the currently selected item + */ + public function isCurrentlySelectedItem(array $values): bool + { + return $this->linkParts !== [] && (int) $this->linkParts['pid'] === (int) $values['pid']; + } + + /** + * Returns the URL of the current script + */ + public function getScriptUrl(): string + { + return $this->linkBrowser->getScriptUrl(); + } + + /** + * Render elements of configured table + */ + private function renderTableRecords(ServerRequestInterface $request): string + { + $html = []; + $backendUser = $this->getBackendUser(); + $selectedPage = $this->expandPage; + if ($selectedPage < 0 || !$backendUser->isInWebMount($selectedPage)) { + return ''; + } + + $table = $this->configuration['table']; + $permsClause = $backendUser->getPagePermsClause(Permission::PAGE_SHOW); + $pageInfo = BackendUtility::readPageAccess($selectedPage, $permsClause); + $selectedTable = (string) ($request->getParsedBody()['table'] ?? $request->getQueryParams()['table'] ?? ''); + $searchWord = (string) ($request->getParsedBody()['searchTerm'] ?? $request->getQueryParams()['searchTerm'] ?? ''); + $pointer = (int) ($request->getParsedBody()['pointer'] ?? $request->getQueryParams()['pointer'] ?? 0); + + // If table is 'pages', add a pre-entry to make selected page selectable directly. + $titleLen = (int) $backendUser->uc['titleLen']; + $mainPageRecord = BackendUtility::getRecordWSOL('pages', $selectedPage); + if (is_array($mainPageRecord)) { + $pText = htmlspecialchars(GeneralUtility::fixed_lgd_cs($mainPageRecord['title'], $titleLen)); + $html[] = '

' . $this->iconFactory->getIconForRecord('pages', $mainPageRecord, Icon::SIZE_SMALL)->render() . ' '; + if ($table === 'pages') { + $html[] = ''; + $html[] = '' . $this->iconFactory->getIcon( + 'actions-plus', + Icon::SIZE_SMALL + )->render() . ''; + $html[] = '' . $pText . ''; + $html[] = ''; + } else { + $html[] = $pText; + } + + $html[] = '

'; + } + + $dbList = $this->elementBrowserRecordList; + $dbList->setRequest($request); + $dbList->setOverrideUrlParameters( + array_merge($this->getUrlParameters([]), ['mode' => 'db', 'expandPage' => $selectedPage]), + $request + ); + $dbList->setIsEditable(false); + + $dbList->calcPerms = new Permission($backendUser->calcPerms($pageInfo)); + $dbList->noControlPanels = true; + $dbList->clickMenuEnabled = false; + $dbList->displayRecordDownload = false; + $dbList->tableList = $table; + $dbList->start($selectedPage, $selectedTable, MathUtility::forceIntegerInRange($pointer, 0, 100000), $searchWord); + + $html[] = $this->recordSearchBoxComponent + ->setSearchWord($searchWord) + ->render($request, $dbList->listURL('', '-1', 'pointer,searchTerm')); + $html[] = $dbList->generateList(); + + return implode("\n", $html); + } +} diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml index 61fee9a..bde78b8 100644 --- a/Configuration/Services.yaml +++ b/Configuration/Services.yaml @@ -14,3 +14,6 @@ services: AOE\HappyFeet\Service\RenderingService: AOE\HappyFeet\Domain\Repository\FootnoteRepository: + + AOE\HappyFeet\Typo3\Hook\HappyFeetLinkWizzard: + public: true diff --git a/Configuration/TsConfig/Page/TceMain.tsconfig b/Configuration/TsConfig/Page/TceMain.tsconfig index 3b38ec4..375d689 100644 --- a/Configuration/TsConfig/Page/TceMain.tsconfig +++ b/Configuration/TsConfig/Page/TceMain.tsconfig @@ -1,10 +1,21 @@ -TCEMAIN.linkHandler { - happy_feet { - handler = AOE\HappyFeet\Typo3\Hook\LinkWizzard +#TCEMAIN.linkHandler { +# happy_feet { +# handler = AOE\HappyFeet\Typo3\Hook\LinkWizzard +# label = LLL:EXT:happy_feet/Resources/Private/Language/locallang_db.xlf:tx_happyfeet_domain_model_footnote +# configuration.table = tx_happyfeet_domain_model_footnote +# scanBefore = page +# } +#} + +TCEMAIN.linkHandler.happy_feet { + handler = AOE\HappyFeet\Typo3\Hook\HappyFeetLinkWizzard label = LLL:EXT:happy_feet/Resources/Private/Language/locallang_db.xlf:tx_happyfeet_domain_model_footnote - configuration.table = tx_happyfeet_domain_model_footnote + configuration { + table = tx_happyfeet_domain_model_footnote + storagePid = 49 + pageTreeMountPoints = 49 + } scanBefore = page - } } RTE { diff --git a/ext_localconf.php b/ext_localconf.php index fa8d8ae..87db85a 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -15,8 +15,8 @@ "@import 'EXT:happy_feet/Configuration/TsConfig/Page/TceMain.tsconfig'" ); -$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass']['happy_feet'] = - Tcemain::class; +#$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass']['happy_feet'] = +# Tcemain::class; $GLOBALS['TYPO3_CONF_VARS']['FE']['typolinkBuilder']['happy_feet'] = LinkRenderer::class; $GLOBALS['TYPO3_CONF_VARS']['SYS']['linkHandler']['happy_feet'] = LinkHandler::class;