From 6cf0fe878067ba46872212da92e5288fb3331312 Mon Sep 17 00:00:00 2001 From: Johann-S Date: Thu, 6 Apr 2017 23:16:07 +0200 Subject: Use Popper for tooltip and popover --- js/src/popover.js | 2 -- js/src/tooltip.js | 73 +++++++++++++++++-------------------------------------- 2 files changed, 22 insertions(+), 53 deletions(-) (limited to 'js/src') diff --git a/js/src/popover.js b/js/src/popover.js index b68b47998..e20b50f97 100644 --- a/js/src/popover.js +++ b/js/src/popover.js @@ -118,8 +118,6 @@ const Popover = (($) => { this.setElementContent($tip.find(Selector.CONTENT), this._getContent()) $tip.removeClass(`${ClassName.FADE} ${ClassName.SHOW}`) - - this.cleanupTether() } // private diff --git a/js/src/tooltip.js b/js/src/tooltip.js index 47c3d8d05..c4c4ee2f6 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -1,4 +1,4 @@ -/* global Tether */ +/* global Popper */ import Util from './util' @@ -13,11 +13,11 @@ import Util from './util' const Tooltip = (($) => { /** - * Check for Tether dependency - * Tether - http://tether.io/ + * Check for Popper dependency + * Tether - https://popper.js.org */ - if (typeof Tether === 'undefined') { - throw new Error('Bootstrap tooltips require Tether (http://tether.io/)') + if (typeof Popper === 'undefined') { + throw new Error('Bootstrap tooltips require Popper (https://popper.js.org)') } @@ -33,8 +33,6 @@ const Tooltip = (($) => { const EVENT_KEY = `.${DATA_KEY}` const JQUERY_NO_CONFLICT = $.fn[NAME] const TRANSITION_DURATION = 150 - const CLASS_PREFIX = 'bs-tether' - const TETHER_PREFIX_REGEX = new RegExp(`(^|\\s)${CLASS_PREFIX}\\S+`, 'g') const Default = { animation : true, @@ -66,10 +64,10 @@ const Tooltip = (($) => { } const AttachmentMap = { - TOP : 'bottom center', - RIGHT : 'middle left', - BOTTOM : 'top center', - LEFT : 'middle right' + TOP : 'top', + RIGHT : 'right', + BOTTOM : 'bottom', + LEFT : 'left' } const HoverState = { @@ -100,11 +98,6 @@ const Tooltip = (($) => { TOOLTIP_INNER : '.tooltip-inner' } - const TetherClass = { - element : false, - enabled : false - } - const Trigger = { HOVER : 'hover', FOCUS : 'focus', @@ -128,7 +121,7 @@ const Tooltip = (($) => { this._timeout = 0 this._hoverState = '' this._activeTrigger = {} - this._tether = null + this._popper = null // protected this.element = element @@ -220,8 +213,6 @@ const Tooltip = (($) => { dispose() { clearTimeout(this._timeout) - this.cleanupTether() - $.removeData(this.element, this.constructor.DATA_KEY) $(this.element).off(this.constructor.EVENT_KEY) @@ -235,7 +226,7 @@ const Tooltip = (($) => { this._timeout = null this._hoverState = null this._activeTrigger = null - this._tether = null + this._popper = null this.element = null this.config = null @@ -288,19 +279,19 @@ const Tooltip = (($) => { $(this.element).trigger(this.constructor.Event.INSERTED) - this._tether = new Tether({ - attachment, - element : tip, - target : this.element, - classes : TetherClass, - classPrefix : CLASS_PREFIX, - offset : this.config.offset, - constraints : this.config.constraints, - addTargetClasses: false + this._popper = new Popper(this.element, tip, { + placement : attachment, + modifiers : { + arrow : { + element : Selector.TOOLTIP + }, + offset : { + offset : this.config.offset + } + } }) Util.reflow(tip) - this._tether.position() $(tip).addClass(ClassName.SHOW) @@ -342,11 +333,9 @@ const Tooltip = (($) => { tip.parentNode.removeChild(tip) } - this._cleanTipClass() this.element.removeAttribute('aria-describedby') $(this.element).trigger(this.constructor.Event.HIDDEN) - this.cleanupTether() - + this._popper.destroy() if (callback) { callback() } @@ -398,12 +387,8 @@ const Tooltip = (($) => { setContent() { const $tip = $(this.getTipElement()) - this.setElementContent($tip.find(Selector.TOOLTIP_INNER), this.getTitle()) - $tip.removeClass(`${ClassName.FADE} ${ClassName.SHOW}`) - - this.cleanupTether() } setElementContent($element, content) { @@ -434,12 +419,6 @@ const Tooltip = (($) => { return title } - cleanupTether() { - if (this._tether) { - this._tether.destroy() - } - } - // private @@ -447,14 +426,6 @@ const Tooltip = (($) => { return AttachmentMap[placement.toUpperCase()] } - _cleanTipClass() { - const $tip = $(this.getTipElement()) - const tabClass = $tip.attr('class').match(TETHER_PREFIX_REGEX) - if (tabClass !== null && tabClass.length > 0) { - $tip.removeClass(tabClass.join('')) - } - } - _setListeners() { const triggers = this.config.trigger.split(' ') -- cgit v1.2.3 From 81e07ec05218d75d64454787449dcb870b5b66ec Mon Sep 17 00:00:00 2001 From: Johann-S Date: Fri, 7 Apr 2017 11:12:17 +0200 Subject: Begin to add arrow to Popover and Tooltip --- js/src/popover.js | 1 + js/src/tooltip.js | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'js/src') diff --git a/js/src/popover.js b/js/src/popover.js index e20b50f97..02efe2b2e 100644 --- a/js/src/popover.js +++ b/js/src/popover.js @@ -28,6 +28,7 @@ const Popover = (($) => { trigger : 'click', content : '', template : '' }) diff --git a/js/src/tooltip.js b/js/src/tooltip.js index c4c4ee2f6..505a8d492 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -37,6 +37,7 @@ const Tooltip = (($) => { const Default = { animation : true, template : '', trigger : 'hover focus', title : '', @@ -281,10 +282,8 @@ const Tooltip = (($) => { this._popper = new Popper(this.element, tip, { placement : attachment, + arrowElement : '.arrow', modifiers : { - arrow : { - element : Selector.TOOLTIP - }, offset : { offset : this.config.offset } @@ -335,7 +334,10 @@ const Tooltip = (($) => { this.element.removeAttribute('aria-describedby') $(this.element).trigger(this.constructor.Event.HIDDEN) - this._popper.destroy() + if (this._popper !== null) { + this._popper.destroy() + } + if (callback) { callback() } -- cgit v1.2.3 From b40b1bc396adb80944b887f72d0ae616277c852d Mon Sep 17 00:00:00 2001 From: Johann-S Date: Fri, 7 Apr 2017 13:20:34 +0200 Subject: Add attachment classes --- js/src/popover.js | 14 ++++++++++++++ js/src/tooltip.js | 16 ++++++++++++++++ 2 files changed, 30 insertions(+) (limited to 'js/src') diff --git a/js/src/popover.js b/js/src/popover.js index 02efe2b2e..f89d3d5c8 100644 --- a/js/src/popover.js +++ b/js/src/popover.js @@ -22,6 +22,8 @@ const Popover = (($) => { const DATA_KEY = 'bs.popover' const EVENT_KEY = `.${DATA_KEY}` const JQUERY_NO_CONFLICT = $.fn[NAME] + const CLASS_PREFIX = 'bs-popover' + const BSCLS_PREFIX_REGEX = new RegExp(`(^|\\s)${CLASS_PREFIX}\\S+`, 'g') const Default = $.extend({}, Tooltip.Default, { placement : 'right', @@ -107,6 +109,10 @@ const Popover = (($) => { return this.getTitle() || this._getContent() } + addAttachmentClass(attachment) { + $(this.getTipElement()).addClass(`${CLASS_PREFIX}-${attachment}`) + } + getTipElement() { return this.tip = this.tip || $(this.config.template)[0] } @@ -130,6 +136,14 @@ const Popover = (($) => { this.config.content) } + _cleanTipClass() { + const $tip = $(this.getTipElement()) + const tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX) + if (tabClass !== null && tabClass.length > 0) { + $tip.removeClass(tabClass.join('')) + } + } + // static diff --git a/js/src/tooltip.js b/js/src/tooltip.js index 505a8d492..fb4ff131c 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -33,6 +33,8 @@ const Tooltip = (($) => { const EVENT_KEY = `.${DATA_KEY}` const JQUERY_NO_CONFLICT = $.fn[NAME] const TRANSITION_DURATION = 150 + const CLASS_PREFIX = 'bs-tooltip' + const BSCLS_PREFIX_REGEX = new RegExp(`(^|\\s)${CLASS_PREFIX}\\S+`, 'g') const Default = { animation : true, @@ -269,6 +271,7 @@ const Tooltip = (($) => { this.config.placement const attachment = this._getAttachment(placement) + this.addAttachmentClass(attachment) const container = this.config.container === false ? document.body : $(this.config.container) @@ -332,6 +335,7 @@ const Tooltip = (($) => { tip.parentNode.removeChild(tip) } + this._cleanTipClass() this.element.removeAttribute('aria-describedby') $(this.element).trigger(this.constructor.Event.HIDDEN) if (this._popper !== null) { @@ -383,6 +387,10 @@ const Tooltip = (($) => { return Boolean(this.getTitle()) } + addAttachmentClass(attachment) { + $(this.getTipElement()).addClass(`${CLASS_PREFIX}-${attachment}`) + } + getTipElement() { return this.tip = this.tip || $(this.config.template)[0] } @@ -624,6 +632,14 @@ const Tooltip = (($) => { return config } + _cleanTipClass() { + const $tip = $(this.getTipElement()) + const tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX) + if (tabClass !== null && tabClass.length > 0) { + $tip.removeClass(tabClass.join('')) + } + } + // static -- cgit v1.2.3 From d8996a7e0a90ad2a00151c5e14bae6a37bf8e186 Mon Sep 17 00:00:00 2001 From: Johann-S Date: Sat, 8 Apr 2017 21:13:15 +0200 Subject: Fix arrow for tooltip and popover --- js/src/tooltip.js | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'js/src') diff --git a/js/src/tooltip.js b/js/src/tooltip.js index fb4ff131c..c380f8675 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -285,11 +285,8 @@ const Tooltip = (($) => { this._popper = new Popper(this.element, tip, { placement : attachment, - arrowElement : '.arrow', - modifiers : { - offset : { - offset : this.config.offset - } + offsets : { + popper : this.config.offset } }) @@ -632,13 +629,13 @@ const Tooltip = (($) => { return config } - _cleanTipClass() { - const $tip = $(this.getTipElement()) - const tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX) - if (tabClass !== null && tabClass.length > 0) { - $tip.removeClass(tabClass.join('')) + _cleanTipClass() { + const $tip = $(this.getTipElement()) + const tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX) + if (tabClass !== null && tabClass.length > 0) { + $tip.removeClass(tabClass.join('')) + } } - } // static -- cgit v1.2.3 From 54a8ab40111dacdf50fad22e6f36d2801ba653c9 Mon Sep 17 00:00:00 2001 From: Johann-S Date: Fri, 14 Apr 2017 11:25:53 +0200 Subject: Begin to use Popper for Dropdown --- js/src/dropdown.js | 98 +++++++++++++++++++++++++++++++++++++++++++++++++----- js/src/tooltip.js | 2 +- 2 files changed, 91 insertions(+), 9 deletions(-) (limited to 'js/src') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index eb536dc7d..a2b5561c2 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -10,6 +10,13 @@ import Util from './util' 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)' } + 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 { - constructor(element) { + constructor(element, config) { this._element = element + this._popper = null + this._config = this._getConfig(config) + this._menu = this._getMenuElement() this._addEventListeners() } @@ -77,16 +101,30 @@ const Dropdown = (($) => { return VERSION } + static get Default() { + return Default + } + + static get DefaultType() { + return DefaultType + } + // public 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 } const parent = Dropdown._getParentFromElement(this) - const isActive = $(parent).hasClass(ClassName.SHOW) + const isActive = $(context._menu).hasClass(ClassName.SHOW) Dropdown._clearMenus() @@ -97,7 +135,7 @@ const Dropdown = (($) => { const relatedTarget = { relatedTarget : this } - const showEvent = $.Event(Event.SHOW, relatedTarget) + const showEvent = $.Event(Event.SHOW, relatedTarget) $(parent).trigger(showEvent) @@ -105,6 +143,13 @@ const Dropdown = (($) => { 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 // empty mouseover listeners to the body's immediate children; // only needed because of broken event delegation on iOS @@ -117,8 +162,10 @@ const Dropdown = (($) => { this.focus() this.setAttribute('aria-expanded', true) - $(parent).toggleClass(ClassName.SHOW) - $(parent).trigger($.Event(Event.SHOWN, relatedTarget)) + $(context._menu).toggleClass(ClassName.SHOW) + $(parent) + .toggleClass(ClassName.SHOW) + .trigger($.Event(Event.SHOWN, relatedTarget)) return false } @@ -127,6 +174,10 @@ const Dropdown = (($) => { $.removeData(this._element, DATA_KEY) $(this._element).off(EVENT_KEY) 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) } + _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 _jQueryInterface(config) { return this.each(function () { let data = $(this).data(DATA_KEY) + let _config = typeof config === 'object' ? config : null if (!data) { - data = new Dropdown(this) + data = new Dropdown(this, _config) $(this).data(DATA_KEY, data) } @@ -164,13 +240,18 @@ const Dropdown = (($) => { } const toggles = $.makeArray($(Selector.DATA_TOGGLE)) - for (let i = 0; i < toggles.length; i++) { const parent = Dropdown._getParentFromElement(toggles[i]) + let context = $(toggles[i]).data(DATA_KEY) const relatedTarget = { relatedTarget : toggles[i] } + if (!context) { + continue + } + + let dropdownMenu = context._menu if (!$(parent).hasClass(ClassName.SHOW)) { continue } @@ -195,6 +276,7 @@ const Dropdown = (($) => { toggles[i].setAttribute('aria-expanded', 'false') + $(dropdownMenu).removeClass(ClassName.SHOW) $(parent) .removeClass(ClassName.SHOW) .trigger($.Event(Event.HIDDEN, relatedTarget)) diff --git a/js/src/tooltip.js b/js/src/tooltip.js index c380f8675..2c22a7ed4 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -14,7 +14,7 @@ const Tooltip = (($) => { /** * Check for Popper dependency - * Tether - https://popper.js.org + * Popper - https://popper.js.org */ if (typeof Popper === 'undefined') { throw new Error('Bootstrap tooltips require Popper (https://popper.js.org)') -- cgit v1.2.3 From c21a2b0d92ca78b63bb9ec21ca0fbf9e9206a18e Mon Sep 17 00:00:00 2001 From: Johann-S Date: Fri, 14 Apr 2017 12:05:54 +0200 Subject: Remove constraints option and check every options --- js/src/dropdown.js | 14 ++++++-------- js/src/tooltip.js | 12 ++++++------ 2 files changed, 12 insertions(+), 14 deletions(-) (limited to 'js/src') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index a2b5561c2..ad5ee8d9f 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -63,17 +63,13 @@ const Dropdown = (($) => { } const Default = { - animation : true, - trigger : 'click', placement : 'bottom', - offset : '0 0' + offset : {} } const DefaultType = { - animation : 'boolean', - trigger : 'string', placement : 'string', - offset : 'string' + offset : 'number' } @@ -145,8 +141,10 @@ const Dropdown = (($) => { this._popper = new Popper(this, context._menu, { placement : context._config.placement, - offsets : { - popper : context._config.offset + modifiers : { + offset : { + offset : this.config.offset + } } }) diff --git a/js/src/tooltip.js b/js/src/tooltip.js index 2c22a7ed4..5f5e3d7bc 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -47,8 +47,7 @@ const Tooltip = (($) => { html : false, selector : false, placement : 'top', - offset : '0 0', - constraints : [], + offset : {}, container : false } @@ -61,8 +60,7 @@ const Tooltip = (($) => { html : 'boolean', selector : '(string|boolean)', placement : '(string|function)', - offset : 'string', - constraints : 'array', + offset : 'number', container : '(string|element|boolean)' } @@ -285,8 +283,10 @@ const Tooltip = (($) => { this._popper = new Popper(this.element, tip, { placement : attachment, - offsets : { - popper : this.config.offset + modifiers : { + offset : { + offset : this.config.offset + } } }) -- cgit v1.2.3 From 69de65180f750cadf5f96a774d2524f69d19beab Mon Sep 17 00:00:00 2001 From: Johann-S Date: Fri, 14 Apr 2017 13:30:55 +0200 Subject: Fix unit tests + Update Popper to 1.6.0 --- js/src/dropdown.js | 14 ++++++++------ js/src/tooltip.js | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'js/src') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index ad5ee8d9f..ce25e9671 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -1,3 +1,5 @@ +/* global Popper */ + import Util from './util' @@ -64,7 +66,7 @@ const Dropdown = (($) => { const Default = { placement : 'bottom', - offset : {} + offset : 0 } const DefaultType = { @@ -143,7 +145,7 @@ const Dropdown = (($) => { placement : context._config.placement, modifiers : { offset : { - offset : this.config.offset + offset : context._config.offset } } }) @@ -204,7 +206,7 @@ const Dropdown = (($) => { _getMenuElement() { if (!this._menu) { - let parent = Dropdown._getParentFromElement(this._element) + const parent = Dropdown._getParentFromElement(this._element) this._menu = $(parent).find(Selector.MENU)[0] } return this._menu @@ -215,7 +217,7 @@ const Dropdown = (($) => { static _jQueryInterface(config) { return this.each(function () { let data = $(this).data(DATA_KEY) - let _config = typeof config === 'object' ? config : null + const _config = typeof config === 'object' ? config : null if (!data) { data = new Dropdown(this, _config) @@ -240,7 +242,7 @@ const Dropdown = (($) => { const toggles = $.makeArray($(Selector.DATA_TOGGLE)) for (let i = 0; i < toggles.length; i++) { const parent = Dropdown._getParentFromElement(toggles[i]) - let context = $(toggles[i]).data(DATA_KEY) + const context = $(toggles[i]).data(DATA_KEY) const relatedTarget = { relatedTarget : toggles[i] } @@ -249,7 +251,7 @@ const Dropdown = (($) => { continue } - let dropdownMenu = context._menu + const dropdownMenu = context._menu if (!$(parent).hasClass(ClassName.SHOW)) { continue } diff --git a/js/src/tooltip.js b/js/src/tooltip.js index 5f5e3d7bc..9995cede7 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -47,7 +47,7 @@ const Tooltip = (($) => { html : false, selector : false, placement : 'top', - offset : {}, + offset : 0, container : false } -- cgit v1.2.3 From 53ee455bc735af9fc54de586ed4d23ac56b69ab8 Mon Sep 17 00:00:00 2001 From: Johann-S Date: Mon, 17 Apr 2017 14:26:40 +0200 Subject: Handle dropup for Dropdown --- js/src/dropdown.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'js/src') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index ce25e9671..33171cf20 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -64,8 +64,13 @@ const Dropdown = (($) => { VISIBLE_ITEMS : '.dropdown-menu .dropdown-item:not(.disabled)' } + const AttachmentMap = { + TOP : 'top', + BOTTOM : 'bottom' + } + const Default = { - placement : 'bottom', + placement : AttachmentMap.BOTTOM, offset : 0 } @@ -141,8 +146,10 @@ const Dropdown = (($) => { return false } + // Handle dropup + const dropdownPlacement = $(this).parent().hasClass('dropup') ? AttachmentMap.TOP : context._config.placement this._popper = new Popper(this, context._menu, { - placement : context._config.placement, + placement : dropdownPlacement, modifiers : { offset : { offset : context._config.offset -- cgit v1.2.3 From d5fabf8de50710c5a09ecd91f4b9e961e67d7937 Mon Sep 17 00:00:00 2001 From: Johann-S Date: Tue, 18 Apr 2017 14:02:24 +0200 Subject: Remove totaly Tether from documentation + dependencies --- js/src/dropdown.js | 6 +++--- js/src/tooltip.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'js/src') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 33171cf20..d678a3a02 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -17,7 +17,7 @@ const Dropdown = (($) => { * Popper - https://popper.js.org */ if (typeof Popper === 'undefined') { - throw new Error('Bootstrap dropdown require Popper (https://popper.js.org)') + throw new Error('Bootstrap dropdown require Popper.js (https://popper.js.org)') } /** @@ -75,8 +75,8 @@ const Dropdown = (($) => { } const DefaultType = { - placement : 'string', - offset : 'number' + placement : 'string', + offset : '(number|string)' } diff --git a/js/src/tooltip.js b/js/src/tooltip.js index 9995cede7..2c34ac5d7 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -17,7 +17,7 @@ const Tooltip = (($) => { * Popper - https://popper.js.org */ if (typeof Popper === 'undefined') { - throw new Error('Bootstrap tooltips require Popper (https://popper.js.org)') + throw new Error('Bootstrap tooltips require Popper.js (https://popper.js.org)') } @@ -60,7 +60,7 @@ const Tooltip = (($) => { html : 'boolean', selector : '(string|boolean)', placement : '(string|function)', - offset : 'number', + offset : '(number|string)', container : '(string|element|boolean)' } -- cgit v1.2.3 From 18e4e851e2829aedc6d1ff2b703ba5cae2c0a288 Mon Sep 17 00:00:00 2001 From: Johann-S Date: Wed, 19 Apr 2017 10:20:50 +0200 Subject: Better placement for Dropdown + Handle flip of Tooltip/Popover --- js/src/dropdown.js | 4 ++-- js/src/tooltip.js | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'js/src') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index d678a3a02..613a23812 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -65,8 +65,8 @@ const Dropdown = (($) => { } const AttachmentMap = { - TOP : 'top', - BOTTOM : 'bottom' + TOP : 'top-start', + BOTTOM : 'bottom-start' } const Default = { diff --git a/js/src/tooltip.js b/js/src/tooltip.js index 2c34ac5d7..b446d9bcc 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -287,6 +287,12 @@ const Tooltip = (($) => { offset : { offset : this.config.offset } + }, + onCreate : (data) => { + this._handlePopperPlacementChange(data) + }, + onUpdate : (data) => { + this._handlePopperPlacementChange(data) } }) @@ -637,6 +643,12 @@ const Tooltip = (($) => { } } + _handlePopperPlacementChange(data) { + if (data.originalPlacement !== data.placement) { + this._cleanTipClass() + this.addAttachmentClass(this._getAttachment(data.placement)) + } + } // static -- cgit v1.2.3 From fc8b85b62670b8396cac7fb821c025c58fa77a78 Mon Sep 17 00:00:00 2001 From: Johann-S Date: Wed, 19 Apr 2017 10:59:10 +0200 Subject: Fix some css for the arrow of Popover/Tooltip + update documentation --- js/src/tooltip.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'js/src') diff --git a/js/src/tooltip.js b/js/src/tooltip.js index b446d9bcc..a8c0ab6f1 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -289,7 +289,9 @@ const Tooltip = (($) => { } }, onCreate : (data) => { - this._handlePopperPlacementChange(data) + if (data.originalPlacement !== data.placement) { + this._handlePopperPlacementChange(data) + } }, onUpdate : (data) => { this._handlePopperPlacementChange(data) @@ -644,10 +646,8 @@ const Tooltip = (($) => { } _handlePopperPlacementChange(data) { - if (data.originalPlacement !== data.placement) { this._cleanTipClass() this.addAttachmentClass(this._getAttachment(data.placement)) - } } // static -- cgit v1.2.3 From e5a0471b0b618409e30529a5e02933d5a74a4cc5 Mon Sep 17 00:00:00 2001 From: Johann-S Date: Wed, 19 Apr 2017 15:08:06 +0200 Subject: Add an update method to allow to update position for Tooltip/Popover/Dropdown manually --- js/src/dropdown.js | 6 ++++++ js/src/tooltip.js | 12 ++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'js/src') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 613a23812..0c082edd6 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -185,8 +185,14 @@ const Dropdown = (($) => { if (this._popper !== null) { this._popper.destroy() } + this._popper = null } + update() { + if (this._popper !== null) { + this._popper.scheduleUpdate() + } + } // private diff --git a/js/src/tooltip.js b/js/src/tooltip.js index a8c0ab6f1..d50ddbb3e 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -227,6 +227,9 @@ const Tooltip = (($) => { this._timeout = null this._hoverState = null this._activeTrigger = null + if (this._popper !== null) { + this._popper.destroy() + } this._popper = null this.element = null @@ -385,6 +388,11 @@ const Tooltip = (($) => { } + update() { + if (this._popper !== null) { + this._popper.scheduleUpdate() + } + } // protected @@ -646,8 +654,8 @@ const Tooltip = (($) => { } _handlePopperPlacementChange(data) { - this._cleanTipClass() - this.addAttachmentClass(this._getAttachment(data.placement)) + this._cleanTipClass() + this.addAttachmentClass(this._getAttachment(data.placement)) } // static -- cgit v1.2.3 From 4f882a840c9f2b62f543c32d56b3e904582ced90 Mon Sep 17 00:00:00 2001 From: Johann-S Date: Fri, 21 Apr 2017 10:49:04 +0200 Subject: Allow to disable flip behaviour on Dropdown + documentation --- js/src/dropdown.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'js/src') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 0c082edd6..71247728a 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -71,12 +71,14 @@ const Dropdown = (($) => { const Default = { placement : AttachmentMap.BOTTOM, - offset : 0 + offset : 0, + flip : true } const DefaultType = { placement : 'string', - offset : '(number|string)' + offset : '(number|string)', + flip : 'boolean' } @@ -153,6 +155,9 @@ const Dropdown = (($) => { modifiers : { offset : { offset : context._config.offset + }, + flip : { + enabled : context._config.flip } } }) @@ -201,6 +206,11 @@ const Dropdown = (($) => { } _getConfig(config) { + const elementData = $(this._element).data() + if (elementData.placement !== undefined) { + elementData.placement = AttachmentMap[elementData.placement.toUpperCase()] + } + config = $.extend( {}, this.constructor.Default, -- cgit v1.2.3 From 0ae9d28ba3e9c4f119a3ba0b370717993350be2c Mon Sep 17 00:00:00 2001 From: Johann-S Date: Fri, 5 May 2017 21:22:55 +0200 Subject: Add fallbackPlacement option for Tooltip and Popover --- js/src/dropdown.js | 3 ++- js/src/tooltip.js | 55 +++++++++++++++++++++++++++++------------------------- 2 files changed, 32 insertions(+), 26 deletions(-) (limited to 'js/src') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 71247728a..1da2098dd 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -157,7 +157,8 @@ const Dropdown = (($) => { offset : context._config.offset }, flip : { - enabled : context._config.flip + enabled : context._config.flip, + behavior : [AttachmentMap.TOP, AttachmentMap.BOTTOM] } } }) diff --git a/js/src/tooltip.js b/js/src/tooltip.js index d50ddbb3e..eb517252e 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -36,32 +36,18 @@ const Tooltip = (($) => { const CLASS_PREFIX = 'bs-tooltip' const BSCLS_PREFIX_REGEX = new RegExp(`(^|\\s)${CLASS_PREFIX}\\S+`, 'g') - const Default = { - animation : true, - template : '', - trigger : 'hover focus', - title : '', - delay : 0, - html : false, - selector : false, - placement : 'top', - offset : 0, - container : false - } - const DefaultType = { - animation : 'boolean', - template : 'string', - title : '(string|element|function)', - trigger : 'string', - delay : '(number|object)', - html : 'boolean', - selector : '(string|boolean)', - placement : '(string|function)', - offset : '(number|string)', - container : '(string|element|boolean)' + animation : 'boolean', + template : 'string', + title : '(string|element|function)', + trigger : 'string', + delay : '(number|object)', + html : 'boolean', + selector : '(string|boolean)', + placement : '(string|function)', + offset : '(number|string)', + container : '(string|element|boolean)', + fallbackPlacement : '(string|array)' } const AttachmentMap = { @@ -71,6 +57,22 @@ const Tooltip = (($) => { LEFT : 'left' } + const Default = { + animation : true, + template : '', + trigger : 'hover focus', + title : '', + delay : 0, + html : false, + selector : false, + placement : 'top', + offset : 0, + container : false, + fallbackPlacement : [AttachmentMap.TOP, AttachmentMap.RIGHT, AttachmentMap.BOTTOM, AttachmentMap.LEFT] + } + const HoverState = { SHOW : 'show', OUT : 'out' @@ -289,6 +291,9 @@ const Tooltip = (($) => { modifiers : { offset : { offset : this.config.offset + }, + flip : { + behavior : this.config.fallbackPlacement } }, onCreate : (data) => { -- cgit v1.2.3 From 0cdf176f7a4cdc66aa6c84898c6795c8fd4bc58a Mon Sep 17 00:00:00 2001 From: Johann-S Date: Thu, 11 May 2017 11:29:46 +0200 Subject: Use _jQueryInterface for Dropdown to call toggle method --- js/src/dropdown.js | 54 ++++++++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 28 deletions(-) (limited to 'js/src') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 1da2098dd..39a4a86ca 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -114,51 +114,43 @@ const Dropdown = (($) => { return DefaultType } - // public toggle() { - 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 + if (this._element.disabled || $(this._element).hasClass(ClassName.DISABLED)) { + return } - const parent = Dropdown._getParentFromElement(this) - const isActive = $(context._menu).hasClass(ClassName.SHOW) + const parent = Dropdown._getParentFromElement(this._element) + const isActive = $(this._menu).hasClass(ClassName.SHOW) Dropdown._clearMenus() if (isActive) { - return false + return } const relatedTarget = { - relatedTarget : this + relatedTarget : this._element } const showEvent = $.Event(Event.SHOW, relatedTarget) $(parent).trigger(showEvent) if (showEvent.isDefaultPrevented()) { - return false + return } // Handle dropup - const dropdownPlacement = $(this).parent().hasClass('dropup') ? AttachmentMap.TOP : context._config.placement - this._popper = new Popper(this, context._menu, { + const dropdownPlacement = $(this._element).parent().hasClass('dropup') ? AttachmentMap.TOP : this._config.placement + this._popper = new Popper(this._element, this._menu, { placement : dropdownPlacement, modifiers : { offset : { - offset : context._config.offset + offset : this._config.offset }, flip : { - enabled : context._config.flip, - behavior : [AttachmentMap.TOP, AttachmentMap.BOTTOM] + enabled : this._config.flip } } }) @@ -172,15 +164,13 @@ const Dropdown = (($) => { $('body').children().on('mouseover', null, $.noop) } - this.focus() - this.setAttribute('aria-expanded', true) + this._element.focus() + this._element.setAttribute('aria-expanded', true) - $(context._menu).toggleClass(ClassName.SHOW) + $(this._menu).toggleClass(ClassName.SHOW) $(parent) .toggleClass(ClassName.SHOW) .trigger($.Event(Event.SHOWN, relatedTarget)) - - return false } dispose() { @@ -203,7 +193,11 @@ const Dropdown = (($) => { // private _addEventListeners() { - $(this._element).on(Event.CLICK, this.toggle) + $(this._element).on(Event.CLICK, (event) => { + event.preventDefault() + event.stopPropagation() + this.toggle() + }) } _getConfig(config) { @@ -252,7 +246,7 @@ const Dropdown = (($) => { if (data[config] === undefined) { throw new Error(`No method named "${config}"`) } - data[config].call(this) + data[config]() } }) } @@ -266,7 +260,7 @@ const Dropdown = (($) => { const toggles = $.makeArray($(Selector.DATA_TOGGLE)) for (let i = 0; i < toggles.length; i++) { const parent = Dropdown._getParentFromElement(toggles[i]) - const context = $(toggles[i]).data(DATA_KEY) + const context = $(toggles[i]).data(DATA_KEY) const relatedTarget = { relatedTarget : toggles[i] } @@ -382,7 +376,11 @@ const Dropdown = (($) => { .on(Event.KEYDOWN_DATA_API, Selector.DATA_TOGGLE, Dropdown._dataApiKeydownHandler) .on(Event.KEYDOWN_DATA_API, Selector.MENU, Dropdown._dataApiKeydownHandler) .on(`${Event.CLICK_DATA_API} ${Event.KEYUP_DATA_API}`, Dropdown._clearMenus) - .on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, Dropdown.prototype.toggle) + .on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) { + event.preventDefault() + event.stopPropagation() + Dropdown._jQueryInterface.call($(this), 'toggle') + }) .on(Event.CLICK_DATA_API, Selector.FORM_CHILD, (e) => { e.stopPropagation() }) -- cgit v1.2.3 From cc455c16c3363fed5b360cdaa780e612d10caf74 Mon Sep 17 00:00:00 2001 From: Johann-S Date: Fri, 12 May 2017 09:39:27 +0200 Subject: Fix bad position for Tooltips with animation at true --- js/src/tooltip.js | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'js/src') diff --git a/js/src/tooltip.js b/js/src/tooltip.js index eb517252e..6d3db06ab 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -306,8 +306,6 @@ const Tooltip = (($) => { } }) - Util.reflow(tip) - $(tip).addClass(ClassName.SHOW) // if this is a touch-enabled device we add extra @@ -319,6 +317,9 @@ const Tooltip = (($) => { } const complete = () => { + if (this.config.animation) { + this._fixTransition() + } const prevHoverState = this._hoverState this._hoverState = null @@ -333,10 +334,10 @@ const Tooltip = (($) => { $(this.tip) .one(Util.TRANSITION_END, complete) .emulateTransitionEnd(Tooltip._TRANSITION_DURATION) - return } - - complete() + else { + complete() + } } } @@ -663,6 +664,19 @@ const Tooltip = (($) => { this.addAttachmentClass(this._getAttachment(data.placement)) } + _fixTransition() { + const tip = this.getTipElement() + const initConfigAnimation = this.config.animation + if (tip.getAttribute('x-placement') !== null) { + return; + } + $(tip).removeClass(ClassName.FADE) + this.config.animation = false + this.hide() + this.show() + this.config.animation = initConfigAnimation + } + // static static _jQueryInterface(config) { -- cgit v1.2.3 From c78cbb275b0c559f5c9436ee3df816e1f6195201 Mon Sep 17 00:00:00 2001 From: Johann-S Date: Fri, 12 May 2017 21:22:12 +0200 Subject: Change fallbackPlacement to flip by default for Tooltips/Popovers --- js/src/tooltip.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'js/src') diff --git a/js/src/tooltip.js b/js/src/tooltip.js index 6d3db06ab..f447ed4ce 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -70,7 +70,7 @@ const Tooltip = (($) => { placement : 'top', offset : 0, container : false, - fallbackPlacement : [AttachmentMap.TOP, AttachmentMap.RIGHT, AttachmentMap.BOTTOM, AttachmentMap.LEFT] + fallbackPlacement : 'flip' } const HoverState = { @@ -334,8 +334,7 @@ const Tooltip = (($) => { $(this.tip) .one(Util.TRANSITION_END, complete) .emulateTransitionEnd(Tooltip._TRANSITION_DURATION) - } - else { + } else { complete() } } @@ -668,7 +667,7 @@ const Tooltip = (($) => { const tip = this.getTipElement() const initConfigAnimation = this.config.animation if (tip.getAttribute('x-placement') !== null) { - return; + return } $(tip).removeClass(ClassName.FADE) this.config.animation = false -- cgit v1.2.3 From b36d8ae6cb9dcd2e4183202a747d53706f1c1c8a Mon Sep 17 00:00:00 2001 From: Johann-S Date: Wed, 17 May 2017 22:03:11 +0200 Subject: Use popper to align dropdown menu instead of using css with important --- js/src/dropdown.js | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) (limited to 'js/src') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 39a4a86ca..846746384 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -52,8 +52,11 @@ const Dropdown = (($) => { } const ClassName = { - DISABLED : 'disabled', - SHOW : 'show' + DISABLED : 'disabled', + SHOW : 'show', + DROPUP : 'dropup', + MENURIGHT : 'dropdown-menu-right', + MENULEFT : 'dropdown-menu-left' } const Selector = { @@ -142,7 +145,7 @@ const Dropdown = (($) => { } // Handle dropup - const dropdownPlacement = $(this._element).parent().hasClass('dropup') ? AttachmentMap.TOP : this._config.placement + const dropdownPlacement = $(this._element).parent().hasClass(ClassName.DROPUP) ? AttachmentMap.TOP : this._config.placement this._popper = new Popper(this._element, this._menu, { placement : dropdownPlacement, modifiers : { @@ -151,6 +154,11 @@ const Dropdown = (($) => { }, flip : { enabled : this._config.flip + }, + beforeApplyStyle: { + order: 899, // 900 is the order of applyStyle + enabled: true, + fn: this._beforePopperApplyStyle } } }) @@ -230,6 +238,23 @@ const Dropdown = (($) => { return this._menu } + _beforePopperApplyStyle(data) { + if ($(data.instance.popper).hasClass(ClassName.MENURIGHT)) { + data.styles = { + right: 0, + left: 'auto' + } + } + + if ($(data.instance.popper).hasClass(ClassName.MENULEFT)) { + data.styles = { + right: 'auto', + left: 0 + } + } + return data + } + // static static _jQueryInterface(config) { -- cgit v1.2.3 From 70f4a30defaa1d3269385ce713a5926ab84d7727 Mon Sep 17 00:00:00 2001 From: Johann-S Date: Mon, 22 May 2017 16:14:10 +0200 Subject: Better management of dropdown/dropup with alignment --- js/src/dropdown.js | 48 ++++++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 22 deletions(-) (limited to 'js/src') diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 846746384..acc3ed453 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -68,8 +68,10 @@ const Dropdown = (($) => { } const AttachmentMap = { - TOP : 'top-start', - BOTTOM : 'bottom-start' + TOP : 'top-start', + TOPEND : 'top-end', + BOTTOM : 'bottom-start', + BOTTOMEND : 'bottom-end' } const Default = { @@ -144,21 +146,21 @@ const Dropdown = (($) => { return } - // Handle dropup - const dropdownPlacement = $(this._element).parent().hasClass(ClassName.DROPUP) ? AttachmentMap.TOP : this._config.placement - this._popper = new Popper(this._element, this._menu, { - placement : dropdownPlacement, + let element = this._element + // for dropup with alignment we use the parent as popper container + if ($(parent).hasClass(ClassName.DROPUP)) { + if ($(this._menu).hasClass(ClassName.MENULEFT) || $(this._menu).hasClass(ClassName.MENURIGHT)) { + element = parent + } + } + this._popper = new Popper(element, this._menu, { + placement : this._getPlacement(), modifiers : { offset : { offset : this._config.offset }, flip : { enabled : this._config.flip - }, - beforeApplyStyle: { - order: 899, // 900 is the order of applyStyle - enabled: true, - fn: this._beforePopperApplyStyle } } }) @@ -238,21 +240,23 @@ const Dropdown = (($) => { return this._menu } - _beforePopperApplyStyle(data) { - if ($(data.instance.popper).hasClass(ClassName.MENURIGHT)) { - data.styles = { - right: 0, - left: 'auto' + _getPlacement() { + const $parentDropdown = $(this._element).parent() + let placement = this._config.placement + + // Handle dropup + if ($parentDropdown.hasClass(ClassName.DROPUP) || this._config.placement === AttachmentMap.TOP) { + placement = AttachmentMap.TOP + if ($(this._menu).hasClass(ClassName.MENURIGHT)) { + placement = AttachmentMap.TOPEND } } - - if ($(data.instance.popper).hasClass(ClassName.MENULEFT)) { - data.styles = { - right: 'auto', - left: 0 + else { + if ($(this._menu).hasClass(ClassName.MENURIGHT)) { + placement = AttachmentMap.BOTTOMEND } } - return data + return placement } // static -- cgit v1.2.3 From aa36439e173720701c6eac1929c699056714df9c Mon Sep 17 00:00:00 2001 From: Johann-S Date: Tue, 23 May 2017 14:17:07 +0200 Subject: Use Popper.js to manage arrow position --- js/src/popover.js | 2 +- js/src/tooltip.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'js/src') diff --git a/js/src/popover.js b/js/src/popover.js index f89d3d5c8..6c9d78664 100644 --- a/js/src/popover.js +++ b/js/src/popover.js @@ -30,7 +30,7 @@ const Popover = (($) => { trigger : 'click', content : '', template : '' }) diff --git a/js/src/tooltip.js b/js/src/tooltip.js index f447ed4ce..ceb9bc04c 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -60,7 +60,7 @@ const Tooltip = (($) => { const Default = { animation : true, template : '', trigger : 'hover focus', title : '', -- cgit v1.2.3 From 2c72af88ee177758f67bc7797b95f7dfc95f701b Mon Sep 17 00:00:00 2001 From: Johann-S Date: Wed, 24 May 2017 13:48:32 +0200 Subject: Placement auto for tooltips --- js/src/tooltip.js | 1 + 1 file changed, 1 insertion(+) (limited to 'js/src') diff --git a/js/src/tooltip.js b/js/src/tooltip.js index ceb9bc04c..1d53b0470 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -51,6 +51,7 @@ const Tooltip = (($) => { } const AttachmentMap = { + AUTO : 'auto', TOP : 'top', RIGHT : 'right', BOTTOM : 'bottom', -- cgit v1.2.3 From 4c3b6c5ceb8eda2f0c3f23317d5862248c6d6f9b Mon Sep 17 00:00:00 2001 From: Johann-S Date: Wed, 24 May 2017 14:09:36 +0200 Subject: Placement auto for popovers --- js/src/popover.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js/src') diff --git a/js/src/popover.js b/js/src/popover.js index 6c9d78664..a068420d6 100644 --- a/js/src/popover.js +++ b/js/src/popover.js @@ -23,7 +23,7 @@ const Popover = (($) => { const EVENT_KEY = `.${DATA_KEY}` const JQUERY_NO_CONFLICT = $.fn[NAME] const CLASS_PREFIX = 'bs-popover' - const BSCLS_PREFIX_REGEX = new RegExp(`(^|\\s)${CLASS_PREFIX}\\S+`, 'g') + const BSCLS_PREFIX_REGEX = new RegExp(`(^|\\s)${CLASS_PREFIX}\\S+`, 'g') const Default = $.extend({}, Tooltip.Default, { placement : 'right', -- cgit v1.2.3