diff --git a/CHANGELOG b/CHANGELOG index ed2dc33..bc3d685 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +* Re-enable the XPath approach in Selector for Safari 3. Falls back to the non-XPath version when it sees a problematic token. [Andrew Dupont] + * Fix a bug in the IE-specific Element#descendantOf logic. [Nicholas, Andrew Dupont] * Make Ajax.Updater clone its options hash before modifying it. Prevents memory leaks in Ajax.PeriodicalUpdater. Closes #10049 [Mislav Marohnić, Tobie Langel]. diff --git a/src/prototype.js b/src/prototype.js index 3b7d7e8..1b16d6a 100644 --- a/src/prototype.js +++ b/src/prototype.js @@ -30,8 +30,6 @@ var Prototype = { if (Prototype.Browser.MobileSafari) Prototype.BrowserFeatures.SpecificElementExtensions = false; -if (Prototype.Browser.WebKit) - Prototype.BrowserFeatures.XPath = false; <%= include 'base.js', 'string.js' %> diff --git a/src/selector.js b/src/selector.js index d17eb3e..d763c1d 100644 --- a/src/selector.js +++ b/src/selector.js @@ -8,9 +8,26 @@ var Selector = Class.create({ this.compileMatcher(); }, + shouldUseXPath: function() { + if (!Prototype.BrowserFeatures.XPath) return false; + + var e = this.expression; + + // Safari 3 chokes on :*-of-type and :empty + if (Prototype.Browser.WebKit && + (e.include("-of-type") || e.include(":empty"))) + return false; + + // XPath can't do namespaced attributes, nor can it read + // the "checked" property from DOM nodes + if ((/(\[[\w-]*?:|:checked)/).test(this.expression)) + return false; + + return true; + }, + compileMatcher: function() { - // Selectors with namespaced attributes can't use the XPath version - if (Prototype.BrowserFeatures.XPath && !(/(\[[\w-]*?:|:checked)/).test(this.expression)) + if (this.shouldUseXPath()) return this.compileXPathMatcher(); var e = this.expression, ps = Selector.patterns, h = Selector.handlers, @@ -133,8 +150,12 @@ Object.extend(Selector, { }, className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", id: "[@id='#{1}']", - attrPresence: "[@#{1}]", + attrPresence: function(m) { + m[1] = m[1].toLowerCase(); + return new Template("[@#{1}]").evaluate(m); + }, attr: function(m) { + m[1] = m[1].toLowerCase(); m[3] = m[5] || m[6]; return new Template(Selector.xpath.operators[m[2]]).evaluate(m); }, diff --git a/test/unit/selector.html b/test/unit/selector.html index 3ad7664..77afc4d 100644 --- a/test/unit/selector.html +++ b/test/unit/selector.html @@ -158,9 +158,9 @@ }}, testSelectorWithTagNameAndAttributeExistence: function() {with(this) { - assertEnumEqual($$('#fixtures h1'), $$('h1[class]')); - assertEnumEqual($$('#fixtures h1'), $$('h1[CLASS]')); - assertEnumEqual([$('item_3')], $$('li#item_3[class]')); + assertEnumEqual($$('#fixtures h1'), $$('h1[class]'), 'h1[class]'); + assertEnumEqual($$('#fixtures h1'), $$('h1[CLASS]'), 'h1[CLASS]'); + assertEnumEqual([$('item_3')], $$('li#item_3[class]'), 'li#item_3[class]'); }}, testSelectorWithTagNameAndSpecificAttributeValue: function() {with(this) {