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