]> git.ipfire.org Git - thirdparty/bootstrap.git/commitdiff
fix tests & re-set position gs/support-drop-down-in-navbar 35901/head
authorGeoSot <geo.sotis@gmail.com>
Wed, 2 Mar 2022 22:55:27 +0000 (00:55 +0200)
committerGeoSot <geo.sotis@gmail.com>
Wed, 23 Nov 2022 22:37:07 +0000 (00:37 +0200)
js/src/dropdown.js
js/tests/unit/dropdown.spec.js
js/tests/visual/dropdown.html
site/content/docs/5.2/examples/headers/headers.css

index bc614836046a4412273e97989b59b380f595a597..233b2d1ea9aba84ee0e9e6613868f5f73bc0d357 100644 (file)
@@ -55,7 +55,6 @@ const CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center'
 const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="dropdown"]:not(.disabled):not(:disabled)'
 const SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE}.${CLASS_NAME_SHOW}`
 const SELECTOR_MENU = '.dropdown-menu'
-const SELECTOR_NAVBAR_NAV = '.navbar-nav'
 const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'
 
 const PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'
@@ -99,7 +98,6 @@ class Dropdown extends BaseComponent {
     this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] ||
       SelectorEngine.prev(this._element, SELECTOR_MENU)[0] ||
       SelectorEngine.findOne(SELECTOR_MENU, this._parent)
-    this._inNavbar = this._detectNavbar()
   }
 
   // Getters
@@ -141,7 +139,7 @@ class Dropdown extends BaseComponent {
     // empty mouseover listeners to the body's immediate children;
     // only needed because of broken event delegation on iOS
     // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
-    if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) {
+    if ('ontouchstart' in document.documentElement) {
       for (const element of [].concat(...document.body.children)) {
         EventHandler.on(element, 'mouseover', noop)
       }
@@ -304,15 +302,20 @@ class Dropdown extends BaseComponent {
       {
         name: 'applyCustomStyles',
         enabled: true,
-        phase: 'afterWrite',
-        fn: () => {
+        phase: 'beforeRead',
+        fn: ({ state, instance }) => {
           this._menu.style.removeProperty('position')
           const initialPosition = getComputedStyle(this._menu).position
           if (this._config.display === 'static' || initialPosition === 'static') {
-            // this._menu.style.position = 'static'
-            this._menu.style.removeProperty('margin')
-            this._menu.style.removeProperty('transform')
             Manipulator.setDataAttribute(this._menu, 'popper', 'static') // todo:v6 remove?
+            instance.setOptions({
+              modifiers: [{
+                name: 'applyStyles',
+                enabled: false
+              }]
+            })
+          } else {
+            this._menu.style.position = state.styles.popper.position // put back position
           }
         }
       }]
index 2bbd7c00a794a6813bf1d70147f13296575325c2..0eb0872746ec4bb06e0a801d2f474c2795f32eb6 100644 (file)
@@ -1093,7 +1093,7 @@ describe('Dropdown', () => {
   })
 
   describe('update', () => {
-    it('should call Popper and detect navbar on update', () => {
+    it('should call Popper on update', () => {
       fixtureEl.innerHTML = [
         '<div class="dropdown">',
         '  <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
@@ -1111,33 +1111,10 @@ describe('Dropdown', () => {
       expect(dropdown._popper).not.toBeNull()
 
       const spyUpdate = spyOn(dropdown._popper, 'update')
-      const spyDetect = spyOn(dropdown, '_detectNavbar')
 
       dropdown.update()
 
       expect(spyUpdate).toHaveBeenCalled()
-      expect(spyDetect).toHaveBeenCalled()
-    })
-
-    it('should just detect navbar on update', () => {
-      fixtureEl.innerHTML = [
-        '<div class="dropdown">',
-        '  <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
-        '  <div class="dropdown-menu">',
-        '    <a class="dropdown-item" href="#">Secondary link</a>',
-        '  </div>',
-        '</div>'
-      ].join('')
-
-      const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
-      const dropdown = new Dropdown(btnDropdown)
-
-      const spy = spyOn(dropdown, '_detectNavbar')
-
-      dropdown.update()
-
-      expect(dropdown._popper).toBeNull()
-      expect(spy).toHaveBeenCalled()
     })
   })
 
@@ -1185,33 +1162,6 @@ describe('Dropdown', () => {
       })
     })
 
-    it('should not use "static" Popper in navbar', () => {
-      return new Promise(resolve => {
-        fixtureEl.innerHTML = [
-          '<nav class="navbar navbar-expand-md bg-light">',
-          '  <div class="dropdown">',
-          '    <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
-          '    <div class="dropdown-menu">',
-          '      <a class="dropdown-item" href="#">Secondary link</a>',
-          '    </div>',
-          '  </div>',
-          '</nav>'
-        ].join('')
-
-        const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
-        const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
-        const dropdown = new Dropdown(btnDropdown)
-
-        btnDropdown.addEventListener('shown.bs.dropdown', () => {
-          expect(dropdown._popper).not.toBeNull()
-          expect(dropdownMenu.getAttribute('data-bs-popper')).toEqual('static')
-          resolve()
-        })
-
-        dropdown.show()
-      })
-    })
-
     it('should not collapse the dropdown when clicking a select option nested in the dropdown', () => {
       return new Promise(resolve => {
         fixtureEl.innerHTML = [
@@ -1255,13 +1205,13 @@ describe('Dropdown', () => {
       })
     })
 
-    it('should manage bs attribute `data-bs-popper`="static" when dropdown is in navbar', () => {
+    it('should manage bs attribute `data-bs-popper`="static" when dropdown has position=static', () => {
       return new Promise(resolve => {
         fixtureEl.innerHTML = [
           '<nav class="navbar navbar-expand-md bg-light">',
           '  <div class="dropdown">',
           '    <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
-          '    <div class="dropdown-menu">',
+          '    <div class="dropdown-menu" style="position:static;">',
           '      <a class="dropdown-item" href="#">Secondary link</a>',
           '    </div>',
           '  </div>',
@@ -1273,8 +1223,13 @@ describe('Dropdown', () => {
         const dropdown = new Dropdown(btnDropdown)
 
         btnDropdown.addEventListener('shown.bs.dropdown', () => {
-          expect(dropdownMenu.getAttribute('data-bs-popper')).toEqual('static')
-          dropdown.hide()
+          setTimeout(() => {
+            expect(dropdownMenu.getAttribute('data-bs-popper')).toEqual('static')
+            expect(dropdownMenu.style.getPropertyValue('margin')).toEqual('')
+            expect(dropdownMenu.style.getPropertyValue('position')).toEqual('')
+            expect(dropdownMenu.style.getPropertyValue('transform')).toEqual('')
+            dropdown.hide()
+          })
         })
 
         btnDropdown.addEventListener('hidden.bs.dropdown', () => {
@@ -1286,7 +1241,7 @@ describe('Dropdown', () => {
       })
     })
 
-    it('should not use Popper if display set to static', () => {
+    it('should handle Popper if display set to static', () => {
       return new Promise(resolve => {
         fixtureEl.innerHTML = [
           '<div class="dropdown">',
@@ -1302,7 +1257,51 @@ describe('Dropdown', () => {
 
         btnDropdown.addEventListener('shown.bs.dropdown', () => {
           // Popper adds this attribute when we use it
+
           expect(dropdownMenu.getAttribute('data-popper-placement')).toBeNull()
+          setTimeout(() => {
+            expect(dropdownMenu.style.getPropertyValue('margin')).toEqual('')
+            expect(dropdownMenu.style.getPropertyValue('position')).toEqual('')
+            expect(dropdownMenu.style.getPropertyValue('transform')).toEqual('')
+            resolve()
+          })
+        })
+
+        btnDropdown.click()
+      })
+    })
+
+    it('should handle Popper if css position is set to static', () => {
+      return new Promise(resolve => {
+        fixtureEl.innerHTML = [
+          '<style>',
+          '  .dropdown-menu { position: static }',
+          '</style>',
+          '<div class="dropdown">',
+          '  <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+          '  <div class="dropdown-menu">',
+          '    <a class="dropdown-item" href="#">Secondary link</a>',
+          '  </div>',
+          '</div>'
+        ].join('')
+
+        const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+        const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
+
+        btnDropdown.addEventListener('shown.bs.dropdown', () => {
+          // Popper adds this attribute when we use it
+          expect(dropdownMenu.getAttribute('data-popper-placement')).toBeNull()
+          setTimeout(() => {
+            expect(dropdownMenu.getAttribute('data-bs-popper')).toEqual('static')
+            expect(dropdownMenu.style.getPropertyValue('margin')).toEqual('')
+            expect(dropdownMenu.style.getPropertyValue('position')).toEqual('')
+            expect(dropdownMenu.style.getPropertyValue('transform')).toEqual('')
+            btnDropdown.click()
+          })
+        })
+
+        btnDropdown.addEventListener('hidden.bs.dropdown', () => {
+          expect(dropdownMenu.getAttribute('data-bs-popper')).toBeNull()
           resolve()
         })
 
@@ -1326,8 +1325,10 @@ describe('Dropdown', () => {
         const dropdown = new Dropdown(btnDropdown)
 
         btnDropdown.addEventListener('shown.bs.dropdown', () => {
-          expect(dropdownMenu.getAttribute('data-bs-popper')).toEqual('static')
-          dropdown.hide()
+          setTimeout(() => {
+            expect(dropdownMenu.getAttribute('data-bs-popper')).toEqual('static')
+            dropdown.hide()
+          })
         })
 
         btnDropdown.addEventListener('hidden.bs.dropdown', () => {
@@ -1974,7 +1975,7 @@ describe('Dropdown', () => {
         const dropdown = new Dropdown(triggerDropdown)
         const button = fixtureEl.querySelector('button[data-bs-toggle="dropdown"]')
 
-        const spy = spyOn(dropdown, 'toggle')
+        spyOn(dropdown, 'toggle')
 
         // Key escape
         button.focus()
@@ -1984,7 +1985,7 @@ describe('Dropdown', () => {
         button.dispatchEvent(keydownEscape)
 
         setTimeout(() => {
-          expect(spy).not.toHaveBeenCalled()
+          expect(dropdown.toggle).not.toHaveBeenCalled()
           expect(triggerDropdown).not.toHaveClass('show')
           resolve()
         }, 20)
index 04cf06d7b62ce08656c5a9920cb668cd28362649..498bb7fe339bfb4008584b3eadab2ce1fb6028b3 100644 (file)
     <div class="container">
       <h1>Dropdown <small>Bootstrap Visual Test</small></h1>
 
+
+      <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
+        <div class="container-fluid">
+          <a class="navbar-brand" href="#">Expand at lg</a>
+          <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarsExample05" aria-controls="navbarsExample05" aria-expanded="false" aria-label="Toggle navigation">
+            <span class="navbar-toggler-icon"></span>
+          </button>
+
+          <div class="collapse navbar-collapse" id="navbarsExample05">
+            <ul class="navbar-nav me-auto mb-2 mb-lg-0">
+              <li class="nav-item">
+                <a class="nav-link active" aria-current="page" href="#">Home</a>
+              </li>
+              <li class="nav-item">
+                <a class="nav-link" href="#">Link</a>
+              </li>
+              <li class="nav-item">
+                <a class="nav-link disabled">Disabled</a>
+              </li>
+              <li class="nav-item dropdown">
+                <a class="nav-link dropdown-toggle" href="#" id="dropdown05" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
+                <ul class="dropdown-menu" aria-labelledby="dropdown05">
+                  <li><a class="dropdown-item" href="#">Action</a></li>
+                  <li><a class="dropdown-item" href="#">Another action</a></li>
+                  <li><a class="dropdown-item" href="#">Something else here</a></li>
+                </ul>
+              </li>
+            </ul>
+            <form role="search">
+              <input class="form-control" type="search" placeholder="Search" aria-label="Search">
+            </form>
+            <div class="nav-item dropdown">
+              <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
+                Positioned dropdown
+              </a>
+              <ul class="dropdown-menu" aria-labelledby="navbarDropdown">
+                <li><a class="dropdown-item" href="#">Action</a></li>
+                <li><a class="dropdown-item" href="#">Another action</a></li>
+                <li><a class="dropdown-item" href="#">Another action</a></li>
+                <li><a class="dropdown-item" href="#">Another action</a></li>
+                <li><a class="dropdown-item" href="#">Another action</a></li>
+                <li><a class="dropdown-item" href="#">Another action</a></li>
+                <li><a class="dropdown-item" href="#">Another action</a></li>
+                <li><a class="dropdown-item" href="#">Another action</a></li>
+                <li><a class="dropdown-item" href="#">Another action</a></li>
+                <li><a class="dropdown-item" href="#">Another action</a></li>
+                <li><a class="dropdown-item" href="#">Another action</a></li>
+                <li><a class="dropdown-item" href="#">Another action</a></li>
+                <li><a class="dropdown-item" href="#">Another action</a></li>
+                <li><a class="dropdown-item" href="#">Another action</a></li>
+                <li><a class="dropdown-item" href="#">Another action</a></li>
+                <li><a class="dropdown-item" href="#">Another action</a></li>
+                <li><a class="dropdown-item" href="#">Another action</a></li>
+                <li><a class="dropdown-item" href="#">Another action</a></li>
+                <li><hr class="dropdown-divider"></li>
+                <li><a class="dropdown-item" href="#">Something else here</a></li>
+              </ul>
+            </div>
+          </div>
+        </div>
+      </nav>
+
       <nav class="navbar navbar-expand-md bg-light">
         <a class="navbar-brand" href="#">Navbar</a>
         <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
@@ -28,7 +90,7 @@
               <a class="nav-link" href="#">Link</a>
             </li>
             <li class="nav-item dropdown">
-              <a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
+              <a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown" data-bs-offset="0,20" aria-expanded="false">Dropdown</a>
               <ul class="dropdown-menu">
                 <li><a class="dropdown-item" href="#">Action</a></li>
                 <li><a class="dropdown-item" href="#">Another action</a></li>
index 8cc52db064fe0b52e5176fa2cc97790d2b851fe8..8230c9a5f58f040512e5cae505c4981b34558e2d 100644 (file)
@@ -1,7 +1,3 @@
-body {
-  padding-top: 5rem;
-}
-
 .form-control-dark {
   border-color: var(--bs-gray);
 }