diff --git a/Classes/Middleware/FrontendEditInitiator.php b/Classes/Middleware/FrontendEditInitiator.php index c50fef6..6a1c792 100644 --- a/Classes/Middleware/FrontendEditInitiator.php +++ b/Classes/Middleware/FrontendEditInitiator.php @@ -20,9 +20,11 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; +use TYPO3\CMS\Adminpanel\Service\ConfigurationService; use TYPO3\CMS\Backend\FrontendBackendUserAuthentication; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Feedit\DataHandling\FrontendEditDataHandler; +use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController; /** * PSR-15 middleware initializing frontend editing @@ -43,6 +45,11 @@ class FrontendEditInitiator implements MiddlewareInterface public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { if (isset($GLOBALS['BE_USER']) && $GLOBALS['BE_USER'] instanceof FrontendBackendUserAuthentication) { + $this->initializeTypoScriptFrontend( + $GLOBALS['TSFE'], + $request, + GeneralUtility::makeInstance(ConfigurationService::class) + ); $config = $GLOBALS['BE_USER']->getTSConfig()['admPanel.'] ?? []; $active = (int)$GLOBALS['TSFE']->displayEditIcons === 1 || (int)$GLOBALS['TSFE']->displayFieldEditIcons === 1; // Include classes for editing IF editing module in Admin Panel is open @@ -83,4 +90,23 @@ class FrontendEditInitiator implements MiddlewareInterface } return false; } + + protected function initializeTypoScriptFrontend( + TypoScriptFrontendController $typoScriptFrontend, + ServerRequestInterface $request, + ConfigurationService $configurationService + ): void { + $typoScriptFrontend->displayEditIcons = $configurationService->getConfigurationOption('edit', 'displayIcons'); + $typoScriptFrontend->displayFieldEditIcons = $configurationService->getConfigurationOption('edit', 'displayFieldIcons'); + + if ($request->getQueryParams()['ADMCMD_editIcons'] ?? $request->getParsedBody()['ADMCMD_editIcons'] ?? false) { + $typoScriptFrontend->displayFieldEditIcons = '1'; + } + if ($typoScriptFrontend->displayEditIcons) { + $typoScriptFrontend->set_no_cache('Admin Panel: Display edit icons', true); + } + if ($typoScriptFrontend->displayFieldEditIcons) { + $typoScriptFrontend->set_no_cache('Admin Panel: Display field edit icons', true); + } + } } diff --git a/Classes/Modules/EditModule.php b/Classes/Modules/EditModule.php index cf67ad7..67c86f0 100644 --- a/Classes/Modules/EditModule.php +++ b/Classes/Modules/EditModule.php @@ -21,9 +21,10 @@ use TYPO3\CMS\Adminpanel\ModuleApi\AbstractModule; use TYPO3\CMS\Adminpanel\ModuleApi\InitializableInterface; use TYPO3\CMS\Adminpanel\ModuleApi\PageSettingsProviderInterface; use TYPO3\CMS\Adminpanel\ModuleApi\ResourceProviderInterface; -use TYPO3\CMS\Adminpanel\Service\EditToolbarService; +use TYPO3\CMS\Backend\Routing\UriBuilder; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Feedit\Service\EditToolbarService; use TYPO3\CMS\Fluid\View\StandaloneView; use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController; @@ -32,6 +33,20 @@ use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController; */ class EditModule extends AbstractModule implements PageSettingsProviderInterface, InitializableInterface, ResourceProviderInterface { + /** + * @var UriBuilder + */ + protected $uriBuilder; + + /** + * @param UriBuilder $uriBuilder + */ + public function __construct(UriBuilder $uriBuilder) + { + parent::__construct(); + $this->uriBuilder = $uriBuilder; + } + /** * Creates the content for the "edit" section ("module") of the Admin Panel * @@ -53,9 +68,12 @@ class EditModule extends AbstractModule implements PageSettingsProviderInterface ], 'toolbar' => $toolbar, 'script' => [ - 'pageUid' => (int)$this->getTypoScriptFrontendController()->page['uid'], - 'pageModule' => $this->getPageModule(), - 'backendScript' => BackendUtility::getBackendScript(), + 'backendScript' => $this->uriBuilder->buildUriFromRoute( + 'web_layout', + [ + 'id' => (int)$this->getTypoScriptFrontendController()->page['uid'], + ] + ), 't3BeSitenameMd5' => md5('Typo3Backend-' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']), ], ] @@ -113,19 +131,6 @@ class EditModule extends AbstractModule implements PageSettingsProviderInterface */ public function initializeModule(ServerRequestInterface $request): void { - $typoScriptFrontend = $this->getTypoScriptFrontendController(); - $typoScriptFrontend->displayEditIcons = $this->configurationService->getConfigurationOption('edit', 'displayIcons'); - $typoScriptFrontend->displayFieldEditIcons = $this->configurationService->getConfigurationOption('edit', 'displayFieldIcons'); - - if ($request->getQueryParams()['ADMCMD_editIcons'] ?? $request->getParsedBody()['ADMCMD_editIcons'] ?? false) { - $typoScriptFrontend->displayFieldEditIcons = '1'; - } - if ($typoScriptFrontend->displayEditIcons) { - $typoScriptFrontend->set_no_cache('Admin Panel: Display edit icons', true); - } - if ($typoScriptFrontend->displayFieldEditIcons) { - $typoScriptFrontend->set_no_cache('Admin Panel: Display field edit icons', true); - } } /** diff --git a/Classes/Service/EditToolbarService.php b/Classes/Service/EditToolbarService.php new file mode 100644 index 0000000..94d387f --- /dev/null +++ b/Classes/Service/EditToolbarService.php @@ -0,0 +1,293 @@ +-tags linking them to proper functions. + */ + public function createToolbar(): string + { + /** @var LanguageAspect $languageAspect */ + $languageAspect = GeneralUtility::makeInstance(Context::class)->getAspect('language'); + $iconFactory = GeneralUtility::makeInstance(IconFactory::class); + $tsfe = $this->getTypoScriptFrontendController(); + // If mod.newContentElementWizard.override is set, use that extension's create new content wizard instead: + $moduleName = BackendUtility::getPagesTSconfig($tsfe->page['uid'])['mod.']['newContentElementWizard.']['override'] ?? 'new_content_element'; + $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); + $perms = $this->getBackendUser()->calcPerms($tsfe->page); + $langAllowed = $this->getBackendUser()->checkLanguageAccess($languageAspect->getId()); + $id = $tsfe->id; + $returnUrl = GeneralUtility::getIndpEnv('REQUEST_URI'); + $classes = 'typo3-adminPanel-btn typo3-adminPanel-btn-default typo3-adminPanel-btn-openBackend'; + $output = []; + $output[] = '
'; + $output[] = '
'; + $t3BeSitenameMd5 = md5('Typo3Backend-' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']); + + // History + $link = (string)$uriBuilder->buildUriFromRoute( + 'record_history', + [ + 'element' => 'pages:' . $id, + 'returnUrl' => $returnUrl, + ] + ); + $title = $this->getLabel('edit_recordHistory'); + $output[] = ''; + $output[] = ' ' . $iconFactory->getIcon('actions-document-history-open', Icon::SIZE_SMALL)->render(); + $output[] = ''; + + // New Content + if ($perms & Permission::CONTENT_EDIT && $langAllowed) { + $linkParameters = [ + 'id' => $id, + 'returnUrl' => $returnUrl, + ]; + if (!empty($languageAspect->getId())) { + $linkParameters['sys_language_uid'] = $languageAspect->getId(); + } + $link = (string)$uriBuilder->buildUriFromRoute($moduleName, $linkParameters); + $icon = $iconFactory->getIcon('actions-add', Icon::SIZE_SMALL)->render(); + $title = $this->getLabel('edit_newContentElement'); + $output[] = ''; + $output[] = ' ' . $icon; + $output[] = ''; + } + + // Move Page + if ($perms & Permission::PAGE_EDIT) { + $link = (string)$uriBuilder->buildUriFromRoute( + 'move_element', + [ + 'table' => 'pages', + 'uid' => $id, + 'returnUrl' => $returnUrl, + ] + ); + $icon = $iconFactory->getIcon('actions-document-move', Icon::SIZE_SMALL)->render(); + $title = $this->getLabel('edit_move_page'); + $output[] = ''; + $output[] = ' ' . $icon; + $output[] = ''; + } + + // New Page + if ($perms & Permission::PAGE_NEW) { + $link = (string)$uriBuilder->buildUriFromRoute( + 'db_new', + [ + 'id' => $id, + 'pagesOnly' => 1, + 'returnUrl' => $returnUrl, + ] + ); + $icon = $iconFactory->getIcon('actions-page-new', Icon::SIZE_SMALL)->render(); + $title = $this->getLabel('edit_newPage'); + $output[] = ''; + $output[] = ' ' . $icon; + $output[] = ''; + } + + // Edit Page + if ($perms & Permission::PAGE_EDIT) { + $link = (string)$uriBuilder->buildUriFromRoute( + 'record_edit', + [ + 'edit[pages][' . $id . ']' => 'edit', + 'noView' => 1, + 'returnUrl' => $returnUrl, + ] + ); + $icon = $iconFactory->getIcon('actions-page-open', Icon::SIZE_SMALL)->render(); + $title = $this->getLabel('edit_editPageProperties'); + $output[] = ''; + $output[] = ' ' . $icon; + $output[] = ''; + } + + // Edit Page Overlay + if ($perms & Permission::PAGE_EDIT && $languageAspect->getId() > 0 && $langAllowed) { + $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) + ->getQueryBuilderForTable('pages'); + $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class)); + $row = $queryBuilder + ->select('uid', 'pid', 't3ver_state') + ->from('pages') + ->where( + $queryBuilder->expr()->eq( + $GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'], + $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT) + ), + $queryBuilder->expr()->eq( + $GLOBALS['TCA']['pages']['ctrl']['languageField'], + $queryBuilder->createNamedParameter($languageAspect->getId(), \PDO::PARAM_INT) + ) + ) + ->setMaxResults(1) + ->execute() + ->fetch(); + $tsfe->sys_page->versionOL('pages', $row); + if (is_array($row)) { + $link = (string)$uriBuilder->buildUriFromRoute( + 'record_edit', + [ + 'edit[pages][' . $row['uid'] . ']' => 'edit', + 'noView' => 1, + 'returnUrl' => $returnUrl, + ] + ); + $icon = $iconFactory->getIcon('mimetypes-x-content-page-language-overlay', Icon::SIZE_SMALL) + ->render(); + $title = $this->getLabel('edit_editPageOverlay'); + $output[] = ''; + $output[] = ' ' . $icon; + $output[] = ''; + } + } + + // Open list view + if ($this->getBackendUser()->check('modules', 'web_list')) { + $link = (string)$uriBuilder->buildUriFromRoute( + 'web_list', + [ + 'id' => $id, + 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI'), + ] + ); + $icon = $iconFactory->getIcon('actions-system-list-open', Icon::SIZE_SMALL)->render(); + $title = $this->getLabel('edit_db_list'); + $output[] = ''; + $output[] = ' ' . $icon; + $output[] = ''; + } + + $output[] = '
'; + $output[] = '
'; + return implode('', $output); + } + + /** + * Translate given key + * + * @param string $key Key for a label in the $LOCAL_LANG array of "sysext/core/Resources/Private/Language/locallang_tsfe.xlf + * @return string The value for the $key + */ + protected function getLabel($key): ?string + { + return htmlspecialchars( + $this->getLanguageService()->sL('LLL:EXT:feedit/Resources/Private/Language/locallang_edit.xlf:' . $key), + ENT_QUOTES | ENT_HTML5 + ); + } + + /** + * @return FrontendBackendUserAuthentication + */ + protected function getBackendUser(): FrontendBackendUserAuthentication + { + return $GLOBALS['BE_USER']; + } + + /** + * @return LanguageService + */ + protected function getLanguageService(): LanguageService + { + return $GLOBALS['LANG']; + } + + /** + * @return TypoScriptFrontendController + */ + protected function getTypoScriptFrontendController(): TypoScriptFrontendController + { + return $GLOBALS['TSFE']; + } +} diff --git a/Configuration/RequestMiddlewares.php b/Configuration/RequestMiddlewares.php index 71ca4ac..5f8b4dd 100644 --- a/Configuration/RequestMiddlewares.php +++ b/Configuration/RequestMiddlewares.php @@ -15,7 +15,10 @@ return [ 'after' => [ 'typo3/cms-adminpanel/initiator', 'typo3/cms-frontend/page-resolver', - ] + ], + 'before' => [ + 'typo3/cms-frontend/prepare-tsfe-rendering', + ], ], ] ]; diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml new file mode 100644 index 0000000..1c9db19 --- /dev/null +++ b/Configuration/Services.yaml @@ -0,0 +1,11 @@ +services: + _defaults: + autowire: true + autoconfigure: true + public: false + + TYPO3\CMS\Feedit\: + resource: '../Classes/*' + + TYPO3\CMS\Feedit\Modules\EditModule: + public: true diff --git a/Resources/Private/Language/locallang_edit.xlf b/Resources/Private/Language/locallang_edit.xlf index 3e00082..bbb4aba 100644 --- a/Resources/Private/Language/locallang_edit.xlf +++ b/Resources/Private/Language/locallang_edit.xlf @@ -16,6 +16,36 @@ Open TYPO3 Backend + + Editing + + + Editforms on page + + + No popup window + + + View record change history + + + Create new content element + + + Move page + + + Create new page + + + Edit page properties + + + Edit properties of translated page + + + Web>List module + diff --git a/Resources/Private/Templates/Modules/Settings/Edit.html b/Resources/Private/Templates/Modules/Settings/Edit.html index 6e68f49..5433086 100644 --- a/Resources/Private/Templates/Modules/Settings/Edit.html +++ b/Resources/Private/Templates/Modules/Settings/Edit.html @@ -9,7 +9,7 @@ value: display.displayIcons }" debug="false"/> {toolbar}
- +
diff --git a/Resources/Public/JavaScript/Modules/Edit.js b/Resources/Public/JavaScript/Modules/Edit.js index 0fee2e8..48d6381 100644 --- a/Resources/Public/JavaScript/Modules/Edit.js +++ b/Resources/Public/JavaScript/Modules/Edit.js @@ -1,23 +1,30 @@ +this.Element && function(ElementPrototype) { + ElementPrototype.closest = ElementPrototype.closest || + function(selector) { + var el = this; + while (el.matches && !el.matches(selector)) el = el.parentNode; + return el.matches ? el : null; + } +}(Element.prototype); + function editModuleOnClickHandler(event) { event.preventDefault(); var element = event.target; - if (parent.opener && parent.opener.top) { - parent.opener.top.fsMod.recentIds['web'] = element.getAttribute('data-pageUid'); - if (parent.opener.top && parent.opener.top.nav_frame && parent.opener.top.nav_frame.refresh_nav) { - parent.opener.top.nav_frame.refresh_nav(); - } - parent.opener.top.goToModule(element.getAttribute('data-pageModule')); - parent.opener.top.focus(); - } else { - var vHWin = window.open(element.getAttribute('data-backendScript'), element.getAttribute('data-t3BeSitenameMd5')); - vHWin.focus(); + + if (element.tagName !== 'A') { + element = element.closest('A.typo3-adminPanel-btn-openBackend'); } + + var vHWin = window.open(element.getAttribute('data-backendScript'), element.getAttribute('data-t3BeSitenameMd5')); + vHWin.focus(); return false; } function initializeEditModule() { - var editModuleBtnOpenBackend = document.querySelector('.typo3-adminPanel-btn-openBackend'); - editModuleBtnOpenBackend.addEventListener('click', editModuleOnClickHandler); + var editModuleBtnsOpenBackend = document.querySelectorAll('.typo3-adminPanel-btn-openBackend'); + for (var i = 0, len = editModuleBtnsOpenBackend.length; i < len; i++ ) { + editModuleBtnsOpenBackend[i].addEventListener('click', editModuleOnClickHandler); + } }