[FEATURE] Configurable width of the Element Browser Popups
[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 'debugPanel' => 'js/extjs/debugPanel.js',
125 'viewport' => 'js/extjs/viewport.js',
126 'iframepanel' => 'sysext/backend/Resources/Public/JavaScript/iframepanel.js',
127 'backendcontentiframe' => 'js/extjs/backendcontentiframe.js',
128 'viewportConfiguration' => 'js/extjs/viewportConfiguration.js',
129 'util' => 'sysext/backend/Resources/Public/JavaScript/util.js'
130 );
131 if (!$this->debug) {
132 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LoginRefresh');
133 }
134 // Add default BE css
135 $this->pageRenderer->addCssLibrary('contrib/normalize/normalize.css', 'stylesheet', 'all', '', TRUE, TRUE);
136
137 // load FlashMessages functionality
138 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/FlashMessages');
139 $this->css = '';
140 $this->initializeToolbarItems();
141 $this->menuWidth = isset($GLOBALS['TBE_STYLES']['dims']['leftMenuFrameW']) ? (int)$GLOBALS['TBE_STYLES']['dims']['leftMenuFrameW'] : $this->menuWidthDefault;
142 $this->executeHook('constructPostProcess');
143 }
144
145 /**
146 * Initialize toolbar item objects
147 *
148 * @throws \RuntimeException
149 * @return void
150 */
151 protected function initializeToolbarItems() {
152 $toolbarItemInstances = array();
153 $classNameRegistry = $GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'];
154 foreach ($classNameRegistry as $className) {
155 $toolbarItemInstance = GeneralUtility::makeInstance($className);
156 if (!$toolbarItemInstance instanceof \TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface) {
157 throw new \RuntimeException(
158 'class ' . $className . ' is registered as toolbar item but does not implement'
159 . \TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface::class,
160 1415958218
161 );
162 }
163 $index = (int)$toolbarItemInstance->getIndex();
164 if ($index < 0 || $index > 100) {
165 throw new \RuntimeException(
166 'getIndex() must return an integer between 0 and 100',
167 1415968498
168 );
169 }
170 // Find next free position in array
171 while(array_key_exists($index, $toolbarItemInstances)) {
172 $index++;
173 }
174 $toolbarItemInstances[$index] = $toolbarItemInstance;
175 }
176 ksort($toolbarItemInstances);
177 $this->toolbarItems = $toolbarItemInstances;
178 }
179
180 /**
181 * Main function generating the BE scaffolding
182 *
183 * @return void
184 */
185 public function render() {
186 $this->executeHook('renderPreProcess');
187
188 // Prepare the scaffolding, at this point extension may still add javascript and css
189 $view = $this->getFluidTemplateObject('EXT:backend/Resources/Private/Templates/Backend/Main.html');
190 // @todo: kick logo view class and move all logic to Fluid
191 $view->assign('logo', GeneralUtility::makeInstance(\TYPO3\CMS\Backend\View\LogoView::class)->render());
192 $view->assign('moduleMenu', $this->generateModuleMenu());
193 $view->assign('toolbar', $this->renderToolbar());
194
195 /******************************************************
196 * Now put the complete backend document together
197 ******************************************************/
198 foreach ($this->cssFiles as $cssFileName => $cssFile) {
199 $this->pageRenderer->addCssFile($cssFile);
200 // Load additional css files to overwrite existing core styles
201 if (!empty($GLOBALS['TBE_STYLES']['stylesheets'][$cssFileName])) {
202 $this->pageRenderer->addCssFile($GLOBALS['TBE_STYLES']['stylesheets'][$cssFileName]);
203 }
204 }
205 if (!empty($this->css)) {
206 $this->pageRenderer->addCssInlineBlock('BackendInlineCSS', $this->css);
207 }
208 foreach ($this->jsFiles as $jsFile) {
209 $this->pageRenderer->addJsFile($jsFile);
210 }
211 $this->generateJavascript();
212 $this->pageRenderer->addJsInlineCode('BackendInlineJavascript', $this->js, FALSE);
213 $this->loadResourcesForRegisteredNavigationComponents();
214
215 // Add state provider
216 $GLOBALS['TBE_TEMPLATE']->setExtDirectStateProvider();
217 $states = $GLOBALS['BE_USER']->uc['BackendComponents']['States'];
218 // Save states in BE_USER->uc
219 $extOnReadyCode = '
220 Ext.state.Manager.setProvider(new TYPO3.state.ExtDirectProvider({
221 key: "BackendComponents.States",
222 autoRead: false
223 }));
224 ';
225
226 if ($states) {
227 $extOnReadyCode .= 'Ext.state.Manager.getProvider().initState(' . json_encode($states) . ');';
228 }
229
230 $extOnReadyCode .= '
231 TYPO3.Backend = new TYPO3.Viewport(TYPO3.Viewport.configuration);
232 if (typeof console === "undefined") {
233 console = TYPO3.Backend.DebugConsole;
234 }
235 TYPO3.ContextHelpWindow.init(' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('help_cshmanual')) . ');';
236 $this->pageRenderer->addExtOnReadyCode($extOnReadyCode);
237 // Set document title:
238 $title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] ? $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] . ' [TYPO3 CMS ' . TYPO3_version . ']' : 'TYPO3 CMS ' . TYPO3_version;
239 // Renders the module page
240 $this->content = $GLOBALS['TBE_TEMPLATE']->render($title, $view->render());
241 $hookConfiguration = array('content' => &$this->content);
242 $this->executeHook('renderPostProcess', $hookConfiguration);
243 echo $this->content;
244 }
245
246 /**
247 * Loads the css and javascript files of all registered navigation widgets
248 *
249 * @return void
250 */
251 protected function loadResourcesForRegisteredNavigationComponents() {
252 if (!is_array($GLOBALS['TBE_MODULES']['_navigationComponents'])) {
253 return;
254 }
255 $loadedComponents = array();
256 foreach ($GLOBALS['TBE_MODULES']['_navigationComponents'] as $module => $info) {
257 if (in_array($info['componentId'], $loadedComponents)) {
258 continue;
259 }
260 $loadedComponents[] = $info['componentId'];
261 $component = strtolower(substr($info['componentId'], strrpos($info['componentId'], '-') + 1));
262 $componentDirectory = 'components/' . $component . '/';
263 if ($info['isCoreComponent']) {
264 $absoluteComponentPath = PATH_site . 'typo3/js/extjs/' . $componentDirectory;
265 $relativeComponentPath = '../' . str_replace(PATH_site, '', $absoluteComponentPath);
266 } else {
267 $absoluteComponentPath = ExtensionManagementUtility::extPath($info['extKey']) . $componentDirectory;
268 $relativeComponentPath = ExtensionManagementUtility::extRelPath($info['extKey']) . $componentDirectory;
269 }
270 $cssFiles = GeneralUtility::getFilesInDir($absoluteComponentPath . 'css/', 'css');
271 if (file_exists($absoluteComponentPath . 'css/loadorder.txt')) {
272 // Don't allow inclusion outside directory
273 $loadOrder = str_replace('../', '', GeneralUtility::getUrl($absoluteComponentPath . 'css/loadorder.txt'));
274 $cssFilesOrdered = GeneralUtility::trimExplode(LF, $loadOrder, TRUE);
275 $cssFiles = array_merge($cssFilesOrdered, $cssFiles);
276 }
277 foreach ($cssFiles as $cssFile) {
278 $this->pageRenderer->addCssFile($relativeComponentPath . 'css/' . $cssFile);
279 }
280 $jsFiles = GeneralUtility::getFilesInDir($absoluteComponentPath . 'javascript/', 'js');
281 if (file_exists($absoluteComponentPath . 'javascript/loadorder.txt')) {
282 // Don't allow inclusion outside directory
283 $loadOrder = str_replace('../', '', GeneralUtility::getUrl($absoluteComponentPath . 'javascript/loadorder.txt'));
284 $jsFilesOrdered = GeneralUtility::trimExplode(LF, $loadOrder, TRUE);
285 $jsFiles = array_merge($jsFilesOrdered, $jsFiles);
286 }
287 foreach ($jsFiles as $jsFile) {
288 $this->pageRenderer->addJsFile($relativeComponentPath . 'javascript/' . $jsFile);
289 }
290 $this->pageRenderer->addInlineSetting('RecordHistory', 'moduleUrl', BackendUtility::getModuleUrl('record_history'));
291 }
292 }
293
294 /**
295 * Renders the items in the top toolbar
296 *
297 * @return string top toolbar elements as HTML
298 */
299 protected function renderToolbar() {
300 $toolbar = array();
301 foreach ($this->toolbarItems as $toolbarItem) {
302 /** @var \TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface $toolbarItem */
303 if ($toolbarItem->checkAccess()) {
304 $hasDropDown = (bool)$toolbarItem->hasDropDown();
305 $additionalAttributes = (array)$toolbarItem->getAdditionalAttributes();
306
307 $liAttributes = array();
308
309 // Merge class: Add dropdown class if hasDropDown, add classes from additonal attributes
310 $classes = array();
311 if ($hasDropDown) {
312 $classes[] = 'dropdown';
313 }
314 if (isset($additionalAttributes['class'])) {
315 $classes[] = $additionalAttributes['class'];
316 unset($additionalAttributes['class']);
317 }
318 $liAttributes[] = 'class="' . implode(' ', $classes) . '"';
319
320 // Add further attributes
321 foreach($additionalAttributes as $name => $value) {
322 $liAttributes[] = $name . '="' . $value . '"';
323 }
324
325 // Create a unique id from class name
326 $className = get_class($toolbarItem);
327 $className = GeneralUtility::underscoredToLowerCamelCase($className);
328 $className = GeneralUtility::camelCaseToLowerCaseUnderscored($className);
329 $className = str_replace(array('_', '\\'), '-', $className);
330 $liAttributes[] = 'id="' . $className . '"';
331
332 $toolbar[] = '<li ' . implode(' ', $liAttributes) . '>';
333
334 if ($hasDropDown) {
335 $toolbar[] = '<a href="#" class="dropdown-toggle" data-toggle="dropdown">';
336 $toolbar[] = $toolbarItem->getItem();
337 $toolbar[] = '</a>';
338 $toolbar[] = '<div class="dropdown-menu" role="menu">';
339 $toolbar[] = $toolbarItem->getDropDown();
340 $toolbar[] = '</div>';
341 } else {
342 $toolbar[] = $toolbarItem->getItem();
343 }
344 $toolbar[] = '</li>';
345 }
346 }
347 return implode(LF, $toolbar);
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
471 // Needed for tceform manipulation (date picker)
472 $dateFormat = ($GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat'] ? array('MM-DD-YYYY', 'HH:mm MM-DD-YYYY') : array('DD-MM-YYYY', 'HH:mm DD-MM-YYYY'));
473 $this->pageRenderer->addInlineSetting('DateTimePicker', 'DateFormat', $dateFormat);
474 // define the window size of the element browser etc.
475 $popupWindowSize = trim($GLOBALS['BE_USER']->getTSConfigVal('options.popupWindowSize'));
476 if (!empty($popupWindowSize)) {
477 list($popupWindowWidth, $popupWindowHeight) = GeneralUtility::trimExplode('x', $popupWindowSize);
478 }
479 $popupWindowWidth = !empty($popupWindowWidth) ? (int)$popupWindowWidth : 700;
480 $popupWindowHeight = !empty($popupWindowHeight) ? (int)$popupWindowHeight : 750;
481
482 // define the window size of the popups within the RTE
483 $rtePopupWindowSize = trim($GLOBALS['BE_USER']->getTSConfigVal('options.rte.popupWindowSize'));
484 if (!empty($rtePopupWindowSize)) {
485 list($rtePopupWindowWidth, $rtePopupWindowHeight) = GeneralUtility::trimExplode('x', $rtePopupWindowSize);
486 }
487 $rtePopupWindowWidth = !empty($rtePopupWindowWidth) ? (int)$rtePopupWindowWidth : ($popupWindowWidth-200);
488 $rtePopupWindowHeight = !empty($rtePopupWindowHeight) ? (int)$rtePopupWindowHeight : ($popupWindowHeight-250);
489
490 $pathTYPO3 = GeneralUtility::dirname(GeneralUtility::getIndpEnv('SCRIPT_NAME')) . '/';
491 // If another page module was specified, replace the default Page module with the new one
492 $newPageModule = trim($GLOBALS['BE_USER']->getTSConfigVal('options.overridePageModule'));
493 $pageModule = BackendUtility::isModuleSetInTBE_MODULES($newPageModule) ? $newPageModule : 'web_layout';
494 if (!$GLOBALS['BE_USER']->check('modules', $pageModule)) {
495 $pageModule = '';
496 }
497 // Determine security level from conf vars and default to super challenged
498 if ($GLOBALS['TYPO3_CONF_VARS']['BE']['loginSecurityLevel']) {
499 $this->loginSecurityLevel = $GLOBALS['TYPO3_CONF_VARS']['BE']['loginSecurityLevel'];
500 } else {
501 $this->loginSecurityLevel = 'superchallenged';
502 }
503 $t3Configuration = array(
504 'siteUrl' => GeneralUtility::getIndpEnv('TYPO3_SITE_URL'),
505 'PATH_typo3' => $pathTYPO3,
506 'PATH_typo3_enc' => rawurlencode($pathTYPO3),
507 'username' => htmlspecialchars($GLOBALS['BE_USER']->user['username']),
508 'uniqueID' => GeneralUtility::shortMD5(uniqid('', TRUE)),
509 'securityLevel' => $this->loginSecurityLevel,
510 'TYPO3_mainDir' => TYPO3_mainDir,
511 'pageModule' => $pageModule,
512 'inWorkspace' => $GLOBALS['BE_USER']->workspace !== 0,
513 'workspaceFrontendPreviewEnabled' => $GLOBALS['BE_USER']->user['workspace_preview'] ? 1 : 0,
514 'veriCode' => $GLOBALS['BE_USER']->veriCode(),
515 'denyFileTypes' => PHP_EXTENSIONS_DEFAULT,
516 'moduleMenuWidth' => $this->menuWidth - 1,
517 'topBarHeight' => isset($GLOBALS['TBE_STYLES']['dims']['topFrameH']) ? (int)$GLOBALS['TBE_STYLES']['dims']['topFrameH'] : 30,
518 'showRefreshLoginPopup' => isset($GLOBALS['TYPO3_CONF_VARS']['BE']['showRefreshLoginPopup']) ? (int)$GLOBALS['TYPO3_CONF_VARS']['BE']['showRefreshLoginPopup'] : FALSE,
519 'listModulePath' => ExtensionManagementUtility::extRelPath('recordlist') . 'mod1/',
520 'debugInWindow' => $GLOBALS['BE_USER']->uc['debugInWindow'] ? 1 : 0,
521 'ContextHelpWindows' => array(
522 'width' => 600,
523 'height' => 400
524 ),
525 'PopupWindow' => array(
526 'width' => $popupWindowWidth,
527 'height' => $popupWindowHeight
528 ),
529 'RTEPopupWindow' => array(
530 'width' => $rtePopupWindowWidth,
531 'height' => $rtePopupWindowHeight
532 )
533 );
534 $this->js .= '
535 TYPO3.configuration = ' . json_encode($t3Configuration) . ';
536
537 /**
538 * TypoSetup object.
539 */
540 function typoSetup() { //
541 this.PATH_typo3 = TYPO3.configuration.PATH_typo3;
542 this.PATH_typo3_enc = TYPO3.configuration.PATH_typo3_enc;
543 this.username = TYPO3.configuration.username;
544 this.uniqueID = TYPO3.configuration.uniqueID;
545 this.navFrameWidth = 0;
546 this.securityLevel = TYPO3.configuration.securityLevel;
547 this.veriCode = TYPO3.configuration.veriCode;
548 this.denyFileTypes = TYPO3.configuration.denyFileTypes;
549 }
550 var TS = new typoSetup();
551 //backwards compatibility
552 /**
553 * Frameset Module object
554 *
555 * Used in main modules with a frameset for submodules to keep the ID between modules
556 * Typically that is set by something like this in a Web>* sub module:
557 * if (top.fsMod) top.fsMod.recentIds["web"] = "\'.(int)$this->id.\'";
558 * if (top.fsMod) top.fsMod.recentIds["file"] = "...(file reference/string)...";
559 */
560 function fsModules() { //
561 this.recentIds=new Array(); // used by frameset modules to track the most recent used id for list frame.
562 this.navFrameHighlightedID=new Array(); // used by navigation frames to track which row id was highlighted last time
563 this.currentMainLoaded="";
564 this.currentBank="0";
565 }
566 var fsMod = new fsModules();
567
568 top.goToModule = function(modName, cMR_flag, addGetVars) {
569 TYPO3.ModuleMenu.App.showModule(modName, addGetVars);
570 }
571 ' . $this->setStartupModule();
572 // Check editing of page:
573 $this->handlePageEditing();
574 }
575
576 /**
577 * Checking if the "&edit" variable was sent so we can open it for editing the page.
578 *
579 * @return void
580 */
581 protected function handlePageEditing() {
582 // EDIT page:
583 $editId = preg_replace('/[^[:alnum:]_]/', '', GeneralUtility::_GET('edit'));
584 $editRecord = '';
585 if ($editId) {
586 // Looking up the page to edit, checking permissions:
587 $where = ' AND (' . $GLOBALS['BE_USER']->getPagePermsClause(2) . ' OR ' . $GLOBALS['BE_USER']->getPagePermsClause(16) . ')';
588 if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($editId)) {
589 $editRecord = BackendUtility::getRecordWSOL('pages', $editId, '*', $where);
590 } else {
591 $records = BackendUtility::getRecordsByField('pages', 'alias', $editId, $where);
592 if (is_array($records)) {
593 $editRecord = reset($records);
594 BackendUtility::workspaceOL('pages', $editRecord);
595 }
596 }
597 // If the page was accessible, then let the user edit it.
598 if (is_array($editRecord) && $GLOBALS['BE_USER']->isInWebMount($editRecord['uid'])) {
599 // Setting JS code to open editing:
600 $this->js .= '
601 // Load page to edit:
602 window.setTimeout("top.loadEditId(' . (int)$editRecord['uid'] . ');", 500);
603 ';
604 // Checking page edit parameter:
605 if (!$GLOBALS['BE_USER']->getTSConfigVal('options.bookmark_onEditId_dontSetPageTree')) {
606 $bookmarkKeepExpanded = $GLOBALS['BE_USER']->getTSConfigVal('options.bookmark_onEditId_keepExistingExpanded');
607 // Expanding page tree:
608 BackendUtility::openPageTree((int)$editRecord['pid'], !$bookmarkKeepExpanded);
609 }
610 } else {
611 $this->js .= '
612 // Warning about page editing:
613 alert(' . GeneralUtility::quoteJSvalue(sprintf($GLOBALS['LANG']->getLL('noEditPage'), $editId)) . ');
614 ';
615 }
616 }
617 }
618
619 /**
620 * Sets the startup module from either GETvars module and modParams or user configuration.
621 *
622 * @return string the JavaScript code for the startup module
623 */
624 protected function setStartupModule() {
625 $startModule = preg_replace('/[^[:alnum:]_]/', '', GeneralUtility::_GET('module'));
626 if (!$startModule) {
627 // start module on first login, will be removed once used the first time
628 if (isset($GLOBALS['BE_USER']->uc['startModuleOnFirstLogin'])) {
629 $startModule = $GLOBALS['BE_USER']->uc['startModuleOnFirstLogin'];
630 unset($GLOBALS['BE_USER']->uc['startModuleOnFirstLogin']);
631 $GLOBALS['BE_USER']->writeUC();
632 } elseif ($GLOBALS['BE_USER']->uc['startModule']) {
633 $startModule = $GLOBALS['BE_USER']->uc['startModule'];
634 } elseif ($GLOBALS['BE_USER']->uc['startInTaskCenter']) {
635 $startModule = 'user_task';
636 }
637
638 // check if the start module has additional parameters, so a redirect to a specific
639 // action is possible
640 if (strpos($startModule, '->') !== FALSE) {
641 list($startModule, $startModuleParameters) = explode('->', $startModule, 2);
642 }
643 }
644
645 $moduleParameters = GeneralUtility::_GET('modParams');
646 // if no GET parameters are set, check if there are parameters given from the UC
647 if (!$moduleParameters && $startModuleParameters) {
648 $moduleParameters = $startModuleParameters;
649 }
650
651 if ($startModule) {
652 return '
653 // start in module:
654 top.startInModule = [\'' . $startModule . '\', ' . GeneralUtility::quoteJSvalue($moduleParameters) . '];
655 ';
656 } else {
657 return '';
658 }
659 }
660
661 /**
662 * Adds a javascript snippet to the backend
663 *
664 * @param string $javascript Javascript snippet
665 * @return void
666 * @throws \InvalidArgumentException
667 */
668 public function addJavascript($javascript) {
669 // @todo do we need more checks?
670 if (!is_string($javascript)) {
671 throw new \InvalidArgumentException('parameter $javascript must be of type string', 1195129553);
672 }
673 $this->js .= $javascript;
674 }
675
676 /**
677 * Adds a javscript file to the backend after it has been checked that it exists
678 *
679 * @param string $javascriptFile Javascript file reference
680 * @return bool TRUE if the javascript file was successfully added, FALSE otherwise
681 */
682 public function addJavascriptFile($javascriptFile) {
683 $jsFileAdded = FALSE;
684 // @todo add more checks if necessary
685 if (file_exists(GeneralUtility::resolveBackPath(PATH_typo3 . $javascriptFile))) {
686 $this->jsFiles[] = $javascriptFile;
687 $jsFileAdded = TRUE;
688 }
689 return $jsFileAdded;
690 }
691
692 /**
693 * Adds a css snippet to the backend
694 *
695 * @param string $css Css snippet
696 * @return void
697 */
698 public function addCss($css) {
699 if (!is_string($css)) {
700 throw new \InvalidArgumentException('parameter $css must be of type string', 1195129642);
701 }
702 $this->css .= $css;
703 }
704
705 /**
706 * Adds a css file to the backend after it has been checked that it exists
707 *
708 * @param string $cssFileName The css file's name with out the .css ending
709 * @param string $cssFile Css file reference
710 * @return bool TRUE if the css file was added, FALSE otherwise
711 */
712 public function addCssFile($cssFileName, $cssFile) {
713 $cssFileAdded = FALSE;
714 if (empty($this->cssFiles[$cssFileName])) {
715 $this->cssFiles[$cssFileName] = $cssFile;
716 $cssFileAdded = TRUE;
717 }
718 return $cssFileAdded;
719 }
720
721 /**
722 * Adds an item to the toolbar, the class file for the toolbar item must be loaded at this point
723 *
724 * @param string $toolbarItemName Toolbar item name, f.e. tx_toolbarExtension_coolItem
725 * @param string $toolbarItemClassName Toolbar item class name, f.e. tx_toolbarExtension_coolItem
726 * @return void
727 * @throws \UnexpectedValueException
728 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Toolbar items are registered in $GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'] now.
729 */
730 public function addToolbarItem($toolbarItemName, $toolbarItemClassName) {
731 GeneralUtility::logDeprecatedFunction();
732 }
733
734 /**
735 * Executes defined hooks functions for the given identifier.
736 *
737 * These hook identifiers are valid:
738 * + constructPostProcess
739 * + renderPreProcess
740 * + renderPostProcess
741 *
742 * @param string $identifier Specific hook identifier
743 * @param array $hookConfiguration Additional configuration passed to hook functions
744 * @return void
745 */
746 protected function executeHook($identifier, array $hookConfiguration = array()) {
747 $options = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/backend.php'];
748 if (isset($options[$identifier]) && is_array($options[$identifier])) {
749 foreach ($options[$identifier] as $hookFunction) {
750 GeneralUtility::callUserFunction($hookFunction, $hookConfiguration, $this);
751 }
752 }
753 }
754
755 /**
756 * loads all modules from the repository
757 * and renders it with a template
758 *
759 * @return string
760 */
761 protected function generateModuleMenu() {
762 // get all modules except the user modules for the side menu
763 $moduleStorage = $this->backendModuleRepository->loadAllowedModules(array('user', 'help'));
764
765 $view = $this->getFluidTemplateObject('EXT:backend/Resources/Private/Templates/ModuleMenu/Main.html');
766 $view->assign('modules', $moduleStorage);
767 return $view->render();
768 }
769
770 /**
771 * Returns the Module menu for the AJAX API
772 *
773 * @param array $params
774 * @param \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxRequestHandler
775 * @return void
776 */
777 public function getModuleMenuForReload($params, $ajaxRequestHandler) {
778 $content = $this->generateModuleMenu();
779 $ajaxRequestHandler->addContent('menu', $content);
780 $ajaxRequestHandler->setContentFormat('json');
781 }
782
783 /**
784 * returns a new standalone view, shorthand function
785 *
786 * @param string $templatePathAndFileName optional the path to set the template path and filename
787 * @return \TYPO3\CMS\Fluid\View\StandaloneView
788 */
789 protected function getFluidTemplateObject($templatePathAndFileName = NULL) {
790 $view = GeneralUtility::makeInstance(\TYPO3\CMS\Fluid\View\StandaloneView::class);
791 if ($templatePathAndFileName) {
792 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templatePathAndFileName));
793 }
794 return $view;
795 }
796
797 }