From 3c82f8fb4aed7b4e65e1dd9ed79718a155a7a492 Mon Sep 17 00:00:00 2001 From: John Resig Date: Sun, 29 Jul 2007 22:32:06 +0000 Subject: [PATCH] Added a fix for Safari's broken CSS getComputedStyle accessing. Additionally, added a fix for Safari mis-reporting @selected for display: none options. The test suite is now completely passing in Safari 3. (Bug #1349) --- src/jquery/jquery.js | 53 +++++++++++++++++++++++++++++++--------- src/selector/selector.js | 2 +- 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/jquery/jquery.js b/src/jquery/jquery.js index 6f4bbe3fb..8e8f7be78 100644 --- a/src/jquery/jquery.js +++ b/src/jquery/jquery.js @@ -1457,7 +1457,8 @@ jQuery.extend({ }, curCSS: function(elem, prop, force) { - var ret; + var ret, getComputedStyle = document.defaultView && + document.defaultView.getComputedStyle, stack = [], swap = []; if (prop == "opacity" && jQuery.browser.msie) { ret = jQuery.attr(elem.style, "opacity"); @@ -1470,27 +1471,52 @@ jQuery.extend({ if (!force && elem.style[prop]) ret = elem.style[prop]; - else if (document.defaultView && document.defaultView.getComputedStyle) { + else if (getComputedStyle) { if (prop.match(/float/i)) prop = "float"; prop = prop.replace(/([A-Z])/g,"-$1").toLowerCase(); - var cur = document.defaultView.getComputedStyle(elem, null); + var cur = getComputedStyle(elem, null); - if ( cur ) + if ( cur && !color(elem) ) ret = cur.getPropertyValue(prop); - else if ( prop == "display" ) - ret = "none"; - else - jQuery.swap(elem, { display: "block" }, function() { - var c = document.defaultView.getComputedStyle(this, ""); - ret = c && c.getPropertyValue(prop) || ""; - }); + + // If the element isn't reporting its values properly in Safari + // then some display: none elements are involved + else { + // Locate all of the parent display: none elements + for ( var a = elem; color(a); a = a.parentNode ) + stack.unshift(a); + + // Go through and make them visible, but in reverse + // (It would be better if we knew the exact display type that they had) + for ( a = 0; a < stack.length; a++ ) + if ( color(stack[a]) ) { + swap[a] = stack[a].style.display; + stack[a].style.display = "block"; + } + + // Since we flip the display style, we have to handle that + // one special, otherwise get the value + ret = prop == "display" && swap[stack.length-1] != null ? + "none" : + getComputedStyle(elem,null).getPropertyValue(prop) || ""; + + // Finally, revert the display styles back + for ( a = 0; a < swap.length; a++ ) + if ( swap[a] != null ) + stack[a].style.display = swap[a]; + } if ( prop == "opacity" && ret == "" ) ret = "1"; + // A helper method for determining if an element's values are broken + function color(a){ + return jQuery.browser.safari && getComputedStyle(a,null).getPropertyValue("color") == ""; + } + } else if (elem.currentStyle) { var newProp = prop.replace(/\-(\w)/g,function(m,c){return c.toUpperCase();}); ret = elem.currentStyle[prop] || elem.currentStyle[newProp]; @@ -1579,6 +1605,11 @@ jQuery.extend({ attr: function(elem, name, value){ var fix = jQuery.isXMLDoc(elem) ? {} : jQuery.props; + + // Safari mis-reports the default selected property of a hidden option + // Accessing the parent's selectedIndex property fixes it + if ( name == "selected" && jQuery.browser.safari ) + elem.parentNode.selectedIndex; // Certain attributes only work when accessed via the old DOM 0 way if ( fix[name] ) { diff --git a/src/selector/selector.js b/src/selector/selector.js index 366cf3188..34aaf61e5 100644 --- a/src/selector/selector.js +++ b/src/selector/selector.js @@ -339,7 +339,7 @@ jQuery.extend({ for ( var i = 0, rl = r.length; i < rl; i++ ) { var a = r[i], z = a[ jQuery.props[m[2]] || m[2] ]; - if ( z == null || /href|src/.test(m[2]) ) + if ( z == null || /href|src|selected/.test(m[2]) ) z = jQuery.attr(a,m[2]) || ''; if ( (type == "" && !!z ||