Index: t3lib/config_default.php =================================================================== --- t3lib/config_default.php (revision 4474) +++ t3lib/config_default.php (working copy) @@ -243,7 +243,9 @@ 'ShortcutMenu::create' => 'typo3/classes/class.shortcutmenu.php:ShortcutMenu->createAjaxShortcut', 'ModuleMenu::saveMenuState' => 'typo3/classes/class.modulemenu.php:ModuleMenu->saveMenuState', 'ModuleMenu::render' => 'typo3/classes/class.modulemenu.php:ModuleMenu->renderAjax', - 'SC_mod_web_perm_ajax::dispatch' => 'typo3/mod/web/perm/class.sc_mod_web_perm_ajax.php:SC_mod_web_perm_ajax->dispatch' + 'SC_mod_web_perm_ajax::dispatch' => 'typo3/mod/web/perm/class.sc_mod_web_perm_ajax.php:SC_mod_web_perm_ajax->dispatch', + 'WorkspaceMenu::toggleWorkspacePreview' => 'typo3/classes/class.workspaceselector.php:WorkspaceSelector->toggleWorkspacePreview', + 'WorkspaceMenu::setWorkspace' => 'typo3/classes/class.workspaceselector.php:WorkspaceSelector->setWorkspace' ), 'XCLASS' => Array(), // See 'Inside TYPO3' document for more information. ), Index: t3lib/class.t3lib_befunc.php =================================================================== --- t3lib/class.t3lib_befunc.php (revision 4474) +++ t3lib/class.t3lib_befunc.php (working copy) @@ -2528,8 +2528,10 @@ if ($altUrl) { $url = $altUrl; } else { - // check where to render the page - $viewScript = ($GLOBALS['BE_USER']->workspace!=0 && !$GLOBALS['BE_USER']->user['workspace_preview']) ? '/'.TYPO3_mainDir.'mod/user/ws/wsol_preview.php?id=' : '/index.php?id='; + + $viewScriptPreviewEnabled = '/' . TYPO3_mainDir . 'mod/user/ws/wsol_preview.php?id='; + $viewScriptPreviewDisabled = '/index.php?id='; + // check alternate Domains if ($rootLine) { $parts = parse_url(t3lib_div::getIndpEnv('TYPO3_SITE_URL')); @@ -2538,11 +2540,14 @@ } } $preUrl = $preUrl_temp ? (t3lib_div::getIndpEnv('TYPO3_SSL') ? 'https://' : 'http://').$preUrl_temp : $backPath.'..'; - $url = $preUrl.$viewScript.$id.$addGetVars.$anchor; + + $urlPreviewEnabled = $preUrl . $viewScriptPreviewEnabled . $id . $addGetVars . $anchor; + $urlPreviewDisabled = $preUrl . $viewScriptPreviewDisabled . $id . $addGetVars . $anchor; } - return "previewWin=window.open('".$url."','newTYPO3frontendWindow');". - ($switchFocus ? 'previewWin.focus();' : ''); + return "previewWin=window.open(top.WorkspaceFrontendPreviewEnabled?'" . + $urlPreviewDisabled . "':'" . $urlPreviewEnabled . + "','newTYPO3frontendWindow');" . ( $switchFocus ? 'previewWin.focus();' : ''); } /** @@ -2931,7 +2936,7 @@ AND sys_lockedrecords.tstamp > '.($GLOBALS['EXEC_TIME']-2*3600) ); while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { - // Get the type of the user that locked this record: + // Get the type of the user that locked this record: if ($row['userid']) { $userTypeLabel = 'beUser'; } elseif ($row['feuserid']) { Index: typo3/js/workspacemenu.js =================================================================== --- typo3/js/workspacemenu.js (revision 0) +++ typo3/js/workspacemenu.js (revision 0) @@ -0,0 +1,175 @@ +/*************************************************************** +* Copyright notice +* +* (c) 2008 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! +***************************************************************/ + + +/** + * class to handle the workspace menu + * + * $Id$ + */ +var WorkspaceMenu = Class.create({ + + /** + * registers for resize event listener and executes on DOM ready + */ + initialize: function() { + Event.observe(window, 'resize', this.positionMenu); + + Event.observe(window, 'load', function(){ + this.positionMenu(); + + Event.observe('workspace-selector-menu', 'click', this.toggleMenu); + Event.observe('frontendPreviewToggle', 'click', this.toggleFrontendPreview.bind(this)); + Event.observe('goToWsModule', 'click', this.goToWorkspaceModule.bind(this)); + + // observe all clicks on workspace links in the menu + $$('#workspace-selector-menu li a.ws').each(function(element) { + Event.observe(element, 'click', this.switchWorkspace.bind(this)); + }.bindAsEventListener(this)); + + }.bindAsEventListener(this)); + }, + + /** + * positions the menu below the toolbar icon, let's do some math! + */ + positionMenu: function() { + var calculatedOffset = 0; + var parentWidth = $('workspace-selector-menu').getWidth(); + var ownWidth = $$('#workspace-selector-menu ul')[0].getWidth(); + var parentSiblings = $('workspace-selector-menu').previousSiblings(); + + parentSiblings.each(function(toolbarItem) { + calculatedOffset += toolbarItem.getWidth() - 1; + // -1 to compensate for the margin-right -1px of the list items, + // which itself is necessary for overlaying the separator with the active state background + + if(toolbarItem.down().hasClassName('no-separator')) { + calculatedOffset -= 1; + } + }); + calculatedOffset = calculatedOffset - ownWidth + parentWidth; + + + $$('#workspace-selector-menu ul')[0].setStyle({ + left: calculatedOffset + 'px' + }); + }, + + /** + * toggles the visibility of the menu and places it under the toolbar icon + */ + toggleMenu: function(event) { + var toolbarItem = $$('#workspace-selector-menu > a')[0]; + var menu = $$('#workspace-selector-menu .toolbar-item-menu')[0]; + toolbarItem.blur(); + + if(!toolbarItem.hasClassName('toolbar-item-active')) { + toolbarItem.addClassName('toolbar-item-active'); + Effect.Appear(menu, {duration: 0.2}); + TYPO3BackendToolbarManager.hideOthers(toolbarItem); + } else { + toolbarItem.removeClassName('toolbar-item-active'); + Effect.Fade(menu, {duration: 0.1}); + } + + if (event) { + Event.stop(event); + } + }, + + /** + * toggles the workspace frontend preview + */ + toggleFrontendPreview: function(event) { + new Ajax.Request('ajax.php', { + parameters: 'ajaxID=WorkspaceMenu::toggleWorkspacePreview', + onSuccess: function(transport, response) { + var stateActiveIcon = $$('#workspace-selector-menu img.state-active')[0].cloneNode(true); + var stateInactiveIcon = $$('#workspace-selector-menu img.state-inactive')[0].cloneNode(true); + + if (response.newWorkspacePreviewState == 1) { + Event.element(event).previous().replace(stateActiveIcon); + top.WorkspaceFrontendPreviewEnabled = true; + } else { + Event.element(event).previous().replace(stateInactiveIcon); + top.WorkspaceFrontendPreviewEnabled = false; + } + } + }); + + this.toggleMenu(event); + }, + + /** + * redirects the user to the workspace module + */ + goToWorkspaceModule: function(event) { + top.goToModule('user_ws'); + + this.toggleMenu(event); + }, + + /** + * switches the workspace, reloads the module menu, and the content frame + */ + switchWorkspace: function(event) { + var workspaceId = Event.element(event).identify().substring(3); + + new Ajax.Request('ajax.php', { + parameters: 'ajaxID=WorkspaceMenu::setWorkspace&workspaceId=' + workspaceId, + onSuccess: function(transport, response) { + // first remove all checks, then set the check in front of the selected workspace + var stateActiveIcon = $$('#workspace-selector-menu img.state-active')[0].cloneNode(true); + var stateInactiveIcon = $$('#workspace-selector-menu img.state-inactive')[0].cloneNode(true); + + // remove "selected" class and checkmark + $$('#workspace-selector-menu li.selected img.state-active')[0].replace(stateInactiveIcon); + $$('#workspace-selector-menu li.selected')[0].removeClassName('selected'); + + // add "selected" class and checkmark + Event.element(event).previous().replace(stateActiveIcon); + Event.element(event).up().addClassName('selected'); + + // when in web module reload, otherwise send the user to the web module + if (currentModuleLoaded.startsWith('web_')) { + // the boolean "true" makes the page reload from the server + $('content').contentWindow.location.reload(true); + } else { + top.goToModule('web_layout'); + } + + // reload the module menu + TYPO3ModuleMenu.refreshMenu(); + } + }); + + this.toggleMenu(event); + } + +}); + +var TYPO3BackendWorkspaceMenu = new WorkspaceMenu(); Index: typo3/css/backend-style.css =================================================================== --- typo3/css/backend-style.css (revision 4474) +++ typo3/css/backend-style.css (working copy) @@ -121,12 +121,56 @@ /* ----- Workspace Selector ----- */ -#workspace-selector span { +#workspace-selector-menu { + width: 30px; +} + +#workspace-selector-menu ul { + position: absolute; + list-style: none; + padding: 2px 0px 0px; + margin: 0px; + background-color: #f9f9f9; + border: 1px solid #abb2bc; + border-top: none; + width: 180px; +} + +#workspace-selector-menu li { padding-top: 2px; - padding-left: 7px; - margin-right: 5px; + padding-left: 2px; + text-align: left; + float: none; + vertical-align: middle; + min-height: 19px; +} +* html #workspace-selector-menu li { + height: 19px; +} + +#workspace-selector-menu li img { + float: left; +} + +#workspace-selector-menu li a { + text-decoration: none; + line-height: 12px; + vertical-align: middle; + display: block; + padding-bottom: 2px; + padding-left: 3px; + font-size: 11px; +} + +#workspace-selector-menu li.divider { + border-top: 1px solid #a5a5a5; + border-right: 1px solid #a5a5a5; + background-image: url('../gfx/shortcutgroups-bg.png'); + background-repeat: repeat-x; + padding-top: 4px; } + /* ----- Caching ----- */ #clear-cache-actions-menu { Index: typo3/sysext/lang/locallang_core.xml =================================================================== --- typo3/sysext/lang/locallang_core.xml (revision 4474) +++ typo3/sysext/lang/locallang_core.xml (working copy) @@ -227,6 +227,7 @@ + Index: typo3/classes/class.workspaceselector.php =================================================================== --- typo3/classes/class.workspaceselector.php (revision 4474) +++ typo3/classes/class.workspaceselector.php (working copy) @@ -25,6 +25,10 @@ * This copyright notice MUST APPEAR in all copies of the script! ***************************************************************/ + // TODO remove the include once the autoloader is in place +if(TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_AJAX) { + require_once('interfaces/interface.backend_toolbaritem.php'); +} /** * class to render the workspace selector @@ -98,6 +102,37 @@ } /** + * toggles the frontend preview setting for workspaces. If the preview is + * activated it will turned off and vice versa. Gets called through AJAX + * + * @param array array of parameters from the AJAX interface, currently unused + * @param TYPO3AJAX object of type TYPO3AJAX + * @return void + */ + public function toggleWorkspacePreview($parameters = array(), TYPO3AJAX &$ajaxObj = null) { + $newState = $GLOBALS['BE_USER']->user['workspace_preview'] ? '0' : '1'; + $GLOBALS['BE_USER']->setWorkspacePreview($newState); + + $ajaxObj->addContent('newWorkspacePreviewState', $newState); + $ajaxObj->setContentFormat('json'); + } + + /** + * sets the workspace for the backend + * + * @param unknown_type $params + * @param TYPO3AJAX $ajaxObj + */ + public function setWorkspace($parameters = array(), TYPO3AJAX &$ajaxObj = null) { + $workspaceId = (int) t3lib_div::_POST('workspaceId'); + + $GLOBALS['BE_USER']->setWorkspace($workspaceId); + + $ajaxObj->addContent('setWorkspaceId', $workspaceId); + $ajaxObj->setContentFormat('json'); + } + + /** * retrieves the available workspaces from the database and checks whether * they're available to the current BE user * @@ -139,50 +174,68 @@ * @return string workspace selector as HTML select */ public function render() { + $title = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:toolbarItems.workspace', true); $this->addJavascriptToBackend(); $this->changeWorkspace(); + $availableWorkspaces = $this->getAvailableWorkspaces(); + $workspaceMenu = array(); - $options = array(); - $workspaceSelector = ''; - $availableWorkspaces = $this->getAvailableWorkspaces(); + $stateCheckedIcon = 'backPath, + 'gfx/state_checked.png', + 'width="16" height="16"') . + ' title="active" alt="active" class="state-active" />'; + $stateUncheckedIcon = 'inactive'; + - // build selector box options - if(count($availableWorkspaces)) { - foreach($availableWorkspaces as $workspaceId => $label) { + $workspaceMenu[] = 'backPath, + 'gfx/i/sys_workspace.png', + 'width="16" height="16"') . + ' title="' . $title . '" alt="' . $title . '" />'; + $workspaceMenu[] = ''; - return $workspaceSelector.''; + return implode("\n", $workspaceMenu); } /** @@ -191,7 +244,7 @@ * @return void */ protected function addJavascriptToBackend() { - $this->backendReference->addJavascriptFile('js/workspaces.js'); + $this->backendReference->addJavascriptFile('js/workspacemenu.js'); } /** @@ -200,7 +253,7 @@ * @return string list item HTML attibutes */ public function getAdditionalAttributes() { - return ' id="workspace-selector"'; + return ' id="workspace-selector-menu"'; } } Index: typo3/backend.php =================================================================== --- typo3/backend.php (revision 4474) +++ typo3/backend.php (working copy) @@ -522,6 +522,9 @@ // Used for tab-panels: var DTM_currentTabs = new Array(); + + // status of WS FE preview + var WorkspaceFrontendPreviewEnabled = ' . (($GLOBALS['BE_USER']->workspace != 0 && !$GLOBALS['BE_USER']->user['workspace_preview']) ? 'false' : 'true') . '; '; // Check editing of page: Index: typo3/stylesheet.css =================================================================== --- typo3/stylesheet.css (revision 4474) +++ typo3/stylesheet.css (working copy) @@ -2207,9 +2207,10 @@ - - - - - - - - - - - - - - - - - - - - - */ div.workspace-info { - padding: 1px 0px 1px 2px; - margin: 0px 5px 4px 0px; + padding: 3px; + margin: -10px 0px 5px -10px; border: 1px solid #999; + background-color: #ccccff; } .ver-element, ul.tree ul li.ver-element {