From dee20ef9181e89af20e99ba959f5f7d2694bad53 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Fri, 18 Dec 2020 05:27:08 +0200 Subject: [PATCH 1/2] tooltip: move common code to a reusable function --- js/src/tooltip.js | 42 +++++++++++++++--------------------------- 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/js/src/tooltip.js b/js/src/tooltip.js index 63a30cf2fbd2..fe0566f57cc8 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -191,13 +191,7 @@ class Tooltip extends BaseComponent { } if (event) { - const dataKey = this.constructor.DATA_KEY - let context = Data.getData(event.delegateTarget, dataKey) - - if (!context) { - context = new this.constructor(event.delegateTarget, this._getDelegateConfig()) - Data.setData(event.delegateTarget, dataKey, context) - } + const context = this._initializeOnDelegatedTarget(event) context._activeTrigger.click = !context._activeTrigger.click @@ -465,6 +459,18 @@ class Tooltip extends BaseComponent { // Private + _initializeOnDelegatedTarget(event, context) { + const dataKey = this.constructor.DATA_KEY + context = context || Data.getData(event.delegateTarget, dataKey) + + if (!context) { + context = new this.constructor(event.delegateTarget, this._getDelegateConfig()) + Data.setData(event.delegateTarget, dataKey, context) + } + + return context + } + _getPopperConfig(attachment) { const defaultBsConfig = { placement: attachment, @@ -582,16 +588,7 @@ class Tooltip extends BaseComponent { } _enter(event, context) { - const dataKey = this.constructor.DATA_KEY - context = context || Data.getData(event.delegateTarget, dataKey) - - if (!context) { - context = new this.constructor( - event.delegateTarget, - this._getDelegateConfig() - ) - Data.setData(event.delegateTarget, dataKey, context) - } + context = this._initializeOnDelegatedTarget(event, context) if (event) { context._activeTrigger[ @@ -621,16 +618,7 @@ class Tooltip extends BaseComponent { } _leave(event, context) { - const dataKey = this.constructor.DATA_KEY - context = context || Data.getData(event.delegateTarget, dataKey) - - if (!context) { - context = new this.constructor( - event.delegateTarget, - this._getDelegateConfig() - ) - Data.setData(event.delegateTarget, dataKey, context) - } + context = this._initializeOnDelegatedTarget(event, context) if (event) { context._activeTrigger[ From f575221252f6579b435c8d324b0cc2f228d21681 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Mon, 18 Jan 2021 14:47:59 +0200 Subject: [PATCH 2/2] tooltip: return early in `show()` --- js/src/tooltip.js | 118 +++++++++++++++++++++++----------------------- 1 file changed, 60 insertions(+), 58 deletions(-) diff --git a/js/src/tooltip.js b/js/src/tooltip.js index fe0566f57cc8..909cb0f8a7d5 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -239,83 +239,85 @@ class Tooltip extends BaseComponent { throw new Error('Please use show on visible elements') } - if (this.isWithContent() && this._isEnabled) { - const showEvent = EventHandler.trigger(this._element, this.constructor.Event.SHOW) - const shadowRoot = findShadowRoot(this._element) - const isInTheDom = shadowRoot === null ? - this._element.ownerDocument.documentElement.contains(this._element) : - shadowRoot.contains(this._element) - - if (showEvent.defaultPrevented || !isInTheDom) { - return - } + if (!(this.isWithContent() && this._isEnabled)) { + return + } - const tip = this.getTipElement() - const tipId = getUID(this.constructor.NAME) + const showEvent = EventHandler.trigger(this._element, this.constructor.Event.SHOW) + const shadowRoot = findShadowRoot(this._element) + const isInTheDom = shadowRoot === null ? + this._element.ownerDocument.documentElement.contains(this._element) : + shadowRoot.contains(this._element) - tip.setAttribute('id', tipId) - this._element.setAttribute('aria-describedby', tipId) + if (showEvent.defaultPrevented || !isInTheDom) { + return + } - this.setContent() + const tip = this.getTipElement() + const tipId = getUID(this.constructor.NAME) - if (this.config.animation) { - tip.classList.add(CLASS_NAME_FADE) - } + tip.setAttribute('id', tipId) + this._element.setAttribute('aria-describedby', tipId) - const placement = typeof this.config.placement === 'function' ? - this.config.placement.call(this, tip, this._element) : - this.config.placement + this.setContent() - const attachment = this._getAttachment(placement) - this._addAttachmentClass(attachment) + if (this.config.animation) { + tip.classList.add(CLASS_NAME_FADE) + } - const container = this._getContainer() - Data.setData(tip, this.constructor.DATA_KEY, this) + const placement = typeof this.config.placement === 'function' ? + this.config.placement.call(this, tip, this._element) : + this.config.placement - if (!this._element.ownerDocument.documentElement.contains(this.tip)) { - container.appendChild(tip) - } + const attachment = this._getAttachment(placement) + this._addAttachmentClass(attachment) - EventHandler.trigger(this._element, this.constructor.Event.INSERTED) + const container = this._getContainer() + Data.setData(tip, this.constructor.DATA_KEY, this) - this._popper = Popper.createPopper(this._element, tip, this._getPopperConfig(attachment)) + if (!this._element.ownerDocument.documentElement.contains(this.tip)) { + container.appendChild(tip) + } - tip.classList.add(CLASS_NAME_SHOW) + EventHandler.trigger(this._element, this.constructor.Event.INSERTED) - const customClass = typeof this.config.customClass === 'function' ? this.config.customClass() : this.config.customClass - if (customClass) { - tip.classList.add(...customClass.split(' ')) - } + this._popper = Popper.createPopper(this._element, tip, this._getPopperConfig(attachment)) - // 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 - // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html - if ('ontouchstart' in document.documentElement) { - [].concat(...document.body.children).forEach(element => { - EventHandler.on(element, 'mouseover', noop()) - }) - } + tip.classList.add(CLASS_NAME_SHOW) - const complete = () => { - const prevHoverState = this._hoverState + const customClass = typeof this.config.customClass === 'function' ? this.config.customClass() : this.config.customClass + if (customClass) { + tip.classList.add(...customClass.split(' ')) + } - this._hoverState = null - EventHandler.trigger(this._element, this.constructor.Event.SHOWN) + // 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 + // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html + if ('ontouchstart' in document.documentElement) { + [].concat(...document.body.children).forEach(element => { + EventHandler.on(element, 'mouseover', noop()) + }) + } - if (prevHoverState === HOVER_STATE_OUT) { - this._leave(null, this) - } - } + const complete = () => { + const prevHoverState = this._hoverState - if (this.tip.classList.contains(CLASS_NAME_FADE)) { - const transitionDuration = getTransitionDurationFromElement(this.tip) - EventHandler.one(this.tip, 'transitionend', complete) - emulateTransitionEnd(this.tip, transitionDuration) - } else { - complete() + this._hoverState = null + EventHandler.trigger(this._element, this.constructor.Event.SHOWN) + + if (prevHoverState === HOVER_STATE_OUT) { + this._leave(null, this) } } + + if (this.tip.classList.contains(CLASS_NAME_FADE)) { + const transitionDuration = getTransitionDurationFromElement(this.tip) + EventHandler.one(this.tip, 'transitionend', complete) + emulateTransitionEnd(this.tip, transitionDuration) + } else { + complete() + } } hide() {