31644ddac65f4061165a751e4735f907c08c96db
[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 version 4.2+
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;
52
53 /**
54 * @var array
55 */
56 protected $toolbarItems = array();
57
58 /**
59 * @var int Intentionally private as nobody should modify defaults
60 */
61 private $menuWidthDefault = 190;
62
63 /**
64 * @var int
65 */
66 protected $menuWidth;
67
68 /**
69 * @var bool
70 */
71 protected $debug;
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->js = '';
115 $this->jsFiles = array(
116 'locallang' => $this->getLocalLangFileName(),
117 'modernizr' => 'contrib/modernizr/modernizr.min.js',
118 'md5' => 'sysext/backend/Resources/Public/JavaScript/md5.js',
119 'modulemenu' => 'sysext/backend/Resources/Public/JavaScript/modulemenu.js',
120 'evalfield' => 'sysext/backend/Resources/Public/JavaScript/jsfunc.evalfield.js',
121 'flashmessages' => 'sysext/backend/Resources/Public/JavaScript/flashmessages.js',
122 'tabclosemenu' => 'js/extjs/ux/ext.ux.tabclosemenu.js',
123 'notifications' => 'sysext/backend/Resources/Public/JavaScript/notifications.js',
124 'backend' => 'sysext/backend/Resources/Public/JavaScript/backend.js',
125 'loginrefresh' => 'sysext/backend/Resources/Public/JavaScript/loginrefresh.js',
126 'debugPanel' => 'js/extjs/debugPanel.js',
127 'viewport' => 'js/extjs/viewport.js',
128 'iframepanel' => 'sysext/backend/Resources/Public/JavaScript/iframepanel.js',
129 'backendcontentiframe' => 'js/extjs/backendcontentiframe.js',
130 'viewportConfiguration' => 'js/extjs/viewportConfiguration.js',
131 'util' => 'sysext/backend/Resources/Public/JavaScript/util.js'
132 );
133 if ($this->debug) {
134 unset($this->jsFiles['loginrefresh']);
135 }
136 // Add default BE css
137 $this->pageRenderer->addCssLibrary('contrib/normalize/normalize.css', 'stylesheet', 'all', '', TRUE, TRUE);
138
139 // load the toolbar items
140 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Toolbar/UserMenu');
141
142 $this->css = '';
143 $this->initializeToolbarItems();
144 $this->menuWidth = $this->menuWidthDefault;
145 if (isset($GLOBALS['TBE_STYLES']['dims']['leftMenuFrameW']) && (int)$GLOBALS['TBE_STYLES']['dims']['leftMenuFrameW'] != (int)$this->menuWidth) {
146 $this->menuWidth = (int)$GLOBALS['TBE_STYLES']['dims']['leftMenuFrameW'];
147 }
148 $this->executeHook('constructPostProcess');
149 }
150
151 /**
152 * Initialize toolbar item objects
153 *
154 * @throws \RuntimeException
155 * @return void
156 */
157 protected function initializeToolbarItems() {
158 $toolbarItemInstances = array();
159 $classNameRegistry = $GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'];
160 foreach ($classNameRegistry as $className) {
161 $toolbarItemInstance = GeneralUtility::makeInstance($className);
162 if (!$toolbarItemInstance instanceof \TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface) {
163 throw new \RuntimeException(
164 'class ' . $className . ' is registered as toolbar item but does not implement'
165 . '\TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface',
166 1415958218
167 );
168 }
169 $index = (int)$toolbarItemInstance->getIndex();
170 if ($index < 0 || $index > 100) {
171 throw new \RuntimeException(
172 'getIndex() must return an integer between 0 and 100',
173 1415968498
174 );
175 }
176 // Find next free position in array
177 while(array_key_exists($index, $toolbarItemInstances)) {
178 $index++;
179 }
180 $toolbarItemInstances[$index] = $toolbarItemInstance;
181 }
182 ksort($toolbarItemInstances);
183 $this->toolbarItems = $toolbarItemInstances;
184 }
185
186 /**
187 * Main function generating the BE scaffolding
188 *
189 * @return void
190 */
191 public function render() {
192 $this->executeHook('renderPreProcess');
193
194 // Prepare the scaffolding, at this point extension may still add javascript and css
195 $logo = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\View\LogoView::class);
196
197 // Create backend scaffolding
198 $backendScaffolding = '
199 <div class="navbar navbar-inverse x-hide-display" role="navigation" id="typo3-top-container">
200 <div class="container-fluid">
201 <div class="navbar-header" id="typo3-logo">' .
202 $logo->render() .
203 '</div>
204 <div id="typo3-top">' .
205 $this->renderToolbar() .
206 '</div>
207 </div>
208 </div>' .
209 $this->generateModuleMenu();
210
211 /******************************************************
212 * Now put the complete backend document together
213 ******************************************************/
214 foreach ($this->cssFiles as $cssFileName => $cssFile) {
215 $this->pageRenderer->addCssFile($cssFile);
216 // Load additional css files to overwrite existing core styles
217 if (!empty($GLOBALS['TBE_STYLES']['stylesheets'][$cssFileName])) {
218 $this->pageRenderer->addCssFile($GLOBALS['TBE_STYLES']['stylesheets'][$cssFileName]);
219 }
220 }
221 if (!empty($this->css)) {
222 $this->pageRenderer->addCssInlineBlock('BackendInlineCSS', $this->css);
223 }
224 foreach ($this->jsFiles as $jsFile) {
225 $this->pageRenderer->addJsFile($jsFile);
226 }
227 $this->generateJavascript();
228 $this->pageRenderer->addJsInlineCode('BackendInlineJavascript', $this->js, FALSE);
229 $this->loadResourcesForRegisteredNavigationComponents();
230
231 // Add state provider
232 $GLOBALS['TBE_TEMPLATE']->setExtDirectStateProvider();
233 $states = $GLOBALS['BE_USER']->uc['BackendComponents']['States'];
234 // Save states in BE_USER->uc
235 $extOnReadyCode = '
236 Ext.state.Manager.setProvider(new TYPO3.state.ExtDirectProvider({
237 key: "BackendComponents.States",
238 autoRead: false
239 }));
240 ';
241
242 if ($states) {
243 $extOnReadyCode .= 'Ext.state.Manager.getProvider().initState(' . json_encode($states) . ');';
244 }
245
246 $extOnReadyCode .= '
247 TYPO3.Backend = new TYPO3.Viewport(TYPO3.Viewport.configuration);
248 if (typeof console === "undefined") {
249 console = TYPO3.Backend.DebugConsole;
250 }
251 TYPO3.ContextHelpWindow.init(' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('help_cshmanual')) . ');';
252 $this->pageRenderer->addExtOnReadyCode($extOnReadyCode);
253 // Set document title:
254 $title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] ? $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] . ' [TYPO3 CMS ' . TYPO3_version . ']' : 'TYPO3 CMS ' . TYPO3_version;
255 $this->content = $backendScaffolding;
256 // Renders the module page
257 $this->content = $GLOBALS['TBE_TEMPLATE']->render($title, $this->content);
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 }
309 }
310
311 /**
312 * Renders the items in the top toolbar
313 *
314 * @return string top toolbar elements as HTML
315 */
316 protected function renderToolbar() {
317 $toolbar = array();
318 $toolbar[] = '<ul class="nav navbar-nav navbar-right typo3-top-toolbar" id="typo3-toolbar">';
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 $toolbar[] = '</ul>';
366
367 return implode(LF, $toolbar);
368 }
369
370 /**
371 * Returns the file name to the LLL JavaScript, containing the localized labels,
372 * which can be used in JavaScript code.
373 *
374 * @return string File name of the JS file, relative to TYPO3_mainDir
375 */
376 protected function getLocalLangFileName() {
377 $code = $this->generateLocalLang();
378 $filePath = 'typo3temp/locallang-BE-' . sha1($code) . '.js';
379 if (!file_exists((PATH_site . $filePath))) {
380 // writeFileToTypo3tempDir() returns NULL on success (please double-read!)
381 if (GeneralUtility::writeFileToTypo3tempDir(PATH_site . $filePath, $code) !== NULL) {
382 throw new \RuntimeException('LocalLangFile could not be written to ' . $filePath, 1295193026);
383 }
384 }
385 return '../' . $filePath;
386 }
387
388 /**
389 * Reads labels required in JavaScript code from the localization system and returns them as JSON
390 * array in TYPO3.LLL.
391 *
392 * @return string JavaScript code containing the LLL labels in TYPO3.LLL
393 */
394 protected function generateLocalLang() {
395 $coreLabels = array(
396 'waitTitle' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_logging_in'),
397 'refresh_login_failed' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_failed'),
398 'refresh_login_failed_message' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_failed_message'),
399 'refresh_login_title' => sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_title'), htmlspecialchars($GLOBALS['BE_USER']->user['username'])),
400 'login_expired' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.login_expired'),
401 'refresh_login_username' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_username'),
402 'refresh_login_password' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_password'),
403 'refresh_login_emptyPassword' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_emptyPassword'),
404 'refresh_login_button' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_button'),
405 'refresh_logout_button' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_logout_button'),
406 'please_wait' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.please_wait'),
407 'loadingIndicator' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:loadingIndicator'),
408 'be_locked' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.be_locked'),
409 'refresh_login_countdown_singular' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_countdown_singular'),
410 'refresh_login_countdown' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_countdown'),
411 'login_about_to_expire' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.login_about_to_expire'),
412 'login_about_to_expire_title' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.login_about_to_expire_title'),
413 'refresh_login_refresh_button' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_refresh_button'),
414 'refresh_direct_logout_button' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_direct_logout_button'),
415 'tabs_closeAll' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:tabs.closeAll'),
416 'tabs_closeOther' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:tabs.closeOther'),
417 'tabs_close' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:tabs.close'),
418 'tabs_openInBrowserWindow' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:tabs.openInBrowserWindow'),
419 'csh_tooltip_loading' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:csh_tooltip_loading')
420 );
421 $labels = array(
422 'fileUpload' => array(
423 'windowTitle',
424 'buttonSelectFiles',
425 'buttonCancelAll',
426 'infoComponentMaxFileSize',
427 'infoComponentFileUploadLimit',
428 'infoComponentFileTypeLimit',
429 'infoComponentOverrideFiles',
430 'processRunning',
431 'uploadWait',
432 'uploadStarting',
433 'uploadProgress',
434 'uploadSuccess',
435 'errorQueueLimitExceeded',
436 'errorQueueFileSizeLimit',
437 'errorQueueZeroByteFile',
438 'errorQueueInvalidFiletype',
439 'errorUploadHttp',
440 'errorUploadMissingUrl',
441 'errorUploadIO',
442 'errorUploadSecurityError',
443 'errorUploadLimit',
444 'errorUploadFailed',
445 'errorUploadFileIDNotFound',
446 'errorUploadFileValidation',
447 'errorUploadFileCancelled',
448 'errorUploadStopped',
449 'allErrorMessageTitle',
450 'allErrorMessageText',
451 'allError401',
452 'allError2038'
453 ),
454 'liveSearch' => array(
455 'title',
456 'helpTitle',
457 'emptyText',
458 'loadingText',
459 'listEmptyText',
460 'showAllResults',
461 'helpDescription',
462 'helpDescriptionPages',
463 'helpDescriptionContent'
464 ),
465 'viewPort' => array(
466 'tooltipModuleMenuSplit',
467 'tooltipNavigationContainerSplitDrag',
468 'tooltipDebugPanelSplitDrag'
469 )
470 );
471 $generatedLabels = array();
472 $generatedLabels['core'] = $coreLabels;
473 // First loop over all categories (fileUpload, liveSearch, ..)
474 foreach ($labels as $categoryName => $categoryLabels) {
475 // Then loop over every single label
476 foreach ($categoryLabels as $label) {
477 // LLL identifier must be called $categoryName_$label, e.g. liveSearch_loadingText
478 $generatedLabels[$categoryName][$label] = $GLOBALS['LANG']->getLL($categoryName . '_' . $label);
479 }
480 }
481 return 'TYPO3.LLL = ' . json_encode($generatedLabels) . ';';
482 }
483
484 /**
485 * Generates the JavaScript code for the backend.
486 *
487 * @return void
488 */
489 protected function generateJavascript() {
490 $pathTYPO3 = GeneralUtility::dirname(GeneralUtility::getIndpEnv('SCRIPT_NAME')) . '/';
491 // If another page module was specified, replace the default Page module with the new one
492 $newPageModule = trim($GLOBALS['BE_USER']->getTSConfigVal('options.overridePageModule'));
493 $pageModule = BackendUtility::isModuleSetInTBE_MODULES($newPageModule) ? $newPageModule : 'web_layout';
494 if (!$GLOBALS['BE_USER']->check('modules', $pageModule)) {
495 $pageModule = '';
496 }
497 $menuFrameName = 'menu';
498 if ($GLOBALS['BE_USER']->uc['noMenuMode'] === 'icons') {
499 $menuFrameName = 'topmenuFrame';
500 }
501 // Determine security level from conf vars and default to super challenged
502 if ($GLOBALS['TYPO3_CONF_VARS']['BE']['loginSecurityLevel']) {
503 $this->loginSecurityLevel = $GLOBALS['TYPO3_CONF_VARS']['BE']['loginSecurityLevel'];
504 } else {
505 $this->loginSecurityLevel = 'superchallenged';
506 }
507 $t3Configuration = array(
508 'siteUrl' => GeneralUtility::getIndpEnv('TYPO3_SITE_URL'),
509 'PATH_typo3' => $pathTYPO3,
510 'PATH_typo3_enc' => rawurlencode($pathTYPO3),
511 'username' => htmlspecialchars($GLOBALS['BE_USER']->user['username']),
512 'uniqueID' => GeneralUtility::shortMD5(uniqid('', TRUE)),
513 'securityLevel' => $this->loginSecurityLevel,
514 'TYPO3_mainDir' => TYPO3_mainDir,
515 'pageModule' => $pageModule,
516 'inWorkspace' => $GLOBALS['BE_USER']->workspace !== 0,
517 'workspaceFrontendPreviewEnabled' => $GLOBALS['BE_USER']->user['workspace_preview'] ? 1 : 0,
518 'veriCode' => $GLOBALS['BE_USER']->veriCode(),
519 'denyFileTypes' => PHP_EXTENSIONS_DEFAULT,
520 'moduleMenuWidth' => $this->menuWidth - 1,
521 'topBarHeight' => isset($GLOBALS['TBE_STYLES']['dims']['topFrameH']) ? (int)$GLOBALS['TBE_STYLES']['dims']['topFrameH'] : 30,
522 'showRefreshLoginPopup' => isset($GLOBALS['TYPO3_CONF_VARS']['BE']['showRefreshLoginPopup']) ? (int)$GLOBALS['TYPO3_CONF_VARS']['BE']['showRefreshLoginPopup'] : FALSE,
523 'listModulePath' => ExtensionManagementUtility::extRelPath('recordlist') . 'mod1/',
524 'debugInWindow' => $GLOBALS['BE_USER']->uc['debugInWindow'] ? 1 : 0,
525 'ContextHelpWindows' => array(
526 'width' => 600,
527 'height' => 400
528 ),
529 );
530 $this->js .= '
531 TYPO3.configuration = ' . json_encode($t3Configuration) . ';
532
533 /**
534 * TypoSetup object.
535 */
536 function typoSetup() { //
537 this.PATH_typo3 = TYPO3.configuration.PATH_typo3;
538 this.PATH_typo3_enc = TYPO3.configuration.PATH_typo3_enc;
539 this.username = TYPO3.configuration.username;
540 this.uniqueID = TYPO3.configuration.uniqueID;
541 this.navFrameWidth = 0;
542 this.securityLevel = TYPO3.configuration.securityLevel;
543 this.veriCode = TYPO3.configuration.veriCode;
544 this.denyFileTypes = TYPO3.configuration.denyFileTypes;
545 }
546 var TS = new typoSetup();
547 //backwards compatibility
548 /**
549 * Frameset Module object
550 *
551 * Used in main modules with a frameset for submodules to keep the ID between modules
552 * Typically that is set by something like this in a Web>* sub module:
553 * if (top.fsMod) top.fsMod.recentIds["web"] = "\'.(int)$this->id.\'";
554 * if (top.fsMod) top.fsMod.recentIds["file"] = "...(file reference/string)...";
555 */
556 function fsModules() { //
557 this.recentIds=new Array(); // used by frameset modules to track the most recent used id for list frame.
558 this.navFrameHighlightedID=new Array(); // used by navigation frames to track which row id was highlighted last time
559 this.currentMainLoaded="";
560 this.currentBank="0";
561 }
562 var fsMod = new fsModules();
563
564 top.goToModule = function(modName, cMR_flag, addGetVars) {
565 TYPO3.ModuleMenu.App.showModule(modName, addGetVars);
566 }
567 ' . $this->setStartupModule();
568 // Check editing of page:
569 $this->handlePageEditing();
570 }
571
572 /**
573 * Checking if the "&edit" variable was sent so we can open it for editing the page.
574 *
575 * @return void
576 */
577 protected function handlePageEditing() {
578 // EDIT page:
579 $editId = preg_replace('/[^[:alnum:]_]/', '', GeneralUtility::_GET('edit'));
580 $editRecord = '';
581 if ($editId) {
582 // Looking up the page to edit, checking permissions:
583 $where = ' AND (' . $GLOBALS['BE_USER']->getPagePermsClause(2) . ' OR ' . $GLOBALS['BE_USER']->getPagePermsClause(16) . ')';
584 if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($editId)) {
585 $editRecord = BackendUtility::getRecordWSOL('pages', $editId, '*', $where);
586 } else {
587 $records = BackendUtility::getRecordsByField('pages', 'alias', $editId, $where);
588 if (is_array($records)) {
589 $editRecord = reset($records);
590 BackendUtility::workspaceOL('pages', $editRecord);
591 }
592 }
593 // If the page was accessible, then let the user edit it.
594 if (is_array($editRecord) && $GLOBALS['BE_USER']->isInWebMount($editRecord['uid'])) {
595 // Setting JS code to open editing:
596 $this->js .= '
597 // Load page to edit:
598 window.setTimeout("top.loadEditId(' . (int)$editRecord['uid'] . ');", 500);
599 ';
600 // Checking page edit parameter:
601 if (!$GLOBALS['BE_USER']->getTSConfigVal('options.bookmark_onEditId_dontSetPageTree')) {
602 $bookmarkKeepExpanded = $GLOBALS['BE_USER']->getTSConfigVal('options.bookmark_onEditId_keepExistingExpanded');
603 // Expanding page tree:
604 BackendUtility::openPageTree((int)$editRecord['pid'], !$bookmarkKeepExpanded);
605 }
606 } else {
607 $this->js .= '
608 // Warning about page editing:
609 alert(' . GeneralUtility::quoteJSvalue(sprintf($GLOBALS['LANG']->getLL('noEditPage'), $editId)) . ');
610 ';
611 }
612 }
613 }
614
615 /**
616 * Sets the startup module from either GETvars module and modParams or user configuration.
617 *
618 * @return string the JavaScript code for the startup module
619 */
620 protected function setStartupModule() {
621 $startModule = preg_replace('/[^[:alnum:]_]/', '', GeneralUtility::_GET('module'));
622 if (!$startModule) {
623 // start module on first login, will be removed once used the first time
624 if (isset($GLOBALS['BE_USER']->uc['startModuleOnFirstLogin'])) {
625 $startModule = $GLOBALS['BE_USER']->uc['startModuleOnFirstLogin'];
626 unset($GLOBALS['BE_USER']->uc['startModuleOnFirstLogin']);
627 $GLOBALS['BE_USER']->writeUC();
628 } elseif ($GLOBALS['BE_USER']->uc['startModule']) {
629 $startModule = $GLOBALS['BE_USER']->uc['startModule'];
630 } elseif ($GLOBALS['BE_USER']->uc['startInTaskCenter']) {
631 $startModule = 'user_task';
632 }
633
634 // check if the start module has additional parameters, so a redirect to a specific
635 // action is possible
636 if (strpos($startModule, '->') !== FALSE) {
637 list($startModule, $startModuleParameters) = explode('->', $startModule, 2);
638 }
639 }
640
641 $moduleParameters = GeneralUtility::_GET('modParams');
642 // if no GET parameters are set, check if there are parameters given from the UC
643 if (!$moduleParameters && $startModuleParameters) {
644 $moduleParameters = $startModuleParameters;
645 }
646
647 if ($startModule) {
648 return '
649 // start in module:
650 top.startInModule = [\'' . $startModule . '\', ' . GeneralUtility::quoteJSvalue($moduleParameters) . '];
651 ';
652 } else {
653 return '';
654 }
655 }
656
657 /**
658 * Adds a javascript snippet to the backend
659 *
660 * @param string $javascript Javascript snippet
661 * @return void
662 * @throws \InvalidArgumentException
663 */
664 public function addJavascript($javascript) {
665 // TODO do we need more checks?
666 if (!is_string($javascript)) {
667 throw new \InvalidArgumentException('parameter $javascript must be of type string', 1195129553);
668 }
669 $this->js .= $javascript;
670 }
671
672 /**
673 * Adds a javscript file to the backend after it has been checked that it exists
674 *
675 * @param string $javascriptFile Javascript file reference
676 * @return bool TRUE if the javascript file was successfully added, FALSE otherwise
677 */
678 public function addJavascriptFile($javascriptFile) {
679 $jsFileAdded = FALSE;
680 //TODO add more checks if necessary
681 if (file_exists(GeneralUtility::resolveBackPath(PATH_typo3 . $javascriptFile))) {
682 $this->jsFiles[] = $javascriptFile;
683 $jsFileAdded = TRUE;
684 }
685 return $jsFileAdded;
686 }
687
688 /**
689 * Adds a css snippet to the backend
690 *
691 * @param string $css Css snippet
692 * @return void
693 */
694 public function addCss($css) {
695 if (!is_string($css)) {
696 throw new \InvalidArgumentException('parameter $css must be of type string', 1195129642);
697 }
698 $this->css .= $css;
699 }
700
701 /**
702 * Adds a css file to the backend after it has been checked that it exists
703 *
704 * @param string $cssFileName The css file's name with out the .css ending
705 * @param string $cssFile Css file reference
706 * @return bool TRUE if the css file was added, FALSE otherwise
707 */
708 public function addCssFile($cssFileName, $cssFile) {
709 $cssFileAdded = FALSE;
710 if (empty($this->cssFiles[$cssFileName])) {
711 $this->cssFiles[$cssFileName] = $cssFile;
712 $cssFileAdded = TRUE;
713 }
714 return $cssFileAdded;
715 }
716
717 /**
718 * Adds an item to the toolbar, the class file for the toolbar item must be loaded at this point
719 *
720 * @param string $toolbarItemName Toolbar item name, f.e. tx_toolbarExtension_coolItem
721 * @param string $toolbarItemClassName Toolbar item class name, f.e. tx_toolbarExtension_coolItem
722 * @return void
723 * @throws \UnexpectedValueException
724 * @deprecated since CMS 7, will be removed with CMS 8. Toolbar items are registered in $GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'] now.
725 */
726 public function addToolbarItem($toolbarItemName, $toolbarItemClassName) {
727 GeneralUtility::logDeprecatedFunction();
728 }
729
730 /**
731 * Executes defined hooks functions for the given identifier.
732 *
733 * These hook identifiers are valid:
734 * + constructPostProcess
735 * + renderPreProcess
736 * + renderPostProcess
737 *
738 * @param string $identifier Specific hook identifier
739 * @param array $hookConfiguration Additional configuration passed to hook functions
740 * @return void
741 */
742 protected function executeHook($identifier, array $hookConfiguration = array()) {
743 $options = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/backend.php'];
744 if (isset($options[$identifier]) && is_array($options[$identifier])) {
745 foreach ($options[$identifier] as $hookFunction) {
746 GeneralUtility::callUserFunction($hookFunction, $hookConfiguration, $this);
747 }
748 }
749 }
750
751 /**
752 * loads all modules from the repository
753 * and renders it with a template
754 *
755 * @return string
756 */
757 protected function generateModuleMenu() {
758 // get all modules except the user modules for the side menu
759 $moduleStorage = $this->backendModuleRepository->loadAllowedModules(array('user', 'help'));
760
761 /** @var $view \TYPO3\CMS\Fluid\View\StandaloneView */
762 $view = GeneralUtility::makeInstance(\TYPO3\CMS\Fluid\View\StandaloneView::class);
763 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates/ModuleMenu/Main.html'));
764 $view->assign('modules', $moduleStorage);
765 return $view->render();
766 }
767
768 /**
769 * Returns the Module menu for the AJAX API
770 *
771 * @param array $params
772 * @param \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxRequestHandler
773 * @return void
774 */
775 public function getModuleMenuForReload($params, $ajaxRequestHandler) {
776 $content = $this->generateModuleMenu();
777 $ajaxRequestHandler->addContent('menu', $content);
778 $ajaxRequestHandler->setContentFormat('json');
779 }
780 }