Re: [Selectors API 2] Is matchesSelector stable enough to unprefix in implementations?

2011-11-25 Thread Sean Hogan

On 26/11/11 12:00 AM, Lachlan Hunt wrote:

On 2011-11-25 00:19, Sean Hogan wrote:

This has been raised before, but I'll restate it here.

How should the selector be expanded in
elt.findAll(div span, div :scope span)?


The implication of :scope has to be done on a per complex selector 
basis, rather than applied to the entire list.  That would be 
equivalent to:


elt.findAll(:scope div span, div :scope span)


If this isn't to throw an error then a more complex definition is
required which can apply a different rule for implying :scope in
different parts of the selector argument. This is sure to be confusing
for anyone reading the code.


Selectors in selector lists are always independent of each other, so 
authors who use a selector list would likely assume that one doesn't 
affect how another in the list matches.  It would seem far more 
confusing for authors to do it using the other alternatives.




Discussion on this list has indicated that allowing explicit :scope in 
findAll() is confusing, which-ever definition is used. OTOH, there has 
been little or no confusion about how findAll() would behave if :scope 
is always implied. Do you expect the general web-dev community to be 
different?







Re: [Selectors API 2] Is matchesSelector stable enough to unprefix in implementations?

2011-11-25 Thread Sean Hogan

On 25/11/11 6:49 PM, Lachlan Hunt wrote:

On 2011-11-25 01:07, Sean Hogan wrote:

On 24/11/11 7:46 PM, Lachlan Hunt wrote:

On 2011-11-23 23:38, Sean Hogan wrote:
- If you want to use selectors with :scope implied at the start of 
each

selector in the selector list (as most js libs currently do) then you
use find / findAll / matches.


The matches method will not change behaviour depending on whether or
not there is an explicit :scope because it is always evaluated in the
context of the entire tree. There is never an implied :scope inserted
into the selector, so there will not be two alternative matches 
methods.


If and when there is a need for a matching method that does imply :scope
(which I provided a use-case for in
http://lists.w3.org/Archives/Public/public-webapps/2011OctDec/0342.html)
then it could be called matches().


Oh, it wasn't clear that you were talking about a case involving 
explicit reference nodes before.


But adding two separate methods that are only subtly different would 
add more complexity for authors, since the difference will not always 
be obvious where there is no explicit reference nodes supplied and 
they may get them confused.


In fact, with a method that always prepends :scope, it could result in 
an unexpected result in some cases:


e.g.

   root.matches(html.foo);
   root.matchesSelector(html.foo);

These aren't obviously different, but when you consider that the first 
would always prepend :scope under your proposal, the first would 
unexpectedly return false, since it's equivalent to:


   root.matchesSelector(:scope html.foo);

This would happen whether the root element is the root of the 
document, or the root of a disconnected tree.


We could instead address your use case by implying :scope if a 
refElement or refNodes is supplied.  That way, if the author calls 
.matches() without any refNodes, they get the expected result with no 
implied :scope.  If they do supply refNodes, and there is no explicit 
:scope, then imply :scope at the beginning.


This approach would be completely backwards compatible with the 
existing implementations, as nothing changes until refNodes/refElement 
and :scope are supported.




You mentioned this before, but anyway:

el.matches(div span) - ok

el.matches( div span) - throws, because no :scope implied

el.matches(div :scope span) - ok, but can't match anything
el.matches( div span, refNode) - ok
el.matches(div :scope span, refNode) - ok

el.matches(div span, refNode) - what does this do? How do you know 
that the intention isn't to just ignore the refNode if there is no 
explicit :scope?


I guess if you wanted this last behavior, you could call something like
/:scope\b/.test(selector)
before-hand and if it is false then not pass the refNode to matches().

I'm not sure if there are other problematic cases.

Sean




Re: Remaining Problems with Explicit :scope Switching in find/findAll

2011-11-25 Thread Sean Hogan

On 25/11/11 5:53 AM, Yehuda Katz wrote:


So, the rules end up being very simple.  find always evaluates against
the whole document.  If one of the selectors starts with a combinator
or doesn't contain a :scope pseudoclass somewhere in it, :scope is
prepended to it.  That's it.  With this, we make the most common cases
(searching descendants/siblings) easy, while making the global case
*also* easy.  There's a bit of intent-guessing when :scope is used in
an indirect way, but I believe it's better to err on the side of
simplicity and consistency there.


I am ok with this, but I am also ok with find always evaluates 
against the whole document.  If one of the selectors doesn't contain a 
:scope pseudoclass somewhere in it, :scope is prepended to it.


I also thing we agreed that filtering selectors, in the case of 
implicit scope, are applied on the :scope, not as a descendent of the 
:scope.


As I said above, since the cases of starting with a combinator are 
nonsense queries (correct me if I'm missing something obvious), we can 
simplify the rules even more and eliminate the case of starting with 
a combinator *and* has a :scope


Are you AGAINST findAll() always implying :scope at the start of each 
selector in a selector list, and leaving explicit :scope to 
querySelectorAll()?


If so, why?

Sean



Re: [Selectors API 2] Is matchesSelector stable enough to unprefix in implementations?

2011-11-24 Thread Sean Hogan

On 24/11/11 10:52 AM, Yehuda Katz wrote:


Yehuda Katz
(ph) 718.877.1325


On Wed, Nov 23, 2011 at 2:38 PM, Sean Hogan shogu...@westnet.com.au 
mailto:shogu...@westnet.com.au wrote:


On 23/11/11 12:17 AM, Boris Zbarsky wrote:

On 11/22/11 6:50 AM, Lachlan Hunt wrote:

Last time we had this discussion, you had a desire to keep
the name
prefixed until the refNodes and :scope stuff was
implemented [1]. What's
the status on that now?


The status is that I've given up on the :scope discussion
reaching a conclusion in finite time (esp. because it sounds
like people would like to change what it means depending on
the name of the function being called) and would be quite
happy to ship an implementation that only takes one argument.
 Web pages can use .length on the function to detect support
for the two-argument version if that ever happens.


Are there any issues with:

- If you want to use selectors with explicit :scope then you use
querySelector / querySelectorAll / matchesSelector.

- If you want to use selectors with :scope implied at the start of
each selector in the selector list (as most js libs currently do)
then you use find / findAll / matches.


The alternative option (find / findAll / matches can accept
explicit :scope, but will otherwise imply :scope) seems to be
where all the ambiguity lies.


What exact cases are ambiguous with find/findAll/matches can accept 
explicit :scope, but will otherwise imply :scope?





This has been raised before, but I'll restate it here.

How should the selector be expanded in
elt.findAll(div span, div :scope span)?

The straight-forward interpretation of implies :scope unless it is 
explicit is to not expand this, thus:

div span, div :scope span

But with that interpretation
elt.findAll( div span, div :scope span)
will throw an error, although
elt.findAll( div span); elt.findAll(div :scope span);
is allowed.

If this isn't to throw an error then a more complex definition is 
required which can apply a different rule for implying :scope in 
different parts of the selector argument. This is sure to be confusing 
for anyone reading the code.


OTOH, if find / findAll  always implies :scope there isn't this problem. 
Moreover, that is what people will expect if they are used to jQuery's 
find() and equivalents in other JS libs.


This makes for a fairly straight-forward explanation of usage:

- If you want to use selectors with explicit :scope then you use 
querySelector / querySelectorAll / matchesSelector.


- If you want to use selectors with :scope implied at the start of each 
selector in the selector list (as most js libs currently do) then you 
use find / findAll / matches.




Re: [Selectors API 2] Is matchesSelector stable enough to unprefix in implementations?

2011-11-24 Thread Sean Hogan

On 24/11/11 7:46 PM, Lachlan Hunt wrote:

On 2011-11-23 23:38, Sean Hogan wrote:

Are there any issues with:

- If you want to use selectors with explicit :scope then you use
querySelector / querySelectorAll / matchesSelector.

- If you want to use selectors with :scope implied at the start of each
selector in the selector list (as most js libs currently do) then you
use find / findAll / matches.


The matches method will not change behaviour depending on whether or 
not there is an explicit :scope because it is always evaluated in the 
context of the entire tree.  There is never an implied :scope inserted 
into the selector, so there will not be two alternative matches methods.




A matching method that doesn't imply :scope should be called 
matchesSelector().


If and when there is a need for a matching method that does imply :scope 
(which I provided a use-case for in 
http://lists.w3.org/Archives/Public/public-webapps/2011OctDec/0342.html) 
then it could be called matches().


I should be able to define querySelectorAll() in terms of 
matchesSelector(),

and findAll() in terms of matches().

Thus:

function querySelectorAll(selector) {
var refNode = this;
return [].filter.call(refNode.getElementsByTagName(*),
function(elt) { return elt.matchesSelector(selector, refNode); });
}

function findAll(selector) {
var refNode = this, list = [];
for (var node=refNode; node; node=node.nextSibling) {
if (node.nodeType != 1) continue;
if (node != refNode  node.matches(selector, refNode)) 
list.push(node);

[].push.apply(list, [].filter.call(node.getElementsByTagName(*),
function(elt) { return elt.matches(selector, refNode); });
}
return list;
}






Re: [Selectors API 2] Is matchesSelector stable enough to unprefix in implementations?

2011-11-23 Thread Sean Hogan

On 23/11/11 12:17 AM, Boris Zbarsky wrote:

On 11/22/11 6:50 AM, Lachlan Hunt wrote:

Last time we had this discussion, you had a desire to keep the name
prefixed until the refNodes and :scope stuff was implemented [1]. What's
the status on that now?


The status is that I've given up on the :scope discussion reaching a 
conclusion in finite time (esp. because it sounds like people would 
like to change what it means depending on the name of the function 
being called) and would be quite happy to ship an implementation that 
only takes one argument.  Web pages can use .length on the function to 
detect support for the two-argument version if that ever happens.




Are there any issues with:

- If you want to use selectors with explicit :scope then you use 
querySelector / querySelectorAll / matchesSelector.


- If you want to use selectors with :scope implied at the start of each 
selector in the selector list (as most js libs currently do) then you 
use find / findAll / matches.



The alternative option (find / findAll / matches can accept explicit 
:scope, but will otherwise imply :scope) seems to be where all the 
ambiguity lies.


Sean





Re: [Selectors API 2] Is matchesSelector stable enough to unprefix in implementations?

2011-11-22 Thread Sean Hogan

On 22/11/11 7:14 PM, Roland Steiner wrote:
On Tue, Nov 22, 2011 at 14:19, Yehuda Katz wyc...@gmail.com 
mailto:wyc...@gmail.com wrote:



Yehuda Katz
(ph) 718.877.1325 tel:718.877.1325


On Mon, Nov 21, 2011 at 8:34 AM, Boris Zbarsky bzbar...@mit.edu
mailto:bzbar...@mit.edu wrote:

On 11/21/11 11:31 AM, Tab Atkins Jr. wrote:

1)  Make sense.
2)  Not break existing content.
3)  Be short.


.matches
.is


I like .is, the name jQuery uses for this purpose. Any reason not
to go with it?


IMHO 'is' seems awfully broad in meaning and doesn't very well 
indicate that the parameter should be a selector. Inasmuch I like 
.matches better.


Also, FWIW, an 'is' attribute on elements was/is in discussion on this 
ML as one possibility to specify components.




Funnily enough, I've just been talking to the DOM5 and DOM6 API 
designers and they said almost exactly the same thing.






Re: [Selectors API 2] Is matchesSelector stable enough to unprefix in implementations?

2011-11-21 Thread Sean Hogan

On 22/11/11 3:23 AM, Boris Zbarsky wrote:

On 11/21/11 10:56 AM, Tab Atkins Jr. wrote:

On Mon, Nov 21, 2011 at 7:22 AM, Boris Zbarskybzbar...@mit.edu  wrote:
What's the current state of matchesSelector?  Are we confident 
enough in the

name and such to unprefix it?


I think that matchesSelector suffers from the same verbosity that qSA
does, and would benefit from the same discussion as what has happened
over .find/findAll.


I was wondering about that; hence the question.

Let's have this discussion right now.  What name here would:

1)  Make sense.


The current defined behavior of matchesSelector() goes with the behavior 
of querySelectorAll(), so the name seems appropriate.


If find / findAll is implemented then a matches() method with 
corresponding behavior might be appropriate. See the discussion that 
started at


http://lists.w3.org/Archives/Public/public-webapps/2011OctDec/0342.html

Sean




Re: QSA, the problem with :scope, and naming

2011-10-30 Thread Sean Hogan

On 30/10/11 2:28 PM, Cameron McCormack wrote:

On 20/10/11 3:50 AM, Alex Russell wrote:

I strongly agree that it should be an Array *type*, but I think just
returning a plain Array is the wrong resolution to our NodeList
problem. WebIDL should specify that DOM List types *are* Array types.
It's insane that we even have a NodeList type which isn't a real array
at all. Adding a parallel system when we could just fix the one we
have (and preserve the value of a separate prototype for extension) is
wonky to me.

That said, I'd *also* support the ability to have some sort of
decorator mechanism before return on .find() or a way to re-route the
prototype of the returned Array.

+heycam to debate this point.


Late replying here again, apologies, but I agree with others who say 
that an actual Array object should be returned from this new API given 
that it is not meant to be live.  What benefit is there from returning 
a NodeList?





I think it's already been said, but if StaticNodeList (or whatever) 
inherits from Array then it receives array methods plus it can still 
have .item() for people who are assuming it is like NodeList.


Sean




Re: QSA, the problem with :scope, and naming

2011-10-25 Thread Sean Hogan

On 26/10/11 4:43 AM, Yehuda Katz wrote:

Your guesses are all right in terms of existing jQuery but one:

'div': [1, 2, 3, 4]
'': []
'#3': [3]
' div': [1, 2, 3]
'[foo=bar]': []
'[id=1]': [1]
':first-child': [1, 4]
'+ div': [5]
'~ div': [5, 6]

You can see the results live at http://jsfiddle.net/Dj3Ab/.

The basic rule is that if there is no combinator, a descendent 
combinator is implied.


jQuery returns an empty list with an empty String, but 
querySelectorAll throws an exception (the spec says that the selector 
SHOULD match a slightly loosened version of the selector production in 
http://www.w3.org/TR/2009/PR-css3-selectors-20091215/#w3cselgrammar, 
which disallows the empty string). It probably makes sense for find or 
findAll to raise an exception too, but an empty list is fine too.


I'm not as sure about the :scope cases. I can make some guesses:

