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/

Reply via email to