[TASK] Clean up workspace preview top bar
[Packages/TYPO3.CMS.git] / typo3 / sysext / workspaces / Classes / Controller / PreviewController.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Workspaces\Controller;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use Psr\Http\Message\ResponseInterface;
19 use Psr\Http\Message\ServerRequestInterface;
20 use TYPO3\CMS\Backend\Routing\UriBuilder;
21 use TYPO3\CMS\Backend\Template\ModuleTemplate;
22 use TYPO3\CMS\Backend\Utility\BackendUtility;
23 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
24 use TYPO3\CMS\Core\Http\HtmlResponse;
25 use TYPO3\CMS\Core\Utility\GeneralUtility;
26 use TYPO3\CMS\Fluid\View\StandaloneView;
27 use TYPO3\CMS\Workspaces\Service\StagesService;
28 use TYPO3\CMS\Workspaces\Service\WorkspaceService;
29
30 /**
31 * Implements the preview controller of the workspace module.
32 */
33 class PreviewController
34 {
35 /**
36 * @var StagesService
37 */
38 protected $stageService;
39
40 /**
41 * @var WorkspaceService
42 */
43 protected $workspaceService;
44
45 /**
46 * @var int
47 */
48 protected $pageId;
49
50 /**
51 * ModuleTemplate object
52 *
53 * @var ModuleTemplate
54 */
55 protected $moduleTemplate;
56
57 /**
58 * @var \TYPO3Fluid\Fluid\View\ViewInterface
59 */
60 protected $view;
61
62 /**
63 * Set up the module template
64 */
65 public function __construct()
66 {
67 $this->stageService = GeneralUtility::makeInstance(StagesService::class);
68 $this->workspaceService = GeneralUtility::makeInstance(WorkspaceService::class);
69 $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
70 $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Workspaces/Preview');
71 $this->moduleTemplate->getDocHeaderComponent()->disable();
72 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
73 $states = $this->getBackendUser()->uc['moduleData']['Workspaces']['States'];
74 $this->moduleTemplate->getPageRenderer()->addInlineSetting('Workspaces', 'States', $states);
75 $this->moduleTemplate->getPageRenderer()->addInlineSetting('FormEngine', 'moduleUrl', (string)$uriBuilder->buildUriFromRoute('record_edit'));
76 $this->moduleTemplate->getPageRenderer()->addInlineSetting('RecordHistory', 'moduleUrl', (string)$uriBuilder->buildUriFromRoute('record_history'));
77 $this->moduleTemplate->getPageRenderer()->addJsInlineCode('workspace-inline-code', $this->generateJavascript());
78 $this->moduleTemplate->getPageRenderer()->addCssFile('EXT:workspaces/Resources/Public/Css/preview.css');
79 $this->moduleTemplate->getPageRenderer()->addInlineLanguageLabelFile('EXT:workspaces/Resources/Private/Language/locallang.xlf');
80 }
81
82 /**
83 * Sets up the view
84 *
85 * @param string $templateName
86 */
87 protected function initializeView(string $templateName)
88 {
89 $this->view = GeneralUtility::makeInstance(StandaloneView::class);
90 $this->view->setTemplate($templateName);
91 $this->view->setTemplateRootPaths(['EXT:workspaces/Resources/Private/Templates/Preview']);
92 $this->view->setPartialRootPaths(['EXT:workspaces/Resources/Private/Partials']);
93 $this->view->setLayoutRootPaths(['EXT:workspaces/Resources/Private/Layouts']);
94 }
95
96 /**
97 * Basically makes sure that the workspace preview is rendered.
98 * The preview itself consists of three frames, so there are
99 * only the frames-urls we have to generate here
100 *
101 * @param ServerRequestInterface $request
102 * @return ResponseInterface
103 */
104 public function handleRequest(ServerRequestInterface $request): ResponseInterface
105 {
106 $this->initializeView('Index');
107
108 // Get all the GET parameters to pass them on to the frames
109 $queryParameters = $request->getQueryParams();
110
111 $previewWS = $queryParameters['previewWS'] ?? null;
112 $this->pageId = (int)$queryParameters['id'];
113
114 // Remove the GET parameters related to the workspaces module
115 unset($queryParameters['route'], $queryParameters['token'], $queryParameters['previewWS']);
116
117 // Assemble a query string from the retrieved parameters
118 $queryString = GeneralUtility::implodeArrayForUrl('', $queryParameters);
119
120 // fetch the next and previous stage
121 $workspaceItemsArray = $this->workspaceService->selectVersionsInWorkspace($this->stageService->getWorkspaceId(), 1, -99, $this->pageId, 0, 'tables_modify');
122 list(, $nextStage) = $this->stageService->getNextStageForElementCollection($workspaceItemsArray);
123 list(, $previousStage) = $this->stageService->getPreviousStageForElementCollection($workspaceItemsArray);
124 $availableWorkspaces = $this->workspaceService->getAvailableWorkspaces();
125 $activeWorkspace = $this->getBackendUser()->workspace;
126 if ($previewWS !== null && in_array($previewWS, array_keys($availableWorkspaces)) && $activeWorkspace != $previewWS) {
127 $activeWorkspace = $previewWS;
128 $this->getBackendUser()->setWorkspace($activeWorkspace);
129 BackendUtility::setUpdateSignal('updatePageTree');
130 }
131
132 // Base URL for frontend preview links
133 $previewBaseUrl = BackendUtility::getViewDomain($this->pageId) . '/index.php?' . $queryString;
134
135 // Build the "list view" link to the review controller
136 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
137 $wsSettingsUrl = $uriBuilder->buildUriFromRoute('web_WorkspacesWorkspaces', [
138 'tx_workspaces_web_workspacesworkspaces' => ['action' => 'singleIndex']
139 ], UriBuilder::ABSOLUTE_URL);
140
141 if (!WorkspaceService::isNewPage($this->pageId)) {
142 $liveUrl = $previewBaseUrl . '&ADMCMD_noBeUser=1&ADMCMD_prev=IGNORE';
143 }
144 $wsUrl = $previewBaseUrl . '&ADMCMD_prev=IGNORE&ADMCMD_view=1&ADMCMD_editIcons=1';
145
146 // Evaluate available preview modes
147 $splitPreviewTsConfig = BackendUtility::getModTSconfig($this->pageId, 'workspaces.splitPreviewModes');
148 $splitPreviewModes = GeneralUtility::trimExplode(',', $splitPreviewTsConfig['value']);
149 $allPreviewModes = ['slider', 'vbox', 'hbox'];
150 if (!array_intersect($splitPreviewModes, $allPreviewModes)) {
151 $splitPreviewModes = $allPreviewModes;
152 }
153 $this->moduleTemplate->getPageRenderer()->addInlineSetting('Workspaces', 'SplitPreviewModes', $splitPreviewModes);
154
155 $backendDomain = $request->getAttribute('normalizedParams')->getRequestHostOnly();
156 $this->getBackendUser()->setAndSaveSessionData('workspaces.backend_domain', $backendDomain);
157
158 $this->view->assignMultiple([
159 'logoLink' => TYPO3_URL_GENERAL,
160 'liveUrl' => $liveUrl ?? false,
161 'wsUrl' => $wsUrl,
162 'wsSettingsUrl' => $wsSettingsUrl,
163 'backendDomain' => $backendDomain,
164 'activeWorkspace' => $availableWorkspaces[$activeWorkspace],
165 'splitPreviewModes' => $splitPreviewModes,
166 'firstPreviewMode' => current($splitPreviewModes),
167 'enablePreviousStageButton' => $this->isValidStage($previousStage),
168 'enableNextStageButton' => $this->isValidStage($nextStage),
169 'enableDiscardStageButton' => $this->isValidStage($nextStage) || $this->isValidStage($previousStage),
170 'nextStage' => $nextStage['title'],
171 'nextStageId' => $nextStage['uid'],
172 'prevStage' => $previousStage['title'],
173 'prevStageId' => $previousStage['uid'],
174 ]);
175
176 $this->moduleTemplate->setContent($this->view->render());
177 return new HtmlResponse($this->moduleTemplate->renderContent());
178 }
179
180 /**
181 * Evaluate the activate state based on given $stageArray.
182 *
183 * @param array $stageArray
184 * @return bool
185 */
186 protected function isValidStage($stageArray): bool
187 {
188 return is_array($stageArray) && !empty($stageArray);
189 }
190
191 /**
192 * Generates the JavaScript code for the backend,
193 * and since we're loading a backend module outside of the actual backend
194 * this copies parts of the backend main script.
195 *
196 * @return string
197 */
198 protected function generateJavascript(): string
199 {
200 // If another page module was specified, replace the default Page module with the new one
201 $pageModule = trim($this->getBackendUser()->getTSConfigVal('options.overridePageModule') ?? '');
202 $pageModule = BackendUtility::isModuleSetInTBE_MODULES($pageModule) ? $pageModule : 'web_layout';
203 if (!$this->getBackendUser()->check('modules', $pageModule)) {
204 $pageModule = '';
205 }
206 $t3Configuration = [
207 'username' => htmlspecialchars($this->getBackendUser()->user['username']),
208 'pageModule' => $pageModule,
209 'inWorkspace' => $this->getBackendUser()->workspace !== 0,
210 'showRefreshLoginPopup' => (bool)($GLOBALS['TYPO3_CONF_VARS']['BE']['showRefreshLoginPopup'] ?? false)
211 ];
212
213 return 'TYPO3.configuration = ' . json_encode($t3Configuration) . ';';
214 }
215
216 /**
217 * @return BackendUserAuthentication
218 */
219 protected function getBackendUser(): BackendUserAuthentication
220 {
221 return $GLOBALS['BE_USER'];
222 }
223 }