e.findAll(:scope) // context
e.findAll(div:scope) // context
e.findAll([foo=bar]:scope) // context
e.findAll(:scope div) // 1,2,3,4
e.findAll(div:scope div) // 1,2,3,4
e.findAll(div:scope #3) // 3
e.findAll(body  :scope  div) // 1,2,3
e.findAll(div, :scope) // 0,context,1,2,3,4,5,6
e.findAll(body  :scope  div, :scope) // context,1,2,3
e.findAll(:not(:scope)) // all elements except context

In cases where :scope is used, I would say that the selector behaves 
identically to the id hack used by most JavaScript libraries. In 
particular, the selector is relative to the root element, and the 
:scope element simply represents the context element.




I think allowing explicit :scope in findAll() will be perpetually 
confusing. I can imagine someone looking at old code like:


e.findAll(div.foo span, div.bar :scope span)

and asking themselves what's the rule again? If there's :scope in the 
selector then there's no :scope implied? Or was that just on each single 
selector? Or is :scope always implied at the start of the whole selector 
list and that's why it's explicit in the second part? Dammit, why didn't 
we just use querySelectorAll() if we wanted explicit :scope?



So you could change the :scope rules to be:

e.findAll(#context) // context
e.findAll(div#context) // context
e.findAll([foo=bar]#context) // context
e.findAll(#context div) // 1,2,3,4
e.findAll(div#context div) // 1,2,3,4
e.findAll(div#context #3) // 3
e.findAll(body  #context  div) // 1,2,3
e.findAll(div, #context) // 0,context,1,2,3,4,5,6
e.findAll(body  #context  div, #context) // context,1,2,3
e.findAll(:not(#context)) // all elements except context

This also means that the above (non-:scope) rule could (I think) be 
restated as:


  * Each selector in a selector group passed to find or findAll has an
implied leading :scope
  * If no initial combinator is supplied, a descendent combinator is
implied

Yehuda Katz
(ph) 718.877.1325


On Fri, Oct 21, 2011 at 12:41 AM, Jonas Sicking jo...@sicking.cc wrote:

On Thu, Oct 20, 2011 at 2:33 PM, Lachlan Hunt
lachlan.h...@lachy.id.au mailto:lachlan.h...@lachy.id.au wrote:
 Not necessarily.  It depends what exactly it means for a
selector to contain
 :scope for determining whether or not to enable the implied :scope
 behaviour.  Consider:

  foo.find(:not(:scope));

Ooh, this is an interesting case too. So here's the full list of
cases which we need defined behavior for (again looking at Alex
and Yehuda here).

In the following DOM

body id=3
div id=0/div
div id=context foo=bar
div id=1/div
div class=class id=2/div
div class=withChildren id=3div class=child id=4/div/div
/div
div id=5/div
div id=6/div
/body

What would each of the following .findAll calls return. I've
included my guessed based on the discussions so far:

var e = document.getElementById('context');

e.findAll(div)  // returns ids 1,2,3,4
e.findAll()  // returns an empty list
e.findAll(#3)  // returns id 3, but not the body node
e.findAll( div) // returns ids 1,2,3
e.findAll([foo=bar]) // returns nothing
e.findAll([id=1]) // returns id 1
e.findAll(:first-child) // returns id 1
e.findAll(+ div) // returns id 5
e.findAll(~ div) // returns id 5, 6
e.findAll(:scope)
e.findAll(div:scope)
e.findAll([foo=bar]:scope)
e.findAll(:scope div)
e.findAll(div:scope div)
e.findAll(div:scope #3)
e.findAll(body  :scope  div)
e.findAll(div, :scope)
e.findAll(body  :scope  div, :scope)
e.findAll(:not(:scope))

/ Jonas 







Re: QSA, the problem with :scope, and naming

2011-10-25 Thread Sean Hogan

On 26/10/11 7:51 AM, Tab Atkins Jr. wrote:

On Tue, Oct 25, 2011 at 1:47 PM, Sean Hoganshogu...@westnet.com.au  wrote:

I think allowing explicit :scope in findAll() will be perpetually confusing.
I can imagine someone looking at old code like:

 e.findAll(div.foo span, div.bar :scope span)

and asking themselves what's the rule again? If there's :scope in the
selector then there's no :scope implied? Or was that just on each single
selector? Or is :scope always implied at the start of the whole selector
list and that's why it's explicit in the second part? Dammit, why didn't we
just use querySelectorAll() if we wanted explicit :scope?

Using :scope explicitly at the beginning of selectors is necessary if
we want a sane way to have selector lists chain off of the scoping
element.  I'm okay with the string starting with a combinator when
it's a single selector like + foo, but not when it's a selector list
like + foo, + bar.

~TJ



I didn't follow that. Why does findAll() need to support explicit :scope?

It is simpler if querySelectorAll() supports explicit :scope and 
findAll() doesn't.

Plus it means findAll() matches how js libs currently work.

Sean




Re: QSA, the problem with :scope, and naming

2011-10-25 Thread Sean Hogan

On 26/10/11 9:28 AM, Tab Atkins Jr. wrote:

On Tue, Oct 25, 2011 at 2:33 PM, Sean Hoganshogu...@westnet.com.au  wrote:

On 26/10/11 7:51 AM, Tab Atkins Jr. wrote:

On Tue, Oct 25, 2011 at 1:47 PM, Sean Hoganshogu...@westnet.com.au
  wrote:

I think allowing explicit :scope in findAll() will be perpetually
confusing.
I can imagine someone looking at old code like:

 e.findAll(div.foo span, div.bar :scope span)

and asking themselves what's the rule again? If there's :scope in the
selector then there's no :scope implied? Or was that just on each single
selector? Or is :scope always implied at the start of the whole selector
list and that's why it's explicit in the second part? Dammit, why didn't
we
just use querySelectorAll() if we wanted explicit :scope?

Using :scope explicitly at the beginning of selectors is necessary if
we want a sane way to have selector lists chain off of the scoping
element.  I'm okay with the string starting with a combinator when
it's a single selector like + foo, but not when it's a selector list
like + foo, + bar.

I didn't follow that. Why does findAll() need to support explicit :scope?

Did you not understand my example?  el.find(+ foo, + bar) feels
really weird and I don't like it.  I'm okay with a single selector
starting with a combinator, like el.find(+ foo), but not a selector
list.


So +foo becomes :scope +foo
But +foo, +bar throws an error?
What about:
+foo, bar
:scope+foo, bar
body :scope+foo, :scope+bar

What do JS lib selectors do? Do any support :scope? Do any not support 
+foo, +bar, foo, bar?


Sean




Re: QSA, the problem with :scope, and naming

2011-10-25 Thread Sean Hogan

On 26/10/11 11:03 AM, Yehuda Katz wrote:
fwiw, jQuery doesn't properly handle the comma-separated case, but 
this is most definitely a bug, caused by the naïve implementation that 
Alex showed early on in this thread.




So no-one is actually using +foo, +bar? How common is +foo usage?

Sean




Re: QSA, the problem with :scope, and naming

2011-10-23 Thread Sean Hogan

On 23/10/11 5:44 AM, Timmy wrote:

On Oct 21, 2011, at 7:57 PM, Sean Hogan wrote:

It was definitely not a design flaw in QSA. As Alex's sample code shows it is 
possible to get findAll() behavior using QSA.

I think that further supports my argument.  JS libraries have commonly 
considered this to be an oversight in the design of QSA, hence the need for ID 
hack.  That is still true whether it was actually a design flaw or not.


To do the reverse would involve calling document.findAll() then filtering for 
nodes that are descendants of the invoking node.

I don't think anyone is interested in implementing the reverse in selector 
engines.  The most useful thing would be elem.findAll().  No manual filtering 
required.


rant
This sounds like:

Although X is more composable than Y, this is irrelevant because no-one 
would use X if Y is available.


This was the rationale used for removing matchesSelector() from the 
original Selectors API spec.


In my experience, when someone (me, for instance) or a committee or 
work-group can't think of a benefit of a more composable function it 
merely indicates a limited experience or imagination.


Once it has been decided that an API will be provided for a particular 
feature, the more primitive methods should be available by default. To 
*not* include them should require good reasons.


More specific methods should require use-cases and a rationale for why 
they shouldn't be composed from other methods.


Anyway, the use-case for element.querySelectorAll() - apart from being 
called from selector engines in js libs - is quite straight-forward.


Say I want to augment all elements in a page that match a given 
selector. After the page has loaded I can find all the elements by 
calling document.querySelectorAll(). When new content is added into the 
page I don't want to call document.querySelectorAll() and filter out 
already augmented elements. But if I only had element.findAll() then I 
might miss elements that match the selector because for findAll() the 
*whole* selector must match within the scope of element.


This is similar to the way jQuery.fn.delegate() works. One of the 
strengths of .delegate() is that it can handle events for elements that 
match the given selector even if the element wasn't in the document when 
delegate() was called. But .delegate() scopes selectors to the whole 
document, not the invoking nodes.

/rant


But if findAll() is implemented they can advertise that avoiding non-standard 
pseudo selectors gives virtually native performance (on supporting platforms). 
I imagine this would be almost equivalent to deprecating them, which would be a 
win.

This is extraneous.  The implementation of custom pseudo selectors would be 
identical.


Well, no-one can prevent JS libs implementing custom pseudo selectors, 
just as they can't be prevented from implementing custom DOM methods, 
e.g. HTMLElement.prototype.awesome().
But they both have the same negatives, most especially that if the 
method name / pseudo-selector name is one day implemented in browsers 
but with a different definition then code that was relying on the 
library will start receiving the different native behavior.


Of course, there are counter-arguments to the negatives. Never-the-less 
it is considered good practice (good web-citizenship if you like) to use 
vendor prefixes for custom methods and custom selectors.


Sean




Re: QSA, the problem with :scope, and naming

2011-10-21 Thread Sean Hogan

On 20/10/11 12:39 AM, Timmy Willison wrote:
From the perspective of building a selector engine, I think all 
selector engines need something like .findAll, and not something like 
:scope.


On Tue, Oct 18, 2011 at 8:00 PM, Alex Russell slightly...@google.com 
mailto:slightly...@google.com wrote:


No need to wait. We had something nearly identical for this in Dojo
using an ID prefix hack. It looked something like this:

   (function(){
   var ctr = 0;
   query = function(query, root){
   root = root||document;
   var rootIsDoc = (root.nodeType == 9);
   var doc = rootIsDoc ? root :
(root.ownerDocment||document);

   if(!rootIsDoc ||
(~+.indexOf(query.charAt(0)) = 0)){
   // Generate an ID prefix for the
selector
root.id http://root.id = root.id
http://root.id||(qUnique+(ctr++));
   query = #+root.id
http://root.id+ +query;
   }

   return Array.prototype.slice.call(
   doc.querySelectorAll(query)
   );
   };
   })();

This is exactly the same dance that :scope does.


Sizzle and Slick do the same thing. As far as I can tell, nwmatcher 
doesn't deal with it.  We can't just add :scope to all selections (for 
many reasons) and adding just before QSA would require the same logic 
that Alex has demonstrated above.


All of the selector engines do predictions at loadtime on whether QSA 
will work.  They continue differently beyond that, but one thing every 
library has in common is a try/catch around the call to QSA that falls 
back to manual parsing if it throws an exception (intentionally 
avoiding the need for complete parsing before calling QSA).  The point 
is it is a misconception that selector engines parse selectors before 
delegating to QSA. The number of things libraries want to do before 
getting to the QSA call is very minimal.  The one that hurts us all 
the most is this need for scoping and ':scope' would simply never be 
used in a selector engine, since the id trick already works 
everywhere.  The case Alex wrote above is pretty much the only case 
where the selector is parsed beyond checking for tag only, id only, or 
class only and it is due to what all of the js libraries has 
considered a design flaw in QSA.  A method like findAll would fix 
that, leaving as much parsing as possible in the hands of the browser.




It was definitely not a design flaw in QSA. As Alex's sample code shows 
it is possible to get findAll() behavior using QSA. To do the reverse 
would involve calling document.findAll() then filtering for nodes that 
are descendants of the invoking node.


Clearly JS libs aren't going to switch from implied :scope to explicit 
:scope.


But if findAll() is implemented they can advertise that avoiding 
non-standard pseudo selectors gives virtually native performance (on 
supporting platforms). I imagine this would be almost equivalent to 
deprecating them, which would be a win.


PS - I should say I don't necessarily think the name 'findAll' would 
work. I agree it should be short.  The equivalent of querySelector 
would be find and in library land 'find' selects more than one thing, 
but I'm not as concerned about the name.




Re: QSA, the problem with :scope, and naming

2011-10-20 Thread Sean Hogan

On 20/10/11 1:07 PM, Jonas Sicking wrote:

On Tue, Oct 18, 2011 at 9:42 AM, Alex Russellslightly...@google.com  wrote:

Lachlan and I have been having an...um...*spirited* twitter discussion
regarding querySelectorAll, the (deceased?) queryScopedSelectorAll,
and :scope. He asked me to continue here, so I'll try to keep it
short:

The rooted forms of querySelector and querySelectorAll are mis-designed.



I like the general idea here. And since we're changing behavior, I
think it's a good opportunity to come up with shorter names. Naming is
really hard. The shorter names we use, the more likely it is that
we're going to break webpages which are messing around with the
prototype chain and it increases the risk that we'll regret it later
when we come up with even better functions which should use those
names. Say that we come up with an even better query language than
selectors, at that point .find will simply not be available to us.

However, it does seem like selectors are here to stay. And as much as
they have shortcomings, people seem to really like them for querying.

So with that out of the way, I agree that the CSS working group
shouldn't be what is holding us back.


I don't agree with Selectors API supporting invalid selectors, but I 
guess the discussion is more appropriate here than there.



However we do need a precise
definition of what the new function does. Is prepending :scope  and
then parsing as a normal selector always going to give the behavior we
want? This is actually what I think we got stuck on when the original
querySelector was designed.

So let's get into specifics about how things should work. According to
your proposal of simply prepending a conceptual :scope to each
selector group, for the following DOM:

body id=3
   div id=context foo=bar
 div id=1/div
 div class=class id=2/div
 div class=withChildren id=3div class=child id=4/div/div
   /div
/body

you'd get the following behavior:

.findAll(div)  // returns ids 1,2,3,4
.findAll()  // returns the context node itself. This was
indicated undesirable
.findAll(body  :scope  div)  // returns nothing
.findAll(#3)  // returns id 3, but not the body node
.findAll(  div) // returns ids 1,2,3
.findAll([foo=bar]) // returns nothing
.findAll([id=1]) // returns id 1
.findAll(:first-child) // returns id 1

Is this desired behavior in all cases except the empty string? If so
this seems very doable to me. We can easily make an exception for the
case when the passed in string contains no selectors and make that an
error or some such.


I know everyone knows this, but...

These specific examples (where the selector is not a comma separated 
list) plus most instances of selector lists (e.g. th, td,  ul  li, 
 ol  li) can be trivially supported by a tiny wrapper around 
querySelectorAll() as defined in Selectors API v2. In fact, I've never 
seen a selector list that couldn't be successfully split on , and I 
wouldn't be surprised if they are never used outside of stylesheets.



I do however like the idea that if :scope appears in the selector,
then this removes the prepending of :scope  to that selector group.
Is there a reason not to do that?


1. Already supported (in the draft spec) by querySelectorAll().
2. Not supported by JS libs.
3. No use cases requiring it.


Additionally it seems to me that we could allow the same syntax for
style scoped. But maybe others disagree?


Surely it is both or neither. You don't want to set a precedent for DOM 
selectors not matching CSS selectors.



I think appropriate optimizations as well as extensible functions
should be out-of-scope for this thread. They are both big subjects on
their own and we're approaching 50 emails in this thread.






Re: QSA, the problem with :scope, and naming

2011-10-20 Thread Sean Hogan

On 20/10/11 5:41 PM, Jonas Sicking wrote:

On Wed, Oct 19, 2011 at 11:14 PM, Sean Hoganshogu...@westnet.com.au  wrote:

I do however like the idea that if :scope appears in the selector,
then this removes the prepending of :scope  to that selector group.
Is there a reason not to do that?

1. Already supported (in the draft spec) by querySelectorAll().
2. Not supported by JS libs.
3. No use cases requiring it.

It's annoying if querying engines have to work with two different
query methods (.findAll and .querySelectorAll) and know when to call
which. So I don't think 1 is a particularly good point.


I don't follow that.
If you want style scoped behavior you call findAll().
If not you call querySelectorAll().

Sean




Re: QSA, the problem with :scope, and naming

2011-10-20 Thread Sean Hogan

On 20/10/11 1:07 PM, Jonas Sicking wrote:

On Tue, Oct 18, 2011 at 9:42 AM, Alex Russellslightly...@google.com  wrote:

Lachlan and I have been having an...um...*spirited* twitter discussion
regarding querySelectorAll, the (deceased?) queryScopedSelectorAll,
and :scope. He asked me to continue here, so I'll try to keep it
short:

The rooted forms of querySelector and querySelectorAll are mis-designed.



  I'd like to instead propose that we
shorten all of this up and kill both stones by introducing a new API
pair, find and findAll, that are rooted as JS devs expect. The
above becomes:

   element.findAll(  div  .thinger);


I like the general idea here.

I think appropriate optimizations as well as extensible functions
should be out-of-scope for this thread. They are both big subjects on
their own and we're approaching 50 emails in this thread.


If find / findAll are added to the spec there should also be an 
equivalent of matchesSelector that handles implicitly scoped selector, 
e.g.  div  .thinger. To aid discussion I will call this matches(), 
but I don't think it is a good final choice.


The primary use-case for matchesSelector() has been event-delegation, 
and this is the same for matches(). More specifically, consider the 
following scenario:


jQuery adds a new event registration method that uses event delegation 
to mimic the behavior of:

$(elem).find( div  .thinger).bind(eventType, fn);
The new method is called proxybind(), and the equivalent of the above is:
$(elem).proxybind( div  .thinger, eventType, fn);

The event handling for proxybind() would invoke matches( div  
.thinger, [elem]) on elements between the event target and elem to find 
matching elements.


Sean




Re: QSA, the problem with :scope, and naming

2011-10-20 Thread Sean Hogan

On 20/10/11 7:32 PM, Jonas Sicking wrote:

On Thu, Oct 20, 2011 at 1:14 AM, Sean Hoganshogu...@westnet.com.au  wrote:

On 20/10/11 1:07 PM, Jonas Sicking wrote:

On Tue, Oct 18, 2011 at 9:42 AM, Alex Russellslightly...@google.com
  wrote:

Lachlan and I have been having an...um...*spirited* twitter discussion
regarding querySelectorAll, the (deceased?) queryScopedSelectorAll,
and :scope. He asked me to continue here, so I'll try to keep it
short:

The rooted forms of querySelector and querySelectorAll are
mis-designed.
  I'd like to instead propose that we
shorten all of this up and kill both stones by introducing a new API
pair, find and findAll, that are rooted as JS devs expect. The
above becomes:

   element.findAll(div.thinger);


I like the general idea here.

I think appropriate optimizations as well as extensible functions
should be out-of-scope for this thread. They are both big subjects on
their own and we're approaching 50 emails in this thread.

If find / findAll are added to the spec there should also be an equivalent
of matchesSelector that handles implicitly scoped selector, e.g.   div
.thinger. To aid discussion I will call this matches(), but I don't think
it is a good final choice.

How would .matches() work? For .findAll we basically prepend a :scope
 selector step where the :scope pseudo-class matches the element on
which .findAll was called.

If we did the same for .matches() then

elem.matches(foo)

would try to match elem against the selector :scope foo where
:scope only matches elem and thus the selector only matches elements
which are descendants of the element on which .matches() was called.

In other words, .matches() would never match anything.

Clearly you must have some other behavior in mind as a function which
always returns false isn't particularly interesting.

/ Jonas


See the definition of matchesSelector(selector, [ refNodes ]) in the spec:
http://www.w3.org/TR/selectors-api2/#matchtesting




Re: QSA, the problem with :scope, and naming

2011-10-20 Thread Sean Hogan

On 20/10/11 8:42 PM, Lachlan Hunt wrote:

On 2011-10-20 10:14, Sean Hogan wrote:

The primary use-case for matchesSelector() has been event-delegation,
and this is the same for matches(). More specifically, consider the
following scenario:

jQuery adds a new event registration method that uses event delegation
to mimic the behavior of:
$(elem).find( div  .thinger).bind(eventType, fn);
The new method is called proxybind(), and the equivalent of the above 
is:

$(elem).proxybind( div  .thinger, eventType, fn);

The event handling for proxybind() would invoke matches( div 
.thinger, [elem]) on elements between the event target and elem to find
matching elements.


It may not be too late to introduce that behaviour into 
matchesSelector, with a switch based on the presence or absence of the 
refNodes/refElement parameter.


As currently specified, calling the following doesn't and shouldn't 
prepend :scope.


  el.matchesSelector(div .foo);

This one also matches the prefixed implementations in browsers, since 
most haven't started supporting :scope yet, and I don't believe 
Mozilla's experimental implementation [1] has landed yet.


As currently specified, calling this:

  el.matchesSelector(div .foo, ref);

Also doesn't prepend :scope automatically, but in that case, the ref 
nodes do nothing useful. 


But this selector can still match elements. Admittedly I can't think of 
a use-case for this, but it is conceivable for someone to expect this to 
work without an implied :scope.


Authors have to use :scope explicitly for them to be useful as in 
something like:


  el.matchesSelector(:scope div .foo, ref);

Or

  el.matchesSelector(div:scope .foo, ref);

One thing we could possibly do is define that if ref nodes are passed, 
and the selector doesn't explicitly use :scope, then effectively 
prepend :scope .  This would be exactly the same behaviour as that 
discussed for .findAll();


That wouldn't break compatibility with anything, optimises for a 
common case and avoids introducing two separate match methods.




I don't see the need for findAll(), but if it is added I think it should 
always imply :scope  at the start of a selector, and I think a 
separate match method that does the same should be added. To do 
otherwise seems too ambiguous for a DOM API.



e.g.
el.matchesSelector(div .foo); // No ref, no magic :scope

el.matchesSelector(div .foo, ref);// Implied, magic :scope
el.matchesSelector(+.foo, ref);   // Implied, magic :scope

el.matchesSelector(:scope div .foo, ref); // Explicit, no magic :scope
el.matchesSelector(div:scope .foo, ref);  // Explicit, no magic :scope

[1] https://bugzilla.mozilla.org/show_bug.cgi?id=648722






Re: QSA, the problem with :scope, and naming

2011-10-20 Thread Sean Hogan

On 20/10/11 10:05 PM, Lachlan Hunt wrote:

On 2011-10-20 12:50, Alex Russell wrote:

On Thu, Oct 20, 2011 at 6:55 AM, Jonas Sickingjo...@sicking.cc  wrote:

Oh, and as a separate issue. I think .findAll should return a plain
old JS Array. Not a NodeList or any other type of host object.


I strongly agree that it should be an Array *type*, but I think just
returning a plain Array is the wrong resolution to our NodeList
problem. WebIDL should specify that DOM List types *are* Array types.


We need NodeList separate from Array where they are live lists.  I 
forget the reason we originally opted for a static NodeList rather 
than Array when this issue was originally discussed a few years ago.




I wonder if anyone is relying on querySelectorAll() returning a 
StaticNodeList?





Re: QSA, the problem with :scope, and naming

2011-10-20 Thread Sean Hogan

On 20/10/11 10:49 PM, Lachlan Hunt wrote:

On 2011-10-20 13:35, Sean Hogan wrote:

I wonder if anyone is relying on querySelectorAll() returning a
StaticNodeList?


Only if there are people out there using list.item(n) instead of 
list[n], or people extending the NodeList interface and expecting such 
methods to be available on the result.  Though I suspect the former is 
very rare, and the latter doesn't work in all browsers.




And I wonder if one of the browser vendors would be willing to silently 
change the behavior and see if they get any bug reports.





Re: QSA, the problem with :scope, and naming

2011-10-19 Thread Sean Hogan

On 19/10/11 2:39 PM, Ojan Vafai wrote:

Overall, I wholeheartedly support the proposal.

I don't really see the benefit of allowing starting with a combinator. 
I think it's a rare case that you actually care about the scope 
element and in those cases, using :scope is fine. Instead of 
element.findAll( div  .thinger), you use element.findAll(:scope  
div  .thinger). That said, I don't object to considering the :scope 
implied if the selector starts with a combinator.




I can think of two reasons one might ponder allowing :scope to be explicit.

1. so that the selector string can be a valid CSS selector string. 
(:scopediv.thinger instead of div.thinger). But if this is 
important then :scope should always be explicit, in which case we can 
just use querySelectorAll().


2. to allow break-out behavior. e.g.

div.findAll(body div span); // finds nothing
div.findAll(body div:scope span); // finds span's that are descendants 
of div


In this scenario, the :scope pseudo allows ancestors of div to be 
matched against. (No-one would use body in this context, but it is easy 
to imagine them using a .class selector which matches an ancestor of div.)


But if you want break-out behavior you might not know which part of the 
selector to put the :scope pseudo on. Could it be:

body div:scope span
body *:scope div span
body div *:scope span

So for break-out behavior just use querySelectorAll().

I'm pretty sure previous discussions (before this thread) have covered 
this more thoroughly, and shown that it has to be all or nothing with 
the :scope pseudo-attribute. That is, either

a) :scope MUST be explicit, in which case just use querySelectorAll()
b) :scope MUST be implied at the start of every selector chain.

Sean



Re: QSA, the problem with :scope, and naming

2011-10-18 Thread Sean Hogan

On 19/10/11 7:20 AM, Yehuda Katz wrote:

I agree entirely.

I have asked a number of practitioner friends about this scenario:

div id=parent
p id=childspan id=inlineContent/span/p
/div

  document.getElementById(child).querySelectorAll(div span); // 
returns #inline


In 100% of cases, people consider this behavior *broken*. Not just 
interesting, I wouldn't have expected that, but who came up with 
that!?. In all cases involving JavaScript practitioners, people 
expect querySelectorAll to operate on the element as though the 
element was the root of a new document, and where combinators are 
relative to the element.




It matches the definition of CSS selectors, so I don't think it can be 
called broken. For this case, node.querySelectorAll(div span) finds 
all span's (in document order) which are contained within the invoking 
node and checks that they match the selector expression, in this case 
simply checking they are a descendant of a div.


The new definition being promoted is:
- start at the containing node
- find all descendant div's
- for every div, find all descendant span's.
- with the list of span's, remove duplicates and place in document-order

Once you understand the proper definition it is hard to see this new 
definition as more logical.
To me, the problem here is some (not all) Javascript practitioners not 
learning the proper definition of CSS selectors.


We already knew this was true since all JavaScript libraries that 
implement selectors implemented them in this way.




To me, this indicates that there's no problem here. If you want to use 
an alternative definition of selectors then you use a JS lib that 
supports them. If you want to use the DOM API then you learn how CSS 
selectors work.


I don't see JS libs ever calling the browsers querySelectorAll (or even 
a new findAll) without parsing the selector string first because:

- JS libs support selectors that haven't been implemented on all browsers
- JS libs support selectors that are never going to be part of the standard

Since JS libs will always parse selector strings and call qSA, etc as 
appropriate, I can't see much benefit in creating DOM methods that 
accept non-standard selector strings.


Sean




Re: QSA, the problem with :scope, and naming

2011-10-18 Thread Sean Hogan

On 19/10/11 10:58 AM, Tab Atkins Jr. wrote:

On Tue, Oct 18, 2011 at 4:46 PM, Sean Hoganshogu...@westnet.com.au  wrote:

On 19/10/11 7:20 AM, Yehuda Katz wrote:

I agree entirely.

I have asked a number of practitioner friends about this scenario:

div id=parent
p id=childspan id=inlineContent/span/p
/div

  document.getElementById(child).querySelectorAll(div span); // returns
#inline

In 100% of cases, people consider this behavior *broken*. Not just
interesting, I wouldn't have expected that, but who came up with that!?.
In all cases involving JavaScript practitioners, people expect
querySelectorAll to operate on the element as though the element was the
root of a new document, and where combinators are relative to the element.


It matches the definition of CSS selectors, so I don't think it can be
called broken. For this case, node.querySelectorAll(div span) finds all
span's (in document order) which are contained within the invoking node and
checks that they match the selector expression, in this case simply checking
they are a descendant of a div.

The new definition being promoted is:
- start at the containing node
- find all descendant div's
- for every div, find all descendant span's.
- with the list of span's, remove duplicates and place in document-order

Once you understand the proper definition it is hard to see this new
definition as more logical.
To me, the problem here is some (not all) Javascript practitioners not
learning the proper definition of CSS selectors.

Not at all.  I'm not sure why you think this is somehow an improper
way to think about things.

There are two ways you can scope a selector.  The first is to filter
the results of a selector match to only those under a certain element
(what QSA does today).  The second is to scope the entire selector to
only apply underneath the scoping element, which is what Alex is
proposing.

An alternative view of this is that current QSA restricts the final
compound selector in a selector to match only elements in the scope,
while allowing the rest of the selector to match elements anywhere in
the document.  Alex's proposal (and every other JS selector engine)
restricts all of the selector component to matching only elements in
the scope.

There is nothing unnatural or improper about this.  The fact that
every JS selector engine works in the latter fashion, and that JS devs
are regularly surprised by the former behavior, suggests strongly that
the latter behavior is the better default behavior.

Based on discussion on the mailing list,style scoped  will be
changing to the latter behavior as well, with the ability to invoke
the former behavior in the rare circumstances when you explicitly want
it.


If it becomes part of the standard definition of CSS selectors then it 
can be supported by a query method. At that point the only discussion is 
for the name.


However, in reading that thread I don't see any mention of selectors 
such as  div  span. Did I miss something?


Sean




Re: Mutation Observers: a replacement for DOM Mutation Events

2011-10-13 Thread Sean Hogan

On 13/10/11 2:33 PM, Ryosuke Niwa wrote:
On Wed, Oct 12, 2011 at 8:14 PM, Sean Hogan shogu...@westnet.com.au 
mailto:shogu...@westnet.com.au wrote:


Maybe you can provide concrete examples (i.e. with code snippets,
actual instances of use cases, etc...)


Actually, it is the proponents of changing the status-quo and of
the more complex solution who bear more responsibility for
providing these. But if it helps, here's a specific example:

MathJax (http://mathjax.org) is a js lib for rendering math in
web-pages. One feature it provides is converting LaTeX into
(typically) a HTML representation of the math. It is desirable for
the LaTeX source to remain available in the document, and MathJax
stores it as the content of a script type=math/tex element.
MathJax provides an API for changing the LaTeX source and thus the
rendered output.

It might be desirable if MathJax could update the rendering
automatically in response to changes in the script content.
Mutation events would be necessary for this. But what is the
appropriate way to signal to other consumers of mutation events
that the math rendering changes are to be ignored?


Why do you assume that all other mutation observers should ignore such 
changes? If there's a library that's automatically syncing the 
document with a server, then such an observer certainly needs to know 
any mutations that happen in the document.


- Ryosuke



In the case of MathJax, the HTML rendering for math is generated in the 
browser. It is only the LaTeX that you would want synced on the server.


However, my main concern (which I probably haven't emphasized 
sufficiently) is that the current proposal is more complex than 
absolutely necessary. Therefore

- it will be complex to implement
- it is easy to imagine that the preliminary analysis has missed 
problems, and
- it still doesn't allow different mutation event listeners to safely 
ignore the possibility of each-other.


My concerns may be unreasonable. Given there is an implementation just 
around the corner, we'll soon have a better idea, rather than just 
speculating.


Sean



Re: Mutation Observers: a replacement for DOM Mutation Events

2011-10-13 Thread Sean Hogan

On 13/10/11 7:58 PM, Ryosuke Niwa wrote:


On Thu, Oct 13, 2011 at 1:32 AM, Sean Hogan shogu...@westnet.com.au 
mailto:shogu...@westnet.com.au wrote:



Why do you assume that all other mutation observers should ignore
such changes? If there's a library that's automatically syncing
the document with a server, then such an observer certainly needs
to know any mutations that happen in the document.

- Ryosuke



In the case of MathJax, the HTML rendering for math is generated
in the browser. It is only the LaTeX that you would want synced on
the server.


No, my use case addresses the case where you want to mirror the exact 
DOM state (except event handlers and script elements) elsewhere. And 
for that to work, I need to be able to see whatever MathJax is 
generating, NOT the LaTeX code.


For that use case I think you would be happy with my proposal which 
doesn't implement any filtering of mutation events at all.


By the way, I'm not arguing that the mutation observers proposal should 
provide a mechanism for hiding some mutations. I'm arguing that whatever 
solution is provided (even a complex one) still won't make mutation 
handling straight-forward... so why not just provide the simplest 
solution and let the js libs sort out the details.


Sean



Re: Mutation Observers: a replacement for DOM Mutation Events

2011-10-12 Thread Sean Hogan

On 12/10/11 3:26 AM, Tab Atkins Jr. wrote:

On Mon, Oct 10, 2011 at 7:51 PM, Sean Hoganshogu...@westnet.com.au  wrote:

On 24/09/11 7:16 AM, Adam Klein wrote:

- Is free of the faults of the existing Mutation Events mechanism
(enumerated in detail here:
http://lists.w3.org/Archives/Public/public-webapps/2011JulSep/0779.html)

A simpler solution that is free from the faults listed in that email would
be to have (at max) one mutation observer for the whole page context. I
guess this would be called at the end of the task or immediately before page
reflows.

If a js lib (or multiple libs) want to provide finer grained mutation
handling then let them work out the details.

That seems unworkably restrictive.  It's very easy to imagine multiple
libraries listening for different kinds of things at the same time.
Libraries would just end up re-implementing event distribution, which
is something we can avoid by doing it correctly now.


This proposal doesn't entirely avoid the issue of event distribution. 
There is no equivalent of event.stopPropagation() and hence no way to 
prevent mutation records being delivered to observers. The observers may 
have to be written with this is in mind.


For example, what if two observers can potentially handle the same 
mutation - which one should handle it?


Alternatively, some code might respond to an attribute by adding content 
to the DOM. What if there are mutation listeners that could respond to 
that added content? Is it desired that they ignore or handle it?


Another pattern that doesn't seem to be reliably handled is mutations 
within DOM fragments that are temporarily removed from the document. 
That is:
- if the fragment always remains in the document then all mutations can 
be monitored by observers on the document (or document.body), but
- if the fragment is removed from the document followed by mutation 
observers being called, then  any further mutations won't be delivered 
to the observers, even when the fragment is reinserted into the document.


The exact behavior in this scenario depends on whether mutations 
complete within one microtask or more than one


Sean.





Re: Mutation Observers: a replacement for DOM Mutation Events

2011-10-12 Thread Sean Hogan

On 13/10/11 12:34 AM, Olli Pettay wrote:

On 10/12/2011 02:00 PM, Sean Hogan wrote:

On 12/10/11 3:26 AM, Tab Atkins Jr. wrote:

On Mon, Oct 10, 2011 at 7:51 PM, Sean Hoganshogu...@westnet.com.au
wrote:

On 24/09/11 7:16 AM, Adam Klein wrote:

- Is free of the faults of the existing Mutation Events mechanism
(enumerated in detail here:
http://lists.w3.org/Archives/Public/public-webapps/2011JulSep/0779.html) 




A simpler solution that is free from the faults listed in that email
would
be to have (at max) one mutation observer for the whole page 
context. I

guess this would be called at the end of the task or immediately
before page
reflows.

If a js lib (or multiple libs) want to provide finer grained mutation
handling then let them work out the details.

That seems unworkably restrictive. It's very easy to imagine multiple
libraries listening for different kinds of things at the same time.
Libraries would just end up re-implementing event distribution, which
is something we can avoid by doing it correctly now.


This proposal doesn't entirely avoid the issue of event distribution.
There is no equivalent of event.stopPropagation() and hence no way to
prevent mutation records being delivered to observers. The observers may
have to be written with this is in mind.

For example, what if two observers can potentially handle the same
mutation - which one should handle it?
Both. Or the observers need to somehow communicate with each others to 
decide who handles it. This is no different to event listeners.
Event listeners don't know if there are other listeners before them or 
after them. You can have several listeners in the same target and 
different script libraries may have added them without knowing about 
each others.




It is different to event listeners. The following

document.body.addEventListener(DOMAttrModified, handler, false);

document.getElementById(target).addEventListener(DOMAttrModified, 
preferred_handler, false);


allows preferred_handler to prevent handler receiving the event. The 
observer solution (something like):


handler_observer.observe(document.body, ...);

preferred_handler_observer.observe(document.getElementById(target), ...);


does not.

My argument may be weak, but you don't help this discussion by providing 
an even weaker argument to counter it.







Alternatively, some code might respond to an attribute by adding content
to the DOM. What if there are mutation listeners that could respond to
that added content? Is it desired that they ignore or handle it?

Another pattern that doesn't seem to be reliably handled is mutations
within DOM fragments that are temporarily removed from the document.
That is:
- if the fragment always remains in the document then all mutations can
be monitored by observers on the document (or document.body), but
- if the fragment is removed from the document followed by mutation
observers being called, then any further mutations won't be delivered to
the observers, even when the fragment is reinserted into the document.


 The exact behavior in this scenario depends on whether mutations
 complete within one microtask or more than one

If the modifications to the fragment are done during the same 
microtask, then the observer will just get notified about those 
modifications. If in different microtask, then observer should observe
that fragment (so when the fragment is removed from document, 
observer.observe(root_of_fragement, options) should be called.).


If there was just a global - per document observers, those wouldn't
handle all the cases when node is adopted to and from other documents.


I didn't think of that but I don't think it's a good idea anyway. If 
observing mutations in another document is required then use their per 
document observer. Or have I missed something?



Also, such observers would make all the DOM mutations slower, since
the callback would need to be called all the time.



Yes, but you have to remember that many DOM mutations necessitate page 
reflow, and the cost of mutation listeners has to be weighed against 
that, not the execution time of one DOM operation.


In the extreme case, per document observers won't be any slower than

observer.observe(document, all_options);


The proposed API allows one to restrict mutation observing to certain 
set of nodes. Mutations outside that set can be kept as fast as having 
no mutationobservers at all.
And also, since the observed set can expand, and isn't limited to same 
document handling, it can easily handle cases when nodes are moved to 
some other document.




My main reservation towards the proposal is its complexity - it promises 
a lot and I will be surprised if it is as trivial to implement as you 
have implied. Even then, I'm expecting that it isn't the improvement 
(over the status-quo) that everyone is speculating. It's great that 
there is going to be an implementation real-soon-now so that my concerns 
can be allayed / confirmed

Re: Mutation Observers: a replacement for DOM Mutation Events

2011-10-12 Thread Sean Hogan

On 13/10/11 4:50 AM, Rafael Weinstein wrote:

Hi Sean,

I find it hard to reason about cases in the abstract. None of the
examples you list seem concerning to me (i.e. I believe they can be
properly handled), but perhaps it's a failure of my imagination.


I didn't say they can't be properly handled. I said that the proposal by 
itself doesn't properly handle them, and I suggested a similar but 
simpler solution that also doesn't properly handle them by itself.


Another way of phrasing this deficiency is that the proposal provides a 
way to signal interest in mutations in regions of a page, but doesn't 
provide a way to ignore mutations within those regions. So the libs 
using this API may have to provide their own mechanism for this.



Maybe you can provide concrete examples (i.e. with code snippets,
actual instances of use cases, etc...)


Actually, it is the proponents of changing the status-quo and of the 
more complex solution who bear more responsibility for providing these. 
But if it helps, here's a specific example:


MathJax (http://mathjax.org) is a js lib for rendering math in 
web-pages. One feature it provides is converting LaTeX into (typically) 
a HTML representation of the math. It is desirable for the LaTeX source 
to remain available in the document, and MathJax stores it as the 
content of a script type=math/tex element. MathJax provides an API 
for changing the LaTeX source and thus the rendered output.


It might be desirable if MathJax could update the rendering 
automatically in response to changes in the script content. Mutation 
events would be necessary for this. But what is the appropriate way to 
signal to other consumers of mutation events that the math rendering 
changes are to be ignored?





On Wed, Oct 12, 2011 at 4:00 AM, Sean Hoganshogu...@westnet.com.au  wrote:

On 12/10/11 3:26 AM, Tab Atkins Jr. wrote:

On Mon, Oct 10, 2011 at 7:51 PM, Sean Hoganshogu...@westnet.com.au
  wrote:

On 24/09/11 7:16 AM, Adam Klein wrote:

- Is free of the faults of the existing Mutation Events mechanism
(enumerated in detail here:
http://lists.w3.org/Archives/Public/public-webapps/2011JulSep/0779.html)

A simpler solution that is free from the faults listed in that email
would
be to have (at max) one mutation observer for the whole page context. I
guess this would be called at the end of the task or immediately before
page
reflows.

If a js lib (or multiple libs) want to provide finer grained mutation
handling then let them work out the details.

That seems unworkably restrictive.  It's very easy to imagine multiple
libraries listening for different kinds of things at the same time.
Libraries would just end up re-implementing event distribution, which
is something we can avoid by doing it correctly now.

This proposal doesn't entirely avoid the issue of event distribution. There
is no equivalent of event.stopPropagation() and hence no way to prevent
mutation records being delivered to observers. The observers may have to be
written with this is in mind.

For example, what if two observers can potentially handle the same mutation
- which one should handle it?

Alternatively, some code might respond to an attribute by adding content to
the DOM. What if there are mutation listeners that could respond to that
added content? Is it desired that they ignore or handle it?

Another pattern that doesn't seem to be reliably handled is mutations within
DOM fragments that are temporarily removed from the document. That is:
- if the fragment always remains in the document then all mutations can be
monitored by observers on the document (or document.body), but
- if the fragment is removed from the document followed by mutation
observers being called, then  any further mutations won't be delivered to
the observers, even when the fragment is reinserted into the document.

The exact behavior in this scenario depends on whether mutations complete
within one microtask or more than one

Sean.








Re: Mutation Observers: a replacement for DOM Mutation Events

2011-10-10 Thread Sean Hogan

On 24/09/11 7:16 AM, Adam Klein wrote:

Chromium (myself, Rafael Weinstein, Erik Arvidsson, Ryosuke Niwa) and
Mozilla (Olli Pettay, Jonas Sicking) have worked together on a
proposal for a replacement for Mutation Events.

This proposal represents our best attempt to date at making a set of
sensible trade offs which allows for a new mutation observation
mechanism that:

- Is free of the faults of the existing Mutation Events mechanism
(enumerated in detail here:
http://lists.w3.org/Archives/Public/public-webapps/2011JulSep/0779.html)


A simpler solution that is free from the faults listed in that email 
would be to have (at max) one mutation observer for the whole page 
context. I guess this would be called at the end of the task or 
immediately before page reflows.


If a js lib (or multiple libs) want to provide finer grained mutation 
handling then let them work out the details.


Sean




Re: [DOM4] Remove Node.isSameNode

2011-09-09 Thread Sean Hogan

On 10/09/11 3:21 AM, Jonas Sicking wrote:

It's a completely useless function. It just implements the equality
operator. I believe most languages have a equality operator already.
Except Brainfuck [1]. But the DOM isn't implementable in Brainfuck
anyway as it doesn't have objects, so I'm ok with that.

[1] http://en.wikipedia.org/wiki/Brainfuck

/ Jonas




If a DOM implementation returns  node-wrappers instead of exposing the 
actual nodes then you could end up with different node-refs for the same 
node. I'm not sure whether that violates other requirements of the spec.






Re: [DOM4] Remove Node.isSameNode

2011-09-09 Thread Sean Hogan

On 10/09/11 11:00 AM, Jonas Sicking wrote:

On Fri, Sep 9, 2011 at 2:27 PM, Sean Hoganshogu...@westnet.com.au  wrote:

On 10/09/11 3:21 AM, Jonas Sicking wrote:

It's a completely useless function. It just implements the equality
operator. I believe most languages have a equality operator already.
Except Brainfuck [1]. But the DOM isn't implementable in Brainfuck
anyway as it doesn't have objects, so I'm ok with that.

[1] http://en.wikipedia.org/wiki/Brainfuck

If a DOM implementation returns  node-wrappers instead of exposing the
actual nodes then you could end up with different node-refs for the same
node. I'm not sure whether that violates other requirements of the spec.

I would expect that to violate the DOM spec. I.e. I would say that if
an implementation returned true for

someNode.firstChild != someNode.firstChild

then I would say that that that shouldn't be allowed by the DOM.

/ Jonas

The other scenario I can think of is casting. What if I want an object 
that only implements the Element interface of an element, even if it is 
a HTMLInputElement? The two objects will not be equal, but will 
represent the same node. I imagine that was the motivation for initially 
including the method.


Having said that, if no-one is using it then it is completely useless.

Sean




Re: HTMLElement.register--giving components tag names

2011-09-06 Thread Sean Hogan

On 7/09/11 7:20 AM, Alex Russell wrote:

On Sat, Sep 3, 2011 at 8:20 PM, Ian Hicksoni...@hixie.ch  wrote:

On Sat, 3 Sep 2011, Dominic Cooney wrote:

I think the XBL approach is far superior here -- have authors use
existing elements, and use XBL to augment them. For example, if you
want the user to select a country from a map, you can use aselect
with a list of countries inoption  elements in the markup, but then
use CSS/XBL to bind thatselect  to a component that instead makes
theselect  look like a map, with all the interactivity that implies.

That sounds appealing, but it looks really hard to implement from where
we right now.

I don't think it's hard is a good reason to adopt an inferior solution,

Likewise, intimating that something is better because it's hard is a
distraction.


especially given that this is something that will dramatically impact the
Web for decades to come.

The more complex the thing, the more we're saddled with. XBL(2) is
more complex than the proposed model. It likewise needs to be
justified all the more.


I agree that XBL2 may have been too ambitious for it's time.

I would say that the simplest thing that would be useful would be:
a) provide a bare-bones shadow DOM
b) implement something like the NodeWatcher proposal - 
http://www.w3.org/2008/webapps/wiki/MutationReplacement#NodeWatch_.28A_Microsoft_Proposal.29


These features are independently useful and would facilitate Javascript 
library solutions similar to both HTMLElement.register and XBL2.


Then step back and see what the Javascript guys do with it. The next 
step might write itself.


Sean




Re: Custom tags over wire, was Re: HTMLElement.register--giving components tag names

2011-09-04 Thread Sean Hogan

On 3/09/11 4:47 AM, Dimitri Glazkov wrote:

On Fri, Sep 2, 2011 at 2:30 AM, Anne van Kesterenann...@opera.com  wrote:

Examples of elements that should not be replaced but could be changed by a
binding: Having a sortable binding fortable; Exposing cite= on
blockquote; Turning aselect  listing countries into a map.

Great! Let's go through them:

* Sortable binding for a table is really just a table subclass with
some event listeners registered.

* Exposing cite on blockquote sounds like something CSS should do.
There's no extra behavior, and you're not really creating a new type
of element. It's just extra boxes.

* Turning select listing countries into a map -- composition to the rescue!:

x-country-map
select
   optionLilliput
   optionBlefuscu
/select
/x-country-map

 From the author's perspective, you don't actually need the select
element. If you intend to show a map on cool browsers and select on
the less cool ones, you are completely uninterested in having your
select semantics dutifully reproduced. All you need is something that
does what you need. Besides, the behavior of a map and a select are so
different than you probably would scrap the former to build the latter
anyway.


The author wants the select element so that form submission works.

The semantics of select are also quite useful as you might want the 
country-map widget to allow multiple selections, have a default selected 
country, and have a non-comprehensive list of countries to choose from.


As you have indicated, the user needs the select element as the fallback 
presentation.


It would also be useful if user stylesheets could override the behavior 
chosen by the author - either reverting to a browser select widget, or 
something provided by a browser add-on. This capability depends on there 
being a defacto standard for applying the country-map behavior. Which do 
you think would take on more quickly:

a) custom tag-names, or
b) aria or data attributes
I'm almost certain it's b.

My personal opinion is that most of the perceived need for custom 
tag-names is to put presentation into HTML. Kind of like font and 
center but without the benefit of being standards (de facto or de jure).


Sean







Re: More use-cases for mutation events replacement

2011-07-25 Thread Sean Hogan

On 25/07/11 2:18 AM, Aryeh Gregor wrote:

When discussing mutation events use-cases, mostly so far people have
been talking about editors.  However, I think mutation event
replacements would have a much more general appeal if they were easily
usable in certain cases with little performance impact.  Specifically,
one use-case I've run into a lot is I want to modify some class of
node soon after it gets added to the DOM, but before it's actually
painted.  Examples of where this has come up for me in practice:

snip

What would solve all of these use-cases is a way to register a handler
that would get notified every time an element is added to the DOM that
matches a particular CSS selector, which is guaranteed to run at some
point before the element is actually painted.  Thus it could be a
special type of event that runs when the event loop spins *before*
there's any opportunity to paint, or it could be semi-synchronous, or
whatever, as long as it runs before paint.  Then I could easily solve
all the use-cases:

snip

It seems to me this dovetails pretty nicely with some of the proposed
mutation events replacement APIs.  Specifically, people have been
talking about allowing filtering of events, so this use-case should be
solved easily enough if you can use CSS selectors as filters.  In that
case, the perf hit from using such events should be negligible, right?



I assume you are referring to the NodeWatch proposal from Microsoft.

1st draft:
http://www.w3.org/2008/webapps/wiki/Selector-based_Mutation_Events

2nd draft:

http://www.w3.org/2008/webapps/wiki/MutationReplacement#NodeWatch_.28A_Microsoft_Proposal.29



I think the utility of this proposal is unnecessarily limited by the 
restriction of one watcher per node.
Also, it is not clear that handlers would be called before page reflow / 
repaint.
If these issues were resolved, then this feature plus some shadow DOM 
capabilities would facilitate a performant JS implementation of 
(something approaching) XBL2.






Re: Mutation events replacement

2011-07-20 Thread Sean Hogan

On 21/07/11 6:18 AM, David Flanagan wrote:

On 7/20/11 12:11 PM, Ryosuke Niwa wrote:
On Wed, Jul 20, 2011 at 11:56 AM, Aryeh Gregor 
simetrical+...@gmail.com mailto:simetrical%2b...@gmail.com wrote:


On Wed, Jul 20, 2011 at 1:43 AM, David Flanagan
dflana...@mozilla.com mailto:dflana...@mozilla.com wrote:
 Finally, I still think it is worth thinking about trying to
model the
 distinction between removing nodes from the document tree and
moving them
 (atomically) within the tree.

I'll chip in that I think this is useful.  It makes things somewhat
more complicated, but remove/insert and move are conceptually very
different.


But internally, a node movement is a removal then an insertion. 
 There's always possibility that a node gets removed then inserted 
again after mutation observers are invoked.  Also, what happens if a 
function removed a bunch of nodes and then inserted back one of them?


My definition of moving a node atomically is taking a node that is 
already in the tree and passing it to appendChild() or 
insertBefore().  Everything else is regular node removal followed by 
node insertion.


If you get a mutation event that says that node A was removed from 
node B and inserted into node C, you know nothing about the state of 
node A, since it could have been mutated while it was outside of the 
tree and no mutation events would have been recorded.  Its attributes, 
text and children all could have changed, so the mutation listener has 
to basically discard everything it knows about node A and treat it as 
a brand-new node.




Under Jonas' original proposal, mutation listeners would be called for 
nodes that are outside the document (the API would be available on 
Document, Element and DocumentFragment interfaces).


As long as you add listeners to node A before it is removed from node B 
you can be informed of mutations on (or below) node A before it is 
inserted into node C.


Of course, the optimal place to add a listener to node A is in a 
synchronous mutation listener that is fired when node A is removed. In 
the case of asynchronous mutation listeners a better solution might be 
to have the API on the Document interface and use an approach similar to 
event delegation.






Re: Mutation events replacement

2011-07-09 Thread Sean Hogan

On 9/07/11 1:12 AM, Ryosuke Niwa wrote:
On Fri, Jul 8, 2011 at 5:21 AM, Sean Hogan shogu...@westnet.com.au 
mailto:shogu...@westnet.com.au wrote:


- MathJax (http://mathjax.org) is a JS lib that facilitates
putting math onto the web by converting LaTeX or MathML markup in
a page to HTML. By default MathJax triggers off the onload event
to run this conversion on the page. When content containing math
is dynamically added to the page, MathJax must be called manually
to convert the new content. A DOM insertion listener could
potentially be used to handle this conversion automatically.

- A similar use-case is element augmentation too complex for CSS
:before and :after

- ARIA support in JS libs currently involves updating
aria-attributes to be appropriate to behavior the lib is
implementing. Attribute mutation listeners would allow an inverse
approach - behaviors being triggered off changes to aria-attributes.

- DOM insertion and removal listeners could facilitate the
implementation of automatically updating Table-of-* (Headings /
Images / etc).


It seems like all 3 use cases here can be implemented by observers 
that are called AFTER the fact, and do not requiere any events or 
callbacks before mutation.





I agree, but it's just a list of the top of my head - I was merely 
trying to assist with the request for use-cases.


An obvious advantage of callbacks that occur BEFORE mutation is that 
they can be used to implement post-mutation notifications. The reverse 
is impossible.






Re: Mutation events replacement

2011-07-08 Thread Sean Hogan

On 8/07/11 8:28 AM, Jonas Sicking wrote:

On Thu, Jul 7, 2011 at 3:21 PM, John J Barton
johnjbar...@johnjbarton.com  wrote:

Jonas Sicking wrote:

  We are definitely
short on use cases for mutation events in general which is a problem.


3. Client side dynamic translation. Intercept mutations and replace or
extend them. This could be for user tools like scriptish or stylish, dev
tools to inject marks or code, or for re-engineering complex sites for newer
browser features.

I don't fully understand this. Can you give more concrete examples?


- MathJax (http://mathjax.org) is a JS lib that facilitates putting math 
onto the web by converting LaTeX or MathML markup in a page to HTML. By 
default MathJax triggers off the onload event to run this conversion on 
the page. When content containing math is dynamically added to the page, 
MathJax must be called manually to convert the new content. A DOM 
insertion listener could potentially be used to handle this conversion 
automatically.


- A similar use-case is element augmentation too complex for CSS :before 
and :after


- ARIA support in JS libs currently involves updating aria-attributes to 
be appropriate to behavior the lib is implementing. Attribute mutation 
listeners would allow an inverse approach - behaviors being triggered 
off changes to aria-attributes.


- DOM insertion and removal listeners could facilitate the 
implementation of automatically updating Table-of-* (Headings / Images / 
etc).





Re: Mutation events replacement

2011-07-08 Thread Sean Hogan

On 8/07/11 10:21 PM, Sean Hogan wrote:

On 8/07/11 8:28 AM, Jonas Sicking wrote:

On Thu, Jul 7, 2011 at 3:21 PM, John J Barton
johnjbar...@johnjbarton.com  wrote:

Jonas Sicking wrote:

  We are definitely
short on use cases for mutation events in general which is a problem.


3. Client side dynamic translation. Intercept mutations and replace or
extend them. This could be for user tools like scriptish or stylish, 
dev
tools to inject marks or code, or for re-engineering complex sites 
for newer

browser features.

I don't fully understand this. Can you give more concrete examples?




A couple of comments on these use-cases:

- MathJax (http://mathjax.org) is a JS lib that facilitates putting 
math onto the web by converting LaTeX or MathML markup in a page to 
HTML. By default MathJax triggers off the onload event to run this 
conversion on the page. When content containing math is dynamically 
added to the page, MathJax must be called manually to convert the new 
content. A DOM insertion listener could potentially be used to handle 
this conversion automatically.


- A similar use-case is element augmentation too complex for CSS 
:before and :after




The previous cases respond to content being inserted into the page by 
(potentially) adding more content. Ideally these additional insertions 
wouldn't trigger additionally mutation listeners. I guess the current 
event system facilitates this with stopPropagation().


- ARIA support in JS libs currently involves updating aria-attributes 
to be appropriate to behavior the lib is implementing. Attribute 
mutation listeners would allow an inverse approach - behaviors being 
triggered off changes to aria-attributes.




As has been mentioned, listening for attribute mutations is horrendously 
inefficient because your handler has to receive every mutation, even if 
only interested in one attribute.


- DOM insertion and removal listeners could facilitate the 
implementation of automatically updating Table-of-* (Headings / Images 
/ etc).









Re: Mutation events replacement

2011-07-05 Thread Sean Hogan

On 3/07/11 5:36 AM, Ryosuke Niwa wrote:

On Sat, Jul 2, 2011 at 10:46 AM, John J. Barton
johnjbar...@johnjbarton.com  wrote:

2) element transformation. The replacement fires after a mutation.
Library or tools that want to transform the application dynamically want
to get notification before the mutation.

Why do you need to get notified before the mutation?  Again, this is
exactly the sort of usage that causes us headaches and what we want to
avoid because scripts can then modify DOM before we make mutations.


Another reason for notifying before mutation (only applies to 
DOMNodeRemoved):


Some javascript libraries such as reglib 
(http://code.google.com/p/reglib/) use event delegation and CSS 
selectors to apply behavior to elements in a document.


If these libs wanted to take actions when an element is removed from the 
document they would need notification to occur before the element is 
removed, as this would allow element.matchesSelector() or equivalent to 
be called. Being notified after removal would require more complex code.


This is a fairly weak use-case. In general, if you need to know that an 
element is removed from the document then you already responded to it 
being in the document, at which time you could attach a mutation 
listener on the element.


Sean




Re: Comments on proposed editor's draft of XBL2 from Forms WG

2010-09-23 Thread Sean Hogan

 Perhaps HTML Components (HTC) would be a more accurate name now.


On 23/09/10 12:53 PM, Adam Barth wrote:

Perhaps the new effort should be called XBL3?

Adam


On Wed, Sep 22, 2010 at 9:30 AM, Leigh L. Klotz, Jr.
leigh.kl...@xerox.com  wrote:






Re: Publishing Selectors API Level 2 as an FPWD?

2010-01-11 Thread Sean Hogan

On 11/01/10 8:55 PM, Lachlan Hunt wrote:



In the following forms :scope is misleading:

element.queryScopedSelector(:scope + *)
element.queryScopedSelector(:scope ~ *)


What's misleading about that?  :scope would match the context node 
(what the element variable points to), and would return its sibling 
elements.





The definition of scope is (something like)  an area in which something 
acts or operates or has power or control. The examples above can return 
nodes that are not within :scope. Therefore :scope is misleading.



and especially:

element.querySelector(* :scope *, refNode)


Again, how is that misleading?  :scope matches whichever element 
refNode points to, and then follows the normal rules for evaluating 
querySelector.  Given that selector, any descendents of refNode that 
are also descendents of element (the context node) will be matched, 
the first of which will be returned.




In this example, the node represented by :scope isn't the boundary for 
the selection at all.
In one sense, element is the scope because any matched node must be 
descended from element.
In another sense (the sense being used in this discussion), document is 
the scope, because document.documentElement is the upper bounds for 
matching the first * in the selector.


In summary, the proposed :scope pseudo-class only acts as a scope for 
the query in special cases, not in the general case.





Re: Publishing Selectors API Level 2 as an FPWD?

2010-01-11 Thread Sean Hogan

On 11/01/10 6:40 PM, Boris Zbarsky wrote:

On 1/11/10 1:24 AM, Sean Hogan wrote:

That's correct. jQuery's $(element).find(div) is the equivalent of
SelectorsAPI2's element.querySelectorAll(:scope div) or


So in fact jquery can simply implement Element.find in terms of 
querySelectorAll by just prepending :scope  to the selector string, 
right?  Note that this happens to work even for the  div case (by 
converting the selector to :scope  div, which is what jquery means).


So the  div thing doesn't seem to require preparsing (modulo commas 
in the selector; was that the key point?).  Of course the jquery 
selectors that aren't in CSS do (or possibly post-parsing depending on 
how it's implemented).




If we could assume that commas only ever delimit selectors in a 
selector-string, and if jQuery didn't support selectors not implemented 
by the browser then something like the following conversion would be 
sufficient for all jQuery queries:


function preprocess(str) { return :scope  + str.split(,).join(, 
:scope ); }


Hence no value is added by queryScopedSelector*().

If we can't assume those things then jQuery will still need its current 
selector parser.

Hence no value is added by queryScopedSelector*().



My point is that jQuery's $(element).find( div) isn't supported
(without pre-processing by the JS lib) by 
element.queryScopedSelectorAll().


...


element.queryScopedSelectorAll(:scope  div) generally becomes
element.parentNode.querySelectorAll(:scope  div, element) which is
the same as
element.querySelectorAll(:scope  div, element) or even
element.querySelectorAll(:scope  div)


That's what I'm confused about.  Does implementing element.find( 
div) as element.queryScopedSelectorAll(:scope  div) not do what 
the current jquery code does?  If not, how do they differ?




They will select the same list of elements.
As will element.querySelectorAll(:scope  div)

I'm still confused about queryScopedSelectorAll, though. It sounds 
from your example like queryScopedSelectorAll just prepends :scope  
to the whole query string and then calls querySelectorAll on the 
parentNode of the scope node, with the scope node passed in as the 
optional argument.  So:


  element.queryScopedSelectorAll(myStr)

is the same as:

  element.parentNode.querySelectorAll(:scope  + myStr, element);

is that correct?



For some selector-strings yes.
More specifically, the parsing rules for scoped selectors are at:
http://dev.w3.org/2006/webapi/selectors-api2/#parse-a-scoped-selector

Scoped selectors must still be valid selectors, so  div, + div, ~ 
div will all throw exceptions.
They must be explicitly written as :scope  div, etc in the call to 
element.queryScopedSelectorAll().

Thus the queryScopedSelectorAll call won't prepend them with :scope .




Re: Publishing Selectors API Level 2 as an FPWD?

2010-01-11 Thread Sean Hogan

On 12/01/10 5:30 AM, Lachlan Hunt wrote:

Sean Hogan wrote:

In summary, the proposed :scope pseudo-class only acts as a scope for
the query in special cases, not in the general case.


Yes, I'm aware of that.  That was basically my reasoning for 
attempting to change it to :reference, but that name wasn't 
particularly well received either.  However, keep in mind, I'd prefer 
to avoid having this turn into another naming debate.  Selectors API 
has suffered enough in the past as a result of that.


So if you have anything more to add, I'd request that you check the 
archives for this list and www-style for messages relating to 
:scope/:reference/:context, etc. to see what arguments have been 
raised previously.


The most recent discussion of and objections to :reference are in this 
thread from www-style last September.  There were also other 
objections raised with me on IRC and told to me directly.


http://lists.w3.org/Archives/Public/www-style/2009Sep/thread.html#msg251

In particular, this one lists most of the alternatives have been 
considered, and it also sums up why the selector pre-processing for 
scoped selectors got watered down to its current state.


http://lists.w3.org/Archives/Public/www-style/2009Sep/0317.html


Yes, it sounds like I have nothing to add.

The new refNodes argument to querySelector*() will be useful, even if 
:scope is the place-holder for refNodes.
The new queryScopedSelector*() methods add no value. I suspect that if / 
when they get removed there will be no objection to renaming :scope to 
something more appropriate.


I've been an active part of discussion on this list. If you don't want 
to have the same arguments on two different lists you should reference 
the other list and discussion a bit more promptly.





Re: Publishing Selectors API Level 2 as an FPWD?

2010-01-10 Thread Sean Hogan

On 8/01/10 1:19 AM, Lachlan Hunt wrote:

Hi,
  Now that Selectors API Level 1 is published and basically all but 
finalised (just waiting for some implementations to be officially 
released before taking it to REC), can we publish Selectors API Level 
2 as an FPWD?


It would be useful to have it more widely reviewed, especially since 
Mozilla and WebKit have begun their implementation of matchesSelector, 
which is defined in it.


The editor's draft is here.

http://dev.w3.org/2006/webapi/selectors-api2/

FYI, it seems the whole Status of this Document hasn't been updated for 
Selectors-API2.


For instance:

This document has been approved for publication as a Candidate 
Recommendation by the working group. However, in light of existing 
interoperable implementations, the group is considering requesting 
publication as a Proposed Recommendation.


Also, the links to the W3C CVS are for Selectors-API, not Selectors-API2.

I can't see the value of queryScopedSelector*() methods. The original 
rationale was that JS libs could potentially drop their selector 
engines, but this isn't facilitated by the proposed methods. Given that 
JS libs will still have to parse the selectors it is a trivial step to call

querySelector*(rewrittenSelector, refNode)
rather than
queryScopedSelector*(rewrittenSelector)

The queryScopedSelector*() methods have misleading names - they don't 
match the definition of scope.
It would be ridiculous to stick with those names if there are no 
implementations already out there.

Similarly, the :scope pseudo-class has a misleading name.





Re: Publishing Selectors API Level 2 as an FPWD?

2010-01-10 Thread Sean Hogan

On 11/01/10 8:29 AM, Lachlan Hunt wrote:

Sean Hogan wrote:

On 8/01/10 1:19 AM, Lachlan Hunt wrote:

can we publish Selectors API Level 2 as an FPWD?

http://dev.w3.org/2006/webapi/selectors-api2/





I can't see the value of queryScopedSelector*() methods. The original
rationale was that JS libs could potentially drop their selector
engines, but this isn't facilitated by the proposed methods. Given that
JS libs will still have to parse the selectors it is a trivial step 
to call

querySelector*(rewrittenSelector, refNode)
rather than
queryScopedSelector*(rewrittenSelector)


Personally, I agree and was initially hesitant about adding it, but 
there were some reasonable arguments put forth suggesting that lifting 
the burden of pre-processing the selector to prepend :scope from JS 
libs would be useful [1].  Evidence to the contrary would be helpful.  
John Resig also once told me he had an alternative proposal, but he 
hasn't yet shared it with me.




That's my point - in its current form queryScopedSelector*() doesn't 
lift that burden of pre-processing.
I don't know about all selector engines, but jQuery, for example, has 
several non-standard selectors that will continue to require 
pre-processing.

:first, :last, :even, :odd, :eq(), :gt(), :lt(), :header, :animated,
:contains(), :has(), :parent,
:input, :text, :password, :radio, :checkbox, :submit, :image, :reset, 
:button, :file


Even if jQuery deprecates non-standard selectors, the current spec for 
queryScopedSelector*() doesn't support the jQuery implicitly scoped 
selector  *.



The queryScopedSelector*() methods have misleading names - they don't
match the definition of scope.
It would be ridiculous to stick with those names if there are no
implementations already out there.


Do you have a better alternative suggestion?


Similarly, the :scope pseudo-class has a misleading name.


I've tried various alternative names, like :context, :reference, etc., 
but so far scope seems to be the least objectionable.  But all things 
considered, I don't think :scope is a particularly bad name, since 
it's name somewhat describes it's purpose and relates it to its 
utility in scoped stylesheets.




:reference matches the text of the spec. :context would be second choice 
I guess.

I seem to recall :ref-node and :context-node also being suggested.
:scope only describes its purpose in specific cases - queries with one 
of the following forms:


element.queryScopedSelector(:scope *)
element.queryScopedSelector(:scope  *)

In the following forms :scope is misleading:

element.queryScopedSelector(:scope + *)
element.queryScopedSelector(:scope ~ *)

and especially:

element.querySelector(* :scope *, refNode)






Re: Publishing Selectors API Level 2 as an FPWD?

2010-01-10 Thread Sean Hogan

On 11/01/10 4:19 PM, Boris Zbarsky wrote:

On 1/10/10 11:58 PM, Sean Hogan wrote:

Even if jQuery deprecates non-standard selectors, the current spec for
queryScopedSelector*() doesn't support the jQuery implicitly scoped
selector  *.


As I understand it, jquery selectors on elements are always scoped in 
the sense that they behave differently from the v1 Selectors API.  In 
particular, if I understand correctly, the behavior of:


  element.querySelector(body div)

in matching all divs that are descendants of |element| and also 
descendants of a body (which may be an _ancestor_ of |element|) is 
different from the selector behavior in jquery.


Or did I understand incorrectly?


That's correct. jQuery's $(element).find(div) is the equivalent of 
SelectorsAPI2's element.querySelectorAll(:scope div) or 
element.queryScopedSelectorAll(div).


My point is that jQuery's $(element).find( div) isn't supported 
(without pre-processing by the JS lib) by element.queryScopedSelectorAll().




All that said, I just read the draft at 
http://dev.w3.org/2006/webapi/selectors-api2/ and I can't make heads 
or tails of either what the new arguments to querySelector(All) are 
supposed to mean (are they just an enumaration of the things :scope is 
allowed to match during the selector evaluation?) or what 
queryScopedSelector(All) is supposed to do.  Am I just missing 
something?  Am I reading the wrong draft?


(I'd link to the dated version of the draft, in case it changes, but 
that link is broken, sadly.)




You are correct about the new refNodes argument in querySelector*().
queryScopedSelector*() are more-or-less wrappers around querySelector*().

e.g.

element.queryScopedSelectorAll(div) generally becomes
element.parentNode.querySelectorAll(:scope div, element) which is the 
same as

element.querySelectorAll(:scope div, element) or even
element.querySelectorAll(:scope div)


element.queryScopedSelectorAll(:scope  div) generally becomes
element.parentNode.querySelectorAll(:scope  div, element) which is 
the same as

element.querySelectorAll(:scope  div, element) or even
element.querySelectorAll(:scope  div)


element.queryScopedSelectorAll(:scope + div) generally becomes
element.parentNode.querySelectorAll(:scope + div, element)


element.queryScopedSelectorAll(div, div:scope) generally becomes
element.parentNode.querySelectorAll(:scope div, div:scope, element)






Re: Publishing Selectors API Level 2 as an FPWD?

2010-01-10 Thread Sean Hogan

On 11/01/10 5:24 PM, Sean Hogan wrote:

On 11/01/10 4:19 PM, Boris Zbarsky wrote:

On 1/10/10 11:58 PM, Sean Hogan wrote:

Even if jQuery deprecates non-standard selectors, the current spec for
queryScopedSelector*() doesn't support the jQuery implicitly scoped
selector  *.


As I understand it, jquery selectors on elements are always scoped in 
the sense that they behave differently from the v1 Selectors API.  In 
particular, if I understand correctly, the behavior of:


  element.querySelector(body div)

in matching all divs that are descendants of |element| and also 
descendants of a body (which may be an _ancestor_ of |element|) is 
different from the selector behavior in jquery.


Or did I understand incorrectly?


That's correct. jQuery's $(element).find(div) is the equivalent of 
SelectorsAPI2's element.querySelectorAll(:scope div) or 
element.queryScopedSelectorAll(div).




Oops. Not a very insightful example. Perhaps the following would be 
better. Same for examples below.


jQuery's $(element).find(div p) is the equivalent of SelectorsAPI2's 
element.querySelectorAll(:scope div p) or 
element.queryScopedSelectorAll(div p).


My point is that jQuery's $(element).find( div) isn't supported 
(without pre-processing by the JS lib) by 
element.queryScopedSelectorAll().




All that said, I just read the draft at 
http://dev.w3.org/2006/webapi/selectors-api2/ and I can't make heads 
or tails of either what the new arguments to querySelector(All) are 
supposed to mean (are they just an enumaration of the things :scope 
is allowed to match during the selector evaluation?) or what 
queryScopedSelector(All) is supposed to do.  Am I just missing 
something?  Am I reading the wrong draft?


(I'd link to the dated version of the draft, in case it changes, 
but that link is broken, sadly.)




You are correct about the new refNodes argument in querySelector*().
queryScopedSelector*() are more-or-less wrappers around querySelector*().

e.g.

element.queryScopedSelectorAll(div) generally becomes
element.parentNode.querySelectorAll(:scope div, element) which is 
the same as

element.querySelectorAll(:scope div, element) or even
element.querySelectorAll(:scope div)


element.queryScopedSelectorAll(:scope  div) generally becomes
element.parentNode.querySelectorAll(:scope  div, element) which is 
the same as

element.querySelectorAll(:scope  div, element) or even
element.querySelectorAll(:scope  div)


element.queryScopedSelectorAll(:scope + div) generally becomes
element.parentNode.querySelectorAll(:scope + div, element)


element.queryScopedSelectorAll(div, div:scope) generally becomes
element.parentNode.querySelectorAll(:scope div, div:scope, element)








Re: CfC - publish Selectors API as CR

2009-11-26 Thread Sean Hogan

Lachlan Hunt wrote:

Maciej Stachowiak wrote:
The proposed exit criteria are in a separate thread, but essentially 
are:


For a set of tests based on HTML, CSS 2.1 selectors and this spec,
there are two implementations that pass every test interoperably, and
do not fail any additional tests based on misimplementing this
specification (i.e. failures based on not supporting a technology used
only in the additional tests, such as MathML, will not be taken into
account).


Request for clarification. Does this require:

A) There must be two implementations, each of which passes every test
(i.e. the same two implementations pass all the tests); or
B) For each test, there are two implementations that pass it (but not
necessarily the same two for every test).

It reads like (A), but I have seen similar wording interpreted as (B) in
the context of other specs...


The intention in the original exit criteria proposal [1] was for there 
to be at least two complete implementations, each passing 100% of the 
baseline tests.  I can make this clearer in the exit criteria as follows:


---

There must be at least two complete, independent implementations, each 
of which must pass 100% of the baseline testsuite and should pass 
additional tests, dependent on the following conditions:


* The implementations must be native implementations in shipping
  products.  (JavaScript library implementations don't count).


What is the reason for the native implementation requirement?
Is it W3C policy?

Sean





Re: [selectors-api] Scoped Selectors

2009-09-30 Thread Sean Hogan

Lachlan Hunt wrote:

John Resig wrote:

With that in mind, option #3 looks the best to me. It's lame that the 
API
will be longer but we'll be able to use basic object detection to see 
if it

exists. Unfortunately the proper scoping wasn't done the first time the
Selectors API was implemented so we kind of have to play the hand 
we've been

dealt.

Thus there would be two new methods:
queryScopedSelectorAll
queryScopedSelector


I really didn't want to introduce new methods for this if it could be 
avoided.  I realise one problem with the first draft of the API I 
posted yesterday was that is was too cumbersome for scripts to create 
and use scoped selectors, rather than normal selectors.  That draft 
required scripts to do the following:


var selector = document.createSelector(+p, true);
document.querySelector(selector, elm);


This isn't cumbersome:

- JS libraries are still going to provide their own query functions 
which can wrap this trivially


- people who want to use the standard API will also want to use standard 
selectors


- the tiny group of people who don't want to use a JS library but do 
want to use selector strings with implied :scope will just create a 
wrapper function (or method).


Element.prototype.queryScopedSelector = function(selector, scope) {
   return this.querySelector(document.createSelector(selector, true), 
scope);

}

This is just as simple as the new proposal.

Element.prototype.queryScopedSelector = function(selector, scope) {
   return this.querySelector(! + selector, scope);
}




I have come up with a significantly simpler, alternative solution that 
not only abolishes the createSelector() method and the 
SelectorExpression interfaces, but also avoids introducing additional 
methods like queryScopedSelector(), or extra parameters.


The draft now defines the concept of a *selector string* and a *scoped 
selector string*.  The selector string is just an ordinary selector, 
as supported by current implementations.


A scoped selector string is a string that begins with an exclamation 
point followed by a the remainder of the selector.  The purpose of the 
exclamation point is to clearly identify the string as a scoped 
selector that requries an extra pre-processing step to turn it into a 
valid group of selectors.


There are also slightly different requirements for the processing 
Element.querySelectorAll() when the selector argument is a scoped 
selector string.  This allows for the sibling combinator cases to work.


That is quite inconsistent behavior.

- querySelector*() and matchesSelector() can now take standard and 
non-standard selector strings


- matchesSelector() can have explicit declaration of the ::reference 
element, while querySelector*() can have explicit and implied


- element.querySelector*() now has quite complex behavior.
With one selector string it selects from descendants of element, with 
another is selects from descendants of element.parentNode.
If you want element to be the :reference node then it doesn't need a 
second argument. But if you want element and another node to be 
:reference then you have to pass both in an array as the second argument.



It is also less flexible - it makes using non-standard selector strings 
slightly easier but using standard selector strings is now more difficult.


- if I want to provide an API that doesn't accept these non-standard 
selector strings then I can no longer just wrap querySelector*(). 

- if I want to provide an API that doesn't return siblings of the 
context-node then I can no longer just wrap querySelector*().


To illustrate that last point using the previous and current drafts:
To support +p in previous draft is trivial.

Element.prototype.queryScopedSelectorAll = function(selector, ref) {
   return 
this.parentNode.querySelectorAll(document.createSelector(selector, 
true), ref);

}

To NOT support :reference + p in current draft we have to filter 
siblings from the result.


Element.prototype._querySelectorAll = Element.prototype.querySelectorAll;
Element.prototype.querySelectorAll = function(selector, ref) {
   var parent = this.parentNode;
   var nodes = this.querySelectorAll(selector, ref);
   return Array.filter(nodes, function(node) {
  return (node.parentNode == parent) ? false : true;
   });
}

To NOT support + p in current draft have to reject scoped selector 
syntax and filter siblings.


Element.prototype._querySelectorAll = Element.prototype.querySelectorAll;
Element.prototype.querySelectorAll = function(selector, ref) {
   var parent = this.parentNode;
   if (/^(|+|~|!)/.test(selector)) throw ;
   var nodes = this._querySelectorAll(selector, ref);
   return Array.filter(nodes, function(node) {
  return (node.parentNode == parent) ? false : true;
   });
}





e.g. The selector em, strong supported by JS libraries can simply 
be prefixed with a !, like !em, strong and the implementation 
will be able to process it to become :scopeem, :scopestrong.  Of 
course, it 

Re: [selectors-api] Scoped Selectors

2009-09-25 Thread Sean Hogan

Hi Lachy,

Here's a proposal.

querySelector*(selector, context) // allows selectors with :scope 
pseudo-class
queryScopedSelector*(selector, context) // allows selectors with implied 
:scope
matchesSelector(selector, context) // allows selectors with :scope 
pseudo-class


To check if the :scope pseudo-class is available, use:

try { document.body.matchesSelector(:scope, document.body); }
catch (error) { /* not supported */ }

 OR

try { document.querySelector(:scope, document.body); }
catch (error) { /* not supported */ }


Now, querySelector*() can't accept selectors with implied :scope because 
while  em is unambiguously :scope  em, p em would become 
ambiguous. (is it p em or :scope p em)

So we need a new method, such as queryScopedSelector*().
element.querySelector*() limits selection to descendants of elements, 
and element.queryScopedSelector*() should be consistent.
If element is the scope then element.queryScopedSelector*(~p) will 
return no elements.
If we want to support sibling queries then we need to provide a scope 
explicitly, so:


   element.parentNode.queryScopedSelector*(~p, element);

Notes:
1. I don't think browsers should provide queryScopedSelector*()
2. I think :context is a better name than :scope
3. If the context argument of these methods could be an element or a 
NodeList it might satisfy some of the other feature requests.




Lachlan Hunt wrote:

Hi,
   I'm trying to find a suitable solution for the scoped selector
issues, but figuring out what the most suitable API is proving 
challenging.



*Use Cases*

1. JS libraries like JQuery and others, accept special selector 
strings beginning with combinators. e.g. em,+strong. These 
libraries behave as if there was a selector that matched the context 
node.


e.g. In JQuery:

$(+p, elm);

This would select the p element that is a sibling of elm.

2. It would be useful to be able to check if an a given element 
matches a selector in relation to a specified reference element 
(:scope).  For example, check if an event target is a sibling of a 
specific element, and if the parent element has a specifc class name set.


e.g. Matches the selector: .foo:scope~input[type=text]

This may be particularly useful for event delgation.

3. Obtain a collection of elements based on their relation to more 
than one specified reference elements.


e.g.
Query to the document to obtain elements matching :scope+span, where 
:scope is intended to match any of the elements in a specific 
collection.  This would be simpler than iterating all of the nodes in 
the collection, running the query on each of them and then merging the 
results.



*Problems*

1. Need a way to allow the browser to parse implicitly scoped 
selectors beginning with combinators and imply the presence of :scope 
before each in the group.


2. Need to allow :scope to be used within the selector strings, and 
specify one or more scope elements that will be matched by :scope.  
This needs to be useable with all of the querySelector(), 
querySelectorAll() and matchesSelector() methods, or others with 
equivalent functionality.


3. Ideally, there would be an easy, reliable way for scripts to test 
if the implementation supports scoped selectors (at least, implicitly 
scoped selectors. Those using :scope could only be discovered by 
capturing the SYNTAX_ERR exception)  For legacy browsers that don't, 
they can fall back to their own selector engines.



*Possible Solutions*

1. Define a Selector object that can be used to parse and store a
selector, and which can handle pre-parsing the selector and
specifying the scope elements upon creation.  This selector object
can then be passed anywhere that accepts a selector string. (This is
basically part of the createSelector() and Selector interface
proposal from earlier).

2. Add parameters to the querySelector(), querySelectorAll() and
matchesSelector() methods for:
a. Indicating whether the selectors parameter should be processed
   with an implied scope.
b. Specifying one or more reference elements that would match :scope.

3. Create new scoped versions of the existing methods that accept one
or more reference elements that would match the implied scope.
Add an optional parameter to the existing querySelector*() methods
that would Allow one or more reference elements to be specified to
match the explicit use of :scope in the selector.


Option 2 doesn't provide an easy way to detect browser support.  
Option 3 creates an additional queryScopedSelector*() and 
matchesScopedSelector() methods, but this could get quite verbose if 
we also add equivalent NS methods to handle the namespace issue, to 
both the scoped and non-scoped versions.  This would create an 
unreasonable number of different methods that would make understanding 
the API quite complex.  Option 1 is syntactically messy, and requires 
the creation of a new object just to handle a scoped selector, even if 
that selector is 

Re: [selectors-api] Scoped Selectors

2009-09-25 Thread Sean Hogan

Sean Hogan wrote:

Hi Lachy,

Here's a proposal.

querySelector*(selector, context) // allows selectors with :scope 
pseudo-class
queryScopedSelector*(selector, context) // allows selectors with 
implied :scope
matchesSelector(selector, context) // allows selectors with :scope 
pseudo-class


To check if the :scope pseudo-class is available, use:

try { document.body.matchesSelector(:scope, document.body); }
catch (error) { /* not supported */ }

 OR

try { document.querySelector(:scope, document.body); }
catch (error) { /* not supported */ }

Sorry. Replace document.body with document.documentElement. That should 
be more efficient for the querySelector test.




Re: [selectors-api] Scoped Selectors

2009-09-25 Thread Sean Hogan

Lachlan Hunt wrote:

Sean Hogan wrote:

Here's a proposal.

querySelector*(selector, context) // allows selectors with :scope
pseudo-class
queryScopedSelector*(selector, context) // allows selectors with implied
:scope
matchesSelector(selector, context) // allows selectors with :scope
pseudo-class


Yes, this is effectively the same as option #2 that I described, 
except you haven't provided a way to support implied scope there.


That's because implied scope is incompatible with :scope ~ p or ~ p 
should we want to support those. I think it will be confusing to have 
implied and explicit forms for :scope.



element.querySelector*() limits selection to descendants of elements,
and element.queryScopedSelector*() should be consistent.
If element is the scope then element.queryScopedSelector*(~p) will
return no elements.
If we want to support sibling queries then we need to provide a scope
explicitly, so:

element.parentNode.queryScopedSelector*(~p, element);

Notes:
1. I don't think browsers should provide queryScopedSelector*()


This seems contradictory.  You seemed to be proposing that we use 
queryScopedSelector, and now you're saying we shouldn't.  Personally, 
I agree that we shouldn't.  It's my least favourite solution of them all.




I don't think implied :scope selector text should be supported at all. 
It's a whim of the JS libraries. I'm just concerned that if we do have 
it then at least it doesn't screw up the core functionality.



2. I think :context is a better name than :scope


Yeah, the name of :scope is a complicated issue. :context isn't ideal 
either.  It would be slightly confusing because selectors API defines 
the term context node as being the node upon which the method is 
being invoked.  Maybe something like :ref or :reference might work.




Yeah.


3. If the context argument of these methods could be an element or a
NodeList it might satisfy some of the other feature requests.


Yes, the reference elements parameter will accept either a single 
element, Array or NodeList.


I have checked in a new draft containing my first attempt at 
supporting scoped selectors, with support for both :scope (or whatever 
it gets called) and implied scope selectors.  I've opted for a 
combination of options 1 and 2 that I previously described, using the 
createSelector() and SelectorExpression object for being able to 
represent implied scoped selectors easily, and optional refNodes 
parameters on querySelector*() and matchesSelector() methods for 
supplying contextual reference elements (that match :scope).


Basically, for the simple case, it works as illustrated in these 
examples:


elm.querySelector(:scopep);
document.querySelectorAll(:scopep, elm);
document.querySelectorAll(:scopep, [elm1, elm2]);

To provide the functionality of JS libraries supporting implied scope 
selectors, you first create a SelectorExpression object like this:


document.createSelector(em,strong, true);

That object can then be passed to either the querySelector*() or 
matchesSelector() methods.


The effect of this is basically that JavaScript libraries can mostly 
use document.createSelector(str, true) as a direct replacement their 
own custom selector parsing libraries (except for the cases where 
they're using custom pseudo-classes not supported by the browser)


One possible modification I'm considering is introducing a separate 
factory method for creating implied scope selectors: 
createScopedSelector(selector); rather than using a boolean parameter.





Looks okay, except I don't think there should be implied contextual 
reference elements.
What are the chances that we will have to extend createSelector in the 
future? e.g. namespaces





Re: [selectors-api] Summary of Feature Requests for v2

2009-09-24 Thread Sean Hogan

Garrett Smith wrote:

On Thu, Sep 24, 2009 at 12:02 AM, Mike Wilson mike...@hotmail.com wrote:
  

Yes, the base for event delegation is certainly something
like that. I just wanted to make clear that the main reason
for adding this functionality (IMO) is event delegation.
I'll let event delegation library creators chime in on the
details on what is needed for making really efficient
behavioural/delegation implementations, and judge the merits
of various optimizations. There has f ex already been mention
of caching parsed selectors.




The benefit to that is that the selector text is parsed once, so
something like:-

document.onmouseover = function(ev) {
  if(ev.target.matchesSelector(.infotip)) { /*...*/ }
};

could probably be made more efficient as:-

var selector = QuerySelector.create(.infotip);
document.onmouseover = function(ev) {
  if(selector.matches(ev.target)) { /*...*/ }
};

  


I would be surprised if an implementation didn't create an internal 
lookup table keyed off the selector text.





Re: [selectors-api] Summary of Feature Requests for v2

2009-09-24 Thread Sean Hogan

Lachlan Hunt wrote:

Lachlan Hunt wrote:

Sean Hogan wrote:

I think a couple of those features are pretty low priority:

- I don't see the point of collective queries on NodeLists.
Are there any references for the proposal?
Otherwise I can't think of any useful queries that can't already be
achieved with a single querySelectorAll().


It was discussed a couple of days ago in IRC. It's based on the
functionality provided and needed by javascript libraries.


Sorry, I forgot to provide the link.  The relevant discussion is 
spread out quite a bit throughout this log, beginning here.


http://krijnhoetmer.nl/irc-logs/whatwg/20090922#l-

I've highlighted the relevant parts.



I couldn't see where it was needed, only that it was possible in jQuery.
I still can't think of any NodeLists that this could usefully be applied 
to that couldn't be achieved with a single querySelectorAll(). At least 
until we can create arbitrary NodeLists.





Re: [selectors-api] Summary of Feature Requests for v2

2009-09-24 Thread Sean Hogan

Boris Zbarsky wrote:

On 9/24/09 6:29 AM, Sean Hogan wrote:

I would be surprised if an implementation didn't create an internal
lookup table keyed off the selector text.


Gecko doesn't.  Webkit doesn't.

I just checked really quickly, and on my machine (a year-plus old 
laptop) parsing the .foo .bar .baz selector and destroying the 
selector object before returning in Gecko takes about 80% of the 
overhead (that is, not walking the tree and doing selector matching) 
time of a querySelector() call.  Or, in numbers, about 5.5us per call. 
Webkit's time for executing my testcase is comparable, though I can't 
tell how much of their time is selector parsing.




That is surprising. Does the CSS engine do the same? If the CSS engine 
doesn't store the parsed selector then it probably doesn't matter for JS 
calls either.


If you're doing less than 1,000 calls that involve selectors api per 
second, the selector-parsing time is probably not that relevant.  But 
I don't know what the use cases are here.


-Boris


Take a event-delegation system that uses matchesSelector.
Every event that it handles will walk the event path trying 
element.matchesSelector with every registered handler.
e.g. There are twenty registered click handlers and a click event occurs 
on an element ten levels deep. There could be 20 * 10 = 200 calls to 
matchesSelector. Or 400 if the system simulates capture phase as well.


Or take a framework that adds enhancements to HTML elements based on 
selectors.
The framework wants to handle dynamic insertion to / removal from the 
page, so every DOMNodeInserted / DOMNodeRemoved (or equivalent) it will 
call querySelectorAll for all registered enhancements to see if there is 
any work to do.






Re: [selectors-api] Summary of Feature Requests for v2

2009-09-24 Thread Sean Hogan

Lachlan Hunt wrote:

Mike Wilson wrote:

My first priority would be Matches Selector, and see to that
it fulfills the needs for event delegation.


Is there any special functionality that would be needed to achieve 
this?  If I understand correctly, event delegation just needs to be 
able to check whether the event target element matches a given 
selector.  So it would be something like:


if (evt.target.matchesSelector(.fooinput.bar)) {
   ...
}



In case it isn't obvious, we may want to check every element in the 
event path. i.e. all ancestors of  evt.target.


If matchesSelector could be called with a context element then it would 
become a more powerful version of compareDocumentPosition(). It is also 
more limited because you can't do preceding-siblings.


Examples
I'll use the :scope pseudo-class, although :context would be a better name.

elt.matchesSelector(:scope *, context); // descendant
elt.matchesSelector(:scope  * *, context); // descendant but not child
elt.matchesSelector(:scope ~ *, context); // following-sibling
elt.matchesSelector(:scope ~ *  *, context); // nephew (child of a 
following-sibling)


I would probably use it if it was there, but wouldn't complain if it 
wasn't.







Re: [selectors-api] Summary of Feature Requests for v2

2009-09-24 Thread Sean Hogan

Boris Zbarsky wrote:

On 9/24/09 6:45 PM, Sean Hogan wrote:

That is surprising. Does the CSS engine do the same? If the CSS engine
doesn't store the parsed selector then it probably doesn't matter for JS
calls either.


In Gecko the CSS engine stores the parsed selector.  In addition, it 
stores the selectors in various bins in a data structure to make 
matching faster.  In practice this means that you don't have to 
actually match most nodes against most selectors when computing the 
set of rules that match a given node.  This makes sense because you're 
guaranteed that every time a node is inserted into the DOM you will 
have to match it against every single one of those selectors. 
https://developer.mozilla.org/en/Writing_Efficient_CSS has a 
description of the setup.  I believe Webkit has something similar.  
Again, I can't speak to Trident or Presto.


In the querySelector(All) case, the browser has no way to know that 
the selector will ever be reused.  In practice, the native 
implementations were enough faster than what they were replacing, even 
without any particularly fancy optimizations, that simplicity was 
judged more important than squeezing every bit of performance out.  At 
least in Gecko's case.  If we get to the point where they're being a 
bottleneck again, that will likely be revisited.



Take a event-delegation system that uses matchesSelector.
Every event that it handles will walk the event path trying
element.matchesSelector with every registered handler.
e.g. There are twenty registered click handlers and a click event occurs
on an element ten levels deep. There could be 20 * 10 = 200 calls to
matchesSelector. Or 400 if the system simulates capture phase as well.


200 calls would equate to ~1ms of selector parsing time in the the 
case of Gecko.  For a click event, that's not terrible.


No. It will be negligible compared to everything else that has to be done.




Or take a framework that adds enhancements to HTML elements based on
selectors.
The framework wants to handle dynamic insertion to / removal from the
page, so every DOMNodeInserted / DOMNodeRemoved (or equivalent) it will
call querySelectorAll for all registered enhancements to see if there is
any work to do.


This could be much more of a problem.  I'd want be interested in what 
the actual performance is like in this situation.  Remember, the 
selector-parsing time was just the overhead; the real time usage is 
walking the DOM and doing the matching.  For matchesSelector this is 
much less significant, of course, but for querySelectorAll it's likely 
to be the dominating factor (gut feeling; if someone wants to measure 
that would be welcome).


I also wonder how well XBL or something like that would handle cases 
like this...  This setup (matching every node in a subtree against a 
set of selectors) is really not that well served by any of the APIs 
described here.  It's much closer to the CSS use case and would 
benefit from similar optimizations.




XBL (and standard DOM implementations) is what we want.

Note that I don't have anything against exposing parsed selector 
objects in JS.  I don't think it would be that difficult to implement 
it.  I'm just not sure whether the added complexity is really needed, 
and whether it's the best solution for the use cases.  Maybe it is; 
I'm just gathering data.  This is not exactly my area of expertise.


-Boris



Thanks for that perspective. My main concern was that we don't create 
parsed selectors in JS (at least not for performance reasons).





Re: [selectors-api] Scoped Queries

2009-09-23 Thread Sean Hogan

Jonas Sicking wrote:

On Wed, Sep 23, 2009 at 4:51 AM, Lachlan Hunt lachlan.h...@lachy.id.au wrote:
  

*Scoped Queries*
http://www.w3.org/Bugs/Public/show_bug.cgi?id=5860

This has been discussed extensively in the past.  Basically, the idea is
that the selector would be evaluated in the scope of the element, in a way
more compatible with how libraries like JQuery work.  This slightly
different from the :scope pseudo-class proposal, see bug for details.



Note that what makes the strong, em selector (which apparently
some libraries support) hard to support spec-wise is that that is not
in fact valid CSS syntax. It's certainly possible to define behavior
for it, it's pretty clear to me how it's intended to work, but it
would mean specifying our own syntax.
  


It is clear how it is intended to work, but it is less powerful than a 
:scope selector.

I suggest it is a low priority feature.


However if supporting commaseparated queries is critical for libraries
then I see no other choise. We'll one way or another have to specify
our own syntax, though it can be heavily based on the productions in
the Selector spec.

/ Jonas


  



Libraries already parse selector queries anyway. And some of them add 
non-standard selectors and presumeably will continue to do so. I don't 
think it is an issue.






Re: [selectors-api] Summary of Feature Requests for v2

2009-09-23 Thread Sean Hogan

I think a couple of those features are pretty low priority:

- I don't see the point of collective queries on NodeLists.
Are there any references for the proposal?
Otherwise I can't think of any useful queries that can't already be 
achieved with a single querySelectorAll().


- Filtering NodeLists is trivial once we get matchesSelector(). 


Sean


Lachlan Hunt wrote:

Hi,
  I'm planning to look at beginning work on Selectors API v2 soon to 
add a number of requested features that didn't make it into the first 
version.  This e-mail is a summary of what is being considered, and is 
intended to start discussion about which ones are really worth 
focussing on, and how to ensure they address the use cases appropriately.



*Matches Selector*
http://www.w3.org/Bugs/Public/show_bug.cgi?id=5865

*Filtering NodeLists*
http://www.w3.org/Bugs/Public/show_bug.cgi?id=5864

*Scoped Queries*
http://www.w3.org/Bugs/Public/show_bug.cgi?id=5860

*Collective Queries on NodeLists*
http://www.w3.org/Bugs/Public/show_bug.cgi?id=7707

*Namespace Prefix Resolution*
http://www.w3.org/Bugs/Public/show_bug.cgi?id=6290






Re: [selectors-api] Scoped Queries

2009-09-23 Thread Sean Hogan

John Resig wrote:


Libraries already parse selector queries anyway. And some of them
add non-standard selectors and presumeably will continue to do so.
I don't think it is an issue.


However the parsing only happens after the selector has been passed to 
the native querySelectorAll implementation. We assume the qSA will 
provide the fastest solution. If it throws an exception we then branch 
off into the old, slower, selector engine and forget qSA entirely. 
Since there's no good error-reporting coming from qSA we can't, 
reasonably, determine how or why an error happened (was it a syntax 
error (foobar)? is the selector supposed to be supported but just 
isn't (div:nth-of-type(2) in IE 8)? does it look like a valid selector 
but there's no existing implementation (div:first)?).


If there were two solutions, one that forced you to use :scope in 
front of all queries (or sub-queries) and one that had a separate 
method that handled cases like  div properly, I'd take the latter. 
Parsing queries sucks and is slow, it's easier to just pass all of 
that off to the browser.


--John

Yes, it will have to be a new method.
 div may be unambiguously :scope  div, but if you allow it then 
people will expect div p to be :scope div pwhich would conflict the 
current definition.




Re: [selectors-api] Scoped Queries

2009-09-23 Thread Sean Hogan

Jonas Sicking wrote:

On Wed, Sep 23, 2009 at 6:00 PM, Sean Hogan shogu...@westnet.com.au wrote:
  

Jonas Sicking wrote:


On Wed, Sep 23, 2009 at 4:51 AM, Lachlan Hunt lachlan.h...@lachy.id.au
wrote:

  

*Scoped Queries*
http://www.w3.org/Bugs/Public/show_bug.cgi?id=5860

This has been discussed extensively in the past.  Basically, the idea is
that the selector would be evaluated in the scope of the element, in a
way
more compatible with how libraries like JQuery work.  This slightly
different from the :scope pseudo-class proposal, see bug for details.



Note that what makes the strong, em selector (which apparently
some libraries support) hard to support spec-wise is that that is not
in fact valid CSS syntax. It's certainly possible to define behavior
for it, it's pretty clear to me how it's intended to work, but it
would mean specifying our own syntax.

  

It is clear how it is intended to work, but it is less powerful than a
:scope selector.
I suggest it is a low priority feature.



But a :scope selector by itself doesn't help if the passed in selector
to the library contains a comma separated selector like foo, bar.

  

However if supporting commaseparated queries is critical for libraries
then I see no other choise. We'll one way or another have to specify
our own syntax, though it can be heavily based on the productions in
the Selector spec.

/ Jonas
  

Libraries already parse selector queries anyway. And some of them add
non-standard selectors and presumeably will continue to do so. I don't think
it is an issue.



The input I've gotten from library developers is that they would love
to not have to ship a selector engine. Apparently it would reduce the
size of for example jQuery with about 10k which is pretty significant.

/ Jonas

  
They could. If something like the following is not sufficient it 
probably means they aren't happy with the native selector engine. In 
that case they will be providing their own anyway.


Element.prototype.queryScopedSelectorAll = function(selector) {
   var validSel = :scope  + selector.replace(,, , :scope );
   return this.querySelectorAll(validSel);
}





Re: Storage 'length' and enumeration

2009-04-30 Thread Sean Hogan

Ian Hickson wrote:

On Thu, 30 Apr 2009, Sean Hogan wrote:
  

I'm not sure about all those objects, but my (incomplete) testing of
HTML*Collections indicates that when accessed using array notation:
   object[index]; where index  object.length
they behave as a readonly array. Which has the fortuitous by-product of
allowing the object to work with Array.forEach(), etc.

Storage objects have a length property and can be accessed with array 
notation. They look like they should work with Array generic methods... 
and they do... except they aren't reliable if you use numeric keys... 
but they don't even give an error message.



They work the same way as a collection does when one of the items in a 
collection has a name that's numeric, e.g. document.images with an img 
element whose name= attribute has the value 0.


  

I would suggest one of:
1. When accessed as an array they are treated as a readonly array. i.e. MUST
use getItem(), setItem() for numeric keys
2. Treat it as an associative array. Change the name of the length property.



Storage works exactly like a collection in this respect; the values from 0 
to length-1 override the names.


  
Ok, I think you're confirming that Storage objects will work 
consistently with Array generic methods; the callback receiving a key 
into the Storage object.


I obviously haven't been following this thread accurately.




Re: Storage 'length' and enumeration

2009-04-29 Thread Sean Hogan

Ian Hickson wrote:

On Tue, 28 Apr 2009, John J. Barton wrote:
  

I could not figure out from the WebIDL what happens in this case:
   sessionStore[2] = howdy; // no other keys in sessionStore

I guess this does not work like Javascript arrays or objects, rather I 
expect it fails?



It works, it just sets the key 2 to the value howdy.

(Modulo some WebIDL and WebStorage IDL bugs that I will report 
separately, oops.)


  

sessionStore[2] = howdy;
print(sessionStore[2]); // prints null?
print(sessionStore[2]); // prints howdy

To my knowledge that's not consistent with any other object or interface 
in the browser.


Sean







Re: Storage 'length' and enumeration

2009-04-29 Thread Sean Hogan

Boris Zbarsky wrote:

Sean Hogan wrote:

sessionStore[2] = howdy;
print(sessionStore[2]); // prints null?


Where, exactly?  That gives howdy in Gecko, at least.  At least with 
s/sessionStore/window.sessionStorage/.


-Boris

I was following the discussion, and the point is that array-like 
behavior is implied but not consistently delivered.


Anyway, as you point out, for this interface Firefox gives precedence to 
NameGetters over IndexGetters. In the spec it doesn't seemed defined.

FYI, other collections in Firefox give precedence to IndexGetters.



Re: Storage 'length' and enumeration

2009-04-29 Thread Sean Hogan

Ian Hickson wrote:


There are lots of objects that are not arrays (or should not be rendered 
as arrays) and yet have length. Collections, TimeRanges, select 
elements, Window objects, History, CanvasPixelArrays, etc.


  
I'm not sure about all those objects, but my (incomplete) testing of 
HTML*Collections indicates that when accessed using array notation:

   object[index]; where index  object.length
they behave as a readonly array. Which has the fortuitous by-product of 
allowing the object to work with Array.forEach(), etc.


Storage objects have a length property and can be accessed with array 
notation. They look like they should work with Array generic methods... 
and they do... except they aren't reliable if you use numeric keys... 
but they don't even give an error message.



I would suggest one of:
1. When accessed as an array they are treated as a readonly array. i.e. 
MUST use getItem(), setItem() for numeric keys
2. Treat it as an associative array. Change the name of the length 
property.





Re: DOM3 Events call today/tonight?

2009-02-25 Thread Sean Hogan

Charles McCathieNevile wrote:
On Wed, 25 Feb 2009 22:59:06 +0100, Sean Hogan 
shogu...@westnet.com.au wrote:



Garrett Smith wrote:

It might be worth discussing the load event;
http://www.w3.org/TR/DOM-Level-3-Events/events.html#event-load

Seems that it is specified to fire on Document or Element (instead
of window).


I would also suggest a progress event on document or window.
Ideally it would be triggered every 100ms during page-load.


I would suggest that the editor of the progress spec get back to 
dealing with the last issues raised by Ian, but he is writing this 
email :)
Sorry, I don't understand. Is the progress spec anticipated to augment 
DOM-3-Events for HTMLDocument and Window?




However the issue of timing is an interesting one. I am not sure how 
handy it is to expect a particular frequency, since it will vary 
pretty wildly depending on networks as well as other stuff. As a data 
point, I am told that while Australian broadband connections manage to 
deliver on average almost 2/3 of their advertised speed, which is a 
relatively good correspondence although advertised speeds for things 
people pay for are often are often pretty low, in terms of connections 
to actual offshore services they are getting something like 1/8. So 
you would get small progress over a long time.


The basis for the 100ms event interval is related to the rendering of 
new content on the web-page. If new content has arrived then scripts 
should be able to munge it before it is rendered, or at least soon 
afterwards. It doesn't matter how much content has arrived.
When you emit an event it is pretty low cost. But when you deal with a 
javascript that listens for that event and then does something else, 
it is more expensive - and when that starts to eat the battery of your 
mobile phone, maybe 10 times a second is more than people want.


Anyway, I leave the issue of whether to request user agents to make a 
particular timing available to the specs that use progress events, 
although I have reservations about the wisdom of conditioning authors 
to expect things just because broadband in a few countries can deliver 
them easily.



I should raise this as a request for HTML5.




Re: [cors] ACTION-11 API use cases

2009-02-10 Thread Sean Hogan


I don't think the presented XBL use case is valid:

An XBL binding allows full access to the document it is bound to and 
therefore cross-origin XBL usage is prohibited. The resource sharing 
policy enables cross-origin XBL bindings. If the user is authenticated 
with the server that hosts the XBL widget it is possible to have a 
user-specific cross-origin  bindings.


I'm not sure whether an XBL binding allows full access to the document 
it is bound to is talking about accessing the DOM of the bound-document 
or the binding-document, but I don't think either case requires 
access-control.


I don't see where the XBL spec says that the bound-document must have 
access to the binding-document, so I don't understand why cross-origin 
restrictions would apply.


And I don't understand why we should prohibit the XBL binding having 
access to the bound-document. That's the whole point of XBL, and we 
already have the same situation with script src. If you don't trust 
the XBL bindings then don't reference them, just like with scripts.






Anne van Kesteren wrote:


I took a stab at ACTION-11 which is currently assigned to Maciej:

  http://www.w3.org/2008/webapps/track/actions/11
  http://dev.w3.org/2006/waf/access-control/#use-cases

If this is good enough I suggest we close the action.







Re: [cors] ACTION-11 API use cases

2009-02-10 Thread Sean Hogan


Anne van Kesteren wrote:
On Tue, 10 Feb 2009 13:00:35 +0100, Sean Hogan 
shogu...@westnet.com.au wrote:

I don't think the presented XBL use case is valid:

An XBL binding allows full access to the document it is bound to and 
therefore cross-origin XBL usage is prohibited. The resource sharing 
policy enables cross-origin XBL bindings. If the user is 
authenticated with the server that hosts the XBL widget it is 
possible to have a user-specific cross-origin  bindings.


I'm not sure whether an XBL binding allows full access to the 
document it is bound to is talking about accessing the DOM of the 
bound-document or the binding-document, but I don't think either case 
requires access-control.


I don't see where the XBL spec says that the bound-document must have 
access to the binding-document, so I don't understand why 
cross-origin restrictions would apply.


And I don't understand why we should prohibit the XBL binding having 
access to the bound-document. That's the whole point of XBL, and we 
already have the same situation with script src. If you don't trust 
the XBL bindings then don't reference them, just like with scripts.


That example is based on

  http://www.w3.org/TR/2007/CR-xbl-20070316/#security

and maybe some discussion with Ian regarding this. It's been a while.

Does that help?


Ok, I can see that the use case is consistent with what is in the XBL 
spec. I prefer the following wording:


A XBL binding allows the document to which it is bound to have full 
access to the document in which it is defined; therefore cross-origin 
XBL usage is prohibited.


I disagree with the security context of a XBL document being the bound 
document, but that isn't relevant to this thread.





Re: Seeking implementation status of XBL2

2009-02-09 Thread Sean Hogan


There are a few active JS implementation projects:

xbl.googlecode.com, see http://code.google.com/p/xbl/wiki/Features

dojo.E has some support, see: 
http://blog.nexaweb.com/post/xbl-support-for-all-browsers-via-dojoe/


XBLUI, see: http://meekostuff.net/projects/XBLUI/status.html

XBLUI (my project) doesn't implement templates / shadow-trees yet.

cheers,
Sean


Arthur Barstow wrote:

Hi All,

The W3C's XBL2 Candidate spec [1] was published almost two years ago. 
Since then, there has been some implementation activity reported (e.g. 
[2],[3]) but nothing recently.


Does anyone have XBL2 implementation status they can share with us?

-Regards, Art Barstow

[1] http://www.w3.org/TR/2007/CR-xbl-20070316/
[2] 
http://lists.w3.org/Archives/Public/public-appformats/2007Dec/0053.html
[3] 
http://lists.w3.org/Archives/Public/public-appformats/2007Nov/0041.html


 
___

dev-tech-xbl mailing list
dev-tech-...@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-tech-xbl






Re: Call for Consensus - Selectors Last Call

2008-12-06 Thread Sean Hogan


Gregory Reimer (the author of reglib) points out that 
Element.matchesSelector would be useful for event delegation.

See http://blogs.sun.com/greimer/entry/opera_10_will_suport_selector

It would also neatly tie in with NodeFilter in DOM-Traversal, 
facilitating something like a live querySelectorAll() during document load.


Unfortunately I had assumed it was in the spec. I've looked now and seen 
that it wasn't considered due to a lack of presented use cases, which 
seems non-sensical. matchesSelector() is to querySelectorAll() as 
tagName is to getElementsByTagName(). The only reason for it not to be 
in the spec is if it is harmful.


The only complication I can see is supporting the :scope pseudo-attribute.

cheers,
Sean


Charles McCathieNevile wrote:


Hi,

Lachy thinks the latest editor's draft[1] is ready for Last Call, 
after responding to all the comments from last time (and removing the 
NSResolver). The disposition of comments[2] explains what happened to 
those comments.


So this is a call for Consensus to publish the Editor's Draft [1] of 
the Selectors API spec as a Last Call. Please respond before Monday 
November 10. As always, silence is taken as assent but an explicit 
response is preferred.


Opera supports publication of this draft as a Last Call.

[1] http://dev.w3.org/2006/webapi/selectors-api/
[2] 
http://dev.w3.org/2006/webapi/selectors-api/disposition-of-comments.html


cheers

Chaals