Issue #3113649 by bnjmnm, ayushmishra206, ilgnerfagundes, lauriii, nod_, xjm, catch, alexpott, Kristen Pol: Remove drupal.tabbingmanager's jQueryUI dependency

merge-requests/1068/head
Alex Pott 2021-03-05 12:54:27 +00:00
parent cbccba94b6
commit daf10a0695
No known key found for this signature in database
GPG Key ID: 31905460D4A69276
19 changed files with 645 additions and 82 deletions

View File

@ -20,7 +20,8 @@
"Modernizr": true,
"Popper": true,
"Sortable": true,
"CKEDITOR": true
"CKEDITOR": true,
"tabbable": true
},
"settings": {
"react": {

View File

@ -0,0 +1,106 @@
/*! https://mths.be/cssescape v1.5.1 by @mathias | MIT license */
;(function(root, factory) {
// https://github.com/umdjs/umd/blob/master/returnExports.js
if (typeof exports == 'object') {
// For Node.js.
module.exports = factory(root);
} else if (typeof define == 'function' && define.amd) {
// For AMD. Register as an anonymous module.
define([], factory.bind(root, root));
} else {
// For browser globals (not exposing the function separately).
factory(root);
}
}(typeof global != 'undefined' ? global : this, function(root) {
if (root.CSS && root.CSS.escape) {
return root.CSS.escape;
}
// https://drafts.csswg.org/cssom/#serialize-an-identifier
var cssEscape = function(value) {
if (arguments.length == 0) {
throw new TypeError('`CSS.escape` requires an argument.');
}
var string = String(value);
var length = string.length;
var index = -1;
var codeUnit;
var result = '';
var firstCodeUnit = string.charCodeAt(0);
while (++index < length) {
codeUnit = string.charCodeAt(index);
// Note: theres no need to special-case astral symbols, surrogate
// pairs, or lone surrogates.
// If the character is NULL (U+0000), then the REPLACEMENT CHARACTER
// (U+FFFD).
if (codeUnit == 0x0000) {
result += '\uFFFD';
continue;
}
if (
// If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
// U+007F, […]
(codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F ||
// If the character is the first character and is in the range [0-9]
// (U+0030 to U+0039), […]
(index == 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
// If the character is the second character and is in the range [0-9]
// (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
(
index == 1 &&
codeUnit >= 0x0030 && codeUnit <= 0x0039 &&
firstCodeUnit == 0x002D
)
) {
// https://drafts.csswg.org/cssom/#escape-a-character-as-code-point
result += '\\' + codeUnit.toString(16) + ' ';
continue;
}
if (
// If the character is the first character and is a `-` (U+002D), and
// there is no second character, […]
index == 0 &&
length == 1 &&
codeUnit == 0x002D
) {
result += '\\' + string.charAt(index);
continue;
}
// If the character is not handled by one of the above rules and is
// greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or
// is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to
// U+005A), or [a-z] (U+0061 to U+007A), […]
if (
codeUnit >= 0x0080 ||
codeUnit == 0x002D ||
codeUnit == 0x005F ||
codeUnit >= 0x0030 && codeUnit <= 0x0039 ||
codeUnit >= 0x0041 && codeUnit <= 0x005A ||
codeUnit >= 0x0061 && codeUnit <= 0x007A
) {
// the character itself
result += string.charAt(index);
continue;
}
// Otherwise, the escaped character.
// https://drafts.csswg.org/cssom/#escape-a-character
result += '\\' + string.charAt(index);
}
return result;
};
if (!root.CSS) {
root.CSS = {};
}
root.CSS.escape = cssEscape;
return cssEscape;
}));

File diff suppressed because one or more lines are too long

View File

@ -31,7 +31,6 @@
"../position",
"../safe-active-element",
"../safe-blur",
"../tabbable",
"../unique-id",
"../version",
"../widget"

15
core/assets/vendor/tabbable/README.txt vendored Normal file
View File

@ -0,0 +1,15 @@
Drupal core uses the UMD build of tabbable.
To create this build:
Navigate to the root directory of the tabbable library.
Ensure that dependencies have been installed:
```
yarn install
```
Build files for production:
```
yarn build
```
This will create an index.umd.min.js file in dist/ that can be used in Drupal.

View File

@ -0,0 +1,6 @@
/*!
* tabbable 5.1.6
* @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE
*/
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):(e="undefined"!=typeof globalThis?globalThis:e||self,function(){var n=e.tabbable,r=e.tabbable={};t(r),r.noConflict=function(){return e.tabbable=n,r}}())}(this,(function(e){"use strict";var t=["input","select","textarea","a[href]","button","[tabindex]","audio[controls]","video[controls]",'[contenteditable]:not([contenteditable="false"])',"details>summary:first-of-type","details"],n=t.join(","),r="undefined"==typeof Element?function(){}:Element.prototype.matches||Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector,o=function(e,t,o){var i=Array.prototype.slice.apply(e.querySelectorAll(n));return t&&r.call(e,n)&&i.unshift(e),i=i.filter(o)},i=function(e){var t=parseInt(e.getAttribute("tabindex"),10);return isNaN(t)?function(e){return"true"===e.contentEditable}(e)?0:"AUDIO"!==e.nodeName&&"VIDEO"!==e.nodeName&&"DETAILS"!==e.nodeName||null!==e.getAttribute("tabindex")?e.tabIndex:0:t},a=function(e,t){return e.tabIndex===t.tabIndex?e.documentOrder-t.documentOrder:e.tabIndex-t.tabIndex},u=function(e){return"INPUT"===e.tagName},c=function(e){return function(e){return u(e)&&"radio"===e.type}(e)&&!function(e){if(!e.name)return!0;var t,n=e.form||e.ownerDocument,r=function(e){return n.querySelectorAll('input[type="radio"][name="'+e+'"]')};if("undefined"!=typeof window&&void 0!==window.CSS&&"function"==typeof window.CSS.escape)t=r(window.CSS.escape(e.name));else try{t=r(e.name)}catch(e){return console.error("Looks like you have a radio button with a name attribute containing invalid CSS selector characters and need the CSS.escape polyfill: %s",e.message),!1}var o=function(e,t){for(var n=0;n<e.length;n++)if(e[n].checked&&e[n].form===t)return e[n]}(t,e.form);return!o||o===e}(e)},l=function(e){return!(e.disabled||function(e){return u(e)&&"hidden"===e.type}(e)||function(e){if("hidden"===getComputedStyle(e).visibility)return!0;var t=r.call(e,"details>summary:first-of-type")?e.parentElement:e;if(r.call(t,"details:not([open]) *"))return!0;for(;e;){if("none"===getComputedStyle(e).display)return!0;e=e.parentElement}return!1}(e)||function(e){return"DETAILS"===e.tagName&&Array.prototype.slice.apply(e.children).some((function(e){return"SUMMARY"===e.tagName}))}(e))},d=function(e){return!(!l(e)||c(e)||i(e)<0)},f=t.concat("iframe").join(",");e.focusable=function(e,t){return o(e,(t=t||{}).includeContainer,l)},e.isFocusable=function(e){if(!e)throw new Error("No node provided");return!1!==r.call(e,f)&&l(e)},e.isTabbable=function(e){if(!e)throw new Error("No node provided");return!1!==r.call(e,n)&&d(e)},e.tabbable=function(e,t){var n=[],r=[];return o(e,(t=t||{}).includeContainer,d).forEach((function(e,t){var o=i(e);0===o?n.push(e):r.push({documentOrder:t,tabIndex:o,node:e})})),r.sort(a).map((function(e){return e.node})).concat(n)},Object.defineProperty(e,"__esModule",{value:!0})}));
//# sourceMappingURL=index.umd.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -22,6 +22,16 @@ ckeditor:
js:
assets/vendor/ckeditor/ckeditor.js: { preprocess: false, minified: true }
css.escape:
remote: https://github.com/mathiasbynens/CSS.escape
version: "1.5.1"
license:
name: MIT
url: https://raw.githubusercontent.com/mathiasbynens/CSS.escape/v1.5.1/LICENSE-MIT.txt
gpl-compatible: true
js:
assets/vendor/css-escape/css.escape.js: { weight: -20 }
drupal:
version: VERSION
js:
@ -95,7 +105,6 @@ drupal.autocomplete:
assets/vendor/jquery.ui/ui/widgets/autocomplete-min.js: { weight: -11.7, minified: true }
assets/vendor/jquery.ui/ui/labels-min.js: { weight: -11.7, minified: true }
assets/vendor/jquery.ui/ui/widgets/menu-min.js: { weight: -11.7, minified: true }
assets/vendor/jquery.ui/ui/tabbable-min.js: { weight: -11.7, minified: true }
assets/vendor/jquery.ui/ui/data-min.js: { weight: -11.8, minified: true }
assets/vendor/jquery.ui/ui/disable-selection-min.js: { weight: -11.8, minified: true }
assets/vendor/jquery.ui/ui/escape-selector-min.js: { weight: -11.8, minified: true }
@ -126,6 +135,7 @@ drupal.autocomplete:
- core/drupal
- core/drupalSettings
- core/drupal.ajax
- core/tabbable.jquery.shim
drupal.array.find:
version: VERSION
@ -200,7 +210,6 @@ drupal.dialog:
assets/vendor/jquery.ui/ui/form-reset-mixin-min.js: { weight: -11.7, minified: true }
assets/vendor/jquery.ui/ui/labels-min.js: { weight: -11.7, minified: true }
assets/vendor/jquery.ui/ui/widgets/mouse-min.js: { weight: -11.7, minified: true }
assets/vendor/jquery.ui/ui/tabbable-min.js: { weight: -11.7, minified: true }
assets/vendor/jquery.ui/ui/data-min.js: { weight: -11.8, minified: true }
assets/vendor/jquery.ui/ui/disable-selection-min.js: { weight: -11.8, minified: true }
assets/vendor/jquery.ui/ui/form-min.js: { weight: -11.8, minified: true }
@ -235,6 +244,7 @@ drupal.dialog:
- core/drupalSettings
- core/drupal.debounce
- core/drupal.displace
- core/tabbable.jquery.shim
drupal.dialog.ajax:
version: VERSION
@ -338,37 +348,11 @@ drupal.tabbingmanager:
version: VERSION
js:
misc/tabbingmanager.js: {}
# The remaining JavaScript assets previously came from core/jquery.ui, a
# deprecated library. These assets are used to provide the :tabbable pseudo
# selector to core's JavaScript. It should be possible to remove them once
# :tabbable is provided via a non-jQuery UI based library.
# All weights are based on on the requirements defined within each file.
# @todo replace with solution found in https://drupal.org/node/3113649
assets/vendor/jquery.ui/ui/labels-min.js: { weight: -11.7, minified: true }
assets/vendor/jquery.ui/ui/tabbable-min.js: { weight: -11.7, minified: true }
assets/vendor/jquery.ui/ui/disable-selection-min.js: { weight: -11.8, minified: true }
assets/vendor/jquery.ui/ui/form-min.js: { weight: -11.8, minified: true }
assets/vendor/jquery.ui/ui/escape-selector-min.js: { weight: -11.8, minified: true }
assets/vendor/jquery.ui/ui/focusable-min.js: { weight: -11.8, minified: true }
assets/vendor/jquery.ui/ui/ie-min.js: { weight: -11.8, minified: true }
assets/vendor/jquery.ui/ui/jquery-1-7-min.js: { weight: -11.8, minified: true }
assets/vendor/jquery.ui/ui/keycode-min.js: { weight: -11.8, minified: true }
assets/vendor/jquery.ui/ui/plugin-min.js: { weight: -11.8, minified: true }
assets/vendor/jquery.ui/ui/safe-active-element-min.js: { weight: -11.8, minified: true }
assets/vendor/jquery.ui/ui/safe-blur-min.js: { weight: -11.8, minified: true }
assets/vendor/jquery.ui/ui/scroll-parent-min.js: { weight: -11.8, minified: true }
assets/vendor/jquery.ui/ui/unique-id-min.js: { weight: -11.8, minified: true }
assets/vendor/jquery.ui/ui/version-min.js: { weight: -11.9, minified: true }
# All CSS assets previously came from core/jquery.ui, a deprecated library.
# @todo replace with solution found in https://drupal.org/node/3113649
css:
component:
assets/vendor/jquery.ui/themes/base/core.css: { weight: -11.8 }
theme:
assets/vendor/jquery.ui/themes/base/theme.css: { weight: -11.8 }
dependencies:
- core/jquery
- core/drupal
- core/tabbable
- core/tabbable.jquery.shim
drupal.tabledrag:
version: VERSION
@ -528,7 +512,6 @@ jquery.ui:
gpl-compatible: true
js:
assets/vendor/jquery.ui/ui/labels-min.js: { weight: -11.7, minified: true }
assets/vendor/jquery.ui/ui/tabbable-min.js: { weight: -11.7, minified: true }
assets/vendor/jquery.ui/ui/data-min.js: { weight: -11.8, minified: true }
assets/vendor/jquery.ui/ui/disable-selection-min.js: { weight: -11.8, minified: true }
assets/vendor/jquery.ui/ui/escape-selector-min.js: { weight: -11.8, minified: true }
@ -550,6 +533,7 @@ jquery.ui:
assets/vendor/jquery.ui/themes/base/theme.css: { weight: -11.8 }
dependencies:
- core/jquery
- core/tabbable.jquery.shim
deprecated: &jquery_ui_unused_deprecated The "%library_id%" asset library is deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. See https://www.drupal.org/node/3067969
jquery.ui.autocomplete:
@ -598,7 +582,6 @@ jquery.ui.dialog:
assets/vendor/jquery.ui/ui/form-reset-mixin-min.js: { weight: -11.7, minified: true }
assets/vendor/jquery.ui/ui/labels-min.js: { weight: -11.7, minified: true }
assets/vendor/jquery.ui/ui/widgets/mouse-min.js: { weight: -11.7, minified: true }
assets/vendor/jquery.ui/ui/tabbable-min.js: { weight: -11.7, minified: true }
assets/vendor/jquery.ui/ui/data-min.js: { weight: -11.8, minified: true }
assets/vendor/jquery.ui/ui/disable-selection-min.js: { weight: -11.8, minified: true }
assets/vendor/jquery.ui/ui/escape-selector-min.js: { weight: -11.8, minified: true }
@ -627,6 +610,7 @@ jquery.ui.dialog:
assets/vendor/jquery.ui/themes/base/theme.css: { weight: -11.8 }
dependencies:
- core/jquery
- core/tabbable.jquery.shim
deprecated: *jquery_ui_unused_deprecated
jquery.ui.draggable:
@ -754,6 +738,26 @@ sortable:
js:
assets/vendor/sortable/Sortable.min.js: { minified: true }
tabbable:
remote: https://github.com/focus-trap/tabbable
version: "5.1.6"
license:
name: MIT
url: https://raw.githubusercontent.com/focus-trap/tabbable/v5.1.6/LICENSE
gpl-compatible: true
js:
assets/vendor/tabbable/index.umd.min.js: { weight: -1, minified: true }
dependencies:
- core/css.escape
tabbable.jquery.shim:
version: VERSION
js:
misc/jquery.tabbable.shim.js: {}
dependencies:
- core/tabbable
- core/jquery
underscore:
remote: https://github.com/jashkenas/underscore
version: "1.11.0"

View File

@ -50,6 +50,11 @@
// Turn the summary into a clickable link.
const $summary = this.$node.find('> summary');
// If this polyfill is in use, the browser does not recognize
// <summary> as a focusable element. The tabindex is set to -1 so the
// tabbable library does not incorrectly identify it as tabbable.
$summary.attr('tabindex', '-1');
$('<span class="details-summary-prefix visually-hidden"></span>')
.append(this.$node.attr('open') ? Drupal.t('Hide') : Drupal.t('Show'))
.prependTo($summary)

View File

@ -24,6 +24,7 @@
$.extend(CollapsibleDetails.prototype, {
setupSummaryPolyfill: function setupSummaryPolyfill() {
var $summary = this.$node.find('> summary');
$summary.attr('tabindex', '-1');
$('<span class="details-summary-prefix visually-hidden"></span>').append(this.$node.attr('open') ? Drupal.t('Hide') : Drupal.t('Show')).prependTo($summary).after(document.createTextNode(' '));
$('<a class="details-title"></a>').attr('href', "#".concat(this.$node.attr('id'))).prepend($summary.contents()).appendTo($summary);
$summary.append(this.$summary).on('click', $.proxy(this.onSummaryClick, this));

View File

@ -0,0 +1,23 @@
/**
* @file
* Defines a backwards-compatible shim for the jQuery UI :tabbable selector.
*/
(($, Drupal, { isTabbable }) => {
$.extend($.expr[':'], {
tabbable(element) {
// The tabbable library considers the summary element tabbable, and also
// considers a details element without a summary tabbable. The jQuery UI
// :tabbable selector does not. This is due to those element types being
// inert in IE/Edge.
// @see https://allyjs.io/data-tables/focusable.html
if (element.tagName === 'SUMMARY' || element.tagName === 'DETAILS') {
const tabIndex = element.getAttribute('tabIndex');
if (tabIndex === null || tabIndex < 0) {
return false;
}
}
return isTabbable(element);
},
});
})(jQuery, Drupal, window.tabbable);

View File

@ -0,0 +1,23 @@
/**
* DO NOT EDIT THIS FILE.
* See the following change record for more information,
* https://www.drupal.org/node/2815083
* @preserve
**/
(function ($, Drupal, _ref) {
var isTabbable = _ref.isTabbable;
$.extend($.expr[':'], {
tabbable: function tabbable(element) {
if (element.tagName === 'SUMMARY' || element.tagName === 'DETAILS') {
var tabIndex = element.getAttribute('tabIndex');
if (tabIndex === null || tabIndex < 0) {
return false;
}
}
return isTabbable(element);
}
});
})(jQuery, Drupal, window.tabbable);

View File

@ -0,0 +1,32 @@
<?php
namespace Drupal\tabbable_shim_test\Controller;
use Drupal\Core\Controller\ControllerBase;
/**
* For testing the jQuery :tabbable shim as used in a dialog.
*/
class TabbableShimDialogIntegrationTestController extends ControllerBase {
/**
* Provides a page with the jQuery UI dialog library for testing .
*
* @return array
* The render array.
*/
public function build() {
return [
'container' => [
'#type' => 'container',
'#attributes' => [
'id' => 'tabbable-dialog-test-container',
],
],
'#attached' => [
'library' => ['core/jquery.ui.dialog'],
],
];
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace Drupal\tabbable_shim_test\Controller;
use Drupal\Core\Controller\ControllerBase;
/**
* For testing the jQuery :tabbable shim.
*/
class TabbableShimTestController extends ControllerBase {
/**
* Provides a page with the tabbingManager library for testing :tabbable.
*
* @return array
* The render array.
*/
public function build() {
return [
'container' => [
'#type' => 'container',
'#attributes' => [
'id' => 'tabbable-test-container',
],
],
'#attached' => ['library' => ['core/drupal.tabbingmanager']],
];
}
}

View File

@ -0,0 +1,5 @@
name: 'Tabbable Shim Test'
type: module
description: 'Module for the testing the :tabbable selector shim'
package: Testing
version: VERSION

View File

@ -0,0 +1,15 @@
tabbable_test_page:
path: '/tabbable-shim-test'
defaults:
_controller: '\Drupal\tabbable_shim_test\Controller\TabbableShimTestController::build'
_title: 'Tabbable testing'
requirements:
_access: 'TRUE'
tabbable_dialog_integration_test_page:
path: '/tabbable-shim-dialog-integration-test'
defaults:
_controller: '\Drupal\tabbable_shim_test\Controller\TabbableShimDialogIntegrationTestController::build'
_title: 'Tabbable dialog integration testing'
requirements:
_access: 'TRUE'

View File

@ -58,7 +58,6 @@ class JqueryUiLibraryAssetsTest extends BrowserTestBase {
$libraries_to_check = [
'drupal.autocomplete',
'drupal.dialog',
'drupal.tabbingmanager',
'jquery.ui',
'jquery.ui.autocomplete',
'jquery.ui.button',
@ -138,7 +137,6 @@ class JqueryUiLibraryAssetsTest extends BrowserTestBase {
'core/assets/vendor/jquery.ui/ui/widgets/autocomplete-min.js',
'core/assets/vendor/jquery.ui/ui/labels-min.js',
'core/assets/vendor/jquery.ui/ui/widgets/menu-min.js',
'core/assets/vendor/jquery.ui/ui/tabbable-min.js',
'core/assets/vendor/jquery.ui/themes/base/autocomplete.css',
'core/assets/vendor/jquery.ui/themes/base/menu.css',
'core/assets/vendor/jquery.ui/ui/widgets/controlgroup-min.js',
@ -373,7 +371,6 @@ class JqueryUiLibraryAssetsTest extends BrowserTestBase {
'core/assets/vendor/jquery.ui/ui/labels-min.js',
'core/assets/vendor/jquery.ui/ui/jquery-1-7-min.js',
'core/assets/vendor/jquery.ui/ui/scroll-parent-min.js',
'core/assets/vendor/jquery.ui/ui/tabbable-min.js',
'core/assets/vendor/jquery.ui/ui/unique-id-min.js',
'core/assets/vendor/jquery.ui/ui/version-min.js',
'core/assets/vendor/jquery.ui/ui/escape-selector-min.js',
@ -407,7 +404,6 @@ class JqueryUiLibraryAssetsTest extends BrowserTestBase {
'core/assets/vendor/jquery.ui/ui/labels-min.js',
'core/assets/vendor/jquery.ui/ui/jquery-1-7-min.js',
'core/assets/vendor/jquery.ui/ui/scroll-parent-min.js',
'core/assets/vendor/jquery.ui/ui/tabbable-min.js',
'core/assets/vendor/jquery.ui/ui/unique-id-min.js',
'core/assets/vendor/jquery.ui/ui/version-min.js',
'core/assets/vendor/jquery.ui/ui/escape-selector-min.js',
@ -429,31 +425,6 @@ class JqueryUiLibraryAssetsTest extends BrowserTestBase {
'core/assets/vendor/jquery.ui/ui/widgets/dialog-min.js',
],
],
'drupal.tabbingmanager' => [
'library' => 'drupal.tabbingmanager',
'expected_css' => [
'core/assets/vendor/jquery.ui/themes/base/core.css',
'core/assets/vendor/jquery.ui/themes/base/theme.css',
],
'expected_js' => [
'core/assets/vendor/jquery.ui/ui/data-min.js',
'core/assets/vendor/jquery.ui/ui/disable-selection-min.js',
'core/assets/vendor/jquery.ui/ui/form-min.js',
'core/assets/vendor/jquery.ui/ui/labels-min.js',
'core/assets/vendor/jquery.ui/ui/jquery-1-7-min.js',
'core/assets/vendor/jquery.ui/ui/scroll-parent-min.js',
'core/assets/vendor/jquery.ui/ui/tabbable-min.js',
'core/assets/vendor/jquery.ui/ui/unique-id-min.js',
'core/assets/vendor/jquery.ui/ui/version-min.js',
'core/assets/vendor/jquery.ui/ui/escape-selector-min.js',
'core/assets/vendor/jquery.ui/ui/focusable-min.js',
'core/assets/vendor/jquery.ui/ui/ie-min.js',
'core/assets/vendor/jquery.ui/ui/keycode-min.js',
'core/assets/vendor/jquery.ui/ui/plugin-min.js',
'core/assets/vendor/jquery.ui/ui/safe-active-element-min.js',
'core/assets/vendor/jquery.ui/ui/safe-blur-min.js',
],
],
'jquery.ui' => [
'library' => 'jquery.ui',
'expected_css' => [
@ -467,7 +438,6 @@ class JqueryUiLibraryAssetsTest extends BrowserTestBase {
'core/assets/vendor/jquery.ui/ui/labels-min.js',
'core/assets/vendor/jquery.ui/ui/jquery-1-7-min.js',
'core/assets/vendor/jquery.ui/ui/scroll-parent-min.js',
'core/assets/vendor/jquery.ui/ui/tabbable-min.js',
'core/assets/vendor/jquery.ui/ui/unique-id-min.js',
'core/assets/vendor/jquery.ui/ui/version-min.js',
'core/assets/vendor/jquery.ui/ui/escape-selector-min.js',
@ -494,7 +464,6 @@ class JqueryUiLibraryAssetsTest extends BrowserTestBase {
'core/assets/vendor/jquery.ui/ui/labels-min.js',
'core/assets/vendor/jquery.ui/ui/jquery-1-7-min.js',
'core/assets/vendor/jquery.ui/ui/scroll-parent-min.js',
'core/assets/vendor/jquery.ui/ui/tabbable-min.js',
'core/assets/vendor/jquery.ui/ui/unique-id-min.js',
'core/assets/vendor/jquery.ui/ui/version-min.js',
'core/assets/vendor/jquery.ui/ui/escape-selector-min.js',
@ -526,7 +495,6 @@ class JqueryUiLibraryAssetsTest extends BrowserTestBase {
'core/assets/vendor/jquery.ui/ui/labels-min.js',
'core/assets/vendor/jquery.ui/ui/jquery-1-7-min.js',
'core/assets/vendor/jquery.ui/ui/scroll-parent-min.js',
'core/assets/vendor/jquery.ui/ui/tabbable-min.js',
'core/assets/vendor/jquery.ui/ui/unique-id-min.js',
'core/assets/vendor/jquery.ui/ui/version-min.js',
'core/assets/vendor/jquery.ui/ui/escape-selector-min.js',
@ -560,7 +528,6 @@ class JqueryUiLibraryAssetsTest extends BrowserTestBase {
'core/assets/vendor/jquery.ui/ui/labels-min.js',
'core/assets/vendor/jquery.ui/ui/jquery-1-7-min.js',
'core/assets/vendor/jquery.ui/ui/scroll-parent-min.js',
'core/assets/vendor/jquery.ui/ui/tabbable-min.js',
'core/assets/vendor/jquery.ui/ui/unique-id-min.js',
'core/assets/vendor/jquery.ui/ui/version-min.js',
'core/assets/vendor/jquery.ui/ui/escape-selector-min.js',
@ -596,7 +563,6 @@ class JqueryUiLibraryAssetsTest extends BrowserTestBase {
'core/assets/vendor/jquery.ui/ui/labels-min.js',
'core/assets/vendor/jquery.ui/ui/jquery-1-7-min.js',
'core/assets/vendor/jquery.ui/ui/scroll-parent-min.js',
'core/assets/vendor/jquery.ui/ui/tabbable-min.js',
'core/assets/vendor/jquery.ui/ui/unique-id-min.js',
'core/assets/vendor/jquery.ui/ui/version-min.js',
'core/assets/vendor/jquery.ui/ui/escape-selector-min.js',
@ -624,7 +590,6 @@ class JqueryUiLibraryAssetsTest extends BrowserTestBase {
'core/assets/vendor/jquery.ui/ui/labels-min.js',
'core/assets/vendor/jquery.ui/ui/jquery-1-7-min.js',
'core/assets/vendor/jquery.ui/ui/scroll-parent-min.js',
'core/assets/vendor/jquery.ui/ui/tabbable-min.js',
'core/assets/vendor/jquery.ui/ui/unique-id-min.js',
'core/assets/vendor/jquery.ui/ui/version-min.js',
'core/assets/vendor/jquery.ui/ui/escape-selector-min.js',
@ -651,7 +616,6 @@ class JqueryUiLibraryAssetsTest extends BrowserTestBase {
'core/assets/vendor/jquery.ui/ui/labels-min.js',
'core/assets/vendor/jquery.ui/ui/jquery-1-7-min.js',
'core/assets/vendor/jquery.ui/ui/scroll-parent-min.js',
'core/assets/vendor/jquery.ui/ui/tabbable-min.js',
'core/assets/vendor/jquery.ui/ui/unique-id-min.js',
'core/assets/vendor/jquery.ui/ui/version-min.js',
'core/assets/vendor/jquery.ui/ui/escape-selector-min.js',
@ -678,7 +642,6 @@ class JqueryUiLibraryAssetsTest extends BrowserTestBase {
'core/assets/vendor/jquery.ui/ui/labels-min.js',
'core/assets/vendor/jquery.ui/ui/jquery-1-7-min.js',
'core/assets/vendor/jquery.ui/ui/scroll-parent-min.js',
'core/assets/vendor/jquery.ui/ui/tabbable-min.js',
'core/assets/vendor/jquery.ui/ui/unique-id-min.js',
'core/assets/vendor/jquery.ui/ui/version-min.js',
'core/assets/vendor/jquery.ui/ui/escape-selector-min.js',
@ -706,7 +669,6 @@ class JqueryUiLibraryAssetsTest extends BrowserTestBase {
'core/assets/vendor/jquery.ui/ui/labels-min.js',
'core/assets/vendor/jquery.ui/ui/jquery-1-7-min.js',
'core/assets/vendor/jquery.ui/ui/scroll-parent-min.js',
'core/assets/vendor/jquery.ui/ui/tabbable-min.js',
'core/assets/vendor/jquery.ui/ui/unique-id-min.js',
'core/assets/vendor/jquery.ui/ui/version-min.js',
'core/assets/vendor/jquery.ui/ui/escape-selector-min.js',
@ -722,8 +684,8 @@ class JqueryUiLibraryAssetsTest extends BrowserTestBase {
// A few instances of multiple libraries being checked simultaneously are
// here to ensure that multiple libraries requesting the same asset does
// not impact the expected loading order.
'drupal.tabbingmanager|jquery.ui|jquery.ui.widget' => [
'library' => 'drupal.tabbingmanager|jquery.ui|jquery.ui.widget',
'jquery.ui|jquery.ui.widget' => [
'library' => 'jquery.ui|jquery.ui.widget',
'expected_css' => [
'core/assets/vendor/jquery.ui/themes/base/core.css',
'core/assets/vendor/jquery.ui/themes/base/theme.css',
@ -735,7 +697,6 @@ class JqueryUiLibraryAssetsTest extends BrowserTestBase {
'core/assets/vendor/jquery.ui/ui/labels-min.js',
'core/assets/vendor/jquery.ui/ui/jquery-1-7-min.js',
'core/assets/vendor/jquery.ui/ui/scroll-parent-min.js',
'core/assets/vendor/jquery.ui/ui/tabbable-min.js',
'core/assets/vendor/jquery.ui/ui/unique-id-min.js',
'core/assets/vendor/jquery.ui/ui/version-min.js',
'core/assets/vendor/jquery.ui/ui/escape-selector-min.js',
@ -768,7 +729,6 @@ class JqueryUiLibraryAssetsTest extends BrowserTestBase {
'core/assets/vendor/jquery.ui/ui/labels-min.js',
'core/assets/vendor/jquery.ui/ui/jquery-1-7-min.js',
'core/assets/vendor/jquery.ui/ui/scroll-parent-min.js',
'core/assets/vendor/jquery.ui/ui/tabbable-min.js',
'core/assets/vendor/jquery.ui/ui/unique-id-min.js',
'core/assets/vendor/jquery.ui/ui/version-min.js',
'core/assets/vendor/jquery.ui/ui/escape-selector-min.js',
@ -792,8 +752,8 @@ class JqueryUiLibraryAssetsTest extends BrowserTestBase {
'core/assets/vendor/jquery.ui/ui/widgets/dialog-min.js',
],
],
'jquery.ui.widget|jquery.ui.resizable|jquery.ui.position|jquery.ui.mouse|jquery.ui.menu|jquery.ui.dialog|jquery.ui.button|jquery.ui.autocomplete|jquery.ui|drupal.tabbingmanager|drupal.dialog|drupal.autocomplete' => [
'library' => 'jquery.ui.widget|jquery.ui.resizable|jquery.ui.position|jquery.ui.mouse|jquery.ui.menu|jquery.ui.dialog|jquery.ui.button|jquery.ui.autocomplete|jquery.ui|drupal.tabbingmanager|drupal.dialog|drupal.autocomplete',
'jquery.ui.widget|jquery.ui.resizable|jquery.ui.position|jquery.ui.mouse|jquery.ui.menu|jquery.ui.dialog|jquery.ui.button|jquery.ui.autocomplete|jquery.ui|drupal.dialog|drupal.autocomplete' => [
'library' => 'jquery.ui.widget|jquery.ui.resizable|jquery.ui.position|jquery.ui.mouse|jquery.ui.menu|jquery.ui.dialog|jquery.ui.button|jquery.ui.autocomplete|jquery.ui|drupal.dialog|drupal.autocomplete',
'expected_css' => [
'core/assets/vendor/jquery.ui/themes/base/core.css',
'core/assets/vendor/jquery.ui/themes/base/resizable.css',
@ -812,7 +772,6 @@ class JqueryUiLibraryAssetsTest extends BrowserTestBase {
'core/assets/vendor/jquery.ui/ui/labels-min.js',
'core/assets/vendor/jquery.ui/ui/jquery-1-7-min.js',
'core/assets/vendor/jquery.ui/ui/scroll-parent-min.js',
'core/assets/vendor/jquery.ui/ui/tabbable-min.js',
'core/assets/vendor/jquery.ui/ui/unique-id-min.js',
'core/assets/vendor/jquery.ui/ui/version-min.js',
'core/assets/vendor/jquery.ui/ui/escape-selector-min.js',

View File

@ -20,10 +20,10 @@ class DeprecatedJqueryUiAssetsTest extends KernelTestBase {
/** @var \Drupal\Core\Asset\LibraryDiscoveryInterface $library_discovery */
$library_discovery = $this->container->get('library.discovery');
$deprecated_jquery_ui_libraries = [
'jquery.ui' => '1396fab9268ee2cce47df6ac3e4781c8',
'jquery.ui' => '291c28f873a71cd6b3116218d1f5da22',
'jquery.ui.autocomplete' => '153f2836f8f2da39767208b6e09cb5b4',
'jquery.ui.button' => 'ad23e5de0fa1de1f511d10ba2e10d2dd',
'jquery.ui.dialog' => '2027aab39332607b62288c4d20c01f83',
'jquery.ui.dialog' => '729090e5ddcd8563ddade80c3dabc87c',
'jquery.ui.draggable' => 'af0f2bdc8aa4ade1e3de8042f31a9312',
'jquery.ui.menu' => '7d0c4d57f43d2f881d2cd5e5b79effbb',
'jquery.ui.mouse' => '626bb203807fa2cdc62510412685df4a',

View File

@ -0,0 +1,338 @@
// Testing the shimmed jQuery UI :tabbable selector.
// Test confirming the :tabbable shim returns the same values as jQuery UI
// :tabbable.
//
// An array of objects with the following properties:
// - element: the element to test
// - tabbable: the number of items the :tabbable selector should return when
// the element is the only item in the container being queried.
const tabbableTestScenarios = [
{
element: '<div>',
tabbable: 0,
},
{
element: '<div tabindex="0">',
tabbable: 1,
},
{
element: '<div tabindex="0" hidden>',
tabbable: 0,
},
{
element: '<div tabindex="0" style="display:none;">',
tabbable: 0,
},
{
element: '<div href="#">',
tabbable: 0,
},
{
element: '<a>',
tabbable: 0,
},
{
element: '<a href="#">',
tabbable: 1,
},
{
element: '<a tabindex="0">',
tabbable: 1,
},
{
element: '<a tabindex="-1">',
tabbable: 0,
},
{
element: '<input type="hidden">',
tabbable: 0,
},
{
element: '<input type="hidden" tabindex="0">',
tabbable: 0,
},
{
element: '<input type="hidden" tabindex="1">',
tabbable: 0,
},
{
element:
'<details><summary>I am not :tabbable because IE does not support it</summary>This is unfortunate</details>',
tabbable: 0,
},
{
element:
'<details>A details without a summary should also not be :tabbable</details>',
tabbable: 0,
},
{
element: '<ul><li>List item</li></ul>',
tabbable: 0,
},
{
element: '<ul><li tabindex="0">List item</li></ul>',
tabbable: 1,
},
];
// Element types to add to the test scenarios.
const elementTypesUsedByTabbableTest = [
'input-button',
'input-checkbox',
'input-color',
'input-date',
'input-datetime-local',
'input-email',
'input-file',
'input-image',
'input-month',
'input-number',
'input-password',
'input-radio',
'input-range',
'input-reset',
'input-search',
'input-submit',
'input-tel',
'input-text',
'input-time',
'input-url',
'input-week',
'select',
'button',
'textarea',
];
// Create multiple test scenarios.
// For each element type being tested, create multiple variations with different
// attributes and store them in the `element:` property. The `tabbable:` property
// is the number of elements in `element:` that would match the :tabbable
// selector.
// Tha variations include:
// - The element with no additional attributes.
// - Separate scenarios for tabindex 0, 1, and -1.
// - With the hidden attribute
// - With `style="display:none;"`
// - With `style="visibility: hidden;"`
elementTypesUsedByTabbableTest.forEach((item) => {
let elementType = item;
let selfClose = '';
let type = '';
if (item.indexOf('-') > 0) {
[elementType, type] = item.split('-');
type = ` type="${type}"`;
selfClose = ' /';
}
tabbableTestScenarios.push({
element: `<${elementType}${type}${selfClose}>`,
tabbable: 1,
});
tabbableTestScenarios.push({
element: `<${elementType}${type} tabindex="0"${selfClose}>`,
tabbable: 1,
});
tabbableTestScenarios.push({
element: `<${elementType}${type} tabindex="1"${selfClose}>`,
tabbable: 1,
});
tabbableTestScenarios.push({
element: `<${elementType}${type} tabindex="-1"${selfClose}>`,
tabbable: 0,
});
tabbableTestScenarios.push({
element: `<${elementType}${type} hidden${selfClose}>`,
tabbable: 0,
});
tabbableTestScenarios.push({
element: `<${elementType}${type} style="display:none;"${selfClose}>`,
tabbable: 0,
});
tabbableTestScenarios.push({
element: `<${elementType}${type} style="visibility: hidden;"${selfClose}>`,
tabbable: 0,
});
});
// The default options for items in dialogIntegrationTestScenarios.
const defaultDialogOptions = {
buttons: [
{
text: 'Ok',
click: () => {},
},
],
};
// Contains scenarios for testing dialog's use of the :tabbable selector.
// These are based on the "focus tabbable" tests within jQuery UI
// @see
// https://github.com/jquery/jquery-ui/blob/1.12.1/tests/unit/dialog/core.js
const dialogIntegrationTestScenarios = [
{
info: 'An element that was focused previously.',
markup: '<div><input><input></div>',
options: {},
// eslint-disable-next-line object-shorthand, func-names
testActions: function ($element) {
const $input = $element
.find('input:last')
.trigger('focus')
.trigger('blur');
$element.dialog('instance')._focusTabbable();
return $input[0];
},
},
{
info: 'First element inside the dialog matching [autofocus]',
markup: '<div><input><input autofocus></div>',
options: defaultDialogOptions,
// eslint-disable-next-line object-shorthand, func-names
testActions: function ($element) {
return $element.find('input')[1];
},
},
{
info: 'Tabbable element inside the content element',
markup: '<div><input><input></div>',
options: defaultDialogOptions,
// eslint-disable-next-line object-shorthand, func-names
testActions: function ($element) {
return $element.find('input')[0];
},
},
{
info: 'Tabbable element inside the buttonpane',
markup: '<div>text</div>',
options: defaultDialogOptions,
// eslint-disable-next-line object-shorthand, func-names
testActions: function ($element) {
return $element.dialog('widget').find('.ui-dialog-buttonpane button')[0];
},
},
{
info: 'The close button',
markup: '<div>text</div>',
options: {},
// eslint-disable-next-line object-shorthand, func-names
testActions: function ($element) {
return $element
.dialog('widget')
.find('.ui-dialog-titlebar .ui-dialog-titlebar-close')[0];
},
},
{
info: 'The dialog itself',
markup: '<div>text</div>',
options: { autoOpen: false },
// eslint-disable-next-line object-shorthand, func-names
testActions: function ($element) {
$element.dialog('widget').find('.ui-dialog-titlebar-close').hide();
$element.dialog('open');
return $element.parent()[0];
},
},
{
info: 'Focus starts on second input',
markup: '<div><input><input autofocus></div>',
options: {
// eslint-disable-next-line object-shorthand, func-names
open: function () {
const inputs = jQuery(this).find('input');
inputs.last().on('keydown', function (event) {
event.preventDefault();
inputs.first().trigger('focus');
});
},
},
// eslint-disable-next-line object-shorthand, func-names
testActions: function ($element) {
const inputs = $element.find('input');
return inputs[1];
},
},
];
module.exports = {
'@tags': ['core'],
before(browser) {
browser.drupalInstall().drupalLoginAsAdmin(() => {
browser
.drupalRelativeURL('/admin/modules')
.setValue('input[type="search"]', 'Tabbable Shim Test')
.waitForElementVisible(
'input[name="modules[tabbable_shim_test][enable]"]',
1000,
)
.click('input[name="modules[tabbable_shim_test][enable]"]')
.click('input[type="submit"]');
});
},
after(browser) {
browser.drupalUninstall();
},
'test tabbable': (browser) => {
browser
.drupalRelativeURL('/tabbable-shim-test')
.waitForElementPresent('#tabbable-test-container', 1000);
tabbableTestScenarios.forEach((iteration) => {
browser.execute(
// eslint-disable-next-line func-names, prefer-arrow-callback
function (scenario) {
const $container = jQuery('#tabbable-test-container');
$container.empty();
$container.append(jQuery(scenario.element));
return {
expected: scenario.tabbable,
actual: $container.find(':tabbable').length,
element: scenario.element,
};
},
[iteration],
(result) => {
browser.assert.equal(
result.value.actual,
result.value.expected,
`Expected :tabbable to return ${result.value.expected} for element ${result.value.element}`,
);
},
);
});
browser.drupalLogAndEnd({ onlyOnError: false });
},
'test tabbable dialog integration': (browser) => {
browser
.drupalRelativeURL('/tabbable-shim-dialog-integration-test')
.waitForElementPresent('#tabbable-dialog-test-container', 1000);
dialogIntegrationTestScenarios.forEach((iteration) => {
browser.execute(
// eslint-disable-next-line func-names
function (scenario, testActions) {
// Create the jQuery element that will be used in the test steps.
const $element = jQuery(scenario.markup).dialog(scenario.options);
// Convert the testActions string into a function. testActions is a
// string due to functions being removed from objects passed to
// browser.execute().
// The expectedActiveElement function performs steps specific to a test
// iteration, then returns the element expected to be active after
// those steps.
// eslint-disable-next-line no-new-func
const expectedActiveElement = new Function(`return ${testActions}`)();
return expectedActiveElement($element) === document.activeElement;
},
[iteration, iteration.testActions.toString()],
(result) => {
browser.assert.equal(result.value, true, iteration.info);
},
);
});
browser.drupalLogAndEnd({ onlyOnError: false });
},
};