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