From a0787e3a4a25fa6f2ad73c1699dd9458aa2b959c Mon Sep 17 00:00:00 2001 From: Benni Mack Date: Tue, 27 Feb 2018 21:11:20 +0100 Subject: [PATCH] [TASK] Clean up workspace preview top bar The preview controller is now not attached to the backend module anymore, as the Preview functionality ("Split Bar on top") is technically a completely separate backend preview and completely unrelated to the workspaces Backend Module. This change also removes several hacks to generate Backend URLs. Resolves: #84074 Releases: master Change-Id: Id0ce7093f6d3ac94c8e4a9cfecd78027d26d45df Reviewed-on: https://review.typo3.org/55931 Tested-by: TYPO3com Reviewed-by: Andreas Fernandez Tested-by: Andreas Fernandez Reviewed-by: Wouter Wolters Reviewed-by: Daniel Gorges Tested-by: Daniel Gorges Reviewed-by: Benni Mack Tested-by: Benni Mack --- .../Classes/Controller/AbstractController.php | 165 ------------- .../Classes/Controller/AjaxController.php | 3 +- .../Classes/Controller/PreviewController.php | 228 ++++++++---------- .../Classes/Controller/ReviewController.php | 184 +++++++++++--- .../Classes/Hook/BackendUtilityHook.php | 37 ++- .../Classes/Middleware/WorkspacePreview.php | 11 +- .../Classes/Service/WorkspaceService.php | 15 +- .../Configuration/Backend/Routes.php | 10 + .../Resources/Private/Layouts/Empty.html | 1 - .../Resources/Private/Layouts/Popup.html | 4 - .../Resources/Private/Partials/Legend.html | 2 +- .../Partials/Preview/StageButtons.html | 4 +- .../Private/Templates/Preview/Help.html | 5 - .../Private/Templates/Preview/Index.html | 99 ++++---- .../Private/Templates/Preview/NewPage.html | 5 - .../Private/Templates/Preview/Preview.html | 4 - typo3/sysext/workspaces/ext_tables.php | 3 +- 17 files changed, 347 insertions(+), 433 deletions(-) delete mode 100644 typo3/sysext/workspaces/Classes/Controller/AbstractController.php create mode 100644 typo3/sysext/workspaces/Configuration/Backend/Routes.php delete mode 100644 typo3/sysext/workspaces/Resources/Private/Layouts/Empty.html delete mode 100644 typo3/sysext/workspaces/Resources/Private/Layouts/Popup.html delete mode 100644 typo3/sysext/workspaces/Resources/Private/Templates/Preview/Help.html delete mode 100644 typo3/sysext/workspaces/Resources/Private/Templates/Preview/NewPage.html delete mode 100644 typo3/sysext/workspaces/Resources/Private/Templates/Preview/Preview.html diff --git a/typo3/sysext/workspaces/Classes/Controller/AbstractController.php b/typo3/sysext/workspaces/Classes/Controller/AbstractController.php deleted file mode 100644 index 40eb4449880d..000000000000 --- a/typo3/sysext/workspaces/Classes/Controller/AbstractController.php +++ /dev/null @@ -1,165 +0,0 @@ -pageRenderer = $this->getPageRenderer(); - // @todo Evaluate how the (int) typecast can be used with Extbase validators/filters - $this->pageId = (int)GeneralUtility::_GP('id'); - $iconFactory = GeneralUtility::makeInstance(IconFactory::class); - $lang = $this->getLanguageService(); - $icons = [ - 'language' => $iconFactory->getIcon('flags-multiple', Icon::SIZE_SMALL)->render(), - 'integrity' => $iconFactory->getIcon('status-dialog-information', Icon::SIZE_SMALL)->render(), - 'success' => $iconFactory->getIcon('status-dialog-ok', Icon::SIZE_SMALL)->render(), - 'info' => $iconFactory->getIcon('status-dialog-information', Icon::SIZE_SMALL)->render(), - 'warning' => $iconFactory->getIcon('status-dialog-warning', Icon::SIZE_SMALL)->render(), - 'error' => $iconFactory->getIcon('status-dialog-error', Icon::SIZE_SMALL)->render() - ]; - $this->pageRenderer->addInlineSetting('Workspaces', 'icons', $icons); - $this->pageRenderer->addInlineSetting('Workspaces', 'id', $this->pageId); - $this->pageRenderer->addInlineSetting('Workspaces', 'depth', $this->pageId === 0 ? 999 : 1); - $this->pageRenderer->addInlineSetting('Workspaces', 'language', $this->getLanguageSelection()); - $this->pageRenderer->addInlineLanguageLabelArray([ - 'title' => $lang->getLL('title'), - 'path' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.path'), - 'table' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.table'), - 'depth' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_mod_web_perm.xlf:Depth'), - 'depth_0' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_0'), - 'depth_1' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_1'), - 'depth_2' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_2'), - 'depth_3' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_3'), - 'depth_4' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_4'), - 'depth_infi' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_infi') - ]); - $this->pageRenderer->addInlineLanguageLabelFile('EXT:workspaces/Resources/Private/Language/locallang.xlf'); - $this->assignExtensionSettings(); - } - - /** - * Assigns additional Workspace settings to TYPO3.settings.Workspaces.extension - */ - protected function assignExtensionSettings() - { - $extension = [ - 'AdditionalColumn' => [ - 'Definition' => [], - 'Handler' => [], - ], - ]; - - $extension['AdditionalColumn']['Definition'] = $this->getAdditionalColumnService()->getDefinition(); - $extension['AdditionalColumn']['Handler'] = $this->getAdditionalColumnService()->getHandler(); - $this->pageRenderer->addInlineSetting('Workspaces', 'extension', $extension); - } - - /** - * Gets the selected language. - * - * @return string - */ - protected function getLanguageSelection() - { - $language = 'all'; - $backendUser = $this->getBackendUser(); - if (isset($backendUser->uc['moduleData']['Workspaces'][$backendUser->workspace]['language'])) { - $language = $backendUser->uc['moduleData']['Workspaces'][$backendUser->workspace]['language']; - } - return $language; - } - - /** - * @return AdditionalColumnService - */ - protected function getAdditionalColumnService() - { - return $this->objectManager->get(AdditionalColumnService::class); - } - - /** - * @return AdditionalResourceService - */ - protected function getAdditionalResourceService() - { - return $this->objectManager->get(AdditionalResourceService::class); - } - - /** - * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication - */ - protected function getBackendUser() - { - return $GLOBALS['BE_USER']; - } - - /** - * @return \TYPO3\CMS\Core\Localization\LanguageService - */ - protected function getLanguageService() - { - return $GLOBALS['LANG']; - } - - /** - * @return PageRenderer - */ - protected function getPageRenderer() - { - return GeneralUtility::makeInstance(PageRenderer::class); - } -} diff --git a/typo3/sysext/workspaces/Classes/Controller/AjaxController.php b/typo3/sysext/workspaces/Classes/Controller/AjaxController.php index 014ea515572f..0eafc7e63295 100644 --- a/typo3/sysext/workspaces/Classes/Controller/AjaxController.php +++ b/typo3/sysext/workspaces/Classes/Controller/AjaxController.php @@ -18,6 +18,7 @@ use Psr\Http\Message\ServerRequestInterface; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Http\JsonResponse; +use TYPO3\CMS\Core\Type\Bitmask\Permission; /** * Implements the AJAX functionality for the various asynchronous calls @@ -50,7 +51,7 @@ public function switchWorkspaceAction(ServerRequestInterface $request): Response ' AND pages.t3ver_wsid IN (0, ' . $workspaceId . ')' ); if ($page) { - if ($this->getBackendUser()->doesUserHaveAccess($page, 1)) { + if ($this->getBackendUser()->doesUserHaveAccess($page, Permission::PAGE_SHOW)) { break; } } else { diff --git a/typo3/sysext/workspaces/Classes/Controller/PreviewController.php b/typo3/sysext/workspaces/Classes/Controller/PreviewController.php index 3850a7d85cc1..a5774a03ae24 100644 --- a/typo3/sysext/workspaces/Classes/Controller/PreviewController.php +++ b/typo3/sysext/workspaces/Classes/Controller/PreviewController.php @@ -1,4 +1,5 @@ getModuleTemplate()->getDocHeaderComponent()->disable(); - $this->view->getModuleTemplate()->setFlashMessageQueue($this->controllerContext->getFlashMessageQueue()); - } - } + protected $moduleTemplate; + + /** + * @var \TYPO3Fluid\Fluid\View\ViewInterface + */ + protected $view; /** - * Initializes the controller before invoking an action method. + * Set up the module template */ - protected function initializeAction() + public function __construct() { - parent::initializeAction(); - /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */ - $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class); $this->stageService = GeneralUtility::makeInstance(StagesService::class); $this->workspaceService = GeneralUtility::makeInstance(WorkspaceService::class); + $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class); + $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Workspaces/Preview'); + $this->moduleTemplate->getDocHeaderComponent()->disable(); + $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); $states = $this->getBackendUser()->uc['moduleData']['Workspaces']['States']; - $this->pageRenderer->addInlineSetting('Workspaces', 'States', $states); - $this->pageRenderer->addInlineSetting('FormEngine', 'moduleUrl', (string)$uriBuilder->buildUriFromRoute('record_edit')); - $this->pageRenderer->addInlineSetting('RecordHistory', 'moduleUrl', (string)$uriBuilder->buildUriFromRoute('record_history')); - // @todo this part should be done with inlineLocallanglabels - $this->pageRenderer->addJsInlineCode('workspace-inline-code', $this->generateJavascript()); + $this->moduleTemplate->getPageRenderer()->addInlineSetting('Workspaces', 'States', $states); + $this->moduleTemplate->getPageRenderer()->addInlineSetting('FormEngine', 'moduleUrl', (string)$uriBuilder->buildUriFromRoute('record_edit')); + $this->moduleTemplate->getPageRenderer()->addInlineSetting('RecordHistory', 'moduleUrl', (string)$uriBuilder->buildUriFromRoute('record_history')); + $this->moduleTemplate->getPageRenderer()->addJsInlineCode('workspace-inline-code', $this->generateJavascript()); + $this->moduleTemplate->getPageRenderer()->addCssFile('EXT:workspaces/Resources/Public/Css/preview.css'); + $this->moduleTemplate->getPageRenderer()->addInlineLanguageLabelFile('EXT:workspaces/Resources/Private/Language/locallang.xlf'); + } + + /** + * Sets up the view + * + * @param string $templateName + */ + protected function initializeView(string $templateName) + { + $this->view = GeneralUtility::makeInstance(StandaloneView::class); + $this->view->setTemplate($templateName); + $this->view->setTemplateRootPaths(['EXT:workspaces/Resources/Private/Templates/Preview']); + $this->view->setPartialRootPaths(['EXT:workspaces/Resources/Private/Partials']); + $this->view->setLayoutRootPaths(['EXT:workspaces/Resources/Private/Layouts']); } /** * Basically makes sure that the workspace preview is rendered. * The preview itself consists of three frames, so there are - * only the frames-urls we've to generate here + * only the frames-urls we have to generate here * - * @param int $previewWS + * @param ServerRequestInterface $request + * @return ResponseInterface */ - public function indexAction($previewWS = null) + public function handleRequest(ServerRequestInterface $request): ResponseInterface { - $backendUser = $this->getBackendUser(); + $this->initializeView('Index'); // Get all the GET parameters to pass them on to the frames - $queryParameters = GeneralUtility::_GET(); + $queryParameters = $request->getQueryParams(); + + $previewWS = $queryParameters['previewWS'] ?? null; + $this->pageId = (int)$queryParameters['id']; - // Remove the GET parameters related to the workspaces module and the page id - unset($queryParameters['tx_workspaces_web_workspacesworkspaces']); - unset($queryParameters['route']); - unset($queryParameters['id']); + // Remove the GET parameters related to the workspaces module + unset($queryParameters['route'], $queryParameters['token'], $queryParameters['previewWS']); // Assemble a query string from the retrieved parameters $queryString = GeneralUtility::implodeArrayForUrl('', $queryParameters); // fetch the next and previous stage - $workspaceItemsArray = $this->workspaceService->selectVersionsInWorkspace($this->stageService->getWorkspaceId(), ($filter = 1), ($stage = -99), $this->pageId, ($recursionLevel = 0), ($selectionType = 'tables_modify')); + $workspaceItemsArray = $this->workspaceService->selectVersionsInWorkspace($this->stageService->getWorkspaceId(), 1, -99, $this->pageId, 0, 'tables_modify'); list(, $nextStage) = $this->stageService->getNextStageForElementCollection($workspaceItemsArray); list(, $previousStage) = $this->stageService->getPreviousStageForElementCollection($workspaceItemsArray); - /** @var $wsService WorkspaceService */ - $wsService = GeneralUtility::makeInstance(WorkspaceService::class); - $wsList = $wsService->getAvailableWorkspaces(); - $activeWorkspace = $backendUser->workspace; - if (!is_null($previewWS)) { - if (in_array($previewWS, array_keys($wsList)) && $activeWorkspace != $previewWS) { - $activeWorkspace = $previewWS; - $backendUser->setWorkspace($activeWorkspace); - BackendUtility::setUpdateSignal('updatePageTree'); - } + $availableWorkspaces = $this->workspaceService->getAvailableWorkspaces(); + $activeWorkspace = $this->getBackendUser()->workspace; + if ($previewWS !== null && in_array($previewWS, array_keys($availableWorkspaces)) && $activeWorkspace != $previewWS) { + $activeWorkspace = $previewWS; + $this->getBackendUser()->setWorkspace($activeWorkspace); + BackendUtility::setUpdateSignal('updatePageTree'); } - /** @var $uriBuilder UriBuilder */ - $uriBuilder = $this->objectManager->get(UriBuilder::class); - $wsSettingsPath = GeneralUtility::getIndpEnv('TYPO3_SITE_URL'); - $wsSettingsUri = $uriBuilder->uriFor('singleIndex', [], ReviewController::class, 'workspaces', 'web_workspacesworkspaces'); - $wsSettingsParams = '&tx_workspaces_web_workspacesworkspaces[controller]=Review'; - $wsSettingsUrl = $wsSettingsPath . $wsSettingsUri . $wsSettingsParams; - $viewDomain = BackendUtility::getViewDomain($this->pageId); - $wsBaseUrl = $viewDomain . '/index.php?id=' . $this->pageId . $queryString; - // @todo - handle new pages here - // branchpoints are not handled anymore because this feature is not supposed anymore - if (WorkspaceService::isNewPage($this->pageId)) { - $wsNewPageUri = $uriBuilder->uriFor('newPage', [], self::class, 'workspaces', 'web_workspacesworkspaces'); - $wsNewPageParams = '&tx_workspaces_web_workspacesworkspaces[controller]=Preview'; - $liveUrl = $wsSettingsPath . $wsNewPageUri . $wsNewPageParams . '&ADMCMD_prev=IGNORE'; - } else { - $liveUrl = $wsBaseUrl . '&ADMCMD_noBeUser=1&ADMCMD_prev=IGNORE'; + + // Base URL for frontend preview links + $previewBaseUrl = BackendUtility::getViewDomain($this->pageId) . '/index.php?' . $queryString; + + // Build the "list view" link to the review controller + $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); + $wsSettingsUrl = $uriBuilder->buildUriFromRoute('web_WorkspacesWorkspaces', [ + 'tx_workspaces_web_workspacesworkspaces' => ['action' => 'singleIndex'] + ], UriBuilder::ABSOLUTE_URL); + + if (!WorkspaceService::isNewPage($this->pageId)) { + $liveUrl = $previewBaseUrl . '&ADMCMD_noBeUser=1&ADMCMD_prev=IGNORE'; } - $wsUrl = $wsBaseUrl . '&ADMCMD_prev=IGNORE&ADMCMD_view=1&ADMCMD_editIcons=1'; - $backendDomain = GeneralUtility::getIndpEnv('TYPO3_HOST_ONLY'); + $wsUrl = $previewBaseUrl . '&ADMCMD_prev=IGNORE&ADMCMD_view=1&ADMCMD_editIcons=1'; + + // Evaluate available preview modes $splitPreviewTsConfig = BackendUtility::getModTSconfig($this->pageId, 'workspaces.splitPreviewModes'); $splitPreviewModes = GeneralUtility::trimExplode(',', $splitPreviewTsConfig['value']); $allPreviewModes = ['slider', 'vbox', 'hbox']; if (!array_intersect($splitPreviewModes, $allPreviewModes)) { $splitPreviewModes = $allPreviewModes; } + $this->moduleTemplate->getPageRenderer()->addInlineSetting('Workspaces', 'SplitPreviewModes', $splitPreviewModes); - $wsList = $wsService->getAvailableWorkspaces(); - $activeWorkspace = $backendUser->workspace; - - $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Workspaces/Preview'); - $this->pageRenderer->addInlineSetting('Workspaces', 'SplitPreviewModes', $splitPreviewModes); - - $cssFile = 'EXT:workspaces/Resources/Public/Css/preview.css'; - $cssFile = GeneralUtility::getFileAbsFileName($cssFile); - $this->pageRenderer->addCssFile(PathUtility::getAbsoluteWebPath($cssFile)); - - $backendUser->setAndSaveSessionData('workspaces.backend_domain', GeneralUtility::getIndpEnv('TYPO3_HOST_ONLY')); - - $logoPath = GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Public/Images/typo3_logo_orange.svg'); - $logoWidth = 22; - $logoHeight = 22; + $backendDomain = $request->getAttribute('normalizedParams')->getRequestHostOnly(); + $this->getBackendUser()->setAndSaveSessionData('workspaces.backend_domain', $backendDomain); $this->view->assignMultiple([ - 'logoUrl' => PathUtility::getAbsoluteWebPath($logoPath), 'logoLink' => TYPO3_URL_GENERAL, - 'logoWidth' => $logoWidth, - 'logoHeight' => $logoHeight, - 'liveUrl' => $liveUrl, + 'liveUrl' => $liveUrl ?? false, 'wsUrl' => $wsUrl, 'wsSettingsUrl' => $wsSettingsUrl, 'backendDomain' => $backendDomain, - 'activeWorkspace' => $wsList[$activeWorkspace], + 'activeWorkspace' => $availableWorkspaces[$activeWorkspace], 'splitPreviewModes' => $splitPreviewModes, 'firstPreviewMode' => current($splitPreviewModes), - 'enablePreviousStageButton' => !$this->isInvalidStage($previousStage), - 'enableNextStageButton' => !$this->isInvalidStage($nextStage), - 'enableDiscardStageButton' => !$this->isInvalidStage($nextStage) || !$this->isInvalidStage($previousStage), + 'enablePreviousStageButton' => $this->isValidStage($previousStage), + 'enableNextStageButton' => $this->isValidStage($nextStage), + 'enableDiscardStageButton' => $this->isValidStage($nextStage) || $this->isValidStage($previousStage), 'nextStage' => $nextStage['title'], 'nextStageId' => $nextStage['uid'], 'prevStage' => $previousStage['title'], 'prevStageId' => $previousStage['uid'], ]); - foreach ($this->getAdditionalResourceService()->getLocalizationResources() as $localizationResource) { - $this->pageRenderer->addInlineLanguageLabelFile($localizationResource); - } + + $this->moduleTemplate->setContent($this->view->render()); + return new HtmlResponse($this->moduleTemplate->renderContent()); } /** @@ -183,44 +183,30 @@ public function indexAction($previewWS = null) * @param array $stageArray * @return bool */ - protected function isInvalidStage($stageArray) - { - return !(is_array($stageArray) && !empty($stageArray)); - } - - /** - */ - public function newPageAction() + protected function isValidStage($stageArray): bool { - /** @var FlashMessage $flashMessage */ - $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $this->getLanguageService()->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:info.newpage.detail'), $this->getLanguageService()->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:info.newpage'), FlashMessage::INFO); - /** @var $flashMessageService FlashMessageService */ - $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class); - /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */ - $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier(); - $defaultFlashMessageQueue->enqueue($flashMessage); + return is_array($stageArray) && !empty($stageArray); } /** * Generates the JavaScript code for the backend, * and since we're loading a backend module outside of the actual backend - * this copies parts of the index.php?M=main module + * this copies parts of the backend main script. * * @return string */ - protected function generateJavascript() + protected function generateJavascript(): string { - $backendUser = $this->getBackendUser(); // If another page module was specified, replace the default Page module with the new one - $newPageModule = trim($backendUser->getTSConfigVal('options.overridePageModule')); - $pageModule = BackendUtility::isModuleSetInTBE_MODULES($newPageModule) ? $newPageModule : 'web_layout'; - if (!$backendUser->check('modules', $pageModule)) { + $pageModule = trim($this->getBackendUser()->getTSConfigVal('options.overridePageModule') ?? ''); + $pageModule = BackendUtility::isModuleSetInTBE_MODULES($pageModule) ? $pageModule : 'web_layout'; + if (!$this->getBackendUser()->check('modules', $pageModule)) { $pageModule = ''; } $t3Configuration = [ - 'username' => htmlspecialchars($backendUser->user['username']), + 'username' => htmlspecialchars($this->getBackendUser()->user['username']), 'pageModule' => $pageModule, - 'inWorkspace' => $backendUser->workspace !== 0, + 'inWorkspace' => $this->getBackendUser()->workspace !== 0, 'showRefreshLoginPopup' => (bool)($GLOBALS['TYPO3_CONF_VARS']['BE']['showRefreshLoginPopup'] ?? false) ]; @@ -228,17 +214,9 @@ protected function generateJavascript() } /** - * @return \TYPO3\CMS\Core\Localization\LanguageService - */ - protected function getLanguageService() - { - return $GLOBALS['LANG']; - } - - /** - * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication + * @return BackendUserAuthentication */ - protected function getBackendUser() + protected function getBackendUser(): BackendUserAuthentication { return $GLOBALS['BE_USER']; } diff --git a/typo3/sysext/workspaces/Classes/Controller/ReviewController.php b/typo3/sysext/workspaces/Classes/Controller/ReviewController.php index 17b86cfe17d8..70143ee87f91 100644 --- a/typo3/sysext/workspaces/Classes/Controller/ReviewController.php +++ b/typo3/sysext/workspaces/Classes/Controller/ReviewController.php @@ -14,18 +14,46 @@ * The TYPO3 project - inspiring people to share! */ +use TYPO3\CMS\Backend\Routing\UriBuilder; use TYPO3\CMS\Backend\Utility\BackendUtility; +use TYPO3\CMS\Backend\View\BackendTemplateView; use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; use TYPO3\CMS\Core\Imaging\Icon; +use TYPO3\CMS\Core\Imaging\IconFactory; +use TYPO3\CMS\Core\Localization\LanguageService; +use TYPO3\CMS\Core\Page\PageRenderer; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; use TYPO3\CMS\Extbase\Mvc\View\ViewInterface; +use TYPO3\CMS\Workspaces\Service\AdditionalColumnService; +use TYPO3\CMS\Workspaces\Service\AdditionalResourceService; use TYPO3\CMS\Workspaces\Service\WorkspaceService; /** * Review controller. */ -class ReviewController extends AbstractController +class ReviewController extends ActionController { + /** + * @var string + */ + protected $defaultViewObjectName = BackendTemplateView::class; + + /** + * @var BackendTemplateView + */ + protected $view; + + /** + * @var PageRenderer + */ + protected $pageRenderer; + + /** + * @var int + */ + protected $pageId; + /** * Set up the doc header properly here * @@ -58,6 +86,56 @@ protected function registerButtons() $buttonBar->addButton($shortcutButton); } + /** + * Initializes the controller before invoking an action method. + */ + protected function initializeAction() + { + $this->pageRenderer = $this->getPageRenderer(); + // @todo Evaluate how the (int) typecast can be used with Extbase validators/filters + $this->pageId = (int)GeneralUtility::_GP('id'); + $iconFactory = GeneralUtility::makeInstance(IconFactory::class); + $lang = $this->getLanguageService(); + $icons = [ + 'language' => $iconFactory->getIcon('flags-multiple', Icon::SIZE_SMALL)->render(), + 'integrity' => $iconFactory->getIcon('status-dialog-information', Icon::SIZE_SMALL)->render(), + 'success' => $iconFactory->getIcon('status-dialog-ok', Icon::SIZE_SMALL)->render(), + 'info' => $iconFactory->getIcon('status-dialog-information', Icon::SIZE_SMALL)->render(), + 'warning' => $iconFactory->getIcon('status-dialog-warning', Icon::SIZE_SMALL)->render(), + 'error' => $iconFactory->getIcon('status-dialog-error', Icon::SIZE_SMALL)->render() + ]; + $this->pageRenderer->addInlineSetting('Workspaces', 'icons', $icons); + $this->pageRenderer->addInlineSetting('Workspaces', 'id', $this->pageId); + $this->pageRenderer->addInlineSetting('Workspaces', 'depth', $this->pageId === 0 ? 999 : 1); + $this->pageRenderer->addInlineSetting('Workspaces', 'language', $this->getLanguageSelection()); + $this->pageRenderer->addInlineLanguageLabelArray([ + 'title' => $lang->getLL('title'), + 'path' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.path'), + 'table' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.table'), + 'depth' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_mod_web_perm.xlf:Depth'), + 'depth_0' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_0'), + 'depth_1' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_1'), + 'depth_2' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_2'), + 'depth_3' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_3'), + 'depth_4' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_4'), + 'depth_infi' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_infi') + ]); + $this->pageRenderer->addInlineLanguageLabelFile('EXT:workspaces/Resources/Private/Language/locallang.xlf'); + $states = $this->getBackendUser()->uc['moduleData']['Workspaces']['States']; + $this->pageRenderer->addInlineSetting('Workspaces', 'States', $states); + + foreach ($this->getAdditionalResourceService()->getLocalizationResources() as $localizationResource) { + $this->pageRenderer->addInlineLanguageLabelFile($localizationResource); + } + $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); + $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Workspaces/Backend'); + $this->pageRenderer->addInlineSetting('FormEngine', 'moduleUrl', (string)$uriBuilder->buildUriFromRoute('record_edit')); + $this->pageRenderer->addInlineSetting('RecordHistory', 'moduleUrl', (string)$uriBuilder->buildUriFromRoute('record_history')); + $this->pageRenderer->addInlineSetting('Workspaces', 'id', (int)GeneralUtility::_GP('id')); + + $this->assignExtensionSettings(); + } + /** * Renders the review module user dependent with all workspaces. * The module will show all records of one workspace. @@ -98,12 +176,9 @@ public function indexAction() } } } - /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */ - $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class); $this->pageRenderer->addInlineSetting('Workspaces', 'isLiveWorkspace', (int)$backendUser->workspace === 0); $this->pageRenderer->addInlineSetting('Workspaces', 'workspaceTabs', $this->prepareWorkspaceTabs($wsList, $activeWorkspace)); $this->pageRenderer->addInlineSetting('Workspaces', 'activeWorkspaceId', $activeWorkspace); - $this->pageRenderer->addInlineSetting('FormEngine', 'moduleUrl', (string)$uriBuilder->buildUriFromRoute('record_edit')); $workspaceIsAccessible = !($backendUser->workspace === 0 && !$backendUser->isAdmin()); $this->view->assignMultiple([ 'showGrid' => $workspaceIsAccessible, @@ -113,7 +188,6 @@ public function indexAction() 'workspaceList' => $this->prepareWorkspaceTabs($wsList, $activeWorkspace), 'activeWorkspaceUid' => $activeWorkspace, 'activeWorkspaceTitle' => WorkspaceService::getWorkspaceTitle($activeWorkspace), - 'showPreviewLink' => $wsService->canCreatePreviewLink(GeneralUtility::_GP('id'), $activeWorkspace) ]); if ($wsService->canCreatePreviewLink(GeneralUtility::_GP('id'), $activeWorkspace)) { @@ -151,8 +225,7 @@ public function fullIndexAction() 'showGrid' => true, 'showLegend' => true, 'workspaceList' => $this->prepareWorkspaceTabs($wsList, $activeWorkspace), - 'activeWorkspaceUid' => WorkspaceService::SELECT_ALL_WORKSPACES, - 'showPreviewLink', false + 'activeWorkspaceUid' => WorkspaceService::SELECT_ALL_WORKSPACES ]); $this->getBackendUser()->setAndSaveSessionData('tx_workspace_activeWorkspace', WorkspaceService::SELECT_ALL_WORKSPACES); // set flag for javascript @@ -174,7 +247,7 @@ public function singleIndexAction() $this->view->assignMultiple([ 'pageUid' => (int)GeneralUtility::_GP('id'), 'showGrid' => true, - 'workspaceList' => $this->prepareWorkspaceTabs($wsList, $activeWorkspace, false), + 'workspaceList' => $this->prepareWorkspaceTabs($wsList, (int)$activeWorkspace, false), 'activeWorkspaceUid' => $activeWorkspace, 'backendDomain' => $backendDomain ]); @@ -188,27 +261,6 @@ public function singleIndexAction() $this->pageRenderer->addInlineSetting('Workspaces', 'singleView', '1'); } - /** - * Initializes the controller before invoking an action method. - */ - protected function initializeAction() - { - parent::initializeAction(); - $states = $this->getBackendUser()->uc['moduleData']['Workspaces']['States']; - $this->pageRenderer->addInlineSetting('Workspaces', 'States', $states); - - foreach ($this->getAdditionalResourceService()->getLocalizationResources() as $localizationResource) { - $this->pageRenderer->addInlineLanguageLabelFile($localizationResource); - } - /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */ - $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class); - - $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Workspaces/Backend'); - $this->pageRenderer->addInlineSetting('FormEngine', 'moduleUrl', (string)$uriBuilder->buildUriFromRoute('record_edit')); - $this->pageRenderer->addInlineSetting('RecordHistory', 'moduleUrl', (string)$uriBuilder->buildUriFromRoute('record_history')); - $this->pageRenderer->addInlineSetting('Workspaces', 'id', (int)GeneralUtility::_GP('id')); - } - /** * Prepares available workspace tabs. * @@ -217,7 +269,7 @@ protected function initializeAction() * @param bool $showAllWorkspaceTab * @return array */ - protected function prepareWorkspaceTabs(array $workspaceList, $activeWorkspace, $showAllWorkspaceTab = true) + protected function prepareWorkspaceTabs(array $workspaceList, int $activeWorkspace, bool $showAllWorkspaceTab = true) { $tabs = []; @@ -260,11 +312,11 @@ protected function prepareWorkspaceTabs(array $workspaceList, $activeWorkspace, * @param int $workspaceId * @return string */ - protected function getModuleUri($workspaceId) + protected function getModuleUri(int $workspaceId): string { $parameters = [ - 'id' => (int)$this->pageId, - 'workspace' => (int)$workspaceId, + 'id' => $this->pageId, + 'workspace' => $workspaceId, ]; // The "all workspaces" tab is handled in fullIndexAction // which is required as additional GET parameter in the URI then @@ -272,15 +324,71 @@ protected function getModuleUri($workspaceId) $this->uriBuilder->reset()->uriFor('fullIndex'); $parameters = array_merge($parameters, $this->uriBuilder->getArguments()); } - /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */ - $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class); + /** @var UriBuilder $uriBuilder */ + $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); return (string)$uriBuilder->buildUriFromRoute('web_WorkspacesWorkspaces', $parameters); } /** - * @return \TYPO3\CMS\Core\Localization\LanguageService + * Assigns additional Workspace settings to TYPO3.settings.Workspaces.extension + */ + protected function assignExtensionSettings() + { + $extension = [ + 'AdditionalColumn' => [ + 'Definition' => [], + 'Handler' => [], + ], + ]; + + $extension['AdditionalColumn']['Definition'] = $this->getAdditionalColumnService()->getDefinition(); + $extension['AdditionalColumn']['Handler'] = $this->getAdditionalColumnService()->getHandler(); + $this->pageRenderer->addInlineSetting('Workspaces', 'extension', $extension); + } + + /** + * Gets the selected language. + * + * @return string + */ + protected function getLanguageSelection(): string + { + $language = 'all'; + $backendUser = $this->getBackendUser(); + if (isset($backendUser->uc['moduleData']['Workspaces'][$backendUser->workspace]['language'])) { + $language = $backendUser->uc['moduleData']['Workspaces'][$backendUser->workspace]['language']; + } + return $language; + } + + /** + * @return AdditionalColumnService + */ + protected function getAdditionalColumnService(): AdditionalColumnService + { + return $this->objectManager->get(AdditionalColumnService::class); + } + + /** + * @return AdditionalResourceService + */ + protected function getAdditionalResourceService(): AdditionalResourceService + { + return $this->objectManager->get(AdditionalResourceService::class); + } + + /** + * @return PageRenderer + */ + protected function getPageRenderer(): PageRenderer + { + return GeneralUtility::makeInstance(PageRenderer::class); + } + + /** + * @return LanguageService */ - protected function getLanguageService() + protected function getLanguageService(): LanguageService { return $GLOBALS['LANG']; } @@ -288,7 +396,7 @@ protected function getLanguageService() /** * @return BackendUserAuthentication */ - protected function getBackendUser() + protected function getBackendUser(): BackendUserAuthentication { return $GLOBALS['BE_USER']; } diff --git a/typo3/sysext/workspaces/Classes/Hook/BackendUtilityHook.php b/typo3/sysext/workspaces/Classes/Hook/BackendUtilityHook.php index 217c6ad84a0a..c4da94925e10 100644 --- a/typo3/sysext/workspaces/Classes/Hook/BackendUtilityHook.php +++ b/typo3/sysext/workspaces/Classes/Hook/BackendUtilityHook.php @@ -1,4 +1,5 @@ workspace !== 0) { - $viewScript = $this->getWorkspaceService()->generateWorkspaceSplittedPreviewLink($pageUid); + $viewScript = GeneralUtility::makeInstance(WorkspaceService::class)->generateWorkspaceSplittedPreviewLink($pageUid); } } - /** - * Gets an instance of the workspaces service. - * - * @return \TYPO3\CMS\Workspaces\Service\WorkspaceService - */ - protected function getWorkspaceService() - { - return GeneralUtility::makeInstance(\TYPO3\CMS\Workspaces\Service\WorkspaceService::class); - } - /** * Use that hook to show an info message in case someone starts editing * a staged element @@ -70,15 +67,15 @@ protected function getWorkspaceService() public function makeEditForm_accessCheck($params) { if ($GLOBALS['BE_USER']->workspace !== 0 && $GLOBALS['TCA'][$params['table']]['ctrl']['versioningWS']) { - $record = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecordWSOL($params['table'], $params['uid']); - if (abs($record['t3ver_stage']) > \TYPO3\CMS\Workspaces\Service\StagesService::STAGE_EDIT_ID) { - $stages = GeneralUtility::makeInstance(\TYPO3\CMS\Workspaces\Service\StagesService::class); + $record = BackendUtility::getRecordWSOL($params['table'], $params['uid']); + if (abs($record['t3ver_stage']) > StagesService::STAGE_EDIT_ID) { + $stages = GeneralUtility::makeInstance(StagesService::class); $stageName = $stages->getStageTitle($record['t3ver_stage']); - $editingName = $stages->getStageTitle(\TYPO3\CMS\Workspaces\Service\StagesService::STAGE_EDIT_ID); + $editingName = $stages->getStageTitle(StagesService::STAGE_EDIT_ID); $message = $GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:info.elementAlreadyModified'); - $flashMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessage::class, sprintf($message, $stageName, $editingName), '', \TYPO3\CMS\Core\Messaging\FlashMessage::INFO, true); - /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */ - $flashMessageService = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessageService::class); + $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, sprintf($message, $stageName, $editingName), '', FlashMessage::INFO, true); + /** @var $flashMessageService FlashMessageService */ + $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class); /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */ $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier(); $defaultFlashMessageQueue->enqueue($flashMessage); diff --git a/typo3/sysext/workspaces/Classes/Middleware/WorkspacePreview.php b/typo3/sysext/workspaces/Classes/Middleware/WorkspacePreview.php index bb8a8f17b833..dc436ed2c3d7 100644 --- a/typo3/sysext/workspaces/Classes/Middleware/WorkspacePreview.php +++ b/typo3/sysext/workspaces/Classes/Middleware/WorkspacePreview.php @@ -268,13 +268,10 @@ protected function renderPreviewInfo(TypoScriptFrontendController $tsfe, Normali { $backendDomain = $GLOBALS['BE_USER']->getSessionData('workspaces.backend_domain') ?: $normalizedParams->getRequestHostOnly(); - $content = $tsfe->cObj->cObjGetSingle('FLUIDTEMPLATE', [ - 'file' => 'EXT:workspaces/Resources/Private/Templates/Preview/Preview.html', - 'variables.' => [ - 'backendDomain' => 'TEXT', - 'backendDomain.' => ['value' => $backendDomain] - ] - ]); + $content = ''; if (!isset($tsfe->config['config']['disablePreviewNotification']) || (int)$tsfe->config['config']['disablePreviewNotification'] !== 1) { // get the title of the current workspace diff --git a/typo3/sysext/workspaces/Classes/Service/WorkspaceService.php b/typo3/sysext/workspaces/Classes/Service/WorkspaceService.php index 1d2df1d27f0c..dd4649b5f579 100644 --- a/typo3/sysext/workspaces/Classes/Service/WorkspaceService.php +++ b/typo3/sysext/workspaces/Classes/Service/WorkspaceService.php @@ -15,6 +15,7 @@ */ use TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider; +use TYPO3\CMS\Backend\Routing\UriBuilder; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Database\Connection; use TYPO3\CMS\Core\Database\ConnectionPool; @@ -757,7 +758,7 @@ public static function viewSingleRecord($table, $uid, array $liveRecord = null, // Directly use pid value and consider move placeholders $previewPageId = (empty($movePlaceholder['pid']) ? $liveRecord['pid'] : $movePlaceholder['pid']); - $additionalParameters = '&tx_workspaces_web_workspacesworkspaces[previewWS]=' . $versionRecord['t3ver_wsid']; + $additionalParameters = '&previewWS=' . $versionRecord['t3ver_wsid']; // Add language parameter if record is a localization if (BackendUtility::isTableLocalizable($table)) { $languageField = $GLOBALS['TCA'][$table]['ctrl']['languageField']; @@ -857,14 +858,12 @@ public function generateWorkspaceSplittedPreviewLink($uid, $addDomain = false) if ($uid > 0) { $uid = $this->getLivePageUid($uid); } - /** @var $uriBuilder \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder */ - $uriBuilder = $this->getObjectManager()->get(\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::class); - $redirect = 'index.php?redirect_url='; - $viewScript = $uriBuilder - ->setArguments(['route' => '/web/WorkspacesWorkspaces/']) - ->uriFor('index', [], 'Preview', 'workspaces', 'web_workspacesworkspaces') . '&id='; + $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); + // the actual uid will be appended directly in BackendUtility Hook + $viewScript = $uriBuilder->buildUriFromRoute('workspace_previewcontrols', ['id' => '']); if ($addDomain === true) { - return BackendUtility::getViewDomain($uid) . $redirect . urlencode($viewScript) . $uid; + $viewScript = $uriBuilder->buildUriFromRoute('workspace_previewcontrols', ['id' => $uid]); + return BackendUtility::getViewDomain($uid) . 'index.php?redirect_url=' . urlencode($viewScript); } return $viewScript; } diff --git a/typo3/sysext/workspaces/Configuration/Backend/Routes.php b/typo3/sysext/workspaces/Configuration/Backend/Routes.php new file mode 100644 index 000000000000..510c596e82c0 --- /dev/null +++ b/typo3/sysext/workspaces/Configuration/Backend/Routes.php @@ -0,0 +1,10 @@ + [ + 'path' => '/workspace/preview-control/', + 'target' => \TYPO3\CMS\Workspaces\Controller\PreviewController::class . '::handleRequest' + ] +]; diff --git a/typo3/sysext/workspaces/Resources/Private/Layouts/Empty.html b/typo3/sysext/workspaces/Resources/Private/Layouts/Empty.html deleted file mode 100644 index 54d9aa0bb6bc..000000000000 --- a/typo3/sysext/workspaces/Resources/Private/Layouts/Empty.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/typo3/sysext/workspaces/Resources/Private/Layouts/Popup.html b/typo3/sysext/workspaces/Resources/Private/Layouts/Popup.html deleted file mode 100644 index 8b997bb89e17..000000000000 --- a/typo3/sysext/workspaces/Resources/Private/Layouts/Popup.html +++ /dev/null @@ -1,4 +0,0 @@ - - diff --git a/typo3/sysext/workspaces/Resources/Private/Partials/Legend.html b/typo3/sysext/workspaces/Resources/Private/Partials/Legend.html index fa91e9df808f..45ef08ac136e 100644 --- a/typo3/sysext/workspaces/Resources/Private/Partials/Legend.html +++ b/typo3/sysext/workspaces/Resources/Private/Partials/Legend.html @@ -7,4 +7,4 @@
  • 
