- 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