Feature #10639: Integration of the Mass File Uploader (based on SWFUpload and Ext JS)
[Packages/TYPO3.CMS.git] / typo3 / backend.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2007-2009 Ingo Renner <ingo@typo3.org>
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27
28 require_once('init.php');
29 require_once('template.php');
30 require_once('interfaces/interface.backend_toolbaritem.php');
31
32 require('classes/class.typo3logo.php');
33 require('classes/class.modulemenu.php');
34
35 // core toolbar items
36 require('classes/class.workspaceselector.php');
37 require('classes/class.clearcachemenu.php');
38 require('classes/class.shortcutmenu.php');
39 require('classes/class.backendsearchmenu.php');
40
41 require_once(PATH_t3lib.'class.t3lib_loadmodules.php');
42 require_once(PATH_t3lib.'class.t3lib_basicfilefunc.php');
43 require_once('class.alt_menu_functions.inc');
44 $GLOBALS['LANG']->includeLLFile('EXT:lang/locallang_misc.xml');
45
46
47 /**
48 * Class for rendering the TYPO3 backend version 4.2+
49 *
50 * @author Ingo Renner <ingo@typo3.org>
51 * @package TYPO3
52 * @subpackage core
53 */
54 class TYPO3backend {
55
56 protected $content;
57 protected $css;
58 protected $cssFiles;
59 protected $js;
60 protected $jsFiles;
61 protected $toolbarItems;
62 private $menuWidthDefault = 160; // intentionally private as nobody should modify defaults
63 protected $menuWidth;
64
65 /**
66 * Object for loading backend modules
67 *
68 * @var t3lib_loadModules
69 */
70 protected $moduleLoader;
71
72 /**
73 * module menu generating object
74 *
75 * @var ModuleMenu
76 */
77 protected $moduleMenu;
78
79 /**
80 * constructor
81 *
82 * @return void
83 */
84 public function __construct() {
85
86 // Initializes the backend modules structure for use later.
87 $this->moduleLoader = t3lib_div::makeInstance('t3lib_loadModules');
88 $this->moduleLoader->load($GLOBALS['TBE_MODULES']);
89
90 $this->moduleMenu = t3lib_div::makeInstance('ModuleMenu');
91
92 // add default BE javascript
93 $this->js = '';
94 $this->jsFiles = array(
95 'contrib/prototype/prototype.js',
96 'contrib/scriptaculous/scriptaculous.js?load=builder,effects,controls,dragdrop',
97 'contrib/extjs/adapter/ext/ext-base.js',
98 'contrib/extjs/ext-all.js',
99 'contrib/swfupload/swfupload.js',
100 'contrib/swfupload/plugins/swfupload.swfobject.js',
101 'contrib/swfupload/plugins/swfupload.cookies.js',
102 'contrib/swfupload/plugins/swfupload.queue.js',
103 'md5.js',
104 'js/backend.js',
105 'js/common.js',
106 'js/sizemanager.js',
107 'js/toolbarmanager.js',
108 'js/modulemenu.js',
109 'js/iecompatibility.js',
110 'js/flashupload.js',
111 '../t3lib/jsfunc.evalfield.js'
112 );
113
114 // add default BE css
115 $this->css = '';
116 $this->cssFiles = array(
117 'backend-scaffolding' => 'css/backend-scaffolding.css',
118 'backend-style' => 'css/backend-style.css',
119 'modulemenu' => 'css/modulemenu.css',
120 'extJS' => 'contrib/extjs/resources/css/ext-all.css',
121 'extJS-gray' => 'contrib/extjs/resources/css/xtheme-gray.css'
122 );
123
124 $this->toolbarItems = array();
125 $this->initializeCoreToolbarItems();
126
127 $this->menuWidth = $this->menuWidthDefault;
128 if (isset($GLOBALS['TBE_STYLES']['dims']['leftMenuFrameW']) && (int) $GLOBALS['TBE_STYLES']['dims']['leftMenuFrameW'] != (int) $this->menuWidth) {
129 $this->menuWidth = (int) $GLOBALS['TBE_STYLES']['dims']['leftMenuFrameW'];
130 }
131 }
132
133 /**
134 * initializes the core toolbar items
135 *
136 * @return void
137 */
138 protected function initializeCoreToolbarItems() {
139
140 $coreToolbarItems = array(
141 'workspaceSelector' => 'WorkspaceSelector',
142 'shortcuts' => 'ShortcutMenu',
143 'clearCacheActions' => 'ClearCacheMenu',
144 'backendSearch' => 'BackendSearchMenu'
145 );
146
147 foreach($coreToolbarItems as $toolbarItemName => $toolbarItemClassName) {
148 $toolbarItem = t3lib_div::makeInstance($toolbarItemClassName, $this);
149
150 if(!($toolbarItem instanceof backend_toolbarItem)) {
151 throw new UnexpectedValueException('$toolbarItem "'.$toolbarItemName.'" must implement interface backend_toolbarItem', 1195126772);
152 }
153
154 if($toolbarItem->checkAccess()) {
155 $this->toolbarItems[$toolbarItemName] = $toolbarItem;
156 } else {
157 unset($toolbarItem);
158 }
159 }
160 }
161
162 /**
163 * main function generating the BE scaffolding
164 *
165 * @return void
166 */
167 public function render() {
168
169 // prepare the scaffolding, at this point extension may still add javascript and css
170 $logo = t3lib_div::makeInstance('TYPO3Logo');
171 $logo->setLogo('gfx/typo3logo_mini.png');
172
173 $menu = $this->moduleMenu->render();
174
175 if ($this->menuWidth != $this->menuWidthDefault) {
176 $this->css .= '
177 #typo3-logo,
178 #typo3-side-menu {
179 width: ' . ($this->menuWidth - 1) . 'px;
180 }
181
182 #typo3-top,
183 #typo3-content {
184 margin-left: ' . $this->menuWidth . 'px;
185 }
186 ';
187 }
188
189 // create backend scaffolding
190 $backendScaffolding = '
191 <div id="typo3-backend">
192 <div id="typo3-top-container">
193 <div id="typo3-logo">'.$logo->render().'</div>
194 <div id="typo3-top" class="typo3-top-toolbar">'
195 .$this->renderToolbar()
196 .'</div>
197 </div>
198 <div id="typo3-main-container">
199 <div id="typo3-side-menu">
200 '.$menu.'
201 </div>
202 <div id="typo3-content">
203 <iframe src="alt_intro.php" name="content" id="content" marginwidth="0" marginheight="0" frameborder="0" scrolling="auto"></iframe>
204 </div>
205 </div>
206 </div>
207 ';
208
209 /******************************************************
210 * now put the complete backend document together
211 ******************************************************/
212
213 // remove duplicate entries
214 $this->jsFiles = array_unique($this->jsFiles);
215
216 // add javascript
217 foreach($this->jsFiles as $jsFile) {
218 $GLOBALS['TBE_TEMPLATE']->JScode .= '
219 <script type="text/javascript" src="'.$jsFile.'"></script>';
220 }
221 $GLOBALS['TBE_TEMPLATE']->JScode .= chr(10);
222 $this->generateJavascript();
223 $GLOBALS['TBE_TEMPLATE']->JScode .= $GLOBALS['TBE_TEMPLATE']->wrapScriptTags($this->js);
224
225 // FIXME abusing the JS container to add CSS, need to fix template.php
226 foreach($this->cssFiles as $cssFileName => $cssFile) {
227 $GLOBALS['TBE_TEMPLATE']->JScode .= '
228 <link rel="stylesheet" type="text/css" href="'.$cssFile.'" />
229 ';
230
231 // load addditional css files to overwrite existing core styles
232 if(!empty($GLOBALS['TBE_STYLES']['stylesheets'][$cssFileName])) {
233 $GLOBALS['TBE_TEMPLATE']->JScode .= '
234 <link rel="stylesheet" type="text/css" href="'.$GLOBALS['TBE_STYLES']['stylesheets'][$cssFileName].'" />
235 ';
236 }
237 }
238
239 if(!empty($this->css)) {
240 $GLOBALS['TBE_TEMPLATE']->JScode .= '
241 <style type="text/css" id="internalStyle">
242 '.$this->css.'
243 </style>';
244 }
245
246 // set document title:
247 $title = ($GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']
248 ? $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'].' [TYPO3 '.TYPO3_version.']'
249 : 'TYPO3 '.TYPO3_version
250 );
251
252 // start page header:
253 $this->content .= $GLOBALS['TBE_TEMPLATE']->startPage($title);
254 $this->content .= $backendScaffolding;
255 $this->content .= $GLOBALS['TBE_TEMPLATE']->endPage();
256
257 echo $this->content;
258 }
259
260 /**
261 * renders the items in the top toolbar
262 *
263 * @return string top toolbar elements as HTML
264 */
265 protected function renderToolbar() {
266
267 // move search to last position
268 $search = $this->toolbarItems['backendSearch'];
269 unset($this->toolbarItems['backendSearch']);
270 $this->toolbarItems['backendSearch'] = $search;
271
272 $toolbar = '<ul id="typo3-toolbar">';
273 $toolbar.= '<li>'.$this->getLoggedInUserLabel().'</li>
274 <li><div id="logout-button" class="toolbar-item no-separator">'.$this->moduleMenu->renderLogoutButton().'</div></li>';
275
276 foreach($this->toolbarItems as $toolbarItem) {
277 $menu = $toolbarItem->render();
278 if ($menu) {
279 $additionalAttributes = $toolbarItem->getAdditionalAttributes();
280 $toolbar .= '<li' . $additionalAttributes . '>' .$menu. '</li>';
281 }
282 }
283
284 return $toolbar.'</ul>';
285 }
286
287 /**
288 * gets the label of the currently loged in BE user
289 *
290 * @return string html code snippet displaying the currently logged in user
291 */
292 protected function getLoggedInUserLabel() {
293 global $BE_USER, $BACK_PATH;
294
295 $icon = '<img'.t3lib_iconWorks::skinImg(
296 '',
297 $BE_USER->isAdmin() ?
298 'gfx/i/be_users_admin.gif' :
299 'gfx/i/be_users.gif',
300 'width="18" height="16"'
301 )
302 .' title="" alt="" />';
303
304 $label = $GLOBALS['BE_USER']->user['realName'] ?
305 $BE_USER->user['realName'].' ['.$BE_USER->user['username'].']' :
306 $BE_USER->user['username'];
307
308 // Link to user setup if it's loaded and user has access
309 $link = '';
310 if (t3lib_extMgm::isLoaded('setup') && $BE_USER->check('modules','user_setup')) {
311 $link = '<a href="#" onclick="top.goToModule(\'user_setup\');this.blur();return false;">';
312 }
313
314 $username = '">'.$link.$icon.'<span>'.htmlspecialchars($label).'</span>'.($link?'</a>':'');
315
316 // superuser mode
317 if($BE_USER->user['ses_backuserid']) {
318 $username = ' su-user">'.$icon.
319 '<span title="'.$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_misc.xml:switchtouser').'">SU: </span>'.
320 '<span>'.htmlspecialchars($label).'</span>';
321 }
322
323 return '<div id="username" class="toolbar-item no-separator'.$username.'</div>';
324 }
325
326 /**
327 * Generates the JavaScript code for the backend.
328 *
329 * @return void
330 */
331 protected function generateJavascript() {
332
333 $pathTYPO3 = t3lib_div::dirname(t3lib_div::getIndpEnv('SCRIPT_NAME')).'/';
334 $goToModuleSwitch = $this->moduleMenu->getGotoModuleJavascript();
335 $moduleFramesHelper = implode(chr(10), $this->moduleMenu->getFsMod());
336
337 // If another page module was specified, replace the default Page module with the new one
338 $newPageModule = trim($GLOBALS['BE_USER']->getTSConfigVal('options.overridePageModule'));
339 $pageModule = t3lib_BEfunc::isModuleSetInTBE_MODULES($newPageModule) ? $newPageModule : 'web_layout';
340
341 $menuFrameName = 'menu';
342 if($GLOBALS['BE_USER']->uc['noMenuMode'] === 'icons') {
343 $menuFrameName = 'topmenuFrame';
344 }
345
346 // create challenge for the (re)login form and save it in the session.
347 $challenge = md5(uniqid('').getmypid());
348 session_start();
349 $_SESSION['login_challenge'] = $challenge;
350
351 // determine security level from conf vars and default to super challenged
352 if ($GLOBALS['TYPO3_CONF_VARS']['BE']['loginSecurityLevel']) {
353 $this->loginSecurityLevel = $GLOBALS['TYPO3_CONF_VARS']['BE']['loginSecurityLevel'];
354 } else {
355 $this->loginSecurityLevel = 'superchallenged';
356 }
357
358 $this->js .= '
359 Ext.BLANK_IMAGE_URL = "' .
360 // t3lib_div::locationHeaderUrl() will include '/typo3/' in the URL
361 htmlspecialchars(t3lib_div::locationHeaderUrl('gfx/clear.gif')) .
362 '";
363
364 /**
365 * Function similar to PHPs rawurlencode();
366 */
367 function rawurlencode(str) {
368 var output = escape(str);
369 output = str_replace("*","%2A", output);
370 output = str_replace("+","%2B", output);
371 output = str_replace("/","%2F", output);
372 output = str_replace("@","%40", output);
373 return output;
374 }
375
376 /**
377 * Function to similar to PHPs rawurlencode() which removes TYPO3_SITE_URL;
378 */
379 function rawurlencodeAndRemoveSiteUrl(str) { //
380 var siteUrl = "' . t3lib_div::getIndpEnv('TYPO3_SITE_URL') . '";
381 return rawurlencode(str_replace(siteUrl, \'\', str));
382 }
383
384 /**
385 * String-replace function
386 */
387 function str_replace(match,replace,string) { //
388 var input = ""+string;
389 var matchStr = ""+match;
390 if (!matchStr) {return string;}
391 var output = "";
392 var pointer=0;
393 var pos = input.indexOf(matchStr);
394 while (pos!=-1) {
395 output+=""+input.substr(pointer, pos-pointer)+replace;
396 pointer=pos+matchStr.length;
397 pos = input.indexOf(match,pos+1);
398 }
399 output+=""+input.substr(pointer);
400 return output;
401 }
402
403 /**
404 * TypoSetup object.
405 */
406 function typoSetup() { //
407 this.PATH_typo3 = "'.$pathTYPO3.'";
408 this.PATH_typo3_enc = "'.rawurlencode($pathTYPO3).'";
409 this.username = "'.htmlspecialchars($GLOBALS['BE_USER']->user['username']).'";
410 this.uniqueID = "'.t3lib_div::shortMD5(uniqid('')).'";
411 this.veriCode = "' . $GLOBALS['BE_USER']->veriCode() . '";
412 this.navFrameWidth = 0;
413 this.securityLevel = "'.$this->loginSecurityLevel.'";
414 this.denyFileTypes = "' . PHP_EXTENSIONS_DEFAULT . '";
415 }
416 var TS = new typoSetup();
417
418 /**
419 * Language Labels
420 */
421 TYPO3.LLL = {
422 fileUpload: {
423 windowTitle: "File Upload Progress",
424 buttonSelectFiles: "Select Files",
425 buttonCancelAll: "Cancel All Uploads",
426 infoComponentMaxFileSize: "You can upload files with a maximum size of {0}.",
427 infoComponentFileUploadLimit: "You can upload a total of {0}.",
428 infoComponentFileTypeLimit: "You can upload the following file types {0}.",
429 infoComponentOverrideFiles: "' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_misc.xml:overwriteExistingFiles', 1) . '",
430 processRunning: "Another process is already uploading",
431 uploadWait: "Waiting to start upload of {0}",
432 uploadStarting: "Starting upload of {0}",
433 uploadProgress: "{0}% of {1} uploaded",
434 uploadSuccess: "{0} was successfully uploaded!",
435 errorQueueLimitExceeded: "Too many files selected",
436 errorQueueFileSizeLimit: "{0} is too big",
437 errorQueueZeroByteFile: "{0} is empty",
438 errorQueueInvalidFiletype: "Filetype not allowed for {0}",
439 errorUploadHttp: "Too many files selected",
440 errorUploadMissingUrl: "Internal error: No Upload URL set",
441 errorUploadIO: "Internal error: Problems while reading/writing the file",
442 errorUploadSecurityError: "Internal error: {0}",
443 errorUploadLimit: "Upload limit exceeded",
444 errorUploadFailed: "Upload failed",
445 errorUploadFileIDNotFound: "Internal error: File ID not found",
446 errorUploadFileValidation: "Internal error while validating the file",
447 errorUploadFileCancelled: "Upload of {0} canceled",
448 errorUploadStopped: "Upload of {0} stopped"
449 }
450 };
451
452 /**
453 * Functions for session-expiry detection:
454 */
455 function busy() { //
456 this.loginRefreshed = busy_loginRefreshed;
457 this.openRefreshWindow = busy_OpenRefreshWindow;
458 this.openLockedWaitWindow = busy_openLockedWaitWindow;
459 this.busyloadTime=0;
460 this.openRefreshW=0;
461 this.reloginCancelled=0;
462 this.earlyRelogin=0;
463 this.locked=0;
464
465 // starts the timer and resets the earlyRelogin variable so that
466 // the countdown works properly.
467 this.startTimer = function() {
468 this.earlyRelogin = 0;
469 this.timer.start();
470 }
471
472 this.stopTimer = function() {
473 this.timer.stop();
474 }
475
476 // simple timer that polls the server to determine imminent timeout.
477 this.timer = new Ajax.PeriodicalUpdater("","ajax.php", {
478 method: "get",
479 frequency: 60,
480 decay: 1,
481 parameters: "ajaxID=BackendLogin::isTimedOut&skipSessionUpdate=1",
482 onSuccess: function(e) {
483 var login = e.responseJSON.login.evalJSON();
484 if(login.locked) {
485 busy.locked = 1;
486 busy.openLockedWaitWindow();
487 } else if(login.timed_out) {
488 busy.openRefreshWindow();
489 }
490 if (busy.locked && !login.locked && !login.timed_out) {
491 busy.locked = 0;
492 Ext.MessageBox.hide();
493 }
494 }
495 });
496
497 // this function runs the countdown and opens the login window
498 // as soon as the countdown expires.
499 this.countDown = function(progressControl, progressTextFormatPlural, progressTextFormatSingular, secondsRemaining, totalSeconds) {
500
501 if(busy.earlyRelogin == 0) {
502 if(secondsRemaining > 1) {
503 progressControl.updateText(String.format(progressTextFormatPlural, secondsRemaining));
504 progressControl.updateProgress(secondsRemaining/(1.0*totalSeconds));
505 setTimeout(function () {
506 busy.countDown(progressControl, progressTextFormatPlural, progressTextFormatSingular,secondsRemaining - 1, totalSeconds);
507 }, 1000);
508 } else if(secondsRemaining > 0) {
509 progressControl.updateText(String.format(progressTextFormatSingular, secondsRemaining));
510 progressControl.updateProgress(secondsRemaining/(1.0*totalSeconds));
511 setTimeout(function () {
512 busy.countDown(progressControl, progressTextFormatPlural, progressTextFormatSingular,secondsRemaining - 1, totalSeconds);
513 }, 1000);
514 } else {
515 busy.openRefreshW = 1;
516 busy.openLogin();
517 }
518 }
519 };
520
521 // Closes the countdown window and opens a new one with a login form.
522 this.openLogin = function() {
523 var login;
524 doChallengeResponse = function(superchallenged) {
525 password = $$("#loginform form")[0].p_field.value;
526
527 if (password) {
528 if (superchallenged) {
529 password = MD5(password); // this makes it superchallenged!!
530 }
531 str = $("login_username").value+":"+password+":"+$("challenge").value;
532 $("userident").value = MD5(str);
533 $("password").value = "";
534
535 return true;
536 }
537 }
538
539 submitForm = function() {
540 if(TS.securityLevel == "superchallenged") {
541 doChallengeResponse(1);
542 } else if (TS.securityLevel == "challenged") {
543 doChallengeResponse(0);
544 } else {
545 $("userident").value = $$("#loginform form")[0].p_field.value;
546 $("password").value= "";
547 }
548
549 login.getForm().submit({
550 method: "post",
551 waitTitle: "' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:mess.refresh_login_logging_in') . '",
552 waitMsg: " ",
553 params: "ajaxID=BackendLogin::login&login_status=login",
554 success: function() {
555 win.close();
556 setTimeout(busy.startTimer(), 2000);
557
558 },
559
560 failure: function() {
561 // TODO: add failure to notification system instead of alert
562 // Ext.tip.msg("Login failed", "Username or Password incorrect!");
563 Ext.Msg.alert("' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:mess.refresh_login_failed') . '", "' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:mess.refresh_login_failed_message') . '");
564 }
565 });
566 }
567
568 logout = new Ajax.Request("ajax.php", {
569 method: "get",
570 parameters: "ajaxID=BackendLogin::logout"
571 });
572
573 Ext.onReady(function(){
574 login = new Ext.FormPanel({
575 url: "ajax.php",
576 id: "loginform",
577 title: "' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:mess.refresh_login_title') . '",
578 defaultType: "textfield",
579 width: "100%",
580 bodyStyle: "padding: 5px 5px 3px 5px; border-width: 0; margin-bottom: 7px;",
581
582 items: [{
583 xtype: "panel",
584 bodyStyle: "margin-bottom: 7px; border: none;",
585 html: "' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:mess.login_expired') . '"
586 },{
587 fieldLabel: "' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:mess.refresh_login_username') . '",
588 name: "username",
589 id: "login_username",
590 allowBlank: false,
591 width: 250
592 },{
593 fieldLabel: "' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:mess.refresh_login_password') . '",
594 name: "p_field",
595 width: 250,
596 id: "password",
597 inputType: "password"
598 },{
599 xtype: "hidden",
600 name: "userident",
601 id: "userident",
602 value: ""
603 }, {
604 xtype: "hidden",
605 name: "challenge",
606 id: "challenge",
607 value: "' . $challenge . '"
608 }
609 ],
610 keys:({
611 key: Ext.EventObject.ENTER,
612 fn: submitForm,
613 scope: this
614 }),
615 buttons: [{
616 text: "' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:mess.refresh_login_button') . '",
617 formBind: true,
618 handler: submitForm
619 }, {
620 text: "' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:mess.refresh_logout_button') . '",
621 formBind: true,
622 handler: function() {
623 top.location.href = "' . t3lib_div::getIndpEnv('TYPO3_SITE_URL') . TYPO3_mainDir . '";
624 }
625 }]
626 });
627 win.close();
628 win = new Ext.Window({
629 width: 450,
630 autoHeight: true,
631 closable: false,
632 resizable: false,
633 plain: true,
634 border: false,
635 modal: true,
636 draggable: false,
637 items: [login]
638 });
639 win.show();
640 });
641 }
642 }
643
644 function busy_loginRefreshed() { //
645 this.openRefreshW=0;
646 this.earlyRelogin=0;
647 }
648
649 function busy_openLockedWaitWindow() {
650 Ext.MessageBox.show({
651 title: "' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:mess.please_wait') . '",
652 msg: "' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:mess.be_locked') . '",
653 width: 500,
654 icon: Ext.MessageBox.INFO,
655 closable: false
656 });
657 }
658
659 function busy_OpenRefreshWindow() {
660 this.openRefreshW = 1;
661
662 busy.stopTimer();
663
664 var seconds = 30;
665 var progressTextFormatSingular = "' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:mess.refresh_login_countdown_singular') . '";
666 var progressTextFormatPlural = "' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:mess.refresh_login_countdown') . '";
667 var progressText = String.format(progressTextFormatPlural, seconds);
668 var progressControl = new Ext.ProgressBar({
669 autoWidth: true,
670 autoHeight: true,
671 value: 1,
672 text: progressText
673 });
674
675 win = new Ext.Window({
676 closable: false,
677 resizable: false,
678 draggable: false,
679 modal: true,
680 items: [{
681 xtype: "panel",
682 bodyStyle: "padding: 5px 5px 3px 5px; border-width: 0; margin-bottom: 7px;",
683 bodyBorder: false,
684 autoHeight: true,
685 autoWidth: true,
686 html: "' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:mess.login_about_to_expire') . '"
687 },
688 progressControl
689 ],
690 title: "' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:mess.login_about_to_expire_title') . '",
691 width: 450,
692
693 buttons: [{
694 text: "' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:mess.refresh_login_refresh_button') . '",
695 handler: function() {
696 refresh = new Ajax.Request("ajax.php", {
697 method: "get",
698 parameters: "ajaxID=BackendLogin::refreshLogin"
699 });
700 win.close();
701 busy.earlyRelogin = 1;
702 setTimeout("busy.startTimer()", 2000);
703 }
704 }, {
705 text: "' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:mess.refresh_direct_logout_button') . '",
706 handler: function() {
707 top.location.href = "' . t3lib_div::getIndpEnv('TYPO3_SITE_URL') . TYPO3_mainDir . 'logout.php";
708 }
709 }]
710 });
711 win.show();
712 busy.countDown(progressControl, progressTextFormatPlural, progressTextFormatSingular, seconds, seconds);
713 }
714
715 /**
716 * Launcing information window for records/files (fileref as "table" argument)
717 */
718 function launchView(table,uid,bP) { //
719 var backPath= bP ? bP : "";
720 var thePreviewWindow="";
721 thePreviewWindow = window.open(TS.PATH_typo3+"show_item.php?table="+encodeURIComponent(table)+"&uid="+encodeURIComponent(uid),"ShowItem"+TS.uniqueID,"height=400,width=550,status=0,menubar=0,resizable=0,location=0,directories=0,scrollbars=1,toolbar=0");
722 if (thePreviewWindow && thePreviewWindow.focus) {
723 thePreviewWindow.focus();
724 }
725 }
726
727 /**
728 * Opens plain window with url
729 */
730 function openUrlInWindow(url,windowName) { //
731 regularWindow = window.open(url,windowName,"status=1,menubar=1,resizable=1,location=1,directories=0,scrollbars=1,toolbar=1");
732 regularWindow.focus();
733 return false;
734 }
735
736 /**
737 * Loads a page id for editing in the page edit module:
738 */
739 function loadEditId(id,addGetVars) { //
740 top.fsMod.recentIds["web"]=id;
741 top.fsMod.navFrameHighlightedID["web"]="pages"+id+"_0"; // For highlighting
742
743 if (top.content && top.content.nav_frame && top.content.nav_frame.refresh_nav) {
744 top.content.nav_frame.refresh_nav();
745 }
746
747 top.goToModule("'.$pageModule.'", 0, addGetVars?addGetVars:"");
748 }
749
750 /**
751 * Returns incoming URL (to a module) unless nextLoadModuleUrl is set. If that is the case nextLoadModuleUrl is returned (and cleared)
752 * Used by the shortcut frame to set a "intermediate URL"
753 */
754 var nextLoadModuleUrl="";
755 function getModuleUrl(inUrl) { //
756 var nMU;
757 if (top.nextLoadModuleUrl) {
758 nMU=top.nextLoadModuleUrl;
759 top.nextLoadModuleUrl="";
760 return nMU;
761 } else {
762 return inUrl;
763 }
764 }
765
766 /**
767 * Print properties of an object
768 */
769 function debugObj(obj,name) { //
770 var acc;
771 for (i in obj) {
772 if (obj[i]) {
773 acc+=i+": "+obj[i]+"\n";
774 }
775 }
776 alert("Object: "+name+"\n\n"+acc);
777 }
778
779 /**
780 * Initialize login expiration warning object
781 */
782 var busy = new busy();
783 busy.loginRefreshed();
784
785 /**
786 * Function used to switch modules
787 */
788 var currentModuleLoaded = "";
789 var goToModule = '.$goToModuleSwitch.'
790
791 /**
792 * Frameset Module object
793 *
794 * Used in main modules with a frameset for submodules to keep the ID between modules
795 * Typically that is set by something like this in a Web>* sub module:
796 * if (top.fsMod) top.fsMod.recentIds["web"] = "\'.intval($this->id).\'";
797 * if (top.fsMod) top.fsMod.recentIds["file"] = "...(file reference/string)...";
798 */
799 function fsModules() { //
800 this.recentIds=new Array(); // used by frameset modules to track the most recent used id for list frame.
801 this.navFrameHighlightedID=new Array(); // used by navigation frames to track which row id was highlighted last time
802 this.currentMainLoaded="";
803 this.currentBank="0";
804 }
805 var fsMod = new fsModules();
806 '.$moduleFramesHelper.'
807
808 // Used by Frameset Modules
809 var condensedMode = '.($GLOBALS['BE_USER']->uc['condensedMode']?1:0).';
810 var currentSubScript = "";
811 var currentSubNavScript = "";
812
813 // Used for tab-panels:
814 var DTM_currentTabs = new Array();
815
816 // status of WS FE preview
817 var WorkspaceFrontendPreviewEnabled = ' . (($GLOBALS['BE_USER']->workspace != 0 && !$GLOBALS['BE_USER']->user['workspace_preview']) ? 'false' : 'true') . ';
818 ';
819
820 // Check editing of page:
821 $this->handlePageEditing();
822 $this->setStartupModule();
823 }
824
825 /**
826 * Checking if the "&edit" variable was sent so we can open it for editing the page.
827 * Code based on code from "alt_shortcut.php"
828 *
829 * @return void
830 */
831 protected function handlePageEditing() {
832
833 if(!t3lib_extMgm::isLoaded('cms')) {
834 return;
835 }
836
837 // EDIT page:
838 $editId = preg_replace('/[^[:alnum:]_]/', '', t3lib_div::_GET('edit'));
839 $editRecord = '';
840
841 if($editId) {
842
843 // Looking up the page to edit, checking permissions:
844 $where = ' AND ('.$GLOBALS['BE_USER']->getPagePermsClause(2)
845 .' OR '.$GLOBALS['BE_USER']->getPagePermsClause(16).')';
846
847 if(t3lib_div::testInt($editId)) {
848 $editRecord = t3lib_BEfunc::getRecordWSOL('pages', $editId, '*', $where);
849 } else {
850 $records = t3lib_BEfunc::getRecordsByField('pages', 'alias', $editId, $where);
851
852 if(is_array($records)) {
853 reset($records);
854 $editRecord = current($records);
855 t3lib_BEfunc::workspaceOL('pages', $editRecord);
856 }
857 }
858
859 // If the page was accessible, then let the user edit it.
860 if(is_array($editRecord) && $GLOBALS['BE_USER']->isInWebMount($editRecord['uid'])) {
861 // Setting JS code to open editing:
862 $this->js .= '
863 // Load page to edit:
864 window.setTimeout("top.loadEditId('.intval($editRecord['uid']).');", 500);
865 ';
866 // Checking page edit parameter:
867 if(!$GLOBALS['BE_USER']->getTSConfigVal('options.shortcut_onEditId_dontSetPageTree')) {
868
869 // Expanding page tree:
870 t3lib_BEfunc::openPageTree(intval($editRecord['pid']), !$GLOBALS['BE_USER']->getTSConfigVal('options.shortcut_onEditId_keepExistingExpanded'));
871 }
872 } else {
873 $this->js .= '
874 // Warning about page editing:
875 alert('.$GLOBALS['LANG']->JScharCode(sprintf($GLOBALS['LANG']->getLL('noEditPage'), $editId)).');
876 ';
877 }
878 }
879 }
880
881 /**
882 * Sets the startup module from either GETvars module and mpdParams or user configuration.
883 *
884 * @return void
885 */
886 protected function setStartupModule() {
887 $startModule = preg_replace('/[^[:alnum:]_]/', '', t3lib_div::_GET('module'));
888
889 if(!$startModule) {
890 if ($GLOBALS['BE_USER']->uc['startModule']) {
891 $startModule = $GLOBALS['BE_USER']->uc['startModule'];
892 } else if($GLOBALS['BE_USER']->uc['startInTaskCenter']) {
893 $startModule = 'user_task';
894 }
895 }
896
897 $moduleParameters = t3lib_div::_GET('modParams');
898 if($startModule) {
899 $this->js .= '
900 // start in module:
901 function startInModule(modName, cMR_flag, addGetVars) {
902 Event.observe(document, \'dom:loaded\', function() {
903 top.goToModule(modName, cMR_flag, addGetVars);
904 });
905 }
906
907 startInModule(\''.$startModule.'\', false, \''.$moduleParameters.'\');
908 ';
909 }
910 }
911
912 /**
913 * generates the code for the TYPO3 logo, either the default TYPO3 logo or a custom one
914 *
915 * @return string HTML code snippet to display the TYPO3 logo
916 */
917 protected function getLogo() {
918 $logo = '<a href="http://www.typo3.com/" target="_blank" onclick="'.$GLOBALS['TBE_TEMPLATE']->thisBlur().'">'.
919 '<img'.t3lib_iconWorks::skinImg('','gfx/alt_backend_logo.gif','width="117" height="32"').' title="TYPO3 Content Management Framework" alt="" />'.
920 '</a>';
921
922 // overwrite with custom logo
923 if($GLOBALS['TBE_STYLES']['logo']) {
924 if(substr($GLOBALS['TBE_STYLES']['logo'], 0, 3) == '../') {
925 $imgInfo = @getimagesize(PATH_site.substr($GLOBALS['TBE_STYLES']['logo'], 3));
926 }
927 $logo = '<a href="http://www.typo3.com/" target="_blank" onclick="'.$GLOBALS['TBE_TEMPLATE']->thisBlur().'">'.
928 '<img src="'.$GLOBALS['TBE_STYLES']['logo'].'" '.$imgInfo[3].' title="TYPO3 Content Management Framework" alt="" />'.
929 '</a>';
930 }
931
932 return $logo;
933 }
934
935 /**
936 * adds a javascript snippet to the backend
937 *
938 * @param string javascript snippet
939 * @return void
940 */
941 public function addJavascript($javascript) {
942 // TODO do we need more checks?
943 if(!is_string($javascript)) {
944 throw new InvalidArgumentException('parameter $javascript must be of type string', 1195129553);
945 }
946
947 $this->js .= $javascript;
948 }
949
950 /**
951 * adds a javscript file to the backend after it has been checked that it exists
952 *
953 * @param string javascript file reference
954 * @return boolean true if the javascript file was successfully added, false otherwise
955 */
956 public function addJavascriptFile($javascriptFile) {
957 $jsFileAdded = false;
958
959 //TODO add more checks if neccessary
960 if(file_exists(t3lib_div::resolveBackPath(PATH_typo3.$javascriptFile))) {
961 $this->jsFiles[] = $javascriptFile;
962 $jsFileAdded = true;
963 }
964
965 return $jsFileAdded;
966 }
967
968 /**
969 * adds a css snippet to the backend
970 *
971 * @param string css snippet
972 * @return void
973 */
974 public function addCss($css) {
975 if(!is_string($css)) {
976 throw new InvalidArgumentException('parameter $css must be of type string', 1195129642);
977 }
978
979 $this->css .= $css;
980 }
981
982 /**
983 * adds a css file to the backend after it has been checked that it exists
984 *
985 * @param string the css file's name with out the .css ending
986 * @param string css file reference
987 * @return boolean true if the css file was added, false otherwise
988 */
989 public function addCssFile($cssFileName, $cssFile) {
990 $cssFileAdded = false;
991
992 //TODO add more checks if neccessary
993 if(file_exists(t3lib_div::resolveBackPath(PATH_typo3.$cssFile))) {
994 // prevent overwriting existing css files
995 if(empty($this->cssFiles[$cssFileName])) {
996 $this->cssFiles[$cssFileName] = $cssFile;
997 $cssFileAdded = true;
998 }
999 }
1000
1001 return $cssFileAdded;
1002 }
1003
1004 /**
1005 * adds an item to the toolbar, the class file for the toolbar item must be loaded at this point
1006 *
1007 * @param string toolbar item name, f.e. tx_toolbarExtension_coolItem
1008 * @param string toolbar item class name, f.e. tx_toolbarExtension_coolItem
1009 * @return void
1010 */
1011 public function addToolbarItem($toolbarItemName, $toolbarItemClassName) {
1012 $toolbarItem = t3lib_div::makeInstance($toolbarItemClassName, $this);
1013
1014 if(!($toolbarItem instanceof backend_toolbarItem)) {
1015 throw new UnexpectedValueException('$toolbarItem "'.$toolbarItemName.'" must implement interface backend_toolbarItem', 1195125501);
1016 }
1017
1018 if($toolbarItem->checkAccess()) {
1019 $this->toolbarItems[$toolbarItemName] = $toolbarItem;
1020 } else {
1021 unset($toolbarItem);
1022 }
1023 }
1024 }
1025
1026
1027 // include XCLASS
1028 if(defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/backend.php']) {
1029 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/backend.php']);
1030 }
1031
1032
1033 // document generation
1034 $TYPO3backend = t3lib_div::makeInstance('TYPO3backend');
1035
1036 // include extensions which may add css, javascript or toolbar items
1037 if(is_array($GLOBALS['TYPO3_CONF_VARS']['typo3/backend.php']['additionalBackendItems'])) {
1038 foreach($GLOBALS['TYPO3_CONF_VARS']['typo3/backend.php']['additionalBackendItems'] as $additionalBackendItem) {
1039 include_once($additionalBackendItem);
1040 }
1041 }
1042
1043 $TYPO3backend->render();
1044
1045 ?>