From 1f251ca399ec01c75d24293e49ac767938a547e2 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Tue, 11 Jun 2024 12:05:06 -0400 Subject: [PATCH 01/53] Tests: remove testswarm grunt task Closes gh-2263 --- build/tasks/testswarm.js | 115 ------------------------------------ tests/unit/position/core.js | 3 - 2 files changed, 118 deletions(-) delete mode 100644 build/tasks/testswarm.js diff --git a/build/tasks/testswarm.js b/build/tasks/testswarm.js deleted file mode 100644 index 8ab2b7643c..0000000000 --- a/build/tasks/testswarm.js +++ /dev/null @@ -1,115 +0,0 @@ -"use strict"; - -module.exports = function( grunt ) { - -var versions = { - "git": "git", - "3.x-git": "3.x-git", - "3.7": "3.7.0", - "3.6": "3.6.4", - "3.5": "3.5.1", - "3.4": "3.4.1", - "3.3": "3.3.1", - "3.2": "3.2.1", - "3.1": "3.1.1", - "3.0": "3.0.0", - "2.2": "2.2.4", - "2.1": "2.1.4", - "2.0": "2.0.3", - "1.12": "1.12.4", - "1.11": "1.11.3", - "1.10": "1.10.2", - "1.9": "1.9.1", - "1.8": "1.8.3" - }, - tests = { - "Accordion": "accordion/accordion.html", - "Autocomplete": "autocomplete/autocomplete.html", - "Button": "button/button.html", - "Checkboxradio": "checkboxradio/checkboxradio.html", - "Controlgroup": "controlgroup/controlgroup.html", - "Core": "core/core.html", - "Datepicker": "datepicker/datepicker.html", - "Dialog": "dialog/dialog.html", - "Draggable": "draggable/draggable.html", - "Droppable": "droppable/droppable.html", - "Effects": "effects/effects.html", - "Form Reset Mixin": "form-reset-mixin/form-reset-mixin.html", - "jQuery Patch": "jquery-patch/jquery-patch.html", - "Menu": "menu/menu.html", - "Position": "position/position.html", - "Progressbar": "progressbar/progressbar.html", - "Resizable": "resizable/resizable.html", - "Selectable": "selectable/selectable.html", - "Selectmenu": "selectmenu/selectmenu.html", - "Slider": "slider/slider.html", - "Sortable": "sortable/sortable.html", - "Spinner": "spinner/spinner.html", - "Tabs": "tabs/tabs.html", - "Tooltip": "tooltip/tooltip.html", - "Widget": "widget/widget.html" - }; - -function submit( commit, runs, configFile, browserSets, extra, done ) { - var testName, - testswarm = require( "testswarm" ), - config = grunt.file.readJSON( configFile ).jqueryui, - commitUrl = "https://github.com/jquery/jquery-ui/commit/" + commit; - - browserSets = browserSets || config.browserSets; - if ( browserSets[ 0 ] === "[" ) { - - // We got an array, parse it - browserSets = JSON.parse( browserSets ); - } - - if ( extra ) { - extra = " (" + extra + ")"; - } - - for ( testName in runs ) { - runs[ testName ] = config.testUrl + commit + "/tests/unit/" + runs[ testName ]; - } - - testswarm.createClient( { - url: config.swarmUrl - } ) - .addReporter( testswarm.reporters.cli ) - .auth( { - id: config.authUsername, - token: config.authToken - } ) - .addjob( { - name: "Commit " + commit.substr( 0, 10 ) + "" + extra, - runs: runs, - runMax: config.runMax, - browserSets: browserSets, - timeout: 1000 * 60 * 30 - }, function( error, passed ) { - if ( error ) { - grunt.log.error( error ); - } - done( passed ); - } ); -} - -grunt.registerTask( "testswarm", function( commit, configFile, browserSets ) { - var test, - latestTests = {}; - for ( test in tests ) { - latestTests[ test ] = tests[ test ]; - } - submit( commit, latestTests, configFile, browserSets, "", this.async() ); -} ); - -grunt.registerTask( "testswarm-multi-jquery", function( commit, configFile, minor, browserSets ) { - var allTests = {}; - versions[ minor ].split( " " ).forEach( function( version ) { - for ( var test in tests ) { - allTests[ test + "-" + version ] = tests[ test ] + "?jquery=" + version; - } - } ); - submit( commit, allTests, configFile, browserSets, "core " + minor, this.async() ); -} ); - -}; diff --git a/tests/unit/position/core.js b/tests/unit/position/core.js index 9483e716de..ae016f34c3 100644 --- a/tests/unit/position/core.js +++ b/tests/unit/position/core.js @@ -396,8 +396,6 @@ QUnit.test( "collision: fit, no collision", function( assert ) { }, "with offset" ); } ); -// Currently failing in IE8 due to the iframe used by TestSwarm -if ( !/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ) ) { QUnit.test( "collision: fit, collision", function( assert ) { assert.expect( 2 + ( scrollTopSupport() ? 1 : 0 ) ); @@ -428,7 +426,6 @@ QUnit.test( "collision: fit, collision", function( assert ) { win.scrollTop( 0 ).scrollLeft( 0 ); } } ); -} QUnit.test( "collision: flip, no collision", function( assert ) { assert.expect( 2 ); From 376f142b9de42241a20efa9c89644ff5425da174 Mon Sep 17 00:00:00 2001 From: Ralf Koller <1665422+rpkoller@users.noreply.github.com> Date: Fri, 14 Jun 2024 13:04:00 +0200 Subject: [PATCH 02/53] Dialog: Add aria-modal support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reflect the `modal` dialog option into the `aria-modal` attribute - when `modal` is `true`, set `aria-modal` to `"true"`. This helps some accessibility tools like VoiceOver with their rotor functionality as it reduces the number of elements presented. Fixes gh-2246 Closes gh-2257 Co-authored-by: Michał Gołębiowski-Owczarek --- tests/unit/dialog/core.js | 33 +++++++++++++++++++++++++++++++++ ui/widgets/dialog.js | 7 ++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/tests/unit/dialog/core.js b/tests/unit/dialog/core.js index d307504b80..c6bdec778c 100644 --- a/tests/unit/dialog/core.js +++ b/tests/unit/dialog/core.js @@ -84,6 +84,39 @@ QUnit.test( "ARIA", function( assert ) { element.remove(); } ); +QUnit.test( "aria-modal", function( assert ) { + assert.expect( 9 ); + + var element, wrapper; + + element = $( "
" ).dialog( { modal: true } ); + wrapper = element.dialog( "widget" ); + assert.equal( wrapper.attr( "aria-modal" ), "true", "modal option set to true, aria-modal attribute added" ); + element.dialog( "option", "modal", false ); + assert.equal( wrapper.attr( "aria-modal" ), undefined, "modal option set to false, aria-modal attribute not added" ); + element.dialog( "option", "modal", true ); + assert.equal( wrapper.attr( "aria-modal" ), "true", "modal option set to true, aria-modal attribute added" ); + element.remove(); + + element = $( "
" ).dialog( { modal: false } ); + wrapper = element.dialog( "widget" ); + assert.equal( wrapper.attr( "aria-modal" ), undefined, "modal option set to false, aria-modal attribute not added" ); + element.dialog( "option", "modal", true ); + assert.equal( wrapper.attr( "aria-modal" ), "true", "modal option set to true, aria-modal attribute added" ); + element.dialog( "option", "modal", false ); + assert.equal( wrapper.attr( "aria-modal" ), undefined, "modal option set to false, aria-modal attribute not added" ); + element.remove(); + + element = $( "
" ).dialog(); + wrapper = element.dialog( "widget" ); + assert.equal( wrapper.attr( "aria-modal" ), undefined, "modal option not set, aria-modal attribute not added" ); + element.dialog( "option", "modal", true ); + assert.equal( wrapper.attr( "aria-modal" ), "true", "modal option set to true, aria-modal attribute added" ); + element.dialog( "option", "modal", false ); + assert.equal( wrapper.attr( "aria-modal" ), undefined, "modal option set to false, aria-modal attribute not added" ); + element.remove(); +} ); + QUnit.test( "widget method", function( assert ) { assert.expect( 1 ); var dialog = $( "
" ).appendTo( "#qunit-fixture" ).dialog(); diff --git a/ui/widgets/dialog.js b/ui/widgets/dialog.js index 4ba9d11176..756ad1cb10 100644 --- a/ui/widgets/dialog.js +++ b/ui/widgets/dialog.js @@ -347,7 +347,8 @@ $.widget( "ui.dialog", { // Setting tabIndex makes the div focusable tabIndex: -1, - role: "dialog" + role: "dialog", + "aria-modal": this.options.modal ? "true" : null } ) .appendTo( this._appendTo() ); @@ -762,6 +763,10 @@ $.widget( "ui.dialog", { if ( key === "title" ) { this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) ); } + + if ( key === "modal" ) { + uiDialog.attr( "aria-modal", value ? "true" : null ); + } }, _size: function() { From 04b0fd5ceee439dfe4eaaeb7df403620a374a0f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski-Owczarek?= Date: Fri, 14 Jun 2024 18:53:54 +0200 Subject: [PATCH 03/53] Build: Update AUTHORS.txt --- AUTHORS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.txt b/AUTHORS.txt index 5fcf5d1e43..738af9c462 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -379,3 +379,4 @@ Timo Tijhof Timmy Willison divdeploy <166095818+divdeploy@users.noreply.github.com> mark van tilburg +Ralf Koller <1665422+rpkoller@users.noreply.github.com> From 2f1f1eadf3b62e72d9fefc90606ab58f85f8d5d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski-Owczarek?= Date: Fri, 14 Jun 2024 18:56:20 +0200 Subject: [PATCH 04/53] Release: Update download.jqueryui.com from 2.2.14 to 2.3.4 --- build/release.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/release.js b/build/release.js index d9ab580cb1..24ccb5b178 100644 --- a/build/release.js +++ b/build/release.js @@ -153,7 +153,7 @@ Release.define( { }; module.exports.dependencies = [ - "download.jqueryui.com@2.2.14", + "download.jqueryui.com@2.3.4", "node-packager@0.0.7", "shelljs@0.8.5" ]; From b76883ad3f84b2bcd9a6910c4b41b4c35a355fad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski-Owczarek?= Date: Fri, 14 Jun 2024 19:05:41 +0200 Subject: [PATCH 05/53] Release: Fix the release script --- build/release.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/release.js b/build/release.js index 24ccb5b178..6cf0fa78ba 100644 --- a/build/release.js +++ b/build/release.js @@ -59,8 +59,8 @@ function addManifest( packager ) { function buildCDNPackage( callback ) { console.log( "Building CDN package" ); var JqueryUi = require( "download.jqueryui.com/lib/jquery-ui" ); - var PackageWithoutThemes = require( "download.jqueryui.com/lib/package-1-13" ); - var PackageOfThemes = require( "download.jqueryui.com/lib/package-1-13-themes" ); + var PackageWithoutThemes = require( "download.jqueryui.com/lib/package" ); + var PackageOfThemes = require( "download.jqueryui.com/lib/package-themes" ); var Packager = require( "node-packager" ); // PackageOfThemes doesn't contain JS files, PackageWithoutThemes doesn't contain themes; From fdb5ee3a0f0fee66b981261a8e59c7f8d74c9f6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski-Owczarek?= Date: Sat, 15 Jun 2024 00:16:36 +0200 Subject: [PATCH 06/53] Release: Update download.jqueryui.com from 2.3.4 to 2.3.5 --- build/release.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/release.js b/build/release.js index 6cf0fa78ba..0b95685100 100644 --- a/build/release.js +++ b/build/release.js @@ -153,7 +153,7 @@ Release.define( { }; module.exports.dependencies = [ - "download.jqueryui.com@2.3.4", + "download.jqueryui.com@2.3.5", "node-packager@0.0.7", "shelljs@0.8.5" ]; From 2735f7d939012cc234ebce92ff0a43fa106ca523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski-Owczarek?= Date: Sat, 15 Jun 2024 00:31:33 +0200 Subject: [PATCH 07/53] Release: Update download.jqueryui.com from 2.3.5 to 2.3.6 --- build/release.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/release.js b/build/release.js index 0b95685100..a4e1b0d1b5 100644 --- a/build/release.js +++ b/build/release.js @@ -153,7 +153,7 @@ Release.define( { }; module.exports.dependencies = [ - "download.jqueryui.com@2.3.5", + "download.jqueryui.com@2.3.6", "node-packager@0.0.7", "shelljs@0.8.5" ]; From 872c28a94ee3fdd4638af9b4a5ac1747366ce07a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Jul 2024 18:26:55 +0200 Subject: [PATCH 08/53] Build: Bump actions/checkout from 4.1.6 to 4.1.7 Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.6 to 4.1.7. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/a5ac7e51b41094c92402da3b24376905380afc29...692973e3d937129bcbf40652eb9f2f61becf3332) Closes gh-2266 --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/filestash.yml | 2 +- .github/workflows/node.js.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/filestash.yml b/.github/workflows/filestash.yml index f1016b5b53..487644ee98 100644 --- a/.github/workflows/filestash.yml +++ b/.github/workflows/filestash.yml @@ -17,7 +17,7 @@ jobs: name: Update Filestash steps: - name: Checkout - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Use Node.js ${{ env.NODE_VERSION }} uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 18a5faf631..3e2bcda406 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -31,7 +31,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Use Node.js ${{ env.NODE_VERSION }} uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 @@ -75,7 +75,7 @@ jobs: name: jQuery stable steps: - name: Checkout - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Use Node.js ${{ env.NODE_VERSION }} uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 @@ -116,7 +116,7 @@ jobs: name: jQuery stable steps: - name: Checkout - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Use Node.js ${{ env.NODE_VERSION }} uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 From 7f0e920a97cedbe6f18fe41d8363cb3a8ad67938 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski-Owczarek?= Date: Fri, 5 Jul 2024 18:53:40 +0200 Subject: [PATCH 09/53] Release: Update download.jqueryui.com from 2.3.6 to 2.3.7 --- build/release.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/release.js b/build/release.js index a4e1b0d1b5..f2b2de03e6 100644 --- a/build/release.js +++ b/build/release.js @@ -153,7 +153,7 @@ Release.define( { }; module.exports.dependencies = [ - "download.jqueryui.com@2.3.6", + "download.jqueryui.com@2.3.7", "node-packager@0.0.7", "shelljs@0.8.5" ]; From 5665215a8560832193735d9507a90d10e03b90c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski-Owczarek?= Date: Mon, 8 Jul 2024 19:04:44 +0200 Subject: [PATCH 10/53] Build: Group dependabot PRs updating GitHub Actions We have monthly automatic dependabot PRs for GitHub Actions. Unfortunately, as of now we get a separate PR for every dependency which is a bit spammy compared to regular commits updating source. Thankfully, there's now a way to tell dependabot to submit a single PR per a defined group. This change defines a single group to have a single dependabot PR for all action updates. Closes gh-2267 Ref jquery/jquery#5503 --- .github/dependabot.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 6fff16c794..aa2f745652 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,3 +4,10 @@ updates: directory: "/" schedule: interval: monthly + + # Group all dependabot version update PRs into one + groups: + github-actions: + applies-to: version-updates + patterns: + - "*" From 600057f59c57fb428c0a453147476092741842c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski-Owczarek?= Date: Tue, 30 Jul 2024 08:31:10 +0200 Subject: [PATCH 11/53] Demos: Make autocomplete demos work on jqueryui.com The `jqueryui.com` demos build process deAMDifies HTML files, replacing required JS files with direct script tags. On the other hand, when running demos locally from the jQuery UI repository, RequireJS is used. This used to work fine until we got a new `search.js` file introduced in gh-2187. The deAMDifying process doesn't touch non-HTML files which made loading autocomplete demos crash on "require is not a function" To resolve the issues without a major rearchitecture of the build process, the `search.js` file now detects AMD and uses `require`, falling back to relying on the `jQuery` global in the other case. Closes gh-2274 Ref gh-2187 Ref jquery/jqueryui.com#216 --- demos/search.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/demos/search.js b/demos/search.js index 448071cc9f..c6dddb80ef 100644 --- a/demos/search.js +++ b/demos/search.js @@ -1,5 +1,18 @@ -require( [ "jquery", ], function( $ ) { +( function( factory ) { "use strict"; + + if ( typeof define === "function" && define.amd ) { + + // Fetch jQuery as an AMD dependency + require( [ "jquery" ], factory ); + } else { + + // Use the jQuery browser global + factory( jQuery ); + } +} )( function( $ ) { + "use strict"; + var database = { "Great Bittern" : "Botaurus stellaris", "Little Grebe" : "Tachybaptus ruficollis", From cd41c45d917d18839ab800816070db09a359d5bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski-Owczarek?= Date: Tue, 30 Jul 2024 17:53:47 +0200 Subject: [PATCH 12/53] Tests: Update jQuery Migrate from 3.4.1 to 3.5.2, simplify Migrate setup Apart from updating jQuery Migrate, the setup is now changed so that exact Migrate versions are only references when fetching npm packages; other than that, they're represented as `jquery-migrate-1.x` & `jquery-migrate-3.x`. This will allow smaller changes when updating jQuery Migrate in the future. Closes gh-2273 --- Gruntfile.js | 12 +-- bower.json | 4 +- .../LICENSE.txt | 0 .../jquery-migrate.js | 0 .../LICENSE.txt | 0 .../jquery-migrate.js | 79 +++++++++++-------- tests/lib/bootstrap.js | 4 +- 7 files changed, 56 insertions(+), 43 deletions(-) rename external/{jquery-migrate-1.4.1 => jquery-migrate-1.x}/LICENSE.txt (100%) rename external/{jquery-migrate-1.4.1 => jquery-migrate-1.x}/jquery-migrate.js (100%) rename external/{jquery-migrate-3.4.1 => jquery-migrate-3.x}/LICENSE.txt (100%) rename external/{jquery-migrate-3.4.1 => jquery-migrate-3.x}/jquery-migrate.js (94%) diff --git a/Gruntfile.js b/Gruntfile.js index 05e83c9613..334e4bb1ae 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -316,13 +316,13 @@ grunt.initConfig( { "jquery-3.7.1/jquery.js": "jquery-3.7.1/dist/jquery.js", "jquery-3.7.1/LICENSE.txt": "jquery-3.7.1/LICENSE.txt", - "jquery-migrate-1.4.1/jquery-migrate.js": - "jquery-migrate-1.4.1/dist/jquery-migrate.js", - "jquery-migrate-1.4.1/LICENSE.txt": "jquery-migrate-1.4.1/LICENSE.txt", + "jquery-migrate-1.x/jquery-migrate.js": + "jquery-migrate-1.x/dist/jquery-migrate.js", + "jquery-migrate-1.x/LICENSE.txt": "jquery-migrate-1.x/LICENSE.txt", - "jquery-migrate-3.4.1/jquery-migrate.js": - "jquery-migrate-3.4.1/dist/jquery-migrate.js", - "jquery-migrate-3.4.1/LICENSE.txt": "jquery-migrate-3.4.1/LICENSE.txt" + "jquery-migrate-3.x/jquery-migrate.js": + "jquery-migrate-3.x/dist/jquery-migrate.js", + "jquery-migrate-3.x/LICENSE.txt": "jquery-migrate-3.x/LICENSE.txt" } } }, diff --git a/bower.json b/bower.json index 1efb14ee2f..eec454dea0 100644 --- a/bower.json +++ b/bower.json @@ -38,7 +38,7 @@ "jquery-3.6.4": "jquery#3.6.4", "jquery-3.7.0": "jquery#3.7.0", "jquery-3.7.1": "jquery#3.7.1", - "jquery-migrate-1.4.1": "https://registry.npmjs.org/jquery-migrate/-/jquery-migrate-1.4.1.tgz", - "jquery-migrate-3.4.1": "https://registry.npmjs.org/jquery-migrate/-/jquery-migrate-3.4.1.tgz" + "jquery-migrate-1.x": "https://registry.npmjs.org/jquery-migrate/-/jquery-migrate-1.4.1.tgz", + "jquery-migrate-3.x": "https://registry.npmjs.org/jquery-migrate/-/jquery-migrate-3.5.2.tgz" } } diff --git a/external/jquery-migrate-1.4.1/LICENSE.txt b/external/jquery-migrate-1.x/LICENSE.txt similarity index 100% rename from external/jquery-migrate-1.4.1/LICENSE.txt rename to external/jquery-migrate-1.x/LICENSE.txt diff --git a/external/jquery-migrate-1.4.1/jquery-migrate.js b/external/jquery-migrate-1.x/jquery-migrate.js similarity index 100% rename from external/jquery-migrate-1.4.1/jquery-migrate.js rename to external/jquery-migrate-1.x/jquery-migrate.js diff --git a/external/jquery-migrate-3.4.1/LICENSE.txt b/external/jquery-migrate-3.x/LICENSE.txt similarity index 100% rename from external/jquery-migrate-3.4.1/LICENSE.txt rename to external/jquery-migrate-3.x/LICENSE.txt diff --git a/external/jquery-migrate-3.4.1/jquery-migrate.js b/external/jquery-migrate-3.x/jquery-migrate.js similarity index 94% rename from external/jquery-migrate-3.4.1/jquery-migrate.js rename to external/jquery-migrate-3.x/jquery-migrate.js index 5ef505ed92..edc32de392 100644 --- a/external/jquery-migrate-3.4.1/jquery-migrate.js +++ b/external/jquery-migrate-3.x/jquery-migrate.js @@ -1,5 +1,5 @@ /*! - * jQuery Migrate - v3.4.1 - 2023-02-23T15:31Z + * jQuery Migrate - v3.5.2 - 2024-07-17T22:31Z * Copyright OpenJS Foundation and other contributors */ ( function( factory ) { @@ -24,7 +24,7 @@ } )( function( jQuery, window ) { "use strict"; -jQuery.migrateVersion = "3.4.1"; +jQuery.migrateVersion = "3.5.2"; // Returns 0 if v1 == v2, -1 if v1 < v2, 1 if v1 > v2 function compareVersions( v1, v2 ) { @@ -84,26 +84,26 @@ jQuery.migrateIsPatchEnabled = function( patchCode ) { ( function() { - // Support: IE9 only - // IE9 only creates console object when dev tools are first opened - // IE9 console is a host object, callable but doesn't have .apply() - if ( !window.console || !window.console.log ) { - return; - } +// Support: IE9 only +// IE9 only creates console object when dev tools are first opened +// IE9 console is a host object, callable but doesn't have .apply() +if ( !window.console || !window.console.log ) { + return; +} - // Need jQuery 3.x-4.x and no older Migrate loaded - if ( !jQuery || !jQueryVersionSince( "3.0.0" ) || - jQueryVersionSince( "5.0.0" ) ) { - window.console.log( "JQMIGRATE: jQuery 3.x-4.x REQUIRED" ); - } - if ( jQuery.migrateWarnings ) { - window.console.log( "JQMIGRATE: Migrate plugin loaded multiple times" ); - } +// Need jQuery 3.x-4.x and no older Migrate loaded +if ( !jQuery || !jQueryVersionSince( "3.0.0" ) || + jQueryVersionSince( "5.0.0" ) ) { + window.console.log( "JQMIGRATE: jQuery 3.x-4.x REQUIRED" ); +} +if ( jQuery.migrateWarnings ) { + window.console.log( "JQMIGRATE: Migrate plugin loaded multiple times" ); +} - // Show a message on the console so devs know we're active - window.console.log( "JQMIGRATE: Migrate is installed" + - ( jQuery.migrateMute ? "" : " with logging active" ) + - ", version " + jQuery.migrateVersion ); +// Show a message on the console so devs know we're active +window.console.log( "JQMIGRATE: Migrate is installed" + + ( jQuery.migrateMute ? "" : " with logging active" ) + + ", version " + jQuery.migrateVersion ); } )(); @@ -320,7 +320,8 @@ if ( jQueryVersionSince( "3.2.0" ) ) { if ( jQueryVersionSince( "3.3.0" ) ) { - migratePatchAndWarnFunc( jQuery, "isNumeric", function( obj ) { + migratePatchAndWarnFunc( jQuery, "isNumeric", + function( obj ) { // As of jQuery 3.0, isNumeric is limited to // strings and numbers (primitives or objects) @@ -417,6 +418,7 @@ if ( !jQueryVersionSince( "4.0.0" ) ) { var oldRemoveAttr = jQuery.fn.removeAttr, oldToggleClass = jQuery.fn.toggleClass, + rbooleans = /^(?:checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped)$/i, rmatchNonSpace = /\S+/g; migratePatchFunc( jQuery.fn, "removeAttr", function( name ) { @@ -424,7 +426,7 @@ migratePatchFunc( jQuery.fn, "removeAttr", function( name ) { patchNeeded = false; jQuery.each( name.match( rmatchNonSpace ), function( _i, attr ) { - if ( jQuery.expr.match.bool.test( attr ) ) { + if ( rbooleans.test( attr ) ) { // Only warn if at least a single node had the property set to // something else than `false`. Otherwise, this Migrate patch @@ -472,8 +474,8 @@ migratePatchFunc( jQuery.fn, "toggleClass", function( state ) { if ( this.setAttribute ) { this.setAttribute( "class", className || state === false ? - "" : - jQuery.data( this, "__className__" ) || "" + "" : + jQuery.data( this, "__className__" ) || "" ); } } ); @@ -564,7 +566,7 @@ if ( jQueryVersionSince( "3.4.0" ) && typeof Proxy !== "undefined" ) { } // In jQuery >=4 where jQuery.cssNumber is missing fill it with the latest 3.x version: -// https://github.com/jquery/jquery/blob/3.6.0/src/css.js#L212-L233 +// https://github.com/jquery/jquery/blob/3.7.1/src/css.js#L216-L246 // This way, number values for the CSS properties below won't start triggering // Migrate warnings when jQuery gets updated to >=4.0.0 (gh-438). if ( jQueryVersionSince( "4.0.0" ) ) { @@ -573,8 +575,9 @@ if ( jQueryVersionSince( "4.0.0" ) ) { // in a `jQuery.fn.css` patch and this usage shouldn't warn. internalCssNumber = { animationIterationCount: true, + aspectRatio: true, + borderImageSlice: true, columnCount: true, - fillOpacity: true, flexGrow: true, flexShrink: true, fontWeight: true, @@ -589,9 +592,17 @@ if ( jQueryVersionSince( "4.0.0" ) ) { opacity: true, order: true, orphans: true, + scale: true, widows: true, zIndex: true, - zoom: true + zoom: true, + + // SVG-related + fillOpacity: true, + floodOpacity: true, + stopOpacity: true, + strokeMiterlimit: true, + strokeOpacity: true }; if ( typeof Proxy !== "undefined" ) { @@ -837,16 +848,16 @@ jQuery.each( [ "load", "unload", "error" ], function( _, name ) { jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + "change select submit keydown keypress keyup contextmenu" ).split( " " ), - function( _i, name ) { +function( _i, name ) { // Handle event binding migratePatchAndWarnFunc( jQuery.fn, name, function( data, fn ) { return arguments.length > 0 ? this.on( name, null, data, fn ) : this.trigger( name ); - }, - "shorthand-deprecated-v3", - "jQuery.fn." + name + "() event shorthand is deprecated" ); + }, + "shorthand-deprecated-v3", + "jQuery.fn." + name + "() event shorthand is deprecated" ); } ); // Trigger "ready" event only once, on document ready @@ -898,9 +909,11 @@ var rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\ * Deprecated, please use `jQuery.migrateDisablePatches( "self-closed-tags" )` instead. * @deprecated */ -jQuery.UNSAFE_restoreLegacyHtmlPrefilter = function() { +migratePatchAndWarnFunc( jQuery, "UNSAFE_restoreLegacyHtmlPrefilter", function() { jQuery.migrateEnablePatches( "self-closed-tags" ); -}; +}, "legacy-self-closed-tags", +"jQuery.UNSAFE_restoreLegacyHtmlPrefilter deprecated; use " + + "`jQuery.migrateEnablePatches( \"self-closed-tags\" )`" ); migratePatchFunc( jQuery, "htmlPrefilter", function( html ) { warnIfChanged( html ); diff --git a/tests/lib/bootstrap.js b/tests/lib/bootstrap.js index c32d9765e6..2f1b7ef4b5 100644 --- a/tests/lib/bootstrap.js +++ b/tests/lib/bootstrap.js @@ -112,9 +112,9 @@ function migrateUrl() { if ( jqueryVersion === "git" ) { url = "https://releases.jquery.com/git/jquery-migrate-git"; } else if ( jqueryVersion[ 0 ] === "3" ) { - url = "../../../external/jquery-migrate-3.4.1/jquery-migrate"; + url = "../../../external/jquery-migrate-3.x/jquery-migrate"; } else if ( jqueryVersion[ 0 ] === "1" || jqueryVersion[ 0 ] === "2" ) { - url = "../../../external/jquery-migrate-1.4.1/jquery-migrate"; + url = "../../../external/jquery-migrate-1.x/jquery-migrate"; } else if ( jqueryVersion === "custom" ) { if ( parseUrl().migrate ) { throw new Error( "Migrate not currently supported for custom build" ); From a0c5b12e8291e40cf43c61844d50a5f7fdfe021a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Aug 2024 18:32:29 +0200 Subject: [PATCH 13/53] Build: Bump actions/setup-node from 4.0.2 to 4.0.3 in the github-actions group Bumps the github-actions group with 1 update: [actions/setup-node](https://github.com/actions/setup-node). Updates `actions/setup-node` from 4.0.2 to 4.0.3 - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/60edb5dd545a775178f52524783378180af0d1f8...1e60f620b9541d16bece96c5465dc8ee9832be0b) Closes gh-2276 --- updated-dependencies: - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/filestash.yml | 2 +- .github/workflows/node.js.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/filestash.yml b/.github/workflows/filestash.yml index 487644ee98..be43834846 100644 --- a/.github/workflows/filestash.yml +++ b/.github/workflows/filestash.yml @@ -20,7 +20,7 @@ jobs: uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 with: node-version: ${{ env.NODE_VERSION }} diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 3e2bcda406..84e1db7180 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -34,7 +34,7 @@ jobs: uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 with: node-version: ${{ env.NODE_VERSION }} @@ -78,7 +78,7 @@ jobs: uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 with: node-version: ${{ env.NODE_VERSION }} @@ -119,7 +119,7 @@ jobs: uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 with: node-version: ${{ env.NODE_VERSION }} From 02a6e6bcb004696b21324ef14c07374a56d7cd02 Mon Sep 17 00:00:00 2001 From: Porter Clevidence <116387727+porterclev@users.noreply.github.com> Date: Mon, 5 Aug 2024 10:30:53 -0700 Subject: [PATCH 14/53] Datepicker: Hide the UI on destroy When the datepicker UI is shown and then destroyed programmatically: ```js $( "#datepicker" ).datepicker( "destroy" ); ``` hide the datepicker UI without the need for an explicit user action. Previously, in 1.12 the UI would not disappear immediately but only after the first `mousedown`. In later 1.13 versions, the UI would not disappear at all. Fixes gh-2178 Closes gh-2268 --- tests/unit/datepicker/methods.js | 11 ++++++++++- ui/widgets/datepicker.js | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/unit/datepicker/methods.js b/tests/unit/datepicker/methods.js index 32d6117488..ec83fb791b 100644 --- a/tests/unit/datepicker/methods.js +++ b/tests/unit/datepicker/methods.js @@ -11,7 +11,7 @@ var beforeAfterEach = testHelper.beforeAfterEach; QUnit.module( "datepicker: methods", beforeAfterEach() ); QUnit.test( "destroy", function( assert ) { - assert.expect( 35 ); + assert.expect( 39 ); var inl, inp = testHelper.init( "#inp" ), dp = $( "#ui-datepicker-div" ); @@ -21,6 +21,15 @@ QUnit.test( "destroy", function( assert ) { assert.equal( dp.css( "display" ), "block", "Datepicker - visible" ); inp.datepicker( "hide" ).datepicker( "destroy" ); assert.ok( $.datepicker._curInst == null, "Datepicker - destroyed and cleared reference" ); + assert.equal( dp.css( "display" ), "none", "Datepicker - absent" ); + + // Destroy without manual hiding (ensure datepicker is hidden after calling destroy) + inp = testHelper.init( "#inp" ); + inp.datepicker( "show" ); + assert.equal( dp.css( "display" ), "block", "Datepicker - visible" ); + inp.datepicker( "destroy" ); + assert.ok( $.datepicker._curInst == null, "Datepicker - destroyed and cleared reference" ); + assert.equal( dp.css( "display" ), "none", "Datepicker - absent" ); inp = testHelper.init( "#inp" ); assert.ok( inp.is( ".hasDatepicker" ), "Default - marker class set" ); diff --git a/ui/widgets/datepicker.js b/ui/widgets/datepicker.js index 6057605721..323723b893 100644 --- a/ui/widgets/datepicker.js +++ b/ui/widgets/datepicker.js @@ -435,6 +435,7 @@ $.extend( Datepicker.prototype, { $target.removeClass( this.markerClassName ).empty(); } + $.datepicker._hideDatepicker(); if ( datepicker_instActive === inst ) { datepicker_instActive = null; this._curInst = null; From 2fb378e86094a3afc2436a536371a33697277e2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski-Owczarek?= Date: Mon, 5 Aug 2024 19:54:51 +0200 Subject: [PATCH 15/53] Docs: Update AUTHORS.txt --- AUTHORS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.txt b/AUTHORS.txt index 738af9c462..5b10979cae 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -380,3 +380,4 @@ Timmy Willison divdeploy <166095818+divdeploy@users.noreply.github.com> mark van tilburg Ralf Koller <1665422+rpkoller@users.noreply.github.com> +Porter Clevidence <116387727+porterclev@users.noreply.github.com> From 1e67c0d5934cf92c261d557963681010c9750fda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski-Owczarek?= Date: Mon, 5 Aug 2024 20:58:10 +0200 Subject: [PATCH 16/53] Build: Updating the main version to 1.14.1-pre. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 76ae6b05d4..81e5375251 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "jquery-ui", "title": "jQuery UI", "description": "A curated set of user interface interactions, effects, widgets, and themes built on top of the jQuery JavaScript Library.", - "version": "1.14.0-pre", + "version": "1.14.1-pre", "homepage": "https://jqueryui.com", "author": { "name": "OpenJS Foundation and other contributors", From 54f96eea31b21d9ecb00912261df3e5aaebf8cce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski-Owczarek?= Date: Mon, 5 Aug 2024 22:52:56 +0200 Subject: [PATCH 17/53] Release: Update download.jqueryui.com from 2.3.7 to 2.3.10 --- build/release.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/release.js b/build/release.js index f2b2de03e6..14fbd6f153 100644 --- a/build/release.js +++ b/build/release.js @@ -153,7 +153,7 @@ Release.define( { }; module.exports.dependencies = [ - "download.jqueryui.com@2.3.7", + "download.jqueryui.com@2.3.10", "node-packager@0.0.7", "shelljs@0.8.5" ]; From fd1b8a03b22411e68e703426fb85a2566318623d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski-Owczarek?= Date: Mon, 9 Sep 2024 17:52:53 +0200 Subject: [PATCH 18/53] Tests: Properly check `$.uiBackCompat` in common widget tests The "common widget" tests, checking if a widget doesn't overwrite some core widget APIs wasn't running as it was incorrectly checking for `$.uiBackCompat === false` instead of `$.uiBackCompat !== true` after the default changed in gh-2250. Fixing the check uncovered that the draggable & sortable modules do overwrite the `_trigger` method. Add an exception in the test for that; at this stage of the project we don't plan to change the implementation. Closes gh-2286 Ref gh-2250 --- tests/lib/common.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tests/lib/common.js b/tests/lib/common.js index 56b7a3ff38..ba78fb6f63 100644 --- a/tests/lib/common.js +++ b/tests/lib/common.js @@ -34,7 +34,7 @@ function testWidgetDefaults( widget, defaults ) { } function testWidgetOverrides( widget ) { - if ( $.uiBackCompat === false ) { + if ( $.uiBackCompat !== true ) { QUnit.test( "$.widget overrides", function( assert ) { assert.expect( 4 ); $.each( [ @@ -43,8 +43,19 @@ function testWidgetOverrides( widget ) { "option", "_trigger" ], function( i, method ) { - assert.strictEqual( $.ui[ widget ].prototype[ method ], - $.Widget.prototype[ method ], "should not override " + method ); + + if ( method === "_trigger" && + /^(?:draggable|sortable): common widget$/ + .test( assert.test.module.name ) ) { + + // Draggable & sortable modules overwrite _trigger. They + // should not, but we don't plan to change the API at this + // stage of the project. + assert.ok( true, "draggable & sortable modules overwrite _trigger" ); + } else { + assert.strictEqual( $.ui[ widget ].prototype[ method ], + $.Widget.prototype[ method ], "should not override " + method ); + } } ); } ); } From d564731f20a5eee6c6e373344a2bd6fc9d047e63 Mon Sep 17 00:00:00 2001 From: Ralf Koller <1665422+rpkoller@users.noreply.github.com> Date: Mon, 9 Sep 2024 17:55:58 +0200 Subject: [PATCH 19/53] Dialog: Add option to put the dialog title in a header element Implement a new option: `uiDialogTitleHeadingLevel`, allowing to change the `span` wrapping the dialog title into a heading element (`h1`-`h6`). Value `0` represents the `span`, values 1-6 - a heading at the specified level. Fixes gh-2271 Closes gh-2275 --- tests/unit/dialog/common-deprecated.js | 1 + tests/unit/dialog/common.js | 1 + tests/unit/dialog/core.js | 38 ++++++++++++++++++++++++++ ui/widgets/dialog.js | 9 +++++- 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/tests/unit/dialog/common-deprecated.js b/tests/unit/dialog/common-deprecated.js index 1efdcb0301..2cdae9681d 100644 --- a/tests/unit/dialog/common-deprecated.js +++ b/tests/unit/dialog/common-deprecated.js @@ -34,6 +34,7 @@ common.testWidget( "dialog", { resizable: true, show: null, title: null, + uiDialogTitleHeadingLevel: 0, width: 300, // Callbacks diff --git a/tests/unit/dialog/common.js b/tests/unit/dialog/common.js index c8d885ad03..f311810476 100644 --- a/tests/unit/dialog/common.js +++ b/tests/unit/dialog/common.js @@ -33,6 +33,7 @@ common.testWidget( "dialog", { resizable: true, show: null, title: null, + uiDialogTitleHeadingLevel: 0, width: 300, // Callbacks diff --git a/tests/unit/dialog/core.js b/tests/unit/dialog/core.js index c6bdec778c..a8cc9678e5 100644 --- a/tests/unit/dialog/core.js +++ b/tests/unit/dialog/core.js @@ -117,6 +117,44 @@ QUnit.test( "aria-modal", function( assert ) { element.remove(); } ); +QUnit.test( "ui dialog title heading level", function( assert ) { + assert.expect( 8 ); + + var element, nodeName; + + element = $( "
" ).dialog( { modal: true } ); + nodeName = element.dialog( "widget" ).find( ".ui-dialog-title" ).get( 0 ).nodeName.toLowerCase(); + assert.equal( nodeName, "span", "Element wrapping the dialog title is span" ); + + element = $( "
" ).dialog( { modal: true, uiDialogTitleHeadingLevel: 0 } ); + nodeName = element.dialog( "widget" ).find( ".ui-dialog-title" ).get( 0 ).nodeName.toLowerCase(); + assert.equal( nodeName, "span", "Element wrapping the dialog title is span" ); + + element = $( "
" ).dialog( { modal: true, uiDialogTitleHeadingLevel: 1 } ); + nodeName = element.dialog( "widget" ).find( ".ui-dialog-title" ).get( 0 ).nodeName.toLowerCase(); + assert.equal( nodeName, "h1", "Element wrapping the dialog title is h1" ); + + element = $( "
" ).dialog( { modal: true, uiDialogTitleHeadingLevel: 6 } ); + nodeName = element.dialog( "widget" ).find( ".ui-dialog-title" ).get( 0 ).nodeName.toLowerCase(); + assert.equal( nodeName, "h6", "Element wrapping the dialog title is h6" ); + + element = $( "
" ).dialog( { modal: true, uiDialogTitleHeadingLevel: 9 } ); + nodeName = element.dialog( "widget" ).find( ".ui-dialog-title" ).get( 0 ).nodeName.toLowerCase(); + assert.equal( nodeName, "span", "Element wrapping the dialog title is span" ); + + element = $( "
" ).dialog( { modal: true, uiDialogTitleHeadingLevel: -9 } ); + nodeName = element.dialog( "widget" ).find( ".ui-dialog-title" ).get( 0 ).nodeName.toLowerCase(); + assert.equal( nodeName, "span", "Element wrapping the dialog title is span" ); + + element = $( "
" ).dialog( { modal: true, uiDialogTitleHeadingLevel: 2.3 } ); + nodeName = element.dialog( "widget" ).find( ".ui-dialog-title" ).get( 0 ).nodeName.toLowerCase(); + assert.equal( nodeName, "span", "Element wrapping the dialog title is span" ); + + element = $( "
" ).dialog( { modal: true, uiDialogTitleHeadingLevel: "foo" } ); + nodeName = element.dialog( "widget" ).find( ".ui-dialog-title" ).get( 0 ).nodeName.toLowerCase(); + assert.equal( nodeName, "span", "Element wrapping the dialog title is span" ); +} ); + QUnit.test( "widget method", function( assert ) { assert.expect( 1 ); var dialog = $( "
" ).appendTo( "#qunit-fixture" ).dialog(); diff --git a/ui/widgets/dialog.js b/ui/widgets/dialog.js index 756ad1cb10..1ef2fa3d6f 100644 --- a/ui/widgets/dialog.js +++ b/ui/widgets/dialog.js @@ -81,6 +81,7 @@ $.widget( "ui.dialog", { resizable: true, show: null, title: null, + uiDialogTitleHeadingLevel: 0, width: 300, // Callbacks @@ -437,7 +438,13 @@ $.widget( "ui.dialog", { } } ); - uiDialogTitle = $( "" ).uniqueId().prependTo( this.uiDialogTitlebar ); + var uiDialogHeadingLevel = Number.isInteger( this.options.uiDialogTitleHeadingLevel ) && + this.options.uiDialogTitleHeadingLevel > 0 && + this.options.uiDialogTitleHeadingLevel <= 6 ? + "h" + this.options.uiDialogTitleHeadingLevel : "span"; + + uiDialogTitle = $( "<" + uiDialogHeadingLevel + ">" ) + .uniqueId().prependTo( this.uiDialogTitlebar ); this._addClass( uiDialogTitle, "ui-dialog-title" ); this._title( uiDialogTitle ); From c934995efa431efe0b15b6f9a6b614e6b8e88399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= <93217193+Daniel-Garmig@users.noreply.github.com> Date: Mon, 9 Sep 2024 23:51:57 +0200 Subject: [PATCH 20/53] Resizable: Fix content shrink on resize Make resizable elements not shrink on resize when they have scrollbars and "box-sizing: content-box". Fixes: gh-2277 Closes gh-2281 --- tests/unit/resizable/core.js | 68 ++++++++++++++++++++++++++++ tests/unit/resizable/options.js | 62 +++++++++++++++++++++++--- ui/widgets/resizable.js | 78 ++++++++++++++++++++++++++++----- 3 files changed, 191 insertions(+), 17 deletions(-) diff --git a/tests/unit/resizable/core.js b/tests/unit/resizable/core.js index b3c61514a9..b47f0b645f 100644 --- a/tests/unit/resizable/core.js +++ b/tests/unit/resizable/core.js @@ -244,4 +244,72 @@ QUnit.test( "nested resizable", function( assert ) { outer.remove(); } ); +QUnit.test( "Resizable with scrollbars and box-sizing: border-box", function( assert ) { + assert.expect( 4 ); + testResizableWithBoxSizing( assert, { + isBorderBox: true, + applyScaleTransform: false + } ); +} ); + +QUnit.test( "Resizable with scrollbars and box-sizing: content-box", function( assert ) { + assert.expect( 4 ); + testResizableWithBoxSizing( assert, { + isBorderBox: false, + applyScaleTransform: false + } ); +} ); + +QUnit.test( "Resizable with scrollbars, a transform and box-sizing: border-box", function( assert ) { + assert.expect( 4 ); + testResizableWithBoxSizing( assert, { + isBorderBox: true, + applyScaleTransform: true + } ); +} ); + +QUnit.test( "Resizable with scrollbars, a transform and box-sizing: content-box", function( assert ) { + assert.expect( 4 ); + testResizableWithBoxSizing( assert, { + isBorderBox: false, + applyScaleTransform: true + } ); +} ); + +function testResizableWithBoxSizing( assert, options ) { + var widthBefore, heightBefore, + cssBoxSizing = options.isBorderBox ? "border-box" : "content-box", + cssTransform = options.applyScaleTransform ? "scale(1.5)" : "", + elementContent = $( "
" ) + .css( { + width: "200px", + height: "200px", + padding: "10px", + border: "5px", + borderStyle: "solid", + margin: "20px" + } ) + .appendTo( "#resizable1" ), + element = $( "#resizable1" ).css( { overflow: "auto", transform: cssTransform } ).resizable(), + handle = ".ui-resizable-se"; + + $( "" ).appendTo( "#qunit-fixture" ); + + // In some browsers scrollbar may change element size (when "box-sizing: content-box") + widthBefore = element.innerWidth(); + heightBefore = element.innerHeight(); + + // Both scrollbars + testHelper.drag( handle, 10, 10 ); + assert.equal( parseFloat( element.innerWidth() ), widthBefore + 10, "element width (both scrollbars)" ); + assert.equal( parseFloat( element.innerHeight() ), heightBefore + 10, "element height (both scrollbars)" ); + + // Single (vertical) scrollbar. + elementContent.css( "width", "50px" ); + + testHelper.drag( handle, 10, 10 ); + assert.equal( parseFloat( element.innerWidth() ), widthBefore + 20, "element width (only vertical scrollbar)" ); + assert.equal( parseFloat( element.innerHeight() ), heightBefore + 20, "element height (only vertical scrollbar)" ); +} + } ); diff --git a/tests/unit/resizable/options.js b/tests/unit/resizable/options.js index add8d80344..b80c051d58 100644 --- a/tests/unit/resizable/options.js +++ b/tests/unit/resizable/options.js @@ -542,21 +542,22 @@ QUnit.test( "alsoResize + multiple selection", function( assert ) { QUnit.test( "alsoResize with box-sizing: border-box", function( assert ) { assert.expect( 4 ); + $( "" ).appendTo( "#qunit-fixture" ); + var other = $( "
" ) .css( { - width: 50, - height: 50, - padding: 10, - border: 5 + width: "50px", + height: "50px", + padding: "10px", + border: "5px", + borderStyle: "solid" } ) - .appendTo( "body" ), + .appendTo( "#qunit-fixture" ), element = $( "#resizable1" ).resizable( { alsoResize: other } ), handle = ".ui-resizable-se"; - $( "*" ).css( "box-sizing", "border-box" ); - testHelper.drag( handle, 80, 80 ); assert.equal( element.width(), 180, "resizable width" ); @@ -565,4 +566,51 @@ QUnit.test( "alsoResize with box-sizing: border-box", function( assert ) { assert.equal( parseFloat( other.css( "height" ) ), 130, "alsoResize height" ); } ); +QUnit.test( "alsoResize with scrollbars and box-sizing: border-box", function( assert ) { + assert.expect( 4 ); + testAlsoResizeWithBoxSizing( assert, { + isBorderBox: true + } ); +} ); + +QUnit.test( "alsoResize with scrollbars and box-sizing: content-box", function( assert ) { + assert.expect( 4 ); + testAlsoResizeWithBoxSizing( assert, { + isBorderBox: false + } ); +} ); + +function testAlsoResizeWithBoxSizing( assert, options ) { + var widthBefore, heightBefore, + cssBoxSizing = options.isBorderBox ? "border-box" : "content-box", + other = $( "
" ) + .css( { + width: "150px", + height: "150px", + padding: "10px", + border: "5px", + borderStyle: "solid", + margin: "20px", + overflow: "scroll" + } ) + .appendTo( "#qunit-fixture" ), + element = $( "#resizable1" ).resizable( { + alsoResize: other + } ), + handle = ".ui-resizable-se"; + + $( "" ).appendTo( "#qunit-fixture" ); + + // In some browsers scrollbar may change element computed size. + widthBefore = other.innerWidth(); + heightBefore = other.innerHeight(); + + testHelper.drag( handle, 80, 80 ); + + assert.equal( element.width(), 180, "resizable width" ); + assert.equal( parseFloat( other.innerWidth() ), widthBefore + 80, "alsoResize width" ); + assert.equal( element.height(), 180, "resizable height" ); + assert.equal( parseFloat( other.innerHeight() ), heightBefore + 80, "alsoResize height" ); +} + } ); diff --git a/ui/widgets/resizable.js b/ui/widgets/resizable.js index 1698d55e8b..6f1e0ebdec 100644 --- a/ui/widgets/resizable.js +++ b/ui/widgets/resizable.js @@ -80,12 +80,18 @@ $.widget( "ui.resizable", $.ui.mouse, { _hasScroll: function( el, a ) { - if ( $( el ).css( "overflow" ) === "hidden" ) { + var scroll, + has = false, + overflow = $( el ).css( "overflow" ); + + if ( overflow === "hidden" ) { return false; } + if ( overflow === "scroll" ) { + return true; + } - var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", - has = false; + scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop"; if ( el[ scroll ] > 0 ) { return true; @@ -362,7 +368,7 @@ $.widget( "ui.resizable", $.ui.mouse, { _mouseStart: function( event ) { - var curleft, curtop, cursor, + var curleft, curtop, cursor, calculatedSize, o = this.options, el = this.element; @@ -381,20 +387,24 @@ $.widget( "ui.resizable", $.ui.mouse, { this.offset = this.helper.offset(); this.position = { left: curleft, top: curtop }; + if ( !this._helper ) { + calculatedSize = this._calculateAdjustedElementDimensions( el ); + } + this.size = this._helper ? { width: this.helper.width(), height: this.helper.height() } : { - width: el.width(), - height: el.height() + width: calculatedSize.width, + height: calculatedSize.height }; this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { - width: el.width(), - height: el.height() + width: calculatedSize.width, + height: calculatedSize.height }; this.sizeDiff = { @@ -690,6 +700,52 @@ $.widget( "ui.resizable", $.ui.mouse, { }; }, + _calculateAdjustedElementDimensions: function( element ) { + var elWidth, elHeight, paddingBorder, + ce = element.get( 0 ); + + if ( element.css( "box-sizing" ) !== "content-box" || + ( !this._hasScroll( ce ) && !this._hasScroll( ce, "left" ) ) ) { + return { + height: parseFloat( element.css( "height" ) ), + width: parseFloat( element.css( "width" ) ) + }; + } + + // Check if CSS inline styles are set and use those (usually from previous resizes) + elWidth = parseFloat( ce.style.width ); + elHeight = parseFloat( ce.style.height ); + + paddingBorder = this._getPaddingPlusBorderDimensions( element ); + elWidth = isNaN( elWidth ) ? + this._getElementTheoreticalSize( element, paddingBorder, "width" ) : + elWidth; + elHeight = isNaN( elHeight ) ? + this._getElementTheoreticalSize( element, paddingBorder, "height" ) : + elHeight; + + return { + height: elHeight, + width: elWidth + }; + }, + + _getElementTheoreticalSize: function( element, extraSize, dimension ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + var size = Math.max( 0, Math.ceil( + element.get( 0 )[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + extraSize[ dimension ] - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine theoretical size. + // Use an explicit zero to avoid NaN. + // See https://github.com/jquery/jquery/issues/3964 + ) ) || 0; + + return size; + }, + _proportionallyResize: function() { if ( !this._proportionallyResizeElements.length ) { @@ -1044,9 +1100,11 @@ $.ui.plugin.add( "resizable", "alsoResize", { o = that.options; $( o.alsoResize ).each( function() { - var el = $( this ); + var el = $( this ), + elSize = that._calculateAdjustedElementDimensions( el ); + el.data( "ui-resizable-alsoresize", { - width: parseFloat( el.css( "width" ) ), height: parseFloat( el.css( "height" ) ), + width: elSize.width, height: elSize.height, left: parseFloat( el.css( "left" ) ), top: parseFloat( el.css( "top" ) ) } ); } ); From 36ed9fc3b0f0ce348a360e8a10500475337368b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski-Owczarek?= Date: Mon, 16 Sep 2024 17:16:40 +0200 Subject: [PATCH 21/53] Effect: Remove demos & visual tests of the transfer effect The transfer effect is deprecated and not present unless `$.uiBackCompat` is set to `true`. In previous UI versions, the default was including the backwards compat layer so these demos & tests worked; now they do not by default. Just remove them. Fixes gh-2278 Closes gh-2291 --- demos/effect/default.html | 4 ---- tests/visual/effects/all.html | 6 ------ tests/visual/effects/effects.js | 8 -------- 3 files changed, 18 deletions(-) diff --git a/demos/effect/default.html b/demos/effect/default.html index 7d69abb2d7..289d5df7ff 100644 --- a/demos/effect/default.html +++ b/demos/effect/default.html @@ -11,7 +11,6 @@ #button { padding: .5em 1em; text-decoration: none; } #effect { width: 240px; height: 170px; padding: 0.4em; position: relative; } #effect h3 { margin: 0; padding: 0.4em; text-align: center; } - .ui-effects-transfer { border: 2px dotted gray; } - .toggler { width: 500px; height: 200px; position: relative; } From eab06ed31da44e60f2db9e760cb613bf8f5231f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 00:16:34 +0200 Subject: [PATCH 24/53] Build: Bump the github-actions group with 2 updates Bumps the github-actions group with 2 updates: [actions/checkout](https://github.com/actions/checkout) and [actions/setup-node](https://github.com/actions/setup-node). Updates `actions/checkout` from 4.1.7 to 4.2.0 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/692973e3d937129bcbf40652eb9f2f61becf3332...d632683dd7b4114ad314bca15554477dd762a938) Updates `actions/setup-node` from 4.0.3 to 4.0.4 - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/1e60f620b9541d16bece96c5465dc8ee9832be0b...0a44ba7841725637a19e28fa30b79a866c81b0a6) Closes gh-2299 --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/filestash.yml | 4 ++-- .github/workflows/node.js.yml | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/filestash.yml b/.github/workflows/filestash.yml index be43834846..f3944447a8 100644 --- a/.github/workflows/filestash.yml +++ b/.github/workflows/filestash.yml @@ -17,10 +17,10 @@ jobs: name: Update Filestash steps: - name: Checkout - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 with: node-version: ${{ env.NODE_VERSION }} diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 84e1db7180..22116c7dab 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -31,10 +31,10 @@ jobs: steps: - name: Checkout - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 with: node-version: ${{ env.NODE_VERSION }} @@ -75,10 +75,10 @@ jobs: name: jQuery stable steps: - name: Checkout - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 with: node-version: ${{ env.NODE_VERSION }} @@ -116,10 +116,10 @@ jobs: name: jQuery stable steps: - name: Checkout - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 with: node-version: ${{ env.NODE_VERSION }} From 2eebdaf506c3c242f224fedbdb44dfb9f1bf8f8a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 00:10:49 +0200 Subject: [PATCH 25/53] Build: Bump body-parser from 1.20.2 to 1.20.3 Bumps [body-parser](https://github.com/expressjs/body-parser) from 1.20.2 to 1.20.3. - [Release notes](https://github.com/expressjs/body-parser/releases) - [Changelog](https://github.com/expressjs/body-parser/blob/master/HISTORY.md) - [Commits](https://github.com/expressjs/body-parser/compare/1.20.2...1.20.3) Closes gh-2294 --- updated-dependencies: - dependency-name: body-parser dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 81e5375251..cc8b14a9a8 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "jquery": ">=1.12.0 <5.0.0" }, "devDependencies": { - "body-parser": "1.20.2", + "body-parser": "1.20.3", "browserstack-local": "1.5.5", "commitplease": "3.2.0", "diff": "5.2.0", From 3934c68dee9ad5c7f037361e9d8b02215c1296bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 00:11:21 +0200 Subject: [PATCH 26/53] Build: Bump express from 4.19.2 to 4.20.0 Bumps [express](https://github.com/expressjs/express) from 4.19.2 to 4.20.0. - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/master/History.md) - [Commits](https://github.com/expressjs/express/compare/4.19.2...4.20.0) Closes gh-2293 --- updated-dependencies: - dependency-name: express dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cc8b14a9a8..f9f83b4025 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "diff": "5.2.0", "eslint-config-jquery": "3.0.2", "exit-hook": "4.0.0", - "express": "4.19.2", + "express": "4.20.0", "express-body-parser-error-handler": "1.0.7", "grunt": "1.6.1", "grunt-bowercopy": "1.2.5", From 49bb397606b476eacd9df2bda0388795a22fa59a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski-Owczarek?= Date: Thu, 17 Oct 2024 23:47:29 +0200 Subject: [PATCH 27/53] Build: Fix the ESLint config for demos The ESLint config for `demos` extends the one for the `ui` directory. However, the `ui` one used to not be a root one, making the `demos` one effectively not depend on the `jquery` preset. Fix that and fix lots of lint violations in `demos/search.js`. Closes gh-2303 --- demos/.eslintrc.json | 6 +- demos/search.js | 1154 +++++++++++++++++++++--------------------- ui/.eslintrc.json | 4 + 3 files changed, 586 insertions(+), 578 deletions(-) diff --git a/demos/.eslintrc.json b/demos/.eslintrc.json index da1cb6b909..805ec8eb26 100644 --- a/demos/.eslintrc.json +++ b/demos/.eslintrc.json @@ -1,5 +1,9 @@ { "root": true, - "extends": "../ui/.eslintrc.json" + "extends": "../ui/.eslintrc.json", + + "globals": { + "require": true + } } diff --git a/demos/search.js b/demos/search.js index c6dddb80ef..d3a1d8c232 100644 --- a/demos/search.js +++ b/demos/search.js @@ -14,569 +14,569 @@ "use strict"; var database = { - "Great Bittern" : "Botaurus stellaris", - "Little Grebe" : "Tachybaptus ruficollis", - "Black-necked Grebe" : "Podiceps nigricollis", - "Little Bittern" : "Ixobrychus minutus", - "Black-crowned Night Heron" : "Nycticorax nycticorax", - "Purple Heron" : "Ardea purpurea", - "White Stork" : "Ciconia ciconia", - "Spoonbill" : "Platalea leucorodia", - "Red-crested Pochard" : "Netta rufina", - "Common Eider" : "Somateria mollissima", - "Red Kite" : "Milvus milvus", - "Hen Harrier" : "Circus cyaneus", - "Montagu`s Harrier" : "Circus pygargus", - "Black Grouse" : "Tetrao tetrix", - "Grey Partridge" : "Perdix perdix", - "Spotted Crake" : "Porzana porzana", - "Corncrake" : "Crex crex", - "Common Crane" : "Grus grus", - "Avocet" : "Recurvirostra avosetta", - "Stone Curlew" : "Burhinus oedicnemus", - "Common Ringed Plover" : "Charadrius hiaticula", - "Kentish Plover" : "Charadrius alexandrinus", - "Ruff" : "Philomachus pugnax", - "Common Snipe" : "Gallinago gallinago", - "Black-tailed Godwit" : "Limosa limosa", - "Common Redshank" : "Tringa totanus", - "Sandwich Tern" : "Sterna sandvicensis", - "Common Tern" : "Sterna hirundo", - "Arctic Tern" : "Sterna paradisaea", - "Little Tern" : "Sternula albifrons", - "Black Tern" : "Chlidonias niger", - "Barn Owl" : "Tyto alba", - "Little Owl" : "Athene noctua", - "Short-eared Owl" : "Asio flammeus", - "European Nightjar" : "Caprimulgus europaeus", - "Common Kingfisher" : "Alcedo atthis", - "Eurasian Hoopoe" : "Upupa epops", - "Eurasian Wryneck" : "Jynx torquilla", - "European Green Woodpecker" : "Picus viridis", - "Crested Lark" : "Galerida cristata", - "White-headed Duck" : "Oxyura leucocephala", - "Pale-bellied Brent Goose" : "Branta hrota", - "Tawny Pipit" : "Anthus campestris", - "Whinchat" : "Saxicola rubetra", - "European Stonechat" : "Saxicola rubicola", - "Northern Wheatear" : "Oenanthe oenanthe", - "Savi`s Warbler" : "Locustella luscinioides", - "Sedge Warbler" : "Acrocephalus schoenobaenus", - "Great Reed Warbler" : "Acrocephalus arundinaceus", - "Bearded Reedling" : "Panurus biarmicus", - "Red-backed Shrike" : "Lanius collurio", - "Great Grey Shrike" : "Lanius excubitor", - "Woodchat Shrike" : "Lanius senator", - "Common Raven" : "Corvus corax", - "Yellowhammer" : "Emberiza citrinella", - "Ortolan Bunting" : "Emberiza hortulana", - "Corn Bunting" : "Emberiza calandra", - "Great Cormorant" : "Phalacrocorax carbo", - "Hawfinch" : "Coccothraustes coccothraustes", - "Common Shelduck" : "Tadorna tadorna", - "Bluethroat" : "Luscinia svecica", - "Grey Heron" : "Ardea cinerea", - "Barn Swallow" : "Hirundo rustica", - "Hooded Crow" : "Corvus cornix", - "Dunlin" : "Calidris alpina", - "Eurasian Pied Flycatcher" : "Ficedula hypoleuca", - "Eurasian Nuthatch" : "Sitta europaea", - "Short-toed Tree Creeper" : "Certhia brachydactyla", - "Wood Lark" : "Lullula arborea", - "Tree Pipit" : "Anthus trivialis", - "Eurasian Hobby" : "Falco subbuteo", - "Marsh Warbler" : "Acrocephalus palustris", - "Wood Sandpiper" : "Tringa glareola", - "Tawny Owl" : "Strix aluco", - "Lesser Whitethroat" : "Sylvia curruca", - "Barnacle Goose" : "Branta leucopsis", - "Common Goldeneye" : "Bucephala clangula", - "Western Marsh Harrier" : "Circus aeruginosus", - "Common Buzzard" : "Buteo buteo", - "Sanderling" : "Calidris alba", - "Little Gull" : "Larus minutus", - "Eurasian Magpie" : "Pica pica", - "Willow Warbler" : "Phylloscopus trochilus", - "Wood Warbler" : "Phylloscopus sibilatrix", - "Great Crested Grebe" : "Podiceps cristatus", - "Eurasian Jay" : "Garrulus glandarius", - "Common Redstart" : "Phoenicurus phoenicurus", - "Blue-headed Wagtail" : "Motacilla flava", - "Common Swift" : "Apus apus", - "Marsh Tit" : "Poecile palustris", - "Goldcrest" : "Regulus regulus", - "European Golden Plover" : "Pluvialis apricaria", - "Eurasian Bullfinch" : "Pyrrhula pyrrhula", - "Common Whitethroat" : "Sylvia communis", - "Meadow Pipit" : "Anthus pratensis", - "Greylag Goose" : "Anser anser", - "Spotted Flycatcher" : "Muscicapa striata", - "European Greenfinch" : "Carduelis chloris", - "Common Greenshank" : "Tringa nebularia", - "Great Spotted Woodpecker" : "Dendrocopos major", - "Greater Canada Goose" : "Branta canadensis", - "Mistle Thrush" : "Turdus viscivorus", - "Great Black-backed Gull" : "Larus marinus", - "Goosander" : "Mergus merganser", - "Great Egret" : "Casmerodius albus", - "Northern Goshawk" : "Accipiter gentilis", - "Dunnock" : "Prunella modularis", - "Stock Dove" : "Columba oenas", - "Common Wood Pigeon" : "Columba palumbus", - "Eurasian Woodcock" : "Scolopax rusticola", - "House Sparrow" : "Passer domesticus", - "Common House Martin" : "Delichon urbicum", - "Red Knot" : "Calidris canutus", - "Western Jackdaw" : "Corvus monedula", - "Brambling" : "Fringilla montifringilla", - "Northern Lapwing" : "Vanellus vanellus", - "European Reed Warbler" : "Acrocephalus scirpaceus", - "Lesser Black-backed Gull" : "Larus fuscus", - "Little Egret" : "Egretta garzetta", - "Little Stint" : "Calidris minuta", - "Common Linnet" : "Carduelis cannabina", - "Mute Swan" : "Cygnus olor", - "Common Cuckoo" : "Cuculus canorus", - "Black-headed Gull" : "Larus ridibundus", - "Greater White-fronted Goose" : "Anser albifrons", - "Great Tit" : "Parus major", - "Redwing" : "Turdus iliacus", - "Gadwall" : "Anas strepera", - "Fieldfare" : "Turdus pilaris", - "Tufted Duck" : "Aythya fuligula", - "Crested Tit" : "Lophophanes cristatus", - "Willow Tit" : "Poecile montanus", - "Eurasian Coot" : "Fulica atra", - "Common Blackbird" : "Turdus merula", - "Smew" : "Mergus albellus", - "Common Sandpiper" : "Actitis hypoleucos", - "Sand Martin" : "Riparia riparia", - "Purple Sandpiper" : "Calidris maritima", - "Northern Pintail" : "Anas acuta", - "Blue Tit" : "Cyanistes caeruleus", - "European Goldfinch" : "Carduelis carduelis", - "Eurasian Whimbrel" : "Numenius phaeopus", - "Common Reed Bunting" : "Emberiza schoeniclus", - "Eurasian Tree Sparrow" : "Passer montanus", - "Rook" : "Corvus frugilegus", - "European Robin" : "Erithacus rubecula", - "Bar-tailed Godwit" : "Limosa lapponica", - "Dark-bellied Brent Goose" : "Branta bernicla", - "Eurasian Oystercatcher" : "Haematopus ostralegus", - "Eurasian Siskin" : "Carduelis spinus", - "Northern Shoveler" : "Anas clypeata", - "Eurasian Wigeon" : "Anas penelope", - "Eurasian Sparrow Hawk" : "Accipiter nisus", - "Icterine Warbler" : "Hippolais icterina", - "Common Starling" : "Sturnus vulgaris", - "Long-tailed Tit" : "Aegithalos caudatus", - "Ruddy Turnstone" : "Arenaria interpres", - "Mew Gull" : "Larus canus", - "Common Pochard" : "Aythya ferina", - "Common Chiffchaff" : "Phylloscopus collybita", - "Greater Scaup" : "Aythya marila", - "Common Kestrel" : "Falco tinnunculus", - "Garden Warbler" : "Sylvia borin", - "Eurasian Collared Dove" : "Streptopelia decaocto", - "Eurasian Skylark" : "Alauda arvensis", - "Common Chaffinch" : "Fringilla coelebs", - "Common Moorhen" : "Gallinula chloropus", - "Water Pipit" : "Anthus spinoletta", - "Mallard" : "Anas platyrhynchos", - "Winter Wren" : "Troglodytes troglodytes", - "Common Teal" : "Anas crecca", - "Green Sandpiper" : "Tringa ochropus", - "White Wagtail" : "Motacilla alba", - "Eurasian Curlew" : "Numenius arquata", - "Song Thrush" : "Turdus philomelos", - "European Herring Gull" : "Larus argentatus", - "Grey Plover" : "Pluvialis squatarola", - "Carrion Crow" : "Corvus corone", - "Coal Tit" : "Periparus ater", - "Spotted Redshank" : "Tringa erythropus", - "Blackcap" : "Sylvia atricapilla", - "Egyptian Vulture" : "Neophron percnopterus", - "Razorbill" : "Alca torda", - "Alpine Swift" : "Apus melba", - "Long-legged Buzzard" : "Buteo rufinus", - "Audouin`s Gull" : "Larus audouinii", - "Balearic Shearwater" : "Puffinus mauretanicus", - "Upland Sandpiper" : "Bartramia longicauda", - "Greater Spotted Eagle" : "Aquila clanga", - "Ring Ouzel" : "Turdus torquatus", - "Yellow-browed Warbler" : "Phylloscopus inornatus", - "Blue Rock Thrush" : "Monticola solitarius", - "Buff-breasted Sandpiper" : "Tryngites subruficollis", - "Jack Snipe" : "Lymnocryptes minimus", - "White-rumped Sandpiper" : "Calidris fuscicollis", - "Ruddy Shelduck" : "Tadorna ferruginea", - "Cetti's Warbler" : "Cettia cetti", - "Citrine Wagtail" : "Motacilla citreola", - "Roseate Tern" : "Sterna dougallii", - "Black-legged Kittiwake" : "Rissa tridactyla", - "Pygmy Cormorant" : "Phalacrocorax pygmeus", - "Booted Eagle" : "Aquila pennata", - "Lesser White-fronted Goose" : "Anser erythropus", - "Little Bunting" : "Emberiza pusilla", - "Eleonora's Falcon" : "Falco eleonorae", - "European Serin" : "Serinus serinus", - "Twite" : "Carduelis flavirostris", - "Yellow-legged Gull" : "Larus michahellis", - "Gyr Falcon" : "Falco rusticolus", - "Greenish Warbler" : "Phylloscopus trochiloides", - "Red-necked Phalarope" : "Phalaropus lobatus", - "Mealy Redpoll" : "Carduelis flammea", - "Glaucous Gull" : "Larus hyperboreus", - "Great Skua" : "Stercorarius skua", - "Great Bustard" : "Otis tarda", - "Velvet Scoter" : "Melanitta fusca", - "Pine Grosbeak" : "Pinicola enucleator", - "House Crow" : "Corvus splendens", - "Hume`s Leaf Warbler" : "Phylloscopus humei", - "Great Northern Loon" : "Gavia immer", - "Long-tailed Duck" : "Clangula hyemalis", - "Lapland Longspur" : "Calcarius lapponicus", - "Northern Gannet" : "Morus bassanus", - "Eastern Imperial Eagle" : "Aquila heliaca", - "Little Auk" : "Alle alle", - "Lesser Spotted Woodpecker" : "Dendrocopos minor", - "Iceland Gull" : "Larus glaucoides", - "Parasitic Jaeger" : "Stercorarius parasiticus", - "Bewick`s Swan" : "Cygnus bewickii", - "Little Bustard" : "Tetrax tetrax", - "Little Crake" : "Porzana parva", - "Baillon`s Crake" : "Porzana pusilla", - "Long-tailed Jaeger" : "Stercorarius longicaudus", - "King Eider" : "Somateria spectabilis", - "Greater Short-toed Lark" : "Calandrella brachydactyla", - "Houbara Bustard" : "Chlamydotis undulata", - "Curlew Sandpiper" : "Calidris ferruginea", - "Common Crossbill" : "Loxia curvirostra", - "European Shag" : "Phalacrocorax aristotelis", - "Horned Grebe" : "Podiceps auritus", - "Common Quail" : "Coturnix coturnix", - "Bearded Vulture" : "Gypaetus barbatus", - "Lanner Falcon" : "Falco biarmicus", - "Middle Spotted Woodpecker" : "Dendrocopos medius", - "Pomarine Jaeger" : "Stercorarius pomarinus", - "Red-breasted Merganser" : "Mergus serrator", - "Eurasian Black Vulture" : "Aegypius monachus", - "Eurasian Dotterel" : "Charadrius morinellus", - "Common Nightingale" : "Luscinia megarhynchos", - "Northern willow warbler" : "Phylloscopus trochilus acredula", - "Manx Shearwater" : "Puffinus puffinus", - "Northern Fulmar" : "Fulmarus glacialis", - "Eurasian Eagle Owl" : "Bubo bubo", - "Orphean Warbler" : "Sylvia hortensis", - "Melodious Warbler" : "Hippolais polyglotta", - "Pallas's Leaf Warbler" : "Phylloscopus proregulus", - "Atlantic Puffin" : "Fratercula arctica", - "Black-throated Loon" : "Gavia arctica", - "Bohemian Waxwing" : "Bombycilla garrulus", - "Marsh Sandpiper" : "Tringa stagnatilis", - "Great Snipe" : "Gallinago media", - "Squacco Heron" : "Ardeola ralloides", - "Long-eared Owl" : "Asio otus", - "Caspian Tern" : "Hydroprogne caspia", - "Red-breasted Goose" : "Branta ruficollis", - "Red-throated Loon" : "Gavia stellata", - "Common Rosefinch" : "Carpodacus erythrinus", - "Red-footed Falcon" : "Falco vespertinus", - "Ross's Goose" : "Anser rossii", - "Red Phalarope" : "Phalaropus fulicarius", - "Pied Wagtail" : "Motacilla yarrellii", - "Rose-coloured Starling" : "Sturnus roseus", - "Rough-legged Buzzard" : "Buteo lagopus", - "Saker Falcon" : "Falco cherrug", - "European Roller" : "Coracias garrulus", - "Short-toed Eagle" : "Circaetus gallicus", - "Peregrine Falcon" : "Falco peregrinus", - "Merlin" : "Falco columbarius", - "Snow Goose" : "Anser caerulescens", - "Snowy Owl" : "Bubo scandiacus", - "Snow Bunting" : "Plectrophenax nivalis", - "Common Grasshopper Warbler" : "Locustella naevia", - "Golden Eagle" : "Aquila chrysaetos", - "Black-winged Stilt" : "Himantopus himantopus", - "Steppe Eagle" : "Aquila nipalensis", - "Pallid Harrier" : "Circus macrourus", - "European Storm-petrel" : "Hydrobates pelagicus", - "Horned Lark" : "Eremophila alpestris", - "Eurasian Treecreeper" : "Certhia familiaris", - "Taiga Bean Goose" : "Anser fabalis", - "Temminck`s Stint" : "Calidris temminckii", - "Terek Sandpiper" : "Xenus cinereus", - "Tundra Bean Goose" : "Anser serrirostris", - "European Turtle Dove" : "Streptopelia turtur", - "Leach`s Storm-petrel" : "Oceanodroma leucorhoa", - "Eurasian Griffon Vulture" : "Gyps fulvus", - "Paddyfield Warbler" : "Acrocephalus agricola", - "Osprey" : "Pandion haliaetus", - "Firecrest" : "Regulus ignicapilla", - "Water Rail" : "Rallus aquaticus", - "European Honey Buzzard" : "Pernis apivorus", - "Eurasian Golden Oriole" : "Oriolus oriolus", - "Whooper Swan" : "Cygnus cygnus", - "Two-barred Crossbill" : "Loxia leucoptera", - "White-tailed Eagle" : "Haliaeetus albicilla", - "Atlantic Murre" : "Uria aalge", - "Garganey" : "Anas querquedula", - "Black Redstart" : "Phoenicurus ochruros", - "Common Scoter" : "Melanitta nigra", - "Rock Pipit" : "Anthus petrosus", - "Lesser Spotted Eagle" : "Aquila pomarina", - "Cattle Egret" : "Bubulcus ibis", - "White-winged Black Tern" : "Chlidonias leucopterus", - "Black Stork" : "Ciconia nigra", - "Mediterranean Gull" : "Larus melanocephalus", - "Black Kite" : "Milvus migrans", - "Yellow Wagtail" : "Motacilla flavissima", - "Red-necked Grebe" : "Podiceps grisegena", - "Gull-billed Tern" : "Gelochelidon nilotica", - "Pectoral Sandpiper" : "Calidris melanotos", - "Barred Warbler" : "Sylvia nisoria", - "Red-throated Pipit" : "Anthus cervinus", - "Grey Wagtail" : "Motacilla cinerea", - "Richard`s Pipit" : "Anthus richardi", - "Black Woodpecker" : "Dryocopus martius", - "Little Ringed Plover" : "Charadrius dubius", - "Whiskered Tern" : "Chlidonias hybrida", - "Lesser Redpoll" : "Carduelis cabaret", - "Pallas' Bunting" : "Emberiza pallasi", - "Ferruginous Duck" : "Aythya nyroca", - "Whistling Swan" : "Cygnus columbianus", - "Black Brant" : "Branta nigricans", - "Marbled Teal" : "Marmaronetta angustirostris", - "Canvasback" : "Aythya valisineria", - "Redhead" : "Aythya americana", - "Lesser Scaup" : "Aythya affinis", - "Steller`s Eider" : "Polysticta stelleri", - "Spectacled Eider" : "Somateria fischeri", - "Harlequin Duck" : "Histronicus histrionicus", - "Black Scoter" : "Melanitta americana", - "Surf Scoter" : "Melanitta perspicillata", - "Barrow`s Goldeneye" : "Bucephala islandica", - "Falcated Duck" : "Anas falcata", - "American Wigeon" : "Anas americana", - "Blue-winged Teal" : "Anas discors", - "American Black Duck" : "Anas rubripes", - "Baikal Teal" : "Anas formosa", - "Green-Winged Teal" : "Anas carolinensis", - "Hazel Grouse" : "Bonasa bonasia", - "Rock Partridge" : "Alectoris graeca", - "Red-legged Partridge" : "Alectoris rufa", - "Yellow-billed Loon" : "Gavia adamsii", - "Cory`s Shearwater" : "Calonectris borealis", - "Madeiran Storm-Petrel" : "Oceanodroma castro", - "Great White Pelican" : "Pelecanus onocrotalus", - "Dalmatian Pelican" : "Pelecanus crispus", - "American Bittern" : "Botaurus lentiginosus", - "Glossy Ibis" : "Plegadis falcinellus", - "Spanish Imperial Eagle" : "Aquila adalberti", - "Lesser Kestrel" : "Falco naumanni", - "Crab-Plover" : "Dromas ardeola", - "Cream-coloured Courser" : "Cursorius cursor", - "Collared Pratincole" : "Glareola pratincola", - "Black-winged Pratincole" : "Glareola nordmanni", - "Killdeer" : "Charadrius vociferus", - "Lesser Sand Plover" : "Charadrius mongolus", - "Greater Sand Plover" : "Charadrius leschenaultii", - "Caspian Plover" : "Charadrius asiaticus", - "American Golden Plover" : "Pluvialis dominica", - "Pacific Golden Plover" : "Pluvialis fulva", - "Sharp-tailed Sandpiper" : "Calidris acuminata", - "Broad-billed Sandpiper" : "Limicola falcinellus", - "Spoon-Billed Sandpiper" : "Eurynorhynchus pygmaeus", - "Short-Billed Dowitcher" : "Limnodromus griseus", - "Long-billed Dowitcher" : "Limnodromus scolopaceus", - "Hudsonian Godwit" : "Limosa haemastica", - "Little Curlew" : "Numenius minutus", - "Lesser Yellowlegs" : "Tringa flavipes", - "Wilson`s Phalarope" : "Phalaropus tricolor", - "Pallas`s Gull" : "Larus ichthyaetus", - "Laughing Gull" : "Larus atricilla", - "Franklin`s Gull" : "Larus pipixcan", - "Bonaparte`s Gull" : "Larus philadelphia", - "Ring-billed Gull" : "Larus delawarensis", - "American Herring Gull" : "Larus smithsonianus", - "Caspian Gull" : "Larus cachinnans", - "Ivory Gull" : "Pagophila eburnea", - "Royal Tern" : "Sterna maxima", - "Brünnich`s Murre" : "Uria lomvia", - "Crested Auklet" : "Aethia cristatella", - "Parakeet Auklet" : "Cyclorrhynchus psittacula", - "Tufted Puffin" : "Lunda cirrhata", - "Laughing Dove" : "Streptopelia senegalensis", - "Great Spotted Cuckoo" : "Clamator glandarius", - "Great Grey Owl" : "Strix nebulosa", - "Tengmalm`s Owl" : "Aegolius funereus", - "Red-Necked Nightjar" : "Caprimulgus ruficollis", - "Chimney Swift" : "Chaetura pelagica", - "Green Bea-Eater" : "Merops orientalis", - "Grey-headed Woodpecker" : "Picus canus", - "Lesser Short-Toed Lark" : "Calandrella rufescens", - "Eurasian Crag Martin" : "Hirundo rupestris", - "Red-rumped Swallow" : "Cecropis daurica", - "Blyth`s Pipit" : "Anthus godlewskii", - "Pechora Pipit" : "Anthus gustavi", - "Grey-headed Wagtail" : "Motacilla thunbergi", - "Yellow-Headed Wagtail" : "Motacilla lutea", - "White-throated Dipper" : "Cinclus cinclus", - "Rufous-Tailed Scrub Robin" : "Cercotrichas galactotes", - "Thrush Nightingale" : "Luscinia luscinia", - "White-throated Robin" : "Irania gutturalis", - "Caspian Stonechat" : "Saxicola maura variegata", - "Western Black-eared Wheatear" : "Oenanthe hispanica", - "Rufous-tailed Rock Thrush" : "Monticola saxatilis", - "Red-throated Thrush/Black-throated" : "Turdus ruficollis", - "American Robin" : "Turdus migratorius", - "Zitting Cisticola" : "Cisticola juncidis", - "Lanceolated Warbler" : "Locustella lanceolata", - "River Warbler" : "Locustella fluviatilis", - "Blyth`s Reed Warbler" : "Acrocephalus dumetorum", - "Caspian Reed Warbler" : "Acrocephalus fuscus", - "Aquatic Warbler" : "Acrocephalus paludicola", - "Booted Warbler" : "Acrocephalus caligatus", - "Marmora's Warbler" : "Sylvia sarda", - "Dartford Warbler" : "Sylvia undata", - "Subalpine Warbler" : "Sylvia cantillans", - "Ménétries's Warbler" : "Sylvia mystacea", - "Rüppel's Warbler" : "Sylvia rueppelli", - "Asian Desert Warbler" : "Sylvia nana", - "Western Orphean Warbler" : "Sylvia hortensis hortensis", - "Arctic Warbler" : "Phylloscopus borealis", - "Radde`s Warbler" : "Phylloscopus schwarzi", - "Western Bonelli`s Warbler" : "Phylloscopus bonelli", - "Red-breasted Flycatcher" : "Ficedula parva", - "Eurasian Penduline Tit" : "Remiz pendulinus", - "Daurian Shrike" : "Lanius isabellinus", - "Long-Tailed Shrike" : "Lanius schach", - "Lesser Grey Shrike" : "Lanius minor", - "Southern Grey Shrike" : "Lanius meridionalis", - "Masked Shrike" : "Lanius nubicus", - "Spotted Nutcracker" : "Nucifraga caryocatactes", - "Daurian Jackdaw" : "Corvus dauuricus", - "Purple-Backed Starling" : "Sturnus sturninus", - "Red-Fronted Serin" : "Serinus pusillus", - "Arctic Redpoll" : "Carduelis hornemanni", - "Scottish Crossbill" : "Loxia scotica", - "Parrot Crossbill" : "Loxia pytyopsittacus", - "Black-faced Bunting" : "Emberiza spodocephala", - "Pink-footed Goose" : "Anser brachyrhynchus", - "Black-winged Kite" : "Elanus caeruleus", - "European Bee-eater" : "Merops apiaster", - "Sabine`s Gull" : "Larus sabini", - "Sooty Shearwater" : "Puffinus griseus", - "Lesser Canada Goose" : "Branta hutchinsii", - "Ring-necked Duck" : "Aythya collaris", - "Greater Flamingo" : "Phoenicopterus roseus", - "Iberian Chiffchaff" : "Phylloscopus ibericus", - "Ashy-headed Wagtail" : "Motacilla cinereocapilla", - "Stilt Sandpiper" : "Calidris himantopus", - "Siberian Stonechat" : "Saxicola maurus", - "Greater Yellowlegs" : "Tringa melanoleuca", - "Forster`s Tern" : "Sterna forsteri", - "Dusky Warbler" : "Phylloscopus fuscatus", - "Cirl Bunting" : "Emberiza cirlus", - "Olive-backed Pipit" : "Anthus hodgsoni", - "Sociable Lapwing" : "Vanellus gregarius", - "Spotted Sandpiper" : "Actitis macularius", - "Baird`s Sandpiper" : "Calidris bairdii", - "Rustic Bunting" : "Emberiza rustica", - "Yellow-browed Bunting" : "Emberiza chrysophrys", - "Great Shearwater" : "Puffinus gravis", - "Bonelli`s Eagle" : "Aquila fasciata", - "Calandra Lark" : "Melanocorypha calandra", - "Sardinian Warbler" : "Sylvia melanocephala", - "Ross's Gull" : "Larus roseus", - "Yellow-Breasted Bunting" : "Emberiza aureola", - "Pine Bunting" : "Emberiza leucocephalos", - "Black Guillemot" : "Cepphus grylle", - "Pied-billed Grebe" : "Podilymbus podiceps", - "Soft-plumaged Petrel" : "Pterodroma mollis", - "Bulwer's Petrel" : "Bulweria bulwerii", - "White-Faced Storm-Petrel" : "Pelagodroma marina", - "Pallas’s Fish Eagle" : "Haliaeetus leucoryphus", - "Sandhill Crane" : "Grus canadensis", - "Macqueen’s Bustard" : "Chlamydotis macqueenii", - "White-tailed Lapwing" : "Vanellus leucurus", - "Great Knot" : "Calidris tenuirostris", - "Semipalmated Sandpiper" : "Calidris pusilla", - "Red-necked Stint" : "Calidris ruficollis", - "Slender-billed Curlew" : "Numenius tenuirostris", - "Bridled Tern" : "Onychoprion anaethetus", - "Pallas’s Sandgrouse" : "Syrrhaptes paradoxus", - "European Scops Owl" : "Otus scops", - "Northern Hawk Owl" : "Surnia ulula", - "White-Throated Needletail" : "Hirundapus caudacutus", - "Belted Kingfisher" : "Ceryle alcyon", - "Blue-cheeked Bee-eater" : "Merops persicus", - "Black-headed Wagtail" : "Motacilla feldegg", - "Northern Mockingbird" : "Mimus polyglottos", - "Alpine Accentor" : "Prunella collaris", - "Red-flanked Bluetail" : "Tarsiger cyanurus", - "Isabelline Wheatear" : "Oenanthe isabellina", - "Pied Wheatear" : "Oenanthe pleschanka", - "Eastern Black-eared Wheatear" : "Oenanthe melanoleuca", - "Desert Wheatear" : "Oenanthe deserti", - "White`s Thrush" : "Zoothera aurea", - "Siberian Thrush" : "Zoothera sibirica", - "Eyebrowed Thrush" : "Turdus obscurus", - "Dusky Thrush" : "Turdus eunomus", - "Black-throated Thrush" : "Turdus atrogularis", - "Pallas`s Grasshopper Warbler" : "Locustella certhiola", - "Spectacled Warbler" : "Sylvia conspicillata", - "Two-barred Warbler" : "Phylloscopus plumbeitarsus", - "Eastern Bonelli’s Warbler" : "Phylloscopus orientalis", - "Collared Flycatcher" : "Ficedula albicollis", - "Wallcreeper" : "Tichodroma muraria", - "Turkestan Shrike" : "Lanius phoenicuroides", - "Steppe Grey Shrike" : "Lanius pallidirostris", - "Spanish Sparrow" : "Passer hispaniolensis", - "Red-eyed Vireo" : "Vireo olivaceus", - "Myrtle Warbler" : "Dendroica coronata", - "White-crowned Sparrow" : "Zonotrichia leucophrys", - "White-throated Sparrow" : "Zonotrichia albicollis", - "Cretzschmar`s Bunting" : "Emberiza caesia", - "Chestnut Bunting" : "Emberiza rutila", - "Red-headed Bunting" : "Emberiza bruniceps", - "Black-headed Bunting" : "Emberiza melanocephala", - "Indigo Bunting" : "Passerina cyanea", - "Balearic Woodchat Shrike" : "Lanius senator badius", - "Demoiselle Crane" : "Grus virgo", - "Chough" : "Pyrrhocorax pyrrhocorax", - "Red-Billed Chough" : "Pyrrhocorax graculus", - "Elegant Tern" : "Sterna elegans", - "Chukar" : "Alectoris chukar", - "Yellow-Billed Cuckoo" : "Coccyzus americanus", - "American Sandwich Tern" : "Sterna sandvicensis acuflavida", - "Olive-Tree Warbler" : "Hippolais olivetorum", - "Eastern Olivaceous Warbler" : "Acrocephalus pallidus", - "Indian Cormorant" : "Phalacrocorax fuscicollis", - "Spur-Winged Lapwing" : "Vanellus spinosus", - "Yelkouan Shearwater" : "Puffinus yelkouan", - "Trumpeter Finch" : "Bucanetes githagineus", - "Red Grouse" : "Lagopus scoticus", - "Rock Ptarmigan" : "Lagopus mutus", - "Long-Tailed Cormorant" : "Phalacrocorax africanus", - "Double-crested Cormorant" : "Phalacrocorax auritus", - "Magnificent Frigatebird" : "Fregata magnificens", - "Naumann's Thrush" : "Turdus naumanni", - "Oriental Pratincole" : "Glareola maldivarum", - "Bufflehead" : "Bucephala albeola", - "Snowfinch" : "Montifrigilla nivalis", - "Ural owl" : "Strix uralensis", - "Spanish Wagtail" : "Motacilla iberiae", - "Song Sparrow" : "Melospiza melodia", - "Rock Bunting" : "Emberiza cia", - "Siberian Rubythroat" : "Luscinia calliope", - "Pallid Swift" : "Apus pallidus", - "Eurasian Pygmy Owl" : "Glaucidium passerinum", - "Madeira Little Shearwater" : "Puffinus baroli", - "House Finch" : "Carpodacus mexicanus", - "Green Heron" : "Butorides virescens", - "Solitary Sandpiper" : "Tringa solitaria", - "Heuglin's Gull" : "Larus heuglini" + "Great Bittern": "Botaurus stellaris", + "Little Grebe": "Tachybaptus ruficollis", + "Black-necked Grebe": "Podiceps nigricollis", + "Little Bittern": "Ixobrychus minutus", + "Black-crowned Night Heron": "Nycticorax nycticorax", + "Purple Heron": "Ardea purpurea", + "White Stork": "Ciconia ciconia", + "Spoonbill": "Platalea leucorodia", + "Red-crested Pochard": "Netta rufina", + "Common Eider": "Somateria mollissima", + "Red Kite": "Milvus milvus", + "Hen Harrier": "Circus cyaneus", + "Montagu`s Harrier": "Circus pygargus", + "Black Grouse": "Tetrao tetrix", + "Grey Partridge": "Perdix perdix", + "Spotted Crake": "Porzana porzana", + "Corncrake": "Crex crex", + "Common Crane": "Grus grus", + "Avocet": "Recurvirostra avosetta", + "Stone Curlew": "Burhinus oedicnemus", + "Common Ringed Plover": "Charadrius hiaticula", + "Kentish Plover": "Charadrius alexandrinus", + "Ruff": "Philomachus pugnax", + "Common Snipe": "Gallinago gallinago", + "Black-tailed Godwit": "Limosa limosa", + "Common Redshank": "Tringa totanus", + "Sandwich Tern": "Sterna sandvicensis", + "Common Tern": "Sterna hirundo", + "Arctic Tern": "Sterna paradisaea", + "Little Tern": "Sternula albifrons", + "Black Tern": "Chlidonias niger", + "Barn Owl": "Tyto alba", + "Little Owl": "Athene noctua", + "Short-eared Owl": "Asio flammeus", + "European Nightjar": "Caprimulgus europaeus", + "Common Kingfisher": "Alcedo atthis", + "Eurasian Hoopoe": "Upupa epops", + "Eurasian Wryneck": "Jynx torquilla", + "European Green Woodpecker": "Picus viridis", + "Crested Lark": "Galerida cristata", + "White-headed Duck": "Oxyura leucocephala", + "Pale-bellied Brent Goose": "Branta hrota", + "Tawny Pipit": "Anthus campestris", + "Whinchat": "Saxicola rubetra", + "European Stonechat": "Saxicola rubicola", + "Northern Wheatear": "Oenanthe oenanthe", + "Savi`s Warbler": "Locustella luscinioides", + "Sedge Warbler": "Acrocephalus schoenobaenus", + "Great Reed Warbler": "Acrocephalus arundinaceus", + "Bearded Reedling": "Panurus biarmicus", + "Red-backed Shrike": "Lanius collurio", + "Great Grey Shrike": "Lanius excubitor", + "Woodchat Shrike": "Lanius senator", + "Common Raven": "Corvus corax", + "Yellowhammer": "Emberiza citrinella", + "Ortolan Bunting": "Emberiza hortulana", + "Corn Bunting": "Emberiza calandra", + "Great Cormorant": "Phalacrocorax carbo", + "Hawfinch": "Coccothraustes coccothraustes", + "Common Shelduck": "Tadorna tadorna", + "Bluethroat": "Luscinia svecica", + "Grey Heron": "Ardea cinerea", + "Barn Swallow": "Hirundo rustica", + "Hooded Crow": "Corvus cornix", + "Dunlin": "Calidris alpina", + "Eurasian Pied Flycatcher": "Ficedula hypoleuca", + "Eurasian Nuthatch": "Sitta europaea", + "Short-toed Tree Creeper": "Certhia brachydactyla", + "Wood Lark": "Lullula arborea", + "Tree Pipit": "Anthus trivialis", + "Eurasian Hobby": "Falco subbuteo", + "Marsh Warbler": "Acrocephalus palustris", + "Wood Sandpiper": "Tringa glareola", + "Tawny Owl": "Strix aluco", + "Lesser Whitethroat": "Sylvia curruca", + "Barnacle Goose": "Branta leucopsis", + "Common Goldeneye": "Bucephala clangula", + "Western Marsh Harrier": "Circus aeruginosus", + "Common Buzzard": "Buteo buteo", + "Sanderling": "Calidris alba", + "Little Gull": "Larus minutus", + "Eurasian Magpie": "Pica pica", + "Willow Warbler": "Phylloscopus trochilus", + "Wood Warbler": "Phylloscopus sibilatrix", + "Great Crested Grebe": "Podiceps cristatus", + "Eurasian Jay": "Garrulus glandarius", + "Common Redstart": "Phoenicurus phoenicurus", + "Blue-headed Wagtail": "Motacilla flava", + "Common Swift": "Apus apus", + "Marsh Tit": "Poecile palustris", + "Goldcrest": "Regulus regulus", + "European Golden Plover": "Pluvialis apricaria", + "Eurasian Bullfinch": "Pyrrhula pyrrhula", + "Common Whitethroat": "Sylvia communis", + "Meadow Pipit": "Anthus pratensis", + "Greylag Goose": "Anser anser", + "Spotted Flycatcher": "Muscicapa striata", + "European Greenfinch": "Carduelis chloris", + "Common Greenshank": "Tringa nebularia", + "Great Spotted Woodpecker": "Dendrocopos major", + "Greater Canada Goose": "Branta canadensis", + "Mistle Thrush": "Turdus viscivorus", + "Great Black-backed Gull": "Larus marinus", + "Goosander": "Mergus merganser", + "Great Egret": "Casmerodius albus", + "Northern Goshawk": "Accipiter gentilis", + "Dunnock": "Prunella modularis", + "Stock Dove": "Columba oenas", + "Common Wood Pigeon": "Columba palumbus", + "Eurasian Woodcock": "Scolopax rusticola", + "House Sparrow": "Passer domesticus", + "Common House Martin": "Delichon urbicum", + "Red Knot": "Calidris canutus", + "Western Jackdaw": "Corvus monedula", + "Brambling": "Fringilla montifringilla", + "Northern Lapwing": "Vanellus vanellus", + "European Reed Warbler": "Acrocephalus scirpaceus", + "Lesser Black-backed Gull": "Larus fuscus", + "Little Egret": "Egretta garzetta", + "Little Stint": "Calidris minuta", + "Common Linnet": "Carduelis cannabina", + "Mute Swan": "Cygnus olor", + "Common Cuckoo": "Cuculus canorus", + "Black-headed Gull": "Larus ridibundus", + "Greater White-fronted Goose": "Anser albifrons", + "Great Tit": "Parus major", + "Redwing": "Turdus iliacus", + "Gadwall": "Anas strepera", + "Fieldfare": "Turdus pilaris", + "Tufted Duck": "Aythya fuligula", + "Crested Tit": "Lophophanes cristatus", + "Willow Tit": "Poecile montanus", + "Eurasian Coot": "Fulica atra", + "Common Blackbird": "Turdus merula", + "Smew": "Mergus albellus", + "Common Sandpiper": "Actitis hypoleucos", + "Sand Martin": "Riparia riparia", + "Purple Sandpiper": "Calidris maritima", + "Northern Pintail": "Anas acuta", + "Blue Tit": "Cyanistes caeruleus", + "European Goldfinch": "Carduelis carduelis", + "Eurasian Whimbrel": "Numenius phaeopus", + "Common Reed Bunting": "Emberiza schoeniclus", + "Eurasian Tree Sparrow": "Passer montanus", + "Rook": "Corvus frugilegus", + "European Robin": "Erithacus rubecula", + "Bar-tailed Godwit": "Limosa lapponica", + "Dark-bellied Brent Goose": "Branta bernicla", + "Eurasian Oystercatcher": "Haematopus ostralegus", + "Eurasian Siskin": "Carduelis spinus", + "Northern Shoveler": "Anas clypeata", + "Eurasian Wigeon": "Anas penelope", + "Eurasian Sparrow Hawk": "Accipiter nisus", + "Icterine Warbler": "Hippolais icterina", + "Common Starling": "Sturnus vulgaris", + "Long-tailed Tit": "Aegithalos caudatus", + "Ruddy Turnstone": "Arenaria interpres", + "Mew Gull": "Larus canus", + "Common Pochard": "Aythya ferina", + "Common Chiffchaff": "Phylloscopus collybita", + "Greater Scaup": "Aythya marila", + "Common Kestrel": "Falco tinnunculus", + "Garden Warbler": "Sylvia borin", + "Eurasian Collared Dove": "Streptopelia decaocto", + "Eurasian Skylark": "Alauda arvensis", + "Common Chaffinch": "Fringilla coelebs", + "Common Moorhen": "Gallinula chloropus", + "Water Pipit": "Anthus spinoletta", + "Mallard": "Anas platyrhynchos", + "Winter Wren": "Troglodytes troglodytes", + "Common Teal": "Anas crecca", + "Green Sandpiper": "Tringa ochropus", + "White Wagtail": "Motacilla alba", + "Eurasian Curlew": "Numenius arquata", + "Song Thrush": "Turdus philomelos", + "European Herring Gull": "Larus argentatus", + "Grey Plover": "Pluvialis squatarola", + "Carrion Crow": "Corvus corone", + "Coal Tit": "Periparus ater", + "Spotted Redshank": "Tringa erythropus", + "Blackcap": "Sylvia atricapilla", + "Egyptian Vulture": "Neophron percnopterus", + "Razorbill": "Alca torda", + "Alpine Swift": "Apus melba", + "Long-legged Buzzard": "Buteo rufinus", + "Audouin`s Gull": "Larus audouinii", + "Balearic Shearwater": "Puffinus mauretanicus", + "Upland Sandpiper": "Bartramia longicauda", + "Greater Spotted Eagle": "Aquila clanga", + "Ring Ouzel": "Turdus torquatus", + "Yellow-browed Warbler": "Phylloscopus inornatus", + "Blue Rock Thrush": "Monticola solitarius", + "Buff-breasted Sandpiper": "Tryngites subruficollis", + "Jack Snipe": "Lymnocryptes minimus", + "White-rumped Sandpiper": "Calidris fuscicollis", + "Ruddy Shelduck": "Tadorna ferruginea", + "Cetti's Warbler": "Cettia cetti", + "Citrine Wagtail": "Motacilla citreola", + "Roseate Tern": "Sterna dougallii", + "Black-legged Kittiwake": "Rissa tridactyla", + "Pygmy Cormorant": "Phalacrocorax pygmeus", + "Booted Eagle": "Aquila pennata", + "Lesser White-fronted Goose": "Anser erythropus", + "Little Bunting": "Emberiza pusilla", + "Eleonora's Falcon": "Falco eleonorae", + "European Serin": "Serinus serinus", + "Twite": "Carduelis flavirostris", + "Yellow-legged Gull": "Larus michahellis", + "Gyr Falcon": "Falco rusticolus", + "Greenish Warbler": "Phylloscopus trochiloides", + "Red-necked Phalarope": "Phalaropus lobatus", + "Mealy Redpoll": "Carduelis flammea", + "Glaucous Gull": "Larus hyperboreus", + "Great Skua": "Stercorarius skua", + "Great Bustard": "Otis tarda", + "Velvet Scoter": "Melanitta fusca", + "Pine Grosbeak": "Pinicola enucleator", + "House Crow": "Corvus splendens", + "Hume`s Leaf Warbler": "Phylloscopus humei", + "Great Northern Loon": "Gavia immer", + "Long-tailed Duck": "Clangula hyemalis", + "Lapland Longspur": "Calcarius lapponicus", + "Northern Gannet": "Morus bassanus", + "Eastern Imperial Eagle": "Aquila heliaca", + "Little Auk": "Alle alle", + "Lesser Spotted Woodpecker": "Dendrocopos minor", + "Iceland Gull": "Larus glaucoides", + "Parasitic Jaeger": "Stercorarius parasiticus", + "Bewick`s Swan": "Cygnus bewickii", + "Little Bustard": "Tetrax tetrax", + "Little Crake": "Porzana parva", + "Baillon`s Crake": "Porzana pusilla", + "Long-tailed Jaeger": "Stercorarius longicaudus", + "King Eider": "Somateria spectabilis", + "Greater Short-toed Lark": "Calandrella brachydactyla", + "Houbara Bustard": "Chlamydotis undulata", + "Curlew Sandpiper": "Calidris ferruginea", + "Common Crossbill": "Loxia curvirostra", + "European Shag": "Phalacrocorax aristotelis", + "Horned Grebe": "Podiceps auritus", + "Common Quail": "Coturnix coturnix", + "Bearded Vulture": "Gypaetus barbatus", + "Lanner Falcon": "Falco biarmicus", + "Middle Spotted Woodpecker": "Dendrocopos medius", + "Pomarine Jaeger": "Stercorarius pomarinus", + "Red-breasted Merganser": "Mergus serrator", + "Eurasian Black Vulture": "Aegypius monachus", + "Eurasian Dotterel": "Charadrius morinellus", + "Common Nightingale": "Luscinia megarhynchos", + "Northern willow warbler": "Phylloscopus trochilus acredula", + "Manx Shearwater": "Puffinus puffinus", + "Northern Fulmar": "Fulmarus glacialis", + "Eurasian Eagle Owl": "Bubo bubo", + "Orphean Warbler": "Sylvia hortensis", + "Melodious Warbler": "Hippolais polyglotta", + "Pallas's Leaf Warbler": "Phylloscopus proregulus", + "Atlantic Puffin": "Fratercula arctica", + "Black-throated Loon": "Gavia arctica", + "Bohemian Waxwing": "Bombycilla garrulus", + "Marsh Sandpiper": "Tringa stagnatilis", + "Great Snipe": "Gallinago media", + "Squacco Heron": "Ardeola ralloides", + "Long-eared Owl": "Asio otus", + "Caspian Tern": "Hydroprogne caspia", + "Red-breasted Goose": "Branta ruficollis", + "Red-throated Loon": "Gavia stellata", + "Common Rosefinch": "Carpodacus erythrinus", + "Red-footed Falcon": "Falco vespertinus", + "Ross's Goose": "Anser rossii", + "Red Phalarope": "Phalaropus fulicarius", + "Pied Wagtail": "Motacilla yarrellii", + "Rose-coloured Starling": "Sturnus roseus", + "Rough-legged Buzzard": "Buteo lagopus", + "Saker Falcon": "Falco cherrug", + "European Roller": "Coracias garrulus", + "Short-toed Eagle": "Circaetus gallicus", + "Peregrine Falcon": "Falco peregrinus", + "Merlin": "Falco columbarius", + "Snow Goose": "Anser caerulescens", + "Snowy Owl": "Bubo scandiacus", + "Snow Bunting": "Plectrophenax nivalis", + "Common Grasshopper Warbler": "Locustella naevia", + "Golden Eagle": "Aquila chrysaetos", + "Black-winged Stilt": "Himantopus himantopus", + "Steppe Eagle": "Aquila nipalensis", + "Pallid Harrier": "Circus macrourus", + "European Storm-petrel": "Hydrobates pelagicus", + "Horned Lark": "Eremophila alpestris", + "Eurasian Treecreeper": "Certhia familiaris", + "Taiga Bean Goose": "Anser fabalis", + "Temminck`s Stint": "Calidris temminckii", + "Terek Sandpiper": "Xenus cinereus", + "Tundra Bean Goose": "Anser serrirostris", + "European Turtle Dove": "Streptopelia turtur", + "Leach`s Storm-petrel": "Oceanodroma leucorhoa", + "Eurasian Griffon Vulture": "Gyps fulvus", + "Paddyfield Warbler": "Acrocephalus agricola", + "Osprey": "Pandion haliaetus", + "Firecrest": "Regulus ignicapilla", + "Water Rail": "Rallus aquaticus", + "European Honey Buzzard": "Pernis apivorus", + "Eurasian Golden Oriole": "Oriolus oriolus", + "Whooper Swan": "Cygnus cygnus", + "Two-barred Crossbill": "Loxia leucoptera", + "White-tailed Eagle": "Haliaeetus albicilla", + "Atlantic Murre": "Uria aalge", + "Garganey": "Anas querquedula", + "Black Redstart": "Phoenicurus ochruros", + "Common Scoter": "Melanitta nigra", + "Rock Pipit": "Anthus petrosus", + "Lesser Spotted Eagle": "Aquila pomarina", + "Cattle Egret": "Bubulcus ibis", + "White-winged Black Tern": "Chlidonias leucopterus", + "Black Stork": "Ciconia nigra", + "Mediterranean Gull": "Larus melanocephalus", + "Black Kite": "Milvus migrans", + "Yellow Wagtail": "Motacilla flavissima", + "Red-necked Grebe": "Podiceps grisegena", + "Gull-billed Tern": "Gelochelidon nilotica", + "Pectoral Sandpiper": "Calidris melanotos", + "Barred Warbler": "Sylvia nisoria", + "Red-throated Pipit": "Anthus cervinus", + "Grey Wagtail": "Motacilla cinerea", + "Richard`s Pipit": "Anthus richardi", + "Black Woodpecker": "Dryocopus martius", + "Little Ringed Plover": "Charadrius dubius", + "Whiskered Tern": "Chlidonias hybrida", + "Lesser Redpoll": "Carduelis cabaret", + "Pallas' Bunting": "Emberiza pallasi", + "Ferruginous Duck": "Aythya nyroca", + "Whistling Swan": "Cygnus columbianus", + "Black Brant": "Branta nigricans", + "Marbled Teal": "Marmaronetta angustirostris", + "Canvasback": "Aythya valisineria", + "Redhead": "Aythya americana", + "Lesser Scaup": "Aythya affinis", + "Steller`s Eider": "Polysticta stelleri", + "Spectacled Eider": "Somateria fischeri", + "Harlequin Duck": "Histronicus histrionicus", + "Black Scoter": "Melanitta americana", + "Surf Scoter": "Melanitta perspicillata", + "Barrow`s Goldeneye": "Bucephala islandica", + "Falcated Duck": "Anas falcata", + "American Wigeon": "Anas americana", + "Blue-winged Teal": "Anas discors", + "American Black Duck": "Anas rubripes", + "Baikal Teal": "Anas formosa", + "Green-Winged Teal": "Anas carolinensis", + "Hazel Grouse": "Bonasa bonasia", + "Rock Partridge": "Alectoris graeca", + "Red-legged Partridge": "Alectoris rufa", + "Yellow-billed Loon": "Gavia adamsii", + "Cory`s Shearwater": "Calonectris borealis", + "Madeiran Storm-Petrel": "Oceanodroma castro", + "Great White Pelican": "Pelecanus onocrotalus", + "Dalmatian Pelican": "Pelecanus crispus", + "American Bittern": "Botaurus lentiginosus", + "Glossy Ibis": "Plegadis falcinellus", + "Spanish Imperial Eagle": "Aquila adalberti", + "Lesser Kestrel": "Falco naumanni", + "Crab-Plover": "Dromas ardeola", + "Cream-coloured Courser": "Cursorius cursor", + "Collared Pratincole": "Glareola pratincola", + "Black-winged Pratincole": "Glareola nordmanni", + "Killdeer": "Charadrius vociferus", + "Lesser Sand Plover": "Charadrius mongolus", + "Greater Sand Plover": "Charadrius leschenaultii", + "Caspian Plover": "Charadrius asiaticus", + "American Golden Plover": "Pluvialis dominica", + "Pacific Golden Plover": "Pluvialis fulva", + "Sharp-tailed Sandpiper": "Calidris acuminata", + "Broad-billed Sandpiper": "Limicola falcinellus", + "Spoon-Billed Sandpiper": "Eurynorhynchus pygmaeus", + "Short-Billed Dowitcher": "Limnodromus griseus", + "Long-billed Dowitcher": "Limnodromus scolopaceus", + "Hudsonian Godwit": "Limosa haemastica", + "Little Curlew": "Numenius minutus", + "Lesser Yellowlegs": "Tringa flavipes", + "Wilson`s Phalarope": "Phalaropus tricolor", + "Pallas`s Gull": "Larus ichthyaetus", + "Laughing Gull": "Larus atricilla", + "Franklin`s Gull": "Larus pipixcan", + "Bonaparte`s Gull": "Larus philadelphia", + "Ring-billed Gull": "Larus delawarensis", + "American Herring Gull": "Larus smithsonianus", + "Caspian Gull": "Larus cachinnans", + "Ivory Gull": "Pagophila eburnea", + "Royal Tern": "Sterna maxima", + "Brünnich`s Murre": "Uria lomvia", + "Crested Auklet": "Aethia cristatella", + "Parakeet Auklet": "Cyclorrhynchus psittacula", + "Tufted Puffin": "Lunda cirrhata", + "Laughing Dove": "Streptopelia senegalensis", + "Great Spotted Cuckoo": "Clamator glandarius", + "Great Grey Owl": "Strix nebulosa", + "Tengmalm`s Owl": "Aegolius funereus", + "Red-Necked Nightjar": "Caprimulgus ruficollis", + "Chimney Swift": "Chaetura pelagica", + "Green Bea-Eater": "Merops orientalis", + "Grey-headed Woodpecker": "Picus canus", + "Lesser Short-Toed Lark": "Calandrella rufescens", + "Eurasian Crag Martin": "Hirundo rupestris", + "Red-rumped Swallow": "Cecropis daurica", + "Blyth`s Pipit": "Anthus godlewskii", + "Pechora Pipit": "Anthus gustavi", + "Grey-headed Wagtail": "Motacilla thunbergi", + "Yellow-Headed Wagtail": "Motacilla lutea", + "White-throated Dipper": "Cinclus cinclus", + "Rufous-Tailed Scrub Robin": "Cercotrichas galactotes", + "Thrush Nightingale": "Luscinia luscinia", + "White-throated Robin": "Irania gutturalis", + "Caspian Stonechat": "Saxicola maura variegata", + "Western Black-eared Wheatear": "Oenanthe hispanica", + "Rufous-tailed Rock Thrush": "Monticola saxatilis", + "Red-throated Thrush/Black-throated": "Turdus ruficollis", + "American Robin": "Turdus migratorius", + "Zitting Cisticola": "Cisticola juncidis", + "Lanceolated Warbler": "Locustella lanceolata", + "River Warbler": "Locustella fluviatilis", + "Blyth`s Reed Warbler": "Acrocephalus dumetorum", + "Caspian Reed Warbler": "Acrocephalus fuscus", + "Aquatic Warbler": "Acrocephalus paludicola", + "Booted Warbler": "Acrocephalus caligatus", + "Marmora's Warbler": "Sylvia sarda", + "Dartford Warbler": "Sylvia undata", + "Subalpine Warbler": "Sylvia cantillans", + "Ménétries's Warbler": "Sylvia mystacea", + "Rüppel's Warbler": "Sylvia rueppelli", + "Asian Desert Warbler": "Sylvia nana", + "Western Orphean Warbler": "Sylvia hortensis hortensis", + "Arctic Warbler": "Phylloscopus borealis", + "Radde`s Warbler": "Phylloscopus schwarzi", + "Western Bonelli`s Warbler": "Phylloscopus bonelli", + "Red-breasted Flycatcher": "Ficedula parva", + "Eurasian Penduline Tit": "Remiz pendulinus", + "Daurian Shrike": "Lanius isabellinus", + "Long-Tailed Shrike": "Lanius schach", + "Lesser Grey Shrike": "Lanius minor", + "Southern Grey Shrike": "Lanius meridionalis", + "Masked Shrike": "Lanius nubicus", + "Spotted Nutcracker": "Nucifraga caryocatactes", + "Daurian Jackdaw": "Corvus dauuricus", + "Purple-Backed Starling": "Sturnus sturninus", + "Red-Fronted Serin": "Serinus pusillus", + "Arctic Redpoll": "Carduelis hornemanni", + "Scottish Crossbill": "Loxia scotica", + "Parrot Crossbill": "Loxia pytyopsittacus", + "Black-faced Bunting": "Emberiza spodocephala", + "Pink-footed Goose": "Anser brachyrhynchus", + "Black-winged Kite": "Elanus caeruleus", + "European Bee-eater": "Merops apiaster", + "Sabine`s Gull": "Larus sabini", + "Sooty Shearwater": "Puffinus griseus", + "Lesser Canada Goose": "Branta hutchinsii", + "Ring-necked Duck": "Aythya collaris", + "Greater Flamingo": "Phoenicopterus roseus", + "Iberian Chiffchaff": "Phylloscopus ibericus", + "Ashy-headed Wagtail": "Motacilla cinereocapilla", + "Stilt Sandpiper": "Calidris himantopus", + "Siberian Stonechat": "Saxicola maurus", + "Greater Yellowlegs": "Tringa melanoleuca", + "Forster`s Tern": "Sterna forsteri", + "Dusky Warbler": "Phylloscopus fuscatus", + "Cirl Bunting": "Emberiza cirlus", + "Olive-backed Pipit": "Anthus hodgsoni", + "Sociable Lapwing": "Vanellus gregarius", + "Spotted Sandpiper": "Actitis macularius", + "Baird`s Sandpiper": "Calidris bairdii", + "Rustic Bunting": "Emberiza rustica", + "Yellow-browed Bunting": "Emberiza chrysophrys", + "Great Shearwater": "Puffinus gravis", + "Bonelli`s Eagle": "Aquila fasciata", + "Calandra Lark": "Melanocorypha calandra", + "Sardinian Warbler": "Sylvia melanocephala", + "Ross's Gull": "Larus roseus", + "Yellow-Breasted Bunting": "Emberiza aureola", + "Pine Bunting": "Emberiza leucocephalos", + "Black Guillemot": "Cepphus grylle", + "Pied-billed Grebe": "Podilymbus podiceps", + "Soft-plumaged Petrel": "Pterodroma mollis", + "Bulwer's Petrel": "Bulweria bulwerii", + "White-Faced Storm-Petrel": "Pelagodroma marina", + "Pallas’s Fish Eagle": "Haliaeetus leucoryphus", + "Sandhill Crane": "Grus canadensis", + "Macqueen’s Bustard": "Chlamydotis macqueenii", + "White-tailed Lapwing": "Vanellus leucurus", + "Great Knot": "Calidris tenuirostris", + "Semipalmated Sandpiper": "Calidris pusilla", + "Red-necked Stint": "Calidris ruficollis", + "Slender-billed Curlew": "Numenius tenuirostris", + "Bridled Tern": "Onychoprion anaethetus", + "Pallas’s Sandgrouse": "Syrrhaptes paradoxus", + "European Scops Owl": "Otus scops", + "Northern Hawk Owl": "Surnia ulula", + "White-Throated Needletail": "Hirundapus caudacutus", + "Belted Kingfisher": "Ceryle alcyon", + "Blue-cheeked Bee-eater": "Merops persicus", + "Black-headed Wagtail": "Motacilla feldegg", + "Northern Mockingbird": "Mimus polyglottos", + "Alpine Accentor": "Prunella collaris", + "Red-flanked Bluetail": "Tarsiger cyanurus", + "Isabelline Wheatear": "Oenanthe isabellina", + "Pied Wheatear": "Oenanthe pleschanka", + "Eastern Black-eared Wheatear": "Oenanthe melanoleuca", + "Desert Wheatear": "Oenanthe deserti", + "White`s Thrush": "Zoothera aurea", + "Siberian Thrush": "Zoothera sibirica", + "Eyebrowed Thrush": "Turdus obscurus", + "Dusky Thrush": "Turdus eunomus", + "Black-throated Thrush": "Turdus atrogularis", + "Pallas`s Grasshopper Warbler": "Locustella certhiola", + "Spectacled Warbler": "Sylvia conspicillata", + "Two-barred Warbler": "Phylloscopus plumbeitarsus", + "Eastern Bonelli’s Warbler": "Phylloscopus orientalis", + "Collared Flycatcher": "Ficedula albicollis", + "Wallcreeper": "Tichodroma muraria", + "Turkestan Shrike": "Lanius phoenicuroides", + "Steppe Grey Shrike": "Lanius pallidirostris", + "Spanish Sparrow": "Passer hispaniolensis", + "Red-eyed Vireo": "Vireo olivaceus", + "Myrtle Warbler": "Dendroica coronata", + "White-crowned Sparrow": "Zonotrichia leucophrys", + "White-throated Sparrow": "Zonotrichia albicollis", + "Cretzschmar`s Bunting": "Emberiza caesia", + "Chestnut Bunting": "Emberiza rutila", + "Red-headed Bunting": "Emberiza bruniceps", + "Black-headed Bunting": "Emberiza melanocephala", + "Indigo Bunting": "Passerina cyanea", + "Balearic Woodchat Shrike": "Lanius senator badius", + "Demoiselle Crane": "Grus virgo", + "Chough": "Pyrrhocorax pyrrhocorax", + "Red-Billed Chough": "Pyrrhocorax graculus", + "Elegant Tern": "Sterna elegans", + "Chukar": "Alectoris chukar", + "Yellow-Billed Cuckoo": "Coccyzus americanus", + "American Sandwich Tern": "Sterna sandvicensis acuflavida", + "Olive-Tree Warbler": "Hippolais olivetorum", + "Eastern Olivaceous Warbler": "Acrocephalus pallidus", + "Indian Cormorant": "Phalacrocorax fuscicollis", + "Spur-Winged Lapwing": "Vanellus spinosus", + "Yelkouan Shearwater": "Puffinus yelkouan", + "Trumpeter Finch": "Bucanetes githagineus", + "Red Grouse": "Lagopus scoticus", + "Rock Ptarmigan": "Lagopus mutus", + "Long-Tailed Cormorant": "Phalacrocorax africanus", + "Double-crested Cormorant": "Phalacrocorax auritus", + "Magnificent Frigatebird": "Fregata magnificens", + "Naumann's Thrush": "Turdus naumanni", + "Oriental Pratincole": "Glareola maldivarum", + "Bufflehead": "Bucephala albeola", + "Snowfinch": "Montifrigilla nivalis", + "Ural owl": "Strix uralensis", + "Spanish Wagtail": "Motacilla iberiae", + "Song Sparrow": "Melospiza melodia", + "Rock Bunting": "Emberiza cia", + "Siberian Rubythroat": "Luscinia calliope", + "Pallid Swift": "Apus pallidus", + "Eurasian Pygmy Owl": "Glaucidium passerinum", + "Madeira Little Shearwater": "Puffinus baroli", + "House Finch": "Carpodacus mexicanus", + "Green Heron": "Butorides virescens", + "Solitary Sandpiper": "Tringa solitaria", + "Heuglin's Gull": "Larus heuglini" }; function searchResponse( term ) { term = term.toLowerCase(); @@ -584,7 +584,7 @@ for ( var key in database ) { if ( key.toLowerCase().indexOf( term ) !== -1 ) { result.push( { - id: database[key], + id: database[ key ], label: key, value: key } ); @@ -596,32 +596,32 @@ return result; } $.ajaxTransport( "json", function( options, originalOptions ) { - if ( options.url.indexOf( 'search.json' ) === -1 ) { + if ( options.url.indexOf( "search.json" ) === -1 ) { return; } return { - abort: function () {}, - send: function ( headers, completeCallback ) { - console.log( 'Mocked AJAX response for ' + options.url ); - var result = searchResponse( originalOptions.data.term || '' ); + abort: function() {}, + send: function( headers, completeCallback ) { + console.log( "Mocked AJAX response for " + options.url ); + var result = searchResponse( originalOptions.data.term || "" ); setTimeout( function() { - completeCallback( 200, 'OK', { text: JSON.stringify( result ) }, [] ); + completeCallback( 200, "OK", { text: JSON.stringify( result ) }, [] ); }, 2000 ); } }; } ); $.ajaxTransport( "script", function( options, originalOptions ) { - if ( options.url.indexOf( 'search.json' ) === -1 ) { + if ( options.url.indexOf( "search.json" ) === -1 ) { return; } return { - abort: function () {}, - send: function ( headers, completeCallback ) { - console.log( 'Mocked AJAX response for ' + options.url ); - var result = searchResponse( originalOptions.data.term || '' ); - var script = options.jsonpCallback + '(' + JSON.stringify( result ) + ')'; + abort: function() {}, + send: function( headers, completeCallback ) { + console.log( "Mocked AJAX response for " + options.url ); + var result = searchResponse( originalOptions.data.term || "" ); + var script = options.jsonpCallback + "(" + JSON.stringify( result ) + ")"; setTimeout( function() { - completeCallback( 200, 'OK', { text: script }, [] ); + completeCallback( 200, "OK", { text: script }, [] ); }, 2000 ); } }; diff --git a/ui/.eslintrc.json b/ui/.eslintrc.json index 004803729b..eaba81af2a 100644 --- a/ui/.eslintrc.json +++ b/ui/.eslintrc.json @@ -1,4 +1,8 @@ { + "root": true, + + "extends": "jquery", + "parserOptions": { "ecmaVersion": 5 }, From e399092c3ef6ea29443e879695268fc09c6ea9bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski-Owczarek?= Date: Fri, 25 Oct 2024 23:45:12 +0200 Subject: [PATCH 28/53] Build: Add a CodeQL non-mandatory check This is backported from Core at: https://github.com/jquery/jquery/blob/19716254877870ecd649272cadd00a0d0ff8be01/.github/workflows/codeql-analysis.yml Closes gh-2306 --- .github/workflows/codeql-analysis.yml | 58 +++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000000..981b6912b8 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,58 @@ +name: "Code scanning - action" + +on: + pull_request: + push: + branches-ignore: "dependabot/**" + schedule: + - cron: "0 4 * * 6" + +permissions: + contents: read # to fetch code (actions/checkout) + +jobs: + CodeQL-Build: + permissions: + contents: read # to fetch code (actions/checkout) + security-events: write # (github/codeql-action/autobuild) + + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + with: + # We must fetch at least the immediate parents so that if this is + # a pull request then we can checkout the head. + fetch-depth: 2 + + # If this run was triggered by a pull request event, then checkout + # the head of the pull request instead of the merge commit. + - run: git checkout HEAD^2 + if: ${{ github.event_name == 'pull_request' }} + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 + # Override language selection by uncommenting this and choosing your languages + # with: + # languages: go, javascript, csharp, python, cpp, java + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 From ebdcd0d866a5d318c5255c2d6404867878d06d47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski-Owczarek?= Date: Fri, 25 Oct 2024 23:46:00 +0200 Subject: [PATCH 29/53] Tests: Fix titles of `jquery-patch.js` tests The pages were erroneously titled after "Form Reset Mixin". Closes gh-2308 --- tests/unit/jquery-patch/all.html | 2 +- tests/unit/jquery-patch/jquery-patch.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/jquery-patch/all.html b/tests/unit/jquery-patch/all.html index d26b503734..9daa8c6b24 100644 --- a/tests/unit/jquery-patch/all.html +++ b/tests/unit/jquery-patch/all.html @@ -2,7 +2,7 @@ - jQuery UI Form Reset Mixin Test Suite + jQuery UI Legacy jQuery Core patches Test Suite diff --git a/tests/unit/jquery-patch/jquery-patch.html b/tests/unit/jquery-patch/jquery-patch.html index a20e25d4a1..53ce97c9bf 100644 --- a/tests/unit/jquery-patch/jquery-patch.html +++ b/tests/unit/jquery-patch/jquery-patch.html @@ -2,7 +2,7 @@ - jQuery UI Form Reset Mixin Test Suite + jQuery UI Legacy jQuery Core patches Test Suite From af8adca5481d0ac5db0865032b6c4c7e21421be7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski-Owczarek?= Date: Sun, 27 Oct 2024 00:04:00 +0200 Subject: [PATCH 30/53] Tabs: Use `CSS.escape` for sanitizing selectors The previous private `_sanitizeSelector` API was not correctly escaping backslashes and is now removed. The native API should always be correct. Closes gh-2307 --- tests/unit/tabs/core.js | 31 +++++++++++++++++++++++++++++++ tests/unit/tabs/helper.js | 3 +-- ui/widgets/tabs.js | 16 ++++++---------- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/tests/unit/tabs/core.js b/tests/unit/tabs/core.js index ae670ff430..c2fd890488 100644 --- a/tests/unit/tabs/core.js +++ b/tests/unit/tabs/core.js @@ -84,6 +84,37 @@ QUnit.test( "non-tab list items", function( assert ) { "first actual tab is active" ); } ); +QUnit.test( "ID escaping backslashes", function( assert ) { + assert.expect( 5 ); + + location.hash = "#fragment\b-2"; + + var element = $( "#tabs1" ) + .find( "a[href='#fragment-2']" ) + .attr( "href", "#fragment\b-2" ) + .end() + .find( "#fragment-2" ) + .attr( "id", "fragment\b-2" ) + .end() + .tabs(); + var tabs = element.find( ".ui-tabs-nav li" ); + var anchors = tabs.find( ".ui-tabs-anchor" ); + var panels = element.find( ".ui-tabs-panel" ); + + assert.strictEqual( element.tabs( "option", "active" ), 1, + "should set the active option" ); + + assert.strictEqual( anchors.length, 3, "should decorate all anchors" ); + assert.strictEqual( panels.length, 3, "should decorate all panels" ); + + assert.strictEqual( panels.eq( 1 ).attr( "aria-labelledby" ), anchors.eq( 1 ).attr( "id" ), + "panel 2 aria-labelledby equals anchor 2 id" ); + assert.strictEqual( tabs.eq( 1 ).attr( "aria-controls" ), "fragment\b-2", + "tab 2 aria-controls" ); + + location.hash = ""; +} ); + QUnit.test( "aria-controls", function( assert ) { assert.expect( 7 ); var element = $( "#tabs1" ).tabs(), diff --git a/tests/unit/tabs/helper.js b/tests/unit/tabs/helper.js index b3fb1d6fd4..4043d86d8f 100644 --- a/tests/unit/tabs/helper.js +++ b/tests/unit/tabs/helper.js @@ -58,8 +58,7 @@ return $.extend( helper, { var expected = $.makeArray( arguments ).slice( 2 ), actual = tabs.find( ".ui-tabs-nav li" ).map( function() { var tab = $( this ), - panel = $( $.ui.tabs.prototype._sanitizeSelector( - "#" + tab.attr( "aria-controls" ) ) ), + panel = $( "#" + CSS.escape( tab.attr( "aria-controls" ) ) ), tabIsActive = tab.hasClass( "ui-state-active" ), panelIsActive = panel.css( "display" ) !== "none"; diff --git a/ui/widgets/tabs.js b/ui/widgets/tabs.js index 72b868e4f0..7b7907c327 100644 --- a/ui/widgets/tabs.js +++ b/ui/widgets/tabs.js @@ -121,14 +121,14 @@ $.widget( "ui.tabs", { _initialActive: function() { var active = this.options.active, collapsible = this.options.collapsible, - locationHash = location.hash.substring( 1 ); + locationHashDecoded = decodeURIComponent( location.hash.substring( 1 ) ); if ( active === null ) { // check the fragment identifier in the URL - if ( locationHash ) { + if ( locationHashDecoded ) { this.tabs.each( function( i, tab ) { - if ( $( tab ).attr( "aria-controls" ) === locationHash ) { + if ( $( tab ).attr( "aria-controls" ) === locationHashDecoded ) { active = i; return false; } @@ -312,10 +312,6 @@ $.widget( "ui.tabs", { } }, - _sanitizeSelector: function( hash ) { - return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : ""; - }, - refresh: function() { var options = this.options, lis = this.tablist.children( ":has(a[href])" ); @@ -434,9 +430,9 @@ $.widget( "ui.tabs", { // Inline tab if ( that._isLocal( anchor ) ) { - selector = anchor.hash; + selector = decodeURIComponent( anchor.hash ); panelId = selector.substring( 1 ); - panel = that.element.find( that._sanitizeSelector( selector ) ); + panel = that.element.find( "#" + CSS.escape( panelId ) ); // remote tab } else { @@ -874,7 +870,7 @@ $.widget( "ui.tabs", { _getPanelForTab: function( tab ) { var id = $( tab ).attr( "aria-controls" ); - return this.element.find( this._sanitizeSelector( "#" + id ) ); + return this.element.find( "#" + CSS.escape( id ) ); } } ); From 85bed8ddd893390fd41bd7e93d2a44a1b5d9b885 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski-Owczarek?= Date: Mon, 28 Oct 2024 16:47:29 +0100 Subject: [PATCH 31/53] Build: Fix an XSS in the test server HTML serving logic The test server has a rule for `/tests/unit/*/*.html` paths that serves a proper local file. However, the parameters after `/unit/` so far accepted many characters that have special meaning, leading to possibly reading a file from outside of the Git repository. Fix that by only accepting alphanumeric characters, `-` or `_`. This should resolve one CodeQL alert. Closes gh-2309 --- tests/runner/createTestServer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/runner/createTestServer.js b/tests/runner/createTestServer.js index 67770c71d8..875e6d3b13 100644 --- a/tests/runner/createTestServer.js +++ b/tests/runner/createTestServer.js @@ -22,7 +22,7 @@ export async function createTestServer( report ) { } ); // Add a script tag to HTML pages to load the QUnit listeners - app.use( /\/tests\/unit\/([^/]+)\/\1\.html$/, async( req, res ) => { + app.use( /\/tests\/unit\/([a-zA-Z0-9_-]+)\/\1\.html$/, async( req, res ) => { const html = await readFile( `tests/unit/${ req.params[ 0 ] }/${ req.params[ 0 ] }.html`, "utf8" From d591bdd494cf28a399ea7d7ae7ccbae3a5cab020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski-Owczarek?= Date: Wed, 30 Oct 2024 09:58:01 +0100 Subject: [PATCH 32/53] Widget: Don't let widget name affect `$.ui` prototype & constructor This is an edge case and it only affects code accepting untrusted input as a widget name, but it's still technically correct to filter these out. Closes gh-2310 --- tests/unit/widget/core.js | 22 ++++++++++++++++++++++ ui/widget.js | 3 +++ 2 files changed, 25 insertions(+) diff --git a/tests/unit/widget/core.js b/tests/unit/widget/core.js index fe74e18e94..38e63a8c05 100644 --- a/tests/unit/widget/core.js +++ b/tests/unit/widget/core.js @@ -242,6 +242,28 @@ QUnit.test( "error handling", function( assert ) { $.error = error; } ); +QUnit.test( "Prototype pollution", function( assert ) { + assert.expect( 3 ); + + var elem = $( "
" ); + + $.widget( "ui.testWidget", {} ); + + elem.testWidget(); + + try { + $.widget( "ui.__proto__", {} ); + } catch ( _e ) {} + try { + $.widget( "ui.constructor", {} ); + } catch ( _e ) {} + + assert.strictEqual( Object.getPrototypeOf( $.ui ), Object.prototype, + "$.ui constructor not modified" ); + assert.ok( $.ui instanceof Object, "$.ui is an Object instance" ); + assert.notOk( $.ui instanceof Function, "$.ui is not a Function instance" ); +} ); + QUnit.test( "merge multiple option arguments", function( assert ) { assert.expect( 1 ); $.widget( "ui.testWidget", { diff --git a/ui/widget.js b/ui/widget.js index 7201b4fbf6..d5fbd885cf 100644 --- a/ui/widget.js +++ b/ui/widget.js @@ -56,6 +56,9 @@ $.widget = function( name, base, prototype ) { var namespace = name.split( "." )[ 0 ]; name = name.split( "." )[ 1 ]; + if ( name === "__proto__" || name === "constructor" ) { + return $.error( "Invalid widget name: " + name ); + } var fullName = namespace + "-" + name; if ( !prototype ) { From 3bb4232bfa792debf0b858c7eba58c4d080941b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski-Owczarek?= Date: Wed, 30 Oct 2024 17:02:00 +0100 Subject: [PATCH 33/53] Build: Update a few dependencies, drop `grunt-cli` `grunt` already contains the needed binary, no need for `grunt-cli` anymore. Update `download.jqueryui.com` as well. Closes gh-2311 --- build/release.js | 2 +- build/tasks/build.js | 2 +- package.json | 9 ++++----- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/build/release.js b/build/release.js index 14fbd6f153..633dd34d12 100644 --- a/build/release.js +++ b/build/release.js @@ -153,7 +153,7 @@ Release.define( { }; module.exports.dependencies = [ - "download.jqueryui.com@2.3.10", + "download.jqueryui.com@2.3.12", "node-packager@0.0.7", "shelljs@0.8.5" ]; diff --git a/build/tasks/build.js b/build/tasks/build.js index 48feb7aba1..bd07364ea3 100644 --- a/build/tasks/build.js +++ b/build/tasks/build.js @@ -3,7 +3,7 @@ module.exports = function( grunt ) { grunt.registerTask( "clean", function() { - require( "rimraf" ).sync( "dist" ); + require( "rimraf" ).rimrafSync( "dist" ); } ); grunt.registerTask( "asciilint", function() { diff --git a/package.json b/package.json index f9f83b4025..2cb41ef9e3 100644 --- a/package.json +++ b/package.json @@ -61,11 +61,10 @@ "diff": "5.2.0", "eslint-config-jquery": "3.0.2", "exit-hook": "4.0.0", - "express": "4.20.0", + "express": "4.21.1", "express-body-parser-error-handler": "1.0.7", "grunt": "1.6.1", "grunt-bowercopy": "1.2.5", - "grunt-cli": "1.4.3", "grunt-compare-size": "0.4.2", "grunt-contrib-concat": "2.1.0", "grunt-contrib-csslint": "2.0.0", @@ -73,10 +72,10 @@ "grunt-contrib-uglify": "5.2.2", "grunt-eslint": "24.0.1", "grunt-git-authors": "3.2.0", - "grunt-html": "16.0.0", + "grunt-html": "17.1.0", "load-grunt-tasks": "5.1.0", - "rimraf": "4.4.1", - "selenium-webdriver": "4.18.1", + "rimraf": "6.0.1", + "selenium-webdriver": "4.26.0", "yargs": "17.7.2" }, "keywords": [] From bf0d4c3a06852622487c08991f702f225b9631dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski-Owczarek?= Date: Wed, 30 Oct 2024 17:02:53 +0100 Subject: [PATCH 34/53] Docs: Update AUTHORS.txt --- AUTHORS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.txt b/AUTHORS.txt index 5b10979cae..b855d39997 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -381,3 +381,4 @@ divdeploy <166095818+divdeploy@users.noreply.github.com> mark van tilburg Ralf Koller <1665422+rpkoller@users.noreply.github.com> Porter Clevidence <116387727+porterclev@users.noreply.github.com> +Daniel García <93217193+Daniel-Garmig@users.noreply.github.com> From f7bff7b6c19f4279a9e69c1f6ab2eb51ba83ce04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski-Owczarek?= Date: Wed, 30 Oct 2024 17:24:49 +0100 Subject: [PATCH 35/53] Build: Updating the main version to 1.14.2-pre. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2cb41ef9e3..f82758844a 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "jquery-ui", "title": "jQuery UI", "description": "A curated set of user interface interactions, effects, widgets, and themes built on top of the jQuery JavaScript Library.", - "version": "1.14.1-pre", + "version": "1.14.2-pre", "homepage": "https://jqueryui.com", "author": { "name": "OpenJS Foundation and other contributors", From f76bbcd512290621227babf1f72fc295ffdf2983 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 3 Nov 2024 13:28:54 +0100 Subject: [PATCH 36/53] Build: Bump the github-actions group with 4 updates Bumps the github-actions group with 4 updates: [actions/checkout](https://github.com/actions/checkout), [github/codeql-action](https://github.com/github/codeql-action), [actions/setup-node](https://github.com/actions/setup-node) and [actions/cache](https://github.com/actions/cache). Closes gh-2312 Updates `actions/checkout` from 4.2.0 to 4.2.2 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/d632683dd7b4114ad314bca15554477dd762a938...11bd71901bbe5b1630ceea73d27597364c9af683) Updates `github/codeql-action` from 3.26.10 to 3.27.0 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/e2b3eafc8d227b0241d48be5f425d47c2d750a13...662472033e021d55d94146f66f6058822b0b39fd) Updates `actions/setup-node` from 4.0.4 to 4.1.0 - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/0a44ba7841725637a19e28fa30b79a866c81b0a6...39370e3970a6d050c480ffad4ff0ed4d3fdee5af) Updates `actions/cache` from 4.0.2 to 4.1.2 - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/0c45773b623bea8c8e75f6c82b208c3cf94ea4f9...6849a6489940f00c2f30c0fb92c6274307ccb58a) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 8 ++++---- .github/workflows/filestash.yml | 6 +++--- .github/workflows/node.js.yml | 18 +++++++++--------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 981b6912b8..06e8e59328 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -20,7 +20,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: # We must fetch at least the immediate parents so that if this is # a pull request then we can checkout the head. @@ -33,7 +33,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 + uses: github/codeql-action/init@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 # Override language selection by uncommenting this and choosing your languages # with: # languages: go, javascript, csharp, python, cpp, java @@ -41,7 +41,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 + uses: github/codeql-action/autobuild@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -55,4 +55,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 + uses: github/codeql-action/analyze@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 diff --git a/.github/workflows/filestash.yml b/.github/workflows/filestash.yml index f3944447a8..b311ce8992 100644 --- a/.github/workflows/filestash.yml +++ b/.github/workflows/filestash.yml @@ -17,15 +17,15 @@ jobs: name: Update Filestash steps: - name: Checkout - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 with: node-version: ${{ env.NODE_VERSION }} - name: Cache - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 + uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 with: path: ~/.npm key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock-${{ hashFiles('**/package-lock.json') }} diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 22116c7dab..caac8c0479 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -31,15 +31,15 @@ jobs: steps: - name: Checkout - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 with: node-version: ${{ env.NODE_VERSION }} - name: Cache - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 + uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 with: path: ~/.npm key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock-${{ hashFiles('**/package-lock.json') }} @@ -75,15 +75,15 @@ jobs: name: jQuery stable steps: - name: Checkout - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 with: node-version: ${{ env.NODE_VERSION }} - name: Cache - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 + uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 with: path: ~/.npm key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock-${{ hashFiles('**/package-lock.json') }} @@ -116,15 +116,15 @@ jobs: name: jQuery stable steps: - name: Checkout - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 with: node-version: ${{ env.NODE_VERSION }} - name: Cache - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 + uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 with: path: ~/.npm key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock-${{ hashFiles('**/package-lock.json') }} From 7fb4cf1168f950dbdaf86ef0bb8cd0bfc654bbce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Dec 2024 15:53:50 +0100 Subject: [PATCH 37/53] Build: Bump github/codeql-action from 3.27.0 to 3.27.5 in the github-actions group Bumps the github-actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action). Updates `github/codeql-action` from 3.27.0 to 3.27.5 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/662472033e021d55d94146f66f6058822b0b39fd...f09c1c0a94de965c15400f5634aa42fac8fb8f88) Closes gh-2318 --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 06e8e59328..cb990610bd 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -33,7 +33,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 + uses: github/codeql-action/init@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5 # Override language selection by uncommenting this and choosing your languages # with: # languages: go, javascript, csharp, python, cpp, java @@ -41,7 +41,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 + uses: github/codeql-action/autobuild@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -55,4 +55,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 + uses: github/codeql-action/analyze@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5 From 0be13b57cad253dbb5dc7fd3860239b4474d4b26 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Wed, 18 Dec 2024 10:14:42 -0500 Subject: [PATCH 38/53] Demos: fix easing demos Closes gh-2320 --- demos/effect/easing.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/demos/effect/easing.html b/demos/effect/easing.html index 4bee1c41f1..3014f76203 100644 --- a/demos/effect/easing.html +++ b/demos/effect/easing.html @@ -26,8 +26,12 @@ height = 100; $.each( $.easing, function( name, impl ) { + // Skip _default property + if ( typeof impl !== "function" ) { + return; + } var graph = $( "
" ).addClass( "graph" ).appendTo( "#graphs" ), - text = $( "
" ).text( ++i + ". " + name ).appendTo( graph ), + text = $( "
" ).text( name ).css({ fontSize: "13px", textAlign: "center", whiteSpace: "nowrap" }).appendTo( graph ), wrap = $( "
" ).appendTo( graph ).css( 'overflow', 'hidden' ), canvas = $( "" ).appendTo( wrap )[ 0 ]; From 44b0b0af50999a86c30fb9a48214bf5a333527af Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Jan 2025 14:56:20 +0100 Subject: [PATCH 39/53] Build: Bump the github-actions group with 2 updates Bumps the github-actions group with 2 updates: [github/codeql-action](https://github.com/github/codeql-action) and [actions/cache](https://github.com/actions/cache). Closes gh-2323 Updates `github/codeql-action` from 3.27.5 to 3.28.0 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/f09c1c0a94de965c15400f5634aa42fac8fb8f88...48ab28a6f5dbc2a99bf1e0131198dd8f1df78169) Updates `actions/cache` from 4.1.2 to 4.2.0 - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/6849a6489940f00c2f30c0fb92c6274307ccb58a...1bd1e32a3bdc45362d1e726936510720a7c30a57) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/filestash.yml | 2 +- .github/workflows/node.js.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index cb990610bd..f4ce8091cb 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -33,7 +33,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5 + uses: github/codeql-action/init@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0 # Override language selection by uncommenting this and choosing your languages # with: # languages: go, javascript, csharp, python, cpp, java @@ -41,7 +41,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5 + uses: github/codeql-action/autobuild@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -55,4 +55,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5 + uses: github/codeql-action/analyze@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0 diff --git a/.github/workflows/filestash.yml b/.github/workflows/filestash.yml index b311ce8992..8253df1aed 100644 --- a/.github/workflows/filestash.yml +++ b/.github/workflows/filestash.yml @@ -25,7 +25,7 @@ jobs: node-version: ${{ env.NODE_VERSION }} - name: Cache - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 + uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 with: path: ~/.npm key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock-${{ hashFiles('**/package-lock.json') }} diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index caac8c0479..bbabfb8784 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -39,7 +39,7 @@ jobs: node-version: ${{ env.NODE_VERSION }} - name: Cache - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 + uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 with: path: ~/.npm key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock-${{ hashFiles('**/package-lock.json') }} @@ -83,7 +83,7 @@ jobs: node-version: ${{ env.NODE_VERSION }} - name: Cache - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 + uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 with: path: ~/.npm key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock-${{ hashFiles('**/package-lock.json') }} @@ -124,7 +124,7 @@ jobs: node-version: ${{ env.NODE_VERSION }} - name: Cache - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 + uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 with: path: ~/.npm key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock-${{ hashFiles('**/package-lock.json') }} From b6857536606d5d0dd1b07ada519f845cdac5c96e Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Tue, 14 Jan 2025 05:15:49 -0500 Subject: [PATCH 40/53] Tests: Migrate test runner to jquery-test-runner Closes gh-2325 --- .github/workflows/filestash.yml | 2 +- .github/workflows/node.js.yml | 42 +-- jtr-git.yml | 38 ++ jtr-stable.yml | 40 +++ jtr.yml | 30 ++ package.json | 17 +- tests/lib/qunit.js | 2 - tests/runner/.eslintrc.json | 38 -- tests/runner/browsers.js | 242 ------------- tests/runner/browserstack/api.js | 332 ----------------- .../browserstack/buildBrowserFromString.js | 20 -- tests/runner/browserstack/createAuthHeader.js | 7 - tests/runner/browserstack/local.js | 34 -- tests/runner/command.js | 140 -------- tests/runner/createTestServer.js | 66 ---- tests/runner/flags/browsers.js | 24 -- tests/runner/flags/jquery.js | 14 - tests/runner/flags/suites.js | 27 -- tests/runner/lib/buildTestUrl.js | 24 -- tests/runner/lib/generateHash.js | 10 - tests/runner/lib/getBrowserString.js | 48 --- tests/runner/lib/prettyMs.js | 18 - tests/runner/listeners.js | 112 ------ tests/runner/package.json | 3 - tests/runner/queue.js | 119 ------ tests/runner/reporter.js | 134 ------- tests/runner/run.js | 338 ------------------ tests/runner/selenium/createDriver.js | 84 ----- tests/runner/server.js | 13 - 29 files changed, 132 insertions(+), 1886 deletions(-) create mode 100644 jtr-git.yml create mode 100644 jtr-stable.yml create mode 100644 jtr.yml delete mode 100644 tests/runner/.eslintrc.json delete mode 100644 tests/runner/browsers.js delete mode 100644 tests/runner/browserstack/api.js delete mode 100644 tests/runner/browserstack/buildBrowserFromString.js delete mode 100644 tests/runner/browserstack/createAuthHeader.js delete mode 100644 tests/runner/browserstack/local.js delete mode 100644 tests/runner/command.js delete mode 100644 tests/runner/createTestServer.js delete mode 100644 tests/runner/flags/browsers.js delete mode 100644 tests/runner/flags/jquery.js delete mode 100644 tests/runner/flags/suites.js delete mode 100644 tests/runner/lib/buildTestUrl.js delete mode 100644 tests/runner/lib/generateHash.js delete mode 100644 tests/runner/lib/getBrowserString.js delete mode 100644 tests/runner/lib/prettyMs.js delete mode 100644 tests/runner/listeners.js delete mode 100644 tests/runner/package.json delete mode 100644 tests/runner/queue.js delete mode 100644 tests/runner/reporter.js delete mode 100644 tests/runner/run.js delete mode 100644 tests/runner/selenium/createDriver.js delete mode 100644 tests/runner/server.js diff --git a/.github/workflows/filestash.yml b/.github/workflows/filestash.yml index 8253df1aed..8de197a66c 100644 --- a/.github/workflows/filestash.yml +++ b/.github/workflows/filestash.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest environment: filestash env: - NODE_VERSION: 20.x + NODE_VERSION: 22.x name: Update Filestash steps: - name: Checkout diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index bbabfb8784..f23498ffd2 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -12,21 +12,21 @@ permissions: contents: read env: - NODE_VERSION: 20.x + NODE_VERSION: 22.x jobs: build-and-test: runs-on: ubuntu-latest name: | - ${{ matrix.BROWSER }} | ${{ matrix.JQUERYS.name }} + ${{ matrix.BROWSER }} | ${{ matrix.CONFIGS.name }} strategy: fail-fast: false matrix: BROWSER: [chrome, firefox] - JQUERYS: - - versions: --jquery git --jquery 3.x-git + CONFIGS: + - config: jtr-git.yml name: jQuery git - - versions: --jquery 3.7.1 --jquery 3.6.4 --jquery 2.2.4 --jquery 1.12.4 + - config: jtr-stable.yml name: jQuery stable steps: @@ -57,21 +57,21 @@ jobs: - name: Test run: | - npm run test:unit -- -h -b ${{ matrix.BROWSER }} \ - ${{ matrix.JQUERYS.versions }} \ - --retries 3 --hard-retries 1 + npm run test:unit -- \ + --headless -b ${{ matrix.BROWSER }} \ + -c ${{ matrix.CONFIGS.config }} edge: runs-on: windows-latest name: | - edge | ${{ matrix.JQUERYS.name }} + edge | ${{ matrix.CONFIGS.name }} strategy: fail-fast: false matrix: - JQUERYS: - - versions: --jquery git --jquery 3.x-git + CONFIGS: + - config: jtr-git.yml name: jQuery git - - versions: --jquery 3.7.1 --jquery 3.6.4 --jquery 2.2.4 --jquery 1.12.4 + - config: jtr-stable.yml name: jQuery stable steps: - name: Checkout @@ -97,22 +97,19 @@ jobs: run: npm run build - name: Test - run: | - npm run test:unit -- -h -b edge ` - ${{ matrix.JQUERYS.versions }} ` - --retries 3 --hard-retries 1 + run: npm run test:unit -- -- --headless -b edge -c ${{ matrix.CONFIGS.config }} safari: runs-on: macos-latest name: | - safari | ${{ matrix.JQUERYS.name }} + safari | ${{ matrix.CONFIGS.name }} strategy: fail-fast: false matrix: - JQUERYS: - - versions: --jquery git --jquery 3.x-git + CONFIGS: + - config: jtr-git.yml name: jQuery git - - versions: --jquery 3.7.1 --jquery 3.6.4 --jquery 2.2.4 --jquery 1.12.4 + - config: jtr-stable.yml name: jQuery stable steps: - name: Checkout @@ -138,7 +135,4 @@ jobs: run: npm run build - name: Test - run: | - npm run test:unit -- -b safari \ - ${{ matrix.JQUERYS.versions }} \ - --retries 3 --hard-retries 1 + run: npm run test:unit -- -b safari -c ${{ matrix.CONFIGS.config }} diff --git a/jtr-git.yml b/jtr-git.yml new file mode 100644 index 0000000000..0fc81ddd95 --- /dev/null +++ b/jtr-git.yml @@ -0,0 +1,38 @@ +version: 1 + +base-url: /tests/unit/ + +test-urls: + - accordion/accordion.html + - autocomplete/autocomplete.html + - button/button.html + - checkboxradio/checkboxradio.html + - controlgroup/controlgroup.html + - core/core.html + - datepicker/datepicker.html + - dialog/dialog.html + - draggable/draggable.html + - droppable/droppable.html + - effects/effects.html + - form-reset-mixin/form-reset-mixin.html + - jquery-patch/jquery-patch.html + - menu/menu.html + - position/position.html + - progressbar/progressbar.html + - resizable/resizable.html + - selectable/selectable.html + - selectmenu/selectmenu.html + - slider/slider.html + - sortable/sortable.html + - spinner/spinner.html + - tabs/tabs.html + - tooltip/tooltip.html + - widget/widget.html + +runs: + jquery: + - git + - 3.x-git + +retries: 2 +hard-retries: 1 diff --git a/jtr-stable.yml b/jtr-stable.yml new file mode 100644 index 0000000000..1c6c27a103 --- /dev/null +++ b/jtr-stable.yml @@ -0,0 +1,40 @@ +version: 1 + +base-url: /tests/unit/ + +test-urls: + - accordion/accordion.html + - autocomplete/autocomplete.html + - button/button.html + - checkboxradio/checkboxradio.html + - controlgroup/controlgroup.html + - core/core.html + - datepicker/datepicker.html + - dialog/dialog.html + - draggable/draggable.html + - droppable/droppable.html + - effects/effects.html + - form-reset-mixin/form-reset-mixin.html + - jquery-patch/jquery-patch.html + - menu/menu.html + - position/position.html + - progressbar/progressbar.html + - resizable/resizable.html + - selectable/selectable.html + - selectmenu/selectmenu.html + - slider/slider.html + - sortable/sortable.html + - spinner/spinner.html + - tabs/tabs.html + - tooltip/tooltip.html + - widget/widget.html + +runs: + jquery: + - 3.7.1 + - 3.6.4 + - 2.2.4 + - 1.12.4 + +retries: 2 +hard-retries: 1 diff --git a/jtr.yml b/jtr.yml new file mode 100644 index 0000000000..70d30ade8f --- /dev/null +++ b/jtr.yml @@ -0,0 +1,30 @@ +version: 1 + +base-url: /tests/unit/ + +test-urls: + - accordion/accordion.html + - autocomplete/autocomplete.html + - button/button.html + - checkboxradio/checkboxradio.html + - controlgroup/controlgroup.html + - core/core.html + - datepicker/datepicker.html + - dialog/dialog.html + - draggable/draggable.html + - droppable/droppable.html + - effects/effects.html + - form-reset-mixin/form-reset-mixin.html + - jquery-patch/jquery-patch.html + - menu/menu.html + - position/position.html + - progressbar/progressbar.html + - resizable/resizable.html + - selectable/selectable.html + - selectmenu/selectmenu.html + - slider/slider.html + - sortable/sortable.html + - spinner/spinner.html + - tabs/tabs.html + - tooltip/tooltip.html + - widget/widget.html diff --git a/package.json b/package.json index f82758844a..56f60f34dd 100644 --- a/package.json +++ b/package.json @@ -47,22 +47,16 @@ "scripts": { "build": "grunt build", "lint": "grunt lint", - "test:server": "node tests/runner/server.js", - "test:unit": "node tests/runner/command.js", - "test": "grunt && npm run test:unit -- -h" + "test:server": "jtr serve", + "test:unit": "jtr", + "test": "grunt && npm run test:unit -- --headless" }, "dependencies": { "jquery": ">=1.12.0 <5.0.0" }, "devDependencies": { - "body-parser": "1.20.3", - "browserstack-local": "1.5.5", "commitplease": "3.2.0", - "diff": "5.2.0", "eslint-config-jquery": "3.0.2", - "exit-hook": "4.0.0", - "express": "4.21.1", - "express-body-parser-error-handler": "1.0.7", "grunt": "1.6.1", "grunt-bowercopy": "1.2.5", "grunt-compare-size": "0.4.2", @@ -73,10 +67,9 @@ "grunt-eslint": "24.0.1", "grunt-git-authors": "3.2.0", "grunt-html": "17.1.0", + "jquery-test-runner": "0.2.1", "load-grunt-tasks": "5.1.0", - "rimraf": "6.0.1", - "selenium-webdriver": "4.26.0", - "yargs": "17.7.2" + "rimraf": "6.0.1" }, "keywords": [] } diff --git a/tests/lib/qunit.js b/tests/lib/qunit.js index cc2f01d794..6441019bdd 100644 --- a/tests/lib/qunit.js +++ b/tests/lib/qunit.js @@ -13,8 +13,6 @@ QUnit.config.requireExpects = true; QUnit.config.urlConfig.push( { id: "jquery", label: "jQuery version", - - // Keep in sync with tests/runner/jquery.js value: [ "1.12.4", "2.2.4", diff --git a/tests/runner/.eslintrc.json b/tests/runner/.eslintrc.json deleted file mode 100644 index 9ca2e75f60..0000000000 --- a/tests/runner/.eslintrc.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "root": true, - - "extends": "jquery", - - "overrides": [ - { - "files": ["**/*"], - "env": { - "es6": true, - "node": true - }, - "parserOptions": { - "ecmaVersion": 2022, - "sourceType": "module" - } - }, - { - "files": ["./listeners.js"], - "env": { - "browser": true, - "node": false - }, - "globals": { - "QUnit": false, - "Symbol": false, - "require": false - }, - "parserOptions": { - "ecmaVersion": 5, - "sourceType": "script" - }, - "rules": { - "strict": ["error", "function"] - } - } - ] -} diff --git a/tests/runner/browsers.js b/tests/runner/browsers.js deleted file mode 100644 index 1ddccdf785..0000000000 --- a/tests/runner/browsers.js +++ /dev/null @@ -1,242 +0,0 @@ -import chalk from "chalk"; -import { getBrowserString } from "./lib/getBrowserString.js"; -import { - createWorker, - deleteWorker, - getAvailableSessions -} from "./browserstack/api.js"; -import createDriver from "./selenium/createDriver.js"; - -const workers = Object.create( null ); - -/** - * Keys are browser strings - * Structure of a worker: - * { - * browser: object // The browser object - * debug: boolean // Stops the worker from being cleaned up when finished - * lastTouch: number // The last time a request was received - * restarts: number // The number of times the worker has been restarted - * options: object // The options to create the worker - * url: string // The URL the worker is on - * quit: function // A function to stop the worker - * } - */ - -// Acknowledge the worker within the time limit. -// BrowserStack can take much longer spinning up -// some browsers, such as iOS 15 Safari. -const ACKNOWLEDGE_INTERVAL = 1000; -const ACKNOWLEDGE_TIMEOUT = 60 * 1000 * 5; - -const MAX_WORKER_RESTARTS = 5; - -// No report after the time limit -// should refresh the worker -const RUN_WORKER_TIMEOUT = 60 * 1000 * 2; - -const WORKER_WAIT_TIME = 30000; - -// Limit concurrency to 8 by default in selenium -const MAX_SELENIUM_CONCURRENCY = 8; - -export async function createBrowserWorker( url, browser, options, restarts = 0 ) { - if ( restarts > MAX_WORKER_RESTARTS ) { - throw new Error( - `Reached the maximum number of restarts for ${ chalk.yellow( - getBrowserString( browser ) - ) }` - ); - } - const { browserstack, debug, headless, runId, tunnelId, verbose } = options; - while ( await maxWorkersReached( options ) ) { - if ( verbose ) { - console.log( "\nWaiting for available sessions..." ); - } - await new Promise( ( resolve ) => setTimeout( resolve, WORKER_WAIT_TIME ) ); - } - - const fullBrowser = getBrowserString( browser ); - - let worker; - - if ( browserstack ) { - worker = await createWorker( { - ...browser, - url: encodeURI( url ), - project: "jquery", - build: `Run ${ runId }`, - - // This is the maximum timeout allowed - // by BrowserStack. We do this because - // we control the timeout in the runner. - // See https://github.com/browserstack/api/blob/b324a6a5bc1b6052510d74e286b8e1c758c308a7/README.md#timeout300 - timeout: 1800, - - // Not documented in the API docs, - // but required to make local testing work. - // See https://www.browserstack.com/docs/automate/selenium/manage-multiple-connections#nodejs - "browserstack.local": true, - "browserstack.localIdentifier": tunnelId - } ); - worker.quit = () => deleteWorker( worker.id ); - } else { - const driver = await createDriver( { - browserName: browser.browser, - headless, - url, - verbose - } ); - worker = { - quit: () => driver.quit() - }; - } - - worker.debug = !!debug; - worker.url = url; - worker.browser = browser; - worker.restarts = restarts; - worker.options = options; - touchBrowser( browser ); - workers[ fullBrowser ] = worker; - - // Wait for the worker to show up in the list - // before returning it. - return ensureAcknowledged( worker ); -} - -export function touchBrowser( browser ) { - const fullBrowser = getBrowserString( browser ); - const worker = workers[ fullBrowser ]; - if ( worker ) { - worker.lastTouch = Date.now(); - } -} - -export async function setBrowserWorkerUrl( browser, url ) { - const fullBrowser = getBrowserString( browser ); - const worker = workers[ fullBrowser ]; - if ( worker ) { - worker.url = url; - } -} - -export async function restartBrowser( browser ) { - const fullBrowser = getBrowserString( browser ); - const worker = workers[ fullBrowser ]; - if ( worker ) { - await restartWorker( worker ); - } -} - -/** - * Checks that all browsers have received - * a response in the given amount of time. - * If not, the worker is restarted. - */ -export async function checkLastTouches() { - for ( const [ fullBrowser, worker ] of Object.entries( workers ) ) { - if ( Date.now() - worker.lastTouch > RUN_WORKER_TIMEOUT ) { - const options = worker.options; - if ( options.verbose ) { - console.log( - `\nNo response from ${ chalk.yellow( fullBrowser ) } in ${ - RUN_WORKER_TIMEOUT / 1000 / 60 - }min.` - ); - } - await restartWorker( worker ); - } - } -} - -export async function cleanupAllBrowsers( { verbose } ) { - const workersRemaining = Object.values( workers ); - const numRemaining = workersRemaining.length; - if ( numRemaining ) { - try { - await Promise.all( workersRemaining.map( ( worker ) => worker.quit() ) ); - if ( verbose ) { - console.log( - `Stopped ${ numRemaining } browser${ numRemaining > 1 ? "s" : "" }.` - ); - } - } catch ( error ) { - - // Log the error, but do not consider the test run failed - console.error( error ); - } - } -} - -async function maxWorkersReached( { - browserstack, - concurrency = MAX_SELENIUM_CONCURRENCY -} ) { - if ( browserstack ) { - return ( await getAvailableSessions() ) <= 0; - } - return workers.length >= concurrency; -} - -async function waitForAck( worker, { fullBrowser, verbose } ) { - delete worker.lastTouch; - return new Promise( ( resolve, reject ) => { - const interval = setInterval( () => { - if ( worker.lastTouch ) { - if ( verbose ) { - console.log( `\n${ fullBrowser } acknowledged.` ); - } - clearTimeout( timeout ); - clearInterval( interval ); - resolve(); - } - }, ACKNOWLEDGE_INTERVAL ); - - const timeout = setTimeout( () => { - clearInterval( interval ); - reject( - new Error( - `${ fullBrowser } not acknowledged after ${ - ACKNOWLEDGE_TIMEOUT / 1000 / 60 - }min.` - ) - ); - }, ACKNOWLEDGE_TIMEOUT ); - } ); -} - -async function ensureAcknowledged( worker ) { - const fullBrowser = getBrowserString( worker.browser ); - const verbose = worker.options.verbose; - try { - await waitForAck( worker, { fullBrowser, verbose } ); - return worker; - } catch ( error ) { - console.error( error.message ); - await restartWorker( worker ); - } -} - -async function cleanupWorker( worker, { verbose } ) { - for ( const [ fullBrowser, w ] of Object.entries( workers ) ) { - if ( w === worker ) { - delete workers[ fullBrowser ]; - await worker.quit(); - if ( verbose ) { - console.log( `\nStopped ${ fullBrowser }.` ); - } - return; - } - } -} - -async function restartWorker( worker ) { - await cleanupWorker( worker, worker.options ); - await createBrowserWorker( - worker.url, - worker.browser, - worker.options, - worker.restarts + 1 - ); -} diff --git a/tests/runner/browserstack/api.js b/tests/runner/browserstack/api.js deleted file mode 100644 index 632f90c3b4..0000000000 --- a/tests/runner/browserstack/api.js +++ /dev/null @@ -1,332 +0,0 @@ -/** - * Browserstack API is documented at - * https://github.com/browserstack/api - */ - -import { createAuthHeader } from "./createAuthHeader.js"; - -const browserstackApi = "https://api.browserstack.com"; -const apiVersion = 5; - -const username = process.env.BROWSERSTACK_USERNAME; -const accessKey = process.env.BROWSERSTACK_ACCESS_KEY; - -// iOS has null for version numbers, -// and we do not need a similar check for OS versions. -const rfinalVersion = /(?:^[0-9\.]+$)|(?:^null$)/; -const rlatest = /^latest-(\d+)$/; - -const rnonDigits = /(?:[^\d\.]+)|(?:20\d{2})/g; - -async function fetchAPI( path, options = {}, versioned = true ) { - if ( !username || !accessKey ) { - throw new Error( - "BROWSERSTACK_USERNAME and BROWSERSTACK_ACCESS_KEY environment variables must be set." - ); - } - const init = { - method: "GET", - ...options, - headers: { - authorization: createAuthHeader( username, accessKey ), - accept: "application/json", - "content-type": "application/json", - ...options.headers - } - }; - const response = await fetch( - `${ browserstackApi }/${ versioned ? `${ apiVersion }/` : "" }${ path }`, - init - ); - if ( !response.ok ) { - console.log( - `\n${ init.method } ${ path }`, - response.status, - response.statusText - ); - throw new Error( `Error fetching ${ path }` ); - } - return response.json(); -} - -/** - * ============================= - * Browsers API - * ============================= - */ - -function compareVersionNumbers( a, b ) { - if ( a != null && b == null ) { - return -1; - } - if ( a == null && b != null ) { - return 1; - } - if ( a == null && b == null ) { - return 0; - } - const aParts = a.replace( rnonDigits, "" ).split( "." ); - const bParts = b.replace( rnonDigits, "" ).split( "." ); - - if ( aParts.length > bParts.length ) { - return -1; - } - if ( aParts.length < bParts.length ) { - return 1; - } - - for ( let i = 0; i < aParts.length; i++ ) { - const aPart = Number( aParts[ i ] ); - const bPart = Number( bParts[ i ] ); - if ( aPart < bPart ) { - return -1; - } - if ( aPart > bPart ) { - return 1; - } - } - - if ( rnonDigits.test( a ) && !rnonDigits.test( b ) ) { - return -1; - } - if ( !rnonDigits.test( a ) && rnonDigits.test( b ) ) { - return 1; - } - - return 0; -} - -function sortBrowsers( a, b ) { - if ( a.browser < b.browser ) { - return -1; - } - if ( a.browser > b.browser ) { - return 1; - } - const browserComparison = compareVersionNumbers( - a.browser_version, - b.browser_version - ); - if ( browserComparison ) { - return browserComparison; - } - if ( a.os < b.os ) { - return -1; - } - if ( a.os > b.os ) { - return 1; - } - const osComparison = compareVersionNumbers( a.os_version, b.os_version ); - if ( osComparison ) { - return osComparison; - } - const deviceComparison = compareVersionNumbers( a.device, b.device ); - if ( deviceComparison ) { - return deviceComparison; - } - return 0; -} - -export async function getBrowsers( { flat = false } = {} ) { - const query = new URLSearchParams(); - if ( flat ) { - query.append( "flat", true ); - } - const browsers = await fetchAPI( `/browsers?${ query }` ); - return browsers.sort( sortBrowsers ); -} - -function matchVersion( browserVersion, version ) { - if ( !version ) { - return false; - } - const regex = new RegExp( - `^${ version.replace( /\\/g, "\\\\" ).replace( /\./g, "\\." ) }\\b`, - "i" - ); - return regex.test( browserVersion ); -} - -export async function filterBrowsers( filter ) { - const browsers = await getBrowsers( { flat: true } ); - if ( !filter ) { - return browsers; - } - const filterBrowser = ( filter.browser ?? "" ).toLowerCase(); - const filterVersion = ( filter.browser_version ?? "" ).toLowerCase(); - const filterOs = ( filter.os ?? "" ).toLowerCase(); - const filterOsVersion = ( filter.os_version ?? "" ).toLowerCase(); - const filterDevice = ( filter.device ?? "" ).toLowerCase(); - - const filteredWithoutVersion = browsers.filter( ( browser ) => { - return ( - ( !filterBrowser || filterBrowser === browser.browser.toLowerCase() ) && - ( !filterOs || filterOs === browser.os.toLowerCase() ) && - ( !filterOsVersion || matchVersion( browser.os_version, filterOsVersion ) ) && - ( !filterDevice || filterDevice === ( browser.device || "" ).toLowerCase() ) - ); - } ); - - if ( !filterVersion ) { - return filteredWithoutVersion; - } - - if ( filterVersion.startsWith( "latest" ) ) { - const groupedByName = filteredWithoutVersion - .filter( ( b ) => rfinalVersion.test( b.browser_version ) ) - .reduce( ( acc, browser ) => { - acc[ browser.browser ] = acc[ browser.browser ] ?? []; - acc[ browser.browser ].push( browser ); - return acc; - }, Object.create( null ) ); - - const filtered = []; - for ( const group of Object.values( groupedByName ) ) { - const latest = group[ group.length - 1 ]; - - // Mobile devices do not have browser version. - // Skip the version check for these, - // but include the latest in the list if it made it - // through filtering. - if ( !latest.browser_version ) { - - // Do not include in the list for latest-n. - if ( filterVersion === "latest" ) { - filtered.push( latest ); - } - continue; - } - - // Get the latest version and subtract the number from the filter, - // ignoring any patch versions, which may differ between major versions. - const num = rlatest.exec( filterVersion ); - const version = parseInt( latest.browser_version ) - ( num ? num[ 1 ] : 0 ); - const match = group.findLast( ( browser ) => { - return matchVersion( browser.browser_version, version.toString() ); - } ); - if ( match ) { - filtered.push( match ); - } - } - return filtered; - } - - return filteredWithoutVersion.filter( ( browser ) => { - return matchVersion( browser.browser_version, filterVersion ); - } ); -} - -export async function listBrowsers( filter ) { - const browsers = await filterBrowsers( filter ); - console.log( "Available browsers:" ); - for ( const browser of browsers ) { - let message = ` ${ browser.browser }_`; - if ( browser.device ) { - message += `:${ browser.device }_`; - } else { - message += `${ browser.browser_version }_`; - } - message += `${ browser.os }_${ browser.os_version }`; - console.log( message ); - } -} - -export async function getLatestBrowser( filter ) { - if ( !filter.browser_version ) { - filter.browser_version = "latest"; - } - const browsers = await filterBrowsers( filter ); - return browsers[ browsers.length - 1 ]; -} - -/** - * ============================= - * Workers API - * ============================= - */ - -/** - * A browser object may only have one of `browser` or `device` set; - * which property is set will depend on `os`. - * - * `options`: is an object with the following properties: - * `os`: The operating system. - * `os_version`: The operating system version. - * `browser`: The browser name. - * `browser_version`: The browser version. - * `device`: The device name. - * `url` (optional): Which URL to navigate to upon creation. - * `timeout` (optional): Maximum life of the worker (in seconds). Maximum value of `1800`. Specifying `0` will use the default of `300`. - * `name` (optional): Provide a name for the worker. - * `build` (optional): Group workers into a build. - * `project` (optional): Provide the project the worker belongs to. - * `resolution` (optional): Specify the screen resolution (e.g. "1024x768"). - * `browserstack.local` (optional): Set to `true` to mark as local testing. - * `browserstack.video` (optional): Set to `false` to disable video recording. - * `browserstack.localIdentifier` (optional): ID of the local tunnel. - */ -export function createWorker( options ) { - return fetchAPI( "/worker", { - method: "POST", - body: JSON.stringify( options ) - } ); -} - -/** - * Returns a worker object, if one exists, with the following properties: - * `id`: The worker id. - * `status`: A string representing the current status of the worker. - * Possible statuses: `"running"`, `"queue"`. - */ -export function getWorker( id ) { - return fetchAPI( `/worker/${ id }` ); -} - -export async function deleteWorker( id ) { - return fetchAPI( `/worker/${ id }`, { method: "DELETE" } ); -} - -export function getWorkers() { - return fetchAPI( "/workers" ); -} - -/** - * Stop all workers - */ -export async function stopWorkers() { - const workers = await getWorkers(); - - // Run each request on its own - // to avoid connect timeout errors. - console.log( `${ workers.length } workers running...` ); - for ( const worker of workers ) { - try { - await deleteWorker( worker.id ); - } catch ( error ) { - - // Log the error, but continue trying to remove workers. - console.error( error ); - } - } - console.log( "All workers stopped." ); -} - -/** - * ============================= - * Plan API - * ============================= - */ - -export function getPlan() { - return fetchAPI( "/automate/plan.json", {}, false ); -} - -export async function getAvailableSessions() { - try { - const [ plan, workers ] = await Promise.all( [ getPlan(), getWorkers() ] ); - return plan.parallel_sessions_max_allowed - workers.length; - } catch ( error ) { - console.error( error ); - return 0; - } -} diff --git a/tests/runner/browserstack/buildBrowserFromString.js b/tests/runner/browserstack/buildBrowserFromString.js deleted file mode 100644 index e0d99a0392..0000000000 --- a/tests/runner/browserstack/buildBrowserFromString.js +++ /dev/null @@ -1,20 +0,0 @@ -export function buildBrowserFromString( str ) { - const [ browser, versionOrDevice, os, osVersion ] = str.split( "_" ); - - // If the version starts with a colon, it's a device - if ( versionOrDevice && versionOrDevice.startsWith( ":" ) ) { - return { - browser, - device: versionOrDevice.slice( 1 ), - os, - os_version: osVersion - }; - } - - return { - browser, - browser_version: versionOrDevice, - os, - os_version: osVersion - }; -} diff --git a/tests/runner/browserstack/createAuthHeader.js b/tests/runner/browserstack/createAuthHeader.js deleted file mode 100644 index fe4831e9ae..0000000000 --- a/tests/runner/browserstack/createAuthHeader.js +++ /dev/null @@ -1,7 +0,0 @@ -const textEncoder = new TextEncoder(); - -export function createAuthHeader( username, accessKey ) { - const encoded = textEncoder.encode( `${ username }:${ accessKey }` ); - const base64 = btoa( String.fromCodePoint.apply( null, encoded ) ); - return `Basic ${ base64 }`; -} diff --git a/tests/runner/browserstack/local.js b/tests/runner/browserstack/local.js deleted file mode 100644 index c84cf155cd..0000000000 --- a/tests/runner/browserstack/local.js +++ /dev/null @@ -1,34 +0,0 @@ -import browserstackLocal from "browserstack-local"; - -export async function localTunnel( localIdentifier, opts = {} ) { - const tunnel = new browserstackLocal.Local(); - - return new Promise( ( resolve, reject ) => { - - // https://www.browserstack.com/docs/local-testing/binary-params - tunnel.start( - { - "enable-logging-for-api": "", - localIdentifier, - ...opts - }, - async( error ) => { - if ( error || !tunnel.isRunning() ) { - return reject( error ); - } - resolve( { - stop: function stopTunnel() { - return new Promise( ( resolve, reject ) => { - tunnel.stop( ( error ) => { - if ( error ) { - return reject( error ); - } - resolve(); - } ); - } ); - } - } ); - } - ); - } ); -} diff --git a/tests/runner/command.js b/tests/runner/command.js deleted file mode 100644 index cf5ddd8eef..0000000000 --- a/tests/runner/command.js +++ /dev/null @@ -1,140 +0,0 @@ -import yargs from "yargs/yargs"; -import { browsers } from "./flags/browsers.js"; -import { getPlan, listBrowsers, stopWorkers } from "./browserstack/api.js"; -import { buildBrowserFromString } from "./browserstack/buildBrowserFromString.js"; -import { jquery } from "./flags/jquery.js"; -import { suites } from "./flags/suites.js"; -import { run } from "./run.js"; - -const argv = yargs( process.argv.slice( 2 ) ) - .version( false ) - .strict() - .command( { - command: "[options]", - describe: "Run jQuery tests in a browser" - } ) - .option( "suite", { - alias: "s", - type: "array", - choices: suites, - description: - "Run tests for a specific test suite.\n" + - "Pass multiple test suites by repeating the option.\n" + - "Defaults to all suites." - } ) - .option( "jquery", { - alias: "j", - type: "array", - choices: jquery, - description: - "Run tests against a specific jQuery version.\n" + - "Pass multiple versions by repeating the option.", - default: [ "3.7.1" ] - } ) - .option( "migrate", { - type: "boolean", - description: - "Run tests with jQuery Migrate enabled.", - default: false - } ) - .option( "browser", { - alias: "b", - type: "array", - choices: browsers, - description: - "Run tests in a specific browser." + - "Pass multiple browsers by repeating the option." + - "If using BrowserStack, specify browsers using --browserstack.", - default: [ "chrome" ] - } ) - .option( "headless", { - alias: "h", - type: "boolean", - description: - "Run tests in headless mode. Cannot be used with --debug or --browserstack.", - conflicts: [ "debug", "browserstack" ] - } ) - .option( "concurrency", { - alias: "c", - type: "number", - description: - "Run tests in parallel in multiple browsers. " + - "Defaults to 8 in normal mode. In browserstack mode, " + - "defaults to the maximum available under your BrowserStack plan." - } ) - .option( "debug", { - alias: "d", - type: "boolean", - description: - "Leave the browser open for debugging. Cannot be used with --headless.", - conflicts: [ "headless" ] - } ) - .option( "retries", { - alias: "r", - type: "number", - description: "Number of times to retry failed tests by refreshing the URL." - } ) - .option( "hard-retries", { - type: "number", - description: - "Number of times to retry failed tests by restarting the worker. " + - "This is in addition to the normal retries " + - "and are only used when the normal retries are exhausted." - } ) - .option( "verbose", { - alias: "v", - type: "boolean", - description: "Log additional information." - } ) - .option( "browserstack", { - type: "array", - description: - "Run tests in BrowserStack.\n" + - "Requires BROWSERSTACK_USERNAME and BROWSERSTACK_ACCESS_KEY environment variables.\n" + - "The value can be empty for the default configuration, or a string in the format of\n" + - "\"browser_[browserVersion | :device]_os_osVersion\" (see --list-browsers).\n" + - "Pass multiple browsers by repeating the option.\n" + - "The --browser option is ignored when --browserstack has a value.\n" + - "Otherwise, the --browser option will be used, " + - "with the latest version/device for that browser, on a matching OS." - } ) - .option( "run-id", { - type: "string", - description: "A unique identifier for the run in BrowserStack." - } ) - .option( "list-browsers", { - type: "string", - description: - "List available BrowserStack browsers and exit.\n" + - "Leave blank to view all browsers or pass " + - "\"browser_[browserVersion | :device]_os_osVersion\" with each parameter " + - "separated by an underscore to filter the list (any can be omitted).\n" + - "\"latest\" can be used in place of \"browserVersion\" to find the latest version.\n" + - "\"latest-n\" can be used to find the nth latest browser version.\n" + - "Use a colon to indicate a device.\n" + - "Examples: \"chrome__windows_10\", \"safari_latest\", " + - "\"Mobile Safari\", \"Android Browser_:Google Pixel 8 Pro\".\n" + - "Use quotes if spaces are necessary." - } ) - .option( "stop-workers", { - type: "boolean", - description: - "WARNING: This will stop all BrowserStack workers that may exist and exit," + - "including any workers running from other projects.\n" + - "This can be used as a failsafe when there are too many stray workers." - } ) - .option( "browserstack-plan", { - type: "boolean", - description: "Show BrowserStack plan information and exit." - } ) - .help().argv; - -if ( typeof argv.listBrowsers === "string" ) { - listBrowsers( buildBrowserFromString( argv.listBrowsers ) ); -} else if ( argv.stopWorkers ) { - stopWorkers(); -} else if ( argv.browserstackPlan ) { - console.log( await getPlan() ); -} else { - run( argv ); -} diff --git a/tests/runner/createTestServer.js b/tests/runner/createTestServer.js deleted file mode 100644 index 875e6d3b13..0000000000 --- a/tests/runner/createTestServer.js +++ /dev/null @@ -1,66 +0,0 @@ -import { readFile } from "node:fs/promises"; -import bodyParser from "body-parser"; -import express from "express"; -import bodyParserErrorHandler from "express-body-parser-error-handler"; - -export async function createTestServer( report ) { - const app = express(); - - // Redirect home to test page - app.get( "/", ( _req, res ) => { - res.redirect( "/tests/" ); - } ); - - // Redirect to trailing slash - app.use( ( req, res, next ) => { - if ( req.path === "/tests" ) { - const query = req.url.slice( req.path.length ); - res.redirect( 301, `${ req.path }/${ query }` ); - } else { - next(); - } - } ); - - // Add a script tag to HTML pages to load the QUnit listeners - app.use( /\/tests\/unit\/([a-zA-Z0-9_-]+)\/\1\.html$/, async( req, res ) => { - const html = await readFile( - `tests/unit/${ req.params[ 0 ] }/${ req.params[ 0 ] }.html`, - "utf8" - ); - res.send( - html.replace( - "", - "" - ) - ); - } ); - - // Bind the reporter - app.post( - "/api/report", - bodyParser.json( { limit: "50mb" } ), - async( req, res ) => { - if ( report ) { - const response = await report( req.body ); - if ( response ) { - res.json( response ); - return; - } - } - res.sendStatus( 204 ); - } - ); - - // Handle errors from the body parser - app.use( bodyParserErrorHandler() ); - - // Serve static files - app.use( "/dist", express.static( "dist" ) ); - app.use( "/src", express.static( "src" ) ); - app.use( "/tests", express.static( "tests" ) ); - app.use( "/ui", express.static( "ui" ) ); - app.use( "/themes", express.static( "themes" ) ); - app.use( "/external", express.static( "external" ) ); - - return app; -} diff --git a/tests/runner/flags/browsers.js b/tests/runner/flags/browsers.js deleted file mode 100644 index 5d2306afee..0000000000 --- a/tests/runner/flags/browsers.js +++ /dev/null @@ -1,24 +0,0 @@ -// This list is static, so no requests are required -// in the command help menu. - -import { getBrowsers } from "../browserstack/api.js"; - -export const browsers = [ - "chrome", - "ie", - "firefox", - "edge", - "safari", - "opera", - "yandex", - "IE Mobile", - "Android Browser", - "Mobile Safari" -]; - -// A function that can be used to update the above list. -export async function getAvailableBrowsers() { - const browsers = await getBrowsers( { flat: true } ); - const available = [ ...new Set( browsers.map( ( { browser } ) => browser ) ) ]; - return available; -} diff --git a/tests/runner/flags/jquery.js b/tests/runner/flags/jquery.js deleted file mode 100644 index 0d4f215249..0000000000 --- a/tests/runner/flags/jquery.js +++ /dev/null @@ -1,14 +0,0 @@ -// Keep in sync with tests/lib/qunit.js -export const jquery = [ - "1.12.4", - "2.2.4", - "3.0.0", - "3.1.0", "3.1.1", - "3.2.0", "3.2.1", - "3.3.0", "3.3.1", - "3.4.0", "3.4.1", - "3.5.0", "3.5.1", - "3.6.0", "3.6.1", "3.6.2", "3.6.3", "3.6.4", - "3.7.0", "3.7.1", - "3.x-git", "git", "custom" -]; diff --git a/tests/runner/flags/suites.js b/tests/runner/flags/suites.js deleted file mode 100644 index a635ac4e56..0000000000 --- a/tests/runner/flags/suites.js +++ /dev/null @@ -1,27 +0,0 @@ -export const suites = [ - "accordion", - "autocomplete", - "button", - "checkboxradio", - "controlgroup", - "core", - "datepicker", - "dialog", - "draggable", - "droppable", - "effects", - "form-reset-mixin", - "jquery-patch", - "menu", - "position", - "progressbar", - "resizable", - "selectable", - "selectmenu", - "slider", - "sortable", - "spinner", - "tabs", - "tooltip", - "widget" -]; diff --git a/tests/runner/lib/buildTestUrl.js b/tests/runner/lib/buildTestUrl.js deleted file mode 100644 index 5eb3b049b0..0000000000 --- a/tests/runner/lib/buildTestUrl.js +++ /dev/null @@ -1,24 +0,0 @@ -export function buildTestUrl( suite, { browserstack, jquery, migrate, port, reportId } ) { - if ( !port ) { - throw new Error( "No port specified." ); - } - - const query = new URLSearchParams(); - - if ( jquery ) { - query.append( "jquery", jquery ); - } - - if ( migrate ) { - query.append( "migrate", "true" ); - } - - if ( reportId ) { - query.append( "reportId", reportId ); - } - - // BrowserStack supplies a custom domain for local testing, - // which is especially necessary for iOS testing. - const host = browserstack ? "bs-local.com" : "localhost"; - return `http://${ host }:${ port }/tests/unit/${ suite }/${ suite }.html?${ query }`; -} diff --git a/tests/runner/lib/generateHash.js b/tests/runner/lib/generateHash.js deleted file mode 100644 index 66f2161d5d..0000000000 --- a/tests/runner/lib/generateHash.js +++ /dev/null @@ -1,10 +0,0 @@ -import crypto from "node:crypto"; - -export function generateHash( string ) { - const hash = crypto.createHash( "md5" ); - hash.update( string ); - - // QUnit hashes are 8 characters long - // We use 10 characters to be more visually distinct - return hash.digest( "hex" ).slice( 0, 10 ); -} diff --git a/tests/runner/lib/getBrowserString.js b/tests/runner/lib/getBrowserString.js deleted file mode 100644 index 0d293074c7..0000000000 --- a/tests/runner/lib/getBrowserString.js +++ /dev/null @@ -1,48 +0,0 @@ -const browserMap = { - chrome: "Chrome", - edge: "Edge", - firefox: "Firefox", - ie: "IE", - opera: "Opera", - safari: "Safari" -}; - -export function browserSupportsHeadless( browser ) { - browser = browser.toLowerCase(); - return ( - browser === "chrome" || - browser === "firefox" || - browser === "edge" - ); -} - -export function getBrowserString( - { - browser, - browser_version: browserVersion, - device, - os, - os_version: osVersion - }, - headless -) { - browser = browser.toLowerCase(); - browser = browserMap[ browser ] || browser; - let str = browser; - if ( browserVersion ) { - str += ` ${ browserVersion }`; - } - if ( device ) { - str += ` for ${ device }`; - } - if ( os ) { - str += ` on ${ os }`; - } - if ( osVersion ) { - str += ` ${ osVersion }`; - } - if ( headless && browserSupportsHeadless( browser ) ) { - str += " (headless)"; - } - return str; -} diff --git a/tests/runner/lib/prettyMs.js b/tests/runner/lib/prettyMs.js deleted file mode 100644 index 99bae2b353..0000000000 --- a/tests/runner/lib/prettyMs.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Pretty print a time in milliseconds. - */ -export function prettyMs( time ) { - const minutes = Math.floor( time / 60000 ); - const seconds = Math.floor( time / 1000 ); - const ms = Math.floor( time % 1000 ); - - let prettyTime = `${ ms }ms`; - if ( seconds > 0 ) { - prettyTime = `${ seconds }s ${ prettyTime }`; - } - if ( minutes > 0 ) { - prettyTime = `${ minutes }m ${ prettyTime }`; - } - - return prettyTime; -} diff --git a/tests/runner/listeners.js b/tests/runner/listeners.js deleted file mode 100644 index ed6fb24e8d..0000000000 --- a/tests/runner/listeners.js +++ /dev/null @@ -1,112 +0,0 @@ -( function() { - "use strict"; - - // Get the report ID from the URL. - var match = location.search.match( /reportId=([^&]+)/ ); - if ( !match ) { - return; - } - var id = match[ 1 ]; - - // Adopted from https://github.com/douglascrockford/JSON-js - // Support: IE 11+ - // Using the replacer argument of JSON.stringify in IE has issues - // TODO: Replace this with a circular replacer + JSON.stringify + WeakSet - function decycle( object ) { - var objects = []; - - // The derez function recurses through the object, producing the deep copy. - function derez( value ) { - if ( - typeof value === "object" && - value !== null && - !( value instanceof Boolean ) && - !( value instanceof Date ) && - !( value instanceof Number ) && - !( value instanceof RegExp ) && - !( value instanceof String ) - ) { - - // Return a string early for elements - if ( value.nodeType ) { - return value.toString(); - } - - if ( objects.indexOf( value ) > -1 ) { - return; - } - - objects.push( value ); - - if ( Array.isArray( value ) ) { - - // If it is an array, replicate the array. - return value.map( derez ); - } else { - - // If it is an object, replicate the object. - var nu = Object.create( null ); - Object.keys( value ).forEach( function( name ) { - nu[ name ] = derez( value[ name ] ); - } ); - return nu; - } - } - - // Serialize Symbols as string representations so they are - // sent over the wire after being stringified. - if ( typeof value === "symbol" ) { - - // We can *describe* unique symbols, but note that their identity - // (e.g., `Symbol() !== Symbol()`) is lost - var ctor = Symbol.keyFor( value ) !== undefined ? "Symbol.for" : "Symbol"; - return ctor + "(" + JSON.stringify( value.description ) + ")"; - } - - return value; - } - return derez( object ); - } - - function send( type, data ) { - var json = JSON.stringify( { - id: id, - type: type, - data: data ? decycle( data ) : undefined - } ); - var request = new XMLHttpRequest(); - request.open( "POST", "/api/report", true ); - request.setRequestHeader( "Content-Type", "application/json" ); - request.send( json ); - return request; - } - - require( [ "qunit" ], function( QUnit ) { - - // Send acknowledgement to the server. - send( "ack" ); - - QUnit.on( "testEnd", function( data ) { - send( "testEnd", data ); - } ); - - QUnit.on( "runEnd", function( data ) { - - // Reduce the payload size. - // childSuites is large and unused. - data.childSuites = undefined; - - var request = send( "runEnd", data ); - request.onload = function() { - if ( request.status === 200 && request.responseText ) { - try { - var json = JSON.parse( request.responseText ); - window.location = json.url; - } catch ( e ) { - console.error( e ); - } - } - }; - } ); - } ); -} )(); diff --git a/tests/runner/package.json b/tests/runner/package.json deleted file mode 100644 index bedb411a91..0000000000 --- a/tests/runner/package.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "type": "module" -} diff --git a/tests/runner/queue.js b/tests/runner/queue.js deleted file mode 100644 index 1c9ac1acb7..0000000000 --- a/tests/runner/queue.js +++ /dev/null @@ -1,119 +0,0 @@ -import chalk from "chalk"; -import { getBrowserString } from "./lib/getBrowserString.js"; -import { - checkLastTouches, - createBrowserWorker, - restartBrowser, - setBrowserWorkerUrl -} from "./browsers.js"; - -const TEST_POLL_TIMEOUT = 1000; - -const queue = []; - -export function getNextBrowserTest( reportId ) { - const index = queue.findIndex( ( test ) => test.id === reportId ); - if ( index === -1 ) { - return; - } - - // Remove the completed test from the queue - const previousTest = queue[ index ]; - queue.splice( index, 1 ); - - // Find the next test for the same browser - for ( const test of queue.slice( index ) ) { - if ( test.fullBrowser === previousTest.fullBrowser ) { - - // Set the URL for our tracking - setBrowserWorkerUrl( test.browser, test.url ); - test.running = true; - - // Return the URL for the next test. - // listeners.js will use this to set the browser URL. - return { url: test.url }; - } - } -} - -export function retryTest( reportId, maxRetries ) { - if ( !maxRetries ) { - return; - } - const test = queue.find( ( test ) => test.id === reportId ); - if ( test ) { - test.retries++; - if ( test.retries <= maxRetries ) { - console.log( - `\nRetrying test ${ reportId } for ${ chalk.yellow( - test.options.suite - ) }...${ test.retries }` - ); - return test; - } - } -} - -export async function hardRetryTest( reportId, maxHardRetries ) { - if ( !maxHardRetries ) { - return false; - } - const test = queue.find( ( test ) => test.id === reportId ); - if ( test ) { - test.hardRetries++; - if ( test.hardRetries <= maxHardRetries ) { - console.log( - `\nHard retrying test ${ reportId } for ${ chalk.yellow( - test.options.suite - ) }...${ test.hardRetries }` - ); - await restartBrowser( test.browser ); - return true; - } - } - return false; -} - -export function addRun( url, browser, options ) { - queue.push( { - browser, - fullBrowser: getBrowserString( browser ), - hardRetries: 0, - id: options.reportId, - url, - options, - retries: 0, - running: false - } ); -} - -export async function runAll() { - return new Promise( async( resolve, reject ) => { - while ( queue.length ) { - try { - await checkLastTouches(); - } catch ( error ) { - reject( error ); - } - - // Run one test URL per browser at a time - const browsersTaken = []; - for ( const test of queue ) { - if ( browsersTaken.indexOf( test.fullBrowser ) > -1 ) { - continue; - } - browsersTaken.push( test.fullBrowser ); - if ( !test.running ) { - test.running = true; - try { - await createBrowserWorker( test.url, test.browser, test.options ); - } catch ( error ) { - reject( error ); - } - } - } - await new Promise( ( resolve ) => setTimeout( resolve, TEST_POLL_TIMEOUT ) ); - } - resolve(); - } ); -} diff --git a/tests/runner/reporter.js b/tests/runner/reporter.js deleted file mode 100644 index 6e47a68e41..0000000000 --- a/tests/runner/reporter.js +++ /dev/null @@ -1,134 +0,0 @@ -import chalk from "chalk"; -import * as Diff from "diff"; -import { getBrowserString } from "./lib/getBrowserString.js"; -import { prettyMs } from "./lib/prettyMs.js"; - -function serializeForDiff( value ) { - - // Use naive serialization for everything except types with confusable values - if ( typeof value === "string" ) { - return JSON.stringify( value ); - } - if ( typeof value === "bigint" ) { - return `${ value }n`; - } - return `${ value }`; -} - -export function reportTest( test, reportId, { browser, headless } ) { - if ( test.status === "passed" ) { - - // Write to console without newlines - process.stdout.write( "." ); - return; - } - - let message = `${ chalk.bold( `${ test.suiteName }: ${ test.name }` ) }`; - message += `\nTest ${ test.status } on ${ chalk.yellow( - getBrowserString( browser, headless ) - ) } (${ chalk.bold( reportId ) }).`; - - // test.assertions only contains passed assertions; - // test.errors contains all failed asssertions - if ( test.errors.length ) { - for ( const error of test.errors ) { - message += "\n"; - if ( error.message ) { - message += `\n${ error.message }`; - } - message += `\n${ chalk.gray( error.stack ) }`; - - // Show expected and actual values - // if either is defined and non-null. - // error.actual is set to null for failed - // assert.expect() assertions, so skip those as well. - // This should be fine because error.expected would - // have to also be null for this to be skipped. - if ( error.expected != null || error.actual != null ) { - message += `\nexpected: ${ chalk.red( JSON.stringify( error.expected ) ) }`; - message += `\nactual: ${ chalk.green( JSON.stringify( error.actual ) ) }`; - let diff; - - if ( Array.isArray( error.expected ) && Array.isArray( error.actual ) ) { - - // Diff arrays - diff = Diff.diffArrays( error.expected, error.actual ); - } else if ( - typeof error.expected === "object" && - typeof error.actual === "object" - ) { - - // Diff objects - diff = Diff.diffJson( error.expected, error.actual ); - } else if ( - typeof error.expected === "number" && - typeof error.actual === "number" - ) { - - // Diff numbers directly - const value = error.actual - error.expected; - if ( value > 0 ) { - diff = [ { added: true, value: `+${ value }` } ]; - } else { - diff = [ { removed: true, value: `${ value }` } ]; - } - } else if ( - typeof error.expected === "string" && - typeof error.actual === "string" - ) { - - // Diff the characters of strings - diff = Diff.diffChars( error.expected, error.actual ); - } else { - - // Diff everything else as words - diff = Diff.diffWords( - serializeForDiff( error.expected ), - serializeForDiff( error.actual ) - ); - } - - if ( diff ) { - message += "\n"; - message += diff - .map( ( part ) => { - if ( part.added ) { - return chalk.green( part.value ); - } - if ( part.removed ) { - return chalk.red( part.value ); - } - return chalk.gray( part.value ); - } ) - .join( "" ); - } - } - } - } - - console.log( `\n\n${ message }` ); - - // Only return failed messages - if ( test.status === "failed" ) { - return message; - } -} - -export function reportEnd( result, reportId, { browser, headless, jquery, migrate, suite } ) { - const fullBrowser = getBrowserString( browser, headless ); - console.log( - `\n\nTests finished in ${ prettyMs( result.runtime ) } ` + - `for ${ chalk.yellow( suite ) } ` + - `and jQuery ${ chalk.yellow( jquery ) } ` + - ( migrate ? `with ${ chalk.yellow( "jQuery Migrate enabled " ) }` : "" ) + - `in ${ chalk.yellow( fullBrowser ) } (${ chalk.bold( reportId ) })...` - ); - console.log( - ( result.status !== "passed" ? - `${ chalk.red( result.testCounts.failed ) } failed. ` : - "" ) + - `${ chalk.green( result.testCounts.total ) } passed. ` + - `${ chalk.gray( result.testCounts.skipped ) } skipped.` - ); - return result.testCounts; -} diff --git a/tests/runner/run.js b/tests/runner/run.js deleted file mode 100644 index 9c4f8d479b..0000000000 --- a/tests/runner/run.js +++ /dev/null @@ -1,338 +0,0 @@ -import chalk from "chalk"; -import { asyncExitHook, gracefulExit } from "exit-hook"; -import { getLatestBrowser } from "./browserstack/api.js"; -import { buildBrowserFromString } from "./browserstack/buildBrowserFromString.js"; -import { localTunnel } from "./browserstack/local.js"; -import { reportEnd, reportTest } from "./reporter.js"; -import { createTestServer } from "./createTestServer.js"; -import { buildTestUrl } from "./lib/buildTestUrl.js"; -import { generateHash } from "./lib/generateHash.js"; -import { getBrowserString } from "./lib/getBrowserString.js"; -import { suites as allSuites } from "./flags/suites.js"; -import { cleanupAllBrowsers, touchBrowser } from "./browsers.js"; -import { - addRun, - getNextBrowserTest, - hardRetryTest, - retryTest, - runAll -} from "./queue.js"; - -const EXIT_HOOK_WAIT_TIMEOUT = 60 * 1000; - -/** - * Run test suites in parallel in different browser instances. - */ -export async function run( { - browser: browserNames = [], - browserstack, - concurrency, - debug, - hardRetries, - headless, - jquery: jquerys = [], - migrate, - retries = 0, - runId, - suite: suites = [], - verbose -} ) { - if ( !browserNames.length ) { - browserNames = [ "chrome" ]; - } - if ( !suites.length ) { - suites = allSuites; - } - if ( !jquerys.length ) { - jquerys = [ "3.7.1" ]; - } - if ( headless && debug ) { - throw new Error( - "Cannot run in headless mode and debug mode at the same time." - ); - } - - if ( verbose ) { - console.log( browserstack ? "Running in BrowserStack." : "Running locally." ); - } - - const errorMessages = []; - const pendingErrors = {}; - - // Convert browser names to browser objects - let browsers = browserNames.map( ( b ) => ( { browser: b } ) ); - const tunnelId = generateHash( - `${ Date.now() }-${ suites.join( ":" ) }-${ ( browserstack || [] ) - .concat( browserNames ) - .join( ":" ) }` - ); - - // A unique identifier for this run - if ( !runId ) { - runId = tunnelId; - } - - // Create the test app and - // hook it up to the reporter - const reports = Object.create( null ); - const app = await createTestServer( async( message ) => { - switch ( message.type ) { - case "testEnd": { - const reportId = message.id; - const report = reports[ reportId ]; - touchBrowser( report.browser ); - const errors = reportTest( message.data, reportId, report ); - pendingErrors[ reportId ] ??= Object.create( null ); - if ( errors ) { - pendingErrors[ reportId ][ message.data.name ] = errors; - } else { - const existing = pendingErrors[ reportId ][ message.data.name ]; - - // Show a message for flakey tests - if ( existing ) { - console.log(); - console.warn( - chalk.italic( - chalk.gray( existing.replace( "Test failed", "Test flakey" ) ) - ) - ); - console.log(); - delete pendingErrors[ reportId ][ message.data.name ]; - } - } - break; - } - case "runEnd": { - const reportId = message.id; - const report = reports[ reportId ]; - touchBrowser( report.browser ); - const { failed, total } = reportEnd( - message.data, - message.id, - reports[ reportId ] - ); - report.total = total; - - // Handle failure - if ( failed ) { - const retry = retryTest( reportId, retries ); - - // Retry if retryTest returns a test - if ( retry ) { - return retry; - } - - // Return early if hardRetryTest returns true - if ( await hardRetryTest( reportId, hardRetries ) ) { - return; - } - errorMessages.push( ...Object.values( pendingErrors[ reportId ] ) ); - } - - // Run the next test - return getNextBrowserTest( reportId ); - } - case "ack": { - const report = reports[ message.id ]; - touchBrowser( report.browser ); - break; - } - default: - console.warn( "Received unknown message type:", message.type ); - } - } ); - - // Start up local test server - let server; - let port; - await new Promise( ( resolve ) => { - - // Pass 0 to choose a random, unused port - server = app.listen( 0, () => { - port = server.address().port; - resolve(); - } ); - } ); - - if ( !server || !port ) { - throw new Error( "Server not started." ); - } - - if ( verbose ) { - console.log( `Server started on port ${ port }.` ); - } - - function stopServer() { - return new Promise( ( resolve ) => { - server.close( () => { - if ( verbose ) { - console.log( "Server stopped." ); - } - resolve(); - } ); - } ); - } - - async function cleanup() { - console.log( "Cleaning up..." ); - - await cleanupAllBrowsers( { verbose } ); - - if ( tunnel ) { - await tunnel.stop(); - if ( verbose ) { - console.log( "Stopped BrowserStackLocal." ); - } - } - } - - asyncExitHook( - async() => { - await cleanup(); - await stopServer(); - }, - { wait: EXIT_HOOK_WAIT_TIMEOUT } - ); - - // Start up BrowserStackLocal - let tunnel; - if ( browserstack ) { - if ( headless ) { - console.warn( - chalk.italic( - "BrowserStack does not support headless mode. Running in normal mode." - ) - ); - headless = false; - } - - // Convert browserstack to browser objects. - // If browserstack is an empty array, fall back - // to the browsers array. - if ( browserstack.length ) { - browsers = browserstack.map( ( b ) => { - if ( !b ) { - return browsers[ 0 ]; - } - return buildBrowserFromString( b ); - } ); - } - - // Fill out browser defaults - browsers = await Promise.all( - browsers.map( async( browser ) => { - - // Avoid undici connect timeout errors - await new Promise( ( resolve ) => setTimeout( resolve, 100 ) ); - - const latestMatch = await getLatestBrowser( browser ); - if ( !latestMatch ) { - console.error( - chalk.red( `Browser not found: ${ getBrowserString( browser ) }.` ) - ); - gracefulExit( 1 ); - } - return latestMatch; - } ) - ); - - tunnel = await localTunnel( tunnelId ); - if ( verbose ) { - console.log( "Started BrowserStackLocal." ); - } - } - - function queueRuns( suite, browser ) { - const fullBrowser = getBrowserString( browser, headless ); - - for ( const jquery of jquerys ) { - const reportId = generateHash( `${ suite } ${ jquery } ${ fullBrowser }` ); - reports[ reportId ] = { browser, headless, jquery, migrate, suite }; - - const url = buildTestUrl( suite, { - browserstack, - jquery, - migrate, - port, - reportId - } ); - - const options = { - browserstack, - concurrency, - debug, - headless, - jquery, - migrate, - reportId, - runId, - suite, - tunnelId, - verbose - }; - - addRun( url, browser, options ); - } - } - - for ( const browser of browsers ) { - for ( const suite of suites ) { - queueRuns( [ suite ], browser ); - } - } - - try { - console.log( `Starting Run ${ runId }...` ); - await runAll(); - } catch ( error ) { - console.error( error ); - if ( !debug ) { - gracefulExit( 1 ); - } - } finally { - console.log(); - if ( errorMessages.length === 0 ) { - let stop = false; - for ( const report of Object.values( reports ) ) { - if ( !report.total ) { - stop = true; - console.error( - chalk.red( - `No tests were run for ${ report.suite } in ${ getBrowserString( - report.browser - ) }` - ) - ); - } - } - if ( stop ) { - return gracefulExit( 1 ); - } - console.log( chalk.green( "All tests passed!" ) ); - - if ( !debug || browserstack ) { - gracefulExit( 0 ); - } - } else { - console.error( chalk.red( `${ errorMessages.length } tests failed.` ) ); - console.log( - errorMessages.map( ( error, i ) => `\n${ i + 1 }. ${ error }` ).join( "\n" ) - ); - - if ( debug ) { - console.log(); - if ( browserstack ) { - console.log( "Leaving browsers with failures open for debugging." ); - console.log( - "View running sessions at https://automate.browserstack.com/dashboard/v2/" - ); - } else { - console.log( "Leaving browsers open for debugging." ); - } - console.log( "Press Ctrl+C to exit." ); - } else { - gracefulExit( 1 ); - } - } - } -} diff --git a/tests/runner/selenium/createDriver.js b/tests/runner/selenium/createDriver.js deleted file mode 100644 index 095c12214d..0000000000 --- a/tests/runner/selenium/createDriver.js +++ /dev/null @@ -1,84 +0,0 @@ -import { Builder, Capabilities, logging } from "selenium-webdriver"; -import Chrome from "selenium-webdriver/chrome.js"; -import Edge from "selenium-webdriver/edge.js"; -import Firefox from "selenium-webdriver/firefox.js"; -import { browserSupportsHeadless } from "../lib/getBrowserString.js"; - -// Set script timeout to 10min -const DRIVER_SCRIPT_TIMEOUT = 1000 * 60 * 10; - -export default async function createDriver( { browserName, headless, url, verbose } ) { - const capabilities = Capabilities[ browserName ](); - const prefs = new logging.Preferences(); - prefs.setLevel( logging.Type.BROWSER, logging.Level.ALL ); - capabilities.setLoggingPrefs( prefs ); - - let driver = new Builder().withCapabilities( capabilities ); - - const chromeOptions = new Chrome.Options(); - chromeOptions.addArguments( "--enable-chrome-browser-cloud-management" ); - - // Alter the chrome binary path if - // the CHROME_BIN environment variable is set - if ( process.env.CHROME_BIN ) { - if ( verbose ) { - console.log( `Setting chrome binary to ${ process.env.CHROME_BIN }` ); - } - chromeOptions.setChromeBinaryPath( process.env.CHROME_BIN ); - } - - const firefoxOptions = new Firefox.Options(); - - if ( process.env.FIREFOX_BIN ) { - if ( verbose ) { - console.log( `Setting firefox binary to ${ process.env.FIREFOX_BIN }` ); - } - - firefoxOptions.setBinary( process.env.FIREFOX_BIN ); - } - - const edgeOptions = new Edge.Options(); - edgeOptions.addArguments( "--enable-chrome-browser-cloud-management" ); - - // Alter the edge binary path if - // the EDGE_BIN environment variable is set - if ( process.env.EDGE_BIN ) { - if ( verbose ) { - console.log( `Setting edge binary to ${ process.env.EDGE_BIN }` ); - } - edgeOptions.setEdgeChromiumBinaryPath( process.env.EDGE_BIN ); - } - - if ( headless ) { - chromeOptions.addArguments( "--headless=new" ); - firefoxOptions.addArguments( "--headless" ); - edgeOptions.addArguments( "--headless=new" ); - if ( !browserSupportsHeadless( browserName ) ) { - console.log( - `Headless mode is not supported for ${ browserName }.` + - "Running in normal mode instead." - ); - } - } - - driver = await driver - .setChromeOptions( chromeOptions ) - .setFirefoxOptions( firefoxOptions ) - .setEdgeOptions( edgeOptions ) - .build(); - - if ( verbose ) { - const driverCapabilities = await driver.getCapabilities(); - const name = driverCapabilities.getBrowserName(); - const version = driverCapabilities.getBrowserVersion(); - console.log( `\nDriver created for ${ name } ${ version }` ); - } - - // Increase script timeout to 10min - await driver.manage().setTimeouts( { script: DRIVER_SCRIPT_TIMEOUT } ); - - // Set the first URL for the browser - await driver.get( url ); - - return driver; -} diff --git a/tests/runner/server.js b/tests/runner/server.js deleted file mode 100644 index 10fbc220f4..0000000000 --- a/tests/runner/server.js +++ /dev/null @@ -1,13 +0,0 @@ -import { createTestServer } from "./createTestServer.js"; - -const port = process.env.PORT || 3000; - -async function runServer() { - const app = await createTestServer(); - - app.listen( { port, host: "0.0.0.0" }, function() { - console.log( `Open tests at http://localhost:${ port }/tests/` ); - } ); -} - -runServer(); From 303fb3bc7393d3127b6e86e81ade08e06b30019d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2025 23:26:06 +0100 Subject: [PATCH 41/53] Build: Bump the github-actions group with 2 updates Bumps the github-actions group with 2 updates: [github/codeql-action](https://github.com/github/codeql-action) and [actions/setup-node](https://github.com/actions/setup-node). Closes gh-2328 Updates `github/codeql-action` from 3.28.0 to 3.28.8 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/48ab28a6f5dbc2a99bf1e0131198dd8f1df78169...dd746615b3b9d728a6a37ca2045b68ca76d4841a) Updates `actions/setup-node` from 4.1.0 to 4.2.0 - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/39370e3970a6d050c480ffad4ff0ed4d3fdee5af...1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/filestash.yml | 2 +- .github/workflows/node.js.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index f4ce8091cb..e7c145c0a6 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -33,7 +33,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0 + uses: github/codeql-action/init@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3.28.8 # Override language selection by uncommenting this and choosing your languages # with: # languages: go, javascript, csharp, python, cpp, java @@ -41,7 +41,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0 + uses: github/codeql-action/autobuild@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3.28.8 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -55,4 +55,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0 + uses: github/codeql-action/analyze@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3.28.8 diff --git a/.github/workflows/filestash.yml b/.github/workflows/filestash.yml index 8de197a66c..7716025a08 100644 --- a/.github/workflows/filestash.yml +++ b/.github/workflows/filestash.yml @@ -20,7 +20,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 + uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: node-version: ${{ env.NODE_VERSION }} diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index f23498ffd2..6279223a35 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -34,7 +34,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 + uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: node-version: ${{ env.NODE_VERSION }} @@ -78,7 +78,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 + uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: node-version: ${{ env.NODE_VERSION }} @@ -116,7 +116,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 + uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: node-version: ${{ env.NODE_VERSION }} From fd7dbcdff6b4cec9efadfa4a3e290c397afa3a02 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Tue, 18 Feb 2025 14:52:04 -0500 Subject: [PATCH 42/53] Build: Upgrade jtr to 0.2.5 Closes gh-2332 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 56f60f34dd..5e8b700ff8 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "grunt-eslint": "24.0.1", "grunt-git-authors": "3.2.0", "grunt-html": "17.1.0", - "jquery-test-runner": "0.2.1", + "jquery-test-runner": "0.2.5", "load-grunt-tasks": "5.1.0", "rimraf": "6.0.1" }, From 302b488b9214e14830496578f7cf0aebcc33c132 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski-Owczarek?= Date: Mon, 3 Mar 2025 18:58:38 +0100 Subject: [PATCH 43/53] Build: Switch from UglifyJS to SWC minify, make the minified file ES5 More recent UglifyJS versions have started converting regular functions to arrow ones, making ES5 source file migrated to a ES2015+ minified one. We want to avoid that even in 1.14.x as long as we keep the source file in ES5. Closes gh-2335 Ref mishoo/UglifyJS#5967 Ref jquery/download.jqueryui.com#629 --- Gruntfile.js | 11 ++++----- build/tasks/minify.js | 53 +++++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 3 files changed, 58 insertions(+), 8 deletions(-) create mode 100644 build/tasks/minify.js diff --git a/Gruntfile.js b/Gruntfile.js index 334e4bb1ae..cc532b6e93 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -51,9 +51,6 @@ const cssFiles = [ // minified files const minify = { - options: { - preserveComments: false - }, main: { options: { banner: createBanner( uiFiles ) @@ -174,7 +171,7 @@ grunt.initConfig( { } }, - uglify: minify, + minify, htmllint: { good: { options: { @@ -403,9 +400,9 @@ grunt.registerTask( "lint", [ "csslint", "htmllint" ] ); -grunt.registerTask( "build", [ "requirejs", "concat" ] ); +grunt.registerTask( "build", [ "requirejs", "concat", "minify:main" ] ); grunt.registerTask( "default", [ "lint", "build" ] ); -grunt.registerTask( "sizer", [ "requirejs:js", "uglify:main", "compare_size:all" ] ); -grunt.registerTask( "sizer_all", [ "requirejs:js", "uglify", "compare_size" ] ); +grunt.registerTask( "sizer", [ "requirejs:js", "minify:main", "compare_size:all" ] ); +grunt.registerTask( "sizer_all", [ "requirejs:js", "minify", "compare_size" ] ); }; diff --git a/build/tasks/minify.js b/build/tasks/minify.js new file mode 100644 index 0000000000..6d83831ee3 --- /dev/null +++ b/build/tasks/minify.js @@ -0,0 +1,53 @@ +"use strict"; + +const swc = require( "@swc/core" ); + +module.exports = function( grunt ) { + +grunt.registerMultiTask( "minify", async function() { + const done = this.async(); + const options = this.options(); + + for ( const file of this.files ) { + if ( file.src.length === 0 ) { + grunt.log.writeln( + `No source file found, skipping minification to "${ file.dest }".` ); + continue; + } + if ( file.src.length !== 1 ) { + grunt.fail.warn( "Minifying multiple source files into one " + + "destination file not supported" ); + } + + const contents = grunt.file.read( file.src[ 0 ] ); + + const { code } = await swc.minify( + contents, + { + compress: { + ecma: 5, + hoist_funs: false, + loops: false + }, + format: { + ecma: 5, + asciiOnly: true, + comments: false, + preamble: options.banner + }, + inlineSourcesContent: false, + mangle: true, + module: false, + sourceMap: false + } + ); + + grunt.file.write( file.dest, code ); + + grunt.log.writeln( `File ${ file.dest } created.` ); + } + + done(); +} ); + +}; diff --git a/package.json b/package.json index 5e8b700ff8..c34bef799c 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "jquery": ">=1.12.0 <5.0.0" }, "devDependencies": { + "@swc/core": "1.11.5", "commitplease": "3.2.0", "eslint-config-jquery": "3.0.2", "grunt": "1.6.1", @@ -63,7 +64,6 @@ "grunt-contrib-concat": "2.1.0", "grunt-contrib-csslint": "2.0.0", "grunt-contrib-requirejs": "1.0.0", - "grunt-contrib-uglify": "5.2.2", "grunt-eslint": "24.0.1", "grunt-git-authors": "3.2.0", "grunt-html": "17.1.0", From 1da395de2e6759dfe9a7a199b03a39365e30f16c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski-Owczarek?= Date: Mon, 3 Mar 2025 20:15:14 +0100 Subject: [PATCH 44/53] Build: Update ESLint to v9, migrate to flat config, lint dist files Dist files linting is limited to checking if they're proper ES5. Closes gh-2336 --- .eslintignore | 4 - .eslintrc.json | 21 ----- .github/workflows/node.js.yml | 7 +- Gruntfile.js | 5 +- demos/.eslintrc.json | 9 -- eslint.config.mjs | 162 ++++++++++++++++++++++++++++++++++ package.json | 3 +- ui/.eslintrc.json | 42 --------- ui/effect.js | 4 +- ui/effects/effect-explode.js | 2 - ui/widgets/accordion.js | 2 - ui/widgets/datepicker.js | 10 +-- ui/widgets/progressbar.js | 2 - ui/widgets/resizable.js | 2 +- ui/widgets/selectmenu.js | 2 - ui/widgets/tabs.js | 4 +- 16 files changed, 181 insertions(+), 100 deletions(-) delete mode 100644 .eslintignore delete mode 100644 .eslintrc.json delete mode 100644 demos/.eslintrc.json create mode 100644 eslint.config.mjs delete mode 100644 ui/.eslintrc.json diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 5e992599f8..0000000000 --- a/.eslintignore +++ /dev/null @@ -1,4 +0,0 @@ -dist/**/* -external/**/* -tests/lib/vendor/**/* -ui/vendor/**/* diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index e7d67eb0e5..0000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "root": true, - - "extends": "jquery", - - // Uncomment to find useless comment disable directives - // "reportUnusedDisableDirectives": true, - - "parserOptions": { - "ecmaVersion": 2018 - }, - - "env": { - "es6": true, - "node": true - }, - - "rules": { - "strict": [ "error", "global" ] - } -} diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 6279223a35..eef7c86e73 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -49,12 +49,13 @@ jobs: - name: Install npm dependencies run: npm install - - name: Lint - run: npm run lint - - name: Build run: npm run build + # Lint must happen after build as we lint generated files. + - name: Lint + run: npm run lint + - name: Test run: | npm run test:unit -- \ diff --git a/Gruntfile.js b/Gruntfile.js index cc532b6e93..bbb71d33e5 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -204,9 +204,12 @@ grunt.initConfig( { "ui/**/*.js", "!ui/vendor/**/*.js", "Gruntfile.js", + "dist/jquery-ui.js", + "dist/jquery-ui.min.js", "build/**/*.js", "tests/unit/**/*.js", "tests/lib/**/*.js", + "!tests/lib/vendor/**/*.js", "demos/**/*.js" ] }, @@ -401,7 +404,7 @@ grunt.registerTask( "lint", [ "htmllint" ] ); grunt.registerTask( "build", [ "requirejs", "concat", "minify:main" ] ); -grunt.registerTask( "default", [ "lint", "build" ] ); +grunt.registerTask( "default", [ "build", "lint" ] ); grunt.registerTask( "sizer", [ "requirejs:js", "minify:main", "compare_size:all" ] ); grunt.registerTask( "sizer_all", [ "requirejs:js", "minify", "compare_size" ] ); diff --git a/demos/.eslintrc.json b/demos/.eslintrc.json deleted file mode 100644 index 805ec8eb26..0000000000 --- a/demos/.eslintrc.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "root": true, - - "extends": "../ui/.eslintrc.json", - - "globals": { - "require": true - } -} diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000000..4fb03f6b3e --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,162 @@ +import jqueryConfig from "eslint-config-jquery"; +import globals from "globals"; + +export default [ + { + ignores: [ + "dist/**/*", + "!dist/jquery-ui.js", + "!dist/jquery-ui.min.js", + "external/**/*", + "tests/lib/vendor/**/*", + "ui/vendor/**/*" + ] + }, + + { + ignores: [ "dist/**/*" ], + rules: { + ...jqueryConfig.rules, + "no-unused-vars": [ + "error", + { + argsIgnorePattern: "^_", + caughtErrorsIgnorePattern: "^_" + } + ] + } + }, + + { + files: [ "Gruntfile.js" ], + languageOptions: { + ecmaVersion: "latest", + sourceType: "commonjs", + globals: { + ...globals.node + } + }, + rules: { + strict: [ "error", "global" ] + } + }, + + { + files: [ "eslint.config.mjs" ], + languageOptions: { + ecmaVersion: "latest", + sourceType: "module", + globals: { + ...globals.node + } + }, + rules: { + strict: [ "error", "global" ] + } + }, + + // Source, demos + { + files: [ "ui/**/*.js", "demos/**/*.js" ], + languageOptions: { + ecmaVersion: 5, + sourceType: "script", + globals: { + ...globals.browser, + ...globals.jquery, + define: false, + Globalize: false + } + }, + rules: { + strict: [ "error", "function" ], + + // The following rule is relaxed due to too many violations: + "no-unused-vars": [ + "error", + { + args: "after-used", + argsIgnorePattern: "^_", + caughtErrorsIgnorePattern: "^_" + } + ], + + // Too many violations: + camelcase: "off", + "no-nested-ternary": "off" + } + }, + { + files: [ "ui/i18n/**/*.js" ], + rules: { + + // We want to keep all the strings in separate single lines + "max-len": "off" + } + }, + + // Dist files + // For dist files, we don't include any jQuery rules on purpose. + // We just want to make sure the files are correct ES5. + { + files: [ "dist/jquery-ui.js", "dist/jquery-ui.min.js" ], + languageOptions: { + ecmaVersion: 5, + sourceType: "script" + }, + linterOptions: { + reportUnusedDisableDirectives: "off" + } + }, + + // Build + { + files: [ "build/**/*.js" ], + languageOptions: { + ecmaVersion: "latest", + sourceType: "commonjs", + globals: { + ...globals.node + } + }, + rules: { + "no-implicit-globals": "error", + strict: [ "error", "global" ] + } + }, + + // Demos + { + files: [ "demos/**/*.js" ], + languageOptions: { + globals: { + require: true + } + } + }, + + // Tests + { + files: [ "tests/**/*.js" ], + languageOptions: { + ecmaVersion: 5, + sourceType: "script", + globals: { + ...globals.browser, + ...globals.jquery, + define: false, + Globalize: false, + QUnit: false, + require: true, + requirejs: true + } + }, + "rules": { + + // Too many violations: + "max-len": "off", + "no-unused-vars": "off", + strict: "off" // ideally, `[ "error", "function" ]` + } + } +]; diff --git a/package.json b/package.json index c34bef799c..00f9e07fef 100644 --- a/package.json +++ b/package.json @@ -58,13 +58,14 @@ "@swc/core": "1.11.5", "commitplease": "3.2.0", "eslint-config-jquery": "3.0.2", + "globals": "16.0.0", "grunt": "1.6.1", "grunt-bowercopy": "1.2.5", "grunt-compare-size": "0.4.2", "grunt-contrib-concat": "2.1.0", "grunt-contrib-csslint": "2.0.0", "grunt-contrib-requirejs": "1.0.0", - "grunt-eslint": "24.0.1", + "grunt-eslint": "25.0.0", "grunt-git-authors": "3.2.0", "grunt-html": "17.1.0", "jquery-test-runner": "0.2.5", diff --git a/ui/.eslintrc.json b/ui/.eslintrc.json deleted file mode 100644 index eaba81af2a..0000000000 --- a/ui/.eslintrc.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "root": true, - - "extends": "jquery", - - "parserOptions": { - "ecmaVersion": 5 - }, - - "env": { - "browser": true, - "jquery": true, - "node": false - }, - - "rules": { - "strict": [ "error", "function" ], - - // The following rule is relaxed due to too many violations: - "no-unused-vars": [ "error", { "vars": "all", "args": "after-used" } ], - - // Too many violations: - "camelcase": "off", - "no-nested-ternary": "off" - }, - - "globals": { - "define": false, - "Globalize": false - }, - - "overrides": [ - { - "files": [ "i18n/**/*.js" ], - "rules": { - - // We want to keep all the strings in separate single lines - "max-len": "off" - } - } - ] -} diff --git a/ui/effect.js b/ui/effect.js index bbbb733c3d..cb9ab80433 100644 --- a/ui/effect.js +++ b/ui/effect.js @@ -9,9 +9,7 @@ //>>label: Effects Core //>>group: Effects -/* eslint-disable max-len */ //>>description: Extends the internal jQuery effects. Includes morphing and easing. Required by all other effects. -/* eslint-enable max-len */ //>>docs: https://api.jqueryui.com/category/effects-core/ //>>demos: https://jqueryui.com/effect/ @@ -320,7 +318,7 @@ if ( $.uiBackCompat === true ) { try { // eslint-disable-next-line no-unused-expressions active.id; - } catch ( e ) { + } catch ( _e ) { active = document.body; } diff --git a/ui/effects/effect-explode.js b/ui/effects/effect-explode.js index ed40833a89..da38b4d556 100644 --- a/ui/effects/effect-explode.js +++ b/ui/effects/effect-explode.js @@ -9,9 +9,7 @@ //>>label: Explode Effect //>>group: Effects -/* eslint-disable max-len */ //>>description: Explodes an element in all directions into n pieces. Implodes an element to its original wholeness. -/* eslint-enable max-len */ //>>docs: https://api.jqueryui.com/explode-effect/ //>>demos: https://jqueryui.com/effect/ diff --git a/ui/widgets/accordion.js b/ui/widgets/accordion.js index ff6e4631da..43a50db831 100644 --- a/ui/widgets/accordion.js +++ b/ui/widgets/accordion.js @@ -9,9 +9,7 @@ //>>label: Accordion //>>group: Widgets -/* eslint-disable max-len */ //>>description: Displays collapsible content panels for presenting information in a limited amount of space. -/* eslint-enable max-len */ //>>docs: https://api.jqueryui.com/accordion/ //>>demos: https://jqueryui.com/accordion/ //>>css.structure: ../../themes/base/core.css diff --git a/ui/widgets/datepicker.js b/ui/widgets/datepicker.js index 323723b893..029f255e87 100644 --- a/ui/widgets/datepicker.js +++ b/ui/widgets/datepicker.js @@ -1,4 +1,4 @@ -/* eslint-disable max-len, camelcase */ +/* eslint-disable max-len */ /*! * jQuery UI Datepicker @VERSION * https://jqueryui.com @@ -535,7 +535,7 @@ $.extend( Datepicker.prototype, { _getInst: function( target ) { try { return $.data( target, "datepicker" ); - } catch ( err ) { + } catch ( _err ) { throw "Missing instance data for this datepicker"; } }, @@ -768,7 +768,7 @@ $.extend( Datepicker.prototype, { $.datepicker._updateAlternate( inst ); $.datepicker._updateDatepicker( inst ); } - } catch ( err ) { + } catch ( _err ) { } } return true; @@ -1540,7 +1540,7 @@ $.extend( Datepicker.prototype, { try { date = this.parseDate( dateFormat, dates, settings ) || defaultDate; - } catch ( event ) { + } catch ( _err ) { dates = ( noDefault ? "" : dates ); } inst.selectedDay = date.getDate(); @@ -1569,7 +1569,7 @@ $.extend( Datepicker.prototype, { try { return $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ), offset, $.datepicker._getFormatConfig( inst ) ); - } catch ( e ) { + } catch ( _e ) { // Ignore } diff --git a/ui/widgets/progressbar.js b/ui/widgets/progressbar.js index 20e96440a0..ad5366adea 100644 --- a/ui/widgets/progressbar.js +++ b/ui/widgets/progressbar.js @@ -9,9 +9,7 @@ //>>label: Progressbar //>>group: Widgets -/* eslint-disable max-len */ //>>description: Displays a status indicator for loading state, standard percentage, and other progress indicators. -/* eslint-enable max-len */ //>>docs: https://api.jqueryui.com/progressbar/ //>>demos: https://jqueryui.com/progressbar/ //>>css.structure: ../../themes/base/core.css diff --git a/ui/widgets/resizable.js b/ui/widgets/resizable.js index 6f1e0ebdec..0123152831 100644 --- a/ui/widgets/resizable.js +++ b/ui/widgets/resizable.js @@ -104,7 +104,7 @@ $.widget( "ui.resizable", $.ui.mouse, { el[ scroll ] = 1; has = ( el[ scroll ] > 0 ); el[ scroll ] = 0; - } catch ( e ) { + } catch ( _e ) { // `el` might be a string, then setting `scroll` will throw // an error in strict mode; ignore it. diff --git a/ui/widgets/selectmenu.js b/ui/widgets/selectmenu.js index f1b48fa603..749e334919 100644 --- a/ui/widgets/selectmenu.js +++ b/ui/widgets/selectmenu.js @@ -9,9 +9,7 @@ //>>label: Selectmenu //>>group: Widgets -/* eslint-disable max-len */ //>>description: Duplicates and extends the functionality of a native HTML select element, allowing it to be customizable in behavior and appearance far beyond the limitations of a native select. -/* eslint-enable max-len */ //>>docs: https://api.jqueryui.com/selectmenu/ //>>demos: https://jqueryui.com/selectmenu/ //>>css.structure: ../../themes/base/core.css diff --git a/ui/widgets/tabs.js b/ui/widgets/tabs.js index 7b7907c327..49468feb39 100644 --- a/ui/widgets/tabs.js +++ b/ui/widgets/tabs.js @@ -73,10 +73,10 @@ $.widget( "ui.tabs", { // Decoding may throw an error if the URL isn't UTF-8 (#9518) try { anchorUrl = decodeURIComponent( anchorUrl ); - } catch ( error ) {} + } catch ( _error ) {} try { locationUrl = decodeURIComponent( locationUrl ); - } catch ( error ) {} + } catch ( _error ) {} return anchor.hash.length > 1 && anchorUrl === locationUrl; }; From 1749a5f4151b3e63662ddc53549cb5b99da3567a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Mar 2025 19:56:04 +0100 Subject: [PATCH 45/53] Build: Bump the github-actions group with 2 updates Bumps the github-actions group with 2 updates: [github/codeql-action](https://github.com/github/codeql-action) and [actions/cache](https://github.com/actions/cache). Closes gh-2334 Updates `github/codeql-action` from 3.28.8 to 3.28.10 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/dd746615b3b9d728a6a37ca2045b68ca76d4841a...b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d) Updates `actions/cache` from 4.2.0 to 4.2.2 - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/1bd1e32a3bdc45362d1e726936510720a7c30a57...d4323d4df104b026a6aa633fdb11d772146be0bf) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/filestash.yml | 2 +- .github/workflows/node.js.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index e7c145c0a6..cc842ea8e2 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -33,7 +33,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3.28.8 + uses: github/codeql-action/init@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10 # Override language selection by uncommenting this and choosing your languages # with: # languages: go, javascript, csharp, python, cpp, java @@ -41,7 +41,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3.28.8 + uses: github/codeql-action/autobuild@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -55,4 +55,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3.28.8 + uses: github/codeql-action/analyze@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10 diff --git a/.github/workflows/filestash.yml b/.github/workflows/filestash.yml index 7716025a08..88c949ea42 100644 --- a/.github/workflows/filestash.yml +++ b/.github/workflows/filestash.yml @@ -25,7 +25,7 @@ jobs: node-version: ${{ env.NODE_VERSION }} - name: Cache - uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2 with: path: ~/.npm key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock-${{ hashFiles('**/package-lock.json') }} diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index eef7c86e73..7614468f85 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -39,7 +39,7 @@ jobs: node-version: ${{ env.NODE_VERSION }} - name: Cache - uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2 with: path: ~/.npm key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock-${{ hashFiles('**/package-lock.json') }} @@ -84,7 +84,7 @@ jobs: node-version: ${{ env.NODE_VERSION }} - name: Cache - uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2 with: path: ~/.npm key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock-${{ hashFiles('**/package-lock.json') }} @@ -122,7 +122,7 @@ jobs: node-version: ${{ env.NODE_VERSION }} - name: Cache - uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2 with: path: ~/.npm key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock-${{ hashFiles('**/package-lock.json') }} From ef28a5f57036e32a66e6d469e345d7376ecdaffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski-Owczarek?= Date: Tue, 18 Mar 2025 09:35:16 +0100 Subject: [PATCH 46/53] Build: Remove an obsolete `test/.eslintrc.json` file The file was erroneously left in during the migration to the flat config. Closes gh-2340 Ref gh-2336 --- tests/.eslintrc.json | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 tests/.eslintrc.json diff --git a/tests/.eslintrc.json b/tests/.eslintrc.json deleted file mode 100644 index 714077182a..0000000000 --- a/tests/.eslintrc.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "parserOptions": { - "ecmaVersion": 5 - }, - - "env": { - "browser": true, - "jquery": true, - "node": false - }, - - "rules": { - // Too many violations: - "max-len": "off", - "no-unused-vars": "off", - "strict": "off" // ideally, `[ "error", "function" ]` - }, - - "globals": { - "define": false, - "Globalize": false, - "QUnit": false, - "require": true, - "requirejs": true - } -} From 6843ced12e4051aefbee47cf87fa79794737eb8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski-Owczarek?= Date: Tue, 18 Mar 2025 11:45:00 +0100 Subject: [PATCH 47/53] Spinner: Drop dependency on jQuery Mousewheel 1. Listen to the native `wheel` event without depending on any wrapper plugins. 2. Keep listening to the `mousewheel` event for compatibility with projects using the jQuery Mousewheel plugin but route it to the `wheel` handler. Closes gh-2338 --- Gruntfile.js | 3 - bower.json | 1 - demos/spinner/currency.html | 2 +- demos/spinner/decimal.html | 2 +- demos/spinner/default.html | 2 +- demos/spinner/latlong.html | 2 +- demos/spinner/overflow.html | 2 +- demos/spinner/time.html | 2 +- external/jquery-mousewheel/LICENSE.txt | 20 -- .../jquery-mousewheel/jquery.mousewheel.js | 221 ------------------ tests/unit/spinner/core.js | 42 +++- ui/widgets/spinner.js | 19 +- 12 files changed, 64 insertions(+), 254 deletions(-) delete mode 100644 external/jquery-mousewheel/LICENSE.txt delete mode 100644 external/jquery-mousewheel/jquery.mousewheel.js diff --git a/Gruntfile.js b/Gruntfile.js index bbb71d33e5..4f7dcc73e7 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -247,9 +247,6 @@ grunt.initConfig( { "requirejs/require.js": "requirejs/require.js", - "jquery-mousewheel/jquery.mousewheel.js": "jquery-mousewheel/jquery.mousewheel.js", - "jquery-mousewheel/LICENSE.txt": "jquery-mousewheel/LICENSE.txt", - "jquery-simulate/jquery.simulate.js": "jquery-simulate/jquery.simulate.js", "jquery-simulate/LICENSE.txt": "jquery-simulate/LICENSE.txt", diff --git a/bower.json b/bower.json index eec454dea0..3ed76cee9c 100644 --- a/bower.json +++ b/bower.json @@ -13,7 +13,6 @@ }, "devDependencies": { "jquery-color": "3.0.0", - "jquery-mousewheel": "3.1.12", "jquery-simulate": "1.1.1", "qunit": "2.19.4", "requirejs": "2.1.14", diff --git a/demos/spinner/currency.html b/demos/spinner/currency.html index 4180b12e11..fa3744ba51 100644 --- a/demos/spinner/currency.html +++ b/demos/spinner/currency.html @@ -7,7 +7,7 @@ - - - - - - + + + + + + + + + + + diff --git a/ui/widgets/spinner.js b/ui/widgets/spinner.js index 4fb41d7bb6..d4034b4589 100644 --- a/ui/widgets/spinner.js +++ b/ui/widgets/spinner.js @@ -164,6 +164,13 @@ $.widget( "ui.spinner", { // event. The `delta` parameter is provided by the jQuery Mousewheel // plugin if one is loaded. mousewheel: function( event, delta ) { + if ( !event.isTrigger ) { + + // If this is not a trigger call, the `wheel` handler will + // fire as well, let's not duplicate it. + return; + } + var wheelEvent = $.Event( event ); wheelEvent.type = "wheel"; if ( delta ) { From 53129e9cc7eb1c4f55b44a14adc91da23c7be85b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski-Owczarek?= Date: Wed, 26 Mar 2025 14:25:24 +0100 Subject: [PATCH 49/53] Tabs: Support URL-based credentials When credentials are provided directly in the URL, e.g.: https://username:password@www.example.com/ `location.href` strips out the auth part, but anchor links contain them, making our `isLocal` computation broken. This fixes it by only looking at `origin`, `pathname` & `search`. Fixes gh-2213 Closes gh-2345 --- tests/unit/tabs/core.js | 26 ++++++++++++++++++++++++++ ui/widgets/tabs.js | 33 +++++++++++++-------------------- 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/tests/unit/tabs/core.js b/tests/unit/tabs/core.js index c2fd890488..f7515f5850 100644 --- a/tests/unit/tabs/core.js +++ b/tests/unit/tabs/core.js @@ -747,4 +747,30 @@ QUnit.test( "extra listeners created when tabs are added/removed (trac-15136)", "No extra listeners after removing all the extra tabs" ); } ); +QUnit.test( "URL-based auth with local tabs (gh-2213)", function( assert ) { + assert.expect( 1 ); + + var origAjax = $.ajax, + element = $( "#tabs1" ), + anchor = element.find( "a[href='#fragment-3']" ), + url = new URL( anchor.prop( "href" ) ); + + try { + $.ajax = function() { + throw new Error( "Unexpected AJAX call; all tabs are local!" ); + }; + + anchor.attr( "href", url.protocol + "//username:password@" + url.host + + url.pathname + url.search + url.hash ); + + element.tabs(); + anchor.trigger( "click" ); + + assert.strictEqual( element.tabs( "option", "active" ), 2, + "should set the active option" ); + } finally { + $.ajax = origAjax; + } +} ); + } ); diff --git a/ui/widgets/tabs.js b/ui/widgets/tabs.js index 49468feb39..0a8efd3ca3 100644 --- a/ui/widgets/tabs.js +++ b/ui/widgets/tabs.js @@ -61,26 +61,19 @@ $.widget( "ui.tabs", { load: null }, - _isLocal: ( function() { - var rhash = /#.*$/; - - return function( anchor ) { - var anchorUrl, locationUrl; - - anchorUrl = anchor.href.replace( rhash, "" ); - locationUrl = location.href.replace( rhash, "" ); - - // Decoding may throw an error if the URL isn't UTF-8 (#9518) - try { - anchorUrl = decodeURIComponent( anchorUrl ); - } catch ( _error ) {} - try { - locationUrl = decodeURIComponent( locationUrl ); - } catch ( _error ) {} - - return anchor.hash.length > 1 && anchorUrl === locationUrl; - }; - } )(), + _isLocal: function( anchor ) { + var anchorUrl = new URL( anchor.href ), + locationUrl = new URL( location.href ); + + return anchor.hash.length > 1 && + + // `href` may contain a hash but also username & password; + // we want to ignore them, so we check the three fields + // below instead. + anchorUrl.origin === locationUrl.origin && + anchorUrl.pathname === locationUrl.pathname && + anchorUrl.search === locationUrl.search; + }, _create: function() { var that = this, From 89b0ecaaa3fc1f78e6b9f3d3b95de66f6bd22a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski-Owczarek?= Date: Wed, 26 Mar 2025 14:36:58 +0100 Subject: [PATCH 50/53] Tabs: Properly handle decoded/encoded anchor hashes & panel IDs Prior to jQuery UI 1.14.1, hashes in anchor hrefs were used directly. In gh-2307, that was changed - by decoding - to support more complex IDs, e.g. containing emojis which are automatically encoded in `anchor.hash`. Unfortunately, that broke cases where the panel ID is decoded as well. It turns out the spec mandates checking both. In the "scrolling to a fragment" section of the HTML spec[^1]. That uses a concept of document's indicated part[^2]. Slightly below there's an algorithm to compute the indicated part[^3]. The interesting parts are steps 4 to 9: 4. Let potentialIndicatedElement be the result of finding a potential indicated element given document and fragment. 5. If potentialIndicatedElement is not null, then return potentialIndicatedElement. 6. Let fragmentBytes be the result of percent-decoding fragment. 7. Let decodedFragment be the result of running UTF-8 decode without BOM on fragmentBytes. 8. Set potentialIndicatedElement to the result of finding a potential indicated element given document and decodedFragment. 9. If potentialIndicatedElement is not null, then return potentialIndicatedElement. First, in steps 4-5, the algorithm tries the hash as-is, without decoding. Then, if one is not found, the same is attempted with a decoded hash. This change replicates this logic by first trying the hash as-is and then decoding it. Fixes gh-2344 Closes gh-2345 Ref gh-2307 [^1]: https://html.spec.whatwg.org/#scrolling-to-a-fragment [^2]: https://html.spec.whatwg.org/#the-indicated-part-of-the-document [^3]: https://html.spec.whatwg.org/#select-the-indicated-part --- tests/unit/tabs/core.js | 51 +++++++++++++++++++++++++++++++++++++++ tests/unit/tabs/tabs.html | 29 ++++++++++++++++++++++ ui/widgets/tabs.js | 36 ++++++++++++++++++++++++--- 3 files changed, 112 insertions(+), 4 deletions(-) diff --git a/tests/unit/tabs/core.js b/tests/unit/tabs/core.js index f7515f5850..1eac3c2683 100644 --- a/tests/unit/tabs/core.js +++ b/tests/unit/tabs/core.js @@ -773,4 +773,55 @@ QUnit.test( "URL-based auth with local tabs (gh-2213)", function( assert ) { } } ); +( function() { + function getVerifyTab( assert, element ) { + return function verifyTab( index ) { + assert.strictEqual( + element.tabs( "option", "active" ), + index, + "should set the active option to " + index ); + assert.strictEqual( + element.find( "[role='tabpanel']:visible" ).text().trim(), + "Tab " + ( index + 1 ), + "should set the panel to 'Tab " + ( index + 1 ) + "'" ); + }; + } + + QUnit.test( "href encoding/decoding (gh-2344)", function( assert ) { + assert.expect( 12 ); + + location.hash = "#tabs-2"; + + var i, + element = $( "#tabs10" ).tabs(), + tabLinks = element.find( "> ul a" ), + verifyTab = getVerifyTab( assert, element ); + + for ( i = 0; i < tabLinks.length; i++ ) { + tabLinks.eq( i ).trigger( "click" ); + verifyTab( i ); + } + + location.hash = ""; + } ); + + QUnit.test( "href encoding/decoding on init (gh-2344)", function( assert ) { + assert.expect( 12 ); + + var i, + element = $( "#tabs10" ), + tabLinks = element.find( "> ul a" ), + verifyTab = getVerifyTab( assert, element ); + + for ( i = 0; i < tabLinks.length; i++ ) { + location.hash = tabLinks.eq( i ).attr( "href" ); + element.tabs(); + verifyTab( i ); + element.tabs( "destroy" ); + } + + location.hash = ""; + } ); +} )(); + } ); diff --git a/tests/unit/tabs/tabs.html b/tests/unit/tabs/tabs.html index cb4e5389f6..3f18fa015f 100644 --- a/tests/unit/tabs/tabs.html +++ b/tests/unit/tabs/tabs.html @@ -125,6 +125,35 @@
+
+ +
+

Tab 1

+
+
+

Tab 2

+
+
+

Tab 3

+
+
+

Tab 4

+
+
+

Tab 5

+
+
+

Tab 6

+
+
+
diff --git a/ui/widgets/tabs.js b/ui/widgets/tabs.js index 0a8efd3ca3..494e54f224 100644 --- a/ui/widgets/tabs.js +++ b/ui/widgets/tabs.js @@ -114,18 +114,31 @@ $.widget( "ui.tabs", { _initialActive: function() { var active = this.options.active, collapsible = this.options.collapsible, - locationHashDecoded = decodeURIComponent( location.hash.substring( 1 ) ); + locationHash = location.hash.substring( 1 ), + locationHashDecoded = decodeURIComponent( locationHash ); if ( active === null ) { // check the fragment identifier in the URL - if ( locationHashDecoded ) { + if ( locationHash ) { this.tabs.each( function( i, tab ) { - if ( $( tab ).attr( "aria-controls" ) === locationHashDecoded ) { + if ( $( tab ).attr( "aria-controls" ) === locationHash ) { active = i; return false; } } ); + + // If not found, decode the hash & try again. + // See the comment in `_processTabs` under the `_isLocal` check + // for more information. + if ( active === null ) { + this.tabs.each( function( i, tab ) { + if ( $( tab ).attr( "aria-controls" ) === locationHashDecoded ) { + active = i; + return false; + } + } ); + } } // Check for a tab marked active via a class @@ -423,9 +436,24 @@ $.widget( "ui.tabs", { // Inline tab if ( that._isLocal( anchor ) ) { - selector = decodeURIComponent( anchor.hash ); + + // The "scrolling to a fragment" section of the HTML spec: + // https://html.spec.whatwg.org/#scrolling-to-a-fragment + // uses a concept of document's indicated part: + // https://html.spec.whatwg.org/#the-indicated-part-of-the-document + // Slightly below there's an algorithm to compute the indicated + // part: + // https://html.spec.whatwg.org/#the-indicated-part-of-the-document + // First, the algorithm tries the hash as-is, without decoding. + // Then, if one is not found, the same is attempted with a decoded + // hash. Replicate this logic. + selector = anchor.hash; panelId = selector.substring( 1 ); panel = that.element.find( "#" + CSS.escape( panelId ) ); + if ( !panel.length ) { + panelId = decodeURIComponent( panelId ); + panel = that.element.find( "#" + CSS.escape( panelId ) ); + } // remote tab } else { From 5787a75e50193462ae58517fb33ab8d8267526dd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Apr 2025 23:16:06 +0200 Subject: [PATCH 51/53] Build: Bump the github-actions group with 3 updates Bumps the github-actions group with 3 updates: [github/codeql-action](https://github.com/github/codeql-action), [actions/setup-node](https://github.com/actions/setup-node) and [actions/cache](https://github.com/actions/cache). Closes gh-2347 Updates `github/codeql-action` from 3.28.10 to 3.28.13 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d...1b549b9259bda1cb5ddde3b41741a82a2d15a841) Updates `actions/setup-node` from 4.2.0 to 4.3.0 - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a...cdca7365b2dadb8aad0a33bc7601856ffabcc48e) Updates `actions/cache` from 4.2.2 to 4.2.3 - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/d4323d4df104b026a6aa633fdb11d772146be0bf...5a3ec84eff668545956fd18022155c47e93e2684) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/filestash.yml | 4 ++-- .github/workflows/node.js.yml | 12 ++++++------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index cc842ea8e2..6cbef95222 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -33,7 +33,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10 + uses: github/codeql-action/init@1b549b9259bda1cb5ddde3b41741a82a2d15a841 # v3.28.13 # Override language selection by uncommenting this and choosing your languages # with: # languages: go, javascript, csharp, python, cpp, java @@ -41,7 +41,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10 + uses: github/codeql-action/autobuild@1b549b9259bda1cb5ddde3b41741a82a2d15a841 # v3.28.13 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -55,4 +55,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10 + uses: github/codeql-action/analyze@1b549b9259bda1cb5ddde3b41741a82a2d15a841 # v3.28.13 diff --git a/.github/workflows/filestash.yml b/.github/workflows/filestash.yml index 88c949ea42..fd06c31470 100644 --- a/.github/workflows/filestash.yml +++ b/.github/workflows/filestash.yml @@ -20,12 +20,12 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: node-version: ${{ env.NODE_VERSION }} - name: Cache - uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: ~/.npm key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock-${{ hashFiles('**/package-lock.json') }} diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 7614468f85..846ae5dc8c 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -34,12 +34,12 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: node-version: ${{ env.NODE_VERSION }} - name: Cache - uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: ~/.npm key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock-${{ hashFiles('**/package-lock.json') }} @@ -79,12 +79,12 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: node-version: ${{ env.NODE_VERSION }} - name: Cache - uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: ~/.npm key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock-${{ hashFiles('**/package-lock.json') }} @@ -117,12 +117,12 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: node-version: ${{ env.NODE_VERSION }} - name: Cache - uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: ~/.npm key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock-${{ hashFiles('**/package-lock.json') }} From 2ef5467e82bf916657eff8134e3deb54858767cc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 11 May 2025 16:59:16 +0200 Subject: [PATCH 52/53] Build: Bump the github-actions group with 2 updates Bumps the github-actions group with 2 updates: [github/codeql-action](https://github.com/github/codeql-action) and [actions/setup-node](https://github.com/actions/setup-node). Closes gh-2350 Updates `github/codeql-action` from 3.28.13 to 3.28.16 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/1b549b9259bda1cb5ddde3b41741a82a2d15a841...28deaeda66b76a05916b6923827895f2b14ab387) Updates `actions/setup-node` from 4.3.0 to 4.4.0 - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/cdca7365b2dadb8aad0a33bc7601856ffabcc48e...49933ea5288caeca8642d1e84afbd3f7d6820020) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 3.28.16 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: actions/setup-node dependency-version: 4.4.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/filestash.yml | 2 +- .github/workflows/node.js.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 6cbef95222..5344af3243 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -33,7 +33,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@1b549b9259bda1cb5ddde3b41741a82a2d15a841 # v3.28.13 + uses: github/codeql-action/init@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16 # Override language selection by uncommenting this and choosing your languages # with: # languages: go, javascript, csharp, python, cpp, java @@ -41,7 +41,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@1b549b9259bda1cb5ddde3b41741a82a2d15a841 # v3.28.13 + uses: github/codeql-action/autobuild@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -55,4 +55,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@1b549b9259bda1cb5ddde3b41741a82a2d15a841 # v3.28.13 + uses: github/codeql-action/analyze@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16 diff --git a/.github/workflows/filestash.yml b/.github/workflows/filestash.yml index fd06c31470..9f0960a4a9 100644 --- a/.github/workflows/filestash.yml +++ b/.github/workflows/filestash.yml @@ -20,7 +20,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ env.NODE_VERSION }} diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 846ae5dc8c..cccd059d28 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -34,7 +34,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ env.NODE_VERSION }} @@ -79,7 +79,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ env.NODE_VERSION }} @@ -117,7 +117,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ env.NODE_VERSION }} From aafc5a8116d741b96f15c2b0024c49f8f9158689 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Jun 2025 15:30:41 +0200 Subject: [PATCH 53/53] Build: Bump github/codeql-action in the github-actions group Bumps the github-actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action). Closes gh-2353 Updates `github/codeql-action` from 3.28.16 to 3.28.18 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/28deaeda66b76a05916b6923827895f2b14ab387...ff0a06e83cb2de871e5a09832bc6a81e7276941f) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 3.28.18 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 5344af3243..5b2bdead3e 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -33,7 +33,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16 + uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 # Override language selection by uncommenting this and choosing your languages # with: # languages: go, javascript, csharp, python, cpp, java @@ -41,7 +41,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16 + uses: github/codeql-action/autobuild@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -55,4 +55,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16 + uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18