Fix Selector issues with :not and attribute selector double quotes, fixes #7901. [Andrew Dupont]
This commit is contained in:
parent
779cd337b8
commit
4506db2df2
|
@ -1,6 +1,6 @@
|
|||
*SVN*
|
||||
|
||||
* Fix issues with Selector an+b logic, performance improvements. Closes #7873. [Andrew Dupont]
|
||||
* Fix issues with Selector an+b logic, :not support, attribute selector double quotes, plus performance improvements. Closes #7873, #7901. [Andrew Dupont]
|
||||
|
||||
* Fix an issue with Element.getDimensions with some element types on non IE-browsers. Closes #7683. [Andrew Dupont]
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ Selector.prototype = {
|
|||
|
||||
compileXPathMatcher: function() {
|
||||
var e = this.expression, ps = Selector.patterns,
|
||||
x = Selector.xpath, le, p, m;
|
||||
x = Selector.xpath, le, m;
|
||||
|
||||
if (Selector._cache[e]) {
|
||||
this.xpath = Selector._cache[e]; return;
|
||||
|
@ -130,16 +130,22 @@ Object.extend(Selector, {
|
|||
'disabled': "[@disabled]",
|
||||
'enabled': "[not(@disabled)]",
|
||||
'not': function(m) {
|
||||
if (!m[6]) return '';
|
||||
var p = Selector.patterns, x = Selector.xpath;
|
||||
for (var i in p) {
|
||||
if (mm = m[6].match(p[i])) {
|
||||
var ss = typeof x[i] == 'function' ? x[i](mm) : new Template(x[i]).evaluate(mm);
|
||||
m[6] = ss.substring(1, ss.length - 1);
|
||||
break;
|
||||
var e = m[6], p = Selector.patterns,
|
||||
x = Selector.xpath, le, m, v;
|
||||
|
||||
var exclusion = [];
|
||||
while (e && le != e && (/\S/).test(e)) {
|
||||
le = e;
|
||||
for (var i in p) {
|
||||
if (m = e.match(p[i])) {
|
||||
v = typeof x[i] == 'function' ? x[i](m) : new Template(x[i]).evaluate(m);
|
||||
exclusion.push("(" + v.substring(1, v.length - 1) + ")");
|
||||
e = e.replace(m[0], '');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return "[not(" + m[6] + ")]";
|
||||
}
|
||||
return "[not(" + exclusion.join(" and ") + ")]";
|
||||
},
|
||||
'nth-child': function(m) {
|
||||
return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
|
||||
|
@ -187,10 +193,13 @@ Object.extend(Selector, {
|
|||
id: 'n = h.id(n, r, "#{1}", c); c = false;',
|
||||
attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
|
||||
attr: function(m) {
|
||||
m[3] = m[5] || m[6];
|
||||
m[3] = (m[5] || m[6]);
|
||||
return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
|
||||
},
|
||||
pseudo: 'n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;',
|
||||
pseudo: function(m) {
|
||||
if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
|
||||
return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
|
||||
},
|
||||
descendant: 'c = "descendant";',
|
||||
child: 'c = "child";',
|
||||
adjacent: 'c = "adjacent";',
|
||||
|
@ -209,7 +218,7 @@ Object.extend(Selector, {
|
|||
tagName: /^\s*(\*|[\w\-]+)(\b|$)?/,
|
||||
id: /^#([\w\-\*]+)(\b|$)/,
|
||||
className: /^\.([\w\-\*]+)(\b|$)/,
|
||||
pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$)/,
|
||||
pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|\s)/,
|
||||
attrPresence: /^\[([\w]+)\]/,
|
||||
attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\]]*?)\4|([^'"][^\]]*?)))?\]/
|
||||
},
|
||||
|
@ -377,6 +386,7 @@ Object.extend(Selector, {
|
|||
},
|
||||
|
||||
attr: function(nodes, root, attr, value, operator) {
|
||||
if (!nodes) nodes = root.getElementsByTagName("*");
|
||||
var handler = Selector.operators[operator], results = [];
|
||||
for (var i = 0, node; node = nodes[i]; i++) {
|
||||
var nodeValue = Element.readAttribute(node, attr);
|
||||
|
@ -387,7 +397,8 @@ Object.extend(Selector, {
|
|||
},
|
||||
|
||||
pseudo: function(nodes, name, value, root, combinator) {
|
||||
if (combinator) nodes = this[combinator](nodes);
|
||||
if (nodes && combinator) nodes = this[combinator](nodes);
|
||||
if (!nodes) nodes = root.getElementsByTagName("*");
|
||||
return Selector.pseudos[name](nodes, value, root);
|
||||
}
|
||||
},
|
||||
|
@ -488,20 +499,8 @@ Object.extend(Selector, {
|
|||
},
|
||||
|
||||
'not': function(nodes, selector, root) {
|
||||
var h = Selector.handlers, exclusions = $A(nodes), selectorType, m;
|
||||
for (var i in Selector.patterns) {
|
||||
if (m = selector.match(Selector.patterns[i])) {
|
||||
selectorType = i; break;
|
||||
}
|
||||
}
|
||||
switch(selectorType) {
|
||||
case 'className': case 'tagName': case 'id': // fallthroughs
|
||||
case 'attrPresence': exclusions = h[selectorType](exclusions, root, m[1], false); break;
|
||||
case 'attr': m[3] = m[5] || m[6]; exclusions = h.attr(exclusions, root, m[1], m[3], m[2]); break;
|
||||
case 'pseudo': exclusions = h.pseudo(exclusions, m[1], m[6], root, false); break;
|
||||
// only 'simple selectors' (one token) allowed in a :not clause
|
||||
default: throw 'Illegal selector in :not clause.';
|
||||
}
|
||||
var h = Selector.handlers, selectorType, m;
|
||||
var exclusions = new Selector(selector).findElements(root);
|
||||
h.mark(exclusions);
|
||||
for (var i = 0, results = [], node; node = nodes[i]; i++)
|
||||
if (!node._counted) results.push(node);
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
<h1 class="title">Some title <span>here</span></h1>
|
||||
<p id="p" class="first summary">
|
||||
<strong id="strong">This</strong> is a short blurb
|
||||
<a id="link_1" class="first internal" rel="external nofollow" href="#">with a link</a> or
|
||||
<a id="link_1" class="first internal" rel="external nofollow" href="#">with a <em id="em2">link</em></a> or
|
||||
<a id="link_2" class="internal highlight" href="#"><em id="em">two</em></a>.
|
||||
Or <cite id="with_title" title="hello world!">a citation</cite>.
|
||||
</p>
|
||||
|
@ -144,7 +144,7 @@
|
|||
}},
|
||||
|
||||
test$$MatchesAncestryWithTokensSeparatedByWhitespace: function() {with(this) {
|
||||
assertEnumEqual($('em', 'span'), $$('#fixtures a *'));
|
||||
assertEnumEqual($('em2', 'em', 'span'), $$('#fixtures a *'));
|
||||
assertEnumEqual([$('p')], $$('div#fixtures p'));
|
||||
}},
|
||||
|
||||
|
@ -316,13 +316,14 @@
|
|||
}},
|
||||
|
||||
testSelectorWithNot: function() {with(this) {
|
||||
assertEnumEqual([$('link_2')], $$('#p a:not(:first-of-type)'));
|
||||
assertEnumEqual([$('link_1')], $$('#p a:not(:last-of-type)'));
|
||||
assertEnumEqual([$('link_2')], $$('#p a:not(:nth-of-type(1))'));
|
||||
assertEnumEqual([$('link_1')], $$('#p a:not(:nth-last-of-type(1))'));
|
||||
assertEnumEqual([$('link_2')], $$('#p a:not([rel~=nofollow])'));
|
||||
assertEnumEqual([$('link_2')], $$('#p a:not([rel^=external])'));
|
||||
assertEnumEqual([$('link_2')], $$('#p a:not([rel$=nofollow])'));
|
||||
assertEnumEqual([$('link_2')], $$('#p a:not(a:first-of-type)'), 'first-of-type');
|
||||
assertEnumEqual([$('link_1')], $$('#p a:not(a:last-of-type)'), 'last-of-type');
|
||||
assertEnumEqual([$('link_2')], $$('#p a:not(a:nth-of-type(1))'), 'nth-of-type');
|
||||
assertEnumEqual([$('link_1')], $$('#p a:not(a:nth-last-of-type(1))'), 'nth-last-of-type');
|
||||
assertEnumEqual([$('link_2')], $$('#p a:not([rel~=nofollow])'), 'attribute 1');
|
||||
assertEnumEqual([$('link_2')], $$('#p a:not(a[rel^=external])'), 'attribute 2');
|
||||
assertEnumEqual([$('link_2')], $$('#p a:not(a[rel$=nofollow])'), 'attribute 3');
|
||||
assertEnumEqual([$('em')], $$('#p a:not(a[rel$="nofollow"]) > em'), 'attribute 4')
|
||||
}},
|
||||
|
||||
testSelectorWithEnabledDisabledChecked: function() {with(this) {
|
||||
|
|
Loading…
Reference in New Issue