- From: Lachlan Hunt <lachlan.hunt@lachy.id.au>
- Date: Wed, 20 Jun 2012 16:14:25 +0200
- To: Simon Pieters <simonp@opera.com>
- CC: "public-webapps.w3.org" <public-webapps@w3.org>
On 2012-06-18 16:45, Simon Pieters wrote:
> So http://dev.w3.org/2006/webapi/selectors-api2/ introduces the methods
> find() and findAll() in addition to querySelector() and
> querySelectorAll() and changes the scoping behavior for the former
> methods to match what people expect them to do.
The find methods introduce a number of new behaviours that are not
present in qSA. Some of these features could be introduced into qSA in a
backwards compatible way, but some features could only be partially
supported. The following is an objective look at your proposal,
detailing what can and cannot be back-ported to the older qSA methods.
(Note: All rationale below stated to apply to documents also applies
equally to document fragments.)
1. Support for relative selector syntax.
This features implies the :scope pseudo-class when the selector begins
with a combinator.
elm.find(">span") ==> elm.querySelector(":scope>span")
This feature also applies to document.find() and there is no
compatibility problems with adding support for this to document.qSA.
However, it is only useful when refNodes are supplied (see #3 below).
There is no compatibility problems with adding support for this to
element.qSA, however it would have limited utility.
* It cannot work when it begins with a descendant combinator as this
case is indistinguishable from using no combinator. The reason this
actually works for element.find is because of feature #3 below.
* It can never match sibling elements of the context object (see #4
below), so element.qSA("+span") cannot match anything even if :scope
is implied.
* The reference combinator will only be effective when the subject of
the selector is a descendant of the context object.
label.qSA("/for/ input") would only be useful when input is a
descendant of the label.
* This would be effective for the child combinator.
In summary:
elm.querySelector(" span") // Not possible to imply :scope.
elm.querySelector("+span") // Sibling. Not possible to match.
elm.querySelector("~span") // Sibling. Not possible to match.
elm.querySelector("/for/ input") // Limited utility.
elm.querySelector(">span") // Could work.
2. Support for reference nodes.
This feature allows a parameter to specify a set of elements that will
be matched by :scope. This does not apply to Element.find.
var ref = [...] // Collection of elements.
document.findAll(":scope>span", ref)
This was supported on qSA in previous drafts before the new find/findAll
methods were added. It was only removed from qSA because it duplicated
the functionality of the new methods with no additional benefit. There
is no compatibility problems with adding support for this to document.qSA.
3. Implied :scope when a reference element is present.
Like the relative selector syntax, this is another trigger for implying
:scope. This applies when a non-null refNodes parameter is passed to
the document.find methods. The context object is used when it is an
Element node, so :scope is always implied in that case.
elm.find("div p")
document.find("div p", elm)
Both of those are equivalent to using explicit :scope in:
elm.querySelector(":scope div p")
This feature cannot be supported by Element.qSA because implying :scope
would break the following case where the div is not a descendant of the
context object (elm).
elm.querySelector("div p")
This cannot be equivalent to the examples above without breaking
compatibility.
There is no compatibility problems with adding support for this to
document.qSA.
4. Support for returning elements that are not descendants of the
context object.
This feature allows a selector to be constructed such that it matches an
element anywhere in the tree relative to the context element. This
feature is not relevant to document.find(), since it can already return
anything from the whole tree.
elm.find("+span") // span is a sibling
elm.find("/for/ input") // input could be anywhere
elm.find(":not(:scope)") // Everything except the context object
This feature cannot be supported on Element.qSA, even when using eplicit
:scope, because matching elements need to be descendants of the context
object.
5. Return type of the findAll method
Although not yet decided, there have been concerns raised about the
NodeList return type of the querySelectorAll methods. There has been
suggestions that findAll instead return either an Array or an Array-like
object that implements more useful functionality than NodeList currently
does. JS libraries tend to use the Array.slice() technique to convert
node lists to arrays, which they can deal with more effectively.
It's not yet clear if this issue can be addressed by extending the
current NodeList interface or using an alternative return type.
> I'm not convinced that doubling the API surface is a good idea. If we
> were to do that every time we find that a shipped API has suboptimal
> behavior,
We could reduce the API surface area slightly by applying all
functionality of document.find to the document.qSA methods and either
eliminating document.find entirely, or making them aliases. This,
however, would eliminate the possibility of using an alternative return
type for the find methods (see #5 above). This would not be a problem
if NodeList could be usefully extended.
Doing this alone, however, would also make document.qSA inconsistent
with element.qSA in relation to selector syntax. This inconsistency
could be addressed by opting to support the relative selector syntax in
element.qSA anyway despite its limited utility.
This would still leave some important functionality missing from the API
(#3 and #4), which is provided for by the new element.find methods and
would fail to address the serious concerns raised by web developers
regarding the terrible method names.
--
Lachlan Hunt - Opera Software
http://lachy.id.au/
http://www.opera.com/
Received on Wednesday, 20 June 2012 14:15:00 UTC