TYPO3  7.6
BackendController.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Backend\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 
29 
34 {
38  protected $content = '';
39 
43  protected $css = '';
44 
48  protected $cssFiles = array();
49 
53  protected $js = '';
54 
58  protected $jsFiles = array();
59 
63  protected $toolbarItems = array();
64 
68  protected $menuWidth = 190;
69 
73  protected $debug;
74 
78  protected $templatePath = 'EXT:backend/Resources/Private/Templates/';
79 
84 
88  protected $moduleLoader;
89 
93  protected $pageRenderer;
94 
99  public function getPageRenderer()
100  {
102  return $this->pageRenderer;
103  }
104 
108  public function __construct()
109  {
110  $this->getLanguageService()->includeLLFile('EXT:lang/locallang_misc.xlf');
111  $this->backendModuleRepository = GeneralUtility::makeInstance(BackendModuleRepository::class);
112 
113  // Set debug flag for BE development only
114  $this->debug = (int)$GLOBALS['TYPO3_CONF_VARS']['BE']['debug'] === 1;
115  // Initializes the backend modules structure for use later.
116  $this->moduleLoader = GeneralUtility::makeInstance(ModuleLoader::class);
117  $this->moduleLoader->load($GLOBALS['TBE_MODULES']);
118  $this->pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
119  $this->pageRenderer->loadExtJS();
120  // included for the module menu JavaScript, please note that this is subject to change
121  $this->pageRenderer->loadJquery();
122  $this->pageRenderer->addJsInlineCode('consoleOverrideWithDebugPanel', '//already done', false);
123  $this->pageRenderer->addExtDirectCode();
124  // Add default BE javascript
125  $this->jsFiles = array(
126  'locallang' => $this->getLocalLangFileName(),
127  'md5' => 'sysext/backend/Resources/Public/JavaScript/md5.js',
128  'modulemenu' => 'sysext/backend/Resources/Public/JavaScript/modulemenu.js',
129  'evalfield' => 'sysext/backend/Resources/Public/JavaScript/jsfunc.evalfield.js',
130  'notifications' => 'sysext/backend/Resources/Public/JavaScript/notifications.js',
131  'backend' => 'sysext/backend/Resources/Public/JavaScript/backend.js',
132  'viewport' => 'sysext/backend/Resources/Public/JavaScript/extjs/viewport.js',
133  'iframepanel' => 'sysext/backend/Resources/Public/JavaScript/iframepanel.js',
134  'backendcontentiframe' => 'sysext/backend/Resources/Public/JavaScript/extjs/backendcontentiframe.js',
135  'viewportConfiguration' => 'sysext/backend/Resources/Public/JavaScript/extjs/viewportConfiguration.js',
136  );
137  $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LoginRefresh', 'function(LoginRefresh) {
138  LoginRefresh.setLoginFramesetUrl(' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('login_frameset')) . ');
139  LoginRefresh.setLogoutUrl(' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('logout')) . ');
140  }');
141 
142  // load Utility class
143  $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Utility');
144 
145  // load Notification functionality
146  $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Notification');
147 
148  // load Modals
149  $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Modal');
150 
151  // load Legacy CSS Support
152  $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LegacyCssClasses');
153 
154  // load the storage API and fill the UC into the PersistentStorage, so no additional AJAX call is needed
155  $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Storage', 'function(Storage) {
156  Storage.Persistent.load(' . json_encode($this->getBackendUser()->uc) . ');
157  }');
158 
159  // load debug console
160  $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/DebugConsole');
161 
162  // Load RSA encryption
163  $rsaEncryptionEncoder = GeneralUtility::makeInstance(RsaEncryptionEncoder::class);
164  $rsaEncryptionEncoder->enableRsaEncryption(true);
165 
166  $this->pageRenderer->addInlineSetting('ShowItem', 'moduleUrl', BackendUtility::getModuleUrl('show_item'));
167 
168  $this->css = '';
169 
170  $this->initializeToolbarItems();
171  if (isset($GLOBALS['TBE_STYLES']['dims']['leftMenuFrameW'])) {
172  $this->menuWidth = (int)$GLOBALS['TBE_STYLES']['dims']['leftMenuFrameW'];
173  }
174  $this->executeHook('constructPostProcess');
175  $this->includeLegacyBackendItems();
176  }
177 
182  protected function includeLegacyBackendItems()
183  {
184  $TYPO3backend = $this;
185  // Include extensions which may add css, javascript or toolbar items
186  if (is_array($GLOBALS['TYPO3_CONF_VARS']['typo3/backend.php']['additionalBackendItems'])) {
187  foreach ($GLOBALS['TYPO3_CONF_VARS']['typo3/backend.php']['additionalBackendItems'] as $additionalBackendItem) {
188  include_once $additionalBackendItem;
189  }
190  }
191 
192  // Process ExtJS module js and css
193  if (is_array($GLOBALS['TBE_MODULES']['_configuration'])) {
194  foreach ($GLOBALS['TBE_MODULES']['_configuration'] as $moduleConfig) {
195  if (is_array($moduleConfig['cssFiles'])) {
196  foreach ($moduleConfig['cssFiles'] as $cssFileName => $cssFile) {
197  $files = array(\TYPO3\CMS\Core\Utility\GeneralUtility::getFileAbsFileName($cssFile));
198  $files = \TYPO3\CMS\Core\Utility\GeneralUtility::removePrefixPathFromList($files, PATH_site);
199  $TYPO3backend->addCssFile($cssFileName, '../' . $files[0]);
200  }
201  }
202  if (is_array($moduleConfig['jsFiles'])) {
203  foreach ($moduleConfig['jsFiles'] as $jsFile) {
204  $files = array(\TYPO3\CMS\Core\Utility\GeneralUtility::getFileAbsFileName($jsFile));
205  $files = \TYPO3\CMS\Core\Utility\GeneralUtility::removePrefixPathFromList($files, PATH_site);
206  $TYPO3backend->addJavascriptFile('../' . $files[0]);
207  }
208  }
209  }
210  }
211  }
212 
219  protected function initializeToolbarItems()
220  {
221  $toolbarItemInstances = array();
222  $classNameRegistry = $GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'];
223  foreach ($classNameRegistry as $className) {
224  $toolbarItemInstance = GeneralUtility::makeInstance($className);
225  if (!$toolbarItemInstance instanceof ToolbarItemInterface) {
226  throw new \RuntimeException(
227  'class ' . $className . ' is registered as toolbar item but does not implement'
228  . ToolbarItemInterface::class,
229  1415958218
230  );
231  }
232  $index = (int)$toolbarItemInstance->getIndex();
233  if ($index < 0 || $index > 100) {
234  throw new \RuntimeException(
235  'getIndex() must return an integer between 0 and 100',
236  1415968498
237  );
238  }
239  // Find next free position in array
240  while (array_key_exists($index, $toolbarItemInstances)) {
241  $index++;
242  }
243  $toolbarItemInstances[$index] = $toolbarItemInstance;
244  }
245  ksort($toolbarItemInstances);
246  $this->toolbarItems = $toolbarItemInstances;
247  }
248 
258  {
259  $this->render();
260  $response->getBody()->write($this->content);
261  return $response;
262  }
263 
269  public function render()
270  {
271  $this->executeHook('renderPreProcess');
272 
273  // Prepare the scaffolding, at this point extension may still add javascript and css
274  $view = $this->getFluidTemplateObject($this->templatePath . 'Backend/Main.html');
275 
276  // Render the TYPO3 logo in the left corner
277  $logoUrl = $GLOBALS['TBE_STYLES']['logo'] ?: 'sysext/backend/Resources/Public/Images/typo3-topbar@2x.png';
278  $logoPath = GeneralUtility::resolveBackPath(PATH_typo3 . $logoUrl);
279  list($logoWidth, $logoHeight) = @getimagesize($logoPath);
280 
281  // High-resolution?
282  if (strpos($logoUrl, '@2x.') !== false) {
283  $logoWidth = $logoWidth/2;
284  $logoHeight = $logoHeight/2;
285  }
286 
287  $view->assign('logoUrl', $logoUrl);
288  $view->assign('logoWidth', $logoWidth);
289  $view->assign('logoHeight', $logoHeight);
290  $view->assign('logoLink', TYPO3_URL_GENERAL);
291  $view->assign('applicationVersion', TYPO3_version);
292  $view->assign('siteName', $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']);
293  $view->assign('moduleMenu', $this->generateModuleMenu());
294  $view->assign('toolbar', $this->renderToolbar());
295 
296  /******************************************************
297  * Now put the complete backend document together
298  ******************************************************/
299  foreach ($this->cssFiles as $cssFileName => $cssFile) {
300  $this->pageRenderer->addCssFile($cssFile);
301  // Load additional css files to overwrite existing core styles
302  if (!empty($GLOBALS['TBE_STYLES']['stylesheets'][$cssFileName])) {
303  $this->pageRenderer->addCssFile($GLOBALS['TBE_STYLES']['stylesheets'][$cssFileName]);
304  }
305  }
306  if (!empty($this->css)) {
307  $this->pageRenderer->addCssInlineBlock('BackendInlineCSS', $this->css);
308  }
309  foreach ($this->jsFiles as $jsFile) {
310  $this->pageRenderer->addJsFile($jsFile);
311  }
312  $this->generateJavascript();
313  $this->pageRenderer->addJsInlineCode('BackendInlineJavascript', $this->js, false);
315 
316  // Add state provider
317  $this->getDocumentTemplate()->setExtDirectStateProvider();
318  $states = $this->getBackendUser()->uc['BackendComponents']['States'];
319  // Save states in BE_USER->uc
320  $extOnReadyCode = '
321  Ext.state.Manager.setProvider(new TYPO3.state.ExtDirectProvider({
322  key: "BackendComponents.States",
323  autoRead: false
324  }));
325  ';
326 
327  if ($states) {
328  $extOnReadyCode .= 'Ext.state.Manager.getProvider().initState(' . json_encode($states) . ');';
329  }
330 
331  $extOnReadyCode .= '
332  TYPO3.Backend = new TYPO3.Viewport(TYPO3.Viewport.configuration)';
333  $this->pageRenderer->addExtOnReadyCode($extOnReadyCode);
334  // Set document title:
335  $title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] ? $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] . ' [TYPO3 CMS ' . TYPO3_version . ']' : 'TYPO3 CMS ' . TYPO3_version;
336  // Renders the module page
337  $this->content = $this->getDocumentTemplate()->render($title, $view->render());
338  $hookConfiguration = array('content' => &$this->content);
339  $this->executeHook('renderPostProcess', $hookConfiguration);
340  }
341 
348  {
349  if (!is_array($GLOBALS['TBE_MODULES']['_navigationComponents'])) {
350  return;
351  }
352  $loadedComponents = array();
353  foreach ($GLOBALS['TBE_MODULES']['_navigationComponents'] as $module => $info) {
354  if (in_array($info['componentId'], $loadedComponents)) {
355  continue;
356  }
357  $loadedComponents[] = $info['componentId'];
358  $component = strtolower(substr($info['componentId'], strrpos($info['componentId'], '-') + 1));
359  $componentDirectory = 'components/' . $component . '/';
360  if ($info['isCoreComponent']) {
361  $absoluteComponentPath = PATH_site . 'typo3/sysext/backend/Resources/Public/JavaScript/extjs/' . $componentDirectory;
362  $relativeComponentPath = '../' . str_replace(PATH_site, '', $absoluteComponentPath);
363  } else {
364  $absoluteComponentPath = ExtensionManagementUtility::extPath($info['extKey']) . $componentDirectory;
365  $relativeComponentPath = ExtensionManagementUtility::extRelPath($info['extKey']) . $componentDirectory;
366  }
367  $cssFiles = GeneralUtility::getFilesInDir($absoluteComponentPath . 'css/', 'css');
368  if (file_exists($absoluteComponentPath . 'css/loadorder.txt')) {
369  // Don't allow inclusion outside directory
370  $loadOrder = str_replace('../', '', GeneralUtility::getUrl($absoluteComponentPath . 'css/loadorder.txt'));
371  $cssFilesOrdered = GeneralUtility::trimExplode(LF, $loadOrder, true);
372  $cssFiles = array_merge($cssFilesOrdered, $cssFiles);
373  }
374  foreach ($cssFiles as $cssFile) {
375  $this->pageRenderer->addCssFile($relativeComponentPath . 'css/' . $cssFile);
376  }
377  $jsFiles = GeneralUtility::getFilesInDir($absoluteComponentPath . 'javascript/', 'js');
378  if (file_exists($absoluteComponentPath . 'javascript/loadorder.txt')) {
379  // Don't allow inclusion outside directory
380  $loadOrder = str_replace('../', '', GeneralUtility::getUrl($absoluteComponentPath . 'javascript/loadorder.txt'));
381  $jsFilesOrdered = GeneralUtility::trimExplode(LF, $loadOrder, true);
382  $jsFiles = array_merge($jsFilesOrdered, $jsFiles);
383  }
384  foreach ($jsFiles as $jsFile) {
385  $this->pageRenderer->addJsFile($relativeComponentPath . 'javascript/' . $jsFile);
386  }
387  $this->pageRenderer->addInlineSetting('RecordHistory', 'moduleUrl', BackendUtility::getModuleUrl('record_history'));
388  $this->pageRenderer->addInlineSetting('NewRecord', 'moduleUrl', BackendUtility::getModuleUrl('db_new'));
389  $this->pageRenderer->addInlineSetting('FormEngine', 'moduleUrl', BackendUtility::getModuleUrl('record_edit'));
390  }
391  }
392 
398  protected function renderToolbar()
399  {
400  $toolbar = array();
401  foreach ($this->toolbarItems as $toolbarItem) {
403  if ($toolbarItem->checkAccess()) {
404  $hasDropDown = (bool)$toolbarItem->hasDropDown();
405  $additionalAttributes = (array)$toolbarItem->getAdditionalAttributes();
406 
407  $liAttributes = array();
408 
409  // Merge class: Add dropdown class if hasDropDown, add classes from additonal attributes
410  $classes = array();
411  if ($hasDropDown) {
412  $classes[] = 'dropdown';
413  }
414  if (isset($additionalAttributes['class'])) {
415  $classes[] = $additionalAttributes['class'];
416  unset($additionalAttributes['class']);
417  }
418  $liAttributes[] = 'class="' . implode(' ', $classes) . '"';
419 
420  // Add further attributes
421  foreach ($additionalAttributes as $name => $value) {
422  $liAttributes[] = $name . '="' . $value . '"';
423  }
424 
425  // Create a unique id from class name
426  $className = get_class($toolbarItem);
427  $className = GeneralUtility::underscoredToLowerCamelCase($className);
428  $className = GeneralUtility::camelCaseToLowerCaseUnderscored($className);
429  $className = str_replace(array('_', '\\'), '-', $className);
430  $liAttributes[] = 'id="' . $className . '"';
431 
432  $toolbar[] = '<li ' . implode(' ', $liAttributes) . '>';
433 
434  if ($hasDropDown) {
435  $toolbar[] = '<a href="#" class="dropdown-toggle" data-toggle="dropdown">';
436  $toolbar[] = $toolbarItem->getItem();
437  $toolbar[] = '</a>';
438  $toolbar[] = '<div class="dropdown-menu" role="menu">';
439  $toolbar[] = $toolbarItem->getDropDown();
440  $toolbar[] = '</div>';
441  } else {
442  $toolbar[] = $toolbarItem->getItem();
443  }
444  $toolbar[] = '</li>';
445  }
446  }
447  return implode(LF, $toolbar);
448  }
449 
457  protected function getLocalLangFileName()
458  {
459  $code = $this->generateLocalLang();
460  $filePath = 'typo3temp/Language/Backend-' . sha1($code) . '.js';
461  if (!file_exists(PATH_site . $filePath)) {
462  // writeFileToTypo3tempDir() returns NULL on success (please double-read!)
463  $error = GeneralUtility::writeFileToTypo3tempDir(PATH_site . $filePath, $code);
464  if ($error !== null) {
465  throw new \RuntimeException('Locallang JS file could not be written to ' . $filePath . '. Reason: ' . $error, 1295193026);
466  }
467  }
468  return '../' . $filePath;
469  }
470 
477  protected function generateLocalLang()
478  {
479  $lang = $this->getLanguageService();
480  $coreLabels = array(
481  'waitTitle' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_logging_in'),
482  'refresh_login_failed' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_failed'),
483  'refresh_login_failed_message' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_failed_message'),
484  'refresh_login_title' => sprintf($lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_title'), htmlspecialchars($this->getBackendUser()->user['username'])),
485  'login_expired' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.login_expired'),
486  'refresh_login_username' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_username'),
487  'refresh_login_password' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_password'),
488  'refresh_login_emptyPassword' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_emptyPassword'),
489  'refresh_login_button' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_button'),
490  'refresh_logout_button' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_logout_button'),
491  'refresh_exit_button' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_exit_button'),
492  'please_wait' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.please_wait'),
493  'loadingIndicator' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:loadingIndicator'),
494  'be_locked' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.be_locked'),
495  'refresh_login_countdown_singular' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_countdown_singular'),
496  'refresh_login_countdown' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_countdown'),
497  'login_about_to_expire' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.login_about_to_expire'),
498  'login_about_to_expire_title' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.login_about_to_expire_title'),
499  'refresh_login_logout_button' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_logout_button'),
500  'refresh_login_refresh_button' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_refresh_button'),
501  'tabs_closeAll' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:tabs.closeAll'),
502  'tabs_closeOther' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:tabs.closeOther'),
503  'tabs_close' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:tabs.close'),
504  'tabs_openInBrowserWindow' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:tabs.openInBrowserWindow'),
505  'csh_tooltip_loading' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:csh_tooltip_loading')
506  );
507  $labels = array(
508  'fileUpload' => array(
509  'windowTitle',
510  'buttonSelectFiles',
511  'buttonCancelAll',
512  'infoComponentMaxFileSize',
513  'infoComponentFileUploadLimit',
514  'infoComponentFileTypeLimit',
515  'infoComponentOverrideFiles',
516  'processRunning',
517  'uploadWait',
518  'uploadStarting',
519  'uploadProgress',
520  'uploadSuccess',
521  'errorQueueLimitExceeded',
522  'errorQueueFileSizeLimit',
523  'errorQueueZeroByteFile',
524  'errorQueueInvalidFiletype',
525  'errorUploadHttp',
526  'errorUploadMissingUrl',
527  'errorUploadIO',
528  'errorUploadSecurityError',
529  'errorUploadLimit',
530  'errorUploadFailed',
531  'errorUploadFileIDNotFound',
532  'errorUploadFileValidation',
533  'errorUploadFileCancelled',
534  'errorUploadStopped',
535  'allErrorMessageTitle',
536  'allErrorMessageText',
537  'allError401',
538  'allError2038'
539  ),
540  'liveSearch' => array(
541  'title',
542  'helpTitle',
543  'emptyText',
544  'loadingText',
545  'listEmptyText',
546  'showAllResults',
547  'helpDescription',
548  'helpDescriptionPages',
549  'helpDescriptionContent'
550  ),
551  'viewPort' => array(
552  'tooltipModuleMenuSplit',
553  'tooltipNavigationContainerSplitDrag',
554  'tooltipNavigationContainerSplitClick',
555  'tooltipDebugPanelSplitDrag'
556  )
557  );
558  $generatedLabels = array();
559  $generatedLabels['core'] = $coreLabels;
560  // First loop over all categories (fileUpload, liveSearch, ..)
561  foreach ($labels as $categoryName => $categoryLabels) {
562  // Then loop over every single label
563  foreach ($categoryLabels as $label) {
564  // LLL identifier must be called $categoryName_$label, e.g. liveSearch_loadingText
565  $generatedLabels[$categoryName][$label] = $this->getLanguageService()->getLL($categoryName . '_' . $label);
566  }
567  }
568  return 'TYPO3.LLL = ' . json_encode($generatedLabels) . ';';
569  }
570 
576  protected function generateJavascript()
577  {
578  $beUser = $this->getBackendUser();
579  // Needed for FormEngine manipulation (date picker)
580  $dateFormat = ($GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat'] ? array('MM-DD-YYYY', 'HH:mm MM-DD-YYYY') : array('DD-MM-YYYY', 'HH:mm DD-MM-YYYY'));
581  $this->pageRenderer->addInlineSetting('DateTimePicker', 'DateFormat', $dateFormat);
582  // define the window size of the element browser etc.
583  $popupWindowWidth = 700;
584  $popupWindowHeight = 750;
585  $popupWindowSize = trim($beUser->getTSConfigVal('options.popupWindowSize'));
586  if (!empty($popupWindowSize)) {
587  list($popupWindowWidth, $popupWindowHeight) = GeneralUtility::intExplode('x', $popupWindowSize);
588  }
589 
590  // define the window size of the popups within the RTE
591  $rtePopupWindowSize = trim($beUser->getTSConfigVal('options.rte.popupWindowSize'));
592  if (!empty($rtePopupWindowSize)) {
593  list($rtePopupWindowWidth, $rtePopupWindowHeight) = GeneralUtility::trimExplode('x', $rtePopupWindowSize);
594  }
595  $rtePopupWindowWidth = !empty($rtePopupWindowWidth) ? (int)$rtePopupWindowWidth : ($popupWindowWidth-200);
596  $rtePopupWindowHeight = !empty($rtePopupWindowHeight) ? (int)$rtePopupWindowHeight : ($popupWindowHeight-250);
597 
598  $pathTYPO3 = GeneralUtility::dirname(GeneralUtility::getIndpEnv('SCRIPT_NAME')) . '/';
599  // If another page module was specified, replace the default Page module with the new one
600  $newPageModule = trim($beUser->getTSConfigVal('options.overridePageModule'));
601  $pageModule = BackendUtility::isModuleSetInTBE_MODULES($newPageModule) ? $newPageModule : 'web_layout';
602  if (!$beUser->check('modules', $pageModule)) {
603  $pageModule = '';
604  }
605  $t3Configuration = array(
606  'siteUrl' => GeneralUtility::getIndpEnv('TYPO3_SITE_URL'),
607  'PATH_typo3' => $pathTYPO3,
608  'PATH_typo3_enc' => rawurlencode($pathTYPO3),
609  'username' => htmlspecialchars($beUser->user['username']),
610  'userUid' => htmlspecialchars($beUser->user['uid']),
611  'uniqueID' => GeneralUtility::shortMD5(uniqid('', true)),
612  'securityLevel' => trim($GLOBALS['TYPO3_CONF_VARS']['BE']['loginSecurityLevel']) ?: 'normal',
613  'TYPO3_mainDir' => TYPO3_mainDir,
614  'pageModule' => $pageModule,
615  'inWorkspace' => $beUser->workspace !== 0,
616  'workspaceFrontendPreviewEnabled' => $beUser->user['workspace_preview'] ? 1 : 0,
617  'veriCode' => $beUser->veriCode(),
618  'denyFileTypes' => PHP_EXTENSIONS_DEFAULT,
619  'moduleMenuWidth' => $this->menuWidth - 1,
620  'topBarHeight' => isset($GLOBALS['TBE_STYLES']['dims']['topFrameH']) ? (int)$GLOBALS['TBE_STYLES']['dims']['topFrameH'] : 30,
621  'showRefreshLoginPopup' => isset($GLOBALS['TYPO3_CONF_VARS']['BE']['showRefreshLoginPopup']) ? (int)$GLOBALS['TYPO3_CONF_VARS']['BE']['showRefreshLoginPopup'] : false,
622  'listModulePath' => ExtensionManagementUtility::extRelPath('recordlist') . 'mod1/',
623  'debugInWindow' => $beUser->uc['debugInWindow'] ? 1 : 0,
624  'ContextHelpWindows' => array(
625  'width' => 600,
626  'height' => 400
627  ),
628  'PopupWindow' => array(
629  'width' => $popupWindowWidth,
630  'height' => $popupWindowHeight
631  ),
632  'RTEPopupWindow' => array(
633  'width' => $rtePopupWindowWidth,
634  'height' => $rtePopupWindowHeight
635  )
636  );
637  $this->js .= '
638  TYPO3.configuration = ' . json_encode($t3Configuration) . ';
639 
643  function typoSetup() { //
644  this.PATH_typo3 = TYPO3.configuration.PATH_typo3;
645  this.PATH_typo3_enc = TYPO3.configuration.PATH_typo3_enc;
646  this.username = TYPO3.configuration.username;
647  this.uniqueID = TYPO3.configuration.uniqueID;
648  this.securityLevel = TYPO3.configuration.securityLevel;
649  this.veriCode = TYPO3.configuration.veriCode;
650  this.denyFileTypes = TYPO3.configuration.denyFileTypes;
651  }
652  var TS = new typoSetup();
653  //backwards compatibility
662  function fsModules() { //
663  this.recentIds=new Array(); // used by frameset modules to track the most recent used id for list frame.
664  this.navFrameHighlightedID=new Array(); // used by navigation frames to track which row id was highlighted last time
665  this.currentMainLoaded="";
666  this.currentBank="0";
667  }
668  var fsMod = new fsModules();
669 
670  top.goToModule = function(modName, cMR_flag, addGetVars) {
671  TYPO3.ModuleMenu.App.showModule(modName, addGetVars);
672  }
673  ' . $this->setStartupModule();
674  // Check editing of page:
675  $this->handlePageEditing();
676  }
677 
683  protected function handlePageEditing()
684  {
685  $beUser = $this->getBackendUser();
686  // EDIT page:
687  $editId = preg_replace('/[^[:alnum:]_]/', '', GeneralUtility::_GET('edit'));
688  $editRecord = '';
689  if ($editId) {
690  // Looking up the page to edit, checking permissions:
691  $where = ' AND (' . $beUser->getPagePermsClause(2) . ' OR ' . $beUser->getPagePermsClause(16) . ')';
693  $editRecord = BackendUtility::getRecordWSOL('pages', $editId, '*', $where);
694  } else {
695  $records = BackendUtility::getRecordsByField('pages', 'alias', $editId, $where);
696  if (is_array($records)) {
697  $editRecord = reset($records);
698  BackendUtility::workspaceOL('pages', $editRecord);
699  }
700  }
701  // If the page was accessible, then let the user edit it.
702  if (is_array($editRecord) && $beUser->isInWebMount($editRecord['uid'])) {
703  // Setting JS code to open editing:
704  $this->js .= '
705  // Load page to edit:
706  window.setTimeout("top.loadEditId(' . (int)$editRecord['uid'] . ');", 500);
707  ';
708  // Checking page edit parameter:
709  if (!$beUser->getTSConfigVal('options.bookmark_onEditId_dontSetPageTree')) {
710  $bookmarkKeepExpanded = $beUser->getTSConfigVal('options.bookmark_onEditId_keepExistingExpanded');
711  // Expanding page tree:
712  BackendUtility::openPageTree((int)$editRecord['pid'], !$bookmarkKeepExpanded);
713  }
714  } else {
715  $this->js .= '
716  // Warning about page editing:
717  alert(' . GeneralUtility::quoteJSvalue(sprintf($this->getLanguageService()->getLL('noEditPage'), $editId)) . ');
718  ';
719  }
720  }
721  }
722 
728  protected function setStartupModule()
729  {
730  $startModule = preg_replace('/[^[:alnum:]_]/', '', GeneralUtility::_GET('module'));
731  $startModuleParameters = '';
732  if (!$startModule) {
733  $beUser = $this->getBackendUser();
734  // start module on first login, will be removed once used the first time
735  if (isset($beUser->uc['startModuleOnFirstLogin'])) {
736  $startModule = $beUser->uc['startModuleOnFirstLogin'];
737  unset($beUser->uc['startModuleOnFirstLogin']);
738  $beUser->writeUC();
739  } elseif ($beUser->uc['startModule']) {
740  $startModule = $beUser->uc['startModule'];
741  } elseif ($beUser->uc['startInTaskCenter']) {
742  $startModule = 'user_task';
743  }
744 
745  // check if the start module has additional parameters, so a redirect to a specific
746  // action is possible
747  if (strpos($startModule, '->') !== false) {
748  list($startModule, $startModuleParameters) = explode('->', $startModule, 2);
749  }
750  }
751 
752  $moduleParameters = GeneralUtility::_GET('modParams');
753  // if no GET parameters are set, check if there are parameters given from the UC
754  if (!$moduleParameters && $startModuleParameters) {
755  $moduleParameters = $startModuleParameters;
756  }
757 
758  if ($startModule) {
759  return '
760  // start in module:
761  top.startInModule = [' . GeneralUtility::quoteJSvalue($startModule) . ', ' . GeneralUtility::quoteJSvalue($moduleParameters) . '];
762  ';
763  } else {
764  return '';
765  }
766  }
767 
775  public function addJavascript($javascript)
776  {
777  // @todo do we need more checks?
778  if (!is_string($javascript)) {
779  throw new \InvalidArgumentException('parameter $javascript must be of type string', 1195129553);
780  }
781  $this->js .= $javascript;
782  }
783 
790  public function addJavascriptFile($javascriptFile)
791  {
792  $jsFileAdded = false;
793  // @todo add more checks if necessary
794  if (file_exists(GeneralUtility::resolveBackPath(PATH_typo3 . $javascriptFile))) {
795  $this->jsFiles[] = $javascriptFile;
796  $jsFileAdded = true;
797  }
798  return $jsFileAdded;
799  }
800 
808  public function addCss($css)
809  {
810  if (!is_string($css)) {
811  throw new \InvalidArgumentException('parameter $css must be of type string', 1195129642);
812  }
813  $this->css .= $css;
814  }
815 
823  public function addCssFile($cssFileName, $cssFile)
824  {
825  $cssFileAdded = false;
826  if (empty($this->cssFiles[$cssFileName])) {
827  $this->cssFiles[$cssFileName] = $cssFile;
828  $cssFileAdded = true;
829  }
830  return $cssFileAdded;
831  }
832 
842  public function addToolbarItem($toolbarItemName, $toolbarItemClassName)
843  {
845  }
846 
859  protected function executeHook($identifier, array $hookConfiguration = array())
860  {
861  $options = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/backend.php'];
862  if (isset($options[$identifier]) && is_array($options[$identifier])) {
863  foreach ($options[$identifier] as $hookFunction) {
864  GeneralUtility::callUserFunction($hookFunction, $hookConfiguration, $this);
865  }
866  }
867  }
868 
875  protected function generateModuleMenu()
876  {
877  // get all modules except the user modules for the side menu
878  $moduleStorage = $this->backendModuleRepository->loadAllowedModules(array('user', 'help'));
879 
880  $view = $this->getFluidTemplateObject($this->templatePath . 'ModuleMenu/Main.html');
881  $view->assign('modules', $moduleStorage);
882  return $view->render();
883  }
884 
893  {
894  $content = $this->generateModuleMenu();
895 
896  $response->getBody()->write(json_encode(['menu' => $content]));
897  return $response;
898  }
899 
906  protected function getFluidTemplateObject($templatePathAndFileName = null)
907  {
908  $view = GeneralUtility::makeInstance(StandaloneView::class);
909  if ($templatePathAndFileName) {
910  $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templatePathAndFileName));
911  }
912  return $view;
913  }
914 
920  protected function getLanguageService()
921  {
922  return $GLOBALS['LANG'];
923  }
924 
930  protected function getBackendUser()
931  {
932  return $GLOBALS['BE_USER'];
933  }
934 
940  protected function getDocumentTemplate()
941  {
942  return $GLOBALS['TBE_TEMPLATE'];
943  }
944 }