[TASK] Use alternative selector for many workspaces 20/21920/5
authorOliver Hader <oliver@typo3.org>
Fri, 19 Jul 2013 15:31:31 +0000 (17:31 +0200)
committerOliver Hader <oliver.hader@typo3.org>
Tue, 25 Mar 2014 15:17:18 +0000 (16:17 +0100)
The toolbar of the workspace module visualizes each workspace
in a separate tab. On having many workspaces, the toolbar is
extended to multiple lines which actually reduces the available
viewport of the grid panel.

This change introduces a modified TabPanel that shrinks if the
available width is undershot. In this case an additional menu
is rendered to the right side of the panel to visualize the
remaining items in a vertical list.

Resolves: #49689
Releases: 6.2
Change-Id: I85c8b8134dfe27a4dc32c5d70a158cca41763c41
Reviewed-on: https://review.typo3.org/21920
Reviewed-by: Oliver Hader
Tested-by: Oliver Hader
typo3/sysext/workspaces/Classes/Controller/ReviewController.php
typo3/sysext/workspaces/Resources/Private/Layouts/Module.html
typo3/sysext/workspaces/Resources/Public/Images/menu.png [new file with mode: 0644]
typo3/sysext/workspaces/Resources/Public/JavaScript/Component/TabPanel.js [new file with mode: 0644]
typo3/sysext/workspaces/Resources/Public/JavaScript/workspaces.js
typo3/sysext/workspaces/Resources/Public/StyleSheet/module.css

index 63cabc0..f33bcde 100644 (file)
@@ -70,7 +70,10 @@ class ReviewController extends \TYPO3\CMS\Workspaces\Controller\AbstractControll
                                }
                        }
                }
-               $this->pageRenderer->addInlineSetting('Workspaces', 'isLiveWorkspace', $GLOBALS['BE_USER']->workspace == 0 ? TRUE : FALSE);
+               $this->pageRenderer->addInlineSetting('Workspaces', 'isLiveWorkspace', (int)$GLOBALS['BE_USER']->workspace === 0 ? TRUE : FALSE);
+               $this->pageRenderer->addInlineSetting('Workspaces', 'workspaceTabs', $this->prepareWorkspaceTabs($wsList, $activeWorkspace));
+               $this->pageRenderer->addInlineSetting('Workspaces', 'activeWorkspaceId', $activeWorkspace);
+               $this->pageRenderer->addInlineSetting('Workspaces', 'PATH_typo3', GeneralUtility::getIndpEnv('TYPO3_SITE_PATH') . TYPO3_mainDir);
                $this->view->assign('performWorkspaceSwitch', $performWorkspaceSwitch);
                $this->view->assign('workspaceList', $wsList);
                $this->view->assign('activeWorkspaceUid', $activeWorkspace);
@@ -95,6 +98,9 @@ class ReviewController extends \TYPO3\CMS\Workspaces\Controller\AbstractControll
                        $wsList = array_intersect_key($wsList, $wsCur);
                }
 
+               $this->pageRenderer->addInlineSetting('Workspaces', 'workspaceTabs', $this->prepareWorkspaceTabs($wsList, \TYPO3\CMS\Workspaces\Service\WorkspaceService::SELECT_ALL_WORKSPACES));
+               $this->pageRenderer->addInlineSetting('Workspaces', 'activeWorkspaceId', \TYPO3\CMS\Workspaces\Service\WorkspaceService::SELECT_ALL_WORKSPACES);
+               $this->pageRenderer->addInlineSetting('Workspaces', 'PATH_typo3', GeneralUtility::getIndpEnv('TYPO3_SITE_PATH') . TYPO3_mainDir);
                $this->view->assign('pageUid', GeneralUtility::_GP('id'));
                $this->view->assign('showGrid', TRUE);
                $this->view->assign('showLegend', TRUE);
