]> git.ipfire.org Git - thirdparty/bootstrap.git/commitdiff
dropdown: add boundary config option (#24976)
authorTroy Morehouse <troymore@nbnet.nb.ca>
Tue, 12 Dec 2017 09:28:30 +0000 (05:28 -0400)
committerXhmikosR <xhmikosr@gmail.com>
Tue, 12 Dec 2017 09:28:30 +0000 (11:28 +0200)
docs/4.0/components/dropdowns.md
js/src/dropdown.js
js/tests/unit/dropdown.js

index cde123b00c413625a0972b855289ba727c0706ca..926729a3d9abae94d895efc28ee5d122ba4229c3 100644 (file)
@@ -723,9 +723,17 @@ Options can be passed via data attributes or JavaScript. For data attributes, ap
       <td>true</td>
       <td>Allow Dropdown to flip in case of an overlapping on the reference element. For more information refer to Popper.js's <a href="https://popper.js.org/popper-documentation.html#modifiers..flip.enabled">flip docs</a>.</td>
     </tr>
+    <tr>
+      <td>boundary</td>
+      <td>string | element</td>
+      <td>'scrollParent'</td>
+      <td>Overflow constraint boundary of the dropdown menu. Accepts the values of <code>'viewport'</code>, <code>'window'</code>, <code>'scrollParent'</code>, or an HTMLElement reference (JavaScript only). For more information refer to Popper.js's <a href="https://popper.js.org/popper-documentation.html#modifiers..preventOverflow.boundariesElement">preventOverflow docs</a>.</td>
+    </tr>
   </tbody>
 </table>
 
+Note when `boundary` is set to any value other than `'scrollParent'`, the style `position: static` is applied to the `.dropdown` container.
+
 ### Methods
 
 | Method | Description |
index 8affedc6ce9e614a42038229a8b8fec806dec4e5..56559b43457652fa3bc507141b471631a12592bf 100644 (file)
@@ -50,7 +50,8 @@ const Dropdown = (($) => {
     DROPRIGHT : 'dropright',
     DROPLEFT  : 'dropleft',
     MENURIGHT : 'dropdown-menu-right',
-    MENULEFT  : 'dropdown-menu-left'
+    MENULEFT  : 'dropdown-menu-left',
+    POSITION_STATIC : 'position-static'
   }
 
   const Selector = {
@@ -74,12 +75,14 @@ const Dropdown = (($) => {
 
   const Default = {
     offset      : 0,
-    flip        : true
+    flip        : true,
+    boundary    : 'scrollParent'
   }
 
   const DefaultType = {
     offset      : '(number|string|function)',
-    flip        : 'boolean'
+    flip        : 'boolean',
+    boundary    : '(string|element)'
   }
 
 
@@ -159,6 +162,12 @@ const Dropdown = (($) => {
             element = parent
           }
         }
+        // If boundary is not `scrollParent`, then set position to `static`
+        // to allow the menu to "escape" the scroll parent's boundaries
+        // https://github.com/twbs/bootstrap/issues/24251
+        if (this._config.boundary !== 'scrollParent') {
+          $(parent).addClass(ClassName.POSITION_STATIC)
+        }
         this._popper = new Popper(element, this._menu, this._getPopperConfig())
       }
 
@@ -276,6 +285,9 @@ const Dropdown = (($) => {
           offset : offsetConf,
           flip : {
             enabled : this._config.flip
+          },
+          preventOverflow : {
+            boundariesElement : this._config.boundary
           }
         }
       }
index c1202266b13dd9b73faa72a2d05609735da26d5b..41c53a98ad84c74fd0c33bd0ddb82ca820d33507 100644 (file)
@@ -67,6 +67,50 @@ $(function () {
     $dropdown.trigger($.Event('click'))
   })
 
+  QUnit.test('should not add class position-static to dropdown if boundary not set', function (assert) {
+    assert.expect(1)
+    var done = assert.async()
+    var dropdownHTML = '<div class="tabs">'
+        + '<div class="dropdown">'
+        + '<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown</a>'
+        + '<div class="dropdown-menu">'
+        + '<a class="dropdown-item" href="#">Secondary link</a>'
+        + '<a class="dropdown-item" href="#">Something else here</a>'
+        + '</div>'
+        + '</div>'
+        + '</div>'
+    var $dropdown = $(dropdownHTML).find('[data-toggle="dropdown"]').bootstrapDropdown()
+    $dropdown
+      .parent('.dropdown')
+      .on('shown.bs.dropdown', function () {
+        assert.ok(!$dropdown.parent('.dropdown').hasClass('position-static'), '"position-static" class not added')
+        done()
+      })
+    $dropdown.trigger('click')
+  })
+
+  QUnit.test('should add class position-static to dropdown if boundary not scrollParent', function (assert) {
+    assert.expect(1)
+    var done = assert.async()
+    var dropdownHTML = '<div class="tabs">'
+        + '<div class="dropdown">'
+        + '<a href="#" class="dropdown-toggle" data-toggle="dropdown" data-boundary="viewport">Dropdown</a>'
+        + '<div class="dropdown-menu">'
+        + '<a class="dropdown-item" href="#">Secondary link</a>'
+        + '<a class="dropdown-item" href="#">Something else here</a>'
+        + '</div>'
+        + '</div>'
+        + '</div>'
+    var $dropdown = $(dropdownHTML).find('[data-toggle="dropdown"]').bootstrapDropdown()
+    $dropdown
+      .parent('.dropdown')
+      .on('shown.bs.dropdown', function () {
+        assert.ok($dropdown.parent('.dropdown').hasClass('position-static'), '"position-static" class added')
+        done()
+      })
+    $dropdown.trigger('click')
+  })
+
   QUnit.test('should set aria-expanded="true" on target when dropdown menu is shown', function (assert) {
     assert.expect(1)
     var done = assert.async()