aboutsummaryrefslogtreecommitdiff
path: root/js/dropdown.js
diff options
context:
space:
mode:
authorfat <[email protected]>2015-01-03 13:58:44 -0800
committerfat <[email protected]>2015-02-11 11:29:43 -0800
commit834220ea20ce5b7cd31edfb624a28b4bf8b29a6a (patch)
tree19bfdadb0c140df437e7b7034e5e1f5ce58343cc /js/dropdown.js
parentaed1cd31218113d67d2eca3296edf5d1700b19b8 (diff)
downloadbootstrap-834220ea20ce5b7cd31edfb624a28b4bf8b29a6a.tar.xz
bootstrap-834220ea20ce5b7cd31edfb624a28b4bf8b29a6a.zip
bootstrap onto closure
Diffstat (limited to 'js/dropdown.js')
-rw-r--r--js/dropdown.js375
1 files changed, 268 insertions, 107 deletions
diff --git a/js/dropdown.js b/js/dropdown.js
index 200e1c67b..4599d5ba9 100644
--- a/js/dropdown.js
+++ b/js/dropdown.js
@@ -1,161 +1,322 @@
-/* ========================================================================
- * Bootstrap: dropdown.js v3.3.2
- * http://getbootstrap.com/javascript/#dropdowns
+/** =======================================================================
+ * Bootstrap: dropdown.js v4.0.0
+ * http://getbootstrap.com/javascript/#dropdown
* ========================================================================
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
+ * ========================================================================
+ * @fileoverview - Add dropdown menus to nearly anything with this simple
+ * plugin, including the navbar, tabs, and pills.
+ *
+ * Public Methods & Properties:
+ *
+ * + $.dropdown
+ * + $.dropdown.noConflict
+ * + $.dropdown.Constructor
+ * + $.dropdown.Constructor.VERSION
+ * + $.dropdown.Constructor.prototype.toggle
+ *
+ * ========================================================================
+ */
+
+'use strict';
+
+
+/**
+ * Our dropdown class.
+ * @param {Element!} element
+ * @constructor
+ */
+var Dropdown = function (element) {
+ $(element).on('click.bs.dropdown', this['toggle'])
+}
+
+
+/**
+ * @const
+ * @type {string}
+ */
+Dropdown['VERSION'] = '4.0.0'
+
+
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+Dropdown._NAME = 'dropdown'
+
+
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+Dropdown._DATA_KEY = 'bs.dropdown'
+
+
+/**
+ * @const
+ * @type {Function}
+ * @private
+ */
+Dropdown._JQUERY_NO_CONFLICT = $.fn[Dropdown._NAME]
+
+
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Dropdown._Event = {
+ HIDE : 'hide.bs.dropdown',
+ HIDDEN : 'hidden.bs.dropdown',
+ SHOW : 'show.bs.dropdown',
+ SHOWN : 'shown.bs.dropdown'
+}
+
+
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Dropdown._ClassName = {
+ BACKDROP : 'dropdown-backdrop',
+ DISABLED : 'disabled',
+ OPEN : 'open'
+}
+
+
+/**
+ * @const
+ * @enum {string}
+ * @private
+ */
+Dropdown._Selector = {
+ BACKDROP : '.dropdown-backdrop',
+ DATA_TOGGLE : '[data-toggle="dropdown"]',
+ FORM_CHILD : '.dropdown form',
+ ROLE_MENU : '[role="menu"]',
+ ROLE_LISTBOX : '[role="listbox"]',
+ NAVBAR_NAV : '.navbar-nav',
+ VISIBLE_ITEMS : '[role="menu"] li:not(.divider) a, [role="listbox"] li:not(.divider) a'
+}
+
+
+/**
+ * Provides the jQuery Interface for the alert component.
+ * @param {string=} opt_config
+ * @this {jQuery}
+ * @return {jQuery}
+ * @private
+ */
+Dropdown._jQueryInterface = function (opt_config) {
+ return this.each(function () {
+ var data = $(this).data(Dropdown._DATA_KEY)
+
+ if (!data) {
+ $(this).data(Dropdown._DATA_KEY, (data = new Dropdown(this)))
+ }
-+function ($) {
- 'use strict';
+ if (typeof opt_config === 'string') {
+ data[opt_config].call(this)
+ }
+ })
+}
- // DROPDOWN CLASS DEFINITION
- // =========================
- var backdrop = '.dropdown-backdrop'
- var toggle = '[data-toggle="dropdown"]'
- var Dropdown = function (element) {
- $(element).on('click.bs.dropdown', this.toggle)
+/**
+ * @param {Event=} opt_event
+ * @private
+ */
+Dropdown._clearMenus = function (opt_event) {
+ if (opt_event && opt_event.which == 3) {
+ return
}
- Dropdown.VERSION = '3.3.2'
-
- Dropdown.prototype.toggle = function (e) {
- var $this = $(this)
+ var backdrop = $(Dropdown._Selector.BACKDROP)[0]
+ if (backdrop) {
+ backdrop.parentNode.removeChild(backdrop)
+ }
- if ($this.is('.disabled, :disabled')) return
+ var toggles = /** @type {Array.<Element>} */ ($.makeArray($(Dropdown._Selector.DATA_TOGGLE)))
- var $parent = getParent($this)
- var isActive = $parent.hasClass('open')
+ for (var i = 0; i < toggles.length; i++) {
+ var parent = Dropdown._getParentFromElement(toggles[i])
+ var relatedTarget = { 'relatedTarget': toggles[i] }
- clearMenus()
+ if (!$(parent).hasClass(Dropdown._ClassName.OPEN)) {
+ continue
+ }
- if (!isActive) {
- if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
- // if mobile we use a backdrop because click events don't delegate
- $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
- }
+ var hideEvent = $.Event(Dropdown._Event.HIDE, relatedTarget)
+ $(parent).trigger(hideEvent)
+ if (hideEvent.isDefaultPrevented()) {
+ continue
+ }
- var relatedTarget = { relatedTarget: this }
- $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
+ toggles[i].setAttribute('aria-expanded', 'false')
- if (e.isDefaultPrevented()) return
+ $(parent)
+ .removeClass(Dropdown._ClassName.OPEN)
+ .trigger(Dropdown._Event.HIDDEN, relatedTarget)
+ }
+}
- $this
- .trigger('focus')
- .attr('aria-expanded', 'true')
- $parent
- .toggleClass('open')
- .trigger('shown.bs.dropdown', relatedTarget)
- }
+/**
+ * @param {Element} element
+ * @return {Element}
+ * @private
+ */
+Dropdown._getParentFromElement = function (element) {
+ var selector = Bootstrap.getSelectorFromElement(element)
- return false
+ if (selector) {
+ var parent = $(selector)[0]
}
- Dropdown.prototype.keydown = function (e) {
- if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return
+ return /** @type {Element} */ (parent || element.parentNode)
+}
+
- var $this = $(this)
+/**
+ * @param {Event} event
+ * @this {Element}
+ * @private
+ */
+Dropdown._dataApiKeydownHandler = function (event) {
+ if (!/(38|40|27|32)/.test(event.which) || /input|textarea/i.test(event.target.tagName)) {
+ return
+ }
- e.preventDefault()
- e.stopPropagation()
+ event.preventDefault()
+ event.stopPropagation()
- if ($this.is('.disabled, :disabled')) return
+ if (this.disabled || $(this).hasClass(Dropdown._ClassName.DISABLED)) {
+ return
+ }
- var $parent = getParent($this)
- var isActive = $parent.hasClass('open')
+ var parent = Dropdown._getParentFromElement(this)
+ var isActive = $(parent).hasClass(Dropdown._ClassName.OPEN)
- if ((!isActive && e.which != 27) || (isActive && e.which == 27)) {
- if (e.which == 27) $parent.find(toggle).trigger('focus')
- return $this.trigger('click')
+ if ((!isActive && event.which != 27) || (isActive && event.which == 27)) {
+ if (event.which == 27) {
+ var toggle = $(parent).find(Dropdown._Selector.DATA_TOGGLE)[0]
+ $(toggle).trigger('focus')
}
+ $(this).trigger('click')
+ return
+ }
- var desc = ' li:not(.divider):visible a'
- var $items = $parent.find('[role="menu"]' + desc + ', [role="listbox"]' + desc)
+ var items = $.makeArray($(Dropdown._Selector.VISIBLE_ITEMS))
- if (!$items.length) return
+ items = items.filter(function (item) {
+ return item.offsetWidth || item.offsetHeight
+ })
- var index = $items.index(e.target)
+ if (!items.length) {
+ return
+ }
- if (e.which == 38 && index > 0) index-- // up
- if (e.which == 40 && index < $items.length - 1) index++ // down
- if (!~index) index = 0
+ var index = items.indexOf(event.target)
- $items.eq(index).trigger('focus')
- }
+ if (event.which == 38 && index > 0) index-- // up
+ if (event.which == 40 && index < items.length - 1) index++ // down
+ if (!~index) index = 0
+
+ items[index].focus()
+}
- function clearMenus(e) {
- if (e && e.which === 3) return
- $(backdrop).remove()
- $(toggle).each(function () {
- var $this = $(this)
- var $parent = getParent($this)
- var relatedTarget = { relatedTarget: this }
- if (!$parent.hasClass('open')) return
+/**
+ * Toggles the dropdown
+ * @this {Element}
+ * @return {boolean|undefined}
+ */
+Dropdown.prototype['toggle'] = function () {
+ if (this.disabled || $(this).hasClass(Dropdown._ClassName.DISABLED)) {
+ return
+ }
- $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
+ var parent = Dropdown._getParentFromElement(this)
+ var isActive = $(parent).hasClass(Dropdown._ClassName.OPEN)
- if (e.isDefaultPrevented()) return
+ Dropdown._clearMenus()
- $this.attr('aria-expanded', 'false')
- $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
- })
+ if (isActive) {
+ return false
}
- function getParent($this) {
- var selector = $this.attr('data-target')
+ if ('ontouchstart' in document.documentElement && !$(parent).closest(Dropdown._Selector.NAVBAR_NAV).length) {
+ // if mobile we use a backdrop because click events don't delegate
+ var dropdown = document.createElement('div')
+ dropdown.className = Dropdown._ClassName.BACKDROP
+ this.parentNode.insertBefore(this, dropdown)
+ $(dropdown).on('click', Dropdown._clearMenus)
+ }
- if (!selector) {
- selector = $this.attr('href')
- selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
- }
+ var relatedTarget = { 'relatedTarget': this }
+ var showEvent = $.Event(Dropdown._Event.SHOW, relatedTarget)
- var $parent = selector && $(selector)
+ $(parent).trigger(showEvent)
- return $parent && $parent.length ? $parent : $this.parent()
+ if (showEvent.isDefaultPrevented()) {
+ return
}
+ this.focus()
+ this.setAttribute('aria-expanded', 'true')
- // DROPDOWN PLUGIN DEFINITION
- // ==========================
+ $(parent).toggleClass(Dropdown._ClassName.OPEN)
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.dropdown')
+ $(parent).trigger(Dropdown._Event.SHOWN, relatedTarget)
- if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
- if (typeof option == 'string') data[option].call($this)
- })
- }
+ return false
+}
- var old = $.fn.dropdown
- $.fn.dropdown = Plugin
- $.fn.dropdown.Constructor = Dropdown
+/**
+ * ------------------------------------------------------------------------
+ * jQuery Interface + noConflict implementaiton
+ * ------------------------------------------------------------------------
+ */
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Dropdown._NAME] = Dropdown._jQueryInterface
- // DROPDOWN NO CONFLICT
- // ====================
- $.fn.dropdown.noConflict = function () {
- $.fn.dropdown = old
- return this
- }
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Dropdown._NAME]['Constructor'] = Dropdown
+
+/**
+ * @const
+ * @type {Function}
+ */
+$.fn[Dropdown._NAME]['noConflict'] = function () {
+ $.fn[Dropdown._NAME] = Dropdown._JQUERY_NO_CONFLICT
+ return this
+}
- // APPLY TO STANDARD DROPDOWN ELEMENTS
- // ===================================
- $(document)
- .on('click.bs.dropdown.data-api', clearMenus)
- .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
- .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
- .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
- .on('keydown.bs.dropdown.data-api', '[role="menu"]', Dropdown.prototype.keydown)
- .on('keydown.bs.dropdown.data-api', '[role="listbox"]', Dropdown.prototype.keydown)
+/**
+ * ------------------------------------------------------------------------
+ * Data Api implementation
+ * ------------------------------------------------------------------------
+ */
-}(jQuery);
+$(document)
+ .on('click.bs.dropdown.data-api', Dropdown._clearMenus)
+ .on('click.bs.dropdown.data-api', Dropdown._Selector.FORM_CHILD, function (e) { e.stopPropagation() })
+ .on('click.bs.dropdown.data-api', Dropdown._Selector.DATA_TOGGLE, Dropdown.prototype['toggle'])
+ .on('keydown.bs.dropdown.data-api', Dropdown._Selector.DATA_TOGGLE, Dropdown._dataApiKeydownHandler)
+ .on('keydown.bs.dropdown.data-api', Dropdown._Selector.ROLE_MENU, Dropdown._dataApiKeydownHandler)
+ .on('keydown.bs.dropdown.data-api', Dropdown._Selector.ROLE_LISTBOX, Dropdown._dataApiKeydownHandler)