@@ -179,6 +185,7 @@ class ReviewController extends \TYPO3\CMS\Workspaces\Controller\AbstractControll
                $resources = array(
                        $resourcePath . 'Component/RowDetailTemplate.js',
                        $resourcePath . 'Component/RowExpander.js',
+                       $resourcePath . 'Component/TabPanel.js',
                        $resourcePath . 'Store/mainstore.js',
                        $resourcePath . 'configuration.js',
                        $resourcePath . 'helpers.js',
@@ -197,4 +204,59 @@ class ReviewController extends \TYPO3\CMS\Workspaces\Controller\AbstractControll
                $this->pageRenderer->addInlineSetting('RecordHistory', 'moduleUrl', \TYPO3\CMS\Backend\Utility\BackendUtility::getModuleUrl('record_history'));
        }
 
+       /**
+        * Prepares available workspace tabs.
+        *
+        * @param array $workspaceList
+        * @param int $activeWorkspace
+        * @return array
+        */
+       protected function prepareWorkspaceTabs(array $workspaceList, $activeWorkspace) {
+               $tabs = array();
+
+               if ($activeWorkspace !== \TYPO3\CMS\Workspaces\Service\WorkspaceService::SELECT_ALL_WORKSPACES) {
+                       $tabs[] = array(
+                               'title' => $workspaceList[$activeWorkspace],
+                               'itemId' => 'workspace-' . $activeWorkspace,
+                               'workspaceId' => $activeWorkspace,
+                               'triggerUrl' => $this->getModuleUri($activeWorkspace),
+                       );
+               }
+
+               $tabs[] = array(
+                       'title' => 'All workspaces',
+                       'itemId' => 'workspace-' . \TYPO3\CMS\Workspaces\Service\WorkspaceService::SELECT_ALL_WORKSPACES,
+                       'workspaceId' => \TYPO3\CMS\Workspaces\Service\WorkspaceService::SELECT_ALL_WORKSPACES,
+                       'triggerUrl' => $this->getModuleUri(\TYPO3\CMS\Workspaces\Service\WorkspaceService::SELECT_ALL_WORKSPACES),
+               );
+
+               foreach ($workspaceList as $workspaceId => $workspaceTitle) {
+                       if ($workspaceId === $activeWorkspace) {
+                               continue;
+                       }
+                       $tabs[] = array(
+                               'title' => $workspaceTitle,
+                               'itemId' => 'workspace-' . $workspaceId,
+                               'workspaceId' => $workspaceId,
+                               'triggerUrl' => $this->getModuleUri($workspaceId),
+                       );
+               }
+
+               return $tabs;
+       }
+
+       /**
+        * Gets the module URI.
+        *
+        * @param int $workspaceId
+        * @return string
+        */
+       protected function getModuleUri($workspaceId) {
+               $parameters = array(
+                       'id' => (int)$this->pageId,
+                       'workspace' => (int)$workspaceId,
+               );
+               return \TYPO3\CMS\Backend\Utility\BackendUtility::getModuleUrl('web_WorkspacesWorkspaces', $parameters);
+       }
+
 }
index 4d5aeb4..6cf2882 100644 (file)
 
 <div id="typo3-docbody">
        <div id="typo3-inner-docbody">
-
                <f:flashMessages renderMode="div" />
-
-               <f:render partial="navigation" arguments="{workspaceList: workspaceList, activeWorkspaceUid: activeWorkspaceUid, showAllWorkspaceTab:showAllWorkspaceTab}" />
+               <div id="workspacetabs"></div>
                <div class="typo3-dyntabmenu-divs"><f:render section="main" /></div>
                <f:if condition="{showLegend}"><f:render partial="legend" /></f:if>
        </div>
