|
1 | 1 | import { migratePatchFunc, migrateWarn } from "../main.js";
|
| 2 | +import { jQueryVersionSince } from "../compareVersions.js"; |
2 | 3 |
|
3 | 4 | var oldRemoveAttr = jQuery.fn.removeAttr,
|
| 5 | + oldJQueryAttr = jQuery.attr, |
4 | 6 | oldToggleClass = jQuery.fn.toggleClass,
|
5 |
| - rbooleans = /^(?:checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped)$/i, |
6 |
| - rmatchNonSpace = /\S+/g; |
| 7 | + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|" + |
| 8 | + "disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", |
| 9 | + rbooleans = new RegExp( "^(?:" + booleans + ")$", "i" ), |
| 10 | + rmatchNonSpace = /\S+/g, |
| 11 | + |
| 12 | + // Some formerly boolean attributes gained new values with special meaning. |
| 13 | + // Skip the old boolean attr logic for those values. |
| 14 | + extraBoolAttrValues = { |
| 15 | + hidden: [ "until-found" ] |
| 16 | + }; |
| 17 | + |
| 18 | +// HTML boolean attributes have special behavior: |
| 19 | +// we consider the lowercase name to be the only valid value, so |
| 20 | +// getting (if the attribute is present) normalizes to that, as does |
| 21 | +// setting to any non-`false` value (and setting to `false` removes the attribute). |
| 22 | +// See https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#boolean-attributes |
| 23 | +jQuery.each( booleans.split( "|" ), function( _i, name ) { |
| 24 | + var origAttrHooks = jQuery.attrHooks[ name ] || {}; |
| 25 | + jQuery.attrHooks[ name ] = { |
| 26 | + get: origAttrHooks.get || function( elem ) { |
| 27 | + var attrValue; |
| 28 | + |
| 29 | + if ( jQuery.migrateIsPatchEnabled( "boolean-attributes" ) ) { |
| 30 | + attrValue = elem.getAttribute( name ); |
| 31 | + |
| 32 | + if ( attrValue !== name && attrValue != null && |
| 33 | + ( extraBoolAttrValues[ name ] || [] ).indexOf( attrValue ) === -1 |
| 34 | + ) { |
| 35 | + migrateWarn( "boolean-attributes", |
| 36 | + "Boolean attribute '" + name + |
| 37 | + "' value is different from its lowercased name" ); |
| 38 | + |
| 39 | + // jQuery <4 attr hooks setup is complex: there are attr |
| 40 | + // hooks, bool hooks and selector attr handles. Only |
| 41 | + // implement the logic in jQuery >=4 where it's missing |
| 42 | + // and there are only attr hooks. |
| 43 | + if ( jQueryVersionSince( "4.0.0" ) ) { |
| 44 | + return name.toLowerCase(); |
| 45 | + } |
| 46 | + return null; |
| 47 | + } |
| 48 | + } |
| 49 | + |
| 50 | + return null; |
| 51 | + }, |
| 52 | + |
| 53 | + set: origAttrHooks.set || function( elem, value, name ) { |
| 54 | + if ( jQuery.migrateIsPatchEnabled( "boolean-attributes" ) ) { |
| 55 | + if ( value !== name && |
| 56 | + ( extraBoolAttrValues[ name ] || [] ).indexOf( value ) === -1 |
| 57 | + ) { |
| 58 | + if ( value !== false ) { |
| 59 | + migrateWarn( "boolean-attributes", |
| 60 | + "Boolean attribute '" + name + |
| 61 | + "' is not set to its lowercased name" ); |
| 62 | + } |
| 63 | + |
| 64 | + if ( value === false ) { |
| 65 | + |
| 66 | + // Remove boolean attributes when set to false |
| 67 | + jQuery.removeAttr( elem, name ); |
| 68 | + } else { |
| 69 | + elem.setAttribute( name, name ); |
| 70 | + } |
| 71 | + return name; |
| 72 | + } |
| 73 | + } else if ( !jQueryVersionSince( "4.0.0" ) ) { |
| 74 | + |
| 75 | + // jQuery <4 uses a private `boolHook` for the boolean attribute |
| 76 | + // setter. It's only activated if `attrHook` is not set, but we set |
| 77 | + // it here in Migrate. Since we cannot access it, let's just repeat |
| 78 | + // its contents here. |
| 79 | + if ( value === false ) { |
| 80 | + |
| 81 | + // Remove boolean attributes when set to false |
| 82 | + jQuery.removeAttr( elem, name ); |
| 83 | + } else { |
| 84 | + elem.setAttribute( name, name ); |
| 85 | + } |
| 86 | + return name; |
| 87 | + } |
| 88 | + } |
| 89 | + }; |
| 90 | +} ); |
| 91 | + |
| 92 | +migratePatchFunc( jQuery, "attr", function( elem, name, value ) { |
| 93 | + var nType = elem.nodeType; |
| 94 | + |
| 95 | + // Fallback to the original method on text, comment and attribute nodes |
| 96 | + // and when attributes are not supported. |
| 97 | + if ( nType === 3 || nType === 8 || nType === 2 || |
| 98 | + typeof elem.getAttribute === "undefined" ) { |
| 99 | + return oldJQueryAttr.apply( this, arguments ); |
| 100 | + } |
| 101 | + |
| 102 | + if ( value === false && name.toLowerCase().indexOf( "aria-" ) !== 0 && |
| 103 | + !rbooleans.test( name ) ) { |
| 104 | + migrateWarn( "attr-false", |
| 105 | + "Setting the non-ARIA non-boolean attribute '" + name + |
| 106 | + "' to false" ); |
| 107 | + |
| 108 | + jQuery.attr( elem, name, "false" ); |
| 109 | + return; |
| 110 | + } |
| 111 | + |
| 112 | + return oldJQueryAttr.apply( this, arguments ); |
| 113 | +}, "attr-false" ); |
7 | 114 |
|
8 | 115 | migratePatchFunc( jQuery.fn, "removeAttr", function( name ) {
|
9 | 116 | var self = this,
|
|
0 commit comments