[selectors-api] Requirements and Use Cases for Scoped Methods

Hi,
   Based on the ongoing discussion, I've put together the following list 
of requirements and sumarised use cases that should be met by the design 
of new features in selectors API.

*Use Cases*

1. Select elements that are descendants of specific Element node, where 
all elements matched by the chain of selectors are all descendants of 
that element.

<section>
   <h1>A</h1>
   <div id="foo">
     <h1>B</h1>
     <section>
       <h1>C</h1>
     </section>
   </div>

   <section>
     <h1>D</h1>
   </section>

</section>

e.g. JQuery

   $("#foo").find("section h1")

This should find heading C only.


2. Select elements that is a child of a specific Element node.

e.g.

   $("#foo").find(">h1")


3. Select elements that are siblings (adjacent + or general ~) of a 
specific Element node.

e.g.

   $("#foo").find("+section h1")
   $("#foo").find("~section h1")


4. Select elements relative to a specific Element node, conditionally 
based on it's own state.

e.g. (Pseudo code)
   if Element foo has class name "X",
     Select descendant elements matching "input[type=radio]"
   Otherwise, if Element foo has class name "Y"
     Select descendant elements matching "input[type=checkbox]"

Alternatively,
   foo = document.getElementById("foo");
   inputs = foo.querySelectorAll(".X:scope input[type=radio],
                                  .Y:scope input[type=checkbox]");


5. Select elements relative to a specific Element node, conditionally 
based on the state of an ancestor or previous sibling element.

e.g. (Pseudo code)
   if ancestor Element section has class name "X",
     Select descendant elements matching "input[type=radio]"
   Otherwise, if ancestor Element section has class name "Y"
     Select descendant elements matching "input[type=checkbox]"

foo = document.getElementById("foo");
inputs = foo.querySelectorAll("section.X :scope input[type=radio],
                                section.Y :scope input[type=checkbox]");


*General*

* Method names should be short, memorable and easy to type.
   - querySelectorAll is considered too long by authors.
* Methods should prioritise optimisations for the common cases over
   full flexibility.  Less common and more complex cases can be handled
   by existing methods.
   - Use cases 4 and 5 may be left to existing methods, depending on
     complexity they introduce and the impact upon potential
     optimisations.  i.e. The cost vs. benefit of supporting them in new
     methods.

* Optimisations should consider both authors and implementations


*Implicit Scoping*

* In the common case, when called on an element, selectors should be
   scoped relative to the context element
* In the common case when called on the document, it either:
   - Search the whole document, or
   - Be scoped relative to a collection of reference elements

* Support matching descendants, next siblings and their descendants
* Should avoid matching ancestors or previous siblings
   - (See reference combinator issue below)


*Syntax*

* Should not require authors to explicitly use :scope, at least when it
   occurs at the beginning.

* Selectors should be able to begin with combinators, :scope should be
   implied at the beginning.


*Return Value*

* Methods should return either a single Element node and/or an 
collection of elements
* A collection of Elements should be
   - Mutable
   - Static, not live
   - Support all, or at least some, methods from Array.  Need to
     determine which functionality is most important.
   - JS Libraries use Array.slice hack to convert a NodeList to an
     Array. This is a sub-optimal solution.


*Implementation Optimisations*

* It should be possible to, at least in the common cases, to limit the
   set of potential matches to a subset of the document.
   - This reduces the number of comparisons that need to be done and
     thus time to compute the result.

* Ideally, it should be possible to determine heuristically from the 
Selector whether the impelemntation needs to check:
   - Only context element's descendants (descendant or child combinators)
   - Only context element's siblings (sibling combinators)
   - Both

Issue: What should happen with the new reference combinator?

   label.find("/for/ input");
   div.find("label /for/ input")
   div.find(">label /for/ input + span")

   * What would authors expect the result to be?
   * Should these search:
     - The whole document (or whole tree, if disconnected from document)?
     - Only descendants?
     - Only descendants and siblings?
     - Other subset of the document?
   * How does each option affect performance?
   * Are there any possible optimisations for these cases?

e.g.
<label for="foo">Label</label>
   <input type="text" name="a" id="foo">
   <input type="text" name="b" id="foo">

"label /for/ input" matches both inputs, just like "#foo"


Note: If you have anything to add, please do so.  I'll be on holiday and 
mostly offline for the next 3 weeks.  I'll review any additional 
discussion and attempt to draft up a possible solution in the spec after 
I get back from holidays.

-- 
Lachlan Hunt - Opera Software
http://lachy.id.au/
http://www.opera.com/

Received on Friday, 21 October 2011 13:46:21 UTC