Fixed button for collapsible sidebar
authorAlexander Ebert <ebert@woltlab.com>
Tue, 23 Oct 2012 15:57:41 +0000 (17:57 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Tue, 23 Oct 2012 15:57:41 +0000 (17:57 +0200)
com.woltlab.wcf/template/header.tpl
wcfsetup/install/files/js/WCF.js
wcfsetup/install/files/style/layout.less

index f206a4793f03d1b511564e5aba2337e44b0a4aa7..5f6259acb59475d2698a5dca068a938d7bfb7b8e 100644 (file)
@@ -39,7 +39,7 @@
 <div id="main" class="layoutFluid{if $sidebarOrientation|isset && $sidebar|isset} sidebarOrientation{@$sidebarOrientation|ucfirst} clearfix{/if}">
        <div>
                {if $sidebar|isset}
-                       <aside class="sidebar"{if $sidebarOrientation|isset && $sidebarOrientation == 'right'} data-is-open="{if $sidebarCollapsed}0{else}1{/if}" data-sidebar-name="{$sidebarName}"{/if}>
+                       <aside class="sidebar"{if $sidebarOrientation|isset && $sidebarOrientation == 'right'} data-is-open="{if $sidebarCollapsed}false{else}true{/if}" data-sidebar-name="{$sidebarName}"{/if}>
                                {@$sidebar}
                        </aside>
                        
index c8f722735dff9583cd958ae29e80e82ecda196a8..7000f885e362ec150348ce1ae51ef9a2b7cbde9d 100755 (executable)
@@ -3501,12 +3501,24 @@ WCF.Collapsible.Sidebar = Class.extend({
         */
        _button: null,
        
+       /**
+        * trigger button height
+        * @var integer
+        */
+       _buttonHeight: 0,
+       
        /**
         * sidebar state
         * @var boolean
         */
        _isOpen: false,
        
+       /**
+        * main container object
+        * @var jQuery
+        */
+       _mainContainer: null,
+       
        /**
         * action proxy
         * @var WCF.Action.Proxy
@@ -3519,12 +3531,30 @@ WCF.Collapsible.Sidebar = Class.extend({
         */
        _sidebar: null,
        
+       /**
+        * sidebar height
+        * @var integer
+        */
+       _sidebarHeight: 0,
+       
        /**
         * sidebar identifier
         * @var string
         */
        _sidebarName: '',
        
+       /**
+        * sidebar offset from document top
+        * @var integer
+        */
+       _sidebarOffset: 0,
+       
+       /**
+        * user panel height
+        * @var integer
+        */
+       _userPanelHeight: 0,
+       
        /**
         * Creates a new WCF.Collapsible.Sidebar object.
         */
@@ -3535,18 +3565,27 @@ WCF.Collapsible.Sidebar = Class.extend({
                        return;
                }
                
-               this._isOpen = (this._sidebar.data('isOpen') === 'false') ? false : true;
+               this._isOpen = (this._sidebar.data('isOpen')) ? true : false;
                this._sidebarName = this._sidebar.data('sidebarName');
+               this._mainContainer = $('#main');
+               this._sidebarHeight = this._sidebar.height();
+               this._sidebarOffset = this._sidebar.getOffsets('offset').top;
+               this._userPanelHeight = $('#topMenu').outerHeight();
                
                // add toggle button
                this._button = $('<a class="collapsibleButton jsTooltip" title="' + WCF.Language.get('wcf.global.button.collapsible') + '" />').prependTo(this._sidebar);
                this._button.click($.proxy(this._click, this));
+               this._buttonHeight = this._button.outerHeight();
                
                this._proxy = new WCF.Action.Proxy({
-                       url: 'index.php/AJAXInvoke/?t=' + SECURITY_TOKEN + SID_2ND
+                       showLoadingOverlay: false,
+                       url: 'index.php/AJAXInvoke/?t=' + SECURITY_TOKEN + SID_ARG_2ND
                });
                
+               $(document).scroll($.proxy(this._scroll, this)).resize($.proxy(this._scroll, this));
+               
                this._renderSidebar();
+               this._scroll();
        },
        
        /**
@@ -3566,15 +3605,54 @@ WCF.Collapsible.Sidebar = Class.extend({
                this._renderSidebar();
        },
        
+       /**
+        * Aligns the toggle button upon scroll or resize.
+        */
+       _scroll: function() {
+               var $window = $(window);
+               var $scrollOffset = $window.scrollTop();
+               
+               // calculate top and bottom coordinates of visible sidebar
+               var $topOffset = Math.max($scrollOffset - this._sidebarOffset, 0);
+               var $bottomOffset = Math.min(this._mainContainer.height(), ($window.height() + $scrollOffset) - this._sidebarOffset);
+               
+               var $buttonTop = 0;
+               if ($bottomOffset === $topOffset) {
+                       // sidebar not within visible area
+                       $buttonTop = this._sidebarOffset + this._sidebarHeight;
+               }
+               else {
+                       $buttonTop = $topOffset + (($bottomOffset - $topOffset) / 2);
+                       
+                       // if the user panel is above the sidebar, substract it's height
+                       var $overlap = Math.max(Math.min($topOffset - this._userPanelHeight, this._userPanelHeight), 0);
+                       if ($overlap > 0) {
+                               $buttonTop += ($overlap / 2);
+                       }
+               }
+               
+               // ensure the button does not exceed bottom boundaries
+               if (($bottomOffset - $topOffset - this._userPanelHeight) < this._buttonHeight) {
+                       $buttonTop = $buttonTop - this._buttonHeight;
+               }
+               else {
+                       // exclude half button height
+                       $buttonTop = Math.max($buttonTop - (this._buttonHeight / 2), 0);
+               }
+               
+               this._button.css({ top: $buttonTop + 'px' });
+               
+       },
+       
        /**
         * Renders the sidebar state.
         */
        _renderSidebar: function() {
                if (this._isOpen) {
-                       this._sidebar.addClass('sidebarCollapsed');
+                       this._mainContainer.removeClass('sidebarCollapsed');
                }
                else {
-                       this._sidebar.removeClass('sidebarCollapsed');
+                       this._mainContainer.addClass('sidebarCollapsed');
                }
        }
 });
index a6086e549586ff78a9974fdbc36ae5d5c0413d73..0b26ec5d1ca59c8c71cea5f636c0ee7cef88b2d9 100644 (file)
                background-color: @wcfSidebarBackgroundColor;
                
                > .sidebar {
+                       position: relative;
                        width: 300px;
                        z-index: 120;
+
+                       > .collapsibleButton {
+                               background-color: @wcfSidebarBackgroundColor;
+                               background-image: url('../icon/arrowRight.svg');
+                               background-position: 4px 4px;
+                               background-repeat: no-repeat;
+                               background-size: 16px;
+                               border-radius: 6px 0 0 6px;
+                               display: block;
+                               height: 24px;
+                               left: -20px;
+                               position: absolute;
+                               top: 0;
+                               width: 24px;
+                       }
                }
                
                > .content {
        }
        
        &.sidebarOrientationRight {
+               &.sidebarCollapsed > div {
+                       > .content {
+                               margin-right: 20px;
+                       }
+                       
+                       > .sidebar {
+                               width: 20px;
+                               
+                               > div,
+                               > fieldset {
+                                       visibility: hidden;
+                               }
+                               
+                               > .collapsibleButton {
+                                       background-image: url('../icon/arrowLeft.svg');
+                               }
+                       }
+               }
+               
                .content {
                        margin-right: 300px;
                }