diff --git a/.eslintrc.json b/.eslintrc.json index d5a54d46b..ec6aa589c 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -43,14 +43,15 @@ ], "unicorn/consistent-function-scoping": "off", "unicorn/explicit-length-check": "off", - "unicorn/no-array-callback-reference": "off", + "unicorn/import-index": "off", + "unicorn/no-fn-reference-in-iterator": "off", "unicorn/no-for-loop": "off", "unicorn/no-null": "off", "unicorn/no-unused-properties": "error", "unicorn/no-useless-undefined": "off", - "unicorn/prefer-dom-node-append": "off", - "unicorn/prefer-dom-node-dataset": "off", - "unicorn/prefer-dom-node-remove": "off", + "unicorn/prefer-dataset": "off", + "unicorn/prefer-node-append": "off", + "unicorn/prefer-node-remove": "off", "unicorn/prefer-optional-catch-binding": "off", "unicorn/prefer-query-selector": "off", "unicorn/prevent-abbreviations": "off" diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 29135b400..31976021e 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -15,10 +15,3 @@ updates: - v5 versioning-strategy: increase rebase-strategy: disabled - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: weekly - day: tuesday - time: "12:00" - timezone: Europe/Athens diff --git a/.github/workflows/browserstack.yml b/.github/workflows/browserstack.yml index a12bffcf7..00831721d 100644 --- a/.github/workflows/browserstack.yml +++ b/.github/workflows/browserstack.yml @@ -4,8 +4,9 @@ on: push: env: + CI: true FORCE_COLOR: 2 - NODE: 14 + NODE: 14.x jobs: browserstack: @@ -18,7 +19,7 @@ jobs: uses: actions/checkout@v2 - name: Set up Node.js - uses: actions/setup-node@v2 + uses: actions/setup-node@v1 with: node-version: "${{ env.NODE }}" @@ -28,8 +29,8 @@ jobs: path: ~/.npm key: ${{ runner.os }}-node-v${{ env.NODE }}-${{ hashFiles('package.json') }}-${{ hashFiles('package-lock.json') }} restore-keys: | - ${{ runner.os }}-node-v${{ env.NODE }}-${{ hashFiles('package.json') }}-${{ hashFiles('package-lock.json') }} - ${{ runner.os }}-node-v${{ env.NODE }}- + ${{ runner.OS }}-node-v${{ env.NODE }}-${{ hashFiles('package.json') }}-${{ hashFiles('package-lock.json') }} + ${{ runner.OS }}-node-v${{ env.NODE }}- - name: Install npm dependencies run: npm ci diff --git a/.github/workflows/bundlewatch.yml b/.github/workflows/bundlewatch.yml index b2bd5eed5..966dfbf72 100644 --- a/.github/workflows/bundlewatch.yml +++ b/.github/workflows/bundlewatch.yml @@ -7,8 +7,9 @@ on: pull_request: env: + CI: true FORCE_COLOR: 2 - NODE: 14 + NODE: 14.x jobs: bundlewatch: @@ -19,7 +20,7 @@ jobs: uses: actions/checkout@v2 - name: Set up Node.js - uses: actions/setup-node@v2 + uses: actions/setup-node@v1 with: node-version: "${{ env.NODE }}" @@ -29,8 +30,8 @@ jobs: path: ~/.npm key: ${{ runner.os }}-node-v${{ env.NODE }}-${{ hashFiles('package.json') }}-${{ hashFiles('package-lock.json') }} restore-keys: | - ${{ runner.os }}-node-v${{ env.NODE }}-${{ hashFiles('package.json') }}-${{ hashFiles('package-lock.json') }} - ${{ runner.os }}-node-v${{ env.NODE }}- + ${{ runner.OS }}-node-v${{ env.NODE }}-${{ hashFiles('package.json') }}-${{ hashFiles('package-lock.json') }} + ${{ runner.OS }}-node-v${{ env.NODE }}- - name: Install npm dependencies run: npm ci diff --git a/.github/workflows/css.yml b/.github/workflows/css.yml index a28059d79..a75f018c5 100644 --- a/.github/workflows/css.yml +++ b/.github/workflows/css.yml @@ -7,8 +7,9 @@ on: pull_request: env: + CI: true FORCE_COLOR: 2 - NODE: 14 + NODE: 14.x jobs: css: @@ -19,7 +20,7 @@ jobs: uses: actions/checkout@v2 - name: Set up Node.js - uses: actions/setup-node@v2 + uses: actions/setup-node@v1 with: node-version: "${{ env.NODE }}" @@ -29,8 +30,8 @@ jobs: path: ~/.npm key: ${{ runner.os }}-node-v${{ env.NODE }}-${{ hashFiles('package.json') }}-${{ hashFiles('package-lock.json') }} restore-keys: | - ${{ runner.os }}-node-v${{ env.NODE }}-${{ hashFiles('package.json') }}-${{ hashFiles('package-lock.json') }} - ${{ runner.os }}-node-v${{ env.NODE }}- + ${{ runner.OS }}-node-v${{ env.NODE }}-${{ hashFiles('package.json') }}-${{ hashFiles('package-lock.json') }} + ${{ runner.OS }}-node-v${{ env.NODE }}- - name: Install npm dependencies run: npm ci diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 150e4d16c..58b55fc7c 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -7,8 +7,9 @@ on: pull_request: env: + CI: true FORCE_COLOR: 2 - NODE: 14 + NODE: 14.x jobs: docs: @@ -19,7 +20,7 @@ jobs: uses: actions/checkout@v2 - name: Set up Node.js - uses: actions/setup-node@v2 + uses: actions/setup-node@v1 with: node-version: "${{ env.NODE }}" @@ -31,8 +32,8 @@ jobs: path: ~/.npm key: ${{ runner.os }}-node-v${{ env.NODE }}-${{ hashFiles('package.json') }}-${{ hashFiles('package-lock.json') }} restore-keys: | - ${{ runner.os }}-node-v${{ env.NODE }}-${{ hashFiles('package.json') }}-${{ hashFiles('package-lock.json') }} - ${{ runner.os }}-node-v${{ env.NODE }}- + ${{ runner.OS }}-node-v${{ env.NODE }}-${{ hashFiles('package.json') }}-${{ hashFiles('package-lock.json') }} + ${{ runner.OS }}-node-v${{ env.NODE }}- - name: Install npm dependencies run: npm ci diff --git a/.github/workflows/js.yml b/.github/workflows/js.yml index c56a2dfdd..1ec0d6909 100644 --- a/.github/workflows/js.yml +++ b/.github/workflows/js.yml @@ -7,6 +7,7 @@ on: pull_request: env: + CI: true FORCE_COLOR: 2 jobs: @@ -24,7 +25,7 @@ jobs: uses: actions/checkout@v2 - name: Set up Node.js - uses: actions/setup-node@v2 + uses: actions/setup-node@v1 with: node-version: ${{ matrix.node }} @@ -34,8 +35,8 @@ jobs: path: ~/.npm key: ${{ runner.os }}-node-v${{ matrix.node }}-${{ hashFiles('package.json') }}-${{ hashFiles('package-lock.json') }}} restore-keys: | - ${{ runner.os }}-node-v${{ matrix.node }}-${{ hashFiles('package.json') }}-${{ hashFiles('package-lock.json') }} - ${{ runner.os }}-node-v${{ matrix.node }}- + ${{ runner.OS }}-node-v${{ matrix.node }}-${{ hashFiles('package.json') }}-${{ hashFiles('package-lock.json') }} + ${{ runner.OS }}-node-v${{ matrix.node }}- - name: Install npm dependencies run: npm ci diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 369aaced3..e850a1f1b 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -7,8 +7,9 @@ on: pull_request: env: + CI: true FORCE_COLOR: 2 - NODE: 14 + NODE: 14.x jobs: lint: @@ -19,7 +20,7 @@ jobs: uses: actions/checkout@v2 - name: Set up Node.js - uses: actions/setup-node@v2 + uses: actions/setup-node@v1 with: node-version: "${{ env.NODE }}" @@ -29,8 +30,8 @@ jobs: path: ~/.npm key: ${{ runner.os }}-node-v${{ env.NODE }}-${{ hashFiles('package.json') }}-${{ hashFiles('package-lock.json') }} restore-keys: | - ${{ runner.os }}-node-v${{ env.NODE }}-${{ hashFiles('package.json') }}-${{ hashFiles('package-lock.json') }} - ${{ runner.os }}-node-v${{ env.NODE }}- + ${{ runner.OS }}-node-v${{ env.NODE }}-${{ hashFiles('package.json') }}-${{ hashFiles('package-lock.json') }} + ${{ runner.OS }}-node-v${{ env.NODE }}- - name: Install npm dependencies run: npm ci diff --git a/.github/workflows/node-sass.yml b/.github/workflows/node-sass.yml index ee64b2152..2db55f0ff 100644 --- a/.github/workflows/node-sass.yml +++ b/.github/workflows/node-sass.yml @@ -7,8 +7,9 @@ on: pull_request: env: + CI: true FORCE_COLOR: 2 - NODE: 14 + NODE: 14.x jobs: css: @@ -19,7 +20,7 @@ jobs: uses: actions/checkout@v2 - name: Set up Node.js - uses: actions/setup-node@v2 + uses: actions/setup-node@v1 with: node-version: "${{ env.NODE }}" diff --git a/.gitignore b/.gitignore index 0a0f88d15..6208c57d7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,19 @@ # Ignore docs files /_gh_pages/ +# This is the old Jekyll docs dist folder; +# keeping it here so that when we switch branches it doesn't show up +/site/docs/**/dist/ +# Jekyll's cache folder; keeping it for the same reason as above +/site/.jekyll-cache/ # Hugo resources folder /resources/ +# Ignore ruby/bundler files; +# keeping them here so that when we switch branches they don't show up +/.bundle/ +/vendor/ +/.ruby-version + # Numerous always-ignore extensions *.diff *.err diff --git a/.stylelintrc b/.stylelintrc index c068d30b5..1c9ee1811 100644 --- a/.stylelintrc +++ b/.stylelintrc @@ -3,10 +3,6 @@ "stylelint-config-twbs-bootstrap/scss" ], "rules": { - "declaration-property-value-disallowed-list": { - "border": "none", - "outline": "none" - }, "function-disallowed-list": [ "calc", "lighten", diff --git a/LICENSE b/LICENSE index 72dda234e..173a9ebbb 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ The MIT License (MIT) -Copyright (c) 2011-2021 Twitter, Inc. -Copyright (c) 2011-2021 The Bootstrap Authors +Copyright (c) 2011-2020 Twitter, Inc. +Copyright (c) 2011-2020 The Bootstrap Authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index f41498691..8a470260a 100644 --- a/README.md +++ b/README.md @@ -236,4 +236,4 @@ Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com ## Copyright and license -Code and documentation copyright 2011–2021 the [Bootstrap Authors](https://github.com/twbs/bootstrap/graphs/contributors) and [Twitter, Inc.](https://twitter.com) Code released under the [MIT License](https://github.com/twbs/bootstrap/blob/main/LICENSE). Docs released under [Creative Commons](https://creativecommons.org/licenses/by/3.0/). +Code and documentation copyright 2011–2020 the [Bootstrap Authors](https://github.com/twbs/bootstrap/graphs/contributors) and [Twitter, Inc.](https://twitter.com) Code released under the [MIT License](https://github.com/twbs/bootstrap/blob/main/LICENSE). Docs released under [Creative Commons](https://creativecommons.org/licenses/by/3.0/). diff --git a/build/build-plugins.js b/build/build-plugins.js index d1930b855..ea7477390 100644 --- a/build/build-plugins.js +++ b/build/build-plugins.js @@ -2,8 +2,8 @@ /*! * Script to build our plugins to use them separately. - * Copyright 2020-2021 The Bootstrap Authors - * Copyright 2020-2021 Twitter, Inc. + * Copyright 2020 The Bootstrap Authors + * Copyright 2020 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */ @@ -29,7 +29,6 @@ const bsPlugins = { Manipulator: path.resolve(__dirname, '../js/src/dom/manipulator.js'), SelectorEngine: path.resolve(__dirname, '../js/src/dom/selector-engine.js'), Alert: path.resolve(__dirname, '../js/src/alert.js'), - Base: path.resolve(__dirname, '../js/src/base-component.js'), Button: path.resolve(__dirname, '../js/src/button.js'), Carousel: path.resolve(__dirname, '../js/src/carousel.js'), Collapse: path.resolve(__dirname, '../js/src/collapse.js'), @@ -45,13 +44,11 @@ const bsPlugins = { const defaultPluginConfig = { external: [ bsPlugins.Data, - bsPlugins.Base, bsPlugins.EventHandler, bsPlugins.SelectorEngine ], globals: { [bsPlugins.Data]: 'Data', - [bsPlugins.Base]: 'Base', [bsPlugins.EventHandler]: 'EventHandler', [bsPlugins.SelectorEngine]: 'SelectorEngine' } @@ -76,7 +73,6 @@ const getConfigByPluginKey = pluginKey => { } if ( - pluginKey === 'Base' || pluginKey === 'Button' || pluginKey === 'Carousel' || pluginKey === 'Collapse' || @@ -116,13 +112,11 @@ const getConfigByPluginKey = pluginKey => { return { external: [ bsPlugins.Data, - bsPlugins.Base, bsPlugins.EventHandler, bsPlugins.Manipulator ], globals: { [bsPlugins.Data]: 'Data', - [bsPlugins.Base]: 'Base', [bsPlugins.EventHandler]: 'EventHandler', [bsPlugins.Manipulator]: 'Manipulator' } diff --git a/build/change-version.js b/build/change-version.js index 8086ed774..b8a640fa8 100644 --- a/build/change-version.js +++ b/build/change-version.js @@ -2,8 +2,8 @@ /*! * Script to update version number references in the project. - * Copyright 2017-2021 The Bootstrap Authors - * Copyright 2017-2021 Twitter, Inc. + * Copyright 2017-2020 The Bootstrap Authors + * Copyright 2017-2020 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */ diff --git a/build/generate-sri.js b/build/generate-sri.js index 221873b8f..8a2e59360 100644 --- a/build/generate-sri.js +++ b/build/generate-sri.js @@ -5,8 +5,8 @@ * Remember to use the same vendor files as the CDN ones, * otherwise the hashes won't match! * - * Copyright 2017-2021 The Bootstrap Authors - * Copyright 2017-2021 Twitter, Inc. + * Copyright 2017-2020 The Bootstrap Authors + * Copyright 2017-2020 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */ diff --git a/build/vnu-jar.js b/build/vnu-jar.js index c23b94d60..90c1a12ab 100644 --- a/build/vnu-jar.js +++ b/build/vnu-jar.js @@ -2,8 +2,8 @@ /*! * Script to run vnu-jar if Java is available. - * Copyright 2017-2021 The Bootstrap Authors - * Copyright 2017-2021 Twitter, Inc. + * Copyright 2017-2020 The Bootstrap Authors + * Copyright 2017-2020 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */ diff --git a/build/zip-examples.js b/build/zip-examples.js index b2f156502..bf50a0af6 100644 --- a/build/zip-examples.js +++ b/build/zip-examples.js @@ -3,7 +3,7 @@ /*! * Script to create the built examples zip archive; * requires the `zip` command to be present! - * Copyright 2020-2021 The Bootstrap Authors + * Copyright 2020 The Bootstrap Authors * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */ @@ -12,67 +12,36 @@ const path = require('path') const sh = require('shelljs') -const pkg = require('../package.json') +const { version, version_short: versionShort } = require('../package.json') -const versionShort = pkg.config.version_short -const distFolder = `bootstrap-${pkg.version}-examples` -const rootDocsDir = '_gh_pages' -const docsDir = `${rootDocsDir}/docs/${versionShort}/` - -// these are the files we need in the examples -const cssFiles = [ - 'bootstrap.min.css', - 'bootstrap.min.css.map', - 'bootstrap.rtl.min.css', - 'bootstrap.rtl.min.css.map' -] -const jsFiles = [ - 'bootstrap.bundle.min.js', - 'bootstrap.bundle.min.js.map' -] -const imgFiles = [ - 'bootstrap-logo.svg', - 'bootstrap-logo-white.svg' -] +const folderName = `bootstrap-${version}-examples` sh.config.fatal = true -if (!sh.test('-d', rootDocsDir)) { - throw new Error(`The "${rootDocsDir}" folder does not exist, did you forget building the docs?`) +if (!sh.test('-d', '_gh_pages')) { + throw new Error('The "_gh_pages" folder does not exist, did you forget building the docs?') } // switch to the root dir sh.cd(path.join(__dirname, '..')) -// remove any previously created folder/zip with the same name -sh.rm('-rf', [distFolder, `${distFolder}.zip`]) - +// remove any previously created folder with the same name +sh.rm('-rf', folderName) // create any folders so that `cp` works -sh.mkdir('-p', [ - distFolder, - `${distFolder}/assets/brand/`, - `${distFolder}/assets/dist/css/`, - `${distFolder}/assets/dist/js/` -]) +sh.mkdir('-p', folderName) +sh.mkdir('-p', `${folderName}/assets/brand/`) -sh.cp('-Rf', `${docsDir}/examples/*`, distFolder) - -cssFiles.forEach(file => { - sh.cp('-f', `${docsDir}/dist/css/${file}`, `${distFolder}/assets/dist/css/`) -}) - -jsFiles.forEach(file => { - sh.cp('-f', `${docsDir}/dist/js/${file}`, `${distFolder}/assets/dist/js/`) -}) - -imgFiles.forEach(file => { - sh.cp('-f', `${docsDir}/assets/brand/${file}`, `${distFolder}/assets/brand/`) -}) - -sh.rm(`${distFolder}/index.html`) +sh.cp('-Rf', `_gh_pages/docs/${versionShort}/examples/*`, folderName) +sh.cp('-Rf', `_gh_pages/docs/${versionShort}/dist/`, `${folderName}/assets/`) +// also copy the two brand images we use in the examples +sh.cp('-f', [ + `_gh_pages/docs/${versionShort}/assets/brand/bootstrap-logo.svg`, + `_gh_pages/docs/${versionShort}/assets/brand/bootstrap-logo-white.svg` +], `${folderName}/assets/brand/`) +sh.rm(`${folderName}/index.html`) // get all examples' HTML files -sh.find(`${distFolder}/**/*.html`).forEach(file => { +sh.find(`${folderName}/**/*.html`).forEach(file => { const fileContents = sh.cat(file) .toString() .replace(new RegExp(`"/docs/${versionShort}/`, 'g'), '"../') @@ -84,7 +53,7 @@ sh.find(`${distFolder}/**/*.html`).forEach(file => { }) // create the zip file -sh.exec(`zip -r9 "${distFolder}.zip" "${distFolder}"`) +sh.exec(`zip -r9 "${folderName}.zip" "${folderName}"`, { fatal: true }) // remove the folder we created -sh.rm('-rf', distFolder) +sh.rm('-rf', folderName) diff --git a/js/src/collapse.js b/js/src/collapse.js index 0d3eeed54..90bab0ec9 100644 --- a/js/src/collapse.js +++ b/js/src/collapse.js @@ -371,7 +371,7 @@ class Collapse extends BaseComponent { EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { // preventDefault only for elements (which change the URL) not inside the collapsible element - if (event.target.tagName === 'A' || (event.delegateTarget && event.delegateTarget.tagName === 'A')) { + if (event.target.tagName === 'A') { event.preventDefault() } diff --git a/js/src/dom/event-handler.js b/js/src/dom/event-handler.js index e3c685530..2ee13bafc 100644 --- a/js/src/dom/event-handler.js +++ b/js/src/dom/event-handler.js @@ -112,7 +112,6 @@ function bootstrapDelegationHandler(element, selector, fn) { event.delegateTarget = target if (handler.oneOff) { - // eslint-disable-next-line unicorn/consistent-destructuring EventHandler.off(element, event.type, fn) } diff --git a/js/src/dropdown.js b/js/src/dropdown.js index bada537c9..37da987c1 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -57,6 +57,7 @@ const CLASS_NAME_DROPUP = 'dropup' const CLASS_NAME_DROPEND = 'dropend' const CLASS_NAME_DROPSTART = 'dropstart' const CLASS_NAME_NAVBAR = 'navbar' +const CLASS_NAME_POPPER_ACTIVE = 'popper-active' const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="dropdown"]' const SELECTOR_FORM_CHILD = '.dropdown form' @@ -84,7 +85,7 @@ const DefaultType = { offset: '(number|string|function)', flip: 'boolean', boundary: '(string|element)', - reference: '(string|element|object)', + reference: '(string|element)', display: 'string', popperConfig: '(null|object)' } @@ -172,11 +173,14 @@ class Dropdown extends BaseComponent { if (typeof this._config.reference.jquery !== 'undefined') { referenceElement = this._config.reference[0] } - } else if (typeof this._config.reference === 'object') { - referenceElement = this._config.reference } + // The `.popper-active` class removes the `right` property in CSS + // This way popper can position the dropdown correctly + // We add it back after the calculations to get control over our positioning with our CSS again + this._menu.classList.add(CLASS_NAME_POPPER_ACTIVE) this._popper = Popper.createPopper(referenceElement, this._menu, this._getPopperConfig()) + this._menu.classList.remove(CLASS_NAME_POPPER_ACTIVE) } // If this is a touch-enabled device we add extra @@ -259,13 +263,6 @@ class Dropdown extends BaseComponent { typeCheckConfig(NAME, config, this.constructor.DefaultType) - if (typeof config.reference === 'object' && !isElement(config.reference) && - typeof config.reference.getBoundingClientRect !== 'function' - ) { - // Popper virtual elements require a getBoundingClientRect method - throw new TypeError(`${NAME.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`) - } - return config } diff --git a/js/src/modal.js b/js/src/modal.js index fe1b5a4c6..87c22943a 100644 --- a/js/src/modal.js +++ b/js/src/modal.js @@ -590,7 +590,7 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function ( data = new Modal(target, config) } - data.toggle(this) + data.show(this) }) /** diff --git a/js/src/scrollspy.js b/js/src/scrollspy.js index baea49443..a8770ef08 100644 --- a/js/src/scrollspy.js +++ b/js/src/scrollspy.js @@ -76,7 +76,7 @@ class ScrollSpy extends BaseComponent { this._activeTarget = null this._scrollHeight = 0 - EventHandler.on(this._scrollElement, EVENT_SCROLL, () => this._process()) + EventHandler.on(this._scrollElement, EVENT_SCROLL, event => this._process(event)) this.refresh() this._process() diff --git a/js/src/util/index.js b/js/src/util/index.js index 22d0a578b..9ccad1cbb 100644 --- a/js/src/util/index.js +++ b/js/src/util/index.js @@ -111,14 +111,15 @@ const typeCheckConfig = (componentName, config, configTypes) => { Object.keys(configTypes).forEach(property => { const expectedTypes = configTypes[property] const value = config[property] - const valueType = value && isElement(value) ? 'element' : toType(value) + const valueType = value && isElement(value) ? + 'element' : + toType(value) if (!new RegExp(expectedTypes).test(valueType)) { - throw new TypeError( + throw new Error( `${componentName.toUpperCase()}: ` + `Option "${property}" provided type "${valueType}" ` + - `but expected type "${expectedTypes}".` - ) + `but expected type "${expectedTypes}".`) } }) } diff --git a/js/src/util/sanitizer.js b/js/src/util/sanitizer.js index ce3d455a6..d908dd661 100644 --- a/js/src/util/sanitizer.js +++ b/js/src/util/sanitizer.js @@ -37,7 +37,7 @@ const allowedAttribute = (attr, allowedAttributeList) => { if (allowedAttributeList.includes(attrName)) { if (uriAttrs.has(attrName)) { - return Boolean(SAFE_URL_PATTERN.test(attr.nodeValue) || DATA_URL_PATTERN.test(attr.nodeValue)) + return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN)) } return true @@ -47,7 +47,7 @@ const allowedAttribute = (attr, allowedAttributeList) => { // Check if a regular expression validates the attribute. for (let i = 0, len = regExp.length; i < len; i++) { - if (regExp[i].test(attrName)) { + if (attrName.match(regExp[i])) { return true } } diff --git a/js/tests/karma.conf.js b/js/tests/karma.conf.js index cd4946525..38c7003bb 100644 --- a/js/tests/karma.conf.js +++ b/js/tests/karma.conf.js @@ -1,7 +1,5 @@ /* eslint-env node */ -'use strict' - const path = require('path') const ip = require('ip') const { babel } = require('@rollup/plugin-babel') @@ -14,11 +12,10 @@ const { browsersKeys } = require('./browsers') -const ENV = process.env -const BROWSERSTACK = Boolean(ENV.BROWSERSTACK) -const DEBUG = Boolean(ENV.DEBUG) -const JQUERY_TEST = Boolean(ENV.JQUERY) - +const { env } = process +const browserStack = env.BROWSER === 'true' +const debug = env.DEBUG === 'true' +const jQueryTest = env.JQUERY === 'true' const frameworks = [ 'jasmine' ] @@ -33,16 +30,16 @@ const reporters = ['dots'] const detectBrowsers = { usePhantomJS: false, postDetection(availableBrowser) { - if (ENV.CI === true || availableBrowser.includes('Chrome')) { - return DEBUG ? ['Chrome'] : ['ChromeHeadless'] + if (env.CI === true || availableBrowser.includes('Chrome')) { + return debug ? ['Chrome'] : ['ChromeHeadless'] } if (availableBrowser.includes('Chromium')) { - return DEBUG ? ['Chromium'] : ['ChromiumHeadless'] + return debug ? ['Chromium'] : ['ChromiumHeadless'] } if (availableBrowser.includes('Firefox')) { - return DEBUG ? ['Firefox'] : ['FirefoxHeadless'] + return debug ? ['Firefox'] : ['FirefoxHeadless'] } throw new Error('Please install Chrome, Chromium or Firefox') @@ -70,7 +67,7 @@ const conf = { 'node_modules/hammer-simulator/index.js', { pattern: 'js/tests/unit/**/!(jquery).spec.js', - watched: !BROWSERSTACK + watched: !browserStack } ], preprocessors: { @@ -104,11 +101,11 @@ const conf = { } } -if (BROWSERSTACK) { +if (browserStack) { conf.hostname = ip.address() conf.browserStack = { - username: ENV.BROWSER_STACK_USERNAME, - accessKey: ENV.BROWSER_STACK_ACCESS_KEY, + username: env.BROWSER_STACK_USERNAME, + accessKey: env.BROWSER_STACK_ACCESS_KEY, build: `bootstrap-${new Date().toISOString()}`, project: 'Bootstrap', retryLimit: 2 @@ -117,7 +114,7 @@ if (BROWSERSTACK) { conf.customLaunchers = browsers conf.browsers = browsersKeys reporters.push('BrowserStack', 'kjhtml') -} else if (JQUERY_TEST) { +} else if (jQueryTest) { frameworks.push('detectBrowsers') plugins.push( 'karma-chrome-launcher', @@ -158,7 +155,7 @@ if (BROWSERSTACK) { } } - if (DEBUG) { + if (debug) { conf.hostname = ip.address() plugins.push('karma-jasmine-html-reporter') reporters.push('kjhtml') @@ -172,6 +169,7 @@ conf.plugins = plugins conf.reporters = reporters module.exports = karmaConfig => { - conf.logLevel = karmaConfig.LOG_ERROR + // possible values: karmaConfig.LOG_DISABLE || karmaConfig.LOG_ERROR || karmaConfig.LOG_WARN || karmaConfig.LOG_INFO || karmaConfig.LOG_DEBUG + conf.logLevel = karmaConfig.LOG_ERROR || karmaConfig.LOG_WARN karmaConfig.set(conf) } diff --git a/js/tests/unit/carousel.spec.js b/js/tests/unit/carousel.spec.js index 787a276de..0286762fa 100644 --- a/js/tests/unit/carousel.spec.js +++ b/js/tests/unit/carousel.spec.js @@ -1136,9 +1136,11 @@ describe('Carousel', () => { jQueryMock.fn.carousel = Carousel.jQueryInterface jQueryMock.elements = [div] - expect(() => { + try { jQueryMock.fn.carousel.call(jQueryMock, action) - }).toThrowError(TypeError, `No method named "${action}"`) + } catch (error) { + expect(error.message).toEqual(`No method named "${action}"`) + } }) }) diff --git a/js/tests/unit/collapse.spec.js b/js/tests/unit/collapse.spec.js index ff493cf51..d53ab5964 100644 --- a/js/tests/unit/collapse.spec.js +++ b/js/tests/unit/collapse.spec.js @@ -374,29 +374,6 @@ describe('Collapse', () => { }) describe('data-api', () => { - it('should prevent url change if click on nested elements', done => { - fixtureEl.innerHTML = [ - '', - '
' - ].join('') - - const triggerEl = fixtureEl.querySelector('a') - const nestedTriggerEl = fixtureEl.querySelector('#nested') - - spyOn(Event.prototype, 'preventDefault').and.callThrough() - - triggerEl.addEventListener('click', event => { - expect(event.target.isEqualNode(nestedTriggerEl)).toEqual(true) - expect(event.delegateTarget.isEqualNode(triggerEl)).toEqual(true) - expect(Event.prototype.preventDefault).toHaveBeenCalled() - done() - }) - - nestedTriggerEl.click() - }) - it('should show multiple collapsed elements', done => { fixtureEl.innerHTML = [ '', @@ -819,9 +796,11 @@ describe('Collapse', () => { jQueryMock.fn.collapse = Collapse.jQueryInterface jQueryMock.elements = [div] - expect(() => { + try { jQueryMock.fn.collapse.call(jQueryMock, action) - }).toThrowError(TypeError, `No method named "${action}"`) + } catch (error) { + expect(error.message).toEqual(`No method named "${action}"`) + } }) }) diff --git a/js/tests/unit/dropdown.spec.js b/js/tests/unit/dropdown.spec.js index cc4139603..d2171f369 100644 --- a/js/tests/unit/dropdown.spec.js +++ b/js/tests/unit/dropdown.spec.js @@ -367,58 +367,6 @@ describe('Dropdown', () => { dropdown.toggle() }) - it('should toggle a dropdown with a valid virtual element reference', done => { - fixtureEl.innerHTML = [ - '' - ].join('') - - const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const virtualElement = { - getBoundingClientRect() { - return { - width: 0, - height: 0, - top: 0, - right: 0, - bottom: 0, - left: 0 - } - } - } - - expect(() => new Dropdown(btnDropdown, { - reference: {} - })).toThrowError(TypeError, 'DROPDOWN: Option "reference" provided type "object" without a required "getBoundingClientRect" method.') - - expect(() => new Dropdown(btnDropdown, { - reference: { - getBoundingClientRect: 'not-a-function' - } - })).toThrowError(TypeError, 'DROPDOWN: Option "reference" provided type "object" without a required "getBoundingClientRect" method.') - - // use onFirstUpdate as Poppers internal update is executed async - const dropdown = new Dropdown(btnDropdown, { - reference: virtualElement, - popperConfig: { - onFirstUpdate() { - expect(virtualElement.getBoundingClientRect).toHaveBeenCalled() - expect(btnDropdown.classList.contains('show')).toEqual(true) - expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true') - done() - } - } - }) - - spyOn(virtualElement, 'getBoundingClientRect').and.callThrough() - - dropdown.toggle() - }) - it('should not toggle a dropdown if the element is disabled', done => { fixtureEl.innerHTML = [ '
{{< placeholder width="140" height="140" background="#777" color="#777" class="rounded-circle" >}}

