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