Interactive dropdowns now stick during scroll
authorAlexander Ebert <ebert@woltlab.com>
Fri, 9 Sep 2016 10:05:21 +0000 (12:05 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Fri, 9 Sep 2016 10:05:27 +0000 (12:05 +0200)
wcfsetup/install/files/js/WCF.js
wcfsetup/install/files/js/WoltLabSuite/Core/Dom/Util.js
wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Page/Header/Fixed.js
wcfsetup/install/files/style/ui/dropdownInteractive.scss

index 299e3d81bc36317f3b8bc98e49bb4332b602cd8f..e19b619bef5cbb1d7dc07bec61aad26abfe16d68 100755 (executable)
@@ -1010,12 +1010,6 @@ WCF.Dropdown.Interactive.Handler = {
                if (this._dropdownContainer === null) {
                        this._dropdownContainer = $('<div class="dropdownMenuContainer" />').appendTo(document.body);
                        WCF.CloseOverlayHandler.addCallback('WCF.Dropdown.Interactive.Handler', $.proxy(this.closeAll, this));
-                       
-                       window.addEventListener('scroll', (function (event) {
-                               if (!document.documentElement.classList.contains('pageOverlayActive')) {
-                                       this.closeAll();
-                               }
-                       }).bind(this));
                }
                
                var $instance = new WCF.Dropdown.Interactive.Instance(this._dropdownContainer, triggerElement, identifier, options);
@@ -1156,14 +1150,20 @@ WCF.Dropdown.Interactive.Instance = Class.extend({
                
                this._pointer = $('<span class="elementPointer"><span /></span>').appendTo(this._container);
                
-               require(['Environment'], function(Environment) {
-                       if (Environment.platform() === 'desktop' && $itemContainer !== null) {
-                               // use jQuery scrollbar on desktop, mobile browsers have a similar display built-in
-                               $itemContainer.perfectScrollbar({
-                                       suppressScrollX: true
-                               });
+               require(['Environment', 'EventHandler'], (function(Environment, EventHandler) {
+                       if (Environment.platform() === 'desktop') {
+                               EventHandler.add('com.woltlab.wcf.pageHeaderFixed', 'change', (function (data) {
+                                       this.render();
+                               }).bind(this));
+                               
+                               if ($itemContainer !== null) {
+                                       // use jQuery scrollbar on desktop, mobile browsers have a similar display built-in
+                                       $itemContainer.perfectScrollbar({
+                                               suppressScrollX: true
+                                       });
+                               }
                        }
-               });
+               }).bind(this));
                
                this._container.appendTo(dropdownContainer);
        },
@@ -1262,22 +1262,29 @@ WCF.Dropdown.Interactive.Instance = Class.extend({
         * Renders the dropdown.
         */
        render: function() {
-               if (window.matchMedia('(max-width: 767px)').matches) {
-                       this._container.css({
-                               bottom: '',
-                               left: '',
-                               right: '',
-                               top: elById('pageHeader').clientHeight + 'px'
-                       });
-               }
-               else {
-                       require(['Ui/Alignment'], (function(UiAlignment) {
+               require(['Dom/Util', 'Ui/Alignment', 'Ui/Screen'], (function (DomUtil, UiAlignment, UiScreen) {
+                       if (UiScreen.is('screen-lg')) {
+                               this._container[0].classList.remove('interactiveDropdownFixed');
+                               
                                UiAlignment.set(this._container[0], this._triggerElement[0], {
                                        horizontal: 'right',
                                        pointer: true
                                });
-                       }).bind(this));
-               }
+                               
+                               if (DomUtil.getFixedParent(this._triggerElement[0]) !== null) {
+                                       this._container[0].classList.add('interactiveDropdownFixed');
+                                       this._container[0].style.setProperty('top', this._triggerElement[0].clientHeight + 'px', '');
+                               }
+                       }
+                       else {
+                               this._container.css({
+                                       bottom: '',
+                                       left: '',
+                                       right: '',
+                                       top: elById('pageHeader').clientHeight + 'px'
+                               });
+                       }
+               }).bind(this));
        },
        
        /**
index da590cb25b606dc15064f0e58bdad70cc14f9c87..2b1494308458f608d7bd71215a59c28a90c317e9 100644 (file)
@@ -432,6 +432,24 @@ define(['Environment', 'StringUtil'], function(Environment, StringUtil) {
                 */
                isAtNodeEnd: function(element, ancestor) {
                        return _isBoundaryNode(element, ancestor, 'next');
+               },
+               
+               /**
+                * Returns the first ancestor element with position fixed or null.
+                * 
+                * @param       {Element}               element         target element
+                * @returns     {(Element|null)}        first ancestor with position fixed or null
+                */
+               getFixedParent: function (element) {
+                       while (element && element !== document.body) {
+                               if (window.getComputedStyle(element).getPropertyValue('position') === 'fixed') {
+                                       return element;
+                               }
+                               
+                               element = element.offsetParent;
+                       }
+                       
+                       return null;
                }
        };
        
index 2861b35bb9c371359827faa429be5818c511822c..90c9a085cc7b0dfa887a6995914eab41b54c8b70 100644 (file)
@@ -134,14 +134,18 @@ define(['Core', 'EventHandler', 'Ui/Alignment', 'Ui/CloseOverlay', 'Ui/Screen',
                        
                        _isFixed = (window.pageYOffset > _triggerHeight);
                        
-                       _pageHeader.classList[_isFixed ? 'add' : 'remove']('sticky');
-                       _pageHeaderContainer.classList[_isFixed ? 'add' : 'remove']('stickyPageHeader');
-                       
-                       if (!_isFixed && wasFixed) {
-                               _pageHeader.classList.remove('searchBarOpen');
-                               ['bottom', 'left', 'right', 'top'].forEach(function(propertyName) {
-                                       _searchInputContainer.style.removeProperty(propertyName);
-                               });
+                       if (_isFixed !== wasFixed) {
+                               _pageHeader.classList[_isFixed ? 'add' : 'remove']('sticky');
+                               _pageHeaderContainer.classList[_isFixed ? 'add' : 'remove']('stickyPageHeader');
+                               
+                               EventHandler.fire('com.woltlab.wcf.pageHeaderFixed', 'change', { isFixed: _isFixed });
+                               
+                               if (!_isFixed && wasFixed) {
+                                       _pageHeader.classList.remove('searchBarOpen');
+                                       ['bottom', 'left', 'right', 'top'].forEach(function(propertyName) {
+                                               _searchInputContainer.style.removeProperty(propertyName);
+                                       });
+                               }
                        }
                }
        };
index 56f03b29b44f24ae70fd777a97c0173707b4fd4b..425519fd2d3116056e74329276b2cd0185f318c1 100644 (file)
                        -webkit-overflow-scrolling: touch;
                }
        }
+       
+       @include screen-lg {
+               &.interactiveDropdownFixed {
+                       position: fixed;
+               }
+       }
 }
 
 /* drop down header */