diff --git a/typo3/sysext/workspaces/Resources/Public/Images/menu.png b/typo3/sysext/workspaces/Resources/Public/Images/menu.png
new file mode 100644 (file)
index 0000000..7751f97
Binary files /dev/null and b/typo3/sysext/workspaces/Resources/Public/Images/menu.png differ
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/Component/TabPanel.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/Component/TabPanel.js
new file mode 100644 (file)
index 0000000..b0cd410
--- /dev/null
@@ -0,0 +1,159 @@
+Ext.ns('TYPO3.Workspaces.Component');
+
+TYPO3.Workspaces.Component.TabPanel = Ext.extend(Ext.TabPanel, {
+       menuRight: null,
+       tabMenu: null,
+
+       menuItems: [],
+       menuItemTemplate: null,
+
+       listeners: {
+               beforetabchange: function(panel, newTab, currentTab) {
+                       if (typeof currentTab !== 'undefined' && newTab.triggerUrl) {
+                               this.handleTriggerUrl(newTab);
+                       }
+               },
+               afterrender: function() {
+                       this.createMenu();
+                       this.arrangeTabsAfterRender();
+                       this.updateMenu();
+               }
+       },
+
+       initComponent: function() {
+               TYPO3.Workspaces.Component.TabPanel.superclass.initComponent.call(this);
+               Ext.EventManager.onWindowResize(this.handleResize, this);
+
+               this.menuItemTemplate = new Ext.XTemplate(
+                       '<a id="{id}" class="{cls} x-unselectable" hidefocus="true" unselectable="on" href="{href}"',
+                               '<tpl if="hrefTarget">',
+                                       ' target="{hrefTarget}"',
+                               '</tpl>',
+                       '>',
+                               '<span class="x-menu-item-text">{text}</span>',
+                       '</a>'
+               );
+       },
+
+       getParentPanel: function() {
+               return this.findParentByType('panel');
+       },
+
+       createMenu : function() {
+               var position = this.tabPosition=='bottom' ? this.footer : this.header;
+               var h = this.stripWrap.dom.offsetHeight;
+               var menuRight = position.insertFirst({
+                       cls:'x-tab-menu-right'
+               });
+               menuRight.hide();
+               menuRight.setHeight(h);
+               menuRight.addClassOnOver('x-tab-menu-right-over');
+               menuRight.on('click', this.showMenu, this);
+               this.menuRight = menuRight;
+       },
+
+       updateMenu: function() {
+               if (this.menuItems.length) {
+                       this.menuRight.show();
+               } else {
+                       this.menuRight.hide();
+               }
+       },
+
+       showMenu: function(event) {
+               if (this.tabMenu) {
+                       this.tabMenu.destroy();
+                       this.un('destroy', this.tabMenu.destroy, this.tabMenu);
+                       this.tabMenu = null;
+               }
+
+               this.tabMenu =  new Ext.menu.Menu({
+                       cls: 'typo3-workspaces-menu'
+               });
+               this.on('destroy', this.tabMenu.destroy, this.tabMenu);
+
+               this.addMenuItems();
+
+               var target = Ext.get(event.getTarget());
+               var xy = target.getXY();
+               xy[1] += this.menuRight.getHeight() - 1;
+
+               this.tabMenu.showAt(xy);
+       },
+
+       addMenuItems: function() {
+               Ext.each(this.menuItems, function(cmp) {
+                       menuItem = new Ext.menu.Item({
+                               itemTpl: this.menuItemTemplate,
+                               text      : cmp.title,
+                               handler   : this.handleTriggerUrl,
+                               scope     : this,
+                               triggerUrl: cmp.triggerUrl
+                               //iconCls   : item.iconCls
+                       });
+                       this.tabMenu.add(menuItem);
+               }, this);
+       },
+
+       handleTriggerUrl: function(item) {
+               location.href = TYPO3.settings.Workspaces.PATH_typo3 + item.triggerUrl;
+       },
+
+       handleResize: function(width, height) {
+               this.setWidth(width);
+               this.arrangeTabsAfterResize();
+               this.updateMenu();
+       },
+
+       arrangeTabsAfterRender: function() {
+               var i, cmp, moveItems = [], width = 0;
+               var lastIndex = this.items.items.length;
+               var tabPanelWidth = this.getParentPanel().getWidth();
+
+               for (i = 0; i < lastIndex; i++) {
+                       cmp = this.getComponent(i);
+                       width += Ext.get(cmp.tabEl).getWidth() + this.tabMargin;
+                       if (width > tabPanelWidth - this.menuRight.getWidth()) {
+                               moveItems.push(cmp);
+                       }
+               }
+
+               Ext.each(moveItems, function(cmp) {
+                       this.remove(cmp);
+                       this.menuItems.push(cmp);
+               }, this);
+       },
+
+       arrangeTabsAfterResize: function() {
+               var i, cmp, moveItems = [], width = 0;
+               var lastIndex = this.items.items.length;
+               var tabPanelWidth = this.getParentPanel().getWidth();
+
+               for (i = 0; i < lastIndex; i++) {
+                       cmp = this.getComponent(i);
+                       width += Ext.get(cmp.tabEl).getWidth() + this.tabMargin;
+                       if (width > tabPanelWidth - this.menuRight.getWidth()) {
+                               moveItems.unshift(cmp);
+                       }
+               }
+
+               if (moveItems.length) {
+                       Ext.each(moveItems, function(cmp) {
+                               this.remove(cmp);
+                               this.menuItems.unshift(cmp);
+                       }, this);
+               } else {
+                       while (this.menuItems.length) {
+                               cmp = this.menuItems[0];
+                               this.add(cmp);
+                               width += Ext.get(cmp.tabEl).getWidth() + this.tabMargin;
+                               if (width > tabPanelWidth - this.menuRight.getWidth()) {
+                                       this.remove(cmp);
+                                       break;
+                               }
+                               this.menuItems.shift();
+                       }
+               }
+       }
+});
+Ext.reg('WorkspacesTabPanel', TYPO3.Workspaces.Component.TabPanel);
\ No newline at end of file
index 2f70e98..197d506 100644 (file)
@@ -75,6 +75,21 @@ Ext.onReady(function() {
        TYPO3.Workspaces.MainStore.proxy = new Ext.data.DirectProxy({
                directFn : TYPO3.Workspaces.ExtDirect.getWorkspaceInfos
        });
+
+       TYPO3.Workspaces.Tabs = new Ext.Panel({
+               renderTo: 'workspacetabs',
+               autoWidth: true,
+               layout: 'fit',
+               items: [
+                       {
+                               xtype: 'WorkspacesTabPanel',
+                               unstyled: true,
+                               items: TYPO3.settings.Workspaces.workspaceTabs,
+                               activeTab: 'workspace-' + TYPO3.settings.Workspaces.activeWorkspaceId
+                       }
+               ]
+       });
+
        // fire grid
        var WS = new TYPO3.Workspaces.App.init();
 
index 37e6777..06246fa 100644 (file)
@@ -1,7 +1,6 @@
-
 ul.x-tab-strip.x-tab-strip-top {
-       width: 100%;
        margin-bottom: 0;
+       margin-top: 0;
        padding-left: 0;
 }
 ul.x-tab-strip.x-tab-strip-top li.last {
@@ -258,3 +257,35 @@ table.t3-workspaces-foldout-contentDiff td.content {
 .typo3-workspaces-collection-parent-expanded .typo3-workspaces-collection-level-node {
        background-position: -21px 2px;
 }
+
+.x-menu.typo3-workspaces-menu {
+       background-image: none;
+}
+.x-menu.typo3-workspaces-menu a.x-menu-item {
+       padding: 3px 14px;
+}
+
+.x-tab-menu-right {
+       background: #dadada;
+       border-color: #adadad;
+       border-style: solid;
+       border-width: 1px;
+       -moz-border-radius-topleft: 3px;
+       -moz-border-radius-topright: 3px;
+       -webkit-border-top-left-radius: 3px;
+       -webkit-border-top-right-radius: 3px;
+       border-top-left-radius: 3px;
+       border-top-right-radius: 3px;
+       color: #666666;
+       background-position: center 6px;
+       padding: 4px;
+
+       background-image: url('../Images/menu.png');
+       background-repeat: no-repeat;
+       width: 16px;
+       position: absolute;
+       right: 0;
+       top: 0;
+       z-index: 10;
+       cursor:pointer;
+}