عنوان

هو أخر إتفاقية الدولارات الأوروبيّون, ثانية طوكيو و به،, ونتج أعمال مما أم. عن الا يونيو أفريقيا, السيطرة التقليدي ومن ٣٠. هو الغالي الإتفاقية ويكيبيديا، مكن, و الى هُزم اعتداء وايرلندا. وقبل بمباركة الأوروبيّون عن فقد, بتحدّي والفلبين ما كلا.

-

عرض التفاصيل

+

عرض التفاصيل

{{< placeholder width="140" height="140" background="#777" color="#777" class="rounded-circle" >}}

عنوان

غير عن الثقيل وسمّيت الأوضاع, لم تاريخ بالحرب للسيطرة حين, دار اللا تطوير تم. الى بشرية اليابان في. أما الشهيرة الإثنان وايرلندا ما, لإعلان واشتدّت و مدن. في غير والحزب للسيطرة الإكتفاء. ثانية الكونجرس الا من, جُل ٣٠ وبداية الشرقية.

-

عرض التفاصيل

+

عرض التفاصيل

@@ -162,6 +162,6 @@ extra_css: diff --git a/site/content/docs/5.0/examples/carousel/index.html b/site/content/docs/5.0/examples/carousel/index.html index 2c0bc5129..b230392b0 100644 --- a/site/content/docs/5.0/examples/carousel/index.html +++ b/site/content/docs/5.0/examples/carousel/index.html @@ -14,8 +14,8 @@ extra_css: @@ -58,7 +58,7 @@ extra_css: @@ -68,7 +68,7 @@ extra_css: @@ -96,19 +96,19 @@ extra_css: {{< placeholder width="140" height="140" background="#777" color="#777" class="rounded-circle" >}}

Heading

Some representative placeholder content for the three columns of text below the carousel. This is the first column.

-

View details »

+

View details »

{{< placeholder width="140" height="140" background="#777" color="#777" class="rounded-circle" >}}

Heading

Another exciting bit of representative placeholder content. This time, we've moved on to the second column.

-

View details »

+

View details »

{{< placeholder width="140" height="140" background="#777" color="#777" class="rounded-circle" >}}

Heading

And lastly this, the third column of representative placeholder content.

-

View details »

+

View details »

@@ -161,6 +161,6 @@ extra_css: diff --git a/site/content/docs/5.0/examples/navbar-bottom/index.html b/site/content/docs/5.0/examples/navbar-bottom/index.html index aee772e20..8f4e2635c 100644 --- a/site/content/docs/5.0/examples/navbar-bottom/index.html +++ b/site/content/docs/5.0/examples/navbar-bottom/index.html @@ -18,8 +18,8 @@ title: Bottom navbar example