Merge branch 'main' into patrickhlauke-issue26202
This commit is contained in:
commit
35b6242a85
33 changed files with 405 additions and 220 deletions
|
|
@ -38,7 +38,7 @@
|
|||
},
|
||||
{
|
||||
"path": "./dist/js/bootstrap.bundle.min.js",
|
||||
"maxSize": "22 kB"
|
||||
"maxSize": "22.25 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/bootstrap.esm.js",
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import {
|
|||
} from './util/index'
|
||||
import Data from './dom/data'
|
||||
import EventHandler from './dom/event-handler'
|
||||
import BaseComponent from './base-component'
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
|
|
@ -23,7 +24,6 @@ import EventHandler from './dom/event-handler'
|
|||
*/
|
||||
|
||||
const NAME = 'alert'
|
||||
const VERSION = '5.0.0-alpha3'
|
||||
const DATA_KEY = 'bs.alert'
|
||||
const EVENT_KEY = `.${DATA_KEY}`
|
||||
const DATA_API_KEY = '.data-api'
|
||||
|
|
@ -44,19 +44,11 @@ const CLASSNAME_SHOW = 'show'
|
|||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
class Alert {
|
||||
constructor(element) {
|
||||
this._element = element
|
||||
|
||||
if (this._element) {
|
||||
Data.setData(element, DATA_KEY, this)
|
||||
}
|
||||
}
|
||||
|
||||
class Alert extends BaseComponent {
|
||||
// Getters
|
||||
|
||||
static get VERSION() {
|
||||
return VERSION
|
||||
static get DATA_KEY() {
|
||||
return DATA_KEY
|
||||
}
|
||||
|
||||
// Public
|
||||
|
|
@ -72,11 +64,6 @@ class Alert {
|
|||
this._removeElement(rootElement)
|
||||
}
|
||||
|
||||
dispose() {
|
||||
Data.removeData(this._element, DATA_KEY)
|
||||
this._element = null
|
||||
}
|
||||
|
||||
// Private
|
||||
|
||||
_getRootElement(element) {
|
||||
|
|
@ -134,10 +121,6 @@ class Alert {
|
|||
alertInstance.close(this)
|
||||
}
|
||||
}
|
||||
|
||||
static getInstance(element) {
|
||||
return Data.getData(element, DATA_KEY)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
44
js/src/base-component.js
Normal file
44
js/src/base-component.js
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Bootstrap (v5.0.0-alpha3): base-component.js
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
import Data from './dom/data'
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
* Constants
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
const VERSION = '5.0.0-alpha3'
|
||||
|
||||
class BaseComponent {
|
||||
constructor(element) {
|
||||
if (!element) {
|
||||
return
|
||||
}
|
||||
|
||||
this._element = element
|
||||
Data.setData(element, this.constructor.DATA_KEY, this)
|
||||
}
|
||||
|
||||
dispose() {
|
||||
Data.removeData(this._element, this.constructor.DATA_KEY)
|
||||
this._element = null
|
||||
}
|
||||
|
||||
/** Static */
|
||||
|
||||
static getInstance(element) {
|
||||
return Data.getData(element, this.DATA_KEY)
|
||||
}
|
||||
|
||||
static get VERSION() {
|
||||
return VERSION
|
||||
}
|
||||
}
|
||||
|
||||
export default BaseComponent
|
||||
|
|
@ -8,6 +8,7 @@
|
|||
import { getjQuery, onDOMContentLoaded } from './util/index'
|
||||
import Data from './dom/data'
|
||||
import EventHandler from './dom/event-handler'
|
||||
import BaseComponent from './base-component'
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
|
|
@ -16,7 +17,6 @@ import EventHandler from './dom/event-handler'
|
|||
*/
|
||||
|
||||
const NAME = 'button'
|
||||
const VERSION = '5.0.0-alpha3'
|
||||
const DATA_KEY = 'bs.button'
|
||||
const EVENT_KEY = `.${DATA_KEY}`
|
||||
const DATA_API_KEY = '.data-api'
|
||||
|
|
@ -33,16 +33,11 @@ const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
|
|||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
class Button {
|
||||
constructor(element) {
|
||||
this._element = element
|
||||
Data.setData(element, DATA_KEY, this)
|
||||
}
|
||||
|
||||
class Button extends BaseComponent {
|
||||
// Getters
|
||||
|
||||
static get VERSION() {
|
||||
return VERSION
|
||||
static get DATA_KEY() {
|
||||
return DATA_KEY
|
||||
}
|
||||
|
||||
// Public
|
||||
|
|
@ -52,11 +47,6 @@ class Button {
|
|||
this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE))
|
||||
}
|
||||
|
||||
dispose() {
|
||||
Data.removeData(this._element, DATA_KEY)
|
||||
this._element = null
|
||||
}
|
||||
|
||||
// Static
|
||||
|
||||
static jQueryInterface(config) {
|
||||
|
|
@ -72,10 +62,6 @@ class Button {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
static getInstance(element) {
|
||||
return Data.getData(element, DATA_KEY)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import Data from './dom/data'
|
|||
import EventHandler from './dom/event-handler'
|
||||
import Manipulator from './dom/manipulator'
|
||||
import SelectorEngine from './dom/selector-engine'
|
||||
import BaseComponent from './base-component'
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
|
|
@ -29,7 +30,6 @@ import SelectorEngine from './dom/selector-engine'
|
|||
*/
|
||||
|
||||
const NAME = 'carousel'
|
||||
const VERSION = '5.0.0-alpha3'
|
||||
const DATA_KEY = 'bs.carousel'
|
||||
const EVENT_KEY = `.${DATA_KEY}`
|
||||
const DATA_API_KEY = '.data-api'
|
||||
|
|
@ -104,8 +104,10 @@ const PointerType = {
|
|||
* Class Definition
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
class Carousel {
|
||||
class Carousel extends BaseComponent {
|
||||
constructor(element, config) {
|
||||
super(element)
|
||||
|
||||
this._items = null
|
||||
this._interval = null
|
||||
this._activeElement = null
|
||||
|
|
@ -116,25 +118,23 @@ class Carousel {
|
|||
this.touchDeltaX = 0
|
||||
|
||||
this._config = this._getConfig(config)
|
||||
this._element = element
|
||||
this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element)
|
||||
this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0
|
||||
this._pointerEvent = Boolean(window.PointerEvent)
|
||||
|
||||
this._addEventListeners()
|
||||
Data.setData(element, DATA_KEY, this)
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
static get VERSION() {
|
||||
return VERSION
|
||||
}
|
||||
|
||||
static get Default() {
|
||||
return Default
|
||||
}
|
||||
|
||||
static get DATA_KEY() {
|
||||
return DATA_KEY
|
||||
}
|
||||
|
||||
// Public
|
||||
|
||||
next() {
|
||||
|
|
@ -218,12 +218,11 @@ class Carousel {
|
|||
}
|
||||
|
||||
dispose() {
|
||||
super.dispose()
|
||||
EventHandler.off(this._element, EVENT_KEY)
|
||||
Data.removeData(this._element, DATA_KEY)
|
||||
|
||||
this._items = null
|
||||
this._config = null
|
||||
this._element = null
|
||||
this._interval = null
|
||||
this._isPaused = null
|
||||
this._isSliding = null
|
||||
|
|
@ -590,10 +589,6 @@ class Carousel {
|
|||
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
static getInstance(element) {
|
||||
return Data.getData(element, DATA_KEY)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import Data from './dom/data'
|
|||
import EventHandler from './dom/event-handler'
|
||||
import Manipulator from './dom/manipulator'
|
||||
import SelectorEngine from './dom/selector-engine'
|
||||
import BaseComponent from './base-component'
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
|
|
@ -29,7 +30,6 @@ import SelectorEngine from './dom/selector-engine'
|
|||
*/
|
||||
|
||||
const NAME = 'collapse'
|
||||
const VERSION = '5.0.0-alpha3'
|
||||
const DATA_KEY = 'bs.collapse'
|
||||
const EVENT_KEY = `.${DATA_KEY}`
|
||||
const DATA_API_KEY = '.data-api'
|
||||
|
|
@ -67,10 +67,11 @@ const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="collapse"]'
|
|||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
class Collapse {
|
||||
class Collapse extends BaseComponent {
|
||||
constructor(element, config) {
|
||||
super(element)
|
||||
|
||||
this._isTransitioning = false
|
||||
this._element = element
|
||||
this._config = this._getConfig(config)
|
||||
this._triggerArray = SelectorEngine.find(
|
||||
`${SELECTOR_DATA_TOGGLE}[href="#${element.id}"],` +
|
||||
|
|
@ -100,20 +101,18 @@ class Collapse {
|
|||
if (this._config.toggle) {
|
||||
this.toggle()
|
||||
}
|
||||
|
||||
Data.setData(element, DATA_KEY, this)
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
static get VERSION() {
|
||||
return VERSION
|
||||
}
|
||||
|
||||
static get Default() {
|
||||
return Default
|
||||
}
|
||||
|
||||
static get DATA_KEY() {
|
||||
return DATA_KEY
|
||||
}
|
||||
|
||||
// Public
|
||||
|
||||
toggle() {
|
||||
|
|
@ -266,11 +265,9 @@ class Collapse {
|
|||
}
|
||||
|
||||
dispose() {
|
||||
Data.removeData(this._element, DATA_KEY)
|
||||
|
||||
super.dispose()
|
||||
this._config = null
|
||||
this._parent = null
|
||||
this._element = null
|
||||
this._triggerArray = null
|
||||
this._isTransitioning = null
|
||||
}
|
||||
|
|
@ -368,10 +365,6 @@ class Collapse {
|
|||
Collapse.collapseInterface(this, config)
|
||||
})
|
||||
}
|
||||
|
||||
static getInstance(element) {
|
||||
return Data.getData(element, DATA_KEY)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import EventHandler from './dom/event-handler'
|
|||
import Manipulator from './dom/manipulator'
|
||||
import Popper from 'popper.js'
|
||||
import SelectorEngine from './dom/selector-engine'
|
||||
import BaseComponent from './base-component'
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
|
|
@ -27,7 +28,6 @@ import SelectorEngine from './dom/selector-engine'
|
|||
*/
|
||||
|
||||
const NAME = 'dropdown'
|
||||
const VERSION = '5.0.0-alpha3'
|
||||
const DATA_KEY = 'bs.dropdown'
|
||||
const EVENT_KEY = `.${DATA_KEY}`
|
||||
const DATA_API_KEY = '.data-api'
|
||||
|
|
@ -96,24 +96,20 @@ const DefaultType = {
|
|||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
class Dropdown {
|
||||
class Dropdown extends BaseComponent {
|
||||
constructor(element, config) {
|
||||
this._element = element
|
||||
super(element)
|
||||
|
||||
this._popper = null
|
||||
this._config = this._getConfig(config)
|
||||
this._menu = this._getMenuElement()
|
||||
this._inNavbar = this._detectNavbar()
|
||||
|
||||
this._addEventListeners()
|
||||
Data.setData(element, DATA_KEY, this)
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
static get VERSION() {
|
||||
return VERSION
|
||||
}
|
||||
|
||||
static get Default() {
|
||||
return Default
|
||||
}
|
||||
|
|
@ -122,6 +118,10 @@ class Dropdown {
|
|||
return DefaultType
|
||||
}
|
||||
|
||||
static get DATA_KEY() {
|
||||
return DATA_KEY
|
||||
}
|
||||
|
||||
// Public
|
||||
|
||||
toggle() {
|
||||
|
|
@ -229,9 +229,8 @@ class Dropdown {
|
|||
}
|
||||
|
||||
dispose() {
|
||||
Data.removeData(this._element, DATA_KEY)
|
||||
super.dispose()
|
||||
EventHandler.off(this._element, EVENT_KEY)
|
||||
this._element = null
|
||||
this._menu = null
|
||||
if (this._popper) {
|
||||
this._popper.destroy()
|
||||
|
|
@ -489,10 +488,6 @@ class Dropdown {
|
|||
|
||||
items[index].focus()
|
||||
}
|
||||
|
||||
static getInstance(element) {
|
||||
return Data.getData(element, DATA_KEY)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import Data from './dom/data'
|
|||
import EventHandler from './dom/event-handler'
|
||||
import Manipulator from './dom/manipulator'
|
||||
import SelectorEngine from './dom/selector-engine'
|
||||
import BaseComponent from './base-component'
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
|
|
@ -28,7 +29,6 @@ import SelectorEngine from './dom/selector-engine'
|
|||
*/
|
||||
|
||||
const NAME = 'modal'
|
||||
const VERSION = '5.0.0-alpha3'
|
||||
const DATA_KEY = 'bs.modal'
|
||||
const EVENT_KEY = `.${DATA_KEY}`
|
||||
const DATA_API_KEY = '.data-api'
|
||||
|
|
@ -37,15 +37,13 @@ const ESCAPE_KEY = 'Escape'
|
|||
const Default = {
|
||||
backdrop: true,
|
||||
keyboard: true,
|
||||
focus: true,
|
||||
show: true
|
||||
focus: true
|
||||
}
|
||||
|
||||
const DefaultType = {
|
||||
backdrop: '(boolean|string)',
|
||||
keyboard: 'boolean',
|
||||
focus: 'boolean',
|
||||
show: 'boolean'
|
||||
focus: 'boolean'
|
||||
}
|
||||
|
||||
const EVENT_HIDE = `hide${EVENT_KEY}`
|
||||
|
|
@ -81,10 +79,11 @@ const SELECTOR_STICKY_CONTENT = '.sticky-top'
|
|||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
class Modal {
|
||||
class Modal extends BaseComponent {
|
||||
constructor(element, config) {
|
||||
super(element)
|
||||
|
||||
this._config = this._getConfig(config)
|
||||
this._element = element
|
||||
this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, element)
|
||||
this._backdrop = null
|
||||
this._isShown = false
|
||||
|
|
@ -92,19 +91,18 @@ class Modal {
|
|||
this._ignoreBackdropClick = false
|
||||
this._isTransitioning = false
|
||||
this._scrollbarWidth = 0
|
||||
Data.setData(element, DATA_KEY, this)
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
static get VERSION() {
|
||||
return VERSION
|
||||
}
|
||||
|
||||
static get Default() {
|
||||
return Default
|
||||
}
|
||||
|
||||
static get DATA_KEY() {
|
||||
return DATA_KEY
|
||||
}
|
||||
|
||||
// Public
|
||||
|
||||
toggle(relatedTarget) {
|
||||
|
|
@ -201,6 +199,8 @@ class Modal {
|
|||
[window, this._element, this._dialog]
|
||||
.forEach(htmlElement => EventHandler.off(htmlElement, EVENT_KEY))
|
||||
|
||||
super.dispose()
|
||||
|
||||
/**
|
||||
* `document` has 2 events `EVENT_FOCUSIN` and `EVENT_CLICK_DATA_API`
|
||||
* Do not move `document` in `htmlElements` array
|
||||
|
|
@ -208,10 +208,7 @@ class Modal {
|
|||
*/
|
||||
EventHandler.off(document, EVENT_FOCUSIN)
|
||||
|
||||
Data.removeData(this._element, DATA_KEY)
|
||||
|
||||
this._config = null
|
||||
this._element = null
|
||||
this._dialog = null
|
||||
this._backdrop = null
|
||||
this._isShown = null
|
||||
|
|
@ -558,15 +555,9 @@ class Modal {
|
|||
}
|
||||
|
||||
data[config](relatedTarget)
|
||||
} else if (_config.show) {
|
||||
data.show(relatedTarget)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
static getInstance(element) {
|
||||
return Data.getData(element, DATA_KEY)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import Tooltip from './tooltip'
|
|||
*/
|
||||
|
||||
const NAME = 'popover'
|
||||
const VERSION = '5.0.0-alpha3'
|
||||
const DATA_KEY = 'bs.popover'
|
||||
const EVENT_KEY = `.${DATA_KEY}`
|
||||
const CLASS_PREFIX = 'bs-popover'
|
||||
|
|
@ -67,10 +66,6 @@ const SELECTOR_CONTENT = '.popover-body'
|
|||
class Popover extends Tooltip {
|
||||
// Getters
|
||||
|
||||
static get VERSION() {
|
||||
return VERSION
|
||||
}
|
||||
|
||||
static get Default() {
|
||||
return Default
|
||||
}
|
||||
|
|
@ -108,7 +103,7 @@ class Popover extends Tooltip {
|
|||
this.setElementContent(SelectorEngine.findOne(SELECTOR_TITLE, tip), this.getTitle())
|
||||
let content = this._getContent()
|
||||
if (typeof content === 'function') {
|
||||
content = content.call(this.element)
|
||||
content = content.call(this._element)
|
||||
}
|
||||
|
||||
this.setElementContent(SelectorEngine.findOne(SELECTOR_CONTENT, tip), content)
|
||||
|
|
@ -123,7 +118,7 @@ class Popover extends Tooltip {
|
|||
}
|
||||
|
||||
_getContent() {
|
||||
return this.element.getAttribute('data-bs-content') ||
|
||||
return this._element.getAttribute('data-bs-content') ||
|
||||
this.config.content
|
||||
}
|
||||
|
||||
|
|
@ -161,10 +156,6 @@ class Popover extends Tooltip {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
static getInstance(element) {
|
||||
return Data.getData(element, DATA_KEY)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import Data from './dom/data'
|
|||
import EventHandler from './dom/event-handler'
|
||||
import Manipulator from './dom/manipulator'
|
||||
import SelectorEngine from './dom/selector-engine'
|
||||
import BaseComponent from './base-component'
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
|
|
@ -25,7 +26,6 @@ import SelectorEngine from './dom/selector-engine'
|
|||
*/
|
||||
|
||||
const NAME = 'scrollspy'
|
||||
const VERSION = '5.0.0-alpha3'
|
||||
const DATA_KEY = 'bs.scrollspy'
|
||||
const EVENT_KEY = `.${DATA_KEY}`
|
||||
const DATA_API_KEY = '.data-api'
|
||||
|
|
@ -66,9 +66,9 @@ const METHOD_POSITION = 'position'
|
|||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
class ScrollSpy {
|
||||
class ScrollSpy extends BaseComponent {
|
||||
constructor(element, config) {
|
||||
this._element = element
|
||||
super(element)
|
||||
this._scrollElement = element.tagName === 'BODY' ? window : element
|
||||
this._config = this._getConfig(config)
|
||||
this._selector = `${this._config.target} ${SELECTOR_NAV_LINKS}, ${this._config.target} ${SELECTOR_LIST_ITEMS}, ${this._config.target} .${CLASS_NAME_DROPDOWN_ITEM}`
|
||||
|
|
@ -81,20 +81,18 @@ class ScrollSpy {
|
|||
|
||||
this.refresh()
|
||||
this._process()
|
||||
|
||||
Data.setData(element, DATA_KEY, this)
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
static get VERSION() {
|
||||
return VERSION
|
||||
}
|
||||
|
||||
static get Default() {
|
||||
return Default
|
||||
}
|
||||
|
||||
static get DATA_KEY() {
|
||||
return DATA_KEY
|
||||
}
|
||||
|
||||
// Public
|
||||
|
||||
refresh() {
|
||||
|
|
@ -141,10 +139,9 @@ class ScrollSpy {
|
|||
}
|
||||
|
||||
dispose() {
|
||||
Data.removeData(this._element, DATA_KEY)
|
||||
super.dispose()
|
||||
EventHandler.off(this._scrollElement, EVENT_KEY)
|
||||
|
||||
this._element = null
|
||||
this._scrollElement = null
|
||||
this._config = null
|
||||
this._selector = null
|
||||
|
|
@ -301,10 +298,6 @@ class ScrollSpy {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
static getInstance(element) {
|
||||
return Data.getData(element, DATA_KEY)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import {
|
|||
import Data from './dom/data'
|
||||
import EventHandler from './dom/event-handler'
|
||||
import SelectorEngine from './dom/selector-engine'
|
||||
import BaseComponent from './base-component'
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
|
|
@ -25,7 +26,6 @@ import SelectorEngine from './dom/selector-engine'
|
|||
*/
|
||||
|
||||
const NAME = 'tab'
|
||||
const VERSION = '5.0.0-alpha3'
|
||||
const DATA_KEY = 'bs.tab'
|
||||
const EVENT_KEY = `.${DATA_KEY}`
|
||||
const DATA_API_KEY = '.data-api'
|
||||
|
|
@ -56,17 +56,11 @@ const SELECTOR_DROPDOWN_ACTIVE_CHILD = ':scope > .dropdown-menu .active'
|
|||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
class Tab {
|
||||
constructor(element) {
|
||||
this._element = element
|
||||
|
||||
Data.setData(this._element, DATA_KEY, this)
|
||||
}
|
||||
|
||||
class Tab extends BaseComponent {
|
||||
// Getters
|
||||
|
||||
static get VERSION() {
|
||||
return VERSION
|
||||
static get DATA_KEY() {
|
||||
return DATA_KEY
|
||||
}
|
||||
|
||||
// Public
|
||||
|
|
@ -127,11 +121,6 @@ class Tab {
|
|||
}
|
||||
}
|
||||
|
||||
dispose() {
|
||||
Data.removeData(this._element, DATA_KEY)
|
||||
this._element = null
|
||||
}
|
||||
|
||||
// Private
|
||||
|
||||
_activate(element, container, callback) {
|
||||
|
|
@ -217,10 +206,6 @@ class Tab {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
static getInstance(element) {
|
||||
return Data.getData(element, DATA_KEY)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import {
|
|||
import Data from './dom/data'
|
||||
import EventHandler from './dom/event-handler'
|
||||
import Manipulator from './dom/manipulator'
|
||||
import BaseComponent from './base-component'
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
|
|
@ -25,7 +26,6 @@ import Manipulator from './dom/manipulator'
|
|||
*/
|
||||
|
||||
const NAME = 'toast'
|
||||
const VERSION = '5.0.0-alpha3'
|
||||
const DATA_KEY = 'bs.toast'
|
||||
const EVENT_KEY = `.${DATA_KEY}`
|
||||
|
||||
|
|
@ -60,21 +60,17 @@ const SELECTOR_DATA_DISMISS = '[data-bs-dismiss="toast"]'
|
|||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
class Toast {
|
||||
class Toast extends BaseComponent {
|
||||
constructor(element, config) {
|
||||
this._element = element
|
||||
super(element)
|
||||
|
||||
this._config = this._getConfig(config)
|
||||
this._timeout = null
|
||||
this._setListeners()
|
||||
Data.setData(element, DATA_KEY, this)
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
static get VERSION() {
|
||||
return VERSION
|
||||
}
|
||||
|
||||
static get DefaultType() {
|
||||
return DefaultType
|
||||
}
|
||||
|
|
@ -83,6 +79,10 @@ class Toast {
|
|||
return Default
|
||||
}
|
||||
|
||||
static get DATA_KEY() {
|
||||
return DATA_KEY
|
||||
}
|
||||
|
||||
// Public
|
||||
|
||||
show() {
|
||||
|
|
@ -159,9 +159,8 @@ class Toast {
|
|||
}
|
||||
|
||||
EventHandler.off(this._element, EVENT_CLICK_DISMISS)
|
||||
Data.removeData(this._element, DATA_KEY)
|
||||
|
||||
this._element = null
|
||||
super.dispose()
|
||||
this._config = null
|
||||
}
|
||||
|
||||
|
|
@ -208,10 +207,6 @@ class Toast {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
static getInstance(element) {
|
||||
return Data.getData(element, DATA_KEY)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import EventHandler from './dom/event-handler'
|
|||
import Manipulator from './dom/manipulator'
|
||||
import Popper from 'popper.js'
|
||||
import SelectorEngine from './dom/selector-engine'
|
||||
import BaseComponent from './base-component'
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
|
|
@ -34,7 +35,6 @@ import SelectorEngine from './dom/selector-engine'
|
|||
*/
|
||||
|
||||
const NAME = 'tooltip'
|
||||
const VERSION = '5.0.0-alpha3'
|
||||
const DATA_KEY = 'bs.tooltip'
|
||||
const EVENT_KEY = `.${DATA_KEY}`
|
||||
const CLASS_PREFIX = 'bs-tooltip'
|
||||
|
|
@ -54,6 +54,7 @@ const DefaultType = {
|
|||
container: '(string|element|boolean)',
|
||||
fallbackPlacement: '(string|array)',
|
||||
boundary: '(string|element)',
|
||||
customClass: '(string|function)',
|
||||
sanitize: 'boolean',
|
||||
sanitizeFn: '(null|function)',
|
||||
allowList: 'object',
|
||||
|
|
@ -83,6 +84,7 @@ const Default = {
|
|||
container: false,
|
||||
fallbackPlacement: 'flip',
|
||||
boundary: 'scrollParent',
|
||||
customClass: '',
|
||||
sanitize: true,
|
||||
sanitizeFn: null,
|
||||
allowList: DefaultAllowlist,
|
||||
|
|
@ -122,12 +124,14 @@ const TRIGGER_MANUAL = 'manual'
|
|||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
class Tooltip {
|
||||
class Tooltip extends BaseComponent {
|
||||
constructor(element, config) {
|
||||
if (typeof Popper === 'undefined') {
|
||||
throw new TypeError('Bootstrap\'s tooltips require Popper (https://popper.js.org)')
|
||||
}
|
||||
|
||||
super(element)
|
||||
|
||||
// private
|
||||
this._isEnabled = true
|
||||
this._timeout = 0
|
||||
|
|
@ -136,20 +140,14 @@ class Tooltip {
|
|||
this._popper = null
|
||||
|
||||
// Protected
|
||||
this.element = element
|
||||
this.config = this._getConfig(config)
|
||||
this.tip = null
|
||||
|
||||
this._setListeners()
|
||||
Data.setData(element, this.constructor.DATA_KEY, this)
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
static get VERSION() {
|
||||
return VERSION
|
||||
}
|
||||
|
||||
static get Default() {
|
||||
return Default
|
||||
}
|
||||
|
|
@ -225,10 +223,8 @@ class Tooltip {
|
|||
dispose() {
|
||||
clearTimeout(this._timeout)
|
||||
|
||||
Data.removeData(this.element, this.constructor.DATA_KEY)
|
||||
|
||||
EventHandler.off(this.element, this.constructor.EVENT_KEY)
|
||||
EventHandler.off(this.element.closest(`.${CLASS_NAME_MODAL}`), 'hide.bs.modal', this._hideModalHandler)
|
||||
EventHandler.off(this._element, this.constructor.EVENT_KEY)
|
||||
EventHandler.off(this._element.closest(`.${CLASS_NAME_MODAL}`), 'hide.bs.modal', this._hideModalHandler)
|
||||
|
||||
if (this.tip) {
|
||||
this.tip.parentNode.removeChild(this.tip)
|
||||
|
|
@ -243,22 +239,22 @@ class Tooltip {
|
|||
}
|
||||
|
||||
this._popper = null
|
||||
this.element = null
|
||||
this.config = null
|
||||
this.tip = null
|
||||
super.dispose()
|
||||
}
|
||||
|
||||
show() {
|
||||
if (this.element.style.display === 'none') {
|
||||
if (this._element.style.display === 'none') {
|
||||
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 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)
|
||||
this._element.ownerDocument.documentElement.contains(this._element) :
|
||||
shadowRoot.contains(this._element)
|
||||
|
||||
if (showEvent.defaultPrevented || !isInTheDom) {
|
||||
return
|
||||
|
|
@ -268,7 +264,7 @@ class Tooltip {
|
|||
const tipId = getUID(this.constructor.NAME)
|
||||
|
||||
tip.setAttribute('id', tipId)
|
||||
this.element.setAttribute('aria-describedby', tipId)
|
||||
this._element.setAttribute('aria-describedby', tipId)
|
||||
|
||||
this.setContent()
|
||||
|
||||
|
|
@ -277,7 +273,7 @@ class Tooltip {
|
|||
}
|
||||
|
||||
const placement = typeof this.config.placement === 'function' ?
|
||||
this.config.placement.call(this, tip, this.element) :
|
||||
this.config.placement.call(this, tip, this._element) :
|
||||
this.config.placement
|
||||
|
||||
const attachment = this._getAttachment(placement)
|
||||
|
|
@ -286,16 +282,21 @@ class Tooltip {
|
|||
const container = this._getContainer()
|
||||
Data.setData(tip, this.constructor.DATA_KEY, this)
|
||||
|
||||
if (!this.element.ownerDocument.documentElement.contains(this.tip)) {
|
||||
if (!this._element.ownerDocument.documentElement.contains(this.tip)) {
|
||||
container.appendChild(tip)
|
||||
}
|
||||
|
||||
EventHandler.trigger(this.element, this.constructor.Event.INSERTED)
|
||||
EventHandler.trigger(this._element, this.constructor.Event.INSERTED)
|
||||
|
||||
this._popper = new Popper(this.element, tip, this._getPopperConfig(attachment))
|
||||
this._popper = new Popper(this._element, tip, this._getPopperConfig(attachment))
|
||||
|
||||
tip.classList.add(CLASS_NAME_SHOW)
|
||||
|
||||
const customClass = typeof this.config.customClass === 'function' ? this.config.customClass() : this.config.customClass
|
||||
if (customClass) {
|
||||
tip.classList.add(...customClass.split(' '))
|
||||
}
|
||||
|
||||
// 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
|
||||
|
|
@ -314,7 +315,7 @@ class Tooltip {
|
|||
const prevHoverState = this._hoverState
|
||||
this._hoverState = null
|
||||
|
||||
EventHandler.trigger(this.element, this.constructor.Event.SHOWN)
|
||||
EventHandler.trigger(this._element, this.constructor.Event.SHOWN)
|
||||
|
||||
if (prevHoverState === HOVER_STATE_OUT) {
|
||||
this._leave(null, this)
|
||||
|
|
@ -343,12 +344,12 @@ class Tooltip {
|
|||
}
|
||||
|
||||
this._cleanTipClass()
|
||||
this.element.removeAttribute('aria-describedby')
|
||||
EventHandler.trigger(this.element, this.constructor.Event.HIDDEN)
|
||||
this._element.removeAttribute('aria-describedby')
|
||||
EventHandler.trigger(this._element, this.constructor.Event.HIDDEN)
|
||||
this._popper.destroy()
|
||||
}
|
||||
|
||||
const hideEvent = EventHandler.trigger(this.element, this.constructor.Event.HIDE)
|
||||
const hideEvent = EventHandler.trigger(this._element, this.constructor.Event.HIDE)
|
||||
if (hideEvent.defaultPrevented) {
|
||||
return
|
||||
}
|
||||
|
|
@ -443,11 +444,11 @@ class Tooltip {
|
|||
}
|
||||
|
||||
getTitle() {
|
||||
let title = this.element.getAttribute('data-bs-original-title')
|
||||
let title = this._element.getAttribute('data-bs-original-title')
|
||||
|
||||
if (!title) {
|
||||
title = typeof this.config.title === 'function' ?
|
||||
this.config.title.call(this.element) :
|
||||
this.config.title.call(this._element) :
|
||||
this.config.title
|
||||
}
|
||||
|
||||
|
|
@ -496,7 +497,7 @@ class Tooltip {
|
|||
offset.fn = data => {
|
||||
data.offsets = {
|
||||
...data.offsets,
|
||||
...(this.config.offset(data.offsets, this.element) || {})
|
||||
...(this.config.offset(data.offsets, this._element) || {})
|
||||
}
|
||||
|
||||
return data
|
||||
|
|
@ -529,7 +530,7 @@ class Tooltip {
|
|||
|
||||
triggers.forEach(trigger => {
|
||||
if (trigger === 'click') {
|
||||
EventHandler.on(this.element,
|
||||
EventHandler.on(this._element,
|
||||
this.constructor.Event.CLICK,
|
||||
this.config.selector,
|
||||
event => this.toggle(event)
|
||||
|
|
@ -542,12 +543,12 @@ class Tooltip {
|
|||
this.constructor.Event.MOUSELEAVE :
|
||||
this.constructor.Event.FOCUSOUT
|
||||
|
||||
EventHandler.on(this.element,
|
||||
EventHandler.on(this._element,
|
||||
eventIn,
|
||||
this.config.selector,
|
||||
event => this._enter(event)
|
||||
)
|
||||
EventHandler.on(this.element,
|
||||
EventHandler.on(this._element,
|
||||
eventOut,
|
||||
this.config.selector,
|
||||
event => this._leave(event)
|
||||
|
|
@ -556,12 +557,12 @@ class Tooltip {
|
|||
})
|
||||
|
||||
this._hideModalHandler = () => {
|
||||
if (this.element) {
|
||||
if (this._element) {
|
||||
this.hide()
|
||||
}
|
||||
}
|
||||
|
||||
EventHandler.on(this.element.closest(`.${CLASS_NAME_MODAL}`),
|
||||
EventHandler.on(this._element.closest(`.${CLASS_NAME_MODAL}`),
|
||||
'hide.bs.modal',
|
||||
this._hideModalHandler
|
||||
)
|
||||
|
|
@ -578,12 +579,16 @@ class Tooltip {
|
|||
}
|
||||
|
||||
_fixTitle() {
|
||||
const title = this.element.getAttribute('title')
|
||||
const originalTitleType = typeof this.element.getAttribute('data-bs-original-title')
|
||||
const title = this._element.getAttribute('title')
|
||||
const originalTitleType = typeof this._element.getAttribute('data-bs-original-title')
|
||||
|
||||
if (title || originalTitleType !== 'string') {
|
||||
this.element.setAttribute('data-bs-original-title', title || '')
|
||||
this.element.setAttribute('title', '')
|
||||
this._element.setAttribute('data-bs-original-title', title || '')
|
||||
if (title && !this._element.getAttribute('aria-label') && !this._element.textContent) {
|
||||
this._element.setAttribute('aria-label', title)
|
||||
}
|
||||
|
||||
this._element.setAttribute('title', '')
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -676,7 +681,7 @@ class Tooltip {
|
|||
}
|
||||
|
||||
_getConfig(config) {
|
||||
const dataAttributes = Manipulator.getDataAttributes(this.element)
|
||||
const dataAttributes = Manipulator.getDataAttributes(this._element)
|
||||
|
||||
Object.keys(dataAttributes).forEach(dataAttr => {
|
||||
if (DISALLOWED_ATTRIBUTES.has(dataAttr)) {
|
||||
|
|
@ -785,10 +790,6 @@ class Tooltip {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
static getInstance(element) {
|
||||
return Data.getData(element, DATA_KEY)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -170,4 +170,24 @@ describe('Alert', () => {
|
|||
expect(fixtureEl.querySelector('.alert')).not.toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('getInstance', () => {
|
||||
it('should return alert instance', () => {
|
||||
fixtureEl.innerHTML = '<div></div>'
|
||||
|
||||
const div = fixtureEl.querySelector('div')
|
||||
const alert = new Alert(div)
|
||||
|
||||
expect(Alert.getInstance(div)).toEqual(alert)
|
||||
expect(Alert.getInstance(div)).toBeInstanceOf(Alert)
|
||||
})
|
||||
|
||||
it('should return null when there is no alert instance', () => {
|
||||
fixtureEl.innerHTML = '<div></div>'
|
||||
|
||||
const div = fixtureEl.querySelector('div')
|
||||
|
||||
expect(Alert.getInstance(div)).toEqual(null)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -128,4 +128,24 @@ describe('Button', () => {
|
|||
expect(btnEl.classList.contains('active')).toEqual(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getInstance', () => {
|
||||
it('should return button instance', () => {
|
||||
fixtureEl.innerHTML = '<div></div>'
|
||||
|
||||
const div = fixtureEl.querySelector('div')
|
||||
const button = new Button(div)
|
||||
|
||||
expect(Button.getInstance(div)).toEqual(button)
|
||||
expect(Button.getInstance(div)).toBeInstanceOf(Button)
|
||||
})
|
||||
|
||||
it('should return null when there is no button instance', () => {
|
||||
fixtureEl.innerHTML = '<div></div>'
|
||||
|
||||
const div = fixtureEl.querySelector('div')
|
||||
|
||||
expect(Button.getInstance(div)).toEqual(null)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1062,6 +1062,26 @@ describe('Carousel', () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe('getInstance', () => {
|
||||
it('should return carousel instance', () => {
|
||||
fixtureEl.innerHTML = '<div></div>'
|
||||
|
||||
const div = fixtureEl.querySelector('div')
|
||||
const carousel = new Carousel(div)
|
||||
|
||||
expect(Carousel.getInstance(div)).toEqual(carousel)
|
||||
expect(Carousel.getInstance(div)).toBeInstanceOf(Carousel)
|
||||
})
|
||||
|
||||
it('should return null when there is no carousel instance', () => {
|
||||
fixtureEl.innerHTML = '<div></div>'
|
||||
|
||||
const div = fixtureEl.querySelector('div')
|
||||
|
||||
expect(Carousel.getInstance(div)).toEqual(null)
|
||||
})
|
||||
})
|
||||
|
||||
describe('jQueryInterface', () => {
|
||||
it('should create a carousel', () => {
|
||||
fixtureEl.innerHTML = '<div></div>'
|
||||
|
|
|
|||
|
|
@ -812,6 +812,7 @@ describe('Collapse', () => {
|
|||
const collapse = new Collapse(div)
|
||||
|
||||
expect(Collapse.getInstance(div)).toEqual(collapse)
|
||||
expect(Collapse.getInstance(div)).toBeInstanceOf(Collapse)
|
||||
})
|
||||
|
||||
it('should return null when there is no collapse instance', () => {
|
||||
|
|
|
|||
|
|
@ -1612,6 +1612,7 @@ describe('Dropdown', () => {
|
|||
const dropdown = new Dropdown(div)
|
||||
|
||||
expect(Dropdown.getInstance(div)).toEqual(dropdown)
|
||||
expect(Dropdown.getInstance(div)).toBeInstanceOf(Dropdown)
|
||||
})
|
||||
|
||||
it('should return null when there is no dropdown instance', () => {
|
||||
|
|
|
|||
|
|
@ -1108,6 +1108,7 @@ describe('Modal', () => {
|
|||
const modal = new Modal(div)
|
||||
|
||||
expect(Modal.getInstance(div)).toEqual(modal)
|
||||
expect(Modal.getInstance(div)).toBeInstanceOf(Modal)
|
||||
})
|
||||
|
||||
it('should return null when there is no modal instance', () => {
|
||||
|
|
|
|||
|
|
@ -116,6 +116,22 @@ describe('Popover', () => {
|
|||
|
||||
popover.show()
|
||||
})
|
||||
|
||||
it('should show a popover with provided custom class', done => {
|
||||
fixtureEl.innerHTML = '<a href="#" title="Popover" data-bs-content="https://twitter.com/getbootstrap" data-bs-custom-class="custom-class">BS twitter</a>'
|
||||
|
||||
const popoverEl = fixtureEl.querySelector('a')
|
||||
const popover = new Popover(popoverEl)
|
||||
|
||||
popoverEl.addEventListener('shown.bs.popover', () => {
|
||||
const tip = document.querySelector('.popover')
|
||||
expect(tip).toBeDefined()
|
||||
expect(tip.classList.contains('custom-class')).toBeTrue()
|
||||
done()
|
||||
})
|
||||
|
||||
popover.show()
|
||||
})
|
||||
})
|
||||
|
||||
describe('hide', () => {
|
||||
|
|
@ -237,6 +253,7 @@ describe('Popover', () => {
|
|||
const popover = new Popover(popoverEl)
|
||||
|
||||
expect(Popover.getInstance(popoverEl)).toEqual(popover)
|
||||
expect(Popover.getInstance(popoverEl)).toBeInstanceOf(Popover)
|
||||
})
|
||||
|
||||
it('should return null when there is no popover instance', () => {
|
||||
|
|
|
|||
|
|
@ -634,6 +634,16 @@ describe('ScrollSpy', () => {
|
|||
})
|
||||
|
||||
describe('getInstance', () => {
|
||||
it('should return scrollspy instance', () => {
|
||||
fixtureEl.innerHTML = '<div></div>'
|
||||
|
||||
const div = fixtureEl.querySelector('div')
|
||||
const scrollSpy = new ScrollSpy(div)
|
||||
|
||||
expect(ScrollSpy.getInstance(div)).toEqual(scrollSpy)
|
||||
expect(ScrollSpy.getInstance(div)).toBeInstanceOf(ScrollSpy)
|
||||
})
|
||||
|
||||
it('should return null if there is no instance', () => {
|
||||
expect(ScrollSpy.getInstance(fixtureEl)).toEqual(null)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -417,6 +417,7 @@ describe('Tab', () => {
|
|||
const tab = new Tab(divEl)
|
||||
|
||||
expect(Tab.getInstance(divEl)).toEqual(tab)
|
||||
expect(Tab.getInstance(divEl)).toBeInstanceOf(Tab)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -384,6 +384,7 @@ describe('Toast', () => {
|
|||
const toast = new Toast(div)
|
||||
|
||||
expect(Toast.getInstance(div)).toEqual(toast)
|
||||
expect(Toast.getInstance(div)).toBeInstanceOf(Toast)
|
||||
})
|
||||
|
||||
it('should return null when there is no toast instance', () => {
|
||||
|
|
|
|||
|
|
@ -632,6 +632,61 @@ describe('Tooltip', () => {
|
|||
|
||||
tooltipEl.dispatchEvent(createEvent('mouseover'))
|
||||
})
|
||||
|
||||
it('should show a tooltip with custom class provided in data attributes', done => {
|
||||
fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip" data-bs-custom-class="custom-class">'
|
||||
|
||||
const tooltipEl = fixtureEl.querySelector('a')
|
||||
const tooltip = new Tooltip(tooltipEl)
|
||||
|
||||
tooltipEl.addEventListener('shown.bs.tooltip', () => {
|
||||
const tip = document.querySelector('.tooltip')
|
||||
expect(tip).toBeDefined()
|
||||
expect(tip.classList.contains('custom-class')).toBeTrue()
|
||||
done()
|
||||
})
|
||||
|
||||
tooltip.show()
|
||||
})
|
||||
|
||||
it('should show a tooltip with custom class provided as a string in config', done => {
|
||||
fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
|
||||
|
||||
const tooltipEl = fixtureEl.querySelector('a')
|
||||
const tooltip = new Tooltip(tooltipEl, {
|
||||
customClass: 'custom-class custom-class-2'
|
||||
})
|
||||
|
||||
tooltipEl.addEventListener('shown.bs.tooltip', () => {
|
||||
const tip = document.querySelector('.tooltip')
|
||||
expect(tip).toBeDefined()
|
||||
expect(tip.classList.contains('custom-class')).toBeTrue()
|
||||
expect(tip.classList.contains('custom-class-2')).toBeTrue()
|
||||
done()
|
||||
})
|
||||
|
||||
tooltip.show()
|
||||
})
|
||||
|
||||
it('should show a tooltip with custom class provided as a function in config', done => {
|
||||
fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
|
||||
|
||||
const spy = jasmine.createSpy('customClass').and.returnValue('custom-class')
|
||||
const tooltipEl = fixtureEl.querySelector('a')
|
||||
const tooltip = new Tooltip(tooltipEl, {
|
||||
customClass: spy
|
||||
})
|
||||
|
||||
tooltipEl.addEventListener('shown.bs.tooltip', () => {
|
||||
const tip = document.querySelector('.tooltip')
|
||||
expect(tip).toBeDefined()
|
||||
expect(spy).toHaveBeenCalled()
|
||||
expect(tip.classList.contains('custom-class')).toBeTrue()
|
||||
done()
|
||||
})
|
||||
|
||||
tooltip.show()
|
||||
})
|
||||
})
|
||||
|
||||
describe('hide', () => {
|
||||
|
|
@ -975,6 +1030,79 @@ describe('Tooltip', () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe('getInstance', () => {
|
||||
it('should return tooltip instance', () => {
|
||||
fixtureEl.innerHTML = '<div></div>'
|
||||
|
||||
const div = fixtureEl.querySelector('div')
|
||||
const alert = new Tooltip(div)
|
||||
|
||||
expect(Tooltip.getInstance(div)).toEqual(alert)
|
||||
expect(Tooltip.getInstance(div)).toBeInstanceOf(Tooltip)
|
||||
})
|
||||
|
||||
it('should return null when there is no tooltip instance', () => {
|
||||
fixtureEl.innerHTML = '<div></div>'
|
||||
|
||||
const div = fixtureEl.querySelector('div')
|
||||
|
||||
expect(Tooltip.getInstance(div)).toEqual(null)
|
||||
})
|
||||
})
|
||||
|
||||
describe('aria-label', () => {
|
||||
it('should add the aria-label attribute for referencing original title', done => {
|
||||
fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>'
|
||||
|
||||
const tooltipEl = fixtureEl.querySelector('a')
|
||||
const tooltip = new Tooltip(tooltipEl)
|
||||
|
||||
tooltipEl.addEventListener('shown.bs.tooltip', () => {
|
||||
const tooltipShown = document.querySelector('.tooltip')
|
||||
|
||||
expect(tooltipShown).toBeDefined()
|
||||
expect(tooltipEl.getAttribute('aria-label')).toEqual('Another tooltip')
|
||||
done()
|
||||
})
|
||||
|
||||
tooltip.show()
|
||||
})
|
||||
|
||||
it('should not add the aria-label attribute if the attribute already exists', done => {
|
||||
fixtureEl.innerHTML = '<a href="#" rel="tooltip" aria-label="Different label" title="Another tooltip"></a>'
|
||||
|
||||
const tooltipEl = fixtureEl.querySelector('a')
|
||||
const tooltip = new Tooltip(tooltipEl)
|
||||
|
||||
tooltipEl.addEventListener('shown.bs.tooltip', () => {
|
||||
const tooltipShown = document.querySelector('.tooltip')
|
||||
|
||||
expect(tooltipShown).toBeDefined()
|
||||
expect(tooltipEl.getAttribute('aria-label')).toEqual('Different label')
|
||||
done()
|
||||
})
|
||||
|
||||
tooltip.show()
|
||||
})
|
||||
|
||||
it('should not add the aria-label attribute if the element has text content', done => {
|
||||
fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">text content</a>'
|
||||
|
||||
const tooltipEl = fixtureEl.querySelector('a')
|
||||
const tooltip = new Tooltip(tooltipEl)
|
||||
|
||||
tooltipEl.addEventListener('shown.bs.tooltip', () => {
|
||||
const tooltipShown = document.querySelector('.tooltip')
|
||||
|
||||
expect(tooltipShown).toBeDefined()
|
||||
expect(tooltipEl.getAttribute('aria-label')).toBeNull()
|
||||
done()
|
||||
})
|
||||
|
||||
tooltip.show()
|
||||
})
|
||||
})
|
||||
|
||||
describe('jQueryInterface', () => {
|
||||
it('should create a tooltip', () => {
|
||||
fixtureEl.innerHTML = '<div></div>'
|
||||
|
|
|
|||
|
|
@ -40,10 +40,11 @@
|
|||
"js-minify-standalone": "terser --compress --mangle --comments \"/^!/\" --source-map \"content=dist/js/bootstrap.js.map,includeSources,url=bootstrap.min.js.map\" --output dist/js/bootstrap.min.js dist/js/bootstrap.js",
|
||||
"js-minify-standalone-esm": "terser --compress --mangle --comments \"/^!/\" --source-map \"content=dist/js/bootstrap.esm.js.map,includeSources,url=bootstrap.esm.min.js.map\" --output dist/js/bootstrap.esm.min.js dist/js/bootstrap.esm.js",
|
||||
"js-minify-bundle": "terser --compress --mangle --comments \"/^!/\" --source-map \"content=dist/js/bootstrap.bundle.js.map,includeSources,url=bootstrap.bundle.min.js.map\" --output dist/js/bootstrap.bundle.min.js dist/js/bootstrap.bundle.js",
|
||||
"js-test": "npm-run-all --parallel js-test-karma js-test-jquery js-test-integration",
|
||||
"js-test": "npm-run-all --parallel js-test-karma js-test-jquery js-test-integration-*",
|
||||
"js-debug": "cross-env DEBUG=true npm run js-test-karma",
|
||||
"js-test-karma": "karma start js/tests/karma.conf.js",
|
||||
"js-test-integration": "rollup --config js/tests/integration/rollup.bundle.js && rollup --config js/tests/integration/rollup.bundle-modularity.js",
|
||||
"js-test-integration-bundle": "rollup --config js/tests/integration/rollup.bundle.js",
|
||||
"js-test-integration-modularity": "rollup --config js/tests/integration/rollup.bundle-modularity.js",
|
||||
"js-test-cloud": "cross-env BROWSER=true npm run js-test-karma",
|
||||
"js-test-jquery": "cross-env JQUERY=true npm run js-test-karma",
|
||||
"lint": "npm-run-all --parallel js-lint css-lint lockfile-lint",
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@
|
|||
@include border-bottom-radius(0);
|
||||
}
|
||||
|
||||
> .btn:not(:first-child),
|
||||
> .btn ~ .btn,
|
||||
> .btn-group:not(:first-child) > .btn {
|
||||
@include border-top-radius(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
.table {
|
||||
--#{$variable-prefix}table-bg: #{$table-bg};
|
||||
--#{$variable-prefix}table-accent-bg: transparent;
|
||||
--#{$variable-prefix}table-striped-color: #{$table-striped-color};
|
||||
--#{$variable-prefix}table-striped-bg: #{$table-striped-bg};
|
||||
--#{$variable-prefix}table-active-color: #{$table-active-color};
|
||||
|
|
|
|||
|
|
@ -877,12 +877,6 @@ Options can be passed via data attributes or JavaScript. For data attributes, ap
|
|||
<td><code>true</code></td>
|
||||
<td>Puts the focus on the modal when initialized.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>show</code></td>
|
||||
<td>boolean</td>
|
||||
<td><code>true</code></td>
|
||||
<td>Shows the modal when initialized.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
|
|
|||
|
|
@ -262,6 +262,15 @@ Note that for security reasons the `sanitize`, `sanitizeFn`, and `allowList` opt
|
|||
<td><code>'scrollParent'</code></td>
|
||||
<td>Overflow constraint boundary of the popover. Accepts the values of <code>'viewport'</code>, <code>'window'</code>, <code>'scrollParent'</code>, or an HTMLElement reference (JavaScript only). For more information refer to Popper's <a href="https://popper.js.org/docs/v1/#modifiers..preventOverflow.boundariesElement">preventOverflow docs</a>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>customClass</code></td>
|
||||
<td>string | function</td>
|
||||
<td><code>''</code></td>
|
||||
<td>
|
||||
<p>Add classes to the popover when it is shown. Note that these classes will be added in addition to any classes specified in the template. To add multiple classes, separate them with spaces: <code>'class-1 class-2'</code>.</p>
|
||||
<p>You can also pass a function that should return a single string containing additional class names.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>sanitize</code></td>
|
||||
<td>boolean</td>
|
||||
|
|
|
|||
|
|
@ -271,6 +271,15 @@ Note that for security reasons the `sanitize`, `sanitizeFn`, and `allowList` opt
|
|||
<td><code>'scrollParent'</code></td>
|
||||
<td>Overflow constraint boundary of the tooltip. Accepts the values of <code>'viewport'</code>, <code>'window'</code>, <code>'scrollParent'</code>, or an HTMLElement reference (JavaScript only). For more information refer to Popper's <a href="https://popper.js.org/docs/v1/#modifiers..preventOverflow.boundariesElement">preventOverflow docs</a>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>customClass</code></td>
|
||||
<td>string | function</td>
|
||||
<td><code>''</code></td>
|
||||
<td>
|
||||
<p>Add classes to the tooltip when it is shown. Note that these classes will be added in addition to any classes specified in the template. To add multiple classes, separate them with spaces: <code>'class-1 class-2'</code>.</p>
|
||||
<p>You can also pass a function that should return a single string containing additional class names.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>sanitize</code></td>
|
||||
<td>boolean</td>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ Bootstrap sets basic global display, typography, and link styles. When more cont
|
|||
- Use a [native font stack]({{< docsref "/content/reboot#native-font-stack" >}}) that selects the best `font-family` for each OS and device.
|
||||
- For a more inclusive and accessible type scale, we use the browser's default root `font-size` (typically 16px) so visitors can customize their browser defaults as needed.
|
||||
- Use the `$font-family-base`, `$font-size-base`, and `$line-height-base` attributes as our typographic base applied to the `<body>`.
|
||||
- Set the global link color via `$link-color` and apply link underlines only on `:hover`.
|
||||
- Set the global link color via `$link-color`.
|
||||
- Use `$body-bg` to set a `background-color` on the `<body>` (`#fff` by default).
|
||||
|
||||
These styles can be found within `_reboot.scss`, and the global variables are defined in `_variables.scss`. Make sure to set `$font-size-base` in `rem`.
|
||||
|
|
|
|||
|
|
@ -267,6 +267,7 @@ Changes to Reboot, typography, tables, and more.
|
|||
- Removed individual `$display-*-weight` variables for a single `$display-font-weight`.
|
||||
- Added two new `.display-*` heading styles, `.display-5` and `.display-6`.
|
||||
- Resized existing display headings for a slightly more consistent set of `font-size`s.
|
||||
- Links are underlined by default (not just on hover), unless they're part of specific components.
|
||||
|
||||
### Forms
|
||||
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@
|
|||
<img class="img-fluid mt-3 mx-auto" srcset="/docs/{{ .Site.Params.docs_version }}/assets/img/bootstrap-themes.png,
|
||||
/docs/{{ .Site.Params.docs_version }}/assets/img/bootstrap-themes@2x.png 2x"
|
||||
src="/docs/{{ .Site.Params.docs_version }}/assets/img/bootstrap-themes.png"
|
||||
alt="Bootstrap Icons" width="700" height="500" loading="lazy">
|
||||
alt="Bootstrap Themes" width="700" height="500" loading="lazy">
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue