38675e14ff3e61020bc0f797dcd322b8fa615c77
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Controller / BackendController.php
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
17 use TYPO3\CMS\Backend\Utility\BackendUtility;
18 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
19 use TYPO3\CMS\Core\Utility\GeneralUtility;
20
21 /**
22 * Class for rendering the TYPO3 backend
23 *
24 * @author Ingo Renner <ingo@typo3.org>
25 */
26 class BackendController {
27
28 /**
29 * @var string
30 */
31 protected $content = '';
32
33 /**
34 * @var string
35 */
36 protected $css = '';
37
38 /**
39 * @var array
40 */
41 protected $cssFiles = array();
42
43 /**
44 * @var string
45 */
46 protected $js = '';
47
48 /**
49 * @var array
50 */
51 protected $jsFiles = array();
52
53 /**
54 * @var array
55 */
56 protected $toolbarItems = array();
57
58 /**
59 * @var int
60 */
61 protected $menuWidth = 190;
62
63 /**
64 * @var bool
65 */
66 protected $debug;
67
68 /**
69 * @var string
70 */
71 protected $templatePath = 'EXT:backend/Resources/Private/Templates/';
72
73 /**
74 * @var \TYPO3\CMS\Backend\Domain\Repository\Module\BackendModuleRepository
75 */
76 protected $backendModuleRepository;
77
78 /**
79 * @var \TYPO3\CMS\Backend\Module\ModuleLoader Object for loading backend modules
80 */
81 protected $moduleLoader;
82
83 /**
84 * @var \TYPO3\CMS\Core\Page\PageRenderer
85 */
86 protected $pageRenderer;
87
88 /**
89 * @return \TYPO3\CMS\Core\Page\PageRenderer
90 */
91 public function getPageRenderer() {
92 return $this->pageRenderer;
93 }
94
95 /**
96 * Constructor
97 */
98 public function __construct() {
99 $this->backendModuleRepository = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Domain\Repository\Module\BackendModuleRepository::class);
100
101 // Set debug flag for BE development only
102 $this->debug = (int)$GLOBALS['TYPO3_CONF_VARS']['BE']['debug'] === 1;
103 // Initializes the backend modules structure for use later.
104 $this->moduleLoader = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Module\ModuleLoader::class);
105 $this->moduleLoader->load($GLOBALS['TBE_MODULES']);
106 $this->pageRenderer = $GLOBALS['TBE_TEMPLATE']->getPageRenderer();
107 $this->pageRenderer->loadExtJS();
108 // included for the module menu JavaScript, please note that this is subject to change
109 $this->pageRenderer->loadJquery();
110 $this->pageRenderer->enableExtJSQuickTips();
111 $this->pageRenderer->addJsInlineCode('consoleOverrideWithDebugPanel', '//already done', FALSE);
112 $this->pageRenderer->addExtDirectCode();
113 // Add default BE javascript
114 $this->jsFiles = array(
115 'locallang' => $this->getLocalLangFileName(),
116 'modernizr' => 'contrib/modernizr/modernizr.min.js',
117 'md5' => 'sysext/backend/Resources/Public/JavaScript/md5.js',
118 'modulemenu' => 'sysext/backend/Resources/Public/JavaScript/modulemenu.js',
119 'evalfield' => 'sysext/backend/Resources/Public/JavaScript/jsfunc.evalfield.js',
120 'tabclosemenu' => 'js/extjs/ux/ext.ux.tabclosemenu.js',
121 'notifications' => 'sysext/backend/Resources/Public/JavaScript/notifications.js',
122 'backend' => 'sysext/backend/Resources/Public/JavaScript/backend.js',
123 'debugPanel' => 'js/extjs/debugPanel.js',
124 'viewport' => 'js/extjs/viewport.js',
125 'iframepanel' => 'sysext/backend/Resources/Public/JavaScript/iframepanel.js',
126 'backendcontentiframe' => 'js/extjs/backendcontentiframe.js',
127 'viewportConfiguration' => 'js/extjs/viewportConfiguration.js',
128 'util' => 'sysext/backend/Resources/Public/JavaScript/util.js'
129 );
130 if (!$this->debug) {
131 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LoginRefresh', 'function(LoginRefresh) {
132 LoginRefresh.setLoginFramesetUrl(' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('login_frameset')) . ');
133 LoginRefresh.setLogoutUrl(' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('logout')) . ');
134 }');
135 }
136
137 // load FlashMessages functionality
138 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/FlashMessages');
139
140 // load Modals
141 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Modal');
142
143 // load Legacy CSS Support
144 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LegacyCssClasses');
145
146 // load the storage API and fill the UC into the PersistentStorage, so no additional AJAX call is needed
147 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Storage', 'function(Storage) {
148 Storage.Persistent.load(' . json_encode($GLOBALS['BE_USER']->uc) . ');
149 }');
150
151 $this->pageRenderer->addInlineSetting('ShowItem', 'moduleUrl', BackendUtility::getModuleUrl('show_item'));
152
153 $this->css = '';
154
155 $this->initializeToolbarItems();
156 if (isset($GLOBALS['TBE_STYLES']['dims']['leftMenuFrameW'])) {
157 $this->menuWidth = (int)$GLOBALS['TBE_STYLES']['dims']['leftMenuFrameW'];
158 }
159 $this->executeHook('constructPostProcess');
160 }
161
162 /**
163 * Initialize toolbar item objects
164 *
165 * @throws \RuntimeException
166 * @return void
167 */
168 protected function initializeToolbarItems() {
169 $toolbarItemInstances = array();
170 $classNameRegistry = $GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'];
171 foreach ($classNameRegistry as $className) {
172 $toolbarItemInstance = GeneralUtility::makeInstance($className);
173 if (!$toolbarItemInstance instanceof \TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface) {
174 throw new \RuntimeException(
175 'class ' . $className . ' is registered as toolbar item but does not implement'
176 . \TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface::class,
177 1415958218
178 );
179 }
180 $index = (int)$toolbarItemInstance->getIndex();
181 if ($index < 0 || $index > 100) {
182 throw new \RuntimeException(
183 'getIndex() must return an integer between 0 and 100',
184 1415968498
185 );
186 }
187 // Find next free position in array
188 while(array_key_exists($index, $toolbarItemInstances)) {
189 $index++;
190 }
191 $toolbarItemInstances[$index] = $toolbarItemInstance;
192 }
193 ksort($toolbarItemInstances);
194 $this->toolbarItems = $toolbarItemInstances;
195 }
196
197 /**
198 * Main function generating the BE scaffolding
199 *
200 * @return void
201 */
202 public function render() {
203 $this->executeHook('renderPreProcess');
204
205 // Prepare the scaffolding, at this point extension may still add javascript and css
206 $view = $this->getFluidTemplateObject($this->templatePath . 'Backend/Main.html');
207 // @todo: kick logo view class and move all logic to Fluid
208 $view->assign('logo', GeneralUtility::makeInstance(\TYPO3\CMS\Backend\View\LogoView::class)->render());
209 $view->assign('moduleMenu', $this->generateModuleMenu());
210 $view->assign('toolbar', $this->renderToolbar());
211
212 /******************************************************
213 * Now put the complete backend document together
214 ******************************************************/
215 foreach ($this->cssFiles as $cssFileName => $cssFile) {
216 $this->pageRenderer->addCssFile($cssFile);
217 // Load additional css files to overwrite existing core styles
218 if (!empty($GLOBALS['TBE_STYLES']['stylesheets'][$cssFileName])) {
219 $this->pageRenderer->addCssFile($GLOBALS['TBE_STYLES']['stylesheets'][$cssFileName]);
220 }
221 }
222 if (!empty($this->css)) {
223 $this->pageRenderer->addCssInlineBlock('BackendInlineCSS', $this->css);
224 }
225 foreach ($this->jsFiles as $jsFile) {
226 $this->pageRenderer->addJsFile($jsFile);
227 }
228 $this->generateJavascript();
229 $this->pageRenderer->addJsInlineCode('BackendInlineJavascript', $this->js, FALSE);
230 $this->loadResourcesForRegisteredNavigationComponents();
231
232 // Add state provider
233 $GLOBALS['TBE_TEMPLATE']->setExtDirectStateProvider();
234 $states = $GLOBALS['BE_USER']->uc['BackendComponents']['States'];
235 // Save states in BE_USER->uc
236 $extOnReadyCode = '
237 Ext.state.Manager.setProvider(new TYPO3.state.ExtDirectProvider({
238 key: "BackendComponents.States",
239 autoRead: false
240 }));
241 ';
242
243 if ($states) {
244 $extOnReadyCode .= 'Ext.state.Manager.getProvider().initState(' . json_encode($states) . ');';
245 }
246
247 $extOnReadyCode .= '
248 TYPO3.Backend = new TYPO3.Viewport(TYPO3.Viewport.configuration);
249 if (typeof console === "undefined") {
250 console = TYPO3.Backend.DebugConsole;
251 }
252 TYPO3.ContextHelpWindow.init(' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('help_cshmanual')) . ');';
253 $this->pageRenderer->addExtOnReadyCode($extOnReadyCode);
254 // Set document title:
255 $title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] ? $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] . ' [TYPO3 CMS ' . TYPO3_version . ']' : 'TYPO3 CMS ' . TYPO3_version;
256 // Renders the module page
257 $this->content = $GLOBALS['TBE_TEMPLATE']->render($title, $view->render());
258 $hookConfiguration = array('content' => &$this->content);
259 $this->executeHook('renderPostProcess', $hookConfiguration);
260 echo $this->content;
261 }
262
263 /**
264 * Loads the css and javascript files of all registered navigation widgets
265 *
266 * @return void
267 */
268 protected function loadResourcesForRegisteredNavigationComponents() {
269 if (!is_array($GLOBALS['TBE_MODULES']['_navigationComponents'])) {
270 return;
271 }
272 $loadedComponents = array();
273 foreach ($GLOBALS['TBE_MODULES']['_navigationComponents'] as $module => $info) {
274 if (in_array($info['componentId'], $loadedComponents)) {
275 continue;
276 }
277 $loadedComponents[] = $info['componentId'];
278 $component = strtolower(substr($info['componentId'], strrpos($info['componentId'], '-') + 1));
279 $componentDirectory = 'components/' . $component . '/';
280 if ($info['isCoreComponent']) {
281 $absoluteComponentPath = PATH_site . 'typo3/js/extjs/' . $componentDirectory;
282 $relativeComponentPath = '../' . str_replace(PATH_site, '', $absoluteComponentPath);
283 } else {
284 $absoluteComponentPath = ExtensionManagementUtility::extPath($info['extKey']) . $componentDirectory;
285 $relativeComponentPath = ExtensionManagementUtility::extRelPath($info['extKey']) . $componentDirectory;
286 }
287 $cssFiles = GeneralUtility::getFilesInDir($absoluteComponentPath . 'css/', 'css');
288 if (file_exists($absoluteComponentPath . 'css/loadorder.txt')) {
289 // Don't allow inclusion outside directory
290 $loadOrder = str_replace('../', '', GeneralUtility::getUrl($absoluteComponentPath . 'css/loadorder.txt'));
291 $cssFilesOrdered = GeneralUtility::trimExplode(LF, $loadOrder, TRUE);
292 $cssFiles = array_merge($cssFilesOrdered, $cssFiles);
293 }
294 foreach ($cssFiles as $cssFile) {
295 $this->pageRenderer->addCssFile($relativeComponentPath . 'css/' . $cssFile);
296 }
297 $jsFiles = GeneralUtility::getFilesInDir($absoluteComponentPath . 'javascript/', 'js');
298 if (file_exists($absoluteComponentPath . 'javascript/loadorder.txt')) {
299 // Don't allow inclusion outside directory
300 $loadOrder = str_replace('../', '', GeneralUtility::getUrl($absoluteComponentPath . 'javascript/loadorder.txt'));
301 $jsFilesOrdered = GeneralUtility::trimExplode(LF, $loadOrder, TRUE);
302 $jsFiles = array_merge($jsFilesOrdered, $jsFiles);
303 }
304 foreach ($jsFiles as $jsFile) {
305 $this->pageRenderer->addJsFile($relativeComponentPath . 'javascript/' . $jsFile);
306 }
307 $this->pageRenderer->addInlineSetting('RecordHistory', 'moduleUrl', BackendUtility::getModuleUrl('record_history'));
308 $this->pageRenderer->addInlineSetting('NewRecord', 'moduleUrl', BackendUtility::getModuleUrl('db_new'));
309 }
310 }
311
312 /**
313 * Renders the items in the top toolbar
314 *
315 * @return string top toolbar elements as HTML
316 */
317 protected function renderToolbar() {
318 $toolbar = array();
319 foreach ($this->toolbarItems as $toolbarItem) {
320 /** @var \TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface $toolbarItem */
321 if ($toolbarItem->checkAccess()) {
322 $hasDropDown = (bool)$toolbarItem->hasDropDown();
323 $additionalAttributes = (array)$toolbarItem->getAdditionalAttributes();
324
325 $liAttributes = array();
326
327 // Merge class: Add dropdown class if hasDropDown, add classes from additonal attributes
328 $classes = array();
329 if ($hasDropDown) {
330 $classes[] = 'dropdown';
331 }
332 if (isset($additionalAttributes['class'])) {
333 $classes[] = $additionalAttributes['class'];
334 unset($additionalAttributes['class']);
335 }
336 $liAttributes[] = 'class="' . implode(' ', $classes) . '"';
337
338 // Add further attributes
339 foreach($additionalAttributes as $name => $value) {
340 $liAttributes[] = $name . '="' . $value . '"';
341 }
342
343 // Create a unique id from class name
344 $className = get_class($toolbarItem);
345 $className = GeneralUtility::underscoredToLowerCamelCase($className);
346 $className = GeneralUtility::camelCaseToLowerCaseUnderscored($className);
347 $className = str_replace(array('_', '\\'), '-', $className);
348 $liAttributes[] = 'id="' . $className . '"';
349
350 $toolbar[] = '<li ' . implode(' ', $liAttributes) . '>';
351
352 if ($hasDropDown) {
353 $toolbar[] = '<a href="#" class="dropdown-toggle" data-toggle="dropdown">';
354 $toolbar[] = $toolbarItem->getItem();
355 $toolbar[] = '</a>';
356 $toolbar[] = '<div class="dropdown-menu" role="menu">';
357 $toolbar[] = $toolbarItem->getDropDown();
358 $toolbar[] = '</div>';
359 } else {
360 $toolbar[] = $toolbarItem->getItem();
361 }
362 $toolbar[] = '</li>';
363 }
364 }
365 return implode(LF, $toolbar);
366 }
367
368 /**
369 * Returns the file name to the LLL JavaScript, containing the localized labels,
370 * which can be used in JavaScript code.
371 *
372 * @return string File name of the JS file, relative to TYPO3_mainDir
373 */
374 protected function getLocalLangFileName() {
375 $code = $this->generateLocalLang();
376 $filePath = 'typo3temp/locallang-BE-' . sha1($code) . '.js';
377 if (!file_exists((PATH_site . $filePath))) {
378 // writeFileToTypo3tempDir() returns NULL on success (please double-read!)
379 if (GeneralUtility::writeFileToTypo3tempDir(PATH_site . $filePath, $code) !== NULL) {
380 throw new \RuntimeException('LocalLangFile could not be written to ' . $filePath, 1295193026);
381 }
382 }
383 return '../' . $filePath;
384 }
385
386 /**
387 * Reads labels required in JavaScript code from the localization system and returns them as JSON
388 * array in TYPO3.LLL.
389 *
390 * @return string JavaScript code containing the LLL labels in TYPO3.LLL
391 */
392 protected function generateLocalLang() {
393 $coreLabels = array(
394 'waitTitle' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_logging_in'),
395 'refresh_login_failed' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_failed'),
396 'refresh_login_failed_message' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_failed_message'),
397 'refresh_login_title' => sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_title'), htmlspecialchars($GLOBALS['BE_USER']->user['username'])),
398 'login_expired' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.login_expired'),
399 'refresh_login_username' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_username'),
400 'refresh_login_password' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_password'),
401 'refresh_login_emptyPassword' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_emptyPassword'),
402 'refresh_login_button' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_button'),
403 'refresh_logout_button' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_logout_button'),
404 'please_wait' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.please_wait'),
405 'loadingIndicator' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:loadingIndicator'),
406 'be_locked' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.be_locked'),
407 'refresh_login_countdown_singular' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_countdown_singular'),
408 'refresh_login_countdown' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_countdown'),
409 'login_about_to_expire' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.login_about_to_expire'),
410 'login_about_to_expire_title' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.login_about_to_expire_title'),
411 'refresh_login_refresh_button' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_refresh_button'),
412 'refresh_direct_logout_button' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_direct_logout_button'),
413 'tabs_closeAll' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:tabs.closeAll'),
414 'tabs_closeOther' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:tabs.closeOther'),
415 'tabs_close' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:tabs.close'),
416 'tabs_openInBrowserWindow' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:tabs.openInBrowserWindow'),
417 'csh_tooltip_loading' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:csh_tooltip_loading')
418 );
419 $labels = array(
420 'fileUpload' => array(
421 'windowTitle',
422 'buttonSelectFiles',
423 'buttonCancelAll',
424 'infoComponentMaxFileSize',
425 'infoComponentFileUploadLimit',
426 'infoComponentFileTypeLimit',
427 'infoComponentOverrideFiles',
428 'processRunning',
429 'uploadWait',
430 'uploadStarting',
431 'uploadProgress',
432 'uploadSuccess',
433 'errorQueueLimitExceeded',
434 'errorQueueFileSizeLimit',
435 'errorQueueZeroByteFile',
436 'errorQueueInvalidFiletype',
437 'errorUploadHttp',
438 'errorUploadMissingUrl',
439 'errorUploadIO',
440 'errorUploadSecurityError',
441 'errorUploadLimit',
442 'errorUploadFailed',
443 'errorUploadFileIDNotFound',
444 'errorUploadFileValidation',
445 'errorUploadFileCancelled',
446 'errorUploadStopped',
447 'allErrorMessageTitle',
448 'allErrorMessageText',
449 'allError401',
450 'allError2038'
451 ),
452 'liveSearch' => array(
453 'title',
454 'helpTitle',
455 'emptyText',
456 'loadingText',
457 'listEmptyText',
458 'showAllResults',
459 'helpDescription',
460 'helpDescriptionPages',
461 'helpDescriptionContent'
462 ),
463 'viewPort' => array(
464 'tooltipModuleMenuSplit',
465 'tooltipNavigationContainerSplitDrag',
466 'tooltipDebugPanelSplitDrag'
467 )
468 );
469 $generatedLabels = array();
470 $generatedLabels['core'] = $coreLabels;
471 // First loop over all categories (fileUpload, liveSearch, ..)
472 foreach ($labels as $categoryName => $categoryLabels) {
473 // Then loop over every single label
474 foreach ($categoryLabels as $label) {
475 // LLL identifier must be called $categoryName_$label, e.g. liveSearch_loadingText
476 $generatedLabels[$categoryName][$label] = $GLOBALS['LANG']->getLL($categoryName . '_' . $label);
477 }
478 }
479 return 'TYPO3.LLL = ' . json_encode($generatedLabels) . ';';
480 }
481
482 /**
483 * Generates the JavaScript code for the backend.
484 *
485 * @return void
486 */
487 protected function generateJavascript() {
488
489 // Needed for FormEngine manipulation (date picker)
490 $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'));
491 $this->pageRenderer->addInlineSetting('DateTimePicker', 'DateFormat', $dateFormat);
492 // define the window size of the element browser etc.
493 $popupWindowWidth = 700;
494 $popupWindowHeight = 750;
495 $popupWindowSize = trim($GLOBALS['BE_USER']->getTSConfigVal('options.popupWindowSize'));
496 if (!empty($popupWindowSize)) {
497 list($popupWindowWidth, $popupWindowHeight) = GeneralUtility::intExplode('x', $popupWindowSize);
498 }
499
500 // define the window size of the popups within the RTE
501 $rtePopupWindowSize = trim($GLOBALS['BE_USER']->getTSConfigVal('options.rte.popupWindowSize'));
502 if (!empty($rtePopupWindowSize)) {
503 list($rtePopupWindowWidth, $rtePopupWindowHeight) = GeneralUtility::trimExplode('x', $rtePopupWindowSize);
504 }
505 $rtePopupWindowWidth = !empty($rtePopupWindowWidth) ? (int)$rtePopupWindowWidth : ($popupWindowWidth-200);
506 $rtePopupWindowHeight = !empty($rtePopupWindowHeight) ? (int)$rtePopupWindowHeight : ($popupWindowHeight-250);
507
508 $pathTYPO3 = GeneralUtility::dirname(GeneralUtility::getIndpEnv('SCRIPT_NAME')) . '/';
509 // If another page module was specified, replace the default Page module with the new one
510 $newPageModule = trim($GLOBALS['BE_USER']->getTSConfigVal('options.overridePageModule'));
511 $pageModule = BackendUtility::isModuleSetInTBE_MODULES($newPageModule) ? $newPageModule : 'web_layout';
512 if (!$GLOBALS['BE_USER']->check('modules', $pageModule)) {
513 $pageModule = '';
514 }
515 // Determine security level from conf vars and default to super challenged
516 if ($GLOBALS['TYPO3_CONF_VARS']['BE']['loginSecurityLevel']) {
517 $this->loginSecurityLevel = $GLOBALS['TYPO3_CONF_VARS']['BE']['loginSecurityLevel'];
518 } else {
519 $this->loginSecurityLevel = 'superchallenged';
520 }
521 $t3Configuration = array(
522 'siteUrl' => GeneralUtility::getIndpEnv('TYPO3_SITE_URL'),
523 'PATH_typo3' => $pathTYPO3,
524 'PATH_typo3_enc' => rawurlencode($pathTYPO3),
525 'username' => htmlspecialchars($GLOBALS['BE_USER']->user['username']),
526 'uniqueID' => GeneralUtility::shortMD5(uniqid('', TRUE)),
527 'securityLevel' => $this->loginSecurityLevel,
528 'TYPO3_mainDir' => TYPO3_mainDir,
529 'pageModule' => $pageModule,
530 'inWorkspace' => $GLOBALS['BE_USER']->workspace !== 0,
531 'workspaceFrontendPreviewEnabled' => $GLOBALS['BE_USER']->user['workspace_preview'] ? 1 : 0,
532 'veriCode' => $GLOBALS['BE_USER']->veriCode(),
533 'denyFileTypes' => PHP_EXTENSIONS_DEFAULT,
534 'moduleMenuWidth' => $this->menuWidth - 1,
535 'topBarHeight' => isset($GLOBALS['TBE_STYLES']['dims']['topFrameH']) ? (int)$GLOBALS['TBE_STYLES']['dims']['topFrameH'] : 30,
536 'showRefreshLoginPopup' => isset($GLOBALS['TYPO3_CONF_VARS']['BE']['showRefreshLoginPopup']) ? (int)$GLOBALS['TYPO3_CONF_VARS']['BE']['showRefreshLoginPopup'] : FALSE,
537 'listModulePath' => ExtensionManagementUtility::extRelPath('recordlist') . 'mod1/',
538 'debugInWindow' => $GLOBALS['BE_USER']->uc['debugInWindow'] ? 1 : 0,
539 'ContextHelpWindows' => array(
540 'width' => 600,
541 'height' => 400
542 ),
543 'PopupWindow' => array(
544 'width' => $popupWindowWidth,
545 'height' => $popupWindowHeight
546 ),
547 'RTEPopupWindow' => array(
548 'width' => $rtePopupWindowWidth,
549 'height' => $rtePopupWindowHeight
550 )
551 );
552 $this->js .= '
553 TYPO3.configuration = ' . json_encode($t3Configuration) . ';
554
555 /**
556 * TypoSetup object.
557 */
558 function typoSetup() { //
559 this.PATH_typo3 = TYPO3.configuration.PATH_typo3;
560 this.PATH_typo3_enc = TYPO3.configuration.PATH_typo3_enc;
561 this.username = TYPO3.configuration.username;
562 this.uniqueID = TYPO3.configuration.uniqueID;
563 this.navFrameWidth = 0;
564 this.securityLevel = TYPO3.configuration.securityLevel;
565 this.veriCode = TYPO3.configuration.veriCode;
566 this.denyFileTypes = TYPO3.configuration.denyFileTypes;
567 }
568 var TS = new typoSetup();
569 //backwards compatibility
570 /**
571 * Frameset Module object
572 *
573 * Used in main modules with a frameset for submodules to keep the ID between modules
574 * Typically that is set by something like this in a Web>* sub module:
575 * if (top.fsMod) top.fsMod.recentIds["web"] = "\'.(int)$this->id.\'";
576 * if (top.fsMod) top.fsMod.recentIds["file"] = "...(file reference/string)...";
577 */
578 function fsModules() { //
579 this.recentIds=new Array(); // used by frameset modules to track the most recent used id for list frame.
580 this.navFrameHighlightedID=new Array(); // used by navigation frames to track which row id was highlighted last time
581 this.currentMainLoaded="";
582 this.currentBank="0";
583 }
584 var fsMod = new fsModules();
585
586 top.goToModule = function(modName, cMR_flag, addGetVars) {
587 TYPO3.ModuleMenu.App.showModule(modName, addGetVars);
588 }
589 ' . $this->setStartupModule();
590 // Check editing of page:
591 $this->handlePageEditing();
592 }
593
594 /**
595 * Checking if the "&edit" variable was sent so we can open it for editing the page.
596 *
597 * @return void
598 */
599 protected function handlePageEditing() {
600 // EDIT page:
601 $editId = preg_replace('/[^[:alnum:]_]/', '', GeneralUtility::_GET('edit'));
602 $editRecord = '';
603 if ($editId) {
604 // Looking up the page to edit, checking permissions:
605 $where = ' AND (' . $GLOBALS['BE_USER']->getPagePermsClause(2) . ' OR ' . $GLOBALS['BE_USER']->getPagePermsClause(16) . ')';
606 if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($editId)) {
607 $editRecord = BackendUtility::getRecordWSOL('pages', $editId, '*', $where);
608 } else {
609 $records = BackendUtility::getRecordsByField('pages', 'alias', $editId, $where);
610 if (is_array($records)) {
611 $editRecord = reset($records);
612 BackendUtility::workspaceOL('pages', $editRecord);
613 }
614 }
615 // If the page was accessible, then let the user edit it.
616 if (is_array($editRecord) && $GLOBALS['BE_USER']->isInWebMount($editRecord['uid'])) {
617 // Setting JS code to open editing:
618 $this->js .= '
619 // Load page to edit:
620 window.setTimeout("top.loadEditId(' . (int)$editRecord['uid'] . ');", 500);
621 ';
622 // Checking page edit parameter:
623 if (!$GLOBALS['BE_USER']->getTSConfigVal('options.bookmark_onEditId_dontSetPageTree')) {
624 $bookmarkKeepExpanded = $GLOBALS['BE_USER']->getTSConfigVal('options.bookmark_onEditId_keepExistingExpanded');
625 // Expanding page tree:
626 BackendUtility::openPageTree((int)$editRecord['pid'], !$bookmarkKeepExpanded);
627 }
628 } else {
629 $this->js .= '
630 // Warning about page editing:
631 alert(' . GeneralUtility::quoteJSvalue(sprintf($GLOBALS['LANG']->getLL('noEditPage'), $editId)) . ');
632 ';
633 }
634 }
635 }
636
637 /**
638 * Sets the startup module from either GETvars module and modParams or user configuration.
639 *
640 * @return string the JavaScript code for the startup module
641 */
642 protected function setStartupModule() {
643 $startModule = preg_replace('/[^[:alnum:]_]/', '', GeneralUtility::_GET('module'));
644 if (!$startModule) {
645 // start module on first login, will be removed once used the first time
646 if (isset($GLOBALS['BE_USER']->uc['startModuleOnFirstLogin'])) {
647 $startModule = $GLOBALS['BE_USER']->uc['startModuleOnFirstLogin'];
648 unset($GLOBALS['BE_USER']->uc['startModuleOnFirstLogin']);
649 $GLOBALS['BE_USER']->writeUC();
650 } elseif ($GLOBALS['BE_USER']->uc['startModule']) {
651 $startModule = $GLOBALS['BE_USER']->uc['startModule'];
652 } elseif ($GLOBALS['BE_USER']->uc['startInTaskCenter']) {
653 $startModule = 'user_task';
654 }
655
656 // check if the start module has additional parameters, so a redirect to a specific
657 // action is possible
658 if (strpos($startModule, '->') !== FALSE) {
659 list($startModule, $startModuleParameters) = explode('->', $startModule, 2);
660 }
661 }
662
663 $moduleParameters = GeneralUtility::_GET('modParams');
664 // if no GET parameters are set, check if there are parameters given from the UC
665 if (!$moduleParameters && $startModuleParameters) {
666 $moduleParameters = $startModuleParameters;
667 }
668
669 if ($startModule) {
670 return '
671 // start in module:
672 top.startInModule = [\'' . $startModule . '\', ' . GeneralUtility::quoteJSvalue($moduleParameters) . '];
673 ';
674 } else {
675 return '';
676 }
677 }
678
679 /**
680 * Adds a javascript snippet to the backend
681 *
682 * @param string $javascript Javascript snippet
683 * @return void
684 * @throws \InvalidArgumentException
685 */
686 public function addJavascript($javascript) {
687 // @todo do we need more checks?
688 if (!is_string($javascript)) {
689 throw new \InvalidArgumentException('parameter $javascript must be of type string', 1195129553);
690 }
691 $this->js .= $javascript;
692 }
693
694 /**
695 * Adds a javscript file to the backend after it has been checked that it exists
696 *
697 * @param string $javascriptFile Javascript file reference
698 * @return bool TRUE if the javascript file was successfully added, FALSE otherwise
699 */
700 public function addJavascriptFile($javascriptFile) {
701 $jsFileAdded = FALSE;
702 // @todo add more checks if necessary
703 if (file_exists(GeneralUtility::resolveBackPath(PATH_typo3 . $javascriptFile))) {
704 $this->jsFiles[] = $javascriptFile;
705 $jsFileAdded = TRUE;
706 }
707 return $jsFileAdded;
708 }
709
710 /**
711 * Adds a css snippet to the backend
712 *
713 * @param string $css Css snippet
714 * @return void
715 */
716 public function addCss($css) {
717 if (!is_string($css)) {
718 throw new \InvalidArgumentException('parameter $css must be of type string', 1195129642);
719 }
720 $this->css .= $css;
721 }
722
723 /**
724 * Adds a css file to the backend after it has been checked that it exists
725 *
726 * @param string $cssFileName The css file's name with out the .css ending
727 * @param string $cssFile Css file reference
728 * @return bool TRUE if the css file was added, FALSE otherwise
729 */
730 public function addCssFile($cssFileName, $cssFile) {
731 $cssFileAdded = FALSE;
732 if (empty($this->cssFiles[$cssFileName])) {
733 $this->cssFiles[$cssFileName] = $cssFile;
734 $cssFileAdded = TRUE;
735 }
736 return $cssFileAdded;
737 }
738
739 /**
740 * Adds an item to the toolbar, the class file for the toolbar item must be loaded at this point
741 *
742 * @param string $toolbarItemName Toolbar item name, f.e. tx_toolbarExtension_coolItem
743 * @param string $toolbarItemClassName Toolbar item class name, f.e. tx_toolbarExtension_coolItem
744 * @return void
745 * @throws \UnexpectedValueException
746 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Toolbar items are registered in $GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'] now.
747 */
748 public function addToolbarItem($toolbarItemName, $toolbarItemClassName) {
749 GeneralUtility::logDeprecatedFunction();
750 }
751
752 /**
753 * Executes defined hooks functions for the given identifier.
754 *
755 * These hook identifiers are valid:
756 * + constructPostProcess
757 * + renderPreProcess
758 * + renderPostProcess
759 *
760 * @param string $identifier Specific hook identifier
761 * @param array $hookConfiguration Additional configuration passed to hook functions
762 * @return void
763 */
764 protected function executeHook($identifier, array $hookConfiguration = array()) {
765 $options = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/backend.php'];
766 if (isset($options[$identifier]) && is_array($options[$identifier])) {
767 foreach ($options[$identifier] as $hookFunction) {
768 GeneralUtility::callUserFunction($hookFunction, $hookConfiguration, $this);
769 }
770 }
771 }
772
773 /**
774 * loads all modules from the repository
775 * and renders it with a template
776 *
777 * @return string
778 */
779 protected function generateModuleMenu() {
780 // get all modules except the user modules for the side menu
781 $moduleStorage = $this->backendModuleRepository->loadAllowedModules(array('user', 'help'));
782
783 $view = $this->getFluidTemplateObject($this->templatePath . 'ModuleMenu/Main.html');
784 $view->assign('modules', $moduleStorage);
785 return $view->render();
786 }
787
788 /**
789 * Returns the Module menu for the AJAX API
790 *
791 * @param array $params
792 * @param \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxRequestHandler
793 * @return void
794 */
795 public function getModuleMenuForReload($params, $ajaxRequestHandler) {
796 $content = $this->generateModuleMenu();
797 $ajaxRequestHandler->addContent('menu', $content);
798 $ajaxRequestHandler->setContentFormat('json');
799 }
800
801 /**
802 * returns a new standalone view, shorthand function
803 *
804 * @param string $templatePathAndFileName optional the path to set the template path and filename
805 * @return \TYPO3\CMS\Fluid\View\StandaloneView
806 */
807 protected function getFluidTemplateObject($templatePathAndFileName = NULL) {
808 $view = GeneralUtility::makeInstance(\TYPO3\CMS\Fluid\View\StandaloneView::class);
809 if ($templatePathAndFileName) {
810 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templatePathAndFileName));
811 }
812 return $view;
813 }
814
815 }