Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tooltip refactoring #32523

Merged
merged 5 commits into from Jan 27, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
158 changes: 74 additions & 84 deletions js/src/tooltip.js
Expand Up @@ -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

Expand Down Expand Up @@ -245,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 (!(this.isWithContent() && this._isEnabled)) {
return
XhmikosR marked this conversation as resolved.
Show resolved Hide resolved
}

if (showEvent.defaultPrevented || !isInTheDom) {
return
}
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)

const tip = this.getTipElement()
const tipId = getUID(this.constructor.NAME)
if (showEvent.defaultPrevented || !isInTheDom) {
return
}

tip.setAttribute('id', tipId)
this._element.setAttribute('aria-describedby', tipId)
const tip = this.getTipElement()
const tipId = getUID(this.constructor.NAME)

this.setContent()
tip.setAttribute('id', tipId)
this._element.setAttribute('aria-describedby', tipId)

if (this.config.animation) {
tip.classList.add(CLASS_NAME_FADE)
}
this.setContent()

const placement = typeof this.config.placement === 'function' ?
this.config.placement.call(this, tip, this._element) :
this.config.placement
if (this.config.animation) {
tip.classList.add(CLASS_NAME_FADE)
}

const attachment = this._getAttachment(placement)
this._addAttachmentClass(attachment)
const placement = typeof this.config.placement === 'function' ?
this.config.placement.call(this, tip, this._element) :
this.config.placement

const container = this._getContainer()
Data.setData(tip, this.constructor.DATA_KEY, this)
const attachment = this._getAttachment(placement)
this._addAttachmentClass(attachment)

if (!this._element.ownerDocument.documentElement.contains(this.tip)) {
container.appendChild(tip)
}
const container = this._getContainer()
Data.setData(tip, this.constructor.DATA_KEY, this)

EventHandler.trigger(this._element, this.constructor.Event.INSERTED)
if (!this._element.ownerDocument.documentElement.contains(this.tip)) {
container.appendChild(tip)
}

this._popper = Popper.createPopper(this._element, tip, this._getPopperConfig(attachment))
EventHandler.trigger(this._element, this.constructor.Event.INSERTED)

tip.classList.add(CLASS_NAME_SHOW)
this._popper = Popper.createPopper(this._element, tip, this._getPopperConfig(attachment))

const customClass = typeof this.config.customClass === 'function' ? this.config.customClass() : this.config.customClass
if (customClass) {
tip.classList.add(...customClass.split(' '))
}
tip.classList.add(CLASS_NAME_SHOW)

// 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())
})
}
const customClass = typeof this.config.customClass === 'function' ? this.config.customClass() : this.config.customClass
if (customClass) {
tip.classList.add(...customClass.split(' '))
}

const complete = () => {
const prevHoverState = this._hoverState
// 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())
})
}

this._hoverState = null
EventHandler.trigger(this._element, this.constructor.Event.SHOWN)
const complete = () => {
const prevHoverState = this._hoverState

if (prevHoverState === HOVER_STATE_OUT) {
this._leave(null, this)
}
}
this._hoverState = null
EventHandler.trigger(this._element, this.constructor.Event.SHOWN)

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()
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() {
Expand Down Expand Up @@ -465,6 +461,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,
Expand Down Expand Up @@ -582,16 +590,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[
Expand Down Expand Up @@ -621,16 +620,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[
Expand Down