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');
36 require('classes/class.workspaceselector.php');
37 require('classes/class.clearcachemenu.php');
38 require('classes/class.shortcutmenu.php');
39 require('classes/class.backendsearchmenu.php');
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');
48 * Class for rendering the TYPO3 backend version 4.2+
50 * @author Ingo Renner <ingo@typo3.org>
62 * Object for loading backend modules
64 * @var t3lib_loadModules
66 private $moduleLoader;
69 * module menu generating object
75 private $leftMenuWidth;
78 private $toolbarItems;
85 public function __construct() {
86 // Initializes the backend modules structure for use later.
87 $this->moduleLoader
= t3lib_div
::makeInstance('t3lib_loadModules');
88 $this->moduleLoader
->load($GLOBALS['TBE_MODULES']);
90 $this->moduleMenu
= t3lib_div
::makeInstance('ModuleMenu');
92 // Check for distances defined in the styles array:
93 if ($TBE_STYLES['dims']['leftMenuFrameW']) {
94 $this->leftMenuWidth
= $TBE_STYLES['dims']['leftMenuFrameW'];
96 if ($TBE_STYLES['dims']['topFrameH']) {
97 $this->topHeight
= $TBE_STYLES['dims']['topFrameH'];
99 if ($TBE_STYLES['dims']['selMenuFrame']) {
100 $this->selectMenu
= $TBE_STYLES['dims']['selMenuFrame'];
103 // add default BE javascript
105 $this->jsFiles
= array(
106 'contrib/prototype/prototype.js',
107 'contrib/scriptaculous/scriptaculous.js?load=builder,effects,controls,dragdrop',
113 'js/toolbarmanager.js',
114 '../t3lib/jsfunc.evalfield.js'
117 // add default BE css
118 $this->cssFiles
= array(
119 'css/backend-scaffolding.css',
120 'css/backend-style.css',
121 'css/verticalmenu.css'
124 $this->toolbarItems
= array();
125 $this->initializeCoreToolbarItems();
129 * initializes the core toolbar items
133 private function initializeCoreToolbarItems() {
135 $coreToolbarItems = array(
136 'workspaceSelector' => 'WorkspaceSelector',
137 'clearCacheActions' => 'ClearCacheMenu',
138 'shortcuts' => 'ShortcutMenu',
139 'backendSearch' => 'BackendSearchMenu'
142 foreach($coreToolbarItems as $toolbarItemName => $toolbarItemClass) {
143 $toolbarItem = t3lib_div
::makeInstance($toolbarItemClass);
145 if(!($toolbarItem instanceof backend_toolbarItem
)) {
146 throw new UnexpectedValueException('$toolbarItem "'.$toolbarItemName.'" must implement interface backend_toolbarItem', 1195126772);
149 $toolbarItem->setBackend($this);
150 $this->toolbarItems
[$toolbarItemName] = $toolbarItem;
155 * main function generating the BE scaffolding
159 public function render() {
161 // prepare the scaffolding, at this point extension still may addjavascript and css
162 $logo = t3lib_div
::makeInstance('TYPO3Logo');
163 $logo->setLogo('gfx/typo3logo_mini.png');
165 $menu = $this->moduleMenu
->render();
168 // create backend scaffolding
169 $backendScaffolding = '
170 <div id="typo3-backend">
171 <div id="typo3-top-container">
172 <div id="typo3-logo">'.$logo->render().'</div>
173 <div id="typo3-top" class="typo3-top-toolbar">'
174 .$this->renderToolbar()
177 <div id="typo3-main-container">
178 <div id="typo3-side-menu">
181 <div id="typo3-content">
182 <iframe src="alt_intro.php" name="content" id="content" marginwidth="0" marginheight="0" frameborder="0" scrolling="auto" noresize="noresize"></iframe>
189 /******************************************************
190 * now put the complete backend document together
191 ******************************************************/
194 $GLOBALS['TBE_TEMPLATE']->docType
= 'xhtml_trans';
197 foreach($this->jsFiles
as $jsFile) {
198 $GLOBALS['TBE_TEMPLATE']->JScode
.= '
199 <script type="text/javascript" src="'.$jsFile.'"></script>';
201 $GLOBALS['TBE_TEMPLATE']->JScode
.= chr(10);
202 $this->generateJavascript();
203 $GLOBALS['TBE_TEMPLATE']->JScode
.= $GLOBALS['TBE_TEMPLATE']->wrapScriptTags($this->js
);
205 // abusing the JS container to add CSS
206 // TODO fix template.php
207 foreach($this->cssFiles
as $cssFile) {
208 $GLOBALS['TBE_TEMPLATE']->JScode
.= '
209 <link rel="stylesheet" type="text/css" href="'.$cssFile.'" />
212 // TODO add CSS from $this->css
214 // set document title
215 $title = $TYPO3_CONF_VARS['SYS']['sitename'] ?
216 $TYPO3_CONF_VARS['SYS']['sitename'].' [TYPO3 '.TYPO3_version
.']'
217 : 'TYPO3 '.TYPO3_version
;
219 // start page header:
220 $this->content
.= $GLOBALS['TBE_TEMPLATE']->startPage($title);
221 $this->content
.= $GLOBALS['TBE_TEMPLATE']->endPage();
223 $this->content
.= $backendScaffolding;
229 * renders the items in the top toolbar
231 * @return string top toolbar elements as HTML
233 private function renderToolbar() {
234 $toolbar = '<ul id="typo3-toolbar">';
235 $toolbar.= '<li>'.$this->getLoggedInUserLabel().'</li>
236 <li><div id="logout-button" class="toolbar-item no-separator">'.$this->moduleMenu
->renderLogoutButton().'</div></li>';
238 foreach($this->toolbarItems
as $toolbarItem) {
239 $additionalAttributes = $toolbarItem->getAdditionalAttributes();
241 $toolbar .= '<li'.$additionalAttributes.'>'.$toolbarItem->render().'</li>';
244 return $toolbar.'</ul>';
248 * gets the label of the currently loged in BE user
250 * @return string html code snippet displaying the currently logged in user
252 private function getLoggedInUserLabel() {
253 $username = '<div id="username" class="toolbar-item no-separator">['.htmlspecialchars($GLOBALS['BE_USER']->user
['username']).']</div>';;
256 if($BE_USER->user
['ses_backuserid']) {
257 $username = '<div id="username" class="toolbar-item no-separator typo3-red-background">[SU: '.htmlspecialchars($GLOBALS['BE_USER']->user
['username']).']</div>';
264 * Generates the JavaScript code for the backend.
268 private function generateJavascript() {
270 $pathTYPO3 = t3lib_div
::dirname(t3lib_div
::getIndpEnv('SCRIPT_NAME')).'/';
271 $goToModuleSwitch = $this->moduleMenu
->getGotoModuleJavascript();
272 $moduleFramesHelper = implode(chr(10), $this->moduleMenu
->getFsMod());
274 // If another page module was specified, replace the default Page module with the new one
275 $newPageModule = trim($GLOBALS['BE_USER']->getTSConfigVal('options.overridePageModule'));
276 $pageModule = t3lib_BEfunc
::isModuleSetInTBE_MODULES($newPageModule) ?
$newPageModule : 'web_layout';
278 $menuFrameName = 'menu';
279 if($GLOBALS['BE_USER']->uc
['noMenuMode'] === 'icons') {
280 $menuFrameName = 'topmenuFrame';
285 * Function similar to PHPs rawurlencode();
287 function rawurlencode(str) { //
288 var output = escape(str);
289 output = str_replace("*","%2A", output);
290 output = str_replace("+","%2B", output);
291 output = str_replace("/","%2F", output);
292 output = str_replace("@","%40", output);
297 * String-replace function
299 function str_replace(match,replace,string) { //
300 var input = ""+string;
301 var matchStr = ""+match;
302 if (!matchStr) {return string;}
305 var pos = input.indexOf(matchStr);
307 output+=""+input.substr(pointer, pos-pointer)+replace;
308 pointer=pos+matchStr.length;
309 pos = input.indexOf(match,pos+1);
311 output+=""+input.substr(pointer);
318 function typoSetup() { //
319 this.PATH_typo3 = "'.$pathTYPO3.'";
320 this.PATH_typo3_enc = "'.rawurlencode($pathTYPO3).'";
321 this.username = "'.$GLOBALS['BE_USER']->user
['username'].'";
322 this.uniqueID = "'.t3lib_div
::shortMD5(uniqid('')).'";
323 this.navFrameWidth = 0;
325 var TS = new typoSetup();
328 * Functions for session-expiry detection:
331 this.loginRefreshed = busy_loginRefreshed;
332 this.checkLoginTimeout = busy_checkLoginTimeout;
333 this.openRefreshWindow = busy_OpenRefreshWindow;
336 this.reloginCancelled=0;
338 function busy_loginRefreshed() { //
339 var date = new Date();
340 this.busyloadTime = Math.floor(date.getTime()/1000);
343 function busy_checkLoginTimeout() { //
344 var date = new Date();
345 var theTime = Math.floor(date.getTime()/1000);
346 if (theTime > this.busyloadTime+'.intval($GLOBALS['BE_USER']->auth_timeout_field
).'-30) {
350 function busy_OpenRefreshWindow() { //
351 vHWin=window.open("login_frameset.php","relogin_"+TS.uniqueID,"height=350,width=700,status=0,menubar=0,location=1");
355 function busy_checkLoginTimeout_timer() { //
356 if (busy.checkLoginTimeout() && !busy.reloginCancelled && !busy.openRefreshW) {
357 if (confirm('.$GLOBALS['LANG']->JScharCode($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:mess.refresh_login')).')) {
358 busy.openRefreshWindow();
360 busy.reloginCancelled = 1;
363 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())
365 // 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!)
366 if (top && top.content && top.content.nav_frame && top.content.nav_frame.document && top.content.nav_frame.document.body) {
367 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;
372 * Launcing information window for records/files (fileref as "table" argument)
374 function launchView(table,uid,bP) { //
375 var backPath= bP ? bP : "";
376 var thePreviewWindow="";
377 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");
378 if (thePreviewWindow && thePreviewWindow.focus) {
379 thePreviewWindow.focus();
384 * Opens plain window with url
386 function openUrlInWindow(url,windowName) { //
387 regularWindow = window.open(url,windowName,"status=1,menubar=1,resizable=1,location=1,directories=0,scrollbars=1,toolbar=1");
388 regularWindow.focus();
393 * Loads a URL in the topmenuFrame
395 function loadTopMenu(url) { //
396 top.topmenuFrame.location = url;
400 * Loads a page id for editing in the page edit module:
402 function loadEditId(id,addGetVars) { //
403 top.fsMod.recentIds["web"]=id;
404 top.fsMod.navFrameHighlightedID["web"]="pages"+id+"_0"; // For highlighting
406 if (top.content && top.content.nav_frame && top.content.nav_frame.refresh_nav) {
407 top.content.nav_frame.refresh_nav();
410 top.goToModule("'.$pageModule.'", 0, addGetVars?addGetVars:"");
414 * Returns incoming URL (to a module) unless nextLoadModuleUrl is set. If that is the case nextLoadModuleUrl is returned (and cleared)
415 * Used by the shortcut frame to set a "intermediate URL"
417 var nextLoadModuleUrl="";
418 function getModuleUrl(inUrl) { //
420 if (top.nextLoadModuleUrl) {
421 nMU=top.nextLoadModuleUrl;
422 top.nextLoadModuleUrl="";
430 * Print properties of an object
432 function debugObj(obj,name) { //
436 acc+=i+": "+obj[i]+"\n";
439 alert("Object: "+name+"\n\n"+acc);
443 * Initialize login expiration warning object
445 var busy = new busy();
446 busy.loginRefreshed();
447 busy_checkLoginTimeout_timer();
453 var currentlyHighLightedId = "";
454 var currentlyHighLighted_restoreValue = "";
455 var currentlyHighLightedMain = "";
456 function highlightModuleMenuItem(trId, mainModule) { //
457 currentlyHighLightedMain = mainModule;
458 // Get document object:
459 if (top.menu && top.menu.document) {
460 var docObj = top.menu.document;
461 var HLclass = mainModule ? "c-mainitem-HL" : "c-subitem-row-HL";
462 } else if (top.topmenuFrame && top.topmenuFrame.document) {
463 var docObj = top.topmenuFrame.document;
464 var HLclass = mainModule ? "c-mainitem-HL" : "c-subitem-HL";
469 if (currentlyHighLightedId && docObj.getElementById(currentlyHighLightedId)) {
470 docObj.getElementById(currentlyHighLightedId).attributes.getNamedItem("class").nodeValue = currentlyHighLighted_restoreValue;
473 currentlyHighLightedId = trId;
474 if (currentlyHighLightedId && docObj.getElementById(currentlyHighLightedId)) {
475 var classAttribObject = docObj.getElementById(currentlyHighLightedId).attributes.getNamedItem("class");
476 currentlyHighLighted_restoreValue = classAttribObject.nodeValue;
477 classAttribObject.nodeValue = HLclass;
483 * Function restoring previous selection in left menu after clearing cache
485 function restoreHighlightedModuleMenuItem() { //
486 if (currentlyHighLightedId) {
487 highlightModuleMenuItem(currentlyHighLightedId,currentlyHighLightedMain);
491 '.$goToModuleSwitch.'
494 * reloads the menu frame
496 function refreshMenu() {
497 top.'.$menuFrameName.'.location.href = top.'.$menuFrameName.'.document.URL
501 * Frameset Module object
503 * Used in main modules with a frameset for submodules to keep the ID between modules
504 * Typically that is set by something like this in a Web>* sub module:
505 * if (top.fsMod) top.fsMod.recentIds["web"] = "\'.intval($this->id).\'";
506 * if (top.fsMod) top.fsMod.recentIds["file"] = "...(file reference/string)...";
508 function fsModules() { //
509 this.recentIds=new Array(); // used by frameset modules to track the most recent used id for list frame.
510 this.navFrameHighlightedID=new Array(); // used by navigation frames to track which row id was highlighted last time
511 this.currentMainLoaded="";
512 this.currentBank="0";
514 var fsMod = new fsModules();
515 '.$moduleFramesHelper.'
517 // Used by Frameset Modules
518 var condensedMode = '.($GLOBALS['BE_USER']->uc
['condensedMode']?
1:0).';
519 var currentSubScript = "";
520 var currentSubNavScript = "";
522 // Used for tab-panels:
523 var DTM_currentTabs = new Array();
526 // Check editing of page:
527 $this->editPageHandling();
528 $this->setStartupModule();
532 * Checking if the "&edit" variable was sent so we can open for editing the page.
533 * Code based on code from "alt_shortcut.php"
537 private function editPageHandling() {
539 if(!t3lib_extMgm
::isLoaded('cms')) {
544 $editId = preg_replace('/[^[:alnum:]_]/', '', t3lib_div
::_GET('edit'));
549 // Looking up the page to edit, checking permissions:
550 $where = ' AND ('.$GLOBALS['BE_USER']->getPagePermsClause(2)
551 .' OR '.$GLOBALS['BE_USER']->getPagePermsClause(16).')';
553 if(t3lib_div
::testInt($editId)) {
554 $editRecord = t3lib_BEfunc
::getRecordWSOL('pages', $editId, '*', $where);
556 $records = t3lib_BEfunc
::getRecordsByField('pages', 'alias', $editId, $where);
558 if(is_array($records)) {
560 $editRecord = current($records);
561 t3lib_BEfunc
::workspaceOL('pages', $editRecord);
565 // If the page was accessible, then let the user edit it.
566 if(is_array($editRecord) && $GLOBALS['BE_USER']->isInWebMount($editRecord['uid'])) {
567 // Setting JS code to open editing:
569 // Load page to edit:
570 window.setTimeout("top.loadEditId('.intval($editRecord['uid']).');", 500);
572 // Checking page edit parameter:
573 if(!$GLOBALS['BE_USER']->getTSConfigVal('options.shortcut_onEditId_dontSetPageTree')) {
575 // Expanding page tree:
576 t3lib_BEfunc
::openPageTree(intval($editRecord['pid']), !$GLOBALS['BE_USER']->getTSConfigVal('options.shortcut_onEditId_keepExistingExpanded'));
580 // Warning about page editing:
581 alert('.$GLOBALS['LANG']->JScharCode(sprintf($GLOBALS['LANG']->getLL('noEditPage'), $editId)).');
588 * Sets the startup module from either GETvars module and mpdParams or user configuration.
592 private function setStartupModule() {
593 $startModule = preg_replace('/[^[:alnum:]_]/', '', t3lib_div
::_GET('module'));
596 if ($GLOBALS['BE_USER']->uc
['startModule']) {
597 $startModule = $GLOBALS['BE_USER']->uc
['startModule'];
598 } else if($GLOBALS['BE_USER']->uc
['startInTaskCenter']) {
599 $startModule = 'user_task';
603 $moduleParameters = t3lib_div
::_GET('modParams');
607 function startInModule(modName, cMR_flag, addGetVars) { //
608 if ($(content) && top.goToModule) {
609 top.goToModule(modName, cMR_flag, addGetVars);
611 window.setTimeout(function() { startInModuleModule(modName, cMR_flag, addGetVars); }, 500);
615 // startInModule(\''.$startModule.'\', false, \''.$moduleParameters.'\');
616 '; //TODO get start module working
621 * generates the code for the TYPO3 logo, either the default TYPO3 logo or a custom one
623 * @return string HTML code snippet to display the TYPO3 logo
625 private function getLogo() {
626 $logo = '<a href="http://www.typo3.com/" target="_blank" onclick="'.$GLOBALS['TBE_TEMPLATE']->thisBlur().'">'.
627 '<img'.t3lib_iconWorks
::skinImg('','gfx/alt_backend_logo.gif','width="117" height="32"').' title="TYPO3 Content Management Framework" alt="" />'.
630 // overwrite with custom logo
631 if($GLOBALS['TBE_STYLES']['logo']) {
632 if(substr($GLOBALS['TBE_STYLES']['logo'], 0, 3) == '../') {
633 $imgInfo = @getimagesize
(PATH_site
.substr($GLOBALS['TBE_STYLES']['logo'], 3));
635 $logo = '<a href="http://www.typo3.com/" target="_blank" onclick="'.$GLOBALS['TBE_TEMPLATE']->thisBlur().'">'.
636 '<img src="'.$GLOBALS['TBE_STYLES']['logo'].'" '.$imgInfo[3].' title="TYPO3 Content Management Framework" alt="" />'.
644 * adds a javascript snippet to the backend
646 * @param string javascript snippet
649 public function addJavascript($javascript) {
650 // TODO do we need more checks?
651 if(!is_string($javascript)) {
652 throw new InvalidArgumentException('parameter $javascript must be of type string', 1195129553);
655 $this->js
.= $javascript;
659 * adds a javscript file to the backend after it has been checked that it exists
661 * @param string javascript file reference
664 public function addJavascriptFile($javascriptFile) {
665 //TODO add more checks if neccessary
667 if(file_exists(t3lib_div
::resolveBackPath(PATH_site
.$javascriptFile))) {
669 if(t3lib_div
::isFirstPartOfStr($javascriptFile, 'typo3/')) {
670 $javascriptFile = substr($javascriptFile, 6); // make relative to typo3/
673 $this->jsFiles
[] = $javascriptFile;
678 * adds a css snippet to the backend
680 * @param string css snippet
683 public function addCss($css) {
684 if(!is_string($css)) {
685 throw new InvalidArgumentException('parameter $css must be of type string', 1195129642);
692 * adds a css file to the backend after it has been checked that it exists
694 * @param string css file reference
697 public function addCssFile($cssFile) {
698 //TODO add more checks if neccessary
700 if(file_exists(t3lib_div
::resolveBackPath(PATH_site
.$cssFile))) {
702 if(t3lib_div
::isFirstPartOfStr($cssFile, 'typo3/')) {
703 $cssFile = substr($cssFile, 6); // make relative to typo3/
706 $this->cssFiles
[] = $cssFile;
711 * adds an item to the toolbar
713 * @param string toolbar item class reference, f.e. EXT:toolbarextension/class.tx_toolbarextension_coolitem.php:tx_toolbarExtension_coolItem
715 public function addToolbarItem($toolbarItemName, $toolbarItemClassReference) {
716 $toolbarItem = t3lib_div
::getUserObj($toolbarItemClassReference);
718 if(!($toolbarItem instanceof t3lib_backendToolbarItem
)) {
719 throw new UnexpectedValueException('$toolbarItem "'.$toolbarItemName.'" must implement interface t3lib_backendToolbarItem', 1195125501);
722 $toolbarItem->setBackend($this);
723 $this->toolbarItems
[$toolbarItemName] = $toolbarItem;
729 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE
]['XCLASS']['typo3/backend.php']) {
730 include_once($TYPO3_CONF_VARS[TYPO3_MODE
]['XCLASS']['typo3/backend.php']);
734 // document generation
735 $TYPO3backend = t3lib_div
::makeInstance('TYPO3backend');
737 // include extensions which may add css, javascript or toolbar items
738 if(is_array($GLOBALS['TYPO3_CONF_VARS']['typo3/backend.php']['additionalBackendItems'])) {
739 foreach($GLOBALS['TYPO3_CONF_VARS']['typo3/backend.php']['additionalBackendItems'] as $additionalBackendItem) {
740 include_once($additionalBackendItem);
744 $TYPO3backend->render();