- \ No newline at end of file + diff --git a/typo3/sysext/workspaces/Resources/Private/Partials/Preview/StageButtons.html b/typo3/sysext/workspaces/Resources/Private/Partials/Preview/StageButtons.html index 5f74f59d2e44..f388e32ed563 100644 --- a/typo3/sysext/workspaces/Resources/Private/Partials/Preview/StageButtons.html +++ b/typo3/sysext/workspaces/Resources/Private/Partials/Preview/StageButtons.html @@ -6,6 +6,6 @@ - + - \ No newline at end of file + diff --git a/typo3/sysext/workspaces/Resources/Private/Templates/Preview/Help.html b/typo3/sysext/workspaces/Resources/Private/Templates/Preview/Help.html deleted file mode 100644 index 1dd38b78d490..000000000000 --- a/typo3/sysext/workspaces/Resources/Private/Templates/Preview/Help.html +++ /dev/null @@ -1,5 +0,0 @@ - - - -Help contents - not yet defined - \ No newline at end of file diff --git a/typo3/sysext/workspaces/Resources/Private/Templates/Preview/Index.html b/typo3/sysext/workspaces/Resources/Private/Templates/Preview/Index.html index bdfcd6c36a27..885dbb8f0b45 100644 --- a/typo3/sysext/workspaces/Resources/Private/Templates/Preview/Index.html +++ b/typo3/sysext/workspaces/Resources/Private/Templates/Preview/Index.html @@ -1,22 +1,20 @@ - - - -
-