Re: [selectors-api] Kudos on find/findAll, feedback on spec readability

2012-10-04 Thread Lachlan Hunt

On 2012-09-16 23:40, David Greenspan wrote:

6.2 -  ... first matching Element node within the subtrees...

Don't define a new term subtrees which just means descendants.  Say,
... first matching Element node that is a descendant of the context
object.


I could do that, but doing so makes it harder to rephrase this statement 
without making it more complex.


  3. The implementation must then run the algorithm to evaluate a
 selector against element nodes in the specified tree or subtrees
 using parsed selector as the selector and reference nodes as the
 contextual reference element set, as needed to return the required
 result for the invoked method.

If you have a suggestion for how to rephrase that to remove subtrees 
in a readable way without altering the meaning, please let me know.



The main take-away from section 6.2 should be that find/findAll use a
*different algorithm* from querySelector/querySelectorAll, or the same
algorithm with a different setting (relative=true).  This point is almost
entirely lost.


I think the clearest of those two alternatives is to clearly separate 
the two algorithms.  I have made this change in the spec.



I think the intent is for the reader to perform a sort of
dispatch on type when the algorithm in 6.5 is invoked, but it's confusing
because you can't really look at a selector and a relative selector and
tell them apart, and certainly not before parsing them.


The intent was that the reader is supposed to know whether you have a 
selector or relative selector based on which method was invoked. The 
above changes now make that clearer.



6.2 - When either method is invoked... - there are four methods, not 2


Good point, but with the above changes, I also made it more explicit 
about which methods are being referred to in each case.



6.5 - ... begins with a combinator and that combinator is not ' ' (space)
- how can a relative selector, in a comma-separated list with whitespace,
physically start with a space, i.e. a descendant combinator??


This was added to clarify that ' ' is excluded from the set of possible 
combinators that trigger automatic prepending of :scope, regardless of 
whether the selector meets any of the other conditions.  At this stage 
in the algorithm, no whitespace has been trimmed from the selector, so 
if the input is  div, then it needs to be clear that :scope is not 
prepended in step 1.


Note that there is a known bug in the way the grammar is defined that 
does actually allow for a relative selector to begin with a descendant 
combinator. I just haven't figured out a good way to fix this.  I have 
now noted this issue in the spec.


 Supposing it can (at the beginning of the string, perhaps), why would 

you special-case

it and prepend what's presumably a second descendant combinator in step 5?


Because if steps 2, 3 or 4 apply, then step 5 doesn't apply and :scope 
is not prepended.


e.g.
  document.find( div);  // Matches condition in step 2
  elm.find( not(:scope));   // Matches condition in step 3
  elm.find( body.foo :scope p); // Matches condition in step 4

If space was not excluded, the the spec could be interpreted such that 
:scope should be prepended in those cases.



7 - contextual reference element - This term is revealed to mean simply a
potential :scope element.  I would call it something like a scope
candidate -- or basically anything besides what it's called.


This section was intended to be dropped now that Selectors 4 defines 
:scope adequately, and as such the term contextual reference element 
has been removed.  However, the term contextual reference element set 
still remains due to its definition in Selectors 4.  If you wish to have 
that changed, please follow this up with the CSS WG.


I have now removed section 7 The :scope Pseudo-class entirely from 
this spec.



8 - Feature Strings - Change last paragraph to: Conforming implementations
must return true ... if they are perfectly compliant, and false if they are
not.


No.  Feature strings are a notoriously unreliably method of determining 
support for a given feature and it only exists to provide an indication 
that there is some support for the API, without specifying how compliant 
a given implementation is.



9 - Examples of find() and :scope MUST be added here.  Seriously.  This
section is the last chance to push that lucky reader over the final
threshold to feeling like they fully understand the spec.


They will be added in due course.  They hadn't been added yet due to the 
prior instability of the new API design and their low priority. However, 
feel free to contribute some examples if you like and I will consider 
including them.


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



[selectors-api] Kudos on find/findAll, feedback on spec readability

