From f2bcf87c25155fd8361c744c684a0d526bd184a5 Mon Sep 17 00:00:00 2001 From: Gilad Peleg Date: Tue, 23 Jun 2015 19:42:25 +0300 Subject: [PATCH] Attributes: fix IE8 issues Follow-up for d0388e9e806ca3b30e7bbaaa1c336b7c98dc5f88 --- src/attributes/attr.js | 95 ++++++++++++++++++++++++++++++++++-------- src/attributes/prop.js | 36 ++++++++++++---- 2 files changed, 106 insertions(+), 25 deletions(-) diff --git a/src/attributes/attr.js b/src/attributes/attr.js index 07576738a..689b567cb 100644 --- a/src/attributes/attr.js +++ b/src/attributes/attr.js @@ -3,11 +3,14 @@ define([ "../core/access", "./support", "../var/rnotwhite", + "./val", "../selector" ], function( jQuery, access, support, rnotwhite ) { var boolHook, - attrHandle = jQuery.expr.attrHandle; + attrHandle = jQuery.expr.attrHandle, + ruseDefault = /^(?:checked|selected)$/i, + getSetInput = support.input; jQuery.fn.extend({ attr: function( name, value ) { @@ -15,7 +18,7 @@ jQuery.fn.extend({ }, removeAttr: function( name ) { - return this.each(function() { + return this.each( function() { jQuery.removeAttr( this, name ); }); } @@ -74,6 +77,9 @@ jQuery.extend({ set: function( elem, value ) { if ( !support.radioValue && value === "radio" && jQuery.nodeName( elem, "input" ) ) { + + // Setting the type on a radio button after the value resets the value in IE8-9 + // Reset value to default in case type is set after value during creation var val = elem.value; elem.setAttribute( "type", value ); if ( val ) { @@ -98,7 +104,15 @@ jQuery.extend({ if ( jQuery.expr.match.bool.test( name ) ) { // Set corresponding property to false - elem[ propName ] = false; + if ( getSetInput || !ruseDefault.test( name ) ) { + elem[ propName ] = false; + + // Support: IE<9 + // Also clear defaultChecked/defaultSelected (if appropriate) + } else { + elem[ jQuery.camelCase( "default-" + name ) ] = + elem[ propName ] = false; + } } elem.removeAttribute( name ); @@ -111,30 +125,77 @@ jQuery.extend({ boolHook = { set: function( elem, value, name ) { if ( value === false ) { + // Remove boolean attributes when set to false jQuery.removeAttr( elem, name ); + } else if ( getSetInput || !ruseDefault.test( name ) ) { + elem.setAttribute( jQuery.propFix[ name ] || name, name ); + } else { - elem.setAttribute( name, name ); + + // Support: IE<9 + // Use defaultChecked and defaultSelected for oldIE + elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true; } return name; } }; + jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { var getter = attrHandle[ name ] || jQuery.find.attr; - attrHandle[ name ] = function( elem, name, isXML ) { - var ret, handle; - if ( !isXML ) { - // Avoid an infinite loop by temporarily removing this function from the getter - handle = attrHandle[ name ]; - attrHandle[ name ] = ret; - ret = getter( elem, name, isXML ) != null ? - name.toLowerCase() : - null; - attrHandle[ name ] = handle; - } - return ret; - }; + if ( getSetInput || !ruseDefault.test( name ) ) { + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle; + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ name ]; + attrHandle[ name ] = ret; + ret = getter( elem, name, isXML ) != null ? + name.toLowerCase() : + null; + attrHandle[ name ] = handle; + } + return ret; + }; + } else { + attrHandle[ name ] = function( elem, name, isXML ) { + if ( !isXML ) { + return elem[ jQuery.camelCase( "default-" + name ) ] ? + name.toLowerCase() : + null; + } + }; + } }); +// fix oldIE attroperties +if ( !getSetInput ) { + jQuery.attrHooks.value = { + set: function( elem, value ) { + if ( jQuery.nodeName( elem, "input" ) ) { + + // Does not return so that setAttribute is also used + elem.defaultValue = value; + } + } + }; +} + +if ( !support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + + // Return undefined in the case of empty string + // Note: IE uppercases css property names, but if we were to .toLowerCase() + // .cssText, that would destroy case sensitivity in URL's, like in "background" + return elem.style.cssText || undefined; + }, + set: function( elem, value ) { + return ( elem.style.cssText = value + "" ); + } + }; +} + }); diff --git a/src/attributes/prop.js b/src/attributes/prop.js index 4c7b51e8c..9fad50e41 100644 --- a/src/attributes/prop.js +++ b/src/attributes/prop.js @@ -5,7 +5,8 @@ define([ "../selector" ], function( jQuery, access, support ) { -var rfocusable = /^(?:input|select|textarea|button)$/i; +var rfocusable = /^(?:input|select|textarea|button|object)$/i, + rclickable = /^(?:a|area)$/i; jQuery.fn.extend({ prop: function( name, value ) { @@ -13,8 +14,13 @@ jQuery.fn.extend({ }, removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; return this.each(function() { - delete this[ jQuery.propFix[ name ] || name ]; + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch ( e ) {} }); } }); @@ -55,10 +61,18 @@ jQuery.extend({ propHooks: { tabIndex: { get: function( elem ) { - return elem.hasAttribute( "tabindex" ) || - rfocusable.test( elem.nodeName ) || elem.href ? - elem.tabIndex : - -1; + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + return tabindex ? + parseInt( tabindex, 10 ) : + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && elem.href ? + 0 : + -1; } } }, @@ -73,8 +87,14 @@ if ( !support.optSelected ) { jQuery.propHooks.selected = { get: function( elem ) { var parent = elem.parentNode; - if ( parent && parent.parentNode ) { - parent.parentNode.selectedIndex; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } } return null; }