diff --git a/.eslintrc.json b/.eslintrc.json index 4c49fd0b1..ec6aa589c 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -49,15 +49,11 @@ "unicorn/no-null": "off", "unicorn/no-unused-properties": "error", "unicorn/no-useless-undefined": "off", - "unicorn/prefer-array-find": "off", "unicorn/prefer-dataset": "off", - "unicorn/prefer-includes": "off", "unicorn/prefer-node-append": "off", "unicorn/prefer-node-remove": "off", - "unicorn/prefer-number-properties": "off", "unicorn/prefer-optional-catch-binding": "off", "unicorn/prefer-query-selector": "off", - "unicorn/prefer-set-has": "off", "unicorn/prevent-abbreviations": "off" } } diff --git a/build/build-plugins.js b/build/build-plugins.js index 6d9cdb332..1f44a3b85 100644 --- a/build/build-plugins.js +++ b/build/build-plugins.js @@ -125,17 +125,17 @@ const getConfigByPluginKey = pluginKey => { } } -const utilObjects = [ +const utilObjects = new Set([ 'Util', 'Sanitizer' -] +]) -const domObjects = [ +const domObjects = new Set([ 'Data', 'EventHandler', 'Manipulator', 'SelectorEngine' -] +]) const build = async plugin => { console.log(`Building ${plugin} plugin...`) @@ -144,11 +144,11 @@ const build = async plugin => { const pluginFilename = path.basename(bsPlugins[plugin]) let pluginPath = rootPath - if (utilObjects.includes(plugin)) { + if (utilObjects.has(plugin)) { pluginPath = `${rootPath}/util/` } - if (domObjects.includes(plugin)) { + if (domObjects.has(plugin)) { pluginPath = `${rootPath}/dom/` } diff --git a/js/src/alert.js b/js/src/alert.js index 7eb53ac0b..724cda017 100644 --- a/js/src/alert.js +++ b/js/src/alert.js @@ -28,7 +28,7 @@ const DATA_KEY = 'bs.alert' const EVENT_KEY = `.${DATA_KEY}` const DATA_API_KEY = '.data-api' -const SELECTOR_DISMISS = '[data-dismiss="alert"]' +const SELECTOR_DISMISS = '[data-bs-dismiss="alert"]' const EVENT_CLOSE = `close${EVENT_KEY}` const EVENT_CLOSED = `closed${EVENT_KEY}` diff --git a/js/src/button.js b/js/src/button.js index dc9bd0e9d..42376943d 100644 --- a/js/src/button.js +++ b/js/src/button.js @@ -23,7 +23,7 @@ const DATA_API_KEY = '.data-api' const CLASS_NAME_ACTIVE = 'active' -const SELECTOR_DATA_TOGGLE = '[data-toggle="button"]' +const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="button"]' const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}` diff --git a/js/src/carousel.js b/js/src/carousel.js index 84a88bb04..c663efbea 100644 --- a/js/src/carousel.js +++ b/js/src/carousel.js @@ -91,8 +91,8 @@ const SELECTOR_ITEM = '.carousel-item' const SELECTOR_ITEM_IMG = '.carousel-item img' const SELECTOR_NEXT_PREV = '.carousel-item-next, .carousel-item-prev' const SELECTOR_INDICATORS = '.carousel-indicators' -const SELECTOR_DATA_SLIDE = '[data-slide], [data-slide-to]' -const SELECTOR_DATA_RIDE = '[data-ride="carousel"]' +const SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]' +const SELECTOR_DATA_RIDE = '[data-bs-ride="carousel"]' const PointerType = { TOUCH: 'touch', @@ -419,7 +419,7 @@ class Carousel { return } - const elementInterval = parseInt(element.getAttribute('data-interval'), 10) + const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10) if (elementInterval) { this._config.defaultInterval = this._config.defaultInterval || this._config.interval @@ -576,7 +576,7 @@ class Carousel { ...Manipulator.getDataAttributes(target), ...Manipulator.getDataAttributes(this) } - const slideIndex = this.getAttribute('data-slide-to') + const slideIndex = this.getAttribute('data-bs-slide-to') if (slideIndex) { config.interval = false diff --git a/js/src/collapse.js b/js/src/collapse.js index 838d0f2a3..2ddcb0c04 100644 --- a/js/src/collapse.js +++ b/js/src/collapse.js @@ -59,7 +59,7 @@ const WIDTH = 'width' const HEIGHT = 'height' const SELECTOR_ACTIVES = '.show, .collapsing' -const SELECTOR_DATA_TOGGLE = '[data-toggle="collapse"]' +const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="collapse"]' /** * ------------------------------------------------------------------------ @@ -74,7 +74,7 @@ class Collapse { this._config = this._getConfig(config) this._triggerArray = SelectorEngine.find( `${SELECTOR_DATA_TOGGLE}[href="#${element.id}"],` + - `${SELECTOR_DATA_TOGGLE}[data-target="#${element.id}"]` + `${SELECTOR_DATA_TOGGLE}[data-bs-target="#${element.id}"]` ) const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE) @@ -137,7 +137,7 @@ class Collapse { actives = SelectorEngine.find(SELECTOR_ACTIVES, this._parent) .filter(elem => { if (typeof this._config.parent === 'string') { - return elem.getAttribute('data-parent') === this._config.parent + return elem.getAttribute('data-bs-parent') === this._config.parent } return elem.classList.contains(CLASS_NAME_COLLAPSE) @@ -150,8 +150,8 @@ class Collapse { const container = SelectorEngine.findOne(this._selector) if (actives) { - const tempActiveData = actives.filter(elem => container !== elem) - activesData = tempActiveData[0] ? Data.getData(tempActiveData[0], DATA_KEY) : null + const tempActiveData = actives.find(elem => container !== elem) + activesData = tempActiveData ? Data.getData(tempActiveData, DATA_KEY) : null if (activesData && activesData._isTransitioning) { return @@ -303,7 +303,7 @@ class Collapse { parent = SelectorEngine.findOne(parent) } - const selector = `${SELECTOR_DATA_TOGGLE}[data-parent="${parent}"]` + const selector = `${SELECTOR_DATA_TOGGLE}[data-bs-parent="${parent}"]` SelectorEngine.find(selector, parent) .forEach(element => { diff --git a/js/src/dom/event-handler.js b/js/src/dom/event-handler.js index bf9aa38df..ceb6a6e6e 100644 --- a/js/src/dom/event-handler.js +++ b/js/src/dom/event-handler.js @@ -22,7 +22,7 @@ const customEvents = { mouseenter: 'mouseover', mouseleave: 'mouseout' } -const nativeEvents = [ +const nativeEvents = new Set([ 'click', 'dblclick', 'mouseup', @@ -69,7 +69,7 @@ const nativeEvents = [ 'error', 'abort', 'scroll' -] +]) /** * ------------------------------------------------------------------------ @@ -151,7 +151,7 @@ function normalizeParams(originalTypeEvent, handler, delegationFn) { typeEvent = custom } - const isNative = nativeEvents.indexOf(typeEvent) > -1 + const isNative = nativeEvents.has(typeEvent) if (!isNative) { typeEvent = originalTypeEvent @@ -210,7 +210,7 @@ function removeNamespacedHandlers(element, events, typeEvent, namespace) { const storeElementEvent = events[typeEvent] || {} Object.keys(storeElementEvent).forEach(handlerKey => { - if (handlerKey.indexOf(namespace) > -1) { + if (handlerKey.includes(namespace)) { const event = storeElementEvent[handlerKey] removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector) @@ -235,7 +235,7 @@ const EventHandler = { const [delegation, originalHandler, typeEvent] = normalizeParams(originalTypeEvent, handler, delegationFn) const inNamespace = typeEvent !== originalTypeEvent const events = getEvent(element) - const isNamespace = originalTypeEvent.charAt(0) === '.' + const isNamespace = originalTypeEvent.startsWith('.') if (typeof originalHandler !== 'undefined') { // Simplest case: handler is passed, remove that listener ONLY. @@ -257,7 +257,7 @@ const EventHandler = { Object.keys(storeElementEvent).forEach(keyHandlers => { const handlerKey = keyHandlers.replace(stripUidRegex, '') - if (!inNamespace || originalTypeEvent.indexOf(handlerKey) > -1) { + if (!inNamespace || originalTypeEvent.includes(handlerKey)) { const event = storeElementEvent[keyHandlers] removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector) @@ -273,7 +273,7 @@ const EventHandler = { const $ = getjQuery() const typeEvent = event.replace(stripNameRegex, '') const inNamespace = event !== typeEvent - const isNative = nativeEvents.indexOf(typeEvent) > -1 + const isNative = nativeEvents.has(typeEvent) let jQueryEvent let bubbles = true diff --git a/js/src/dom/manipulator.js b/js/src/dom/manipulator.js index bcbd340ac..faab54b5e 100644 --- a/js/src/dom/manipulator.js +++ b/js/src/dom/manipulator.js @@ -43,13 +43,15 @@ const Manipulator = { return {} } - const attributes = { - ...element.dataset - } + const attributes = {} - Object.keys(attributes).forEach(key => { - attributes[key] = normalizeData(attributes[key]) - }) + Object.keys(element.dataset) + .filter(key => key.startsWith('bs')) + .forEach(key => { + let pureKey = key.replace(/^bs/, '') + pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length) + attributes[pureKey] = normalizeData(element.dataset[key]) + }) return attributes }, diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 3a3f12c48..c262997ce 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -59,7 +59,7 @@ const CLASS_NAME_MENURIGHT = 'dropdown-menu-right' const CLASS_NAME_NAVBAR = 'navbar' const CLASS_NAME_POSITION_STATIC = 'position-static' -const SELECTOR_DATA_TOGGLE = '[data-toggle="dropdown"]' +const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="dropdown"]' const SELECTOR_FORM_CHILD = '.dropdown form' const SELECTOR_MENU = '.dropdown-menu' const SELECTOR_NAVBAR_NAV = '.navbar-nav' diff --git a/js/src/modal.js b/js/src/modal.js index d6d10ab93..548b1d801 100644 --- a/js/src/modal.js +++ b/js/src/modal.js @@ -70,8 +70,8 @@ const CLASS_NAME_STATIC = 'modal-static' const SELECTOR_DIALOG = '.modal-dialog' const SELECTOR_MODAL_BODY = '.modal-body' -const SELECTOR_DATA_TOGGLE = '[data-toggle="modal"]' -const SELECTOR_DATA_DISMISS = '[data-dismiss="modal"]' +const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="modal"]' +const SELECTOR_DATA_DISMISS = '[data-bs-dismiss="modal"]' const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top' const SELECTOR_STICKY_CONTENT = '.sticky-top' @@ -473,8 +473,8 @@ class Modal { .forEach(element => { const actualPadding = element.style.paddingRight const calculatedPadding = window.getComputedStyle(element)['padding-right'] - Manipulator.setDataAttribute(element, 'padding-right', actualPadding) - element.style.paddingRight = `${parseFloat(calculatedPadding) + this._scrollbarWidth}px` + Manipulator.setDataAttribute(element, 'bs-padding-right', actualPadding) + element.style.paddingRight = `${Number.parseFloat(calculatedPadding) + this._scrollbarWidth}px` }) // Adjust sticky content margin @@ -482,16 +482,16 @@ class Modal { .forEach(element => { const actualMargin = element.style.marginRight const calculatedMargin = window.getComputedStyle(element)['margin-right'] - Manipulator.setDataAttribute(element, 'margin-right', actualMargin) - element.style.marginRight = `${parseFloat(calculatedMargin) - this._scrollbarWidth}px` + Manipulator.setDataAttribute(element, 'bs-margin-right', actualMargin) + element.style.marginRight = `${Number.parseFloat(calculatedMargin) - this._scrollbarWidth}px` }) // Adjust body padding const actualPadding = document.body.style.paddingRight const calculatedPadding = window.getComputedStyle(document.body)['padding-right'] - Manipulator.setDataAttribute(document.body, 'padding-right', actualPadding) - document.body.style.paddingRight = `${parseFloat(calculatedPadding) + this._scrollbarWidth}px` + Manipulator.setDataAttribute(document.body, 'bs-padding-right', actualPadding) + document.body.style.paddingRight = `${Number.parseFloat(calculatedPadding) + this._scrollbarWidth}px` } document.body.classList.add(CLASS_NAME_OPEN) @@ -501,9 +501,9 @@ class Modal { // Restore fixed content padding SelectorEngine.find(SELECTOR_FIXED_CONTENT) .forEach(element => { - const padding = Manipulator.getDataAttribute(element, 'padding-right') + const padding = Manipulator.getDataAttribute(element, 'bs-padding-right') if (typeof padding !== 'undefined') { - Manipulator.removeDataAttribute(element, 'padding-right') + Manipulator.removeDataAttribute(element, 'bs-padding-right') element.style.paddingRight = padding } }) @@ -511,19 +511,19 @@ class Modal { // Restore sticky content and navbar-toggler margin SelectorEngine.find(`${SELECTOR_STICKY_CONTENT}`) .forEach(element => { - const margin = Manipulator.getDataAttribute(element, 'margin-right') + const margin = Manipulator.getDataAttribute(element, 'bs-margin-right') if (typeof margin !== 'undefined') { - Manipulator.removeDataAttribute(element, 'margin-right') + Manipulator.removeDataAttribute(element, 'bs-margin-right') element.style.marginRight = margin } }) // Restore body padding - const padding = Manipulator.getDataAttribute(document.body, 'padding-right') + const padding = Manipulator.getDataAttribute(document.body, 'bs-padding-right') if (typeof padding === 'undefined') { document.body.style.paddingRight = '' } else { - Manipulator.removeDataAttribute(document.body, 'padding-right') + Manipulator.removeDataAttribute(document.body, 'bs-padding-right') document.body.style.paddingRight = padding } } diff --git a/js/src/popover.js b/js/src/popover.js index 7203d9bab..46b693e69 100644 --- a/js/src/popover.js +++ b/js/src/popover.js @@ -123,7 +123,7 @@ class Popover extends Tooltip { } _getContent() { - return this.element.getAttribute('data-content') || + return this.element.getAttribute('data-bs-content') || this.config.content } diff --git a/js/src/scrollspy.js b/js/src/scrollspy.js index 53c1700a5..de456e080 100644 --- a/js/src/scrollspy.js +++ b/js/src/scrollspy.js @@ -49,7 +49,7 @@ const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}` const CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item' const CLASS_NAME_ACTIVE = 'active' -const SELECTOR_DATA_SPY = '[data-spy="scroll"]' +const SELECTOR_DATA_SPY = '[data-bs-spy="scroll"]' const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group' const SELECTOR_NAV_LINKS = '.nav-link' const SELECTOR_NAV_ITEMS = '.nav-item' @@ -241,7 +241,7 @@ class ScrollSpy { this._clear() const queries = this._selector.split(',') - .map(selector => `${selector}[data-target="${target}"],${selector}[href="${target}"]`) + .map(selector => `${selector}[data-bs-target="${target}"],${selector}[href="${target}"]`) const link = SelectorEngine.findOne(queries.join(',')) diff --git a/js/src/tab.js b/js/src/tab.js index f7ebfc9cd..56269e2fa 100644 --- a/js/src/tab.js +++ b/js/src/tab.js @@ -46,7 +46,7 @@ const SELECTOR_DROPDOWN = '.dropdown' const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group' const SELECTOR_ACTIVE = '.active' const SELECTOR_ACTIVE_UL = ':scope > li > .active' -const SELECTOR_DATA_TOGGLE = '[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]' +const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]' const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle' const SELECTOR_DROPDOWN_ACTIVE_CHILD = ':scope > .dropdown-menu .active' diff --git a/js/src/toast.js b/js/src/toast.js index bf5a386e8..1e50b0669 100644 --- a/js/src/toast.js +++ b/js/src/toast.js @@ -52,7 +52,7 @@ const Default = { delay: 5000 } -const SELECTOR_DATA_DISMISS = '[data-dismiss="toast"]' +const SELECTOR_DATA_DISMISS = '[data-bs-dismiss="toast"]' /** * ------------------------------------------------------------------------ diff --git a/js/src/tooltip.js b/js/src/tooltip.js index 0b19a9601..7b115a69b 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -39,7 +39,7 @@ const DATA_KEY = 'bs.tooltip' const EVENT_KEY = `.${DATA_KEY}` const CLASS_PREFIX = 'bs-tooltip' const BSCLS_PREFIX_REGEX = new RegExp(`(^|\\s)${CLASS_PREFIX}\\S+`, 'g') -const DISALLOWED_ATTRIBUTES = ['sanitize', 'allowList', 'sanitizeFn'] +const DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn']) const DefaultType = { animation: 'boolean', @@ -443,7 +443,7 @@ class Tooltip { } getTitle() { - let title = this.element.getAttribute('data-original-title') + let title = this.element.getAttribute('data-bs-original-title') if (!title) { title = typeof this.config.title === 'function' ? @@ -578,14 +578,11 @@ class Tooltip { } _fixTitle() { - const titleType = typeof this.element.getAttribute('data-original-title') - - if (this.element.getAttribute('title') || titleType !== 'string') { - this.element.setAttribute( - 'data-original-title', - this.element.getAttribute('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', '') } } @@ -682,7 +679,7 @@ class Tooltip { const dataAttributes = Manipulator.getDataAttributes(this.element) Object.keys(dataAttributes).forEach(dataAttr => { - if (DISALLOWED_ATTRIBUTES.indexOf(dataAttr) !== -1) { + if (DISALLOWED_ATTRIBUTES.has(dataAttr)) { delete dataAttributes[dataAttr] } }) diff --git a/js/src/util/index.js b/js/src/util/index.js index b7fac9c44..c7cb3176a 100644 --- a/js/src/util/index.js +++ b/js/src/util/index.js @@ -33,7 +33,7 @@ const getUID = prefix => { } const getSelector = element => { - let selector = element.getAttribute('data-target') + let selector = element.getAttribute('data-bs-target') if (!selector || selector === '#') { const hrefAttr = element.getAttribute('href') @@ -71,8 +71,8 @@ const getTransitionDurationFromElement = element => { transitionDelay } = window.getComputedStyle(element) - const floatTransitionDuration = parseFloat(transitionDuration) - const floatTransitionDelay = parseFloat(transitionDelay) + const floatTransitionDuration = Number.parseFloat(transitionDuration) + const floatTransitionDelay = Number.parseFloat(transitionDelay) // Return 0 if element or transition duration is not found if (!floatTransitionDuration && !floatTransitionDelay) { @@ -83,7 +83,7 @@ const getTransitionDurationFromElement = element => { transitionDuration = transitionDuration.split(',')[0] transitionDelay = transitionDelay.split(',')[0] - return (parseFloat(transitionDuration) + parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER + return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER } const triggerTransitionEnd = element => { @@ -173,7 +173,7 @@ const reflow = element => element.offsetHeight const getjQuery = () => { const { jQuery } = window - if (jQuery && !document.body.hasAttribute('data-no-jquery')) { + if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) { return jQuery } diff --git a/js/src/util/sanitizer.js b/js/src/util/sanitizer.js index d3747bba9..68469285a 100644 --- a/js/src/util/sanitizer.js +++ b/js/src/util/sanitizer.js @@ -5,7 +5,7 @@ * -------------------------------------------------------------------------- */ -const uriAttrs = [ +const uriAttrs = new Set([ 'background', 'cite', 'href', @@ -14,7 +14,7 @@ const uriAttrs = [ 'poster', 'src', 'xlink:href' -] +]) const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i @@ -35,8 +35,8 @@ const DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|vid const allowedAttribute = (attr, allowedAttributeList) => { const attrName = attr.nodeName.toLowerCase() - if (allowedAttributeList.indexOf(attrName) !== -1) { - if (uriAttrs.indexOf(attrName) !== -1) { + if (allowedAttributeList.includes(attrName)) { + if (uriAttrs.has(attrName)) { return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN)) } @@ -107,7 +107,7 @@ export function sanitizeHtml(unsafeHtml, allowList, sanitizeFn) { const el = elements[i] const elName = el.nodeName.toLowerCase() - if (allowlistKeys.indexOf(elName) === -1) { + if (!allowlistKeys.includes(elName)) { el.parentNode.removeChild(el) continue diff --git a/js/tests/integration/bundle-modularity.js b/js/tests/integration/bundle-modularity.js index 07c6674e6..ed427cd92 100644 --- a/js/tests/integration/bundle-modularity.js +++ b/js/tests/integration/bundle-modularity.js @@ -2,6 +2,6 @@ import 'popper.js' import Tooltip from '../../dist/tooltip' window.addEventListener('load', () => { - [...document.querySelectorAll('[data-toggle="tooltip"]')] + [...document.querySelectorAll('[data-bs-toggle="tooltip"]')] .map(tooltipNode => new Tooltip(tooltipNode)) }) diff --git a/js/tests/integration/bundle.js b/js/tests/integration/bundle.js index 69d754352..1c6e60bf5 100644 --- a/js/tests/integration/bundle.js +++ b/js/tests/integration/bundle.js @@ -2,6 +2,6 @@ import 'popper.js' import { Tooltip } from '../../../dist/js/bootstrap.esm.js' window.addEventListener('load', () => { - [...document.querySelectorAll('[data-toggle="tooltip"]')] + [...document.querySelectorAll('[data-bs-toggle="tooltip"]')] .map(tooltipNode => new Tooltip(tooltipNode)) }) diff --git a/js/tests/integration/index.html b/js/tests/integration/index.html index 5606755b1..0ea0b64c3 100644 --- a/js/tests/integration/index.html +++ b/js/tests/integration/index.html @@ -14,14 +14,14 @@

Hello, world!

- -