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');
35 require ('classes/class.clearcachemenu.php');
37 require_once (PATH_t3lib
.'class.t3lib_loadmodules.php');
38 require_once (PATH_t3lib
.'class.t3lib_basicfilefunc.php');
39 require_once ('class.alt_menu_functions.inc');
40 $GLOBALS['LANG']->includeLLFile('EXT:lang/locallang_misc.xml');
44 * Class for rendering the TYPO3 backend version 4.2+
46 * @author Ingo Renner <ingo@typo3.org>
58 * Object for loading backend modules
60 * @var t3lib_loadModules
62 private $moduleLoader;
65 * module menu generating object
71 private $leftMenuWidth;
74 private $toolbarItems;
81 public function __construct() {
82 // Initializes the backend modules structure for use later.
83 $this->moduleLoader
= t3lib_div
::makeInstance('t3lib_loadModules');
84 $this->moduleLoader
->load($GLOBALS['TBE_MODULES']);
86 $this->moduleMenu
= t3lib_div
::makeInstance('ModuleMenu');
88 // Check for distances defined in the styles array:
89 if ($TBE_STYLES['dims']['leftMenuFrameW']) {
90 $this->leftMenuWidth
= $TBE_STYLES['dims']['leftMenuFrameW'];
92 if ($TBE_STYLES['dims']['topFrameH']) {
93 $this->topHeight
= $TBE_STYLES['dims']['topFrameH'];
95 if ($TBE_STYLES['dims']['selMenuFrame']) {
96 $this->selectMenu
= $TBE_STYLES['dims']['selMenuFrame'];
99 // add default BE javascript
101 $this->jsFiles
= array(
102 'contrib/prototype/prototype.js',
103 'contrib/scriptaculous/scriptaculous.js?load=builder,effects,controls,dragdrop',
106 '../t3lib/jsfunc.evalfield.js'
109 // add default BE css
110 $this->cssFiles
= array(
111 'css/backend-scaffolding.css',
112 'css/backend-style.css',
113 'css/verticalmenu.css'
116 $this->toolbarItems
= array();
117 $this->initializeCoreToolbarItems();
121 * initializes the core toolbar items
125 private function initializeCoreToolbarItems() {
127 $coreToolbarItems = array(
128 'workspaceSelector' => 'WorkspaceSelector',
129 'clearCacheActions' => 'ClearCacheMenu'
131 'backendSearch' => '',
136 foreach($coreToolbarItems as $toolbarItemName => $toolbarItemClass) {
137 $toolbarItem = t3lib_div
::makeInstance($toolbarItemClass);
139 if(!($toolbarItem instanceof backend_toolbarItem
)) {
140 throw new UnexpectedValueException('$toolbarItem "'.$toolbarItemName.'" must implement interface backend_toolbarItem', 1195126772);
143 $toolbarItem->setBackend($this);
144 $this->toolbarItems
[$toolbarItemName] = $toolbarItem;
149 * main function generating the BE scaffolding
153 public function render() {
155 // prepare the scaffolding, at this point extension still may addjavascript and css
156 $logo = t3lib_div
::makeInstance('TYPO3Logo');
157 $logo->setLogo('gfx/typo3logo_mini.png');
159 $menu = $this->moduleMenu
->render();
160 $logout = $this->moduleMenu
->renderLogoutButton();
161 $loginInfo = $this->getLoggedInUserLabel();
163 // create backend scaffolding
164 $backendScaffolding = '
165 <div id="typo3-backend">
166 <div id="typo3-top-container">
167 <div id="typo3-logo">'.$logo->render().'</div>
168 <div id="typo3-top" class="typo3-top-toolbar">'
169 .$this->renderToolbar()
172 <div id="typo3-main-container">
173 <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() {
232 $toolbar = '<ul id="typo3-toolbar">';
234 $toolbarItems = $this->toolbarItems
;
236 foreach($toolbarItems as $toolbarItem) {
237 $additionalAttributes = $toolbarItem->getAdditionalAttributes();
239 $toolbar .= '<li'.$additionalAttributes.'>'.$toolbarItem->render().'</li>';
242 return $toolbar.'</ul>';
246 * gets the label of the currently loged in BE user
248 * @return string html code snippet displaying the currently logged in user
250 private function getLoggedInUserLabel() {
251 $username = '<p id="username">['.htmlspecialchars($GLOBALS['BE_USER']->user
['username']).']</p>';;
254 if($BE_USER->user
['ses_backuserid']) {
255 $username = '<p id="username" class="typo3-red-background">[SU: '.htmlspecialchars($GLOBALS['BE_USER']->user
['username']).']</p>';
258 return '<div id="login-info">'.$username.'</div>';
262 * Generates the JavaScript code for the backend.
266 private function generateJavascript() {
268 $pathTYPO3 = t3lib_div
::dirname(t3lib_div
::getIndpEnv('SCRIPT_NAME')).'/';
269 $goToModuleSwitch = $this->moduleMenu
->getGotoModuleJavascript();
270 $moduleFramesHelper = implode(chr(10), $this->moduleMenu
->getFsMod());
272 // If another page module was specified, replace the default Page module with the new one
273 $newPageModule = trim($GLOBALS['BE_USER']->getTSConfigVal('options.overridePageModule'));
274 $pageModule = t3lib_BEfunc
::isModuleSetInTBE_MODULES($newPageModule) ?
$newPageModule : 'web_layout';
276 $menuFrameName = 'menu';
277 if($GLOBALS['BE_USER']->uc
['noMenuMode'] === 'icons') {
278 $menuFrameName = 'topmenuFrame';
283 * Function similar to PHPs rawurlencode();
285 function rawurlencode(str) { //
286 var output = escape(str);
287 output = str_replace("*","%2A", output);
288 output = str_replace("+","%2B", output);
289 output = str_replace("/","%2F", output);
290 output = str_replace("@","%40", output);
295 * String-replace function
297 function str_replace(match,replace,string) { //
298 var input = ""+string;
299 var matchStr = ""+match;
300 if (!matchStr) {return string;}
303 var pos = input.indexOf(matchStr);
305 output+=""+input.substr(pointer, pos-pointer)+replace;
306 pointer=pos+matchStr.length;
307 pos = input.indexOf(match,pos+1);
309 output+=""+input.substr(pointer);
316 function typoSetup() { //
317 this.PATH_typo3 = "'.$pathTYPO3.'";
318 this.PATH_typo3_enc = "'.rawurlencode($pathTYPO3).'";
319 this.username = "'.$GLOBALS['BE_USER']->user
['username'].'";
320 this.uniqueID = "'.t3lib_div
::shortMD5(uniqid('')).'";
321 this.navFrameWidth = 0;
323 var TS = new typoSetup();
326 * Functions for session-expiry detection:
329 this.loginRefreshed = busy_loginRefreshed;
330 this.checkLoginTimeout = busy_checkLoginTimeout;
331 this.openRefreshWindow = busy_OpenRefreshWindow;
334 this.reloginCancelled=0;
336 function busy_loginRefreshed() { //
337 var date = new Date();
338 this.busyloadTime = Math.floor(date.getTime()/1000);
341 function busy_checkLoginTimeout() { //
342 var date = new Date();
343 var theTime = Math.floor(date.getTime()/1000);
344 if (theTime > this.busyloadTime+'.intval($GLOBALS['BE_USER']->auth_timeout_field
).'-30) {
348 function busy_OpenRefreshWindow() { //
349 vHWin=window.open("login_frameset.php","relogin_"+TS.uniqueID,"height=350,width=700,status=0,menubar=0,location=1");
353 function busy_checkLoginTimeout_timer() { //
354 if (busy.checkLoginTimeout() && !busy.reloginCancelled && !busy.openRefreshW) {
355 if (confirm('.$GLOBALS['LANG']->JScharCode($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:mess.refresh_login')).')) {
356 busy.openRefreshWindow();
358 busy.reloginCancelled = 1;
361 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())
363 // 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!)
364 if (top && top.content && top.content.nav_frame && top.content.nav_frame.document && top.content.nav_frame.document.body) {
365 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;
370 * Launcing information window for records/files (fileref as "table" argument)
372 function launchView(table,uid,bP) { //
373 var backPath= bP ? bP : "";
374 var thePreviewWindow="";
375 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");
376 if (thePreviewWindow && thePreviewWindow.focus) {
377 thePreviewWindow.focus();
382 * Opens plain window with url
384 function openUrlInWindow(url,windowName) { //
385 regularWindow = window.open(url,windowName,"status=1,menubar=1,resizable=1,location=1,directories=0,scrollbars=1,toolbar=1");
386 regularWindow.focus();
391 * Loads a URL in the topmenuFrame
393 function loadTopMenu(url) { //
394 top.topmenuFrame.location = url;
398 * Loads a page id for editing in the page edit module:
400 function loadEditId(id,addGetVars) { //
401 top.fsMod.recentIds["web"]=id;
402 top.fsMod.navFrameHighlightedID["web"]="pages"+id+"_0"; // For highlighting
404 if (top.content && top.content.nav_frame && top.content.nav_frame.refresh_nav) {
405 top.content.nav_frame.refresh_nav();
408 top.goToModule("'.$pageModule.'", 0, addGetVars?addGetVars:"");
412 * Returns incoming URL (to a module) unless nextLoadModuleUrl is set. If that is the case nextLoadModuleUrl is returned (and cleared)
413 * Used by the shortcut frame to set a "intermediate URL"
415 var nextLoadModuleUrl="";
416 function getModuleUrl(inUrl) { //
418 if (top.nextLoadModuleUrl) {
419 nMU=top.nextLoadModuleUrl;
420 top.nextLoadModuleUrl="";
428 * Print properties of an object
430 function debugObj(obj,name) { //
434 acc+=i+": "+obj[i]+"\n";
437 alert("Object: "+name+"\n\n"+acc);
441 * Initialize login expiration warning object
443 var busy = new busy();
444 busy.loginRefreshed();
445 busy_checkLoginTimeout_timer();
451 var currentlyHighLightedId = "";
452 var currentlyHighLighted_restoreValue = "";
453 var currentlyHighLightedMain = "";
454 function highlightModuleMenuItem(trId, mainModule) { //
455 currentlyHighLightedMain = mainModule;
456 // Get document object:
457 if (top.menu && top.menu.document) {
458 var docObj = top.menu.document;
459 var HLclass = mainModule ? "c-mainitem-HL" : "c-subitem-row-HL";
460 } else if (top.topmenuFrame && top.topmenuFrame.document) {
461 var docObj = top.topmenuFrame.document;
462 var HLclass = mainModule ? "c-mainitem-HL" : "c-subitem-HL";
467 if (currentlyHighLightedId && docObj.getElementById(currentlyHighLightedId)) {
468 docObj.getElementById(currentlyHighLightedId).attributes.getNamedItem("class").nodeValue = currentlyHighLighted_restoreValue;
471 currentlyHighLightedId = trId;
472 if (currentlyHighLightedId && docObj.getElementById(currentlyHighLightedId)) {
473 var classAttribObject = docObj.getElementById(currentlyHighLightedId).attributes.getNamedItem("class");
474 currentlyHighLighted_restoreValue = classAttribObject.nodeValue;
475 classAttribObject.nodeValue = HLclass;
481 * Function restoring previous selection in left menu after clearing cache
483 function restoreHighlightedModuleMenuItem() { //
484 if (currentlyHighLightedId) {
485 highlightModuleMenuItem(currentlyHighLightedId,currentlyHighLightedMain);
489 '.$goToModuleSwitch.'
492 * reloads the menu frame
494 function refreshMenu() {
495 top.'.$menuFrameName.'.location.href = top.'.$menuFrameName.'.document.URL
499 * Frameset Module object
501 * Used in main modules with a frameset for submodules to keep the ID between modules
502 * Typically that is set by something like this in a Web>* sub module:
503 * if (top.fsMod) top.fsMod.recentIds["web"] = "\'.intval($this->id).\'";
504 * if (top.fsMod) top.fsMod.recentIds["file"] = "...(file reference/string)...";
506 function fsModules() { //
507 this.recentIds=new Array(); // used by frameset modules to track the most recent used id for list frame.
508 this.navFrameHighlightedID=new Array(); // used by navigation frames to track which row id was highlighted last time
509 this.currentMainLoaded="";
510 this.currentBank="0";
512 var fsMod = new fsModules();
513 '.$moduleFramesHelper.'
515 // Used by Frameset Modules
516 var condensedMode = '.($GLOBALS['BE_USER']->uc
['condensedMode']?
1:0).';
517 var currentSubScript = "";
518 var currentSubNavScript = "";
520 // Used for tab-panels:
521 var DTM_currentTabs = new Array();
524 // Check editing of page:
525 $this->editPageHandling();
526 $this->setStartupModule();
530 * Checking if the "&edit" variable was sent so we can open for editing the page.
531 * Code based on code from "alt_shortcut.php"
535 private function editPageHandling() {
537 if(!t3lib_extMgm
::isLoaded('cms')) {
542 $editId = preg_replace('/[^[:alnum:]_]/', '', t3lib_div
::_GET('edit'));
547 // Looking up the page to edit, checking permissions:
548 $where = ' AND ('.$GLOBALS['BE_USER']->getPagePermsClause(2)
549 .' OR '.$GLOBALS['BE_USER']->getPagePermsClause(16).')';
551 if(t3lib_div
::testInt($editId)) {
552 $editRecord = t3lib_BEfunc
::getRecordWSOL('pages', $editId, '*', $where);
554 $records = t3lib_BEfunc
::getRecordsByField('pages', 'alias', $editId, $where);
556 if(is_array($records)) {
558 $editRecord = current($records);
559 t3lib_BEfunc
::workspaceOL('pages', $editRecord);
563 // If the page was accessible, then let the user edit it.
564 if(is_array($editRecord) && $GLOBALS['BE_USER']->isInWebMount($editRecord['uid'])) {
565 // Setting JS code to open editing:
567 // Load page to edit:
568 window.setTimeout("top.loadEditId('.intval($editRecord['uid']).');", 500);
570 // Checking page edit parameter:
571 if(!$GLOBALS['BE_USER']->getTSConfigVal('options.shortcut_onEditId_dontSetPageTree')) {
573 // Expanding page tree:
574 t3lib_BEfunc
::openPageTree(intval($editRecord['pid']), !$GLOBALS['BE_USER']->getTSConfigVal('options.shortcut_onEditId_keepExistingExpanded'));
578 // Warning about page editing:
579 alert('.$GLOBALS['LANG']->JScharCode(sprintf($GLOBALS['LANG']->getLL('noEditPage'), $editId)).');
586 * Sets the startup module from either GETvars module and mpdParams or user configuration.
590 private function setStartupModule() {
591 $startModule = preg_replace('/[^[:alnum:]_]/', '', t3lib_div
::_GET('module'));
594 if ($GLOBALS['BE_USER']->uc
['startModule']) {
595 $startModule = $GLOBALS['BE_USER']->uc
['startModule'];
596 } else if($GLOBALS['BE_USER']->uc
['startInTaskCenter']) {
597 $startModule = 'user_task';
601 $moduleParameters = t3lib_div
::_GET('modParams');
605 function startInModule(modName, cMR_flag, addGetVars) { //
606 if ($(content) && top.goToModule) {
607 top.goToModule(modName, cMR_flag, addGetVars);
609 window.setTimeout(function() { startInModuleModule(modName, cMR_flag, addGetVars); }, 500);
613 // startInModule(\''.$startModule.'\', false, \''.$moduleParameters.'\');
614 '; //TODO get start module working
619 * generates the code for the TYPO3 logo, either the default TYPO3 logo or a custom one
621 * @return string HTML code snippet to display the TYPO3 logo
623 private function getLogo() {
624 $logo = '<a href="http://www.typo3.com/" target="_blank" onclick="'.$GLOBALS['TBE_TEMPLATE']->thisBlur().'">'.
625 '<img'.t3lib_iconWorks
::skinImg('','gfx/alt_backend_logo.gif','width="117" height="32"').' title="TYPO3 Content Management Framework" alt="" />'.
628 // overwrite with custom logo
629 if($GLOBALS['TBE_STYLES']['logo']) {
630 if(substr($GLOBALS['TBE_STYLES']['logo'], 0, 3) == '../') {
631 $imgInfo = @getimagesize
(PATH_site
.substr($GLOBALS['TBE_STYLES']['logo'], 3));
633 $logo = '<a href="http://www.typo3.com/" target="_blank" onclick="'.$GLOBALS['TBE_TEMPLATE']->thisBlur().'">'.
634 '<img src="'.$GLOBALS['TBE_STYLES']['logo'].'" '.$imgInfo[3].' title="TYPO3 Content Management Framework" alt="" />'.
642 * adds a javascript snippet to the backend
644 * @param string javascript snippet
647 public function addJavascript($javascript) {
648 // TODO do we need more checks?
649 if(!is_string($javascript)) {
650 throw new InvalidArgumentException('parameter $javascript must be of type string', 1195129553);
653 $this->js
.= $javascript;
657 * adds a javscript file to the backend after it has been checked that it exists
659 * @param string javascript file reference
662 public function addJavascriptFile($javascriptFile) {
663 //TODO add more checks if neccessary
665 if(file_exists(t3lib_div
::resolveBackPath(PATH_site
.$javascriptFile))) {
667 if(t3lib_div
::isFirstPartOfStr($javascriptFile, 'typo3/')) {
668 $javascriptFile = substr($javascriptFile, 6); // make relative to typo3/
671 $this->jsFiles
[] = $javascriptFile;
676 * adds a css snippet to the backend
678 * @param string css snippet
681 public function addCss($css) {
682 if(!is_string($css)) {
683 throw new InvalidArgumentException('parameter $css must be of type string', 1195129642);
690 * adds a css file to the backend after it has been checked that it exists
692 * @param string css file reference
695 public function addCssFile($cssFile) {
696 //TODO add more checks if neccessary
698 if(file_exists(t3lib_div
::resolveBackPath(PATH_site
.$cssFile))) {
700 if(t3lib_div
::isFirstPartOfStr($cssFile, 'typo3/')) {
701 $cssFile = substr($cssFile, 6); // make relative to typo3/
704 $this->cssFiles
[] = $cssFile;
709 * adds an item to the toolbar
711 * @param string toolbar item class reference, f.e. EXT:toolbarextension/class.tx_toolbarextension_coolitem.php:tx_toolbarExtension_coolItem
713 public function addToolbarItem($toolbarItemName, $toolbarItemClassReference) {
714 $toolbarItem = t3lib_div
::getUserObj($toolbarItemClassReference);
716 if(!($toolbarItem instanceof t3lib_backendToolbarItem
)) {
717 throw new UnexpectedValueException('$toolbarItem "'.$toolbarItemName.'" must implement interface t3lib_backendToolbarItem', 1195125501);
720 $toolbarItem->setBackend($this);
721 $this->toolbarItems
[$toolbarItemName] = $toolbarItem;
727 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE
]['XCLASS']['typo3/backend.php']) {
728 include_once($TYPO3_CONF_VARS[TYPO3_MODE
]['XCLASS']['typo3/backend.php']);
732 // document generation
733 $TYPO3backend = t3lib_div
::makeInstance('TYPO3backend');
735 // include extensions which may add css, javascript or toolbar items
736 if(is_array($GLOBALS['TYPO3_CONF_VARS']['typo3/backend.php']['additionalBackendItems'])) {
737 foreach($GLOBALS['TYPO3_CONF_VARS']['typo3/backend.php']['additionalBackendItems'] as $additionalBackendItem) {
738 include_once($additionalBackendItem);
742 $TYPO3backend->render();