Begin to use Popper for Dropdown

This commit is contained in:
Johann-S 2017-04-14 11:25:53 +02:00
parent d8996a7e0a
commit 54a8ab4011
4 changed files with 97 additions and 22 deletions

View File

@ -10,6 +10,13 @@ import Util from './util'
const Dropdown = (($) => { const Dropdown = (($) => {
/**
* Check for Popper dependency
* Popper - https://popper.js.org
*/
if (typeof Popper === 'undefined') {
throw new Error('Bootstrap dropdown require Popper (https://popper.js.org)')
}
/** /**
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
@ -55,6 +62,20 @@ const Dropdown = (($) => {
VISIBLE_ITEMS : '.dropdown-menu .dropdown-item:not(.disabled)' VISIBLE_ITEMS : '.dropdown-menu .dropdown-item:not(.disabled)'
} }
const Default = {
animation : true,
trigger : 'click',
placement : 'bottom',
offset : '0 0'
}
const DefaultType = {
animation : 'boolean',
trigger : 'string',
placement : 'string',
offset : 'string'
}
/** /**
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
@ -64,8 +85,11 @@ const Dropdown = (($) => {
class Dropdown { class Dropdown {
constructor(element) { constructor(element, config) {
this._element = element this._element = element
this._popper = null
this._config = this._getConfig(config)
this._menu = this._getMenuElement()
this._addEventListeners() this._addEventListeners()
} }
@ -77,16 +101,30 @@ const Dropdown = (($) => {
return VERSION return VERSION
} }
static get Default() {
return Default
}
static get DefaultType() {
return DefaultType
}
// public // public
toggle() { toggle() {
if (this.disabled || $(this).hasClass(ClassName.DISABLED)) { let context = $(this).data(DATA_KEY)
if (!context) {
context = new Dropdown(this)
$(this).data(DATA_KEY, context)
}
if (context.disabled || $(this).hasClass(ClassName.DISABLED)) {
return false return false
} }
const parent = Dropdown._getParentFromElement(this) const parent = Dropdown._getParentFromElement(this)
const isActive = $(parent).hasClass(ClassName.SHOW) const isActive = $(context._menu).hasClass(ClassName.SHOW)
Dropdown._clearMenus() Dropdown._clearMenus()
@ -97,7 +135,7 @@ const Dropdown = (($) => {
const relatedTarget = { const relatedTarget = {
relatedTarget : this relatedTarget : this
} }
const showEvent = $.Event(Event.SHOW, relatedTarget) const showEvent = $.Event(Event.SHOW, relatedTarget)
$(parent).trigger(showEvent) $(parent).trigger(showEvent)
@ -105,6 +143,13 @@ const Dropdown = (($) => {
return false return false
} }
this._popper = new Popper(this, context._menu, {
placement : context._config.placement,
offsets : {
popper : context._config.offset
}
})
// if this is a touch-enabled device we add extra // if this is a touch-enabled device we add extra
// empty mouseover listeners to the body's immediate children; // empty mouseover listeners to the body's immediate children;
// only needed because of broken event delegation on iOS // only needed because of broken event delegation on iOS
@ -117,8 +162,10 @@ const Dropdown = (($) => {
this.focus() this.focus()
this.setAttribute('aria-expanded', true) this.setAttribute('aria-expanded', true)
$(parent).toggleClass(ClassName.SHOW) $(context._menu).toggleClass(ClassName.SHOW)
$(parent).trigger($.Event(Event.SHOWN, relatedTarget)) $(parent)
.toggleClass(ClassName.SHOW)
.trigger($.Event(Event.SHOWN, relatedTarget))
return false return false
} }
@ -127,6 +174,10 @@ const Dropdown = (($) => {
$.removeData(this._element, DATA_KEY) $.removeData(this._element, DATA_KEY)
$(this._element).off(EVENT_KEY) $(this._element).off(EVENT_KEY)
this._element = null this._element = null
this._menu = null
if (this._popper !== null) {
this._popper.destroy()
}
} }
@ -136,15 +187,40 @@ const Dropdown = (($) => {
$(this._element).on(Event.CLICK, this.toggle) $(this._element).on(Event.CLICK, this.toggle)
} }
_getConfig(config) {
config = $.extend(
{},
this.constructor.Default,
$(this._element).data(),
config
)
Util.typeCheckConfig(
NAME,
config,
this.constructor.DefaultType
)
return config
}
_getMenuElement() {
if (!this._menu) {
let parent = Dropdown._getParentFromElement(this._element)
this._menu = $(parent).find(Selector.MENU)[0]
}
return this._menu
}
// static // static
static _jQueryInterface(config) { static _jQueryInterface(config) {
return this.each(function () { return this.each(function () {
let data = $(this).data(DATA_KEY) let data = $(this).data(DATA_KEY)
let _config = typeof config === 'object' ? config : null
if (!data) { if (!data) {
data = new Dropdown(this) data = new Dropdown(this, _config)
$(this).data(DATA_KEY, data) $(this).data(DATA_KEY, data)
} }
@ -164,13 +240,18 @@ const Dropdown = (($) => {
} }
const toggles = $.makeArray($(Selector.DATA_TOGGLE)) const toggles = $.makeArray($(Selector.DATA_TOGGLE))
for (let i = 0; i < toggles.length; i++) { for (let i = 0; i < toggles.length; i++) {
const parent = Dropdown._getParentFromElement(toggles[i]) const parent = Dropdown._getParentFromElement(toggles[i])
let context = $(toggles[i]).data(DATA_KEY)
const relatedTarget = { const relatedTarget = {
relatedTarget : toggles[i] relatedTarget : toggles[i]
} }
if (!context) {
continue
}
let dropdownMenu = context._menu
if (!$(parent).hasClass(ClassName.SHOW)) { if (!$(parent).hasClass(ClassName.SHOW)) {
continue continue
} }
@ -195,6 +276,7 @@ const Dropdown = (($) => {
toggles[i].setAttribute('aria-expanded', 'false') toggles[i].setAttribute('aria-expanded', 'false')
$(dropdownMenu).removeClass(ClassName.SHOW)
$(parent) $(parent)
.removeClass(ClassName.SHOW) .removeClass(ClassName.SHOW)
.trigger($.Event(Event.HIDDEN, relatedTarget)) .trigger($.Event(Event.HIDDEN, relatedTarget))

View File

@ -14,7 +14,7 @@ const Tooltip = (($) => {
/** /**
* Check for Popper dependency * Check for Popper dependency
* Tether - https://popper.js.org * Popper - https://popper.js.org
*/ */
if (typeof Popper === 'undefined') { if (typeof Popper === 'undefined') {
throw new Error('Bootstrap tooltips require Popper (https://popper.js.org)') throw new Error('Bootstrap tooltips require Popper (https://popper.js.org)')

View File

@ -61,6 +61,7 @@
</div> </div>
<script src="../../../docs/assets/js/vendor/jquery-slim.min.js"></script> <script src="../../../docs/assets/js/vendor/jquery-slim.min.js"></script>
<script src="../../../docs/assets/js/vendor/popper.min.js"></script>
<script src="../../dist/util.js"></script> <script src="../../dist/util.js"></script>
<script src="../../dist/dropdown.js"></script> <script src="../../dist/dropdown.js"></script>
<script src="../../dist/collapse.js"></script> <script src="../../dist/collapse.js"></script>

View File

@ -100,11 +100,6 @@
// Open state for the dropdown // Open state for the dropdown
.show { .show {
// Show the menu
> .dropdown-menu {
display: block;
}
// Remove the outline when :focus is triggered // Remove the outline when :focus is triggered
> a { > a {
outline: 0; outline: 0;
@ -125,6 +120,10 @@
left: 0; left: 0;
} }
.dropdown-menu.show {
display: block;
}
// Dropdown section headers // Dropdown section headers
.dropdown-header { .dropdown-header {
display: block; display: block;
@ -139,11 +138,4 @@
// //
// Just add .dropup after the standard .dropdown class and you're set. // Just add .dropup after the standard .dropdown class and you're set.
.dropup { .dropup {}
// Different positioning for bottom up menu
.dropdown-menu {
top: auto;
bottom: 100%;
margin-bottom: $dropdown-margin-top;
}
}