- From: Lachlan Hunt <lachlan.hunt@lachy.id.au>
- Date: Mon, 14 Jan 2013 15:05:44 +0100
- To: www-style <www-style@w3.org>
On 2012-10-30 11:42, Lachlan Hunt wrote: > Additionally, I would like to move the definition for relative selectors > and the related parsing to Selectors 4. This is a concept I defined in > Selectors API Level 2, which basically allows selectors to begin with a > combinator and have an implied :scope. > > http://dev.w3.org/2006/webapi/selectors-api2/#grammar I see that Selectors 4 has since introduced the concept of "scope-relative selectors", which seems to be what I was asking for. Though, there are some issues with the way it is currently written. http://dev.w3.org/csswg/selectors4/#scoping Firstly, the example in this section states that element.find() uses scope-contained selectors like scoped stylesheets in HTML. But it doesn't. It uses scope relative selectors. These are different because .find() needs to be able to match elements that are not descendants of the context object. Secondly, the current scope-relative selector definition states: > With this method of scoping, ":scope " (the :scope pseudo-class > followed by a space) is implied at the beginning of each complex > selector, allowing them to begin syntactically with a combinator. The > scoping element matches this implied :scope selector, but does not > limit which elements match. The find(), findAll() and matches() methods were designed with special rules that defined when :scope should and should not be prepended to each selector, which are not properly covered by the above definition. These are the rules used in Selectors API: --- 1. If the relative selector begins with a combinator, then prepend the simple selector ":scope" to the relative selector. 2. Otherwise, if the reference nodes is an empty collection, do nothing. 3. Otherwise, if any compound selector within relative selector includes a functional pseudo-class that accepts a selector as its parameter, and which contains the ":scope" pseudo-class anywhere within it, then do nothing. 4. Otherwise, if the relative selector includes :scope within any compound or simple selector, then do nothing. 5. Otherwise, if the scope flag is set, prepend the simple selector ":scope" and a descendant combinator (' ') to the relative selector. --- The 'scope flag' that is mentioned above is set or unset depending on which method is called. The flag is set when find() or findAll() are called, and it is unset when matches() is called. This is because for .matches(), the subject of the selector needs to match the context object, rather than anywhere else in the selector. This would not work if :scope was automatically prepended. To illustrate the effect of the above rules: 1. :scope is always prepended for these cases beginning with a combinator: * document.find(">div") // --> ":scope>div" * document.find("~:not(:scope)") // --> ":scope~:not(:scope)" * document.find("+div:scope p") // --> ":scope+div:scope p" * element.find(">div") // --> ":scope>div" * element.find("~:not(:scope)") // --> ":scope~:not(:scope)" * element.find("+div:scope p") // --> ":scope+div:scope p" * element.matches(">div") // --> ":scope>div" * element.matches("~:not(:scope)") // --> ":scope~:not(:scope)" * element.matches("+div:scope p") // --> ":scope+div:scope p" 2. :scope is not prepended for these cases where the contextual reference element set is empty: * document.find("div", []) // --> "div" * element.find("div", []) // --> "div" * element.matches("div", []) // --> "div" 3. :scope is not prepended for these cases that include ':scope' within a functional pseudo-class: * document.find(":not(:scope)") // --> ":not(:scope)" * element.find(":not(:scope)") // --> ":not(:scope)" * element.matches(":not(:scope)") // --> ":not(:scope)" 4. :scope is not prepended for these cases that include ':scope' as part of any simple or compound selector: * document.find("div:scope p") // --> "div:scope p" * element.find("div:scope p") // --> "div:scope p" * element.matches("div:scope p") // --> "div:scope p" 5. a) :scope and a descendant combinator are prepended when the 'scope flag' is set: * document.find("div p") // --> ":scope div p" * document.find("div p", refNodes) // --> ":scope div p" * element.find("div p") // --> ":scope div p" * element.find("div p", refNodes) // --> ":scope div p" b) :scope is not prepended when the 'scope flag' is unset: * element.matches("div p") // --> "div p" * element.matches("div p", refNodes) // --> "div p" These rules are incorporated into the selectorsapi branch of DOM Standard, which is available on github (See Overview.src.html). These changes aren't published anywhere yet. https://github.com/lachlanhunt/dom/tree/selectorsapi Note: You can still see the old Selectors API 2 draft, which includes an older version of that algorithm. It's more of less the same, but the new version I quoted above was just rephrased slightly. http://dev.w3.org/2006/webapi/selectors-api2/#parse-a-relative-selector -- Lachlan Hunt http://lachy.id.au/ http://www.opera.com/
Received on Monday, 14 January 2013 14:06:08 UTC