2012-09-17 Thread David Greenspan
I've been reading the CSS/selector specs lately.  I'm interested both as a
framework implementer, designing and implementing jQuery-like functionality
for Meteor, and as an app developer who looks forward to the days when
browsers provide the APIs we want.

Coming into the new Selectors API, I was really hoping to discover that the
proposed find and findAll methods behaved essentially like the jQuery
calls.  Put simply, in running elem.find(div p), both the div and the
p in question would have to be descendants of elem (as well as each
other) in order to match.  In running elem.find( div p), there would be
the additional constraint that only immediate descendants of elem would be
considered as candidates for the div.  Unfortunately, this didn't seem to
be the case... until I read the spec about a half dozen more times, and I
realized it was!  If I'm reading it right, the spec does work this way and
is additionally much more flexible about the relationship between the
element, the scoping element (or elements), and the selector.  From reading
the list archives, I get the feeling that few web developers who come
across the spec understand this much.

First of all, I want to offer some encouragement.  The names find and
findAll are great, and their functionality is exactly what web developers
will expect and appreciate.  It's familiar and practical.  And as long as
in basic cases like element.find(a b c + d), it's required that all of a,
b, c, and d descend from the element, I am happy with whatever scope
selectors and edge cases are necessary or desirable.

However, the spec is very hard to understand.  I've read several specs
cover-to-cover (Java VM, ECMAScript, JPEG) and I think there is a lot of
low-hanging fruit in this short document (Selectors API Level 2) -- ways to
improve its clarity and enlist your readers more in support of this spec.

Some feedback from a reader, for what it's worth.

6.2 -  ... first matching Element node within the subtrees...

Don't define a new term subtrees which just means descendants.  Say,
... first matching Element node that is a descendant of the context
object.

The main take-away from section 6.2 should be that find/findAll use a
*different algorithm* from querySelector/querySelectorAll, or the same
algorithm with a different setting (relative=true).  This point is almost
entirely lost.  I think the intent is for the reader to perform a sort of
dispatch on type when the algorithm in 6.5 is invoked, but it's confusing
because you can't really look at a selector and a relative selector and
tell them apart, and certainly not before parsing them.  Isn't a relative
selector (string) just a selector (string) optionally preceded by a
combinator?  It seems to me that find() and querySelector() *do different
things*, conceptually; for example, the former will add an implicit :scope
to your selector and the latter won't.  It's nothing to do with their
arguments.  Given the same arguments, they will do different things.

To make it concrete by analogy, how would you interpret this spec (or short
of that, how does it feel to read and try to understand)?

===
Definitions: Chairs are made of wood.  Generalized Chairs are made of
wood, metal or plastic.

The VARNISH function accepts a chair.
The PAINT function accepts a generalized chair.

VARNISH must coat its input with transparent, Acme brand varnish.
PAINT must coat its input with liquid.

When either method is invoked, the implementation must perform Algorithm
Coat.

Algorithm Coat:
1) If the input is a wooden chair, coat it with varnish.
2) Otherwise, if the input is a generalized chair, coat it with paint whose
color matches the chair's referential color context.
===

Here are the stumbling blocks:

- If you try to simulate the algorithm, it's a head-scratcher.  Aren't
wooden chairs also generalized chairs?  How do we get to step 2 to paint a
wooden chair?  Are we really supposed to varnish or paint based on whether
the chair is known-to-be-wood or merely incidentally-wood, or is painting
wooden chairs not possible?

- Presumably, painting was invented to support new chair materials and
achieve color-coordinated finishes, yet there is barely a functional
description of what PAINT does, let alone the intent.  PAINT must coat its
input with liquid is the closest thing we have to a definition.

- We're describing these two functions along three axes, but the
information is so spread out that it is hard to integrate.

The ideal in clarity, which admittedly is not always possible with the need
to specify algorithms and share them between sections, is something like:
===
The VARNISH function accepts a chair and coats it with transparent, Acme
brand varnish.

The PAINT function accepts a generalized chair and coats it with paint
whose color matches the chair's referential color context.
===
That's a breath of fresh air.

However, there are many other options, like:
===
The VARNISH function accepts a chair as its argument.
The PAINT