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