[TASK] Clean up workspace preview top bar
[Packages/TYPO3.CMS.git] / typo3 / sysext / workspaces / Classes / Controller / ReviewController.php
1 <?php
2 namespace TYPO3\CMS\Workspaces\Controller;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Backend\Routing\UriBuilder;
18 use TYPO3\CMS\Backend\Utility\BackendUtility;
19 use TYPO3\CMS\Backend\View\BackendTemplateView;
20 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
21 use TYPO3\CMS\Core\Imaging\Icon;
22 use TYPO3\CMS\Core\Imaging\IconFactory;
23 use TYPO3\CMS\Core\Localization\LanguageService;
24 use TYPO3\CMS\Core\Page\PageRenderer;
25 use TYPO3\CMS\Core\Utility\GeneralUtility;
26 use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
27 use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
28 use TYPO3\CMS\Workspaces\Service\AdditionalColumnService;
29 use TYPO3\CMS\Workspaces\Service\AdditionalResourceService;
30 use TYPO3\CMS\Workspaces\Service\WorkspaceService;
31
32 /**
33 * Review controller.
34 */
35 class ReviewController extends ActionController
36 {
37 /**
38 * @var string
39 */
40 protected $defaultViewObjectName = BackendTemplateView::class;
41
42 /**
43 * @var BackendTemplateView
44 */
45 protected $view;
46
47 /**
48 * @var PageRenderer
49 */
50 protected $pageRenderer;
51
52 /**
53 * @var int
54 */
55 protected $pageId;
56
57 /**
58 * Set up the doc header properly here
59 *
60 * @param ViewInterface $view
61 */
62 protected function initializeView(ViewInterface $view)
63 {
64 parent::initializeView($view);
65 $this->registerButtons();
66 $this->view->getModuleTemplate()->setFlashMessageQueue($this->controllerContext->getFlashMessageQueue());
67 }
68
69 /**
70 * Registers the DocHeader buttons
71 */
72 protected function registerButtons()
73 {
74 $buttonBar = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar();
75 $currentRequest = $this->request;
76 $moduleName = $currentRequest->getPluginName();
77 $getVars = $this->request->getArguments();
78 $extensionName = $currentRequest->getControllerExtensionName();
79 if (count($getVars) === 0) {
80 $modulePrefix = strtolower('tx_' . $extensionName . '_' . $moduleName);
81 $getVars = ['id', 'route', $modulePrefix];
82 }
83 $shortcutButton = $buttonBar->makeShortcutButton()
84 ->setModuleName($moduleName)
85 ->setGetVariables($getVars);
86 $buttonBar->addButton($shortcutButton);
87 }
88
89 /**
90 * Initializes the controller before invoking an action method.
91 */
92 protected function initializeAction()
93 {
94 $this->pageRenderer = $this->getPageRenderer();
95 // @todo Evaluate how the (int) typecast can be used with Extbase validators/filters
96 $this->pageId = (int)GeneralUtility::_GP('id');
97 $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
98 $lang = $this->getLanguageService();
99 $icons = [
100 'language' => $iconFactory->getIcon('flags-multiple', Icon::SIZE_SMALL)->render(),
101 'integrity' => $iconFactory->getIcon('status-dialog-information', Icon::SIZE_SMALL)->render(),
102 'success' => $iconFactory->getIcon('status-dialog-ok', Icon::SIZE_SMALL)->render(),
103 'info' => $iconFactory->getIcon('status-dialog-information', Icon::SIZE_SMALL)->render(),
104 'warning' => $iconFactory->getIcon('status-dialog-warning', Icon::SIZE_SMALL)->render(),
105 'error' => $iconFactory->getIcon('status-dialog-error', Icon::SIZE_SMALL)->render()
106 ];
107 $this->pageRenderer->addInlineSetting('Workspaces', 'icons', $icons);
108 $this->pageRenderer->addInlineSetting('Workspaces', 'id', $this->pageId);
109 $this->pageRenderer->addInlineSetting('Workspaces', 'depth', $this->pageId === 0 ? 999 : 1);
110 $this->pageRenderer->addInlineSetting('Workspaces', 'language', $this->getLanguageSelection());
111 $this->pageRenderer->addInlineLanguageLabelArray([
112 'title' => $lang->getLL('title'),
113 'path' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.path'),
114 'table' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.table'),
115 'depth' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_mod_web_perm.xlf:Depth'),
116 'depth_0' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_0'),
117 'depth_1' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_1'),
118 'depth_2' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_2'),
119 'depth_3' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_3'),
120 'depth_4' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_4'),
121 'depth_infi' => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_infi')
122 ]);
123 $this->pageRenderer->addInlineLanguageLabelFile('EXT:workspaces/Resources/Private/Language/locallang.xlf');
124 $states = $this->getBackendUser()->uc['moduleData']['Workspaces']['States'];
125 $this->pageRenderer->addInlineSetting('Workspaces', 'States', $states);
126
127 foreach ($this->getAdditionalResourceService()->getLocalizationResources() as $localizationResource) {
128 $this->pageRenderer->addInlineLanguageLabelFile($localizationResource);
129 }
130 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
131 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Workspaces/Backend');
132 $this->pageRenderer->addInlineSetting('FormEngine', 'moduleUrl', (string)$uriBuilder->buildUriFromRoute('record_edit'));
133 $this->pageRenderer->addInlineSetting('RecordHistory', 'moduleUrl', (string)$uriBuilder->buildUriFromRoute('record_history'));
134 $this->pageRenderer->addInlineSetting('Workspaces', 'id', (int)GeneralUtility::_GP('id'));
135
136 $this->assignExtensionSettings();
137 }
138
139 /**
140 * Renders the review module user dependent with all workspaces.
141 * The module will show all records of one workspace.
142 */
143 public function indexAction()
144 {
145 $backendUser = $this->getBackendUser();
146 $moduleTemplate = $this->view->getModuleTemplate();
147
148 /** @var WorkspaceService $wsService */
149 $wsService = GeneralUtility::makeInstance(WorkspaceService::class);
150 if (GeneralUtility::_GP('id')) {
151 $pageRecord = BackendUtility::getRecord('pages', GeneralUtility::_GP('id'));
152 if ($pageRecord) {
153 $moduleTemplate->getDocHeaderComponent()->setMetaInformation($pageRecord);
154 $this->view->assign('pageTitle', BackendUtility::getRecordTitle('pages', $pageRecord));
155 }
156 }
157 $wsList = $wsService->getAvailableWorkspaces();
158 $activeWorkspace = $backendUser->workspace;
159 $performWorkspaceSwitch = false;
160 // Only admins see multiple tabs, we decided to use it this
161 // way for usability reasons. Regular users might be confused
162 // by switching workspaces with the tabs in a module.
163 if (!$backendUser->isAdmin()) {
164 $wsCur = [$activeWorkspace => true];
165 $wsList = array_intersect_key($wsList, $wsCur);
166 } else {
167 if ((string)GeneralUtility::_GP('workspace') !== '') {
168 $switchWs = (int)GeneralUtility::_GP('workspace');
169 if (in_array($switchWs, array_keys($wsList)) && $activeWorkspace != $switchWs) {
170 $activeWorkspace = $switchWs;
171 $backendUser->setWorkspace($activeWorkspace);
172 $performWorkspaceSwitch = true;
173 BackendUtility::setUpdateSignal('updatePageTree');
174 } elseif ($switchWs == WorkspaceService::SELECT_ALL_WORKSPACES) {
175 $this->redirect('fullIndex');
176 }
177 }
178 }
179 $this->pageRenderer->addInlineSetting('Workspaces', 'isLiveWorkspace', (int)$backendUser->workspace === 0);
180 $this->pageRenderer->addInlineSetting('Workspaces', 'workspaceTabs', $this->prepareWorkspaceTabs($wsList, $activeWorkspace));
181 $this->pageRenderer->addInlineSetting('Workspaces', 'activeWorkspaceId', $activeWorkspace);
182 $workspaceIsAccessible = !($backendUser->workspace === 0 && !$backendUser->isAdmin());
183 $this->view->assignMultiple([
184 'showGrid' => $workspaceIsAccessible,
185 'showLegend' => $workspaceIsAccessible,
186 'pageUid' => (int)GeneralUtility::_GP('id'),
187 'performWorkspaceSwitch' => $performWorkspaceSwitch,
188 'workspaceList' => $this->prepareWorkspaceTabs($wsList, $activeWorkspace),
189 'activeWorkspaceUid' => $activeWorkspace,
190 'activeWorkspaceTitle' => WorkspaceService::getWorkspaceTitle($activeWorkspace),
191 ]);
192
193 if ($wsService->canCreatePreviewLink(GeneralUtility::_GP('id'), $activeWorkspace)) {
194 $buttonBar = $moduleTemplate->getDocHeaderComponent()->getButtonBar();
195 $iconFactory = $moduleTemplate->getIconFactory();
196 $showButton = $buttonBar->makeLinkButton()
197 ->setHref('#')
198 ->setClasses('t3js-preview-link')
199 ->setTitle($this->getLanguageService()->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:tooltip.generatePagePreview'))
200 ->setIcon($iconFactory->getIcon('module-workspaces-action-preview-link', Icon::SIZE_SMALL));
201 $buttonBar->addButton($showButton);
202 }
203 $backendUser->setAndSaveSessionData('tx_workspace_activeWorkspace', $activeWorkspace);
204 }
205
206 /**
207 * Renders the review module user dependent.
208 * The module will show all records of all workspaces.
209 */
210 public function fullIndexAction()
211 {
212 $wsService = GeneralUtility::makeInstance(WorkspaceService::class);
213 $wsList = $wsService->getAvailableWorkspaces();
214
215 $activeWorkspace = $this->getBackendUser()->workspace;
216 if (!$this->getBackendUser()->isAdmin()) {
217 $wsCur = [$activeWorkspace => true];
218 $wsList = array_intersect_key($wsList, $wsCur);
219 }
220
221 $this->pageRenderer->addInlineSetting('Workspaces', 'workspaceTabs', $this->prepareWorkspaceTabs($wsList, WorkspaceService::SELECT_ALL_WORKSPACES));
222 $this->pageRenderer->addInlineSetting('Workspaces', 'activeWorkspaceId', WorkspaceService::SELECT_ALL_WORKSPACES);
223 $this->view->assignMultiple([
224 'pageUid' => (int)GeneralUtility::_GP('id'),
225 'showGrid' => true,
226 'showLegend' => true,
227 'workspaceList' => $this->prepareWorkspaceTabs($wsList, $activeWorkspace),
228 'activeWorkspaceUid' => WorkspaceService::SELECT_ALL_WORKSPACES
229 ]);
230 $this->getBackendUser()->setAndSaveSessionData('tx_workspace_activeWorkspace', WorkspaceService::SELECT_ALL_WORKSPACES);
231 // set flag for javascript
232 $this->pageRenderer->addInlineSetting('Workspaces', 'allView', '1');
233 }
234
235 /**
236 * Renders the review module for a single page. This is used within the
237 * workspace-preview frame.
238 */
239 public function singleIndexAction()
240 {
241 $wsService = GeneralUtility::makeInstance(WorkspaceService::class);
242 $wsList = $wsService->getAvailableWorkspaces();
243 $activeWorkspace = $this->getBackendUser()->workspace;
244 $wsCur = [$activeWorkspace => true];
245 $wsList = array_intersect_key($wsList, $wsCur);
246 $backendDomain = GeneralUtility::getIndpEnv('TYPO3_HOST_ONLY');
247 $this->view->assignMultiple([
248 'pageUid' => (int)GeneralUtility::_GP('id'),
249 'showGrid' => true,
250 'workspaceList' => $this->prepareWorkspaceTabs($wsList, (int)$activeWorkspace, false),
251 'activeWorkspaceUid' => $activeWorkspace,
252 'backendDomain' => $backendDomain
253 ]);
254 // Setting the document.domain early before JavScript
255 // libraries are loaded, try to access top frame reference
256 // and possibly run into some CORS issue
257 $this->pageRenderer->setMetaCharsetTag(
258 $this->pageRenderer->getMetaCharsetTag() . LF
259 . GeneralUtility::wrapJS('document.domain = ' . GeneralUtility::quoteJSvalue($backendDomain) . ';')
260 );
261 $this->pageRenderer->addInlineSetting('Workspaces', 'singleView', '1');
262 }
263
264 /**
265 * Prepares available workspace tabs.
266 *
267 * @param array $workspaceList
268 * @param int $activeWorkspace
269 * @param bool $showAllWorkspaceTab
270 * @return array
271 */
272 protected function prepareWorkspaceTabs(array $workspaceList, int $activeWorkspace, bool $showAllWorkspaceTab = true)
273 {
274 $tabs = [];
275
276 if ($activeWorkspace !== WorkspaceService::SELECT_ALL_WORKSPACES) {
277 $tabs[] = [
278 'title' => $workspaceList[$activeWorkspace],
279 'itemId' => 'workspace-' . $activeWorkspace,
280 'workspaceId' => $activeWorkspace,
281 'triggerUrl' => $this->getModuleUri($activeWorkspace),
282 ];
283 }
284
285 if ($showAllWorkspaceTab) {
286 $tabs[] = [
287 'title' => 'All workspaces',
288 'itemId' => 'workspace-' . WorkspaceService::SELECT_ALL_WORKSPACES,
289 'workspaceId' => WorkspaceService::SELECT_ALL_WORKSPACES,
290 'triggerUrl' => $this->getModuleUri(WorkspaceService::SELECT_ALL_WORKSPACES),
291 ];
292 }
293
294 foreach ($workspaceList as $workspaceId => $workspaceTitle) {
295 if ($workspaceId === $activeWorkspace) {
296 continue;
297 }
298 $tabs[] = [
299 'title' => $workspaceTitle,
300 'itemId' => 'workspace-' . $workspaceId,
301 'workspaceId' => $workspaceId,
302 'triggerUrl' => $this->getModuleUri($workspaceId),
303 ];
304 }
305
306 return $tabs;
307 }
308
309 /**
310 * Gets the module URI.
311 *
312 * @param int $workspaceId
313 * @return string
314 */
315 protected function getModuleUri(int $workspaceId): string
316 {
317 $parameters = [
318 'id' => $this->pageId,
319 'workspace' => $workspaceId,
320 ];
321 // The "all workspaces" tab is handled in fullIndexAction
322 // which is required as additional GET parameter in the URI then
323 if ($workspaceId === WorkspaceService::SELECT_ALL_WORKSPACES) {
324 $this->uriBuilder->reset()->uriFor('fullIndex');
325 $parameters = array_merge($parameters, $this->uriBuilder->getArguments());
326 }
327 /** @var UriBuilder $uriBuilder */
328 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
329 return (string)$uriBuilder->buildUriFromRoute('web_WorkspacesWorkspaces', $parameters);
330 }
331
332 /**
333 * Assigns additional Workspace settings to TYPO3.settings.Workspaces.extension
334 */
335 protected function assignExtensionSettings()
336 {
337 $extension = [
338 'AdditionalColumn' => [
339 'Definition' => [],
340 'Handler' => [],
341 ],
342 ];
343
344 $extension['AdditionalColumn']['Definition'] = $this->getAdditionalColumnService()->getDefinition();
345 $extension['AdditionalColumn']['Handler'] = $this->getAdditionalColumnService()->getHandler();
346 $this->pageRenderer->addInlineSetting('Workspaces', 'extension', $extension);
347 }
348
349 /**
350 * Gets the selected language.
351 *
352 * @return string
353 */
354 protected function getLanguageSelection(): string
355 {
356 $language = 'all';
357 $backendUser = $this->getBackendUser();
358 if (isset($backendUser->uc['moduleData']['Workspaces'][$backendUser->workspace]['language'])) {
359 $language = $backendUser->uc['moduleData']['Workspaces'][$backendUser->workspace]['language'];
360 }
361 return $language;
362 }
363
364 /**
365 * @return AdditionalColumnService
366 */
367 protected function getAdditionalColumnService(): AdditionalColumnService
368 {
369 return $this->objectManager->get(AdditionalColumnService::class);
370 }
371
372 /**
373 * @return AdditionalResourceService
374 */
375 protected function getAdditionalResourceService(): AdditionalResourceService
376 {
377 return $this->objectManager->get(AdditionalResourceService::class);
378 }
379
380 /**
381 * @return PageRenderer
382 */
383 protected function getPageRenderer(): PageRenderer
384 {
385 return GeneralUtility::makeInstance(PageRenderer::class);
386 }
387
388 /**
389 * @return LanguageService
390 */
391 protected function getLanguageService(): LanguageService
392 {
393 return $GLOBALS['LANG'];
394 }
395
396 /**
397 * @return BackendUserAuthentication
398 */
399 protected function getBackendUser(): BackendUserAuthentication
400 {
401 return $GLOBALS['BE_USER'];
402 }
403 }