Re: [Selectors API 2] Is matchesSelector stable enough to unprefix in implementations?
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?
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
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?
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?
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?
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?
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?
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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?
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?
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?
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?
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?
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?
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?
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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?
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
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
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
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
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