diff --git a/.cspell.json b/.cspell.json index e477ef8..484af2a 100644 --- a/.cspell.json +++ b/.cspell.json @@ -40,6 +40,7 @@ "dropright", "dropstart", "dropup", + "dgst", "errorf", "favicon", "favicons", diff --git a/.eslintrc.json b/.eslintrc.json index 055acc7..2efe773 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -51,6 +51,7 @@ "SwitchCase": 1 } ], + "logical-assignment-operators": "off", "max-params": [ "warn", 5 @@ -75,6 +76,7 @@ "error", "after" ], + "prefer-object-has-own": "off", "prefer-template": "error", "semi": [ "error", @@ -108,7 +110,7 @@ "node": true }, "parserOptions": { - "sourceType": "script" + "sourceType": "module" }, "rules": { "no-console": "off", diff --git a/.github/workflows/browserstack.yml b/.github/workflows/browserstack.yml index e545d62..a53c233 100644 --- a/.github/workflows/browserstack.yml +++ b/.github/workflows/browserstack.yml @@ -9,7 +9,7 @@ on: env: FORCE_COLOR: 2 - NODE: 18 + NODE: 20 permissions: contents: read @@ -22,12 +22,12 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false - name: Set up Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "${{ env.NODE }}" cache: npm diff --git a/.github/workflows/bundlewatch.yml b/.github/workflows/bundlewatch.yml index c02a37e..99ba060 100644 --- a/.github/workflows/bundlewatch.yml +++ b/.github/workflows/bundlewatch.yml @@ -9,7 +9,7 @@ on: env: FORCE_COLOR: 2 - NODE: 18 + NODE: 20 permissions: contents: read @@ -20,12 +20,12 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false - name: Set up Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "${{ env.NODE }}" cache: npm diff --git a/.github/workflows/calibreapp-image-actions.yml b/.github/workflows/calibreapp-image-actions.yml index 21df1f6..08987b3 100644 --- a/.github/workflows/calibreapp-image-actions.yml +++ b/.github/workflows/calibreapp-image-actions.yml @@ -8,15 +8,21 @@ on: - '**.png' - '**.webp' +permissions: + contents: read + jobs: build: # Only run on Pull Requests within the same repository, and not from forks. if: github.event.pull_request.head.repo.full_name == github.repository name: calibreapp/image-actions runs-on: ubuntu-latest + permissions: + # allow calibreapp/image-actions to update PRs + pull-requests: write steps: - - name: Checkout Repo - uses: actions/checkout@v3 + - name: Clone repository + uses: actions/checkout@v4 with: persist-credentials: false diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b1780ee..dd7f6e7 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -24,21 +24,21 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: config-file: ./.github/codeql/codeql-config.yml languages: "javascript" queries: +security-and-quality - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 with: category: "/language:javascript" diff --git a/.github/workflows/cspell.yml b/.github/workflows/cspell.yml index 11788e3..c671fde 100644 --- a/.github/workflows/cspell.yml +++ b/.github/workflows/cspell.yml @@ -23,12 +23,12 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false - name: Run cspell - uses: streetsidesoftware/cspell-action@v2 + uses: streetsidesoftware/cspell-action@v5 with: config: ".cspell.json" files: "**/*.md" diff --git a/.github/workflows/css.yml b/.github/workflows/css.yml index 66112a9..52e93e2 100644 --- a/.github/workflows/css.yml +++ b/.github/workflows/css.yml @@ -9,7 +9,7 @@ on: env: FORCE_COLOR: 2 - NODE: 18 + NODE: 20 permissions: contents: read @@ -20,12 +20,12 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false - name: Set up Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "${{ env.NODE }}" cache: npm diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 2a684f6..0822205 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -9,7 +9,7 @@ on: env: FORCE_COLOR: 2 - NODE: 18 + NODE: 20 permissions: contents: read @@ -20,12 +20,12 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false - name: Set up Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "${{ env.NODE }}" cache: npm diff --git a/.github/workflows/js.yml b/.github/workflows/js.yml index 805b1b7..1b672aa 100644 --- a/.github/workflows/js.yml +++ b/.github/workflows/js.yml @@ -9,7 +9,7 @@ on: env: FORCE_COLOR: 2 - NODE: 18 + NODE: 20 permissions: contents: read @@ -25,12 +25,12 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false - name: Set up Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ env.NODE }} cache: npm @@ -46,6 +46,7 @@ jobs: - name: Run Coveralls uses: coverallsapp/github-action@v2 + if: ${{ !github.event.repository.fork }} with: github-token: "${{ secrets.GITHUB_TOKEN }}" path-to-lcov: "./js/coverage/lcov.info" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index fd62b41..213f9ec 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -9,7 +9,7 @@ on: env: FORCE_COLOR: 2 - NODE: 18 + NODE: 20 permissions: contents: read @@ -20,12 +20,12 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false - name: Set up Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "${{ env.NODE }}" cache: npm diff --git a/.github/workflows/node-sass.yml b/.github/workflows/node-sass.yml index c558e44..493cc35 100644 --- a/.github/workflows/node-sass.yml +++ b/.github/workflows/node-sass.yml @@ -9,7 +9,7 @@ on: env: FORCE_COLOR: 2 - NODE: 18 + NODE: 20 permissions: contents: read @@ -20,12 +20,12 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false - name: Set up Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "${{ env.NODE }}" diff --git a/.github/workflows/release-notes.yml b/.github/workflows/release-notes.yml index f620dd3..813956a 100644 --- a/.github/workflows/release-notes.yml +++ b/.github/workflows/release-notes.yml @@ -18,6 +18,6 @@ jobs: runs-on: ubuntu-latest if: github.repository == 'twbs/bootstrap' steps: - - uses: release-drafter/release-drafter@v5 + - uses: release-drafter/release-drafter@v6 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/LICENSE b/LICENSE index 6633b55..2a703f5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2011-2023 The Bootstrap Authors +Copyright (c) 2011-2024 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 c08d4cb..cb51a56 100644 --- a/README.md +++ b/README.md @@ -46,11 +46,11 @@ Our default branch is for development of our Bootstrap 5 release. Head to the [` Several quick start options are available: -- [Download the latest release](https://github.com/twbs/bootstrap/archive/v5.3.1.zip) +- [Download the latest release](https://github.com/twbs/bootstrap/archive/v5.3.3.zip) - Clone the repo: `git clone https://github.com/twbs/bootstrap.git` -- Install with [npm](https://www.npmjs.com/): `npm install bootstrap@v5.3.1` -- Install with [yarn](https://yarnpkg.com/): `yarn add bootstrap@v5.3.1` -- Install with [Composer](https://getcomposer.org/): `composer require twbs/bootstrap:5.3.1` +- Install with [npm](https://www.npmjs.com/): `npm install bootstrap@v5.3.3` +- Install with [yarn](https://yarnpkg.com/): `yarn add bootstrap@v5.3.3` +- Install with [Composer](https://getcomposer.org/): `composer require twbs/bootstrap:5.3.3` - Install with [NuGet](https://www.nuget.org/): CSS: `Install-Package bootstrap` Sass: `Install-Package bootstrap.sass` Read the [Getting started page](https://getbootstrap.com/docs/5.3/getting-started/introduction/) for information on the framework contents, templates, examples, and more. @@ -69,7 +69,6 @@ Read the [Getting started page](https://getbootstrap.com/docs/5.3/getting-starte [](https://github.com/twbs/bootstrap/blob/main/dist/css/bootstrap.min.css) [](https://github.com/twbs/bootstrap/blob/main/dist/js/bootstrap.min.js) [](https://github.com/twbs/bootstrap/blob/main/dist/js/bootstrap.min.js) -[](https://www.browserstack.com/automate/public-build/SkxZcStBeExEdVJqQ2hWYnlWckpkNmNEY213SFp6WHFETWk2bGFuY3pCbz0tLXhqbHJsVlZhQnRBdEpod3NLSDMzaHc9PQ==--3d0b75245708616eb93113221beece33e680b229) [](#backers) [](#sponsors) @@ -177,7 +176,8 @@ Get updates on Bootstrap's development and chat with the project maintainers and - Follow [@getbootstrap on Twitter](https://twitter.com/getbootstrap). - Read and subscribe to [The Official Bootstrap Blog](https://blog.getbootstrap.com/). -- Ask and explore [our GitHub Discussions](https://github.com/twbs/bootstrap/discussions). +- Ask questions and explore [our GitHub Discussions](https://github.com/twbs/bootstrap/discussions). +- Discuss, ask questions, and more on [the community Discord](https://discord.gg/bZUvakRU3M) or [Bootstrap subreddit](https://reddit.com/r/bootstrap). - Chat with fellow Bootstrappers in IRC. On the `irc.libera.chat` server, in the `#bootstrap` channel. - Implementation help may be found at Stack Overflow (tagged [`bootstrap-5`](https://stackoverflow.com/questions/tagged/bootstrap-5)). - Developers should use the keyword `bootstrap` on packages which modify or add to the functionality of Bootstrap when distributing through [npm](https://www.npmjs.com/browse/keyword/bootstrap) or similar delivery mechanisms for maximum discoverability. @@ -243,4 +243,4 @@ Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com ## Copyright and license -Code and documentation copyright 2011–2023 the [Bootstrap Authors](https://github.com/twbs/bootstrap/graphs/contributors). 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–2024 the [Bootstrap Authors](https://github.com/twbs/bootstrap/graphs/contributors). 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/banner.js b/build/banner.mjs similarity index 50% rename from build/banner.js rename to build/banner.mjs index a022f1c..3fea93c 100644 --- a/build/banner.js +++ b/build/banner.mjs @@ -1,6 +1,11 @@ -'use strict' +import fs from 'node:fs/promises' +import path from 'node:path' +import { fileURLToPath } from 'node:url' -const pkg = require('../package.json') +const __dirname = path.dirname(fileURLToPath(import.meta.url)) + +const pkgJson = path.join(__dirname, '../package.json') +const pkg = JSON.parse(await fs.readFile(pkgJson, 'utf8')) const year = new Date().getFullYear() @@ -12,4 +17,4 @@ function getBanner(pluginFilename) { */` } -module.exports = getBanner +export default getBanner diff --git a/build/build-plugins.js b/build/build-plugins.mjs similarity index 86% rename from build/build-plugins.js rename to build/build-plugins.mjs index b2833a3..252b4b4 100644 --- a/build/build-plugins.js +++ b/build/build-plugins.mjs @@ -2,17 +2,19 @@ /*! * Script to build our plugins to use them separately. - * Copyright 2020-2023 The Bootstrap Authors + * Copyright 2020-2024 The Bootstrap Authors * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */ -'use strict' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { babel } from '@rollup/plugin-babel' +import globby from 'globby' +import { rollup } from 'rollup' +import banner from './banner.mjs' -const path = require('node:path') -const rollup = require('rollup') -const globby = require('globby') -const { babel } = require('@rollup/plugin-babel') -const banner = require('./banner.js') +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(fileURLToPath(import.meta.url)) const sourcePath = path.resolve(__dirname, '../js/src/').replace(/\\/g, '/') const jsFiles = globby.sync(`${sourcePath}/**/*.js`) @@ -37,7 +39,7 @@ for (const file of jsFiles) { const build = async plugin => { const globals = {} - const bundle = await rollup.rollup({ + const bundle = await rollup({ input: plugin.src, plugins: [ babel({ diff --git a/build/change-version.js b/build/change-version.mjs similarity index 73% rename from build/change-version.js rename to build/change-version.mjs index 9685df5..30cfcc4 100644 --- a/build/change-version.js +++ b/build/change-version.mjs @@ -2,27 +2,26 @@ /*! * Script to update version number references in the project. - * Copyright 2017-2023 The Bootstrap Authors + * Copyright 2017-2024 The Bootstrap Authors * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */ -'use strict' - -const fs = require('node:fs').promises -const path = require('node:path') -const globby = require('globby') +import { execFile } from 'node:child_process' +import fs from 'node:fs/promises' +import process from 'node:process' const VERBOSE = process.argv.includes('--verbose') const DRY_RUN = process.argv.includes('--dry') || process.argv.includes('--dry-run') -// These are the filetypes we only care about replacing the version -const GLOB = [ - '**/*.{css,html,js,json,md,scss,txt,yml}' +// These are the files we only care about replacing the version +const FILES = [ + 'README.md', + 'hugo.yml', + 'js/src/base-component.js', + 'package.js', + 'scss/mixins/_banner.scss', + 'site/data/docs-versions.yml' ] -const GLOBBY_OPTIONS = { - cwd: path.join(__dirname, '..'), - gitignore: true -} // Blame TC39... https://github.com/benjamingr/RegExp.escape/issues/37 function regExpQuote(string) { @@ -53,7 +52,7 @@ async function replaceRecursively(file, oldVersion, newVersion) { } if (VERBOSE) { - console.log(`FILE: ${file}`) + console.log(`Found ${oldVersion} in ${file}`) } if (DRY_RUN) { @@ -63,6 +62,19 @@ async function replaceRecursively(file, oldVersion, newVersion) { await fs.writeFile(file, newString, 'utf8') } +function bumpNpmVersion(newVersion) { + if (DRY_RUN) { + return + } + + execFile('npm', ['version', newVersion, '--no-git-tag'], { shell: true }, error => { + if (error) { + console.error(error) + process.exit(1) + } + }) +} + function showUsage(args) { console.error('USAGE: change-version old_version new_version [--verbose] [--dry[-run]]') console.error('Got arguments:', args) @@ -86,11 +98,11 @@ async function main(args) { showUsage(args) } - try { - const files = await globby(GLOB, GLOBBY_OPTIONS) + bumpNpmVersion(newVersion) + try { await Promise.all( - files.map(file => replaceRecursively(file, oldVersion, newVersion)) + FILES.map(file => replaceRecursively(file, oldVersion, newVersion)) ) } catch (error) { console.error(error) diff --git a/build/generate-sri.js b/build/generate-sri.mjs similarity index 75% rename from build/generate-sri.js rename to build/generate-sri.mjs index 2e22924..384e8f4 100644 --- a/build/generate-sri.js +++ b/build/generate-sri.mjs @@ -5,16 +5,17 @@ * Remember to use the same vendor files as the CDN ones, * otherwise the hashes won't match! * - * Copyright 2017-2023 The Bootstrap Authors + * Copyright 2017-2024 The Bootstrap Authors * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */ -'use strict' +import crypto from 'node:crypto' +import fs from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import sh from 'shelljs' -const crypto = require('node:crypto') -const fs = require('node:fs') -const path = require('node:path') -const sh = require('shelljs') +const __dirname = path.dirname(fileURLToPath(import.meta.url)) sh.config.fatal = true @@ -52,9 +53,9 @@ for (const { file, configPropertyName } of files) { throw error } - const algo = 'sha384' - const hash = crypto.createHash(algo).update(data, 'utf8').digest('base64') - const integrity = `${algo}-${hash}` + const algorithm = 'sha384' + const hash = crypto.createHash(algorithm).update(data, 'utf8').digest('base64') + const integrity = `${algorithm}-${hash}` console.log(`${configPropertyName}: ${integrity}`) diff --git a/build/postcss.config.js b/build/postcss.config.mjs similarity index 86% rename from build/postcss.config.js rename to build/postcss.config.mjs index 7f8186d..7717cfc 100644 --- a/build/postcss.config.js +++ b/build/postcss.config.mjs @@ -1,12 +1,10 @@ -'use strict' - const mapConfig = { inline: false, annotation: true, sourcesContent: true } -module.exports = context => { +export default context => { return { map: context.file.dirname.includes('examples') ? false : mapConfig, plugins: { diff --git a/build/rollup.config.js b/build/rollup.config.mjs similarity index 63% rename from build/rollup.config.js rename to build/rollup.config.mjs index f01918e..dd6c7d1 100644 --- a/build/rollup.config.js +++ b/build/rollup.config.mjs @@ -1,15 +1,17 @@ -'use strict' +import path from 'node:path' +import process from 'node:process' +import { fileURLToPath } from 'node:url' +import { babel } from '@rollup/plugin-babel' +import { nodeResolve } from '@rollup/plugin-node-resolve' +import replace from '@rollup/plugin-replace' +import banner from './banner.mjs' -const path = require('node:path') -const { babel } = require('@rollup/plugin-babel') -const { nodeResolve } = require('@rollup/plugin-node-resolve') -const replace = require('@rollup/plugin-replace') -const banner = require('./banner.js') +const __dirname = path.dirname(fileURLToPath(import.meta.url)) const BUNDLE = process.env.BUNDLE === 'true' const ESM = process.env.ESM === 'true' -let fileDestination = `bootstrap${ESM ? '.esm' : ''}` +let destinationFile = `bootstrap${ESM ? '.esm' : ''}` const external = ['@popperjs/core'] const plugins = [ babel({ @@ -24,7 +26,7 @@ const globals = { } if (BUNDLE) { - fileDestination += '.bundle' + destinationFile += '.bundle' // Remove last entry in external array to bundle Popper external.pop() delete globals['@popperjs/core'] @@ -41,7 +43,7 @@ const rollupConfig = { input: path.resolve(__dirname, `../js/index.${ESM ? 'esm' : 'umd'}.js`), output: { banner: banner(), - file: path.resolve(__dirname, `../dist/js/${fileDestination}.js`), + file: path.resolve(__dirname, `../dist/js/${destinationFile}.js`), format: ESM ? 'esm' : 'umd', globals, generatedCode: 'es2015' @@ -54,4 +56,4 @@ if (!ESM) { rollupConfig.output.name = 'bootstrap' } -module.exports = rollupConfig +export default rollupConfig diff --git a/build/vnu-jar.js b/build/vnu-jar.mjs similarity index 92% rename from build/vnu-jar.js rename to build/vnu-jar.mjs index 22956cb..18a35bd 100644 --- a/build/vnu-jar.js +++ b/build/vnu-jar.mjs @@ -2,14 +2,12 @@ /*! * Script to run vnu-jar if Java is available. - * Copyright 2017-2023 The Bootstrap Authors + * Copyright 2017-2024 The Bootstrap Authors * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */ -'use strict' - -const { execFile, spawn } = require('node:child_process') -const vnu = require('vnu-jar') +import { execFile, spawn } from 'node:child_process' +import vnu from 'vnu-jar' execFile('java', ['-version'], (error, stdout, stderr) => { if (error) { diff --git a/build/zip-examples.js b/build/zip-examples.mjs similarity index 87% rename from build/zip-examples.js rename to build/zip-examples.mjs index 7378c33..e5e39be 100644 --- a/build/zip-examples.js +++ b/build/zip-examples.mjs @@ -3,16 +3,19 @@ /*! * Script to create the built examples zip archive; * requires the `zip` command to be present! - * Copyright 2020-2023 The Bootstrap Authors + * Copyright 2020-2024 The Bootstrap Authors * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */ -'use strict' +import fs from 'node:fs/promises' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import sh from 'shelljs' -const path = require('node:path') -const sh = require('shelljs') +const __dirname = path.dirname(fileURLToPath(import.meta.url)) -const pkg = require('../package.json') +const pkgJson = path.join(__dirname, '../package.json') +const pkg = JSON.parse(await fs.readFile(pkgJson, 'utf8')) const versionShort = pkg.config.version_short const distFolder = `bootstrap-${pkg.version}-examples` diff --git a/hugo.yml b/hugo.yml index 4d71409..17f8b7b 100644 --- a/hugo.yml +++ b/hugo.yml @@ -54,8 +54,8 @@ params: description: "Powerful, extensible, and feature-packed frontend toolkit. Build and customize with Sass, utilize prebuilt grid system and components, and bring projects to life with powerful JavaScript plugins." authors: "Mark Otto, Jacob Thornton, and Bootstrap contributors" - current_version: "5.3.1" - current_ruby_version: "5.3.1" + current_version: "5.3.3" + current_ruby_version: "5.3.3" docs_version: "5.3" rfs_version: "v10.0.0" github_org: "https://github.com/twbs" @@ -68,20 +68,20 @@ params: swag: "https://cottonbureau.com/people/bootstrap" download: - source: "https://github.com/twbs/bootstrap/archive/v5.3.1.zip" - dist: "https://github.com/twbs/bootstrap/releases/download/v5.3.1/bootstrap-5.3.1-dist.zip" - dist_examples: "https://github.com/twbs/bootstrap/releases/download/v5.3.1/bootstrap-5.3.1-examples.zip" + source: "https://github.com/twbs/bootstrap/archive/v5.3.3.zip" + dist: "https://github.com/twbs/bootstrap/releases/download/v5.3.3/bootstrap-5.3.3-dist.zip" + dist_examples: "https://github.com/twbs/bootstrap/releases/download/v5.3.3/bootstrap-5.3.3-examples.zip" cdn: # See https://www.srihash.org for info on how to generate the hashes - css: "https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" - css_hash: "sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" - css_rtl: "https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.rtl.min.css" - css_rtl_hash: "sha384-PRrgQVJ8NNHGieOA1grGdCTIt4h21CzJs6SnWH4YMQ6G5F5+IEzOHz67L4SQaF0o" - js: "https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.min.js" - js_hash: "sha384-Rx+T1VzGupg4BHQYs2gCW9It+akI2MM/mndMCy36UVfodzcJcF0GGLxZIzObiEfa" - js_bundle: "https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js" - js_bundle_hash: "sha384-HwwvtgBNo3bZJJLYd8oVXjrBZt8cqVSpeBNS5n7C8IVInixGAoxmnlMuBnhbgrkm" + css: "https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" + css_hash: "sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" + css_rtl: "https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.rtl.min.css" + css_rtl_hash: "sha384-dpuaG1suU0eT09tx5plTaGMLBsfDLzUCCUXOY2j/LSvXYuG6Bqs43ALlhIqAJVRb" + js: "https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js" + js_hash: "sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" + js_bundle: "https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" + js_bundle_hash: "sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" popper: "https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" popper_hash: "sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r" popper_esm: "https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/esm/popper.min.js" diff --git a/js/src/base-component.js b/js/src/base-component.js index 19a09ad..82bf770 100644 --- a/js/src/base-component.js +++ b/js/src/base-component.js @@ -14,7 +14,7 @@ import { executeAfterTransition, getElement } from './util/index.js' * Constants */ -const VERSION = '5.3.1' +const VERSION = '5.3.3' /** * Class definition diff --git a/js/src/dom/selector-engine.js b/js/src/dom/selector-engine.js index 3cecf6f..a4d81f3 100644 --- a/js/src/dom/selector-engine.js +++ b/js/src/dom/selector-engine.js @@ -29,7 +29,7 @@ const getSelector = element => { selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null } - return parseSelector(selector) + return selector ? selector.split(',').map(sel => parseSelector(sel)).join(',') : null } const SelectorEngine = { diff --git a/js/src/modal.js b/js/src/modal.js index b44cbb9..dd61649 100644 --- a/js/src/modal.js +++ b/js/src/modal.js @@ -11,7 +11,9 @@ import SelectorEngine from './dom/selector-engine.js' import Backdrop from './util/backdrop.js' import { enableDismissTrigger } from './util/component-functions.js' import FocusTrap from './util/focustrap.js' -import { defineJQueryPlugin, isRTL, isVisible, reflow } from './util/index.js' +import { + defineJQueryPlugin, isRTL, isVisible, reflow +} from './util/index.js' import ScrollBarHelper from './util/scrollbar.js' /** diff --git a/js/src/scrollspy.js b/js/src/scrollspy.js index 69de715..368092d 100644 --- a/js/src/scrollspy.js +++ b/js/src/scrollspy.js @@ -8,7 +8,9 @@ import BaseComponent from './base-component.js' import EventHandler from './dom/event-handler.js' import SelectorEngine from './dom/selector-engine.js' -import { defineJQueryPlugin, getElement, isDisabled, isVisible } from './util/index.js' +import { + defineJQueryPlugin, getElement, isDisabled, isVisible +} from './util/index.js' /** * Constants diff --git a/js/src/tab.js b/js/src/tab.js index 5598e15..dfaef0f 100644 --- a/js/src/tab.js +++ b/js/src/tab.js @@ -40,7 +40,7 @@ const CLASS_DROPDOWN = 'dropdown' const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle' const SELECTOR_DROPDOWN_MENU = '.dropdown-menu' -const NOT_SELECTOR_DROPDOWN_TOGGLE = ':not(.dropdown-toggle)' +const NOT_SELECTOR_DROPDOWN_TOGGLE = `:not(${SELECTOR_DROPDOWN_TOGGLE})` const SELECTOR_TAB_PANEL = '.list-group, .nav, [role="tablist"]' const SELECTOR_OUTER = '.nav-item, .list-group-item' diff --git a/js/src/tooltip.js b/js/src/tooltip.js index 1252811..bcdc18f 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -9,7 +9,9 @@ import * as Popper from '@popperjs/core' import BaseComponent from './base-component.js' import EventHandler from './dom/event-handler.js' import Manipulator from './dom/manipulator.js' -import { defineJQueryPlugin, execute, findShadowRoot, getElement, getUID, isRTL, noop } from './util/index.js' +import { + defineJQueryPlugin, execute, findShadowRoot, getElement, getUID, isRTL, noop +} from './util/index.js' import { DefaultAllowlist } from './util/sanitizer.js' import TemplateFactory from './util/template-factory.js' diff --git a/js/src/util/backdrop.js b/js/src/util/backdrop.js index 0d478e9..82b5490 100644 --- a/js/src/util/backdrop.js +++ b/js/src/util/backdrop.js @@ -7,7 +7,9 @@ import EventHandler from '../dom/event-handler.js' import Config from './config.js' -import { execute, executeAfterTransition, getElement, reflow } from './index.js' +import { + execute, executeAfterTransition, getElement, reflow +} from './index.js' /** * Constants diff --git a/js/src/util/sanitizer.js b/js/src/util/sanitizer.js index d2b0808..3d2883a 100644 --- a/js/src/util/sanitizer.js +++ b/js/src/util/sanitizer.js @@ -17,7 +17,10 @@ export const DefaultAllowlist = { br: [], col: [], code: [], + dd: [], div: [], + dl: [], + dt: [], em: [], hr: [], h1: [], diff --git a/js/tests/unit/carousel.spec.js b/js/tests/unit/carousel.spec.js index c468b5c..2960eb5 100644 --- a/js/tests/unit/carousel.spec.js +++ b/js/tests/unit/carousel.spec.js @@ -2,7 +2,9 @@ import Carousel from '../../src/carousel.js' import EventHandler from '../../src/dom/event-handler.js' import { isRTL, noop } from '../../src/util/index.js' import Swipe from '../../src/util/swipe.js' -import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture.js' +import { + clearFixture, createEvent, getFixture, jQueryMock +} from '../helpers/fixture.js' describe('Carousel', () => { const { Simulator, PointerEvent } = window diff --git a/js/tests/unit/dom/selector-engine.spec.js b/js/tests/unit/dom/selector-engine.spec.js index 8dd7b1f..95d9bf8 100644 --- a/js/tests/unit/dom/selector-engine.spec.js +++ b/js/tests/unit/dom/selector-engine.spec.js @@ -359,6 +359,30 @@ describe('SelectorEngine', () => { expect(SelectorEngine.getMultipleElementsFromSelector(testEl)).toEqual(Array.from(fixtureEl.querySelectorAll('.target'))) }) + it('should get elements if several ids are given', () => { + fixtureEl.innerHTML = [ + '
', + '', + '' + ].join('') + + const testEl = fixtureEl.querySelector('#test') + + expect(SelectorEngine.getMultipleElementsFromSelector(testEl)).toEqual(Array.from(fixtureEl.querySelectorAll('.target'))) + }) + + it('should get elements if several ids with special chars are given', () => { + fixtureEl.innerHTML = [ + '', + '', + '' + ].join('') + + const testEl = fixtureEl.querySelector('#test') + + expect(SelectorEngine.getMultipleElementsFromSelector(testEl)).toEqual(Array.from(fixtureEl.querySelectorAll('.target'))) + }) + it('should get elements in array, from href if no data-bs-target set', () => { fixtureEl.innerHTML = [ '', diff --git a/js/tests/unit/dropdown.spec.js b/js/tests/unit/dropdown.spec.js index 8447be6..1560055 100644 --- a/js/tests/unit/dropdown.spec.js +++ b/js/tests/unit/dropdown.spec.js @@ -1,7 +1,9 @@ import EventHandler from '../../src/dom/event-handler.js' import Dropdown from '../../src/dropdown.js' import { noop } from '../../src/util/index.js' -import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture.js' +import { + clearFixture, createEvent, getFixture, jQueryMock +} from '../helpers/fixture.js' describe('Dropdown', () => { let fixtureEl diff --git a/js/tests/unit/modal.spec.js b/js/tests/unit/modal.spec.js index 6434d8b..2aa0b76 100644 --- a/js/tests/unit/modal.spec.js +++ b/js/tests/unit/modal.spec.js @@ -1,7 +1,9 @@ import EventHandler from '../../src/dom/event-handler.js' import Modal from '../../src/modal.js' import ScrollBarHelper from '../../src/util/scrollbar.js' -import { clearBodyAndDocument, clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture.js' +import { + clearBodyAndDocument, clearFixture, createEvent, getFixture, jQueryMock +} from '../helpers/fixture.js' describe('Modal', () => { let fixtureEl @@ -989,6 +991,35 @@ describe('Modal', () => { trigger.click() }) }) + + it('should open modal, having special characters in its id', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + ' ' + ].join('') + + const modalEl = fixtureEl.querySelector('.modal') + const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') + + modalEl.addEventListener('shown.bs.modal', () => { + resolve() + }) + + trigger.click() + }) + }) + it('should not prevent default when a click occurred on data-bs-dismiss="modal" where tagName is DIFFERENT than or ', () => { return new Promise(resolve => { fixtureEl.innerHTML = [ diff --git a/js/tests/unit/offcanvas.spec.js b/js/tests/unit/offcanvas.spec.js index 03e7d9e..3b6c98c 100644 --- a/js/tests/unit/offcanvas.spec.js +++ b/js/tests/unit/offcanvas.spec.js @@ -2,7 +2,9 @@ import EventHandler from '../../src/dom/event-handler.js' import Offcanvas from '../../src/offcanvas.js' import { isVisible } from '../../src/util/index.js' import ScrollBarHelper from '../../src/util/scrollbar.js' -import { clearBodyAndDocument, clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture.js' +import { + clearBodyAndDocument, clearFixture, createEvent, getFixture, jQueryMock +} from '../helpers/fixture.js' describe('Offcanvas', () => { let fixtureEl diff --git a/js/tests/unit/scrollspy.spec.js b/js/tests/unit/scrollspy.spec.js index ecbd952..fc44471 100644 --- a/js/tests/unit/scrollspy.spec.js +++ b/js/tests/unit/scrollspy.spec.js @@ -1,6 +1,8 @@ import EventHandler from '../../src/dom/event-handler.js' import ScrollSpy from '../../src/scrollspy.js' -import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture.js' +import { + clearFixture, createEvent, getFixture, jQueryMock +} from '../helpers/fixture.js' describe('ScrollSpy', () => { let fixtureEl diff --git a/js/tests/unit/tab.spec.js b/js/tests/unit/tab.spec.js index 007addd..4fcf8ee 100644 --- a/js/tests/unit/tab.spec.js +++ b/js/tests/unit/tab.spec.js @@ -1,5 +1,7 @@ import Tab from '../../src/tab.js' -import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture.js' +import { + clearFixture, createEvent, getFixture, jQueryMock +} from '../helpers/fixture.js' describe('Tab', () => { let fixtureEl diff --git a/js/tests/unit/toast.spec.js b/js/tests/unit/toast.spec.js index cfc56c7..200fe3e 100644 --- a/js/tests/unit/toast.spec.js +++ b/js/tests/unit/toast.spec.js @@ -1,5 +1,7 @@ import Toast from '../../src/toast.js' -import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture.js' +import { + clearFixture, createEvent, getFixture, jQueryMock +} from '../helpers/fixture.js' describe('Toast', () => { let fixtureEl diff --git a/js/tests/unit/tooltip.spec.js b/js/tests/unit/tooltip.spec.js index 080432e..ceb8de4 100644 --- a/js/tests/unit/tooltip.spec.js +++ b/js/tests/unit/tooltip.spec.js @@ -1,7 +1,9 @@ import EventHandler from '../../src/dom/event-handler.js' import Tooltip from '../../src/tooltip.js' import { noop } from '../../src/util/index.js' -import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture.js' +import { + clearFixture, createEvent, getFixture, jQueryMock +} from '../helpers/fixture.js' describe('Tooltip', () => { let fixtureEl diff --git a/js/tests/visual/modal.html b/js/tests/visual/modal.html index 09d4233..efb5127 100644 --- a/js/tests/visual/modal.html +++ b/js/tests/visual/modal.html @@ -13,21 +13,25 @@ -