2 /***************************************************************
5 * (c) 2007 Ingo Renner <ingo@typo3.org>
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.
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.
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.
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
28 require_once ('init.php');
29 require_once ('template.php');
30 require_once ('interfaces/interface.backend_toolbaritem.php');
32 require ('classes/class.typo3logo.php');
33 require ('classes/class.modulemenu.php');
34 require ('classes/class.workspaceselector.php');
36 require_once (PATH_t3lib
.'class.t3lib_loadmodules.php');
37 require_once (PATH_t3lib
.'class.t3lib_basicfilefunc.php');
38 require_once ('class.alt_menu_functions.inc');
39 $GLOBALS['LANG']->includeLLFile('EXT:lang/locallang_misc.xml');
43 * Class for rendering the TYPO3 backend version 4.2+
45 * @author Ingo Renner <ingo@typo3.org>
57 * Object for loading backend modules
59 * @var t3lib_loadModules
61 private $moduleLoader;
64 * module menu generating object
70 private $leftMenuWidth;
73 private $toolbarItems;
80 public function __construct() {
81 // Initializes the backend modules structure for use later.
82 $this->moduleLoader
= t3lib_div
::makeInstance('t3lib_loadModules');
83 $this->moduleLoader
->load($GLOBALS['TBE_MODULES']);
85 $this->moduleMenu
= t3lib_div
::makeInstance('ModuleMenu');
87 // Check for distances defined in the styles array:
88 if ($TBE_STYLES['dims']['leftMenuFrameW']) {
89 $this->leftMenuWidth
= $TBE_STYLES['dims']['leftMenuFrameW'];
91 if ($TBE_STYLES['dims']['topFrameH']) {
92 $this->topHeight
= $TBE_STYLES['dims']['topFrameH'];
94 if ($TBE_STYLES['dims']['selMenuFrame']) {
95 $this->selectMenu
= $TBE_STYLES['dims']['selMenuFrame'];
98 // add default BE javascript
100 $this->jsFiles
= array(
101 'contrib/prototype/prototype.js',
104 '../t3lib/jsfunc.evalfield.js'
107 // add default BE css
108 $this->cssFiles
= array(
109 'css/backend-scaffolding.css',
110 'css/backend-style.css',
111 'css/verticalmenu.css'
114 $this->toolbarItems
= array();
115 $this->initializeCoreToolbarItems();
119 * initializes the core toolbar items
123 private function initializeCoreToolbarItems() {
125 $coreToolbarItems = array(
126 'workspaceSelector' => 'WorkspaceSelector',
128 'clearCacheActions' => '',
129 'backendSearch' => '',
134 foreach($coreToolbarItems as $toolbarItemName => $toolbarItemClass) {
135 $toolbarItem = t3lib_div
::makeInstance($toolbarItemClass);
137 if(!($toolbarItem instanceof backend_toolbarItem
)) {
138 throw new UnexpectedValueException('$toolbarItem "'.$toolbarItemName.'" must implement interface backend_toolbarItem', 1195126772);
141 $toolbarItem->setBackend($this);
142 $this->toolbarItems
[] = $toolbarItem;
147 * main function generating the BE scaffolding
151 public function render() {
153 // prepare the scaffolding, at this point extension still may addjavascript and css
154 $logo = t3lib_div
::makeInstance('TYPO3Logo');
155 $logo->setLogo('gfx/typo3logo_mini.png');
157 $menu = $this->moduleMenu
->render();
158 $cacheActions = $this->moduleMenu
->renderCacheActions();
159 $logout = $this->moduleMenu
->renderLogoutButton();
160 $loginInfo = $this->getLoggedInUserLabel();
162 // create backend scaffolding
163 $backendScaffolding = '
164 <div id="typo3-backend">
165 <div id="typo3-top-container">
166 <div id="typo3-logo">'.$logo->render().'</div>
167 <div id="typo3-top" class="typo3-top-toolbar">'
168 .$this->renderToolbar()
171 <div id="typo3-main-container">
172 <div id="typo3-side-menu">'
179 <div id="typo3-content">
180 <iframe src="alt_intro.php" name="content" id="content" marginwidth="0" marginheight="0" frameborder="0" scrolling="auto" noresize="noresize"></iframe>
187 /******************************************************
188 * now put the complete backend document together
189 ******************************************************/
192 $GLOBALS['TBE_TEMPLATE']->docType
= 'xhtml_trans';
195 foreach($this->jsFiles
as $jsFile) {
196 $GLOBALS['TBE_TEMPLATE']->JScode
.= '
197 <script type="text/javascript" src="'.$jsFile.'"></script>';
199 $GLOBALS['TBE_TEMPLATE']->JScode
.= chr(10);
200 $this->generateJavascript();
201 $GLOBALS['TBE_TEMPLATE']->JScode
.= $GLOBALS['TBE_TEMPLATE']->wrapScriptTags($this->js
);
203 // abusing the JS container to add CSS
204 // TODO fix template.php
205 foreach($this->cssFiles
as $cssFile) {
206 $GLOBALS['TBE_TEMPLATE']->JScode
.= '
207 <link rel="stylesheet" type="text/css" href="'.$cssFile.'" />
210 // TODO add CSS from $this->css
212 // set document title
213 $title = $TYPO3_CONF_VARS['SYS']['sitename'] ?
214 $TYPO3_CONF_VARS['SYS']['sitename'].' [TYPO3 '.TYPO3_version
.']'
215 : 'TYPO3 '.TYPO3_version
;
217 // start page header:
218 $this->content
.= $GLOBALS['TBE_TEMPLATE']->startPage($title);
219 $this->content
.= $GLOBALS['TBE_TEMPLATE']->endPage();
221 $this->content
.= $backendScaffolding;
227 * renders the items in the top toolbar
229 * @return string top toolbar elements as HTML
231 private function renderToolbar() {
234 foreach($this->toolbarItems
as $toolbarItem) {
235 $toolbar .= $toolbarItem->render();
242 * gets the label of the currently loged in BE user
244 * @return string html code snippet displaying the currently logged in user
246 private function getLoggedInUserLabel() {
247 $username = '<p id="username">['.htmlspecialchars($GLOBALS['BE_USER']->user
['username']).']</p>';;
250 if($BE_USER->user
['ses_backuserid']) {
251 $username = '<p id="username" class="typo3-red-background">[SU: '.htmlspecialchars($GLOBALS['BE_USER']->user
['username']).']</p>';
254 return '<div id="login-info">'.$username.'</div>';
258 * Generates the JavaScript code for the backend.
262 private function generateJavascript() {
264 $pathTYPO3 = t3lib_div
::dirname(t3lib_div
::getIndpEnv('SCRIPT_NAME')).'/';
265 $goToModuleSwitch = $this->moduleMenu
->getGotoModuleJavascript();
266 $moduleFramesHelper = implode(chr(10), $this->moduleMenu
->getFsMod());
268 // If another page module was specified, replace the default Page module with the new one
269 $newPageModule = trim($GLOBALS['BE_USER']->getTSConfigVal('options.overridePageModule'));
270 $pageModule = t3lib_BEfunc
::isModuleSetInTBE_MODULES($newPageModule) ?
$newPageModule : 'web_layout';
272 $menuFrameName = 'menu';
273 if($GLOBALS['BE_USER']->uc
['noMenuMode'] === 'icons') {
274 $menuFrameName = 'topmenuFrame';
279 * Function similar to PHPs rawurlencode();
281 function rawurlencode(str) { //
282 var output = escape(str);
283 output = str_replace("*","%2A", output);
284 output = str_replace("+","%2B", output);
285 output = str_replace("/","%2F", output);
286 output = str_replace("@","%40", output);
291 * String-replace function
293 function str_replace(match,replace,string) { //
294 var input = ""+string;
295 var matchStr = ""+match;
296 if (!matchStr) {return string;}
299 var pos = input.indexOf(matchStr);
301 output+=""+input.substr(pointer, pos-pointer)+replace;
302 pointer=pos+matchStr.length;
303 pos = input.indexOf(match,pos+1);
305 output+=""+input.substr(pointer);
312 function typoSetup() { //
313 this.PATH_typo3 = "'.$pathTYPO3.'";
314 this.PATH_typo3_enc = "'.rawurlencode($pathTYPO3).'";
315 this.username = "'.$GLOBALS['BE_USER']->user
['username'].'";
316 this.uniqueID = "'.t3lib_div
::shortMD5(uniqid('')).'";
317 this.navFrameWidth = 0;
319 var TS = new typoSetup();
322 * Functions for session-expiry detection:
325 this.loginRefreshed = busy_loginRefreshed;
326 this.checkLoginTimeout = busy_checkLoginTimeout;
327 this.openRefreshWindow = busy_OpenRefreshWindow;
330 this.reloginCancelled=0;
332 function busy_loginRefreshed() { //
333 var date = new Date();
334 this.busyloadTime = Math.floor(date.getTime()/1000);
337 function busy_checkLoginTimeout() { //
338 var date = new Date();
339 var theTime = Math.floor(date.getTime()/1000);
340 if (theTime > this.busyloadTime+'.intval($GLOBALS['BE_USER']->auth_timeout_field
).'-30) {
344 function busy_OpenRefreshWindow() { //
345 vHWin=window.open("login_frameset.php","relogin_"+TS.uniqueID,"height=350,width=700,status=0,menubar=0,location=1");
349 function busy_checkLoginTimeout_timer() { //
350 if (busy.checkLoginTimeout() && !busy.reloginCancelled && !busy.openRefreshW) {
351 if (confirm('.$GLOBALS['LANG']->JScharCode($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:mess.refresh_login')).')) {
352 busy.openRefreshWindow();
354 busy.reloginCancelled = 1;
357 window.setTimeout("busy_checkLoginTimeout_timer();",2*1000); // Each 2nd second is enough for checking. The popup will be triggered 10 seconds before the login expires (see above, busy_checkLoginTimeout())
359 // Detecting the frameset module navigation frame widths (do this AFTER setting new timeout so that any errors in the code below does not prevent another time to be set!)
360 if (top && top.content && top.content.nav_frame && top.content.nav_frame.document && top.content.nav_frame.document.body) {
361 TS.navFrameWidth = (top.content.nav_frame.document.documentElement && top.content.nav_frame.document.documentElement.clientWidth) ? top.content.nav_frame.document.documentElement.clientWidth : top.content.nav_frame.document.body.clientWidth;
366 * Launcing information window for records/files (fileref as "table" argument)
368 function launchView(table,uid,bP) { //
369 var backPath= bP ? bP : "";
370 var thePreviewWindow="";
371 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");
372 if (thePreviewWindow && thePreviewWindow.focus) {
373 thePreviewWindow.focus();
378 * Opens plain window with url
380 function openUrlInWindow(url,windowName) { //
381 regularWindow = window.open(url,windowName,"status=1,menubar=1,resizable=1,location=1,directories=0,scrollbars=1,toolbar=1");
382 regularWindow.focus();
387 * Loads a URL in the topmenuFrame
389 function loadTopMenu(url) { //
390 top.topmenuFrame.location = url;
394 * Loads a page id for editing in the page edit module:
396 function loadEditId(id,addGetVars) { //
397 top.fsMod.recentIds["web"]=id;
398 top.fsMod.navFrameHighlightedID["web"]="pages"+id+"_0"; // For highlighting
400 if (top.content && top.content.nav_frame && top.content.nav_frame.refresh_nav) {
401 top.content.nav_frame.refresh_nav();
404 top.goToModule("'.$pageModule.'", 0, addGetVars?addGetVars:"");
408 * Returns incoming URL (to a module) unless nextLoadModuleUrl is set. If that is the case nextLoadModuleUrl is returned (and cleared)
409 * Used by the shortcut frame to set a "intermediate URL"
411 var nextLoadModuleUrl="";
412 function getModuleUrl(inUrl) { //
414 if (top.nextLoadModuleUrl) {
415 nMU=top.nextLoadModuleUrl;
416 top.nextLoadModuleUrl="";
424 * Print properties of an object
426 function debugObj(obj,name) { //
430 acc+=i+": "+obj[i]+"\n";
433 alert("Object: "+name+"\n\n"+acc);
437 * Initialize login expiration warning object
439 var busy = new busy();
440 busy.loginRefreshed();
441 busy_checkLoginTimeout_timer();
447 var currentlyHighLightedId = "";
448 var currentlyHighLighted_restoreValue = "";
449 var currentlyHighLightedMain = "";
450 function highlightModuleMenuItem(trId, mainModule) { //
451 currentlyHighLightedMain = mainModule;
452 // Get document object:
453 if (top.menu && top.menu.document) {
454 var docObj = top.menu.document;
455 var HLclass = mainModule ? "c-mainitem-HL" : "c-subitem-row-HL";
456 } else if (top.topmenuFrame && top.topmenuFrame.document) {
457 var docObj = top.topmenuFrame.document;
458 var HLclass = mainModule ? "c-mainitem-HL" : "c-subitem-HL";
463 if (currentlyHighLightedId && docObj.getElementById(currentlyHighLightedId)) {
464 docObj.getElementById(currentlyHighLightedId).attributes.getNamedItem("class").nodeValue = currentlyHighLighted_restoreValue;
467 currentlyHighLightedId = trId;
468 if (currentlyHighLightedId && docObj.getElementById(currentlyHighLightedId)) {
469 var classAttribObject = docObj.getElementById(currentlyHighLightedId).attributes.getNamedItem("class");
470 currentlyHighLighted_restoreValue = classAttribObject.nodeValue;
471 classAttribObject.nodeValue = HLclass;
477 * Function restoring previous selection in left menu after clearing cache
479 function restoreHighlightedModuleMenuItem() { //
480 if (currentlyHighLightedId) {
481 highlightModuleMenuItem(currentlyHighLightedId,currentlyHighLightedMain);
485 '.$goToModuleSwitch.'
488 * reloads the menu frame
490 function refreshMenu() {
491 top.'.$menuFrameName.'.location.href = top.'.$menuFrameName.'.document.URL
495 * Frameset Module object
497 * Used in main modules with a frameset for submodules to keep the ID between modules
498 * Typically that is set by something like this in a Web>* sub module:
499 * if (top.fsMod) top.fsMod.recentIds["web"] = "\'.intval($this->id).\'";
500 * if (top.fsMod) top.fsMod.recentIds["file"] = "...(file reference/string)...";
502 function fsModules() { //
503 this.recentIds=new Array(); // used by frameset modules to track the most recent used id for list frame.
504 this.navFrameHighlightedID=new Array(); // used by navigation frames to track which row id was highlighted last time
505 this.currentMainLoaded="";
506 this.currentBank="0";
508 var fsMod = new fsModules();
509 '.$moduleFramesHelper.'
511 // Used by Frameset Modules
512 var condensedMode = '.($GLOBALS['BE_USER']->uc
['condensedMode']?
1:0).';
513 var currentSubScript = "";
514 var currentSubNavScript = "";
516 // Used for tab-panels:
517 var DTM_currentTabs = new Array();
520 // Check editing of page:
521 $this->editPageHandling();
522 $this->setStartupModule();
526 * Checking if the "&edit" variable was sent so we can open for editing the page.
527 * Code based on code from "alt_shortcut.php"
531 private function editPageHandling() {
533 if(!t3lib_extMgm
::isLoaded('cms')) {
538 $editId = preg_replace('/[^[:alnum:]_]/', '', t3lib_div
::_GET('edit'));
543 // Looking up the page to edit, checking permissions:
544 $where = ' AND ('.$GLOBALS['BE_USER']->getPagePermsClause(2)
545 .' OR '.$GLOBALS['BE_USER']->getPagePermsClause(16).')';
547 if(t3lib_div
::testInt($editId)) {
548 $editRecord = t3lib_BEfunc
::getRecordWSOL('pages', $editId, '*', $where);
550 $records = t3lib_BEfunc
::getRecordsByField('pages', 'alias', $editId, $where);
552 if(is_array($records)) {
554 $editRecord = current($records);
555 t3lib_BEfunc
::workspaceOL('pages', $editRecord);
559 // If the page was accessible, then let the user edit it.
560 if(is_array($editRecord) && $GLOBALS['BE_USER']->isInWebMount($editRecord['uid'])) {
561 // Setting JS code to open editing:
563 // Load page to edit:
564 window.setTimeout("top.loadEditId('.intval($editRecord['uid']).');", 500);
566 // Checking page edit parameter:
567 if(!$GLOBALS['BE_USER']->getTSConfigVal('options.shortcut_onEditId_dontSetPageTree')) {
569 // Expanding page tree:
570 t3lib_BEfunc
::openPageTree(intval($editRecord['pid']), !$GLOBALS['BE_USER']->getTSConfigVal('options.shortcut_onEditId_keepExistingExpanded'));
574 // Warning about page editing:
575 alert('.$GLOBALS['LANG']->JScharCode(sprintf($GLOBALS['LANG']->getLL('noEditPage'), $editId)).');
582 * Sets the startup module from either GETvars module and mpdParams or user configuration.
586 private function setStartupModule() {
587 $startModule = preg_replace('/[^[:alnum:]_]/', '', t3lib_div
::_GET('module'));
590 if ($GLOBALS['BE_USER']->uc
['startModule']) {
591 $startModule = $GLOBALS['BE_USER']->uc
['startModule'];
592 } else if($GLOBALS['BE_USER']->uc
['startInTaskCenter']) {
593 $startModule = 'user_task';
597 $moduleParameters = t3lib_div
::_GET('modParams');
601 function startInModule(modName, cMR_flag, addGetVars) { //
602 if ($(content) && top.goToModule) {
603 top.goToModule(modName, cMR_flag, addGetVars);
605 window.setTimeout(function() { startInModuleModule(modName, cMR_flag, addGetVars); }, 500);
609 // startInModule(\''.$startModule.'\', false, \''.$moduleParameters.'\');
610 '; //TODO get start module working
615 * generates the code for the TYPO3 logo, either the default TYPO3 logo or a custom one
617 * @return string HTML code snippet to display the TYPO3 logo
619 private function getLogo() {
620 $logo = '<a href="http://www.typo3.com/" target="_blank" onclick="'.$GLOBALS['TBE_TEMPLATE']->thisBlur().'">'.
621 '<img'.t3lib_iconWorks
::skinImg('','gfx/alt_backend_logo.gif','width="117" height="32"').' title="TYPO3 Content Management Framework" alt="" />'.
624 // overwrite with custom logo
625 if($GLOBALS['TBE_STYLES']['logo']) {
626 if(substr($GLOBALS['TBE_STYLES']['logo'], 0, 3) == '../') {
627 $imgInfo = @getimagesize
(PATH_site
.substr($GLOBALS['TBE_STYLES']['logo'], 3));
629 $logo = '<a href="http://www.typo3.com/" target="_blank" onclick="'.$GLOBALS['TBE_TEMPLATE']->thisBlur().'">'.
630 '<img src="'.$GLOBALS['TBE_STYLES']['logo'].'" '.$imgInfo[3].' title="TYPO3 Content Management Framework" alt="" />'.
638 * adds a javascript snippet to the backend
640 * @param string javascript snippet
643 public function addJavascript($javascript) {
644 // TODO do we need more checks?
645 if(!is_string($javascript)) {
646 throw new InvalidArgumentException('parameter $javascript must be of type string', 1195129553);
649 $this->js
.= $javascript;
653 * adds a javscript file to the backend after it has been checked that it exists
655 * @param string javascript file reference
658 public function addJavascriptFile($javascriptFile) {
659 //TODO add more checks if neccessary
661 if(file_exists(t3lib_div
::resolveBackPath(PATH_site
.$javascriptFile))) {
663 if(t3lib_div
::isFirstPartOfStr($javascriptFile, 'typo3/')) {
664 $javascriptFile = substr($javascriptFile, 6); // make relative to typo3/
667 $this->jsFiles
[] = $javascriptFile;
672 * adds a css snippet to the backend
674 * @param string css snippet
677 public function addCss($css) {
678 if(!is_string($css)) {
679 throw new InvalidArgumentException('parameter $css must be of type string', 1195129642);
686 * adds a css file to the backend after it has been checked that it exists
688 * @param string css file reference
691 public function addCssFile($cssFile) {
692 //TODO add more checks if neccessary
694 if(file_exists(t3lib_div
::resolveBackPath(PATH_site
.$cssFile))) {
696 if(t3lib_div
::isFirstPartOfStr($cssFile, 'typo3/')) {
697 $cssFile = substr($cssFile, 6); // make relative to typo3/
700 $this->cssFiles
[] = $cssFile;
705 * adds an item to the toolbar
707 * @param string toolbar item class reference, f.e. EXT:toolbarextension/class.tx_toolbarextension_coolitem.php:tx_toolbarExtension_coolItem
709 public function addToolbarItem($toolbarItemName, $toolbarItemClassReference) {
710 $toolbarItem = t3lib_div
::getUserObj($toolbarItemClassReference);
712 if(!($toolbarItem instanceof t3lib_backendToolbarItem
)) {
713 throw new UnexpectedValueException('$toolbarItem "'.$toolbarItemName.'" must implement interface t3lib_backendToolbarItem', 1195125501);
716 $toolbarItem->setBackend($this);
717 $this->toolbarItems
[$toolbarItemName] = $toolbarItem;
723 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE
]['XCLASS']['typo3/backend.php']) {
724 include_once($TYPO3_CONF_VARS[TYPO3_MODE
]['XCLASS']['typo3/backend.php']);
728 // document generation
729 $TYPO3backend = t3lib_div
::makeInstance('TYPO3backend');
731 // include extensions which may add css, javascript or toolbar items
732 if(is_array($GLOBALS['TYPO3_CONF_VARS']['typo3/backend.php']['additionalBackendItems'])) {
733 foreach($GLOBALS['TYPO3_CONF_VARS']['typo3/backend.php']['additionalBackendItems'] as $additionalBackendItem) {
734 include_once($additionalBackendItem);
738 $TYPO3backend->render();