Index: t3lib/interfaces/interface.t3lib_backendtoolbaritem.php =================================================================== --- t3lib/interfaces/interface.t3lib_backendtoolbaritem.php (revision 0) +++ t3lib/interfaces/interface.t3lib_backendtoolbaritem.php (revision 0) @@ -0,0 +1,54 @@ + +* All rights reserved +* +* This script is part of the TYPO3 project. The TYPO3 project is +* free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* The GNU General Public License can be found at +* http://www.gnu.org/copyleft/gpl.html. +* A copy is found in the textfile GPL.txt and important notices to the license +* from the author is found in LICENSE.txt distributed with these scripts. +* +* +* This script is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* This copyright notice MUST APPEAR in all copies of the script! +***************************************************************/ + + +/** + * interface for classes which extend the backend by adding items to the top toolbar + * + * @author Ingo Renner + * @package TYPO3 + * @subpackage t3lib + */ +interface t3lib_backendToolbarItem { + + /** + * sets the reference to the backend object + * + * @param TYPO3backend TYPO3 backend object reference + * @return void + */ + public function setBackend(&$backendReference); + + /** + * renders the toolbar item + * + * @return string the toolbar item rendered as HTML string + */ + public function render(); +} + +?> \ No newline at end of file Index: typo3/backend.php =================================================================== --- typo3/backend.php (revision 2709) +++ typo3/backend.php (working copy) @@ -27,8 +27,11 @@ require_once ('init.php'); require_once ('template.php'); +require_once (PATH_t3lib.'interfaces/interface.t3lib_backendtoolbaritem.php'); + require ('classes/class.typo3logo.php'); require ('classes/class.modulemenu.php'); +require ('classes/class.workspaceselector.php'); require_once (PATH_t3lib.'class.t3lib_loadmodules.php'); require_once (PATH_t3lib.'class.t3lib_basicfilefunc.php'); @@ -35,6 +38,7 @@ require_once ('class.alt_menu_functions.inc'); $GLOBALS['LANG']->includeLLFile('EXT:lang/locallang_misc.xml'); + /** * Class for rendering the TYPO3 backend version 4.2+ * @@ -66,6 +70,7 @@ private $leftMenuWidth; private $topHeight; private $selectMenu; + private $toolbarItems; /** * constructor @@ -105,44 +110,47 @@ 'css/backend-style.css', 'css/verticalmenu.css' ); + + $this->toolbarItems = array(); + $this->initializeCoreToolbarItems(); } /** - * main function generating the BE scaffolding + * initializes the core toolbar items * * @return void */ - public function render() { + private function initializeCoreToolbarItems() { - // set doctype - $GLOBALS['TBE_TEMPLATE']->docType = 'xhtml_trans'; + $coreToolbarItems = array( + 'workspaceSelector' => 'WorkspaceSelector', + /* TODO + 'clearCacheActions' => '', + 'backendSearch' => '', + 'shortcutMenu' => '' + */ + ); - // add javascript - foreach($this->jsFiles as $jsFile) { - $GLOBALS['TBE_TEMPLATE']->JScode .= ' - '; - } - $GLOBALS['TBE_TEMPLATE']->JScode .= chr(10); - $this->generateJavascript(); - $GLOBALS['TBE_TEMPLATE']->JScode .= $GLOBALS['TBE_TEMPLATE']->wrapScriptTags($this->js); + foreach($coreToolbarItems as $toolbarItemName => $toolbarItemClass) { + $toolbarItem = t3lib_div::makeInstance($toolbarItemClass); - // abusing the JS container to add CSS - // TODO fix template.php - foreach($this->cssFiles as $cssFile) { - $GLOBALS['TBE_TEMPLATE']->JScode .= ' - - '; + if(!($toolbarItem instanceof t3lib_backendToolbarItem)) { + throw new UnexpectedValueException('$toolbarItem "'.$toolbarItemName.'" must implement interface t3lib_backendToolbarItem', 1195126772); + } + + $toolbarItem->setBackend($this); + $this->toolbarItems[] = $toolbarItem; } + } - // set document title - $title = $TYPO3_CONF_VARS['SYS']['sitename'] ? - $TYPO3_CONF_VARS['SYS']['sitename'].' [TYPO3 '.TYPO3_version.']' - : 'TYPO3 '.TYPO3_version; - - // start page header: - $this->content .= $GLOBALS['TBE_TEMPLATE']->startPage($title); - $this->content .= $GLOBALS['TBE_TEMPLATE']->endPage(); + /** + * main function generating the BE scaffolding + * + * @return void + */ + public function render() { + // prepare the scaffolding, at this point extension still may addjavascript and css $logo = t3lib_div::makeInstance('TYPO3Logo'); $logo->setLogo('gfx/typo3logo_mini.png'); @@ -152,14 +160,13 @@ $loginInfo = $this->getLoggedInUserLabel(); // create backend scaffolding - // TODO change typo3-top to render without iframe, directly into the div - $this->content .= ' + $backendScaffolding = '
-
-   -
+
' + .$this->renderToolbar() + .'
' @@ -177,6 +184,42 @@ '; + /****************************************************** + * now put the complete backend document together + ******************************************************/ + + // set doctype + $GLOBALS['TBE_TEMPLATE']->docType = 'xhtml_trans'; + + // add javascript + foreach($this->jsFiles as $jsFile) { + $GLOBALS['TBE_TEMPLATE']->JScode .= ' + '; + } + $GLOBALS['TBE_TEMPLATE']->JScode .= chr(10); + $this->generateJavascript(); + $GLOBALS['TBE_TEMPLATE']->JScode .= $GLOBALS['TBE_TEMPLATE']->wrapScriptTags($this->js); + + // abusing the JS container to add CSS + // TODO fix template.php + foreach($this->cssFiles as $cssFile) { + $GLOBALS['TBE_TEMPLATE']->JScode .= ' + + '; + } + // TODO add CSS from $this->css + + // set document title + $title = $TYPO3_CONF_VARS['SYS']['sitename'] ? + $TYPO3_CONF_VARS['SYS']['sitename'].' [TYPO3 '.TYPO3_version.']' + : 'TYPO3 '.TYPO3_version; + + // start page header: + $this->content .= $GLOBALS['TBE_TEMPLATE']->startPage($title); + $this->content .= $GLOBALS['TBE_TEMPLATE']->endPage(); + + $this->content .= $backendScaffolding; + echo $this->content; } @@ -181,6 +224,21 @@ } /** + * renders the items in the top toolbar + * + * @return string top toolbar elements as HTML + */ + private function renderToolbar() { + $toolbar = ''; + + foreach($this->toolbarItems as $toolbarItem) { + $toolbar .= $toolbarItem->render(); + } + + return $toolbar; + } + + /** * gets the label of the currently loged in BE user * * @return string html code snippet displaying the currently logged in user @@ -575,10 +633,93 @@ return $logo; } + + /** + * adds a javascript snippet to the backend + * + * @param string javascript snippet + * @return void + */ + public function addJavascript($javascript) { + // TODO do we need more checks? + if(!is_string($javascript)) { + throw new InvalidArgumentException('parameter $javascript must be of type string', 1195129553); + } + + $this->js .= $javascript; + } + + /** + * adds a javscript file to the backend after it has been checked that it exists + * + * @param string javascript file reference + * @return void + */ + public function addJavascriptFile($javascriptFile) { + //TODO add more checks if neccessary + + if(file_exists(t3lib_div::resolveBackPath(PATH_site.$javascriptFile))) { + + if(t3lib_div::isFirstPartOfStr($javascriptFile, 'typo3/')) { + $javascriptFile = substr($javascriptFile, 6); // make relative to typo3/ + } + + $this->jsFiles[] = $javascriptFile; + } + } + + /** + * adds a css snippet to the backend + * + * @param string css snippet + * @return void + */ + public function addCss($css) { + if(!is_string($css)) { + throw new InvalidArgumentException('parameter $css must be of type string', 1195129642); + } + + $this->css .= $css; + } + + /** + * adds a css file to the backend after it has been checked that it exists + * + * @param string css file reference + * @return void + */ + public function addCssFile($cssFile) { + //TODO add more checks if neccessary + + if(file_exists(t3lib_div::resolveBackPath(PATH_site.$cssFile))) { + + if(t3lib_div::isFirstPartOfStr($cssFile, 'typo3/')) { + $cssFile = substr($cssFile, 6); // make relative to typo3/ + } + + $this->cssFiles[] = $cssFile; + } + } + + /** + * adds an item to the toolbar + * + * @param string toolbar item class reference, f.e. EXT:toolbarextension/class.tx_toolbarextension_coolitem.php:tx_toolbarExtension_coolItem + */ + public function addToolbarItem($toolbarItemName, $toolbarItemClassReference) { + $toolbarItem = t3lib_div::getUserObj($toolbarItemClassReference); + + if(!($toolbarItem instanceof t3lib_backendToolbarItem)) { + throw new UnexpectedValueException('$toolbarItem "'.$toolbarItemName.'" must implement interface t3lib_backendToolbarItem', 1195125501); + } + + $toolbarItem->setBackend($this); + $this->toolbarItems[$toolbarItemName] = $toolbarItem; + } } -// Include extension? + // include XCLASS if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/backend.php']) { include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/backend.php']); } @@ -584,9 +725,16 @@ } - // document generation $TYPO3backend = t3lib_div::makeInstance('TYPO3backend'); + + // include extensions which may add css, javascript or toolbar items +if(is_array($GLOBALS['TYPO3_CONF_VARS']['typo3/backend.php']['additionalBackendItems'])) { + foreach($GLOBALS['TYPO3_CONF_VARS']['typo3/backend.php']['additionalBackendItems'] as $additionalBackendItem) { + include_once($additionalBackendItem); + } +} + $TYPO3backend->render(); ?> \ No newline at end of file Index: typo3/classes/class.modulemenu.php =================================================================== --- typo3/classes/class.modulemenu.php (revision 2709) +++ typo3/classes/class.modulemenu.php (working copy) @@ -534,7 +534,7 @@ */ public function setLinkModules($linkModules) { if(!is_bool($linkModules)) { - throw new InvalidArgumentException('parameter $$linkModules must be of type bool', 1193326558); + throw new InvalidArgumentException('parameter $linkModules must be of type bool', 1193326558); } $this->linkModules = $linkModules; Index: typo3/classes/class.workspaceselector.php =================================================================== --- typo3/classes/class.workspaceselector.php (revision 0) +++ typo3/classes/class.workspaceselector.php (revision 0) @@ -0,0 +1,190 @@ + +* All rights reserved +* +* This script is part of the TYPO3 project. The TYPO3 project is +* free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* The GNU General Public License can be found at +* http://www.gnu.org/copyleft/gpl.html. +* A copy is found in the textfile GPL.txt and important notices to the license +* from the author is found in LICENSE.txt distributed with these scripts. +* +* +* This script is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* This copyright notice MUST APPEAR in all copies of the script! +***************************************************************/ + + +/** + * class to render the workspace selector + * + * @author Ingo Renner + * @package TYPO3 + * @subpackage core + */ +class WorkspaceSelector implements t3lib_backendToolbarItem { + + private $changeWorkspace; + private $changeWorkspacePreview; + + /** + * reference back to the backend object + * + * @var TYPO3backend + */ + private $backendReference; + + public function __construct() { + $this->changeWorkspace = t3lib_div::_GP('changeWorkspace'); + $this->changeWorkspacePreview = t3lib_div::_GP('changeWorkspacePreview'); + } + + /** + * sets the backend reference + * + * @param TYPO3backend backend object reference + */ + public function setBackend(&$backendReference) { + $this->backendReference = $backendReference; + } + + /** + * changes workspace if needed and then reloads the backend + * + * @return void + */ + public function changeWorkspace() { + $reloadBackend = false; + + // Changing workspace and if so, reloading entire backend: + if (strlen($this->changeWorkspace)) { + $GLOBALS['BE_USER']->setWorkspace($this->changeWorkspace); + $reloadBackend = true; + } + + // Changing workspace preview and if so, reloading entire backend: + if (strlen($this->changeWorkspacePreview)) { + $GLOBALS['BE_USER']->setWorkspacePreview($this->changeWorkspacePreview); + $reloadBackend = true; + } + + if($reloadBackend) { + $this->backendReference->addJavascript( + 'top.location.href=\'backend.php\';' + ); + } + } + + /** + * retrieves the available workspaces from the database and checks whether + * they're available to the current BE user + * + * @return array array of worspaces available to the current user + */ + private function getAvailableWorkspaces() { + $availableWorkspaces = array(); + + // add default workspaces + if($GLOBALS['BE_USER']->checkWorkspace(array('uid' => 0))) { + $availableWorkspaces[0] = '['.$GLOBALS['LANG']->getLL('shortcut_onlineWS').']'; + } + if ($GLOBALS['BE_USER']->checkWorkspace(array('uid' => -1))) { + $availableWorkspaces[-1] = '['.$GLOBALS['LANG']->getLL('shortcut_offlineWS').']'; + } + + // add custom workspaces (selecting all, filtering by BE_USER check): + $customWorkspaces = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows( + 'uid, title, adminusers, members, reviewers', + 'sys_workspace', + 'pid = 0'.t3lib_BEfunc::deleteClause('sys_workspace'), + '', + 'title' + ); + if(count($customWorkspaces)) { + foreach($customWorkspaces as $workspace) { + if($GLOBALS['BE_USER']->checkWorkspace($workspace)) { + $availableWorkspaces[$workspace['uid']] = $workspace['uid'].': '.$workspace['title']; + } + } + } + + return $availableWorkspaces; + } + + /** + * Creates the selector for workspaces + * + * @return string workspace selector as HTML select + */ + public function render() { + $this->addJavascriptToBackend(); + $this->changeWorkspace(); + + $options = array(); + $workspaceSelector = ''; + $availableWorkspaces = $this->getAvailableWorkspaces(); + + // build selector box options + if(count($availableWorkspaces)) { + foreach($availableWorkspaces as $workspaceId => $label) { + + $selected = ''; + if((int) $GLOBALS['BE_USER']->workspace === $workspaceId) { + $selected = ' selected="selected"'; + } + + $options[$workspaceId] = ''; + } + } else { + $options[] = ''; + } + + // build selector box + if(count($options) > 1) { + $workspaceSelector .= + ''; + } + + // preview + if($GLOBALS['BE_USER']->workspace !== 0) { + $workspaceSelector.= ' user['workspace_preview'] ? 'checked="checked"' : '').'/>'; + } + + $workspaceSelector.= ' '. + t3lib_iconWorks::getIconImage( + 'sys_workspace', + array(), + $this->doc->backPath, + 'align="top"' + ).''; + + return $workspaceSelector; + } + + /** + * adds the neccessary javascript ot the backend + * + */ + private function addJavascriptToBackend() { + $this->backendReference->addJavascriptFile('typo3/js/workspaces.js'); + } +} + +if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/classes/class.workspaceselector.php']) { + include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/classes/class.workspaceselector.php']); +} + +?> \ No newline at end of file Index: typo3/js/workspaces.js =================================================================== --- typo3/js/workspaces.js (revision 0) +++ typo3/js/workspaces.js (revision 0) @@ -0,0 +1,36 @@ +/*************************************************************** +* Copyright notice +* +* (c) 2007 Ingo Renner +* All rights reserved +* +* This script is part of the TYPO3 project. The TYPO3 project is +* free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* The GNU General Public License can be found at +* http://www.gnu.org/copyleft/gpl.html. +* A copy is found in the textfile GPL.txt and important notices to the license +* from the author is found in LICENSE.txt distributed with these scripts. +* +* +* This script is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* This copyright notice MUST APPEAR in all copies of the script! +***************************************************************/ + +// TODO change this into an object/class "WorkspaceManager" + + +function changeWorkspace(workspaceId) { + window.location.href = 'backend.php?changeWorkspace=' + top.rawurlencode(workspaceId); +} + +function changeWorkspacePreview(newstate) { + window.location.href = 'backend.php?changeWorkspacePreview=' + newstate; +} \ No newline at end of file