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