diff options
| author | Alessandro Chitolina <[email protected]> | 2017-09-21 18:04:47 +0200 |
|---|---|---|
| committer | XhmikosR <[email protected]> | 2019-02-20 22:05:45 +0200 |
| commit | cc6e130fc1c6f794fcdb24737cb584ac2c937d33 (patch) | |
| tree | e303b1b069e2cff03fbaf11c927ca05ce94e8849 /js/src/tooltip.js | |
| parent | 7c1d0a1097657fb604a69cd47375a7e94c0ced93 (diff) | |
| download | bootstrap-cc6e130fc1c6f794fcdb24737cb584ac2c937d33.tar.xz bootstrap-cc6e130fc1c6f794fcdb24737cb584ac2c937d33.zip | |
tooltip without jquery
Diffstat (limited to 'js/src/tooltip.js')
| -rw-r--r-- | js/src/tooltip.js | 202 |
1 files changed, 113 insertions, 89 deletions
diff --git a/js/src/tooltip.js b/js/src/tooltip.js index 64dcb0840..d7fe510b1 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -9,8 +9,10 @@ import { DefaultWhitelist, sanitizeHtml } from './tools/sanitizer' -import $ from 'jquery' +import Data from './dom/data' +import EventHandler from './dom/eventHandler' import Popper from 'popper.js' +import SelectorEngine from './dom/selectorEngine' import Util from './util' /** @@ -23,11 +25,11 @@ const NAME = 'tooltip' const VERSION = '4.3.1' const DATA_KEY = 'bs.tooltip' const EVENT_KEY = `.${DATA_KEY}` -const JQUERY_NO_CONFLICT = $.fn[NAME] const CLASS_PREFIX = 'bs-tooltip' const BSCLS_PREFIX_REGEX = new RegExp(`(^|\\s)${CLASS_PREFIX}\\S+`, 'g') const DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn'] + const DefaultType = { animation : 'boolean', template : 'string', @@ -193,14 +195,14 @@ class Tooltip { if (event) { const dataKey = this.constructor.DATA_KEY - let context = $(event.currentTarget).data(dataKey) + let context = Data.getData(event.delegateTarget, dataKey) if (!context) { context = new this.constructor( event.currentTarget, this._getDelegateConfig() ) - $(event.currentTarget).data(dataKey, context) + Data.setData(event.delegateTarget, dataKey, context) } context._activeTrigger.click = !context._activeTrigger.click @@ -211,7 +213,7 @@ class Tooltip { context._leave(null, context) } } else { - if ($(this.getTipElement()).hasClass(ClassName.SHOW)) { + if (this.getTipElement().classList.contains(ClassName.SHOW)) { this._leave(null, this) return } @@ -223,13 +225,13 @@ class Tooltip { dispose() { clearTimeout(this._timeout) - $.removeData(this.element, this.constructor.DATA_KEY) + Data.removeData(this.element, this.constructor.DATA_KEY) - $(this.element).off(this.constructor.EVENT_KEY) - $(this.element).closest('.modal').off('hide.bs.modal') + EventHandler.off(this.element, this.constructor.EVENT_KEY) + EventHandler.off(SelectorEngine.closest(this.element, '.modal'), 'hide.bs.modal') if (this.tip) { - $(this.tip).remove() + this.tip.parentNode.removeChild(this.tip) } this._isEnabled = null @@ -247,21 +249,18 @@ class Tooltip { } show() { - if ($(this.element).css('display') === 'none') { + if (this.element.style.display === 'none') { throw new Error('Please use show on visible elements') } - const showEvent = $.Event(this.constructor.Event.SHOW) if (this.isWithContent() && this._isEnabled) { - $(this.element).trigger(showEvent) - + const showEvent = EventHandler.trigger(this.element, this.constructor.Event.SHOW) const shadowRoot = Util.findShadowRoot(this.element) - const isInTheDom = $.contains( - shadowRoot !== null ? shadowRoot : this.element.ownerDocument.documentElement, - this.element - ) + const isInTheDom = shadowRoot !== null + ? shadowRoot.contains(this.element) + : this.element.ownerDocument.documentElement.contains(this.element) - if (showEvent.isDefaultPrevented() || !isInTheDom) { + if (showEvent.defaultPrevented || !isInTheDom) { return } @@ -274,7 +273,7 @@ class Tooltip { this.setContent() if (this.config.animation) { - $(tip).addClass(ClassName.FADE) + tip.classList.add(ClassName.FADE) } const placement = typeof this.config.placement === 'function' @@ -285,13 +284,13 @@ class Tooltip { this.addAttachmentClass(attachment) const container = this._getContainer() - $(tip).data(this.constructor.DATA_KEY, this) + Data.setData(tip, this.constructor.DATA_KEY, this) - if (!$.contains(this.element.ownerDocument.documentElement, this.tip)) { - $(tip).appendTo(container) + if (!this.element.ownerDocument.documentElement.contains(this.tip)) { + container.appendChild(tip) } - $(this.element).trigger(this.constructor.Event.INSERTED) + EventHandler.trigger(this.element, this.constructor.Event.INSERTED) this._popper = new Popper(this.element, tip, { placement: attachment, @@ -315,14 +314,16 @@ class Tooltip { onUpdate: (data) => this._handlePopperPlacementChange(data) }) - $(tip).addClass(ClassName.SHOW) + tip.classList.add(ClassName.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) { - $(document.body).children().on('mouseover', null, $.noop) + Util.makeArray(document.body.children).forEach((element) => { + EventHandler.on(element, 'mouseover', Util.noop) + }) } const complete = () => { @@ -332,20 +333,18 @@ class Tooltip { const prevHoverState = this._hoverState this._hoverState = null - $(this.element).trigger(this.constructor.Event.SHOWN) + EventHandler.trigger(this.element, this.constructor.Event.SHOWN) if (prevHoverState === HoverState.OUT) { this._leave(null, this) } } - if ($(this.tip).hasClass(ClassName.FADE)) { + if (this.tip.classList.contains(ClassName.FADE)) { const transitionDuration = Util.getTransitionDurationFromElement(this.tip) - $(this.tip) - .one(Util.TRANSITION_END, complete) - - Util.emulateTransitionEnd(tip, transitionDuration) + EventHandler.one(this.tip, Util.TRANSITION_END, complete) + Util.emulateTransitionEnd(this.tip, transitionDuration) } else { complete() } @@ -354,15 +353,14 @@ class Tooltip { hide(callback) { const tip = this.getTipElement() - const hideEvent = $.Event(this.constructor.Event.HIDE) - const complete = () => { + const complete = () => { if (this._hoverState !== HoverState.SHOW && tip.parentNode) { tip.parentNode.removeChild(tip) } this._cleanTipClass() this.element.removeAttribute('aria-describedby') - $(this.element).trigger(this.constructor.Event.HIDDEN) + EventHandler.trigger(this.element, this.constructor.Event.HIDDEN) if (this._popper !== null) { this._popper.destroy() } @@ -372,30 +370,29 @@ class Tooltip { } } - $(this.element).trigger(hideEvent) - - if (hideEvent.isDefaultPrevented()) { + const hideEvent = EventHandler.trigger(this.element, this.constructor.Event.HIDE) + if (hideEvent.defaultPrevented) { return } - $(tip).removeClass(ClassName.SHOW) + tip.classList.remove(ClassName.SHOW) // If this is a touch-enabled device we remove the extra // empty mouseover listeners we added for iOS support if ('ontouchstart' in document.documentElement) { - $(document.body).children().off('mouseover', null, $.noop) + Util.makeArray(document.body.children) + .forEach((element) => EventHandler.off(element, 'mouseover', Util.noop)) } this._activeTrigger[Trigger.CLICK] = false this._activeTrigger[Trigger.FOCUS] = false this._activeTrigger[Trigger.HOVER] = false - if ($(this.tip).hasClass(ClassName.FADE)) { + if (this.tip.classList.contains(ClassName.FADE)) { const transitionDuration = Util.getTransitionDurationFromElement(tip) - $(tip) - .one(Util.TRANSITION_END, complete) - .emulateTransitionEnd(transitionDuration) + EventHandler.one(tip, Util.TRANSITION_END, complete) + Util.emulateTransitionEnd(tip, transitionDuration) } else { complete() } @@ -416,29 +413,46 @@ class Tooltip { } addAttachmentClass(attachment) { - $(this.getTipElement()).addClass(`${CLASS_PREFIX}-${attachment}`) + this.getTipElement().classList.add(`${CLASS_PREFIX}-${attachment}`) } getTipElement() { - this.tip = this.tip || $(this.config.template)[0] + if (this.tip) { + return this.tip + } + + const element = document.createElement('div') + element.innerHTML = this.config.template + + this.tip = element.children[0] return this.tip } setContent() { const tip = this.getTipElement() - this.setElementContent($(tip.querySelectorAll(Selector.TOOLTIP_INNER)), this.getTitle()) - $(tip).removeClass(`${ClassName.FADE} ${ClassName.SHOW}`) + this.setElementContent(SelectorEngine.findOne(Selector.TOOLTIP_INNER, tip), this.getTitle()) + tip.classList.remove(ClassName.FADE) + tip.classList.remove(ClassName.SHOW) } - setElementContent($element, content) { + setElementContent(element, content) { + if (element === null) { + return + } + if (typeof content === 'object' && (content.nodeType || content.jquery)) { - // Content is a DOM node or a jQuery + if (content.jquery) { + content = content[0] + } + + // content is a DOM node or a jQuery if (this.config.html) { - if (!$(content).parent().is($element)) { - $element.empty().append(content) + if (content.parentNode !== element) { + element.innerHTML = '' + element.appendChild(content) } } else { - $element.text($(content).text()) + element.innerText = content.textContent } return @@ -449,9 +463,9 @@ class Tooltip { content = sanitizeHtml(content, this.config.whiteList, this.config.sanitizeFn) } - $element.html(content) + element.innerHTML = content } else { - $element.text(content) + element.innerText = content } } @@ -494,10 +508,10 @@ class Tooltip { } if (Util.isElement(this.config.container)) { - return $(this.config.container) + return this.config.container } - return $(document).find(this.config.container) + return SelectorEngine.findOne(this.config.container) } _getAttachment(placement) { @@ -509,7 +523,7 @@ class Tooltip { triggers.forEach((trigger) => { if (trigger === 'click') { - $(this.element).on( + EventHandler.on(this.element, this.constructor.Event.CLICK, this.config.selector, (event) => this.toggle(event) @@ -522,21 +536,20 @@ class Tooltip { ? this.constructor.Event.MOUSELEAVE : this.constructor.Event.FOCUSOUT - $(this.element) - .on( - eventIn, - this.config.selector, - (event) => this._enter(event) - ) - .on( - eventOut, - this.config.selector, - (event) => this._leave(event) - ) + EventHandler.on(this.element, + eventIn, + this.config.selector, + (event) => this._enter(event) + ) + EventHandler.on(this.element, + eventOut, + this.config.selector, + (event) => this._leave(event) + ) } }) - $(this.element).closest('.modal').on( + EventHandler.on(SelectorEngine.closest(this.element, '.modal'), 'hide.bs.modal', () => { if (this.element) { @@ -571,14 +584,14 @@ class Tooltip { _enter(event, context) { const dataKey = this.constructor.DATA_KEY - context = context || $(event.currentTarget).data(dataKey) + context = context || Data.getData(event.delegateTarget, dataKey) if (!context) { context = new this.constructor( - event.currentTarget, + event.delegateTarget, this._getDelegateConfig() ) - $(event.currentTarget).data(dataKey, context) + Data.setData(event.delegateTarget, dataKey, context) } if (event) { @@ -587,7 +600,8 @@ class Tooltip { ] = true } - if ($(context.getTipElement()).hasClass(ClassName.SHOW) || context._hoverState === HoverState.SHOW) { + if (context.getTipElement().classList.contains(ClassName.SHOW) || + context._hoverState === HoverState.SHOW) { context._hoverState = HoverState.SHOW return } @@ -610,14 +624,14 @@ class Tooltip { _leave(event, context) { const dataKey = this.constructor.DATA_KEY - context = context || $(event.currentTarget).data(dataKey) + context = context || Data.getData(event.delegateTarget, dataKey) if (!context) { context = new this.constructor( - event.currentTarget, + event.delegateTarget, this._getDelegateConfig() ) - $(event.currentTarget).data(dataKey, context) + Data.setData(event.delegateTarget, dataKey, context) } if (event) { @@ -657,7 +671,7 @@ class Tooltip { } _getConfig(config) { - const dataAttributes = $(this.element).data() + const dataAttributes = Util.getDataAttributes(this.element) Object.keys(dataAttributes) .forEach((dataAttr) => { @@ -666,6 +680,11 @@ class Tooltip { } }) + if (typeof config !== 'undefined' && + typeof config.container === 'object' && config.container.jquery) { + config.container = config.container[0] + } + config = { ...this.constructor.Default, ...dataAttributes, @@ -715,10 +734,12 @@ class Tooltip { } _cleanTipClass() { - const $tip = $(this.getTipElement()) - const tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX) + const tip = this.getTipElement() + const tabClass = tip.getAttribute('class').match(BSCLS_PREFIX_REGEX) if (tabClass !== null && tabClass.length) { - $tip.removeClass(tabClass.join('')) + tabClass + .map((token) => token.trim()) + .forEach((tClass) => tip.classList.remove(tClass)) } } @@ -737,7 +758,7 @@ class Tooltip { return } - $(tip).removeClass(ClassName.FADE) + tip.classList.remove(ClassName.FADE) this.config.animation = false this.hide() this.show() @@ -748,7 +769,7 @@ class Tooltip { static _jQueryInterface(config) { return this.each(function () { - let data = $(this).data(DATA_KEY) + let data = Data.getData(this, DATA_KEY) const _config = typeof config === 'object' && config if (!data && /dispose|hide/.test(config)) { @@ -757,7 +778,7 @@ class Tooltip { if (!data) { data = new Tooltip(this, _config) - $(this).data(DATA_KEY, data) + Data.setData(this, DATA_KEY, data) } if (typeof config === 'string') { @@ -775,12 +796,15 @@ class Tooltip { * jQuery * ------------------------------------------------------------------------ */ - -$.fn[NAME] = Tooltip._jQueryInterface -$.fn[NAME].Constructor = Tooltip -$.fn[NAME].noConflict = () => { - $.fn[NAME] = JQUERY_NO_CONFLICT - return Tooltip._jQueryInterface +const $ = Util.jQuery +if (typeof $ !== 'undefined') { + const JQUERY_NO_CONFLICT = $.fn[NAME] + $.fn[NAME] = Tooltip._jQueryInterface + $.fn[NAME].Constructor = Tooltip + $.fn[NAME].noConflict = () => { + $.fn[NAME] = JQUERY_NO_CONFLICT + return Tooltip._jQueryInterface + } } export default Tooltip |
