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