Ticket #7901: 7901.diff
| File 7901.diff, 7.0 kB (added by savetheclocktower, 2 years ago) |
|---|
-
test/unit/selector.html
old new 25 25 <h1 class="title">Some title <span>here</span></h1> 26 26 <p id="p" class="first summary"> 27 27 <strong id="strong">This</strong> is a short blurb 28 <a id="link_1" class="first internal" rel="external nofollow" href="#">with a link</a> or28 <a id="link_1" class="first internal" rel="external nofollow" href="#">with a <em id="em2">link</em></a> or 29 29 <a id="link_2" class="internal highlight" href="#"><em id="em">two</em></a>. 30 30 Or <cite id="with_title" title="hello world!">a citation</cite>. 31 31 </p> … … 144 144 }}, 145 145 146 146 test$$MatchesAncestryWithTokensSeparatedByWhitespace: function() {with(this) { 147 assertEnumEqual($('em ', 'span'), $$('#fixtures a *'));147 assertEnumEqual($('em2', 'em', 'span'), $$('#fixtures a *')); 148 148 assertEnumEqual([$('p')], $$('div#fixtures p')); 149 149 }}, 150 150 … … 314 314 }}, 315 315 316 316 testSelectorWithNot: function() {with(this) { 317 assertEnumEqual([$('link_2')], $$('#p a:not(:first-of-type)')); 318 assertEnumEqual([$('link_1')], $$('#p a:not(:last-of-type)')); 319 assertEnumEqual([$('link_2')], $$('#p a:not(:nth-of-type(1))')); 320 assertEnumEqual([$('link_1')], $$('#p a:not(:nth-last-of-type(1))')); 321 assertEnumEqual([$('link_2')], $$('#p a:not([rel~=nofollow])')); 322 assertEnumEqual([$('link_2')], $$('#p a:not([rel^=external])')); 323 assertEnumEqual([$('link_2')], $$('#p a:not([rel$=nofollow])')); 317 assertEnumEqual([$('link_2')], $$('#p a:not(a:first-of-type)'), 'first-of-type'); 318 assertEnumEqual([$('link_1')], $$('#p a:not(a:last-of-type)'), 'last-of-type'); 319 assertEnumEqual([$('link_2')], $$('#p a:not(a:nth-of-type(1))'), 'nth-of-type'); 320 assertEnumEqual([$('link_1')], $$('#p a:not(a:nth-last-of-type(1))'), 'nth-last-of-type'); 321 assertEnumEqual([$('link_2')], $$('#p a:not([rel~=nofollow])'), 'attribute 1'); 322 assertEnumEqual([$('link_2')], $$('#p a:not(a[rel^=external])'), 'attribute 2'); 323 assertEnumEqual([$('link_2')], $$('#p a:not(a[rel$=nofollow])'), 'attribute 3'); 324 assertEnumEqual([$('em')], $$('#p a:not(a[rel$="nofollow"]) > em'), 'attribute 4') 324 325 }}, 325 326 326 327 testSelectorWithEnabledDisabledChecked: function() {with(this) { -
src/selector.js
old new 44 44 45 45 compileXPathMatcher: function() { 46 46 var e = this.expression, ps = Selector.patterns, 47 x = Selector.xpath, le, p,m;47 x = Selector.xpath, le, m; 48 48 49 49 if (Selector._cache[e]) { 50 50 this.xpath = Selector._cache[e]; return; … … 130 130 'disabled': "[@disabled]", 131 131 'enabled': "[not(@disabled)]", 132 132 'not': function(m) { 133 if (!m[6]) return ''; 134 var p = Selector.patterns, x = Selector.xpath; 135 for (var i in p) { 136 if (mm = m[6].match(p[i])) { 137 var ss = typeof x[i] == 'function' ? x[i](mm) : new Template(x[i]).evaluate(mm); 138 m[6] = ss.substring(1, ss.length - 1); 139 break; 133 var e = m[6], p = Selector.patterns, 134 x = Selector.xpath, le, m, v; 135 136 var exclusion = []; 137 while (e && le != e && (/\S/).test(e)) { 138 le = e; 139 for (var i in p) { 140 if (m = e.match(p[i])) { 141 v = typeof x[i] == 'function' ? x[i](m) : new Template(x[i]).evaluate(m); 142 exclusion.push("(" + v.substring(1, v.length - 1) + ")"); 143 e = e.replace(m[0], ''); 144 break; 145 } 140 146 } 141 } 142 return "[not(" + m[6]+ ")]";147 } 148 return "[not(" + exclusion.join(" and ") + ")]"; 143 149 }, 144 150 'nth-child': function(m) { 145 151 return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m); … … 184 190 id: 'n = h.id(n, r, "#{1}", c); c = false;', 185 191 attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;', 186 192 attr: function(m) { 187 m[3] = m[5] || m[6];193 m[3] = (m[5] || m[6]); 188 194 return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m); 189 195 }, 190 pseudo: 'n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;', 196 pseudo: function(m) { 197 if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); 198 return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); 199 }, 191 200 descendant: 'c = "descendant";', 192 201 child: 'c = "child";', 193 202 adjacent: 'c = "adjacent";', … … 206 215 tagName: /^\s*(\*|[\w\-]+)(\b|$)?/, 207 216 id: /^#([\w\-\*]+)(\b|$)/, 208 217 className: /^\.([\w\-\*]+)(\b|$)/, 209 pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$ )/,218 pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|\s)/, 210 219 attrPresence: /^\[([\w]+)\]/, 211 220 attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\]]*?)\4|([^'"][^\]]*?)))?\]/ 212 221 }, … … 372 381 }, 373 382 374 383 attr: function(nodes, root, attr, value, operator) { 384 if (!nodes) nodes = root.getElementsByTagName("*"); 375 385 var handler = Selector.operators[operator], results = []; 376 386 for (var i = 0, node; node = nodes[i]; i++) { 377 387 var nodeValue = Element.readAttribute(node, attr); … … 382 392 }, 383 393 384 394 pseudo: function(nodes, name, value, root, combinator) { 385 if (combinator) nodes = this[combinator](nodes); 395 if (nodes && combinator) nodes = this[combinator](nodes); 396 if (!nodes) nodes = root.getElementsByTagName("*"); 386 397 return Selector.pseudos[name](nodes, value, root); 387 398 } 388 399 }, … … 469 480 }, 470 481 471 482 'not': function(nodes, selector, root) { 472 var h = Selector.handlers, exclusions = $A(nodes), selectorType, m; 473 for (var i in Selector.patterns) { 474 if (m = selector.match(Selector.patterns[i])) { 475 selectorType = i; break; 476 } 477 } 478 switch(selectorType) { 479 case 'className': case 'tagName': case 'id': // fallthroughs 480 case 'attrPresence': exclusions = h[selectorType](exclusions, root, m[1], false); break; 481 case 'attr': m[3] = m[5] || m[6]; exclusions = h.attr(exclusions, root, m[1], m[3], m[2]); break; 482 case 'pseudo': exclusions = h.pseudo(exclusions, m[1], m[6], root, false); break; 483 // only 'simple selectors' (one token) allowed in a :not clause 484 default: throw 'Illegal selector in :not clause.'; 485 } 483 var h = Selector.handlers, selectorType, m; 484 var exclusions = new Selector(selector).findElements(root); 486 485 h.mark(exclusions); 487 486 for (var i = 0, results = [], node; node = nodes[i]; i++) 488 487 if (!node._counted) results.push(node);