Re: [admin] Should WebApps' HTML Templates spec be published as a WG Note?
SGTM On Tue, Mar 11, 2014 at 9:38 AM, Yves Lafon yla...@w3.org wrote: On Fri, 7 Mar 2014, Arthur Barstow wrote: On 2/27/14 12:10 PM, ext Arthur Barstow wrote: On 2/27/14 11:41 AM, ext Rafael Weinstein wrote: What do you recommend? It seems a little heavy-handed to kill it or gut it. What about putting a big-red warning at the top that it has been merged to HTML and no longer has normative weight. I don't have a strong preference now and would like to hear from others. The above do have different +/-. I think the principle of least surprise (`follow your nose`) indicates navigating to the ED would redirect to the HTML spec. It seems like the worst case scenario is for the contents of the ED to be inconsistent with HTML. Rafael, All - having received no additional feedback and only voices of support for publishing a WG Note, the main questions seem to be: 1) whether the Note should be gutted (f.ex. see [1]) or not; 2) should the ED be gutted too. Although I agree gutting the Note would be a bit heavy-handed as you say, it does eliminate the possibility of the contents being different than HTMLWG's version. As such, I prefer gutting both the Note and the ED and adding a prominent warning plus a link to HTML. For example, borrowing from [1], adding something like to the Status of This Document section: [[ strongWork on this document has been discontinued and it should not be referenced or used as a basis for implementation. The features previously specified in this document are now specified in a href= http://www.w3.org/TR/html5/scripting-1.html#the-template-element HTML5/a./strong ]] WDYT? SGTM, not gutting it has a higher risk of people looking at the wrong doc. -- Baroula que barouleras, au tiéu toujou t'entourneras. ~~Yves
Re: [admin] Should WebApps' HTML Templates spec be published as a WG Note?
On Wed, Mar 12, 2014 at 8:48 AM, Arthur Barstow art.bars...@nokia.comwrote: On 3/12/14 10:27 AM, ext Rafael Weinstein wrote: SGTM On Tue, Mar 11, 2014 at 9:38 AM, Yves Lafon yla...@w3.org mailto: yla...@w3.org wrote: On Fri, 7 Mar 2014, Arthur Barstow wrote: On 2/27/14 12:10 PM, ext Arthur Barstow wrote: [[ strongWork on this document has been discontinued and it should not be referenced or used as a basis for implementation. The features previously specified in this document are now specified in a href=http://www.w3.org/TR/html5/scripting-1.html#the- template-elementHTML5/a./strong ]] WDYT? SGTM, not gutting it has a higher risk of people looking at the wrong doc. OK, then unless I hear otherwise, at the end of this week I'll create a draft WG Note that is gutted and includes the info above (and put the draft Note in https://dvcs.w3.org/hg/webcomponents/file/default/ publish/template/). I'll target a publication of March 18. Rafael - I will plan to update the ED too so please let me know if you prefer to do that. Go for it. Thanks for getting this cleaned up. -Thanks, ArtB
Re: [admin] Should WebApps' HTML Templates spec be published as a WG Note?
What do you recommend? It seems a little heavy-handed to kill it or gut it. What about putting a big-red warning at the top that it has been merged to HTML and no longer has normative weight. On Thu, Feb 27, 2014 at 7:27 AM, Arthur Barstow art.bars...@nokia.comwrote: On 2/26/14 9:43 AM, ext Arthur Barstow wrote: Hi Robin, Dimitri, All, Since HTML Templates is now part of HTML5, to help avoid confusion, I think WebApps' last TR of the spec ([html-templates]) should be replaced with a WG Note that clearly indicates WebApps' work on the standalone spec has stopped and the feature is now part of HTML5. (The Note could also be void of any technical substance as DAP recently did f.ex. [contacts-api]). Dimitri, Rafael, Tony - there is also a question about the contents of the HTML Templates [ED]. What are you planning to do with it (delete it; remove the guts and link to HTML(5); something else)? -Art [ED] http://dvcs.w3.org/hg/webcomponents/raw-file/tip/ spec/templates/index.html WDYT? Any objections? (If we agree to publish a WG Note, I'll create it). -Thanks, AB [html-templates] http://www.w3.org/TR/html-templates/ [contacts-api] http://www.w3.org/TR/contacts-api/
Re: [admin] Should WebApps' HTML Templates spec be published as a WG Note?
No objections. It may be useful to mention in the note that the Template spec was merged to HTML (as opposed to simply becoming a concern of HTML, which might raise the question did HTML do something different than what this spec used to say?). On Wed, Feb 26, 2014 at 12:25 PM, Ryosuke Niwa rn...@apple.com wrote: Sounds great to me. On Feb 26, 2014, at 6:43 AM, Arthur Barstow art.bars...@nokia.com wrote: Hi Robin, Dimitri, All, Since HTML Templates is now part of HTML5, to help avoid confusion, I think WebApps' last TR of the spec ([html-templates]) should be replaced with a WG Note that clearly indicates WebApps' work on the standalone spec has stopped and the feature is now part of HTML5. (The Note could also be void of any technical substance as DAP recently did f.ex. [contacts-api]). WDYT? Any objections? (If we agree to publish a WG Note, I'll create it). -Thanks, AB [html-templates] http://www.w3.org/TR/html-templates/ [contacts-api] http://www.w3.org/TR/contacts-api/
Re: Extending Mutation Observers to address use cases of
I pushed the Web Components folks about exactly this issue (why aren't these callbacks just MutationObservers?) early last year. They convinced me (and I remain convinced) that these signals should be Custom Element callbacks and not Mutation Observer records Here's the logic that convinced me: Custom Element are a *strongly coupled concern*, while Mutation Observers *allow for* multiple decoupled concerns to peacefully co-exist. In a certain sense, you can extend the argument that CE callbacks should be MO records, and you arrive at the conclusion that you don't need Custom Elements at all -- that everything can be implemented with Mutation Observers. But the point of Custom Elements is two fold: 1) To allow implementation of Elements by user-space code in roughly the same model as privileged code. 2) To explain the platform. Put another way: the *implementation* of an element simply needs to be privileged in some respects. For custom elements, this means a) There can only be one. I.e., we don't allow multiple registration of the same element: Primary behavior is the domain of custom elements, secondary behavior is the domain of Mutation Observers b) Callbacks need to fire ASAP. It's important that the implementation of an element get a chance to respond to events before other concerns so that it can create a synchronously consistent abstraction To my mind, Custom Elements callbacks really *should* be fully sync (yes, including firing createdCallback during parse), but various technical and security constraints make that impossible. In short, Custom Elements and Mutation Observers are servicing very different needs. Custom Elements are privileged, but limited and singular (I can only react to changes in myself and I'm the only responding party), while Mutation Observers are unprivileged, pervasive and multiple (I get to respond to anything in the document, and there are likely other parties doing work in the same place I am). Therefore, it is neither a good idea to make Custom Elements more async, nor a good idea to make Mutation Observers more sync. --- One final note. UNRELATED to custom elements' implementation. I think there's an argument to be made that Mutation Observers *should* be extended to allow for observation of trees which include DOM reachable through shadowRoots. The motivation for this would be to allow existing de-coupled concerns to operate faithfully in the presence of custom elements implemented with shadowDOM. The obvious concern here is that de-coupled code may interfere with the implementation of elements, but that's no more true with custom elements than it is today, and shadowRoot is imperatively public, it's consistent to allow MutationObservers to continue to fully observe a document. However, I don't think there's any rush to do this. Just something to think about for a post-shadowDOM world. On Wed, Feb 12, 2014 at 4:49 AM, Olli Pettay olli.pet...@helsinki.fiwrote: On 02/12/2014 04:27 AM, Ryosuke Niwa wrote: On Feb 11, 2014, at 6:06 PM, Bjoern Hoehrmann derhoe...@gmx.net wrote: * Olli Pettay wrote: We could add some scheduling thing to mutation observers. By default we'd use microtask, since that tends to be good for various performance reasons, but normal tasks or nanotasks could be possible too. Right, we need some sort of a switch. I'm not certain if we want to add it as a per-observation option or a global switch when we create an observer. My guy feeling is that we want the latter. It would be weird for some mutation records to be delivered earlier than others to the same observer. Yeah, I was thinking per observer. Something like var m = new MutationObserver(callback, { interval: task} ); m.observe(document, { childList: true, subtree: true}); Some devtools devs have asked for adding 'interval: nanotask' thing I was thinking to add such thing only for addons and such in Gecko, because it brings back some of the performance problems Mutation Events have. But if web components stuff would be less special with such option, perhaps it should be enabled for all. -Olli I'd like to know exact semantics requirements before start jumping into details though. This sounds like adding a switch that would dynamically invalidate assumptions mutation observers might make, which sounds like a bad idea. Could you elaborate? I don't really follow what the problem is. Could you elaborate on what you see as a problem? - R. Niwa
Re: [webcomponents] Auto-creating shadow DOM for custom elements
On Sat, Dec 7, 2013 at 3:01 PM, Brian Di Palma off...@gmail.com wrote: From your email it seems you can still achieve everything you can with custom elements when not using them, it would just involve more code/boilerplate. So custom elements without shadow dom or templates are syntactic sugar No. Custom elements (even without templates shadowdom) creates a mechanism where the implementation of elements can *reliably* be bound to all instances of that element. Angular depends on having access to all html so it can compile it (Domenics example of innerHTML shows the counter example). DOM inside the shadow will be undiscoverable by Angular -- and even Mutation Observers (to Ryosuke's point earlier). A central goal here is *composability* of elements. E.g: -I can author components without needing to require that consumers of them use a particular framework -I can author a page which is comprised of the best-of-breed components (full stop). Not best-of-breed components designed to work within X framework. they don't enable functionality that is impossible currently? They make it much nicer and I really like it but I can manage without it and not be too stressed. Much like classes in ES6, they're great sugar but we've been able to do classes in JS since forever. I'm sure Brick is great and it looks lovely but no one in my work place is excited about it. Web Components in it's entirety though is a different matter and we are looking forward to them. Splitting it up into separate specs is good, but it's clear they combine with each other. Making it easy and painless to combine them seems like common sense. On Sat, Dec 7, 2013 at 10:37 PM, Domenic Denicola dome...@domenicdenicola.com wrote: From: Brian Di Palma [mailto:off...@gmail.com] Are they appreciatively more powerful then just building Angular directives though? Do they enable any functionality that you could not access without the custom elements spec? Yes. There are at least two major benefits that I can see: 1) They allow you to create new HTMLElement-derived interfaces which are associated with the custom elements, so that you can do e.g. `document.querySelector(x-flipbox).toggle()` or `document.querySelector(x-flipbox).flipped` and so on. 2) They alert the parser of this new element, so that if you do `document.body.innerHTML = x-flipboxdivFront/divdivBack/div/x-flipbox`, this will be appropriately parsed so as to create a new flipbox with the associated behavior and interface. This effectively allows you to use the web's native widget abstraction, e.g. elements, instead of inventing your own. With something like jQuery UI or Angular, you need to access properties and methods through arcane invocations, e.g. $(document.querySelector(.my-slider)).slider(option, disabled, false); instead of document.querySelector(.my-slider).disabled = false; And if you add new elements via innerHTML, you'll have to do $(elementThatHadItsInnerHTMLChanged).find(.make-me-a-slider).slider(); to add the slider behavior, since there is no parser hook. (As for the Angular comparison, Angular tries to push you toward manipulating controllers and $scope objects, and never touching the DOM or DOM-esque widgets directly, so it's hard to really make such a comparison. Angular, more so than Polymer, seems to me like a good unifying cowpath to pave in the future.)
Re: [webcomponents] Auto-creating shadow DOM for custom elements
On Sat, Dec 7, 2013 at 6:56 PM, Ryosuke Niwa rn...@apple.com wrote: On Dec 7, 2013, at 3:53 PM, Rafael Weinstein rafa...@google.com wrote: The issue is that being an element and having shadow DOM -- or any display DOM, for that matter -- are orthogonal concerns. There are lots of c++ HTML elements that have no display DOM. Polymer already has an even larger number. While that's true in browser implementations, there is very little authors can do with a plain element without any shadow content it since JavaScript can't implement it's own style model (i.e. creating a custom frame object in Gecko / render object in WebKit/Blink) or paint code in JavaScript. If the only customization author has to do is adding some CSS, then we don't need custom element hook at all. I'm was thinking about elements whose purpose isn't presentational. For example, link or script in html, or polymer-ajax in polymer. It's true that mutation observers wouldn't run immediately after innerHTML if authors wanted to add some JS properties but we could fix that issue in some other way; e.g. by delivering mutation records every time we run a parser. - R. Niwa
Re: [webcomponents] HTML Imports
On Wed, Dec 4, 2013 at 10:37 AM, Dimitri Glazkov dglaz...@chromium.orgwrote: On Wed, Dec 4, 2013 at 9:56 AM, Dimitri Glazkov dglaz...@chromium.orgwrote: On Wed, Dec 4, 2013 at 4:32 AM, Anne van Kesteren ann...@annevk.nlwrote: On Wed, Dec 4, 2013 at 9:21 AM, Brian Di Palma off...@gmail.com wrote: I would say though that I get the feeling that Web Components seems a specification that seems really pushed/rushed and I worry that might lead to some poor design decisions whose side effects will be felt by developers in the future. I very much share this sentiment. It's a very reasonable and normal worry to have. I lose sleep over this worry all the time. The trick that helps me is balancing it out with the sadness of the geological timescale that it takes for Web platform to advance. Just to help visualize the geological timescale, the work on Web Components began in late 2010 ( http://wiki.whatwg.org/index.php?title=Component_Model_Use_Casesoldid=5631), and was chartered in this WG over 2 years ago ( http://www.w3.org/2008/webapps/wiki/CharterChanges#Additions_Agreed). To clarify my previous email: Web Components is an extremely hard problem with lots of constraints, and a concern would be that we miss some bits is totally fair. Qualifying this work as pushed/rushed probably ain't. I'd like to make an aside about having respect for one-another's work. Dimitri, Alex, Dominic, Scott, Elliot and many others have put massive time into this problem over the course of many years now, and my view is that the design has evolved and accommodated a dizzying number of challenges and constraints. What this is attempting is big scary is fair. I haven't had time to digest the design is fair. I have the following specific issues is fair. This work is rushed is always understood as an indictment. I've seen too many talented people vote with their feet and decide life will be less frustrating working on a closed system. Let's remember we're all on the same team. AFAICT, evolving the web is fundamentally an exercise in not letting perfect be the enemy of good. I have no doubt Web Components is imperfect, but from what I can tell, it is *extremely* good. Also, go hug your mother. :DG
Re: [webcomponents] HTML Imports
On Mon, Oct 7, 2013 at 3:24 AM, James Graham ja...@hoppipolla.co.uk wrote: On 06/10/13 17:25, Dimitri Glazkov wrote: And, if the script is executed against the global/window object of the main document, can and should you be able to access the imported document? You can and you should. HTML Imports are effectively #include for the Web. Yes, that sounds like a good description of the problem :) It is rather noticable that no one making programming languages today replicates the #include mechanism, and I think html-imports has some of the same design flaws that makes #include unpopular. I think authors will find it very hard to write code in an environment where simple functions like document.getElementById don't actually work on the document containing the script, but on some other document that they can't see. It also seems that the design requires you to be super careful about having side effects; if the author happens to have a non-idempotent action in a document that is imported, then things will break in the relatively uncommon case where a single document is imported more than once. We have an orthogonal mechanism for preventing side-effects: The HTML Template Element. Imports do not prevent side-effects implicitly. This is Good. Authors have control over the semantics they need. Want to include some DOM -- use imports, need some fragment of that to not have side effects -- put it in a template. Overall it feels like html imports has been designed as an over general mechanism to address certain narrow use cases and, in so doing, has handed authors a footgun. Whilst I don't doubt it is usable by the highly competent people who are working at the bleeding edge on polyfilling components, the rest of the population can't be expected to understand the implemetation details that seem to have led the design in this direction. I think it would be useful to go right back to use cases here and work out if we can't design something better.
Re: should mutation observers be able to observe work done by the html parser
Yup. Not sure where this is in W3C DOM, but 12.2.5.1 Creating and inserting nodes (http://www.whatwg.org/specs/web-apps/current-work/) ... DOM mutation events must not fire for changes caused by the UA parsing the document. This includes the parsing of any content inserted using document.write() and document.writeln() calls. [DOMEVENTS] However, mutation observers do fire, as required by the DOM specification. ... On Mon, Sep 16, 2013 at 8:13 AM, Brian Kardell bkard...@gmail.com wrote: was therw ever agreement on this old topic? http://lists.w3.org/Archives/Public/public-webapps/2012JulSep/0618.htmlwhether by de facto implementation or spec agreements? I am not seeing anything in the draft but maybe i am missing it...
Re: [webcomponents]: Platonic form of custom elements declarative syntax
FWIW, I think it's a design mistake to make element registration a concern of template. I'd be more persuaded by the developer ergonomics argument if this was a cost that was incurred with the usage of custom elements, but it's not. It's only incurred with the element definition. Separately, I may have missed it, but it seems to me that allowing custom elements to stamp out light DOM is a new semantic, that isn't obviously solving a problem which is either identified, or related to web components. Did I miss earlier discussion about this? On Wed, Apr 10, 2013 at 12:40 PM, Scott Miles sjmi...@google.com wrote: No, strictly ergonomic. Less nesting and less characters (less nesting is more important IMO). I would also argue that there is less cognitive load on the author then the more explicit factoring, but I believe this is subjective. Scott On Wed, Apr 10, 2013 at 12:36 PM, Rafael Weinstein rafa...@google.com wrote: On Wed, Apr 10, 2013 at 11:47 AM, Dimitri Glazkov dglaz...@google.com wrote: Dear Webappsonites, There's been a ton of thinking on what the custom elements declarative syntax must look like. Here, I present something has near-ideal developer ergonomics at the expense of terrible sins in other areas. Consider it to be beacon, rather than a concrete proposal. First, let's cleanse your palate. Forget about the element element and what goes inside of it. Eat some parsley. == Templates Bound to Tags == Instead, suppose you only have a template: template divYay!/div /template Templates are good for stamping things out, right? So let's invent a way to _bind_ a template to a _tag_. When the browser sees a tag to which the template is bound, it stamps the template out. Like so: 1) Define a template and bind it to a tag name: template bindtotagname=my-yay divYay!/div /template 2) Whenever my-yay is seen by the parser or createElement/NS(my-yay) is called, the template is stamped out to produce: my-yay divYay!/div /my-yay Cool! This is immediately useful for web developers. They can transform any markup into something they can use. Behind the scenes: the presence of boundtotagname triggers a call to document.register, and the argument is a browser-generated prototype object whose readyCallback takes the template and appends it to this. == Organic Shadow Trees == But what if they also wanted to employ encapsulation boundaries, leaving initial markup structure intact? No problem, much-maligned shadowroot to the rescue: 1) Define a template with a shadow tree and bind it to a tag name: template bindtotagname=my-yay shadowroot divYay!/div /shadowroot /template 2) For each my-yay created, the template is stamped out to create a shadow root and populate it. Super-cool! Note, how the developer doesn't have to know anything about Shadow DOM to build custom elements (er, template-bound tags). Shadow trees are just an option. Behind the scenes: exactly the same as the first scenario. == Declarative Meets Imperative == Now, the developer wants to add some APIs to my-yay. Sure, no problem: template bindtotagname=my-yay shadowroot divYay!/div /shadowroot script runwhenbound // runs right after document.register is triggered this.register(ExactSyntaxTBD); script /template So-cool-it-hurts! We built a fully functional custom element, taking small steps from an extremely simple concept to the full-blown thing. In the process, we also saw a completely decoupled shadow DOM from custom elements in both imperative and declarative forms, achieving singularity. Well, or at least a high degree of consistence. == Problems == There are severe issues. The shadowroot is turning out to be super-magical. The bindtotagname attribute will need to be also magical, to be consistent with how document.register could be used. The stamping out, after clearly specified, may raise eyebrows and turn out to be unintuitive. Templates are supposed to be inert, but the whole script runwhenbound thing is strongly negating this. There's probably more that I can't remember now. The following expresses the same semantics: element tagname=my-yay template shadowroot divYay!/div /shadowroot /template script runwhenbound /script /element I get that your proposal is fewer characters to type. Are there other advantages? == Plea == However, I am hopeful that you smart folk will look at this, see the light, tweak the idea just a bit and hit the homerun. See the light, dammit! :DG
Re: [webcomponents]: Platonic form of custom elements declarative syntax
On Wed, Apr 10, 2013 at 2:45 PM, Rafael Weinstein rafa...@google.com wrote: FWIW, I think it's a design mistake to make element registration a concern of template. Sorry. I over-stated my conviction here. Let me walk that back: I'm not yet hearing sufficient justification for making element registration a concern of template I'd be more persuaded by the developer ergonomics argument if this was a cost that was incurred with the usage of custom elements, but it's not. It's only incurred with the element definition. Separately, I may have missed it, but it seems to me that allowing custom elements to stamp out light DOM is a new semantic, that isn't obviously solving a problem which is either identified, or related to web components. Did I miss earlier discussion about this? On Wed, Apr 10, 2013 at 12:40 PM, Scott Miles sjmi...@google.com wrote: No, strictly ergonomic. Less nesting and less characters (less nesting is more important IMO). I would also argue that there is less cognitive load on the author then the more explicit factoring, but I believe this is subjective. Scott On Wed, Apr 10, 2013 at 12:36 PM, Rafael Weinstein rafa...@google.com wrote: On Wed, Apr 10, 2013 at 11:47 AM, Dimitri Glazkov dglaz...@google.com wrote: Dear Webappsonites, There's been a ton of thinking on what the custom elements declarative syntax must look like. Here, I present something has near-ideal developer ergonomics at the expense of terrible sins in other areas. Consider it to be beacon, rather than a concrete proposal. First, let's cleanse your palate. Forget about the element element and what goes inside of it. Eat some parsley. == Templates Bound to Tags == Instead, suppose you only have a template: template divYay!/div /template Templates are good for stamping things out, right? So let's invent a way to _bind_ a template to a _tag_. When the browser sees a tag to which the template is bound, it stamps the template out. Like so: 1) Define a template and bind it to a tag name: template bindtotagname=my-yay divYay!/div /template 2) Whenever my-yay is seen by the parser or createElement/NS(my-yay) is called, the template is stamped out to produce: my-yay divYay!/div /my-yay Cool! This is immediately useful for web developers. They can transform any markup into something they can use. Behind the scenes: the presence of boundtotagname triggers a call to document.register, and the argument is a browser-generated prototype object whose readyCallback takes the template and appends it to this. == Organic Shadow Trees == But what if they also wanted to employ encapsulation boundaries, leaving initial markup structure intact? No problem, much-maligned shadowroot to the rescue: 1) Define a template with a shadow tree and bind it to a tag name: template bindtotagname=my-yay shadowroot divYay!/div /shadowroot /template 2) For each my-yay created, the template is stamped out to create a shadow root and populate it. Super-cool! Note, how the developer doesn't have to know anything about Shadow DOM to build custom elements (er, template-bound tags). Shadow trees are just an option. Behind the scenes: exactly the same as the first scenario. == Declarative Meets Imperative == Now, the developer wants to add some APIs to my-yay. Sure, no problem: template bindtotagname=my-yay shadowroot divYay!/div /shadowroot script runwhenbound // runs right after document.register is triggered this.register(ExactSyntaxTBD); script /template So-cool-it-hurts! We built a fully functional custom element, taking small steps from an extremely simple concept to the full-blown thing. In the process, we also saw a completely decoupled shadow DOM from custom elements in both imperative and declarative forms, achieving singularity. Well, or at least a high degree of consistence. == Problems == There are severe issues. The shadowroot is turning out to be super-magical. The bindtotagname attribute will need to be also magical, to be consistent with how document.register could be used. The stamping out, after clearly specified, may raise eyebrows and turn out to be unintuitive. Templates are supposed to be inert, but the whole script runwhenbound thing is strongly negating this. There's probably more that I can't remember now. The following expresses the same semantics: element tagname=my-yay template shadowroot divYay!/div /shadowroot /template script runwhenbound /script /element I get that your proposal is fewer characters to type. Are there other advantages? == Plea == However, I am hopeful that you smart folk will look at this, see the light, tweak the idea just a bit and hit the homerun. See the light, dammit
Re: [webcomponents]: Re-imagining shadow root as Element
FWIW (and I'm not sure if this is good or bad) it would be consistent with the template element if -shadowroot serialized by default with innerHTML -shadowroot, when parsed is lifted and pushed onto the parent element's shadowroot stack -appendChild(shadowroot) doesn't throw, but doesn't do what you probably want (e.g. shadowroot is simply display:none if not attached to a host). (I imagine there would be imperative API on element, so that the correct imperative operation was to directly push a new shadowroot() onto an element, rather than using appendChild. Of course, if serialization round-tripping is non-lossy, this raises the question about implicit shadow roots (i.e. the element is registered and *creates* its shadowroots whenever it is created). On Mon, Mar 18, 2013 at 2:38 PM, Scott Miles sjmi...@google.com wrote: Sorry if I'm clobbering this thread, I promise to stop after this, but I solved my own mental model. Namely, I decide to treat shadowroot like outerHTML. If I define (pseudo): div id=A shadowroot span id=B shadowroot ... The A.innerHTML == span id=Bshadowroot... I don't see A's shadowroot, because it's really part of it's outer-ness. It's part of what makes A, it's not part of A's content. Now I can send A's innerHTML to B with no problem. Or roundtrip A's content with no problem. I realize I've broken several standard laws, but in any event it seems consistent to itself. On Mon, Mar 18, 2013 at 2:08 PM, Scott Miles sjmi...@google.com wrote: Ok, well obviously, there are times when you don't want the shadowroot to be in innerHTML, so I was correct that I was grossly over simplifying. I guess this is where the second kind of innHTML accessor comes in. Sorry! It's still A though. :) On Mon, Mar 18, 2013 at 2:05 PM, Scott Miles sjmi...@google.com wrote: I'm already on the record with A, but I have a question about 'lossiness'. With my web developer hat on, I wonder why I can't say: div id=foo shadowroot shadow stuff /shadowroot light stuff /div and then have the value of #foo.innerHTML still be shadowroot shadow stuff /shadowroot lightstuff I understand that for DOM, there is a wormhole there and the reality of what this means is new and frightening; but as a developer it seems to be perfectly fine as a mental model. We web devs like to grossly oversimplify things. :) Scott On Mon, Mar 18, 2013 at 1:53 PM, Dimitri Glazkov dglaz...@google.com wrote: Last Friday, still energized after the productive Mozilla/Google meeting, a few of us (cc'd) dug into Shadow DOM. And boy, did that go south quickly! But let's start from the top. We puzzled over the the similarity of two seemingly disconnected problems: a) ShadowRoot is a DocumentFragment and not an Element, and b) there is no declarative way to specify shadow trees. The former is well-known (see http://lists.w3.org/Archives/Public/public-webapps/2013JanMar/thread.html#msg356). The latter came into view very early as a philosophical problem (provide declarative syntax for new imperative APIs) and much later as a practical problem: many modern apps use a freeze-drying performance technique where they load as-rendered HTML content of a page on immediately (so that the user sees content immediately), and only later re-hydrate it with script. With shadow DOM, the lack of declarative syntax means that the content will not appear as-rendered until the script starts running, thus ruining the whole point of freeze-drying. We intentionally stayed away from the arguments like well, with custom elements, all of this happens without script. We did this precisely because we wanted to understand what all of this happens actually means. Trapped between these two problems, we caved in and birthed a new element. Let's call it shadowroot (Second Annual Naming Contest begins in 3.. 2.. ). This element _is_ the ShadowRoot. It's deliciously strange. When you do div.appendChild(document.createElement('shadowroot')), the DOM: 0) opens a magic wormhole to the land of rainbows and unicorns (aka the Gates of Hell) 1) adds shadowroot at the top of div's shadow tree stack This behavior has three implications: i) You can now have detached ShadowRoots. This is mostly harmless. In fact, being able to prepare ShadowRoot instances before adding them to a host seems like a good thing. ii) ShadowRoot never appears as a child of an element. This is desired original behavior. iii) Parsing HTML with shadowroot in it results in loss of data when round-tripping. This is hard to swallow, but one can explain it as a distinction between two trees: a document tree and a composed tree. When you invoke innerHTML, you get a document tree. When you invoke (yet to be invented) innerComposedHTML, you get composed tree. Alternatively, we could just make appendChild/insertBefore/etc. throw and make special rules for
Re: [webcomponents]: Making Shadow DOM Subtrees Traversable
So the two camps in the this argument seem to be arguing largely philosophical views. It's clear that Mozilla has experienced pain via plugins having access to browser internals. I'm curious if jQuery or others have experienced feeling restricted because apps are depending on internals by way of having access to them via monkey-patching It seems to me like if public-by-default was a design mistake on the web, it'd be pretty clearly in evidence already. Is it? On Tue, Feb 26, 2013 at 1:08 PM, Boris Zbarsky bzbar...@mit.edu wrote: On 2/26/13 3:56 PM, Dominic Cooney wrote: One more thought occurs to me: It is easier to add public shadows in a subsequent revision of the spec than it is to take public shadows away. Yes, indeed. That's one of the main reasons I'd like it to be the initial default... I would certainly be completely against shipping anything that does not provide private shadows at all, of course. -Boris
Re: [webcomponents] Making the shadow root an Element
On Tue, Feb 19, 2013 at 11:42 PM, Jonas Sicking jo...@sicking.cc wrote: On Tue, Feb 19, 2013 at 12:24 PM, Rafael Weinstein rafa...@google.com wrote: On Mon, Feb 18, 2013 at 12:06 PM, Jonas Sicking jo...@sicking.cc wrote: On Mon, Feb 18, 2013 at 1:48 AM, Anne van Kesteren ann...@annevk.nl wrote: On Sat, Feb 16, 2013 at 5:23 PM, Dimitri Glazkov dglaz...@google.com wrote: We were thinking of adding innerHTML to DocumentFragments anyway... right, Anne? Well I thought so, but that plan didn't work out at the end of the day. https://www.w3.org/Bugs/Public/show_bug.cgi?id=14694#c7 So given that consensus still putting it on ShadowRoot strikes me like a bad idea (as I think I've said somewhere in a bug). The same goes for various other members of ShadowRoot. I don't think there's a consensus really. JS authors were very vocal about needing this ability. Does anyone have a link to the strong case against adding explicit API for DF.innerHTML from Hixie that that comment refers to? Unfortunately that comment referred to an IRC discussion that took place last June on #whatwg. IIRC, Hixie's position was that adding more explicit API for innerHTML is a moral hazard because it encourages an anti-pattern. (Also IIRC), Anne and Henri both sided with Hixie at the time and the DF.innerHTML got left in a ditch. The discouraging that we're currently doing doesn't seem terribly effective. Developers seem to just grab/create a random element and set .innerHTML on that. So I think the current state of affairs is just doing a disservice to everyone, including ourselves. I agree, and this was my position at the time, FWIW. / Jonas
Re: [webcomponents] Making the shadow root an Element
On Mon, Feb 18, 2013 at 12:06 PM, Jonas Sicking jo...@sicking.cc wrote: On Mon, Feb 18, 2013 at 1:48 AM, Anne van Kesteren ann...@annevk.nl wrote: On Sat, Feb 16, 2013 at 5:23 PM, Dimitri Glazkov dglaz...@google.com wrote: We were thinking of adding innerHTML to DocumentFragments anyway... right, Anne? Well I thought so, but that plan didn't work out at the end of the day. https://www.w3.org/Bugs/Public/show_bug.cgi?id=14694#c7 So given that consensus still putting it on ShadowRoot strikes me like a bad idea (as I think I've said somewhere in a bug). The same goes for various other members of ShadowRoot. I don't think there's a consensus really. JS authors were very vocal about needing this ability. Does anyone have a link to the strong case against adding explicit API for DF.innerHTML from Hixie that that comment refers to? Unfortunately that comment referred to an IRC discussion that took place last June on #whatwg. IIRC, Hixie's position was that adding more explicit API for innerHTML is a moral hazard because it encourages an anti-pattern. (Also IIRC), Anne and Henri both sided with Hixie at the time and the DF.innerHTML got left in a ditch. It's also worth pointing out that if it was decided to have innerHTML on DF and on ShadowRoot, they would likely have subtly different semantics: -DF.innerHTML would parse exactly the way template.innerHTML does (using the 'implied context parsing). -SR.innerHTML would use its host as the context element and the output would be as if the input *had been* applied to host.innerHTML, then lifted out and attached to the SR. (I believe the later currently the case for ShadowRoot). / Jonas
Re: document.register and ES6
On Tue, Feb 5, 2013 at 3:25 PM, Boris Zbarsky bzbar...@mit.edu wrote: On 2/5/13 11:01 PM, Erik Arvidsson wrote: On Tue, Feb 5, 2013 at 5:28 PM, Boris Zbarsky bzbar...@mit.edu wrote: So in particular this allows creation of uninitialized instances in some sense, yes? Depends how much logic is put in the constructor vs @@create. For DOM Elements I think we want to put *all* the logic in create. OK, I can live with that as long as the only arguments are things like for Image. We'll have to be pretty careful about how we define our Element subclass constructors in the future, though... And there are knock-on effects on all other objects in WebIDL. See below. This won't work right given how HTMLButtonElement is currently defined in WebIDL. Need to fix that at the very least. Yes, but for document.register I think we can get away without changing this. No, you can't. You really need to get WebIDL fixed here. We might need to add no op call methods to these functions They already have [[Call]]. What they don't have is a custom [[Construct]]. Which means that they end up invoking the [[Construct]] defined in ES5 section 13.2.2, which in step 8 calls the [[Call]] and if that returns an object (which the WebIDL [[Call]] does) throws away the object that [[construct]] just created and returns the object [[Call]] returned. And you can't no-op the [[Call]] because web pages, afaik, use things like: var myImage = Image(); and var xhr = XMLHttpRequest(); just like they use Date() and Object() and Array(). The above is supported for DOM constructors in at least Gecko and Presto, though apparently not Chrome or Safari; I don't have IE to test right now. But the point is that right now those constructors are not particularly weird in Gecko and Presto, and I'm not entirely happy making them _more_ weird. Maybe the fact that Chrome and Safari don't support this means that we can in fact redefine the [[Construct]] to create the right sort of object and then invoke [[Call]] which will actually initialize the object. But that brings us back to being able to create partially-initialized objects for all IDL interfaces, not just elements Perhaps we need to define an IDL annotation for interfaces that opt in to this split between [[Call]] and [[Construct]] and then have elements opt in to it? but that seems like the right thing to do anyway. The WebIDL interface constructors are already strange as they are Not in Gecko and Presto as far as I can tell... Certainly not any stranger than Date or Array. and I doubt anyone would object to making them less strange. I have no problem with less strange, but you're proposing more strange. Again, as far as I can tell. What happens if the same function is registered for several different tag names, in terms of what happens with the [[Construct]]? I vote for throwing. We could allow the tag name to be used as an alias but I don't really understand the use case you have in mind here. I don't have a use case. What I have is an edge case that I can see implementations doing random non-interoperable crap for if we don't define it. Throwing sounds fine to me. Define, please. How does one determine this, in a rendering engine implementation? I certainly have no way to tell, in Gecko, when I'm entering script, offhand I was told this is needed for mutation observers that are queued up during parse. I'll let Dimitri or Rafael chime in with details. Ah, OK. Defining this stuff to happen at end of microtask or whatever it is that normally triggers mutation observers makes a lot more sense than before entering script. ;) http://www.whatwg.org/specs/web-apps/current-work/#parsing-main-incdata The first thing that happens upon encoutering /script is performing a microtask check point. I think Arv is suggesting that running custom element constructors would be included in this work. Thanks, Boris
Re: Review of the template spec
Note that the spec has moved to FPWD, all of the comments Henri raised have been addressed and WebKit TOT now contains a full implementation including tests. On Fri, Dec 21, 2012 at 1:31 PM, Rafael Weinstein rafa...@google.comwrote: On Fri, Dec 14, 2012 at 2:58 PM, Jonas Sicking jo...@sicking.cc wrote: On Fri, Dec 14, 2012 at 1:32 AM, Simon Pieters sim...@opera.com wrote: On Fri, 14 Dec 2012 00:04:20 +0100, Jonas Sicking jo...@sicking.cc wrote: On Tue, Dec 11, 2012 at 5:00 AM, Henri Sivonen hsivo...@iki.fi wrote: 1. If DOCUMENT does not have a browsing context, Let TEMPLATE CONTENTS OWNER be DOCUMENT and abort these steps. 2. Otherwise, Let TEMPLATE CONTENTS OWNER be a new Document node that does not have a browsing context. Is there a big win from this inconsistency? Why not always have a separate doc as the template contents owner? My goal was to *only* have one separate doc per normal doc. Consider the following: body div id=a template id=1 div id=b template id=2 div id=c template /template /body The if document does not have a browsing context part is needed by template 2 so its contents can be owned by the same document as template 1's contents. I.e. for each document with a browsing context, there is a single (lazily created) template contents owner which is shared by all templates reachable from the main document's documentElement. I'm open to other ways of accomplishing the same thing, but like Jonas, I'm mainly concerned here with minimizing the number of extra documents which need to be constructed to owner template contents. Or why not always use the owner document of the template element? I think that would cause things like img elements to load. Correct. Remember that we've already agreed that the mechanism for template contents inertness is that the content document fragment (and all of its descendants) are owned by a document which does not have a browsing context. True. Though I wonder if that can be solved in other ways. Should be relatively easy to fix in Gecko, though I don't know about other implementations of course. Seems unfortunate to add the wonkyness of separate owner documents just to overcome this hurdle. / Jonas
Re: [html-templates] Typos
Thanks so much! Filed as https://www.w3.org/Bugs/Public/show_bug.cgi?id=20563 On Wed, Jan 2, 2013 at 11:33 AM, Jens O. Meiert j...@meiert.com wrote: Hi, I noticed the following typos in the HTML Templates draft [1]: * Under “Definitions,” “If DOCUMENT does not have a browsing context, Let…” (should be “let”). * Same section, “the stack of open elements is said be have” (seems to miss “to”). * Sometimes the word ”html” is used in lowercase, but not always referring to the standard. It would be good to check for correct use in the document, and to use capitals for references to the standard, and a monospace font for references to the element. * Inconsistent spelling of “insertion mode”. Headings, even for those whose levels don’t use title case, seem to always say “Insertion Mode,” while the copy following it says “insertion mode.” This seems inconsistent either when it comes to the headings (as they’re not all or completely using title case) or the copy (which should then also refer to “Insertion Mode”). HTH, best, Jens. [1] http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html -- Jens O. Meiert http://meiert.com/en/
Re: Review of the template spec
Thanks for reviewing this (and sorry for the delay -- I was on vacation, and blissfully unable to read email). I'm happy (and a little surprised) that there's no comment here about the HTML parser changes. Is that because it all looks good, or because you didn't dig that deep into it yet? The XML/XSLT/XDM stuff is missing only because we didn't have time to get to it yet. It's next on my priority list now that I'm back. The spec bugs for describing the additional semantics are included inline below. Also, FYI: Although we've landed code for the current spec in WebKit and Chrome Canary, it's behind a compile flag, only enabled for the Chromium port and will not go to beta or release until the spec is reasonably settled (including the XML/XSLT/XDM stuff). On Tue, Dec 11, 2012 at 5:00 AM, Henri Sivonen hsivo...@iki.fi wrote: I reviewed http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#dfn-template . Sorry about the delay. Comments: XML parsing isn’t covered. (Should have the wormhole per the discussion at TPAC.) https://www.w3.org/Bugs/Public/show_bug.cgi?id=19889 XSLT output isn’t covered. (When an XSLT program trying to generate a template element with children, the children should go through the wormhole.) Interaction with the DOM to XDM mapping isn’t covered per discussion at TPAC. (Expected template contents not to appear in the XDM when invoking the XPath DOM API (for consistency with querySelectorAll) but expected them to appear in the XDM when an XSLT transformation is being processed (to avoid precluding use cases).) https://www.w3.org/Bugs/Public/show_bug.cgi?id=20483 1. If DOCUMENT does not have a browsing context, Let TEMPLATE CONTENTS OWNER be DOCUMENT and abort these steps. 2. Otherwise, Let TEMPLATE CONTENTS OWNER be a new Document node that does not have a browsing context. Is there a big win from this inconsistency? Why not always have a separate doc as the template contents owner? Do we trust the platform never to introduce a way to plant a document that does not have a browsing context into a browsing context? (Unlikely, but do we really want to make the bet?) -- Henri Sivonen hsivo...@iki.fi http://hsivonen.iki.fi/
Re: Review of the template spec
On Fri, Dec 14, 2012 at 2:58 PM, Jonas Sicking jo...@sicking.cc wrote: On Fri, Dec 14, 2012 at 1:32 AM, Simon Pieters sim...@opera.com wrote: On Fri, 14 Dec 2012 00:04:20 +0100, Jonas Sicking jo...@sicking.cc wrote: On Tue, Dec 11, 2012 at 5:00 AM, Henri Sivonen hsivo...@iki.fi wrote: 1. If DOCUMENT does not have a browsing context, Let TEMPLATE CONTENTS OWNER be DOCUMENT and abort these steps. 2. Otherwise, Let TEMPLATE CONTENTS OWNER be a new Document node that does not have a browsing context. Is there a big win from this inconsistency? Why not always have a separate doc as the template contents owner? My goal was to *only* have one separate doc per normal doc. Consider the following: body div id=a template id=1 div id=b template id=2 div id=c template /template /body The if document does not have a browsing context part is needed by template 2 so its contents can be owned by the same document as template 1's contents. I.e. for each document with a browsing context, there is a single (lazily created) template contents owner which is shared by all templates reachable from the main document's documentElement. I'm open to other ways of accomplishing the same thing, but like Jonas, I'm mainly concerned here with minimizing the number of extra documents which need to be constructed to owner template contents. Or why not always use the owner document of the template element? I think that would cause things like img elements to load. Correct. Remember that we've already agreed that the mechanism for template contents inertness is that the content document fragment (and all of its descendants) are owned by a document which does not have a browsing context. True. Though I wonder if that can be solved in other ways. Should be relatively easy to fix in Gecko, though I don't know about other implementations of course. Seems unfortunate to add the wonkyness of separate owner documents just to overcome this hurdle. / Jonas
Scheduling multiple types of end-of-(micro)task work
CSS Regions regionLayoutUpdate brings up an issue I think we need to get ahead of: https://www.w3.org/Bugs/Public/show_bug.cgi?id=16391 For context: Mutation Observers are currently spec'd in DOM4 http://dom.spec.whatwg.org/#mutation-observers and delivery timing is defined in HTML http://www.whatwg.org/specs/web-apps/current-work/#perform-a-microtask-checkpoint The timing here is described as a microtask checkpoint and is conceptually deliver all pending mutation records immediately after any script invocation exits. TC-39 has recently approved Object.observe http://wiki.ecmascript.org/doku.php?id=harmony:observe for inclusion in ECMAScript. It is conceptually modeled on Mutation Observers, and delivers all pending change records immediately *before* the last script stack frame exits. Additionally, although I've seen various discussion of dispatching DOM Events with the microtask timing, CSS regionLayoutUpdate is the first I'm aware of to attempt it http://dev.w3.org/csswg/css3-regions/#region-flow-layout-events [I think this is wrong, and I'm hoping this email can help nail down what will work better]. --- Strawman: I'd like to propose a mental model for how these types of work get scheduled. Note that my guiding principles are consistent with the original design of the the end-of-(micro)task timing: -Observers should be delivered to async, but soon -Best efforts should be made to prevent future events from running in a world where pending observer work has not yet been completed. Delivery cycles: 1) Script (Object.observe) delivery. This is conceptually identical to Mutation Observers. http://wiki.ecmascript.org/doku.php?id=harmony:observe#deliverallchangerecords 2) DOM (Mutation Observers) delivery. http://dom.spec.whatwg.org/#mutation-observers 3) End-of-task queue. This would be a new construct. Conceptually it would be a task queue like other task queues, except that its purpose is to schedule end-of-task work. Running it causes events to be dispatched in order until the queue is empty. Scheduling: A) Immediately before any script invocation returns to the browser (after the last stack frame exits), run (1). This can be purely a concern of the script engine and spec'd independent of HTML DOM4. B) Immediately after any script invocation returns to the browser (microtask checkpoint), run (2). Note that delivering to each observer creates a new script invocation, at the end of which, (1) will run again because of (A). C) Immediately before the UA completes the current task, run (2). This is necessary incase DOM changes have occurred outside of a script context (e.g. an input event triggered a change), and is already implemented as part of DOM Mutation Observers. D) Run (3). Note that each script invocation terminates in running (1) because of (A), then (2) because of (B).
Re: Scheduling multiple types of end-of-(micro)task work
On Thu, Oct 18, 2012 at 2:51 PM, Olli Pettay olli.pet...@helsinki.fi wrote: On 10/19/2012 12:08 AM, Rafael Weinstein wrote: CSS Regions regionLayoutUpdate brings up an issue I think we need to get ahead of: https://www.w3.org/Bugs/Public/show_bug.cgi?id=16391 For context: Mutation Observers are currently spec'd in DOM4 http://dom.spec.whatwg.org/#mutation-observers and delivery timing is defined in HTML http://www.whatwg.org/specs/web-apps/current-work/#perform-a-microtask-checkpoint The timing here is described as a microtask checkpoint and is conceptually deliver all pending mutation records immediately after any script invocation exits. TC-39 has recently approved Object.observe http://wiki.ecmascript.org/doku.php?id=harmony:observe (Not sure how that will work with native objects.) I assume you mean host objects (e.g. HTMLElement). The Object.observe doesn't say anything about host objects, so unless the wrapper property actually changes (e.g myElem.myExpando = 'newValue'), it won't be observable. The goal of this mechanism wasn't to observe changes to host objects. for inclusion in ECMAScript. It is conceptually modeled on Mutation Observers, and delivers all pending change records immediately *before* the last script stack frame exits. Additionally, although I've seen various discussion of dispatching DOM Events with the microtask timing, CSS regionLayoutUpdate is the first I'm aware of to attempt it http://dev.w3.org/csswg/css3-regions/#region-flow-layout-events Could you explain why microtasks are good for this case? I would have expected something bound to animation frame callback handling, or perhaps just tasks (but before next layout flush or something). I can't. I don't know enough about CSS Regions. I'm bringing this up now because I've seen multiple instances of people *considering* microtask timing for Event dispatch, but this is the first time someone is trying it. -Olli [I think this is wrong, and I'm hoping this email can help nail down what will work better]. --- Strawman: I'd like to propose a mental model for how these types of work get scheduled. Note that my guiding principles are consistent with the original design of the the end-of-(micro)task timing: -Observers should be delivered to async, but soon -Best efforts should be made to prevent future events from running in a world where pending observer work has not yet been completed. Delivery cycles: 1) Script (Object.observe) delivery. This is conceptually identical to Mutation Observers. http://wiki.ecmascript.org/doku.php?id=harmony:observe#deliverallchangerecords 2) DOM (Mutation Observers) delivery. http://dom.spec.whatwg.org/#mutation-observers 3) End-of-task queue. This would be a new construct. Conceptually it would be a task queue like other task queues, except that its purpose is to schedule end-of-task work. Running it causes events to be dispatched in order until the queue is empty. Scheduling: A) Immediately before any script invocation returns to the browser (after the last stack frame exits), run (1). This can be purely a concern of the script engine and spec'd independent of HTML DOM4. B) Immediately after any script invocation returns to the browser (microtask checkpoint), run (2). Note that delivering to each observer creates a new script invocation, at the end of which, (1) will run again because of (A). C) Immediately before the UA completes the current task, run (2). This is necessary incase DOM changes have occurred outside of a script context (e.g. an input event triggered a change), and is already implemented as part of DOM Mutation Observers. D) Run (3). Note that each script invocation terminates in running (1) because of (A), then (2) because of (B).
Re: Should MutationObservers be able to observe work done by the HTML parser?
On Fri, Jun 29, 2012 at 6:14 PM, Jonas Sicking jo...@sicking.cc wrote: On Fri, Jun 29, 2012 at 8:25 PM, Adam Klein ad...@chromium.org wrote: On Fri, Jun 29, 2012 at 2:44 AM, Jonas Sicking jo...@sicking.cc wrote: All in all I think that as soon as we introduce exceptions to when MutationObserver callbacks fire we change the API from being a reliable way to track DOM mutations to a unreliable way where all callers have to be aware of exceptions and deal with them in other ways. I.e. it feels like it significantly reduces the value of MutationObservers. And so far I don't see any good arguments made for making that reduction in value. Did I miss any arguments other then the randomness argument? Performance was one concern that's come up in discussing this with Ojan and Rafael. Imagine a MutationObserver attached to the document near the top of the page. Now we need to create basically one MutationRecord per node inserted (because the parser operates in a depth-first sort of order). I'm not at all sure this is a show-stopper (we might be able to introduce some new MutationRecord type that could compactly represent parser-style operation), but it definitely seems worrisome, especially given that one of the common uses for MutationObservers is extensions which might run on many (all?) pages. Hmm.. is there actually anything requiring that nodes are inserted one at a time? Internally in mozilla we do insert nodes one at a time, but the notifications we send out to the various subsystems make it seem like nodes are inserted in big chunks. This has previously been to Are the chunks arbitrarily shaped fragments? I.e. is their any restriction on their shape other than a tree? give us good performance from the layout engine which benefits from getting notified by large chunks being inserted rather than nodes being inserted one at a time. The MutationObserver implementation hangs off of the same notification system and thus also sees nodes as being inserted in big chunks. / Jonas
Re: [webcomponents] HTML Parsing and the template element
I think I'm not understanding the implications of your argument. You're making a principled argument about future pitfalls. Can you help me get my head around it by way of example? Perhaps: -pitfalls developers fall into -further dangerous points along the slippery slope you think this opens up (you mentioned pandoras box) On Fri, Jun 15, 2012 at 4:04 AM, Henri Sivonen hsivo...@iki.fi wrote: On Thu, Jun 14, 2012 at 11:48 PM, Ian Hickson i...@hixie.ch wrote: Does anyone object to me adding template, content, and shadow to the HTML parser spec next week? I don't object to adding them if they create normal child elements in the DOM. I do object if template has a null firstChild and the new property that leads to a fragment that belongs to a different owner document. (My non-objection to creating normal children in the DOM should not be read as a commitment to support templates Gecko.) -- Henri Sivonen hsivo...@iki.fi http://hsivonen.iki.fi/
Re: Proposal: Document.parse() [AKA: Implied Context Parsing]
E4H doesn't address all the use cases of Document.parse(). It doesn't solve the problem of existing templating libraries constructing DOM fragments from processed templates. E4H (or something similar) would be great, but I think it's a mistake to make it mutually exclusive with Document.parse(). On Tue, Jun 5, 2012 at 11:24 PM, Ian Hickson i...@hixie.ch wrote: On Mon, 4 Jun 2012, Adam Barth wrote: http://www.hixie.ch/specs/e4h/strawman Who wants to be first to implement it? Doesn't e4h have the same security problems as e4x? As written it did, yes (specifically, if you can inject content into an XML file you can cause it to run JS under your control in your origin with content from the other origin). However, as Anne and you have said, it's easy to fix, either by using an XML-incompatible syntax or using CORS to disable it. Since we have to disable it in Workers anyway, I'd go with disabling it when there's no CORS. Strawman has been updated accordingly. On Tue, 5 Jun 2012, Anne van Kesteren wrote: A (bigger?) problem with E4H/H4E is that TC39 does not like it: http://lists.w3.org/Archives/Public/public-script-coord/2011OctDec/thread.html#msg33 What matters is what implementors want to do. The TC-39 spec process isn't the problem here. TC-39 is composed of implementors, and they are clearly stating a preference for quasis. -- Ian Hickson U+1047E )\._.,--,'``. fL http://ln.hixie.ch/ U+263A /, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Re: [webcomponents] HTML Parsing and the template element
On Mon, Jun 11, 2012 at 3:13 PM, Henri Sivonen hsivo...@iki.fi wrote: On Thu, Jun 7, 2012 at 8:35 PM, Tab Atkins Jr. jackalm...@gmail.com wrote: Just saying that querySelector/All doesn't match elements in a template (unless the scope is inside the template already) would work, but it means that we have to make sure that all future similar APIs also pay attention to this. I think that would be preferable compared to opening the Pandora's box of breaking the correspondence between the markup of the DOM tree. Besides, we'd need something like this for the XML case anyway if the position the spec takes is that it shies away from changing the correspondence between XML source and the DOM. In general, I think the willingness to break the correspondence between the source and the DOM should be the same for both HTML and XML serializations. If you believe that it's not legitimate to break the correspondence between XML source and the DOM, it would be logical to treat radical changes to the correspondence between HTML source and the DOM as equally suspect. I think looking at this as whether we are breaking the correspondance between source and DOM may not be helpful -- because it's likely to be a matter of opinion. I'd like to suggest that we look at more precise issues. There are several axes of presence for elements WRT to a Document: -serialization: do the elements appear in the serialization of the Document, as delivered to the client and if the client re-serializes via innerHTML, etc... -DOM traversal: do the elements appear via traversing the document's childNodes hierarchy -querySelector*, get*by*, etc: are the element's returned via various document-level query mechanisms -CSS: are the element's considered for matching any present or future document-level selectors The goal of the template element is this: the page author would like a declarative mechanism to author DOM fragments which are not in use as of page construction, but are readily available to be used when needed. Further, the author would like to be able to declare the fragments inline, at the location in the document where they should be placed, if when they are needed. Thus, template require that its contents be present for only serialization, and not for DOM traversal, querySelector*/etc..., or CSS. Also, it may be helpful to think about this in terms of classical object systems. Currently we only have instances. What we need is a classes. Native app windowing systems don't force you to create an instance of every window or dialog that your app may ever need and place it off screen until it's needed. They allow for the notion of declaring what the window or dialog will be and delay creating any UI resources (HWNDs, buttons, drag targets, etc..) until the app creates an instance. I worry that if we take the position here that it's okay to change your correspondence between the source and the DOM in order to optimize for a real or perceived need, it will open the floodgates for all sorts of arguments that we can make the parser generate whatever data structures regardless of what the input looks like and we'll end up in a world of pain. It's bad enough that isindex is a parser macro. -- Henri Sivonen hsivo...@iki.fi http://hsivonen.iki.fi/
Re: Implied Context Parsing (DocumentFragment.innerHTML, or similar) proposal details to be sorted out
Yehuda, Can you help clarify here whether jQuery's behavior is intentional (i.e. use cases drive the need for executability), or if it's a side-effect of the implementation? On Fri, Jun 1, 2012 at 1:27 PM, Ryosuke Niwa rn...@webkit.org wrote: On Thu, May 31, 2012 at 7:55 AM, Henri Sivonen hsivo...@iki.fi wrote: On Sat, May 19, 2012 at 6:29 AM, Ryosuke Niwa rn...@webkit.org wrote: There appears to be a consensus to use document.parse (which is fine with me), so I would like to double-check which behavior we're picking. IMO, the only sane choice is to unset the already-started flag since doing otherwise implies script elements parsed by document.parse won't be executed when inserted into a document. I was expecting document.parse() to make scripts unexecutable. Are there use cases for creating executable scripts using this facility? jQuery appears to let script elements run: http://jsfiddle.net/kB8Fp/2/ Also, we're talking about using the same algorithm for template element. I would like script elements inside my template to run. - Ryosuke
Re: Proposal: Document.parse() [AKA: Implied Context Parsing]
Just to be clear: what you are objecting to is the addition of formal API for this. You're generally supportive of adding a template element whose contents would parse the way we're discussing here -- and given that, a webdev could trivially polyfil Document.parse(). I.e. you're ok with the approach of the parser picking a context element based on the contents of markup, but against giving webdevs the impression that innerHTML is good practice, by adding more API in that direction? Put another way, though you're not happy with adding the API, you willing to set that aside and help spec the parser changes required for both this and template element (assuming the remaining issues with template can be agreed upon)? FWIW, I agree with Hixie in principle, but disagree in practice. I think innerHTML is generally to be avoided, but I feel that adding Document.parse() improves the situation by making some current uses (which aren't likely to go away) less hacky. Also, I'm not as worried with webdevs taking the wrong message from us adding API. My feeling is that they just do what works best for them and don't think much about what we are or are not encouraging. Also, I'm highly supportive of the goal of allowing HTML literals in script. I fully agree that better load (compile) time feedback would be beneficial to authors here. On Mon, Jun 4, 2012 at 3:47 PM, Ian Hickson i...@hixie.ch wrote: On Fri, 25 May 2012, Rafael Weinstein wrote: Now's the time to raise objections to UA's adding support for this feature. For the record, I very much object to Document.parse(). I think it's a terrible API. We should IMHO resolve the use case of generate a DOM tree from script using a much more robust solution that has compile-time syntax checking and so forth, rather than relying on the super-hacky concatenate a bunch of strings and then parse them solution that authors are forced to use today. innerHTML and document.write() are abominations unto computer science, and we are doing nobody any favours by continuing the platform down this road. They lead to programming styles that are rife with injection bugs (XSS), they are extremely difficult to debug and maintain, and they are terribly complicated to implement compared to more structured alternatives. The core reasons for these problems, IMHO, are two-fold: 1. Lack of compile-time syntax checking, which leads to typos not being caught and thus programmer intent not being faithfully represented, and 2. Putting markup syntax and data at the same level, instead of having separating them as with other features in JS. For example, this kind of bug is easy to introduce and hard to spot or debug: var heading = 'h1Hello/h1'; // ... div.innerHTML = 'h1' + heading + '/h1'; Even worse are things like typos: tr.innerHTML = 'td' + c1 + '/tdtd' + c2 + '/tddt' + c3 + '/td; Compile-time syntax checking makes this a non-issue. Making data variables be qualitatively different than the syntax also solves problems, e.g.: var title = I hate /p tags.; // ... div.innerHTML = 'pToday's topic is: ' + title + '/p'; // oops, not escaped There have been several alternative proposals; my personal favourite is Anne's E4H solution, basically E4X but simplified just for HTML, which I've written a strawman spec for here: http://www.hixie.ch/specs/e4h/strawman I'm happy to write a more serious spec for this if this is something anyone is interested in implementing. The above examples become much easier to debug. The first one results in very ugly markup visible in the output of the page rather than in the weird spacing: var heading = 'h1Hello/h1'; // ... div.appendChild(h1{heading}/h1); The second results in a compile-time syntax error so would be caught even before the code is reviewed: tr.appendChild(td{c1}/tdtd{c2}/tddt{c3}/td/); The third becomes a non-issue because you don't need to escape text to avoid it from being mistaken for markup [1]: var title = I hate /p tags.; // ... div.innerHTML = pToday's topic is: {title}/p; Other proposed solutions include Element.create(), which is less verbose than the DOM but still more verbose than innerHTML or E4H; and quasistrings, which still suffer from lack of compile-time checking and mix markup with data, but at least would be more structured than raw strings and could offer better injection protection. [1] (This is not the same as auto-escaping strings in other contexts. For example, E4H doesn't propose to have CSS literals, so a string embedded in a style= attribute wouldn't be automagically safe.) -- Ian Hickson U+1047E )\._.,--,'``. fL http://ln.hixie.ch/ U+263A /, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Re: [webcomponents] HTML Parsing and the template element
On Mon, Jun 4, 2012 at 3:50 PM, Ian Hickson i...@hixie.ch wrote: On Mon, 4 Jun 2012, Tab Atkins Jr. wrote: [...] We could do this by having the parser insert a fake node into the stack of open elements just for this purpose, I think. That is, when switching insertion mode in response to the first start tag inside the template insertion mode, also insert something into the stack so that the next time we reset, we reset correctly. We need to do that in a way that doesn't match end tags, though... Maybe we have to introduce a new kind of thing we push on the stack, which doesn't get matched by anything but the reset algorithm? A template context? Sets the context for the rest of parsing, and gets popped by a /template returning to its matching template. Yeah, something like that could work. We'd have to make sure we defined it as happening when /template was popped, but if we force that to only ever happen when we see a literal /template (which the proposal seems to, though I haven't verified that) that might work ok. So the most straight-forward way I saw to approach this (implemented here: https://bugs.webkit.org/show_bug.cgi?id=86031) was to make the context element become a stack of context elements. The idea is that each level of nested template opens a new fragment parsing context, with a coinciding context element which is initially unknown. E.g. from you example above: template tbody /tbody template /template tr /template -When the first template element is encountered, the parser switches into ImpliedContext insertion mode and pushes an unknown element on the stack of context elements which is associated with the current template element -When the tbody is encountered, it replaces the unknown element with a table context element -When the inner template is encountered, it pushes another unknown context element onto the stack of context elements -When the inner /template is encountered, the template is popped from the stack of open elements and the unknown element is popped from the stack of context elements. The reset insertion mode appropriately algorithm is run -- which now examines the current context element (associated with the first template which is the current element) which is table and sets the insertion mode to InTable. The proposal here doesn't support SVG (or MathML, but SVG seems more important for template). Short of hard-coding a list of SVG elements, which seems really bad for forwards compatibility, I don't have a good proposal for dealing with this. I suppose we could go back to having an attribute on template, this time setting the context at a more coarse level of just HTML vs SVG vs MathML; that's more likely to be understood by authors than what I was suggesting before (in table body, etc). It doesn't require any more hard-coding than HTML needs in order to create proper elements instead of HTMLUnknownElements. You have to know the list of valid HTML elements to produce a proper DOM, and update that as you add more, even if the rest of parser is unchanged. This is the same thing, except it needs the list of valid SVG and MathML elements. I agree that it's the same. I don't think having a hard-coded list of HTML elements is a good thing either, it's got the same forward-compatibility problems. Unfortunately in the case of the existing lists we had no choice because UAs already had them. Here, we have a choice. -- Ian Hickson U+1047E )\._.,--,'``. fL http://ln.hixie.ch/ U+263A /, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Proposal: Document.parse() [AKA: Implied Context Parsing]
Ok, so from consensus on earlier threads, here's the full API semantics. Now's the time to raise objections to UA's adding support for this feature. - 1) The Document interface is extended to include a new method: DocumentFragment parse (DOMString markup); which: -Invokes the fragment parsing algorithm with markup and an empty context element, -Unmarks all scripts in the returned fragment node as already started -Returns the fragment node 2) The fragment parsing algorithm's context element is now optional. It's behavior is similar to the case of a known context element, but the tokenizer is simply set to the data state 3) Resetting the insertion appropriately now sets the mode to Implied Context if parsing a fragment and no context element is set, and aborts. 4) A new Implied Context insertion mode is defined which -Ignores doctype, end tag tokens -Handles comment character tokens as if in body -Handles the following start tags as if in body (which is as if in head): style, script, link, meta -Handles any other start tag by selecting a context element, resetting the insertion mode appropriately and reprocessing the token. 5) A new selecting a context element algorithm is defined which takes a start tag as input and outputs an element. The element's identity is as follows: -If start tag is tbody, thead, tfoot, caption or colgroup return table -if start tag is tr, return tbody -if start tag is col return colgroup -if start tag is td or td return tr -if start tag is head or body return html -if start tag is rp or rt return ruby -if start tag is a defined SVG localName (case insensitive) return svg -if start tag is a defined MathML localName (case insensitive) return math -otherwise, return body
Re: Proposal: Document.parse() [AKA: Implied Context Parsing]
On Fri, May 25, 2012 at 12:32 AM, Simon Pieters sim...@opera.com wrote: On Fri, 25 May 2012 09:01:43 +0200, Rafael Weinstein rafa...@google.com wrote: Ok, so from consensus on earlier threads, here's the full API semantics. Now's the time to raise objections to UA's adding support for this feature. - 1) The Document interface is extended to include a new method: DocumentFragment parse (DOMString markup); which: -Invokes the fragment parsing algorithm with markup and an empty context element, -Unmarks all scripts in the returned fragment node as already started -Returns the fragment node 2) The fragment parsing algorithm's context element is now optional. It's behavior is similar to the case of a known context element, but the tokenizer is simply set to the data state 3) Resetting the insertion appropriately now sets the mode to Implied Context if parsing a fragment and no context element is set, and aborts. 4) A new Implied Context insertion mode is defined which -Ignores doctype, end tag tokens -Handles comment character tokens as if in body -Handles the following start tags as if in body (which is as if in head): style, script, link, meta -Handles any other start tag by selecting a context element, resetting the insertion mode appropriately and reprocessing the token. 5) A new selecting a context element algorithm is defined which takes a start tag as input and outputs an element. The element's identity is as follows: -If start tag is tbody, thead, tfoot, caption or colgroup return table -if start tag is tr, return tbody -if start tag is col return colgroup -if start tag is td or td return tr -if start tag is head or body return html -if start tag is rp or rt return ruby I think ruby is better handled by always making rp and rt generate implied end tags in the fragment case (maybe even when parsing normally, too). Making the context element ruby still doesn't make rt parse right, because the spec currently looks for ruby on the *stack* (and the context element isn't on the stack). Also, the ruby base is allowed to include markup, so this would fail: ruby.appendChild(document.parse('spanfoo/spanrtbarrtbaz')); -if start tag is a defined SVG localName (case insensitive) return svg Except those that conflict with HTML? Yes. Thank you. Item 5 should be: 5) A new selecting a context element algorithm is defined which takes a start tag as input and outputs an element. The element's identity is as follows: -If start tag is tbody, thead, tfoot, caption or colgroup return table -if start tag is tr, return tbody -if start tag is col return colgroup -if start tag is td or td return tr -if start tag is head or body return html -if start tag is rp or rt return ruby -if start tag is a defined HTML localName (case insensitive) return body -if start tag is a defined SVG localName (case insensitive) return svg -if start tag is a defined MathML localName (case insensitive) return math -otherwise, return body -if start tag is a defined MathML localName (case insensitive) return math (Making the context element svg or math doesn't do anything currently: https://www.w3.org/Bugs/Public/show_bug.cgi?id=16635 ) -otherwise, return body -- Simon Pieters Opera Software
Re: Implied Context Parsing (DocumentFragment.innerHTML, or similar) proposal details to be sorted out
This seems sensible. I've updated the WebKit patch to do exactly this: https://bugs.webkit.org/show_bug.cgi?id=84646 It appears that the details of the proposal are now sorted out. I'll start a new thread describing the full API semantics. On Fri, May 18, 2012 at 8:29 PM, Ryosuke Niwa rn...@webkit.org wrote: Not that I want to start another bike-shedding, there is one clear distinction between innerHTML and createDocumentFragment, which is that innerHTML sets already-started flag on parsed script elements but createDocumentFragment does not (or rather it unsets it after the fragment parsing algorithm has ran). See http://html5.org/specs/dom-parsing.html#dom-range-createcontextualfragment There appears to be a consensus to use document.parse (which is fine with me), so I would like to double-check which behavior we're picking. IMO, the only sane choice is to unset the already-started flag since doing otherwise implies script elements parsed by document.parse won't be executed when inserted into a document. While we can change the behavior for template elements, I would rather have the same behavior between all 3 APIs (createDocumentFragment, parse, and template element) and let innerHTML be the outlier for legacy reasons. (Note: I intend to fix the bug in WebKit that already-started flag isn't unmarked in createDocumentFragment). - Ryosuke
Re: Implied Context Parsing (DocumentFragment.innerHTML, or similar) proposal details to be sorted out
On Wed, May 16, 2012 at 4:52 PM, Rafael Weinstein rafa...@google.com wrote: On Wed, May 16, 2012 at 4:49 PM, Jonas Sicking jo...@sicking.cc wrote: On Wed, May 16, 2012 at 4:29 PM, Rafael Weinstein rafa...@google.com wrote: Ok. I think I'm convinced on all points. I've uploaded a webkit patch which implements what we've agreed on here: https://bugs.webkit.org/show_bug.cgi?id=84646 I'm happy to report that this patch is nicer than the queued-token approach. Good call, Henri. On Tue, May 15, 2012 at 9:39 PM, Yehuda Katz wyc...@gmail.com wrote: Yehuda Katz (ph) 718.877.1325 On Tue, May 15, 2012 at 6:46 AM, Henri Sivonen hsivo...@iki.fi wrote: On Fri, May 11, 2012 at 10:04 PM, Rafael Weinstein rafa...@google.com wrote: Issue 1: How to handle tokens which precede the first start tag Options: a) Queue them, and then later run them through tree construction once the implied context element has been picked b) Create a new insertion like waiting for context element, which probably ignores end tags and doctype and inserts character tokens and comments. Once the implied context element is picked, reset the insertion mode appropriately, and procede normally. I prefer b). I like b as well. I assume it means that the waiting for context element insertion mode would keep scanning until the ambiguity was resolved, and then enter the appropriate insertion mode. Am I misunderstanding? I think what Yehuda is getting at here is that there are a handful of tags which are allowed to appear anywhere, so it doesn't make sense to resolve the ambiguity based on their identity. I talked with Tab about this, and happily, that set seems to be style, script, meta, link. Happily, because this means that the new ImpliedContext insertion mode can handle start tags as follows (code from the above patch) if (token.name() == styleTag || token.name() == scriptTag || token.name() == metaTag || token.name() == linkTag) { processStartTagForInHead(token); // process following the rules for the in head insertion mode return; } m_fragmentContext.setContextTag(getImpliedContextTag(token.name())); set the context element resetInsertionModeAppropriately(); reset the insertion mode appropriately processStartTag(token); // reprocess the token So if I understand things correctly, that would mean that: document.parse(parsed as textscriptparsed as script content/scripttrtdtable content/td/tr); would return a fragment like: #fragment #text parsed as text script #text parsed as script content tr td #text table content Note that I added an explicit test case for this: #data parse as textscriptparse as spanscript/span/scripttrtdtable content/td/tr #errors #document-fragment #document | parse as text | script | parse as spanscript/span | tr | td | table content Is this correct? The important part here is that the contents of the script element is parsed according to the rules which normally apply when parsing scripts? (That of course leaves the terrible situation that script parsing is vastly different in HTML and SVG, but that's a bad problem that already exists) Yes. Exactly. / Jonas
Re: Implied Context Parsing (DocumentFragment.innerHTML, or similar) proposal details to be sorted out
Ok. I think I'm convinced on all points. I've uploaded a webkit patch which implements what we've agreed on here: https://bugs.webkit.org/show_bug.cgi?id=84646 I'm happy to report that this patch is nicer than the queued-token approach. Good call, Henri. On Tue, May 15, 2012 at 9:39 PM, Yehuda Katz wyc...@gmail.com wrote: Yehuda Katz (ph) 718.877.1325 On Tue, May 15, 2012 at 6:46 AM, Henri Sivonen hsivo...@iki.fi wrote: On Fri, May 11, 2012 at 10:04 PM, Rafael Weinstein rafa...@google.com wrote: Issue 1: How to handle tokens which precede the first start tag Options: a) Queue them, and then later run them through tree construction once the implied context element has been picked b) Create a new insertion like waiting for context element, which probably ignores end tags and doctype and inserts character tokens and comments. Once the implied context element is picked, reset the insertion mode appropriately, and procede normally. I prefer b). I like b as well. I assume it means that the waiting for context element insertion mode would keep scanning until the ambiguity was resolved, and then enter the appropriate insertion mode. Am I misunderstanding? I think what Yehuda is getting at here is that there are a handful of tags which are allowed to appear anywhere, so it doesn't make sense to resolve the ambiguity based on their identity. I talked with Tab about this, and happily, that set seems to be style, script, meta, link. Happily, because this means that the new ImpliedContext insertion mode can handle start tags as follows (code from the above patch) if (token.name() == styleTag || token.name() == scriptTag || token.name() == metaTag || token.name() == linkTag) { processStartTagForInHead(token); // process following the rules for the in head insertion mode return; } m_fragmentContext.setContextTag(getImpliedContextTag(token.name())); set the context element resetInsertionModeAppropriately(); reset the insertion mode appropriately processStartTag(token); // reprocess the token I'm assuming the use case for this stuff isn't that authors throw random stuff at the API and then insert the result somewhere. I expect authors to pass string literals or somewhat cooked string literals to the API knowing where they're going to insert the result but not telling the insertion point to the API as a matter of convenience. If you know you are planning to insert stuff as a child of tbody, don't start your string literal with stuff that would tokenize as characters! (Firefox currently does not have the capability to queue tokens. Speculative parsing in Firefox is not based on queuing tokens. See https://developer.mozilla.org/en/Gecko/HTML_parser_threading for the details.) Issue 2: How to infer a non-HTML implied context element Options: a) By tagName alone. When multiple namespaces match, prefer HTML, and then either SVG or MathML (possibly on a per-tagName basis) b) Also inspect attributes for tagNames which may be in multiple namespaces AFAICT, the case where this really matters (if my assumptions about use cases are right) is a. (Fragment parsing makes scripts useless anyway by setting their already started flag, authors probably shouldn't be adding styles by parsing style, both HTML and SVG font are considered harmful and cross-browser support Content MathML is far off in the horizon.) So I prefer a) possibly with a-specific elaborations if we can come up with some. Generic solutions seem to involve more complexity. For example, if we supported a generic attribute for forcing SVG interpretation, would it put us on a slippery slope to support it when it appears on tokens that aren't the first start tag token in a contextless fragment parse? Issue 3: What form does the API take a) Document.innerHTML b) document.parse() c) document.createDocumentFragment() I prefer b) because: * It doesn't involve creating the fragment as a separate step. * It doesn't need to be foolishly consistent with the HTML vs. XML design errors of innerHTML. * It's shorted than document.createDocumentFragment(). * Unlike innerHTML, it is a method, so we can add more arguments later (or right away) to refine its behavior. -- Henri Sivonen hsivo...@iki.fi http://hsivonen.iki.fi/
Re: Implied Context Parsing (DocumentFragment.innerHTML, or similar) proposal details to be sorted out
On Wed, May 16, 2012 at 4:49 PM, Jonas Sicking jo...@sicking.cc wrote: On Wed, May 16, 2012 at 4:29 PM, Rafael Weinstein rafa...@google.com wrote: Ok. I think I'm convinced on all points. I've uploaded a webkit patch which implements what we've agreed on here: https://bugs.webkit.org/show_bug.cgi?id=84646 I'm happy to report that this patch is nicer than the queued-token approach. Good call, Henri. On Tue, May 15, 2012 at 9:39 PM, Yehuda Katz wyc...@gmail.com wrote: Yehuda Katz (ph) 718.877.1325 On Tue, May 15, 2012 at 6:46 AM, Henri Sivonen hsivo...@iki.fi wrote: On Fri, May 11, 2012 at 10:04 PM, Rafael Weinstein rafa...@google.com wrote: Issue 1: How to handle tokens which precede the first start tag Options: a) Queue them, and then later run them through tree construction once the implied context element has been picked b) Create a new insertion like waiting for context element, which probably ignores end tags and doctype and inserts character tokens and comments. Once the implied context element is picked, reset the insertion mode appropriately, and procede normally. I prefer b). I like b as well. I assume it means that the waiting for context element insertion mode would keep scanning until the ambiguity was resolved, and then enter the appropriate insertion mode. Am I misunderstanding? I think what Yehuda is getting at here is that there are a handful of tags which are allowed to appear anywhere, so it doesn't make sense to resolve the ambiguity based on their identity. I talked with Tab about this, and happily, that set seems to be style, script, meta, link. Happily, because this means that the new ImpliedContext insertion mode can handle start tags as follows (code from the above patch) if (token.name() == styleTag || token.name() == scriptTag || token.name() == metaTag || token.name() == linkTag) { processStartTagForInHead(token); // process following the rules for the in head insertion mode return; } m_fragmentContext.setContextTag(getImpliedContextTag(token.name())); set the context element resetInsertionModeAppropriately(); reset the insertion mode appropriately processStartTag(token); // reprocess the token So if I understand things correctly, that would mean that: document.parse(parsed as textscriptparsed as script content/scripttrtdtable content/td/tr); would return a fragment like: #fragment #text parsed as text script #text parsed as script content tr td #text table content Is this correct? The important part here is that the contents of the script element is parsed according to the rules which normally apply when parsing scripts? (That of course leaves the terrible situation that script parsing is vastly different in HTML and SVG, but that's a bad problem that already exists) Yes. Exactly. / Jonas
Re: [webcomponents] Template element parser changes = Proposal for adding DocumentFragment.innerHTML
On Fri, May 11, 2012 at 12:13 AM, Ojan Vafai o...@chromium.org wrote: On Thu, May 10, 2012 at 9:28 PM, Rafael Weinstein rafa...@google.com wrote: On Thu, May 10, 2012 at 4:19 PM, Ian Hickson i...@hixie.ch wrote: On Thu, 10 May 2012, Rafael Weinstein wrote: On Thu, May 10, 2012 at 4:01 PM, Ian Hickson i...@hixie.ch wrote: On Fri, 11 May 2012, Tab Atkins Jr. wrote: But ok, let's assume that the use case is create an element and its subtree so that you can insert dynamically generated parts of an application during runtime, e.g. inserting images in a dynamically generated gallery [...] [...[ but here's one that comes to mind which is valid markup: What's the output for this myDocFrag.innerHTML = optionOneoptiontwooptionthree; My proposal would return a single option element with the value One. But the example here suggests a different use case. There are presumably three elements there, not one. If this is a use case we want to address, then let's go back to the use cases again: what is the problem we are trying to solve? When would you create a document fragment of some options, instead of just creating a select with options? BTW, for example In handlerbars, select {{# each optionListThatComeInPairs }} option{{ firstThingInPair }} option{{ secondThingInPair }} {{/ each }} /select Or equivalently, in MDV select template iterate=optionsListThatComeInPairs option{{ firstThingInPair }} option{{ secondThingInPair }} /template /select To clarify, this doesn't suffer from the string concatenation problem that Ian was worried about, right? {{ firstThingInPair }} is inserted as a string, not HTML, right? Similarly, if you had 'data-foo={{ attributeValue }}', it would be escaped appropriately so as to avoid any possibility of XSS? Correct. In the first example, handlebars will escape the script before doing innerHTML, and MDV doesn't invoke the parser, it assigns the Text node's textContent. Ojan
Re: History Re: [webcomponents] Template element parser changes = Proposal for adding DocumentFragment.innerHTML
It was wrong for me to editorialize about SVG and MathML -- and punish was very poor word choice. I apologize to anyone who was insulted. It certainly wasn't my intent. I should have just said that I'm frustrated with the world we've arrived in WRT HTML vs XML and left it at that. On Fri, May 11, 2012 at 3:07 AM, Charles McCathieNevile cha...@opera.com wrote: On Fri, 11 May 2012 10:55:27 +0200, Henri Sivonen hsivo...@iki.fi wrote: On Wed, May 9, 2012 at 7:45 PM, Rafael Weinstein rafa...@google.com wrote: I'm very much of a like mike with Henri here, in that I'm frustrated with the situation we're currently in WRT SVG MathML parsing foreign content in HTML, etc... In particular, I'm tempted to feel like SVG and MathML made this bed for themselves and they should now have to sleep in it. I think that characterization is unfair to MathML. The math working group tried hard to avoid local name collisions with HTML. They didn't want to play namespace games. As I understand it, they were forced into a different namespace by W3C strategy tax arising from the NAMESPACE ALL THE THINGS! attitude. Actually, I think even that is an unfair characterisation. At the time both these technologies were developed (mid-late 90s) everyone assumed that XML was the path of the future for everything, and that de-crentralised extensibility was a critical requirement for a powerful web platform. Given that scenario, it is unclear whether there is a better approach. The current HTML approach of if it is important it will get into the mainline spec effectively breaks the key extensibility assumption. Leading implementors like Adobe, SodiPodi and Inkscape all introduced namespaced content all over the SVG map - in many cases doing things that active SVG WG members thought were excessive. Likewise Microsoft Office (at the time probably as widespread as web browsers in general) introduced namespaced content all over HTML (IE didn't support XHTML). Seven years later, both of those assumptions came under attack from the nascent WHAT-WG approach to updating HTML - but unlike the case for HTML, where the market leader had clearly resisted implementing XHTML, SVG in particular was backed by a number of XML-happy engines. It was several more years before SVG and MathML were incorporated into HTML in a way that clearly made sense. Punishing people, or even ridiculing them, for using XML in the late 90s, seems counter-productive at best. Outside HTML even Microsoft - who were one of the big creative forces behind XML - were pushing it everywhere, it was considered de riguer for making the mobile web a possibility outside Opera (which supported it anyway, but didn't require it), and it had, and still has, huge deployment. It just failed on the web browser platform, for reasons that are far easier to see in hindsight than they were at the time. cheers Chaals -- Charles 'chaals' McCathieNevile Opera Software, Standards Group je parle français -- hablo español -- jeg kan noen norsk http://my.opera.com/chaals Try Opera: http://www.opera.com
Re: [webcomponents] Template element parser changes = Proposal for adding DocumentFragment.innerHTML
It feels like we're making progress here. It seems as though there are basically two camps: 1) We shouldn't attempt to solve this problem. E.g. an explicit context element should be required for fragment parsing. 2) The basic idea of inferring a context element is workable and there are details to be worked out. I suggest that we suspend for a bit the question of camp 1 vs 2 and just focus on the best possible (i.e. mutually agreeable) solution for camp 2. It goes without saying, that I'd really appreciate feedback in this direction from folks who are in camp #1 -- I'm looking at you, Hixie -- even if you hate this idea, you still have to help =-P. Once we have a complete proposal written down, then we can decide whether it's worth doing or not. Now, WRT camp #2, there seem to be three issues to resolve 1) What is done with tokens which precede the first start tag? 2) What is the mechanism (if any) for handling SVG MathML elements? 3) What is the form of the API (e.g. DocumentFragment.innerHTML, document.parse(), etc...). I'm actually encouraged because, while I have preferences WRT the above, I think all the permutations would solve the use cases we have. I'll start a new thread whose purpose is to sort out an agreeable proposal for the behavior of camp #2. On Fri, May 11, 2012 at 5:39 AM, Scott González scott.gonza...@gmail.com wrote: On Fri, May 11, 2012 at 7:13 AM, Henri Sivonen hsivo...@iki.fi wrote: However, I'm not strongly opposed to adding innerHTML to DocumentFragment if we also add a method on Document that parses a string using the HTML parser regardless of the HTMLness flag of the document and returns a DocumentFragment (or has an optional extra argument for forcing XML parsing explicitly). Just a side note, but at least parsing XML seems to be fairly sane today. I haven't really done any testing around this, but it seems like this would get you parsing of arbitrary XML fragments, including leading and trailing text nodes: (new DOMParser).parseFromString( x + string + /x, text/xml ).documentElement.childNodes Obviously this is overly verbose compared to document.parse( string, flag ).
Implied Context Parsing (DocumentFragment.innerHTML, or similar) proposal details to be sorted out
Ok, So from the previous threads, there are appear to be three issues to resolve, and I'll list the options that I've noted. I'll follow up with my perspective of pros/cons and ask others to do the same. Please point out options or issues that I've missed. Issue 1: How to handle tokens which precede the first start tag Options: a) Queue them, and then later run them through tree construction once the implied context element has been picked b) Create a new insertion like waiting for context element, which probably ignores end tags and doctype and inserts character tokens and comments. Once the implied context element is picked, reset the insertion mode appropriately, and procede normally. --- Issue 2: How to infer a non-HTML implied context element Options: a) By tagName alone. When multiple namespaces match, prefer HTML, and then either SVG or MathML (possibly on a per-tagName basis) b) Also inspect attributes for tagNames which may be in multiple namespaces c) Allow for inline name spacing of elements which would normally inherit the proper namespace from svg or math d) Somewhat orthogonal, but later allow for template to have an optional context attribute (e.g. template context=svg), which explicitly picks a context element. e) Some combination of the above. --- Issue 3: What form does the API take a) Document.innerHTML b) document.parse() c) document.createDocumentFragment()
Re: Implied Context Parsing (DocumentFragment.innerHTML, or similar) proposal details to be sorted out
Ok, so I have some preferences, but they are *mild* preferences and any permutation of the options below is acceptable to me. On Fri, May 11, 2012 at 12:04 PM, Rafael Weinstein rafa...@google.com wrote: Ok, So from the previous threads, there are appear to be three issues to resolve, and I'll list the options that I've noted. I'll follow up with my perspective of pros/cons and ask others to do the same. Please point out options or issues that I've missed. Issue 1: How to handle tokens which precede the first start tag Options: a) Queue them, and then later run them through tree construction once the implied context element has been picked I like option (a) because you always get identical output for any input relative to if you had applied it via innerHTML to the appropriate implied context element. E.g. myHTMLElement.innerHTML = foobodybar; myDocumentFragment.innerHTML = foobodybar; myHTMLElement.innerHTML == myDocumentFragment.innerHTML; // true; Also, most browsers are already speculatively tokenizing ahead for resource preloading purposes, so the implementation complexity isn't especially daunting. b) Create a new insertion like waiting for context element, which probably ignores end tags and doctype and inserts character tokens and comments. Once the implied context element is picked, reset the insertion mode appropriately, and procede normally. --- Issue 2: How to infer a non-HTML implied context element Options: a) By tagName alone. When multiple namespaces match, prefer HTML, and then either SVG or MathML (possibly on a per-tagName basis) b) Also inspect attributes for tagNames which may be in multiple namespaces c) Allow for inline name spacing of elements which would normally inherit the proper namespace from svg or math d) Somewhat orthogonal, but later allow for template to have an optional context attribute (e.g. template context=svg), which explicitly picks a context element. e) Some combination of the above. I have a mild preference for not getting to fancy here. I'll mostly stay out of this and let those who know more about SVG and MathML sort it out, but I'll just note that the main concern cited for needing this to work is with web components, and there I think Hixie's idea of a declarative context element (e.g. option (d)) above is a nice addition and might alleviate the need to get fancy. --- Issue 3: What form does the API take a) Document.innerHTML b) document.parse() c) document.createDocumentFragment() I'm torn here between (a) (b). I like the familiarity of (a), but agree with Henri's point of about the namespace of the owner document being a downside. I don't like (c) for stylistic reasons.
Re: [webcomponents] Template element parser changes = Proposal for adding DocumentFragment.innerHTML
On Thu, May 10, 2012 at 4:01 PM, Ian Hickson i...@hixie.ch wrote: On Fri, 11 May 2012, Tab Atkins Jr. wrote: The innerHTML API is convenient. It lets you set the entire descendant tree of an element, creating elements and giving them attributes, in a single call, using the same syntax you'd use if you were writing it in HTML (module some extra quote-escaping maybe). [...] I'll go ahead and anticipate your response of they should just use the Element.create() API That would indeed be my response. while Element.create() is great, it solves a different use-case. Being able to construct DOM from raw HTML is easy to read and write and understand, particularly when it's a static fragment (or a concatenation of mostly static fragments), while Element.create() requires a translation into a JS API with a much different syntax. Element.create() is much more readable and writable when you're making some DOM out of a *lot* of dynamic information. In other words, this: $(div class=fooimg src=+foosrc+/div) is a lot easier than: Element.create(div, {class: foo}, [ Element.create(img, {src: foosrc}) ]); So, that's the use-case for this API. The idea of building elements using string concatenation is a security disaster. What if foosrc above contains ' onclick=...' ? But ok, let's assume that the use case is create an element and its subtree so that you can insert dynamically generated parts of an application during runtime, e.g. inserting images in a dynamically generated gallery, and security by damned. If we're going to do that, then we don't need any lookahead at all. We should support literally that: parsing one element and its descendants. We determine what element is being generatd by looking at the top of the string (div ... - it's a div, tr ... - it's a tr, etc), and we parse until that element is popped from the stack or the end of the string is reached. This avoids all the problems with doing magical lookahead. This was more or less Yehuda's original proposal. If we can make this work, I think it also solves the problem and would be acceptable. My sense is that this solution probably introduces more complexity into the parser and it's output isn't any superior. Anne pointed out that accomplishing this isn't straightforward. I forget what his examples were (I think they had to do with poorly formed markup), but here's one that comes to mind which is valid markup: What's the output for this myDocFrag.innerHTML = optionOneoptiontwooptionthree; But I'm very skeptical about creating new APIs to encourage authors to use injection-prone, non-type-checked, direct string manipulation in script to generate DOM trees. -- Ian Hickson U+1047E )\._.,--,'``. fL http://ln.hixie.ch/ U+263A /, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Re: [webcomponents] Template element parser changes = Proposal for adding DocumentFragment.innerHTML
On Thu, May 10, 2012 at 4:27 PM, Scott González scott.gonza...@gmail.com wrote: On Thu, May 10, 2012 at 7:15 PM, Rafael Weinstein rafa...@google.com wrote: On Thu, May 10, 2012 at 4:01 PM, Ian Hickson i...@hixie.ch wrote: If we're going to do that, then we don't need any lookahead at all. We should support literally that: parsing one element and its descendants. We determine what element is being generatd by looking at the top of the string (div ... - it's a div, tr ... - it's a tr, etc), and we parse until that element is popped from the stack or the end of the string is reached. This avoids all the problems with doing magical lookahead. This was more or less Yehuda's original proposal. If we can make this work, I think it also solves the problem and would be acceptable. My sense is that this solution probably introduces more complexity into the parser and it's output isn't any superior. Yehuda has actually been complaining about this limitation for quite a while. I know that he would not consider this a full solution. Ah, sorry. I didn't quite understand Hixie's proposal. I retract my statement -- this isn't a workable solution. Also, I'm curious why it's ok to peak at the first few characters of the string, and not ok to peak at the token stream until we see the first start tag?
Re: [webcomponents] Template element parser changes = Proposal for adding DocumentFragment.innerHTML
On Thu, May 10, 2012 at 4:58 PM, Ian Hickson i...@hixie.ch wrote: On Thu, 10 May 2012, Rafael Weinstein wrote: Also, I'm curious why it's ok to peak at the first few characters of the string, and not ok to peak at the token stream until we see the first start tag? Because it's predictable and easy to debug. When you're dealing with a weird effect caused by some accidental markup hundreds of lines down a string, it's really hard to work out what's going on. When the effect is caused by the very first thing in the string, it's much easier to notice it. (You see this kind problem sometimes on Web pages where text/plain files are sent as text/html, or text files are slightly augmented with HTML without properly escaping everything -- they render fine until they get to something that accidentally looks like markup, and the parser does its stuff, and you wonder why half of the 100-page document is bold.) In the abstract, I actually agree with you, but this happens to be a case when this is effectively never going to be a problem. Just have a look at *any* templating langauge. Any time you see some kind of conditional, or loop construct, look at it's contents and imagine that that's what'll be passed to innerHTML here. 99.9% of the time it's going to either be all character tokens, or whitespace followed by a start tag. You're letting an non-existent problem kill a perfectly useful proposal. I'm not a huge fan of everything jQuery does either, but regardless of it's objective goodness, it has already done the test by offering this functionality. The kind of bug your describing hasn't been observed at all. Someone with more jQuery-cred correct me if I'm wrong. -- Ian Hickson U+1047E )\._.,--,'``. fL http://ln.hixie.ch/ U+263A /, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Re: [webcomponents] Template element parser changes = Proposal for adding DocumentFragment.innerHTML
On Thu, May 10, 2012 at 5:03 PM, Ian Hickson i...@hixie.ch wrote: On Fri, 11 May 2012, Tab Atkins Jr. wrote: For something like this: $(pExample +exnum+:/ppimg src=+exsrc+).appendTo(container); Can we really not come up with anything better? It makes me really sad to think that the best we can do here is to go from a nice structured environment, concatenate our data together into a string, and then reparse the string back into structured data to add it to the DOM. I understand that people do this kind of thing all the time, but I've always at least assumed that everyone agreed that it was a necessarily evil because the alternatives were even worse. I had hope when we were discussing Element.create() that maybe we were finally coming up with a workable alternative, but as far as I can tell that never went anywhere and now we're actually talking about adding APIs to _support_ string-based DOM tree generation as if it's an actually sane way of writing code. Am I really the only one here who thinks this is horrifying? I find it horrifying, and I'll venture that Yehuda and the author of every other templating mechanism does as well -- at least in the sense that all of our goal is to generally remove the *need* for page authors to have to use innerHTML, by declaring how their views should be composed, rather than doing it imperatively. Libraries exist at a higher leverage point and if *they* do the right thing, then a greater number of authors are protected. Adding this, makes it easier for libraries (and if I get my way, the platform itself) to do this right so that authors can stop constructing DOM imperatively altogether. -- Ian Hickson U+1047E )\._.,--,'``. fL http://ln.hixie.ch/ U+263A /, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Re: [webcomponents] Template element parser changes = Proposal for adding DocumentFragment.innerHTML
On Thu, May 10, 2012 at 4:19 PM, Ian Hickson i...@hixie.ch wrote: On Thu, 10 May 2012, Rafael Weinstein wrote: On Thu, May 10, 2012 at 4:01 PM, Ian Hickson i...@hixie.ch wrote: On Fri, 11 May 2012, Tab Atkins Jr. wrote: But ok, let's assume that the use case is create an element and its subtree so that you can insert dynamically generated parts of an application during runtime, e.g. inserting images in a dynamically generated gallery [...] [...[ but here's one that comes to mind which is valid markup: What's the output for this myDocFrag.innerHTML = optionOneoptiontwooptionthree; My proposal would return a single option element with the value One. But the example here suggests a different use case. There are presumably three elements there, not one. If this is a use case we want to address, then let's go back to the use cases again: what is the problem we are trying to solve? When would you create a document fragment of some options, instead of just creating a select with options? BTW, for example In handlerbars, select {{# each optionListThatComeInPairs }} option{{ firstThingInPair }} option{{ secondThingInPair }} {{/ each }} /select Or equivalently, in MDV select template iterate=optionsListThatComeInPairs option{{ firstThingInPair }} option{{ secondThingInPair }} /template /select -- Ian Hickson U+1047E )\._.,--,'``. fL http://ln.hixie.ch/ U+263A /, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Re: [webcomponents] Template element parser changes = Proposal for adding DocumentFragment.innerHTML
I'm very much of a like mike with Henri here, in that I'm frustrated with the situation we're currently in WRT SVG MathML parsing foreign content in HTML, etc... In particular, I'm tempted to feel like SVG and MathML made this bed for themselves and they should now have to sleep in it. However, on balance, I'm in favor of this magic (picking the correct namespace based on the first element's tagName) for the following three reasons: *Not doing so means that using template to declare web components that do super awesome SVG stuff much more cumbersome. *Doing so doesn't negatively impact HTML. *SVG mostly working (modulo a few overlapping tagNames), is preferable to not working at all (and there's not really a problem with MathML). Much as I dislike it, parsing foreign content is kind of already gross magic, and it seems to me like this behavior is in keeping with what's already there. Moreover, not including it kind of punishes the wrong people, by making webdevs sleep in the bed that SVG and MathML made. I.e. It would make my life easier, but at the expense of webdevs. On Wed, May 9, 2012 at 12:52 AM, Henri Sivonen hsivo...@iki.fi wrote: On Tue, Apr 24, 2012 at 6:39 AM, Rafael Weinstein rafa...@google.com wrote: What doesn't appear to be controversial is the parser changes which would allow the template element to have arbitrary top-level content elements. It's not controversial as long as an HTML context is assumed. I think it is still controversial for SVG and MathML elements that aren't wrapped in an svg or math element. I'd like to propose that we add DocumentFragment.innerHTML which parses markup into elements without a context element. Why should the programmer first create a document fragment and then set a property on it? Why not introduce four methods on Document that return a DocumentFragment: document.parseFragmentHTML (parses like template.innerHTML), document.parseFragementSVG (parses like svg.innerHTML), document.parseFragmentMathML (parses like math.innerHTML) and document.parseFragmentXML (parses like innerHTML in the XML mode without namespace context)? This would avoid magic for distinguishing HTML a and SVG a. On Thu, Apr 26, 2012 at 8:23 PM, Tab Atkins Jr. jackalm...@gmail.com wrote: (In my dreams, we just merge SVG into the HTML namespace, and then this step disappears.) In retrospect, it would have been great if Namespaces in XML had never been introduced and SVG, MathML and HTML shared a single namespace. However, at this point trying to merge the namespaces would lead to chameleon namespaces which are evil and more trouble than fixing the historical mistake is worth. I feel very strongly that vendors and the W3C should stay away from turning SVG into a chameleon namespace. SVG is way more established them CSS gradients or Flexbox in terms of what kind of changes are acceptable. See http://lists.w3.org/Archives/Public/www-archive/2009Feb/0065.html as well as various XML experiences from non-browser contexts. -- Henri Sivonen hsivo...@iki.fi http://hsivonen.iki.fi/
Re: [webcomponents] Template element parser changes = Proposal for adding DocumentFragment.innerHTML
On Wed, May 9, 2012 at 12:51 PM, Ian Hickson i...@hixie.ch wrote: On Wed, 9 May 2012, Jonas Sicking wrote: I think having to provide a context every wherewhere you want to parse HTML is creating very bad developer ergonomics. You wouldn't have to provide it everywhere. The vast majority of the time, the default body context is fine. But the whole point of DocumentFragment.innerHTML is that you'd need to inspect the markup in order to know the context fragment. body may be fine 98%, but the use cases that motivated this feature need to know 100% of the time if it needs to be something else. I think the proposals here, and the fact that jQuery has implemented context-free HTML parsing, proves that it is technically possible. I don't think look-ahead and magically determining the parse mode from a preparse of the string is really a sane solution. It doesn't handle all cases (e.g. it doesn't handle the style example I gave), and it results in very weird results (very bad developer ergonomics) for cases like 1GB of text followed by caption vs 1GB of text followed by coption (where the former loses the text and the latter does not). For me, both of these examples fall squarely in the I can live with that bucket. I'll try again to persuade everyone that we not let perfect be the enemy of good. =-) -- Ian Hickson U+1047E )\._.,--,'``. fL http://ln.hixie.ch/ U+263A /, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Re: [webcomponents] Template element parser changes = Proposal for adding DocumentFragment.innerHTML
On Wed, May 9, 2012 at 1:32 PM, Rafael Weinstein rafa...@google.com wrote: On Wed, May 9, 2012 at 12:51 PM, Ian Hickson i...@hixie.ch wrote: On Wed, 9 May 2012, Jonas Sicking wrote: I think having to provide a context every wherewhere you want to parse HTML is creating very bad developer ergonomics. You wouldn't have to provide it everywhere. The vast majority of the time, the default body context is fine. But the whole point of DocumentFragment.innerHTML is that you'd need to inspect the markup in order to know the context fragment. body may be fine 98%, but the use cases that motivated this feature need to know 100% of the time if it needs to be something else. I think the proposals here, and the fact that jQuery has implemented context-free HTML parsing, proves that it is technically possible. I don't think look-ahead and magically determining the parse mode from a preparse of the string is really a sane solution. It doesn't handle all cases (e.g. it doesn't handle the style example I gave), and it results in very weird results (very bad developer ergonomics) for cases like 1GB of text followed by caption vs 1GB of text followed by coption (where the former loses the text and the latter does not). BTW, This does not appear to be the case in webkit, gecko or IE8. t = document.createElement('table'); neither of t.innerHTML = 'foocaptionbar/caption' t.innerHTML = 'foocoptionbar/coption discard foo. For me, both of these examples fall squarely in the I can live with that bucket. I'll try again to persuade everyone that we not let perfect be the enemy of good. =-) -- Ian Hickson U+1047E )\._.,--,'``. fL http://ln.hixie.ch/ U+263A /, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Re: [webcomponents] Custom Elements Spec
Is it worth separating the issues of fallback behavior and extracting element semantics? It strikes me as unlikely that in practice components *can* be used if you need to target legacy browsers, and that fallback won't mean much unless legacy browsers are specifically targeted because proper behavior will involve different control flow paths (hooking up the right events, etc..). Sorry, if I'm making a leap here or just being stupid. It seems like if you remove the legacy UAs issue, it opens up a bunch of other options for extracting semantics (e.g. for indexing or accessibility). On Fri, May 4, 2012 at 12:29 PM, Ian Hickson i...@hixie.ch wrote: On Fri, 4 May 2012, Marat Tanalin | tanalin.com wrote: So what happens in browsers that don't support components? Or in search engines or other data analysis tools that are trying to extract the semantics from the page? Elements with custom tag-names would have EXACTLY SAME semantic (as for core HTML5 semantics) meaning as a common container (SPAN or DIV) with a class. No more and no less. If it's purely stylistic, then using div and not having semantics is fine. Stylistic components should just be invoked from the CSS layer. Components that are not purely stylistic, e,g, things like form controls or data (tables or graphical), need to have fallback semantics. Those are the ones that appear in the markup. -- Ian Hickson U+1047E )\._.,--,'``. fL http://ln.hixie.ch/ U+263A /, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Re: [webcomponents] Template element parser changes = Proposal for adding DocumentFragment.innerHTML
On Thu, Apr 26, 2012 at 1:33 AM, Anne van Kesteren ann...@opera.com wrote: On Thu, 26 Apr 2012 10:05:28 +0200, Ryosuke Niwa rn...@webkit.org wrote: Also, I think Anne convinced me that it's better to deduce the insertion mode from the first element than inventing a new insertion mode (I've asked him to post his reasoning). 1) You cannot look at various elements and make a decision. E.g. if your first element is plaintext there will not be any other elements. 2) Defining a new top-level insertion mode while retaining compatible behavior might be an interesting exercise in parser complexity, but it's not clear there is a benefit (use cases?) and feasibility has not been demonstrated (consider handling ptdp, trptd, ...). The more we can define in terms of the existing parser, the better it is for developers. The behavior will be more predictable and there will be less quirks to learn. FWIW, https://www.w3.org/Bugs/Public/show_bug.cgi?id=14694 is the bug on the I've updated this bug with the current proposal. DOM Parsing spec, I don't think there's a bug on the HTML spec (other than https://www.w3.org/Bugs/Public/show_bug.cgi?id=16635 for SVG/MathML), but I There aren't any parser changes required. DocumentFragment.innerHTML can still provide the fragment case with a context element and procede normally. It's not obvious to me what bug to open against HTML. Anne, can we move forward with this? Also, note that a webkit patch which implements implied context is here: https://bugs.webkit.org/show_bug.cgi?id=84646 might be mistaken. -- Anne van Kesteren http://annevankesteren.nl/
Re: [webcomponents] Template element parser changes = Proposal for adding DocumentFragment.innerHTML
On Mon, Apr 30, 2012 at 6:51 PM, Tab Atkins Jr. jackalm...@gmail.com wrote: On Mon, Apr 30, 2012 at 5:43 PM, Anne van Kesteren ann...@opera.com wrote: I personally think it would be better if HTML kept defining all entry points to the HTML parser. And at least conceptually this is a new insertion mode I think contrary to what you suggest in http://lists.w3.org/Archives/Public/public-webapps/2012AprJun/0334.html as only insertion modes handle emitted tokens. And although I guess it does not matter here for now, given that the tree builder can change the behavior of the tokenizer decoupling them seems rather odd to me. This is simply invoking the fragment parsing algorithm that's already defined in DOMParsing, but intelligently supplying a context element. There's no need to worry about emitting tokens or anything, except insofar as DOMParsing already has to worry about that. I think Anne's concern is that in order to find the first start tag, the tokenizer must be used. In this case, the tokenizer would be used absent of a parser. I'm actually ok with that because the tokenizer is not a risk of changing states (it starts in the DATA state and stops searching on the first start tag, so for this use it can't change state), but I understand the conceptual novelty. We can put this in the parser spec, but I'm not yet convinced it deserves a new insertion mode. UA's may implement it that way, so as to avoid duplication of some tokenization work, but it seems cleaner to describe it as running the tokenizer to look ahead to the first start tag. The Any other * tagName design also seems somewhat fragile to me. I think those lists need to be explicit and coordinated. We should at least put some checks in place to make sure we are not introducing more overlapping element names in the future. I'm fine with that, as long as implementations are okay with updating their lists of elements as the underlying languages (SVG and MathML) change. This *will* potentially cause a behavior difference, as elements that previously parsed as HTMLUnknownElement instead parse as some specific SVG or MathML element. ~TJ
Re: [webcomponents] Template element parser changes = Proposal for adding DocumentFragment.innerHTML
Henri, Does this address the concerns you raised earlier? On Thu, Apr 26, 2012 at 10:23 AM, Tab Atkins Jr. jackalm...@gmail.com wrote: On Thu, Apr 26, 2012 at 1:26 AM, Simon Pieters sim...@opera.com wrote: On Wed, 25 Apr 2012 21:39:53 +0200, Rafael Weinstein rafa...@google.com wrote: Any other HTML tagName = HTMLBodyElement Isn't this one redundant with the last step? No, this captures known HTML tagnames, so that HTML can lay claim on the few tags that overlap with SVG. The last step just captures any remaining tags that fell through the cracks, so they can become HTMLUnknownElements. Any other SVG tagName = SVGElement Any other MathML tagName = MathElement What are these two, exactly? The parser currently doesn't have a list of SVG/MathML tag names, and the SVG WG didn't like it when it was proposed to use a fixed list of SVG tag names for parsing SVG in text/html, IIRC. We don't need a specific list in the spec, but each browser would need one, constructed from whatever elements they currently understand. (In my dreams, we just merge SVG into the HTML namespace, and then this step disappears.) Also note that innerHTML on non-HTML elements currently always parses in the in body insertion mode. I'd like to see that fixed before we try to support foreign content in contextless innerHTML. https://www.w3.org/Bugs/Public/show_bug.cgi?id=16635 Yes, that needs to be fixed. As Ms2ger said yesterday in IRC, the DOMParsing spec already handles this appropriately, but HTML needs a a fix, since the former hooks into the latter. ~TJ
Re: [webcomponents] Template element parser changes = Proposal for adding DocumentFragment.innerHTML
Ok, so from the thread that Yehuda started last year, There seem to be three issues: 1) Interop (e.g. WRT IE) 2) Defining the behavior for all elements 3) HTML vs SVG vs MathML I think what Yehuda outlined earlier is basically right, and I have a proposal which accomplishes everything he wants in a different way and also addresses the three concerns above. My approach here is to not let perfect be the enemy of good. DocumentFragment.innerHTML has the following behavior. It picks an *implied context element* based on the tagName of the first start tag token which appears in the html provided. It then operates per the fragment case of the spec, using the implied context element as the context element. Here's the approach for picking the implied context element: Let the first start tag token imply the context element. The start tag = implied context element is as follows: caption, colgroup, thead, tbody, tfoot = HTMLTableElement tr = HTMLTableBodyElement col = HTMLColGroupElement td, th = HTMLTableRowElement head, body = HTMLHTMLElement rp, rt = HTMLRubyElement Any other HTML tagName = HTMLBodyElement Any other SVG tagName = SVGElement Any other MathML tagName = MathElement Any other tagName = HTMLBodyElement Note a few things about this: *Because this is basically a pre-processing step to the existing fragment case, the changes to the parser spec are purely additive (no new insertion modes or other parser changes needed). *It addresses (1) by only adding new parsing behavior to new API (implicitly retaining compat) *It explains (2) *The only problem with (3) is the SVG style, script, a font tags. Here HTML wins and I think that's fine. This problem is inherent to the SVG 1.1 spec and we shouldn't let it wreak more havoc on HTML. *This doesn't attempt to do anything clever with sequences of markup that contain conflicting top-level nodes (e.g. df.innerHTML = 'tdFoo/tdg/g';). There's nothing clever to be done, and IMO, attempting to be clever is a mistake. Here's how some of the examples from the previous thread would be parsed. I've tested these by simply inspecting the output of innerHTML applied to the implied context element from the example. On Thu, Nov 10, 2011 at 3:43 AM, Henri Sivonen hsivo...@iki.fi wrote: What about SVG and MathML elements? I totally sympathize that this is a problem with tr, but developing a complete solution that works sensibly even when you do stuff like frag.innerHTML = head/head head body frag.innerHTML = headdiv/div/head head body div frag.innerHTML = frameset/frameseta!-- b -- a !-- b -- frag.innerHTML = htmlbodyfoo/htmlbartr/tr foobar frag.innerHTML = htmlbodyfoo/htmltr/tr foo frag.innerHTML = div/divtr/tr div frag.innerHTML = tr/trdiv/div tbody tr div frag.innerHTML = gpath//g g path [Note that innerHTML doesn't work presently on SVGElements in WebKit or Gecko, but this last example would result if it did] On Tue, Apr 24, 2012 at 5:26 AM, Rafael Weinstein rafa...@google.com wrote: No, I hadn't. Let me digest this thread. Much of what I'm implicitly asking has already been discussed. I'll repost if I have anything to add here. Apologies for the noise. On Mon, Apr 23, 2012 at 10:32 PM, Ryosuke Niwa rn...@webkit.org wrote: Have you looked at http://lists.w3.org/Archives/Public/public-webapps/2011OctDec/0663.html ? On Mon, Apr 23, 2012 at 8:39 PM, Rafael Weinstein rafa...@google.com wrote: The main points of contention in the discussion about the template element are 1) By what mechanism are its content elements 'inert' 2) Do template contents reside in the document, or outside of it What doesn't appear to be controversial is the parser changes which would allow the template element to have arbitrary top-level content elements. I'd like to propose that we add DocumentFragment.innerHTML which parses markup into elements without a context element. This has come up in the past, and is in itself a useful feature. The problem it solves is allowing templating systems to create DOM from markup without having to sniff the content and only innerHTML on an appropriate parent element (Yehuda can speak more to this). The parser changes required for this are a subset of the changes that Dimitri uncovered here: http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html And I've uploaded a webkit patch which implements them here: https://bugs.webkit.org/show_bug.cgi?id=84646 I'm hoping this is a sensible way to make progress. Thoughts?
Re: [webcomponents] Template element parser changes = Proposal for adding DocumentFragment.innerHTML
On Wed, Apr 25, 2012 at 12:39 PM, Rafael Weinstein rafa...@google.com wrote: Ok, so from the thread that Yehuda started last year, There seem to be three issues: 1) Interop (e.g. WRT IE) 2) Defining the behavior for all elements 3) HTML vs SVG vs MathML I think what Yehuda outlined earlier is basically right, and I have a proposal which accomplishes everything he wants in a different way and also addresses the three concerns above. My approach here is to not let perfect be the enemy of good. DocumentFragment.innerHTML has the following behavior. It picks an *implied context element* based on the tagName of the first start tag token which appears in the html provided. It then operates per the fragment case of the spec, using the implied context element as the context element. Here's the approach for picking the implied context element: Let the first start tag token imply the context element. The start tag = implied context element is as follows: caption, colgroup, thead, tbody, tfoot = HTMLTableElement tr = HTMLTableBodyElement col = HTMLColGroupElement td, th = HTMLTableRowElement head, body = HTMLHTMLElement rp, rt = HTMLRubyElement Any other HTML tagName = HTMLBodyElement Any other SVG tagName = SVGElement Any other MathML tagName = MathElement Any other tagName = HTMLBodyElement Note a few things about this: *Because this is basically a pre-processing step to the existing fragment case, the changes to the parser spec are purely additive (no new insertion modes or other parser changes needed). *It addresses (1) by only adding new parsing behavior to new API (implicitly retaining compat) *It explains (2) *The only problem with (3) is the SVG style, script, a font tags. Here HTML wins and I think that's fine. This problem is inherent to the SVG 1.1 spec and we shouldn't let it wreak more havoc on HTML. *This doesn't attempt to do anything clever with sequences of markup that contain conflicting top-level nodes (e.g. df.innerHTML = 'tdFoo/tdg/g';). There's nothing clever to be done, and IMO, attempting to be clever is a mistake. Here's how some of the examples from the previous thread would be parsed. I've tested these by simply inspecting the output of innerHTML applied to the implied context element from the example. On Thu, Nov 10, 2011 at 3:43 AM, Henri Sivonen hsivo...@iki.fi wrote: What about SVG and MathML elements? I totally sympathize that this is a problem with tr, but developing a complete solution that works sensibly even when you do stuff like frag.innerHTML = head/head head body frag.innerHTML = headdiv/div/head head body div frag.innerHTML = frameset/frameseta!-- b -- a !-- b -- frag.innerHTML = htmlbodyfoo/htmlbartr/tr foobar frag.innerHTML = htmlbodyfoo/htmltr/tr foo frag.innerHTML = div/divtr/tr div frag.innerHTML = tr/trdiv/div tbody tr div Sorry, this should have been just tr frag.innerHTML = gpath//g g path [Note that innerHTML doesn't work presently on SVGElements in WebKit or Gecko, but this last example would result if it did] On Tue, Apr 24, 2012 at 5:26 AM, Rafael Weinstein rafa...@google.com wrote: No, I hadn't. Let me digest this thread. Much of what I'm implicitly asking has already been discussed. I'll repost if I have anything to add here. Apologies for the noise. On Mon, Apr 23, 2012 at 10:32 PM, Ryosuke Niwa rn...@webkit.org wrote: Have you looked at http://lists.w3.org/Archives/Public/public-webapps/2011OctDec/0663.html ? On Mon, Apr 23, 2012 at 8:39 PM, Rafael Weinstein rafa...@google.com wrote: The main points of contention in the discussion about the template element are 1) By what mechanism are its content elements 'inert' 2) Do template contents reside in the document, or outside of it What doesn't appear to be controversial is the parser changes which would allow the template element to have arbitrary top-level content elements. I'd like to propose that we add DocumentFragment.innerHTML which parses markup into elements without a context element. This has come up in the past, and is in itself a useful feature. The problem it solves is allowing templating systems to create DOM from markup without having to sniff the content and only innerHTML on an appropriate parent element (Yehuda can speak more to this). The parser changes required for this are a subset of the changes that Dimitri uncovered here: http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html And I've uploaded a webkit patch which implements them here: https://bugs.webkit.org/show_bug.cgi?id=84646 I'm hoping this is a sensible way to make progress. Thoughts?
Re: [webcomponents] Template element parser changes = Proposal for adding DocumentFragment.innerHTML
No, I hadn't. Let me digest this thread. Much of what I'm implicitly asking has already been discussed. I'll repost if I have anything to add here. Apologies for the noise. On Mon, Apr 23, 2012 at 10:32 PM, Ryosuke Niwa rn...@webkit.org wrote: Have you looked at http://lists.w3.org/Archives/Public/public-webapps/2011OctDec/0663.html ? On Mon, Apr 23, 2012 at 8:39 PM, Rafael Weinstein rafa...@google.com wrote: The main points of contention in the discussion about the template element are 1) By what mechanism are its content elements 'inert' 2) Do template contents reside in the document, or outside of it What doesn't appear to be controversial is the parser changes which would allow the template element to have arbitrary top-level content elements. I'd like to propose that we add DocumentFragment.innerHTML which parses markup into elements without a context element. This has come up in the past, and is in itself a useful feature. The problem it solves is allowing templating systems to create DOM from markup without having to sniff the content and only innerHTML on an appropriate parent element (Yehuda can speak more to this). The parser changes required for this are a subset of the changes that Dimitri uncovered here: http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html And I've uploaded a webkit patch which implements them here: https://bugs.webkit.org/show_bug.cgi?id=84646 I'm hoping this is a sensible way to make progress. Thoughts?
Re: [webcomponents] HTML Parsing and the template element
Yes. I think this issue is a distraction. Using the script tag for encoding opaque text contents is a hack, but it works as well as it can. AFAIC, The main drawback is that the contents cannot contain the string /script. This will be the case for any new element we came up with for this purpose. If someone has an idea for how to do better than this and why it's worth doing, please speak up. Part of the point of parsing the template contents as HTML is exactly so that template contents can contain subtemplates. It's a universal feature of templating systems and needs to be well supported. On Mon, Apr 23, 2012 at 4:11 PM, Ryosuke Niwa rn...@webkit.org wrote: Why don't we just use script elements for that then? On Mon, Apr 23, 2012 at 3:52 PM, Yuval Sadan sadan.yu...@gmail.com wrote: You musn't forget what we're not planning for. Templates can be great for so many applications - generating code (JSON, Javascript), generating plain-text or otherwise formatted (markdown, restructured text, etc.) content and much more. I don't think templates should be parsed by DOM unless explicitly requested. The simplest scenario should also be supported imho, that is script type=text/html/script-ish markup with access to textContent. On Thu, Apr 19, 2012 at 1:56 AM, Rafael Weinstein rafa...@google.com wrote: On Wed, Apr 18, 2012 at 2:54 PM, Dimitri Glazkov dglaz...@chromium.org wrote: On Wed, Apr 18, 2012 at 2:31 PM, James Graham jgra...@opera.com wrote: On Wed, 18 Apr 2012, Dimitri Glazkov wrote: Wouldn't it make more sense to host the template contents as normal descendants of the template element and to make templating APIs accept either template elements or document fragments as template input? Or to make the template elements have a cloneAsFragment() method if the template fragment is designed to be cloned as the first step anyway? When implementing this, making embedded content inert is probably the most time-consuming part and just using a document fragment as a wrapper isn't good enough anyway, since for example img elements load their src even when not inserted into the DOM tree. Currently, Gecko can make imbedded content inert on a per-document basis. This capability is used for documents returned by XHR, createDocument and createHTMLDocument. It looks like the template proposal will involve computing inertness from the ancestor chain (template ancestor or DocumentFragment marked as inert as an ancestor). It's unclear to me what the performance impact will be. Right, ancestor-based inertness is exactly what we avoid with sticking the parsed contents into a document fragment from an inert document. Otherwise, things get hairy quick. I am also pretty scared of tokenising stuff like it is markup but then sticking it into a different document. It seems like very surprising behaviour. Have you considered (and this may be a very bad idea) exposing the markup inside the template as a text node, but exposing the corresponding DOM as an IDL attribute on the HTMLTemplateElement (or whatever it's called) interface? This seems like a neat idea -- though I haven't thought about this in depth yet. I think there are two orthogonal issues here: 1) Are the contents of the template element (a) parsed, context-free in a separate document which lacks a browsing context, or (b) simply processed as text. 2) Where are the contents of the template element put. (I'm separating these because James' proposal is about the second, not the first). I think there's a disconnect here between what seems strange to us a UA implementors and what isn't strange at all to webdevs. In a way, the goal here is exactly to create a mechanism which is strange in this way. Effective, every web app that does client-side templating is totally used to this idea: E.g. I want to ship fragments of DOM structures inside my document to the client, but have those fragments exist *outside* the DOM constructed for that document for all practical purposes (rendering, traversal, resource loading, selector matching, etc...). This goal of this feature is provide webdevs with a supported mechanism to do this which lacks the pitfalls of the available hacks. Assuming (1) is uncontroversially (a), then the idea to re-serialize the parsed content and append it is a text child to the template element would resolve our worry about the contents living outside the DOM being strange, but it has the downside that nearly all uses will immediately re-parse. [Dimitri addressed the problem with (1) being (b) earlier in the thread, if anyone is interested]. :DG
Re: [webcomponents] HTML Parsing and the template element
On Wed, Apr 18, 2012 at 9:32 AM, Dimitri Glazkov dglaz...@chromium.org wrote: On Wed, Apr 18, 2012 at 7:49 AM, Henri Sivonen hsivo...@iki.fi wrote: On Tue, Apr 3, 2012 at 1:21 AM, Dimitri Glazkov dglaz...@chromium.org wrote: Perhaps lost among other updates was the fact that I've gotten the first draft of HTML Templates spec out: http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html Once parsed, the template contents must not be in the document tree. That's surprising, radical and weird. Why are the template contents hosted in a document fragment that the template element points to using a non-child property? Why aren't the template contents simply hosted as a subtree rooted at the template element? In terms of weirdness, this is not much different from the textarea, script, or xmp. It does change the existing behavior, so anyone using a template tag today will suddenly find no child nodes -- that part _is_ a bit surprising. However, moving this into a separate document fragment allows us to easily define the boundaries of intertness. If you look at the spec, the document fragment is indeed created from a separate document is inert (like createHTMLDocument case): http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#dfn-template-contents-initialization. This also breaks the natural mapping between XML source and the DOM in the XML case. True. I've created a bug against the spec to make clear that the XML parser will be unchanged WRT the template element. https://www.w3.org/Bugs/Public/show_bug.cgi?id=16787 This weirdness also requires a special case to the serialization algorithm. True. If the document fragment wasn't there and the contents of the template were simply children of template element, the parsing algorithm changes would look rather sensible. Great! Wouldn't it make more sense to host the template contents as normal descendants of the template element and to make templating APIs accept either template elements or document fragments as template input? Or to make the template elements have a cloneAsFragment() method if the template fragment is designed to be cloned as the first step anyway? When implementing this, making embedded content inert is probably the most time-consuming part and just using a document fragment as a wrapper isn't good enough anyway, since for example img elements load their src even when not inserted into the DOM tree. Currently, Gecko can make imbedded content inert on a per-document basis. This capability is used for documents returned by XHR, createDocument and createHTMLDocument. It looks like the template proposal will involve computing inertness from the ancestor chain (template ancestor or DocumentFragment marked as inert as an ancestor). It's unclear to me what the performance impact will be. Right, ancestor-based inertness is exactly what we avoid with sticking the parsed contents into a document fragment from an inert document. Otherwise, things get hairy quick. :DG -- Henri Sivonen hsivo...@iki.fi http://hsivonen.iki.fi/
Re: [webcomponents] HTML Parsing and the template element
On Mon, Apr 2, 2012 at 3:21 PM, Dimitri Glazkov dglaz...@chromium.org wrote: On Wed, Feb 8, 2012 at 11:25 PM, Henri Sivonen hsivo...@iki.fi wrote: On Thu, Feb 9, 2012 at 12:00 AM, Dimitri Glazkov dglaz...@chromium.org wrote: == IDEA 1: Keep template contents parsing in the tokenizer == Not this! Here's why: Making something look like markup but then not tokenizing it as markup is confusing. The confusion leads to authors not having a clear mental model of what's going on and where stuff ends. Trying to make things just work for authors leads to even more confusing here be dragons solutions. Check out http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#script-data-double-escaped-dash-dash-state Making something that looks like markup but isn't tokenized as markup also makes the delta between HTML and XHTML greater. Some people may be ready to throw XHTML under the bus completely at this point, but this also goes back to the confusion point. Apart from namespaces, the mental model you can teach for XML is remarkably sane. Whenever HTML deviates from it, it's a complication in the understandability of HTML. Also, multi-level parsing is in principle bad for perf. (How bad really? Dunno.) I *really* don't want to end up writing a single-pass parser that has to be black-box indishtinguishable from something that's defined as a multi-pass parser. (There might be a longer essay about how this sucks in the public-html archives, since the SVG WG proposed something like this at one point, too.) == IDEA 2: Just tweak insertion modes == I think a DWIM insertion mode that switches to another mode and reprocesses the token upon the first start tag token *without* trying to return to the DWIM insertion mode when the matching end tag is seen for the start tag that switched away from the DWIM mode is something that might be worth pursuing. If we do it, I think we should make it work for a fragment parsing API that doesn't require context beyound assuming HTML, too. (I think we shouldn't try to take the DWIM so far that a contextless API would try to guess HTML vs. SVG vs. MathML.) Just to connect the threads. A few weeks back, I posted an update about the HTML Templates spec: http://lists.w3.org/Archives/Public/public-webapps/2012JanMar/1171.html Perhaps lost among other updates was the fact that I've gotten the first draft of HTML Templates spec out: http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html The draft is roughly two parts: motivation for the spec and deltas to HTML specification to allow serialization and parsing of the template element. To be honest, after finishing the draft, I wondered if we should just merge the whole thing into the HTML specification. As a warm-up exercise for the draft, I first implemented the changes to tree construction algorithm here in WebKit (https://bugs.webkit.org/show_bug.cgi?id=78734). The patch (https://bugs.webkit.org/attachment.cgi?id=128579action=review) includes new parsing tests, and should be fairly intuitive to read to those familiar with the test format. The interesting bit here is that all parser changes are additive: we are only adding what effectively are extensions points -- well, that and a new contextless parsing mode for when inside of the template tag. I think the task previously was to show how dramatic the changes to the parser would need to be. Talking to Dimitri, it sounds to me like they turned out to be less open-heart-surgery and more quick outpatient procedure. Adam, Hixie, Henri, how do you guys feel about the invasiveness of the parser changes that Dimitri has turned out here? The violation of the Degrade Gracefully principle and tearing the parser spec open right when everybody converged on the spec worry me, though. I'm still hoping for a design that doesn't require parser changes at all and that doesn't blow up in legacy browsers (even better if the results in legacy browsers were sane enough to serve as input for a polyfill). I agree with your concern. It's bugging me too -- that's why I am not being an arrogant jerk yelling at people and trying to shove this through. In general, it's difficult to justify making changes to anything that's stable -- especially considering how long and painful the road to getting stable was. However, folks like Yehuda, Erik, and Rafael spent years tackling this problem, and I tend to trust their steady hand... hands? I don't think there's an option to degrade gracefully here. My personal feeling is that even if it's years before browsers reliably support this and developers can use it without needing to be careful until then, there's a long term view here which is the sooner me put this into the spec, the sooner that day will arrive. Also, I like this approach because it addresses the inert DOM use case as well as the context-free parsing use case. :DG
Re: [webcomponents] HTML Parsing and the template element
[This time from the right email] On Wed, Feb 8, 2012 at 2:10 PM, Adam Barth w...@adambarth.com wrote: Re-using the generic raw text element parsing algorithm would be the simplest change to the parser. Do you have a concrete example of where nested template declarations are required? For example, rather than including nested templates, you might instead consider referencing other template elements by id. Referencing templates rather than including sub-templates inline is certainly a solution. In fact, it's a common feature of templating systems. It's useful when a single component is used in multiple disparate or random places throughout the page. However, it's worth backing up here and thinking about what templating is. Templating is about convenience and maintainability of pages -- Not about any core capability. Templating is useful and near ubiquitous because it makes it easy to think about authoring your page. Web pages are highly complex and often deeply nested repeating tree structures. You can certainly de-construct the page into some sort of templating-4th-normal-form and dump each component at the top level of the document. However, doing this abandons the largely coherent structure of template, e.g. where table rows are defined in the context of the table in which they are used, etc... -- which is sort of the idea of templating -- that you get to describe your page in more or less the way that it will be rendered. Adam On Wed, Feb 8, 2012 at 2:00 PM, Dimitri Glazkov dglaz...@chromium.org wrote: Hello folks! You may be familiar with the work around the template element, or a way to declare document fragments in HTML (see http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2011-November/033868.html for some background). In trying to understand how this newfangled beast would work, I started researching HTML parsing, and--oh boy was I ever sorry! Err.. I mean.. --and investigating how the contents of the template element could be parsed. So far, I have two ideas. Both introduce changes to HTML parsing algorithm. Both have flaws, and I thought the best thing to do would be to share the data with the experts and seek their opinions. Those of you cc'd -- you're the designated experts :) == IDEA 1: Keep template contents parsing in the tokenizer == PRO: if we could come up with a way to perceive the stuff between template and /template as a character stream, we enable a set of use cases where the template contents does not need to be a complete HTML subtree. For example, I could define a template that sets up a start of a table, then a few that provide repetition patterns for rows/cells, and then one to close out a table: template id=headtablecaptionNyan-nyan/captionthead ... tbody/template template id=rowtrtemplatetd ... /td/template/tr/template template id=foot/tbody/table/template Then I could slam these templates together with some API and produce an arbitrary set of tables. PRO: Since the template contents are parsed as string, we create opportunities for performance optimizations at the UA level. If a bunch of templates is declared, but only a handful is used, we could parse template contents on demand, thus reducing the churn of DOM elements. CON: Tokenizer needs to be really smart and will start looking a lot like a specialized parser. At first glance, template behaves much like a textarea -- any tags inside will just be treated as characters. It works until you realize that templates sometimes need to be nested. Any use case that involves building a larger-than-one-dimensional data representation (like tables) will involve nested templates. This makes things rather tricky. I made an attempt of sketching this out here: http://dvcs.w3.org/hg/webcomponents/raw-file/a28e16cc4167/spec/templates/index.html#parsing. As you can see, this adds a largish set of new states to tokenizer. And it is still incomplete, breaking in cases like templatescriptalert('template is awesome!');/script/template. It could be argued that--while pursuing the tokenizer algorithm perfection--we could just stop at some point of complexity and issue a stern warning for developers to not get too crazy, because stuff will break -- akin to including /script string in your Javascript code. == IDEA 2: Just tweak insertion modes == PRO: It's a lot less intrusive to the parser -- just adjust insertion modes to allow template tags in places where they would ordinary be ignored or foster-parented, and add a new insertion for template contents to let all tags in. I made a quick sketch here: http://dvcs.w3.org/hg/webcomponents/raw-file/c96f051ca008/spec/templates/index.html#parsing (Note: more massaging is needed to make it really work) CON: You can't address fun partial-tree scenarios. Which idea appeals to you? Perhaps you have better ideas? Please share. :DG
Re: [webcomponents] HTML Parsing and the template element
Here's a real-world example, that's probably relatively simple compared to high traffic web pages (i.e. amazon or facebook) http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/template/api_template.html?revision=120962content-type=text%2Fplain that produces each page of the chrome extensions API doc, e.g. http://code.google.com/chrome/extensions/contextMenus.html This uses jstemplate. Do a search in the first link. Every time you see jsdisplay or jsselect, think template. On Wed, Feb 8, 2012 at 2:36 PM, Adam Barth w...@adambarth.com wrote: On Wed, Feb 8, 2012 at 2:20 PM, Erik Arvidsson a...@chromium.org wrote: On Wed, Feb 8, 2012 at 14:10, Adam Barth w...@adambarth.com wrote: ... Do you have a concrete example of where nested template declarations are required? When working with tree like structures it is comment to use recursive templates. http://code.google.com/p/mdv/source/browse/use_cases/tree.html I'm not sure I fully understand how templates work, so please forgive me if I'm butchering it, but here's how I could imagine changing that example: === Original === ul class=tree template iterate id=t1 li class={{ children | toggle('has-children') }}{{name}} ul template ref=t1 iterate=children/template /ul /li /template /ul === Changed === ul class=tree template iterate id=t1 li class={{ children | toggle('has-children') }}{{name}} ul template-reference ref=t1 iterate=children/template-reference /ul /li /template /ul (Obviously you'd want a snappier name than template-reference to reference another template element.) I looked at the other examples in the same directory and I didn't see any other examples of nested template declarations. Adam
Re: [webcomponents] HTML Parsing and the template element
On Wed, Feb 8, 2012 at 3:16 PM, Adam Barth w...@adambarth.com wrote: On Wed, Feb 8, 2012 at 2:47 PM, Rafael Weinstein rafa...@chromium.org wrote: Here's a real-world example, that's probably relatively simple compared to high traffic web pages (i.e. amazon or facebook) http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/template/api_template.html?revision=120962content-type=text%2Fplain that produces each page of the chrome extensions API doc, e.g. http://code.google.com/chrome/extensions/contextMenus.html This uses jstemplate. Do a search in the first link. Every time you see jsdisplay or jsselect, think template. It's a bit hard for me to understand that example because I don't know how jstemplate works. Sorry. This example wasn't really meant to be understood so much as observed for: 1) A general feel for levels of nesting. 2) That the nested components are defined where they are used. 3) How complex the templating already is, even given that templates can be nested. 3) Imagine what this page might look like if each nested component was pulled out and put somewhere else (possibly the top level). I'm just suggesting that rather than trying to jam a square peg (template) into a round hole (the HTML parser), there might be a way of reshaping both the peg and the hole into an octagon. I get that. Unfortunately, I'm useless on this front because I know next to nothing about HTML parsing. All I can offer is an opinion as to how well various declarative semantics will address the templating use case. Maybe the best analogy I can give is this: try to imagine if someone proposed that C looping constructs couldn't contain a body -- only a function call. e.g. for (int i = 0; i count; i++) doMyThing(); You can still write all the same programs, but it'd be an unfortunately feature to give up. Adam On Wed, Feb 8, 2012 at 2:36 PM, Adam Barth w...@adambarth.com wrote: On Wed, Feb 8, 2012 at 2:20 PM, Erik Arvidsson a...@chromium.org wrote: On Wed, Feb 8, 2012 at 14:10, Adam Barth w...@adambarth.com wrote: ... Do you have a concrete example of where nested template declarations are required? When working with tree like structures it is comment to use recursive templates. http://code.google.com/p/mdv/source/browse/use_cases/tree.html I'm not sure I fully understand how templates work, so please forgive me if I'm butchering it, but here's how I could imagine changing that example: === Original === ul class=tree template iterate id=t1 li class={{ children | toggle('has-children') }}{{name}} ul template ref=t1 iterate=children/template /ul /li /template /ul === Changed === ul class=tree template iterate id=t1 li class={{ children | toggle('has-children') }}{{name}} ul template-reference ref=t1 iterate=children/template-reference /ul /li /template /ul (Obviously you'd want a snappier name than template-reference to reference another template element.) I looked at the other examples in the same directory and I didn't see any other examples of nested template declarations. Adam
Re: Mutation Observers: a replacement for DOM Mutation Events
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. Maybe you can provide concrete examples (i.e. with code snippets, actual instances of use cases, etc...) On Wed, Oct 12, 2011 at 4:00 AM, Sean Hogan shogu...@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: DOM Mutation Events Replacement: Findings from implementing net-effect projections
On Wed, Aug 17, 2011 at 3:17 AM, Olli Pettay olli.pet...@helsinki.fi wrote: On 08/17/2011 04:54 AM, Rafael Weinstein wrote: TL;DR; 1) ObserveSubtree semantics doesn't provide a robust mechanism for observing a tree/fragment, and if we don't provide something more complete, libraries will likely register observers at every node in the document. ModificationBatch approach should provide as much information as current mutation events. 2) Not providing position information (e.g childlistIndex) in ChildlistChanged mutations means that the algorithmic complexity of computing whether/where nodes have moved to doesn't improve vs. having to bruce-force compute. Yeah, I think we really to provide some position information. Adding index is easy (although it can be slow in some implementations, but that is implementation specific thing) I'll add this to ModificationBatch. 3) Not providing lastValue for text changes (attribute, textNode, etc...) may adversely impact some use cases. I agree. --- Following up on points 6 7 from http://lists.w3.org/Archives/Public/public-webapps/2011JulSep/0779.html ... I've prototyped the main net-effect projections that I believe various use cases will need. I've published to code to this public github repository: https://github.com/rafaelw/MutationProjections I encourage anyone interested to check my work and make corrections and/or suggestions, or create a branch that experiments in any direction they see fit. --- Per point (3) in the email above, we've concluded that mutations should be delivered in batches, since any number of mutations can have taken place since an observer was notified. Also, though it varies, there's generally a hierarchy of expense for types of operations done from JS: reads/writes on pure JS data DOM Reads DOM Writes External I/O Often, an application is willing to do a some amount of work of a less expensive operation to avoid doing any work of a more expensive operation. Thus, a mutation observer is highly motivated, for both correctness and performance, to answer the question: What is the net-effect of some set of DOM changes that have taken place since I last got to run? --- Depending on the use case, what happened likely means some combination of the following: 1) Reachability: What nodes were added to or removed from the document? 2) Matching: What nodes stopped or started matching a given pattern? This could be arbitrarily complex, but in the use cases discussed, this usually means a simple selector. 3) Parent changes: What nodes are now children of a new parent node? 4) Movement: What nodes moved to a new position in the document? 5) Value change: What character/text or attribute nodes changed value (for attributes, also, whether the attribute was added or removed)? Note that none of the above requires any mechanism of mutation observation. All can be computed given the opportunity to inspect the DOM at two points in time. However, without any information about what happened, the expense of answering each of the above questions is roughly proportional to the number of nodes in the document. All are roughly linear, except (4) Movement, which is roughly quadratic. It seems to me that a good goal for any mutation event replacement should be that the expense of answering the above projections be proportional the number of mutations which actually took place. I've implemented the null case (lacking any mutation information) for 1, 3 4 here: https://github.com/rafaelw/MutationProjections/blob/master/projections.js#L39 And the same projections, but taking mutation records to improve performance here: https://github.com/rafaelw/MutationProjections/blob/master/projections.js#L240 --- Observing sets of nodes In order to implement the above projections, I prototyped: Document.observeOwnedNodes I'm not proposing this (yet), but I think it is conceptually the most general case (btw, to give credit to Jonas, he pointed out that this might be solution to the problem I'm about to describe, though I'm pretty sure he meant sometime down the road). I'm not quite sure what all the Document.observeOwnedNodes approach tries to observe. I assume it should be observing everything, all the changes to child nodes and also changes to attributes. (currently it handles only elements) Is that really needed? It's not fully implemented in the shim I created, in that it only reports ChildlistChanged mutations. It's purpose is to provide a single registration that allows you to be notified of all changes that happen to all nodes owned by this document, regardless of whether they are current in the document. The problem is that observeSubtree doesn't report anything about what happened to a node that was removed from the document, modified, then returned to the document. Consider the following case
DOM Mutation Events Replacement: Findings from implementing net-effect projections
TL;DR; 1) ObserveSubtree semantics doesn't provide a robust mechanism for observing a tree/fragment, and if we don't provide something more complete, libraries will likely register observers at every node in the document. 2) Not providing position information (e.g childlistIndex) in ChildlistChanged mutations means that the algorithmic complexity of computing whether/where nodes have moved to doesn't improve vs. having to bruce-force compute. 3) Not providing lastValue for text changes (attribute, textNode, etc...) may adversely impact some use cases. --- Following up on points 6 7 from http://lists.w3.org/Archives/Public/public-webapps/2011JulSep/0779.html ... I've prototyped the main net-effect projections that I believe various use cases will need. I've published to code to this public github repository: https://github.com/rafaelw/MutationProjections I encourage anyone interested to check my work and make corrections and/or suggestions, or create a branch that experiments in any direction they see fit. --- Per point (3) in the email above, we've concluded that mutations should be delivered in batches, since any number of mutations can have taken place since an observer was notified. Also, though it varies, there's generally a hierarchy of expense for types of operations done from JS: reads/writes on pure JS data DOM Reads DOM Writes External I/O Often, an application is willing to do a some amount of work of a less expensive operation to avoid doing any work of a more expensive operation. Thus, a mutation observer is highly motivated, for both correctness and performance, to answer the question: What is the net-effect of some set of DOM changes that have taken place since I last got to run? --- Depending on the use case, what happened likely means some combination of the following: 1) Reachability: What nodes were added to or removed from the document? 2) Matching: What nodes stopped or started matching a given pattern? This could be arbitrarily complex, but in the use cases discussed, this usually means a simple selector. 3) Parent changes: What nodes are now children of a new parent node? 4) Movement: What nodes moved to a new position in the document? 5) Value change: What character/text or attribute nodes changed value (for attributes, also, whether the attribute was added or removed)? Note that none of the above requires any mechanism of mutation observation. All can be computed given the opportunity to inspect the DOM at two points in time. However, without any information about what happened, the expense of answering each of the above questions is roughly proportional to the number of nodes in the document. All are roughly linear, except (4) Movement, which is roughly quadratic. It seems to me that a good goal for any mutation event replacement should be that the expense of answering the above projections be proportional the number of mutations which actually took place. I've implemented the null case (lacking any mutation information) for 1, 3 4 here: https://github.com/rafaelw/MutationProjections/blob/master/projections.js#L39 And the same projections, but taking mutation records to improve performance here: https://github.com/rafaelw/MutationProjections/blob/master/projections.js#L240 --- Observing sets of nodes In order to implement the above projections, I prototyped: Document.observeOwnedNodes I'm not proposing this (yet), but I think it is conceptually the most general case (btw, to give credit to Jonas, he pointed out that this might be solution to the problem I'm about to describe, though I'm pretty sure he meant sometime down the road). The problem is that observeSubtree doesn't report anything about what happened to a node that was removed from the document, modified, then returned to the document. Consider the following case: -Register a subtreeObserver at the root of the document -Some other code removes an element, appends a new element to it, modifies an attribute, then returns the node to the document. Now, in order to properly compute the above projections, we are nearly back to the null case (matching becomes proportional the number of descendants of added/removed nodes that we heard about, but everything else returns to being proportional to the number of nodes in the document). You may consider this to be an esoteric case, but imagine the situation that library authors will be in. They will have two basic options: a) Use observeSubtree and explain to their users that they have to be careful never to modify something outside the tree. b) Simply register an observer at all nodes in the document. Picking the second option means that my library works properly and I don't need my users to be careful. It burns plenty of memory, but library authors aren't well known for being conservative in that regard -- especially since its pretty hard for them to quantify the memory impact of anything. The danger is
Re: DOM Mutation Events Replacement: When to deliver mutations
Thanks Olli. I think this is now a fairly complete summary of the issues identified thus far. It'd be great to get some additional views -- in particular from folks representing UAs that haven't yet registered any observations or opinons. Note: I think what Olli has listed is fair, but I'm concerned that because of terminology (consistent vs inconsistent semantics), others may be confused. I'm going to clarify a bit. I believe my comments should be uncontroversial. Olli (or anyone else), please correct me if this isn't so. On Thu, Aug 11, 2011 at 2:02 AM, Olli Pettay olli.pet...@helsinki.fi wrote: On 08/11/2011 03:44 AM, Rafael Weinstein wrote: Although everyone seems to agree that mutations should be delivered after the DOM operations which generated them complete, the question remains: When, exactly, should mutations be delivered? The four options I'm aware of are: 1) Immediately - i.e. while the operation is underway. [Note: This is how current DOM Mutation events work]. 2) Upon completion of the outer-most DOM operation. i.e. Immediately before a the lowest-on-the-stack DOM operation returns, but after it has done all of its work. 3) At the end of the current Task. i.e. immediately before the UA is about to fetch a new Task to run. 4) Scheduled as a future Task. i.e. fully async. --- Discussion: Options 1 4 are don't seem to have any proponents that I know of, so briefly: Option 1, Immediately: Pro: -It's conceptually the easiest thing to understand. The following *always* hold: -For calling code: When any DOM operation I make completes, all observers will have run. -For notified code: If I'm being called, the operation which caused this is below me on the stack. Con: -Because mutations must be delivered for some DOM operations before the operation is complete, UAs must tolerate all ways in which script may invalidate their assumptions before they do further work. Option 4, Scheduled as a future Task: Pro: -Conceptually easy to understand -Easy to implement. Con: -It's too late. Most use cases for mutation observation require that observers run before a paint occurs. E.g. a widget library which watches for special attributes. Script may create adiv class=FooButton and an observer will react to this by decorating the div as a FooButton. It is unacceptable (creates visual artifacts/flickering) to have the div be painted before the widget library has decorated it as a FooButton. Both of these options appear to be non-starters. Option 1 has been shown by experience to be an unreasonable implementation burden for UAs. Option 4 clearly doesn't handle properly important use cases. --- Options 2 3 have proponents. Since I'm one of them (a proponent), I'll just summarize the main *pro* arguments for each and invite those who wish (including myself), to weigh in with further support or criticism in follow-on emails. Option 2: Upon completion of the outer-most DOM operation. Pro: -It's conceptually close to fully synchronous. For simple uses (specifically, setting aside the case of making DOM operations within a mutation callback), it has the advantages of Option 1, without its disadvantages. Because of this, it's similar to the behavior of current Mutation Events. Pro: Semantics are consistent: delivery happens right before the outermost DOM operation returns. This statement is true. When I described Option 2 (perhaps too harshly) as having inconsistent semantics, I was referrer only to the expectations of Callers and Observers. To be totally clear: Parties: Caller = any code which performers a DOM operation which triggers a mutation. Observer = any code to whom the mutation is delivered. Expectations for synchrony: Caller: When any DOM operation I make completes, all observers will have been notified. Observer: If I'm being notified, the Caller which triggered the mutation is below me on the stack. Parties: Caller Observer Options 1:Always Always 2:Sometimes(a) Sometimes(a) 3:Never Never 4:Never Never (a) True when Caller is run outside of a mutation observer callback. False when Caller is run inside a mutation observer callback. Easier transition from mutation events to the new API. Not bound to tasks. Side effects, like problems related to spinning event loop are per mutation callback, not per whole task. Option 3: At the end of the current Task. Pro: -No code is at risk for having its assumptions invalidated while it is trying to do work. All participants (main application script, libraries which are implemented using DOM mutation observation) are allowed to complete whatever work (DOM operations) they wish before another participant starts doing work. Con: Since the approach is bound to tasks, it is not clear what should happen if event loop spins while handling the task. What
Re: DOM Mutation Events Replacement: When to deliver mutations
On Thu, Aug 11, 2011 at 9:12 AM, Olli Pettay olli.pet...@helsinki.fi wrote: On 08/11/2011 06:13 PM, Rafael Weinstein wrote: Con: Since the approach is bound to tasks, it is not clear what should happen if event loop spins while handling the task. What if some other task modifies the DOM[1], when should the mutation callbacks fire? Because of this issue, tasks, which may spin event loop, should not also modify DOM since that may cause some unexpected result. I think the *pro* side of this you listed is more fair. Both Options 2 3 must answer this question. It's true that because Option 3 is later, it sort of has this issue more. And it has a lot more. Since for example when handling an event, all the listeners for it are called in the same task and if one event listener modifies DOM and some other spins event loop, it is hard to see what is causing the somewhat unexpected behavior. However, what should happen has been defined. In both cases, if there are any mutations which are queued for delivery when an inner event loop spins up, they are *not* delivered inside the inner event loop. In both Options, they are always delivered in the loop which queued them. But what happens when event loop spins within a task, and some inner task causes new mutations? We want to notify about mutations in the order they have happened, right? In general, yes. But I believe the idea is that spinning an inner event loop is an exception. In that case delivering mutations in the order they were generated will be broken. To be perfectly precise: Mutations will be delivered in the order they were generated *for and within any given event loop*. There's no question this is unfortunate. The case in which the bad thing happens is you: -Made some modifications to the main document -Used showModalDialog -Modified the opener document from the event loop of showModalDialog -Got confused because mutations from within the showModalDialog were delivered before the mutations made before calling it I suppose this comes down to judgement. Mine is that it's acceptable for us to not attempt to improve the outcome in this case. So if there are pending mutations to notify, the inner task must just queue notifications to the queue of the outermost task. This could effectively disable all the mutation callbacks for example when a modal dialog (showModalDialog) is open. Option 2 has similar problem, but *only* while handling mutation callbacks, not during the whole task. -Olli Callback handling is moved far away from the actual mutation. Pro: Can batch more, since the callbacks are called later than in option 2. -Olli [1] showModalDialog(javascript:opener.document.body.textContent = '';, , );
DOM Mutation Events Replacement: The Story So Far / Existing Points of Consensus
What follows is an attempt to summarize the (relatively recent) discussions regarding replacing DOM Mutation Events. My goals here are to: -Provide a quick primer for those who haven't read all hundred or so emails. -Reiterate the aspects of a solution which seem to have broad support. -Identify the main points of divergence which remain. Problem: DOM Mutation events as currently specified and implemented are widely viewed as fatally flawed because they are: (1) Verbose (fire too often) (2) Slow (because of event propagation -- and because they prevent certain UA run-time optimizations) (3) Crashy (have been the source of many crashers for UAs because script can tear up the world in any way it wishes while a DOM operation is underway). Solution: *Agreed upon design points: Primarily because of a proposal made by Jonas Sicking in 2009, the group has been largely in agreement about the following: (1) The vocabulary of mutations should be more expressive and require fewer words to adequately describe what happened . For instance, a single innerHTML assignment which results in removing N nodes and inserting M nodes should be expressed as a single mutation (e.g. { mutation: ChildlistChanged, added: [...], removed: [...] } ) -- not a sequence of mutations, one for each node inserted or removed. (2) Mutations should avoid the expense of event propagation (mainly capture bubble). (3) Mutations should be delivered to observers after the DOM operations which generated them complete -- removing the possibility of having script interfere with their operation. For example, an execCommand() operation is permitted to make any all DOM operations it needs *before* it has to notify any observers of what happened. Through discussing Jonas's proposal, we observed that in a system which allows multiple observers that can, themselves, make mutations, observers will generally need to be tolerant of an arbitrary number of mutations having occurred before being notified. Further, there is strong performance motivation for observers to respond to the net-effect of a set of mutations, rather than acting immediately in response to each mutation. Thus: (4) Observers should be called with the *set* of mutations which has occurred since they were last called (or since registration), rather than being called once per mutation. I.e. Deliver mutations in batches of everything that has happened since the last time I called you - up till now. To my understanding, the most recent proposals made by Jonas, Olli Pettay, Adam Klein and myself all agree on the above four design points. *Design points lacking consensus: (5) When are mutations delivered? There are four options here, only two of which have proponents. =I'm going to try to summarize the discussion on this point in a separate email. (6) The semantics for expressing interest in sets of nodes (7) What information is contained in mutation records =I've done a survey of the main use cases sited and prototyped the main net-effect projections. I'll summarize my findings in another email which attempts to layout the main trade-offs I see so far.
DOM Mutation Events Replacement: When to deliver mutations
Although everyone seems to agree that mutations should be delivered after the DOM operations which generated them complete, the question remains: When, exactly, should mutations be delivered? The four options I'm aware of are: 1) Immediately - i.e. while the operation is underway. [Note: This is how current DOM Mutation events work]. 2) Upon completion of the outer-most DOM operation. i.e. Immediately before a the lowest-on-the-stack DOM operation returns, but after it has done all of its work. 3) At the end of the current Task. i.e. immediately before the UA is about to fetch a new Task to run. 4) Scheduled as a future Task. i.e. fully async. --- Discussion: Options 1 4 are don't seem to have any proponents that I know of, so briefly: Option 1, Immediately: Pro: -It's conceptually the easiest thing to understand. The following *always* hold: -For calling code: When any DOM operation I make completes, all observers will have run. -For notified code: If I'm being called, the operation which caused this is below me on the stack. Con: -Because mutations must be delivered for some DOM operations before the operation is complete, UAs must tolerate all ways in which script may invalidate their assumptions before they do further work. Option 4, Scheduled as a future Task: Pro: -Conceptually easy to understand -Easy to implement. Con: -It's too late. Most use cases for mutation observation require that observers run before a paint occurs. E.g. a widget library which watches for special attributes. Script may create a div class=FooButton and an observer will react to this by decorating the div as a FooButton. It is unacceptable (creates visual artifacts/flickering) to have the div be painted before the widget library has decorated it as a FooButton. Both of these options appear to be non-starters. Option 1 has been shown by experience to be an unreasonable implementation burden for UAs. Option 4 clearly doesn't handle properly important use cases. --- Options 2 3 have proponents. Since I'm one of them (a proponent), I'll just summarize the main *pro* arguments for each and invite those who wish (including myself), to weigh in with further support or criticism in follow-on emails. Option 2: Upon completion of the outer-most DOM operation. Pro: -It's conceptually close to fully synchronous. For simple uses (specifically, setting aside the case of making DOM operations within a mutation callback), it has the advantages of Option 1, without its disadvantages. Because of this, it's similar to the behavior of current Mutation Events. Option 3: At the end of the current Task. Pro: -No code is at risk for having its assumptions invalidated while it is trying to do work. All participants (main application script, libraries which are implemented using DOM mutation observation) are allowed to complete whatever work (DOM operations) they wish before another participant starts doing work.
Re: DOM Mutation Events Replacement: When to deliver mutations
Ok. Being a proponent, here's my further (opinionated) support for Option 3 and criticism for Option 2. On Wed, Aug 10, 2011 at 5:44 PM, Rafael Weinstein rafa...@google.com wrote: Although everyone seems to agree that mutations should be delivered after the DOM operations which generated them complete, the question remains: When, exactly, should mutations be delivered? The four options I'm aware of are: 1) Immediately - i.e. while the operation is underway. [Note: This is how current DOM Mutation events work]. 2) Upon completion of the outer-most DOM operation. i.e. Immediately before a the lowest-on-the-stack DOM operation returns, but after it has done all of its work. 3) At the end of the current Task. i.e. immediately before the UA is about to fetch a new Task to run. 4) Scheduled as a future Task. i.e. fully async. --- Discussion: Options 1 4 are don't seem to have any proponents that I know of, so briefly: Option 1, Immediately: Pro: -It's conceptually the easiest thing to understand. The following *always* hold: -For calling code: When any DOM operation I make completes, all observers will have run. -For notified code: If I'm being called, the operation which caused this is below me on the stack. Con: -Because mutations must be delivered for some DOM operations before the operation is complete, UAs must tolerate all ways in which script may invalidate their assumptions before they do further work. Option 4, Scheduled as a future Task: Pro: -Conceptually easy to understand -Easy to implement. Con: -It's too late. Most use cases for mutation observation require that observers run before a paint occurs. E.g. a widget library which watches for special attributes. Script may create a div class=FooButton and an observer will react to this by decorating the div as a FooButton. It is unacceptable (creates visual artifacts/flickering) to have the div be painted before the widget library has decorated it as a FooButton. Both of these options appear to be non-starters. Option 1 has been shown by experience to be an unreasonable implementation burden for UAs. Option 4 clearly doesn't handle properly important use cases. --- Options 2 3 have proponents. Since I'm one of them (a proponent), I'll just summarize the main *pro* arguments for each and invite those who wish (including myself), to weigh in with further support or criticism in follow-on emails. Option 2: Upon completion of the outer-most DOM operation. Pro: -It's conceptually close to fully synchronous. For simple uses (specifically, setting aside the case of making DOM operations within a mutation callback), it has the advantages of Option 1, without its disadvantages. Because of this, it's similar to the behavior of current Mutation Events. Con: -The timing delays delivery just long enough to guarantee that DOM operations don't have to worry about having their work interfered with, but encourages application script to leave itself exposed to exactly the same risk. -The semantics of delivery are inconsistent. Delivery of mutations is synchronous if calling operation is performed outside of a mutation callback and async if performed inside a mutation callback. Option 3: At the end of the current Task. Pro: -No code is at risk for having its assumptions invalidated while it is trying to do work. All participants (main application script, libraries which are implemented using DOM mutation observation) are allowed to complete whatever work (DOM operations) they wish before another participant starts doing work. Pro: -Creates (and requires use of -- creates a pit of success) a time to run which is ideal in two ways: 1) Performance: The main script is finished doing its work. The observer can minimize work by reacting to only the net-effect of what happened. I.e. not do work in intermediate states which ultimately become irrelevant. E.g. a widget library which needs to destruct widgets which are removed from the document. If a widget is removed but later added elsewhere in the same script event, the library would prefer to avoid destructing the widget and just allow it to be moved. 2) Correctness: The observer isn't at risk for attempting to act when the main script has put the DOM (temporarily) in an inconsistent state. E.g. a templating library which depends upon the value of two attributes of a single element. If script wishes to change both values but cannot do so without creating a temporarily nonsensical state, the library would prefer not to have to react to the nonsensical state and simply wait for the consistent (final) state. To be fair to Option 2, it doesn't preclude these (but it isn't sufficient -- a separate ability to schedule work at the end of the Task would be required). Con: -Behaves quite differently from the current mutation events.
Re: Mutation events replacement
On Tue, Jul 19, 2011 at 4:56 PM, Jonas Sicking jo...@sicking.cc wrote: On Tue, Jul 19, 2011 at 4:18 PM, Ryosuke Niwa rn...@webkit.org wrote: Thanks for the new proposal, Jonas. I'm very excited about the progress we're making towards a saner world! On Tue, Jul 19, 2011 at 4:01 PM, Jonas Sicking jo...@sicking.cc wrote: [ { target: node1, type: childlist, added: [a, b, c, d], removed: [x, y] }, { target: node1, type: attributes, changed: [class, bgcolor, href] }, { target: node2, type: characterdata }, { target: node3, type: childlist, added: [r, s, t, x], removed: [z] } ] A few things to note here: * There is only ever one entry in the array for a given target+type pair. If, for example, multiple changes are made to the classlist of a given node, these changes are added to the added/removed lists. * For childlist changes, you get the full list of which nodes were added and removed. For editing purposes, it's also crucial to know from/to where nodes are removed/inserted. It seems like adding an offset trivially solves this problem without much overhead. I'm not really sure how you're expecting to use indexes. Not that once one node is removed, the index changes for all other nodes. Can you provide a short example code demonstrating how you'd use the index? It's not really short, but it's more or less the analog of doing a projection of a set of splice events if emitted by a hypothetical observable array (startIndex, numDeleted, numAdded). The code is implemented inside MDV here: https://code.google.com/p/mdv/source/browse/trunk/model.js#853 The goal of the projection is to produce a new set of splice mutation records which represent the net effect on the sequence (joining, collapsing, canceling), such that the new set minimally describes the changes and could be applied, in order, to a copy of the sequence's previous state to arrive at the new state. * For attributes changes you get a full list of which attributes were changed. However you do not get the new and old value of the attributes as this could result in significant overhead for attributes like style for example. Again, it'll be very useful to have old and new values for editing purposes. Although I have a reservation as to whether we should do for style or not because calling mutation listeners every time script modifies some style property will be quite expensive as it requires serializing CSSStyleDeclaration. * For characterdata you don't get the old or new value of the node. We could also simply add the before/after values here as there shouldn't be as much serialization overhead involved. For editing purposes, seeing old and new value is essential. As has been previously mentioned, providing the old value comes with significant overhead. For your usecase it seems like this is overhead that you'll need to live with, but for many others it might not be. We could solve this by making it configurable if you want the old values or not. For example by having separate notification types that contain before and after values. Though note that providing the after-values rarely seems useful as you can simply get them as needed from the DOM. As for childlists, the only sane solution I can think of would be to provide what the whole childlist looked like before modifications started. / Jonas
Re: Mutation events replacement
On Thu, Jul 7, 2011 at 1:58 PM, Ryosuke Niwa rn...@webkit.org wrote: On Thu, Jul 7, 2011 at 12:18 PM, Jonas Sicking jo...@sicking.cc wrote: I don't think John J Barton's proposal to fire before mutation notifications is doable. I concur. Being synchronous was one of the reasons why the existing DOM mutation events don't work. We shouldn't adding yet-another synchronous event here. In short before spending more time on this, I'd like to see a comprehensive proposal, including a description of the use cases it solves and how it solves them. I strongly doubt that this approach is practical. Totally agreed. I really like Rafael's proposal to pass a list of mutations that has happened to the notification callbacks. This has the advantage that scripts get *all* the changes that has happened at once, making it possible to make decisions based on all changes made, rather than piece-wise getting the information in separate callbacks. It also has the advantage that we can provide much more detailed information without having to make multiple calls from C++ to JS which is good for performance. For example it seems very doable to provide lists of all nodes that has been removed and added while still keeping performance reasonable. Enthusiastically agreed. I'll write up a proposal based on this idea. Others should feel free to beat me to it :) Nice! Looking forward to it. The main concern that I have with this proposal is that it's so different from mutation events that it might not satisfy the same use cases. Consider a widget implementation that currently observes the DOM using mutation events and makes it possible to write code like: myWidgetBackedElement.appendChild(someNode); myWidgetBackedElement.someFunction(); where someFunction depends on state which is updated by the mutation event handler. Such a widget implementation is simply not doable with these semi-asynchronous callbacks. Right. But on the other hand, if this code were to run inside a mutation observer, it won't work in your proposal either. So the questions is whether writing a function that depends on state updated by the mutation observer without a mutation observer, and then later calling it inside a mutation observer happens frequently enough to annoy developers or not. On the other hand, maybe this isn't a big deal. We are definitely short on use cases for mutation events in general which is a problem. Right. Olli Jonas, I'd really like to understand your thinking about this. Are we not understanding something about your proposal? If accommodating the above is a goal, it seems like the only option is to have mutation events be fully synchronous. I.e. It doesn't seem acceptable to encourage a widget author to expose an API that depends on never being called inside a mutation callback and/or prevents it from being used as a building block for a higher-level abstraction. Agreed. We probably need more real-world use cases. - Ryosuke
Re: Mutation events replacement
On Thu, Jul 7, 2011 at 3:19 PM, Jonas Sicking jo...@sicking.cc wrote: On Thu, Jul 7, 2011 at 2:32 PM, Rafael Weinstein rafa...@google.com wrote: On Thu, Jul 7, 2011 at 1:58 PM, Ryosuke Niwa rn...@webkit.org wrote: On Thu, Jul 7, 2011 at 12:18 PM, Jonas Sicking jo...@sicking.cc wrote: I don't think John J Barton's proposal to fire before mutation notifications is doable. I concur. Being synchronous was one of the reasons why the existing DOM mutation events don't work. We shouldn't adding yet-another synchronous event here. In short before spending more time on this, I'd like to see a comprehensive proposal, including a description of the use cases it solves and how it solves them. I strongly doubt that this approach is practical. Totally agreed. I really like Rafael's proposal to pass a list of mutations that has happened to the notification callbacks. This has the advantage that scripts get *all* the changes that has happened at once, making it possible to make decisions based on all changes made, rather than piece-wise getting the information in separate callbacks. It also has the advantage that we can provide much more detailed information without having to make multiple calls from C++ to JS which is good for performance. For example it seems very doable to provide lists of all nodes that has been removed and added while still keeping performance reasonable. Enthusiastically agreed. I'll write up a proposal based on this idea. Others should feel free to beat me to it :) Nice! Looking forward to it. The main concern that I have with this proposal is that it's so different from mutation events that it might not satisfy the same use cases. Consider a widget implementation that currently observes the DOM using mutation events and makes it possible to write code like: myWidgetBackedElement.appendChild(someNode); myWidgetBackedElement.someFunction(); where someFunction depends on state which is updated by the mutation event handler. Such a widget implementation is simply not doable with these semi-asynchronous callbacks. Right. But on the other hand, if this code were to run inside a mutation observer, it won't work in your proposal either. So the questions is whether writing a function that depends on state updated by the mutation observer without a mutation observer, and then later calling it inside a mutation observer happens frequently enough to annoy developers or not. On the other hand, maybe this isn't a big deal. We are definitely short on use cases for mutation events in general which is a problem. Right. Olli Jonas, I'd really like to understand your thinking about this. Are we not understanding something about your proposal? If accommodating the above is a goal, it seems like the only option is to have mutation events be fully synchronous. I.e. It doesn't seem acceptable to encourage a widget author to expose an API that depends on never being called inside a mutation callback and/or prevents it from being used as a building block for a higher-level abstraction. It's definitely the case that APIs will behave differently inside the mutation notification, and that the code example showed above would not work from inside the notification. Basically I'm asking people to tread carefully inside mutation notifications and only do the minimal amount of data gathering. Heh. We're kind of in violent agreement here. =-) So yes, my proposal only solves the usecase outside mutation handlers. However this is arguably better than never solving the use case as in your proposal. I'm sure people will end up writing buggy code, but ideally this will be found and fixed fairly easily as the behavior is consistent. We are at least giving people the tools needed to implement the synchronous behavior. Ok. Thanks for clarifying. It's helpful to understand this. I'm glad there's mostly common ground on the larger issue. The point of contention is clearly whether accommodating some form of sync mutation actions is a goal or non-goal. It occurs to me that the main use case raised in favor of sync mutation actions is more or less the custom component/widget use case. This seems to border alot on XBL2. Maybe it's useful to look at it through that lens? /me grabs blindly at the air for good ideas about how to come to consensus. / Jonas
Re: Mutation events replacement
Respond On Tue, Jul 5, 2011 at 10:44 AM, Olli Pettay olli.pet...@helsinki.fi wrote: On 07/01/2011 02:17 AM, Rafael Weinstein wrote: On Thu, Jun 30, 2011 at 4:05 AM, Olli Pettayolli.pet...@helsinki.fi wrote: On 06/30/2011 12:54 AM, Rafael Weinstein wrote: On Wed, Jun 29, 2011 at 7:13 AM, Aryeh Gregorsimetrical+...@gmail.com wrote: On Tue, Jun 28, 2011 at 5:24 PM, Jonas Sickingjo...@sicking.cc wrote: This new proposal solves both these by making all the modifications first, then firing all the events. Hence the implementation can separate implementing the mutating function from the code that sends out notifications. Conceptually, you simply queue all notifications in a queue as you're making modifications to the DOM, then right before returning from the function you insert a call like flushAllPendingNotifications(). This way you don't have to care at all about what happens when those notifications fire. So when exactly are these notifications going to be fired? In particular, I hope non-DOM Core specifications are going to have precise control over when they're fired. For instance, execCommand() will ideally want to do all its mutations at once and only then fire the notifications (which I'm told is how WebKit currently works). How will this work spec-wise? Will we have hooks to say things like remove a node but don't fire the notifications yet, and then have to add an extra line someplace saying to fire all the notifications? This could be awkward in some cases. At least personally, I often say things like call insertNode(foo) on the range in the middle of a long algorithm, and I don't want magic happening at that point just because DOM Range fires notifications before returning from insertNode. Also, even if specs have precise control, I take it the idea is authors won't, right? If a library wants to implement some fancy feature and be compatible with users of the library firing these notifications, they'd really want to be able to control when notifications are fired, just like specs want to. In practice, the only reason this isn't an issue with DOM mutation events is because they can say don't use them, and in fact people rarely do use them, but that doesn't seem ideal -- it's just saying library authors shouldn't bother to be robust. In working on Model Driven Views (http://code.google.com/p/mdv), we've run into exactly this problem, and have developed an approach we think is promising. The idea is to more or less take Jonas's proposal, but instead of firing callbacks immediately before the outer-most mutation returns, mutations are recorded for a given observer and handed to it as an in-order sequence at the end of the event. What is the advantage comparing to Jonas' proposal? You guys did the conceptual heavy lifting WRT this problem. Jonas's proposal solves the main problems with current mutation events: (1) they fire too often, (2) they are expensive because of event propagation, (3) they are crashy WRT some DOM operations. If Jonas's proposal is the ultimate solution, I think it's a good outcome and a big improvement over existing spec or tearing out mutation events. I'm asking the group to consider a few changes which I'm hoping are improvements. I'll be happy if I fail =-). --- My concern with Jonas's proposal is that its semantics depend on context (inside vs. outside of a mutation notification). I feel like this is at least a conceptual problem. That, and I kind of shudder imagining trying to explain to a webdev why and when mutation notifications are sync vs async. The place it seems likely to fall down is when someone designs an abstraction using mutation events and depends on them firing synchronously -- then they or someone else attempt to use it inside another abstraction which uses mutation events. How likely is that? I don't even have a guess, but I'm pretty surprised at the crazy things people did with current mutation events. Our proposal's semantics aren't dependent on context. Additionally, our proposal makes it clear that handling a mutation notification is an exercise in dealing with an arbitrary number of ways the DOM could have changed since you were last called. I.e. providing the list of changes. In short, I feel like our proposal is just a small tweak on Jonas's. It is more direct in its form and API about the actually difficultly of being a mutation observer. Also, I'll just note a difference in view: We view it as fundamentally a bad thing to have more than one actor operating at a time (where actor == event handler, or abstraction which observes mutations). It seems as though you guys view this as a good thing (i.e. All other problems aside, mutation events *should* be synchronous). The example I keep using internally is this: an app which uses a) A constraint library which manages interactions between form values (observes data mutations, makes data
Re: Mutation events replacement
On Mon, Jul 4, 2011 at 6:43 PM, Boris Zbarsky bzbar...@mit.edu wrote: On 7/4/11 12:28 PM, Ojan Vafai wrote: I'm not sure there really is a performance tradeoff. I believe that the proposal Rafael put forward should almost always be faster. Storing the list of changes and doing a JS callback once, for nearly all use-cases, should be faster than frequent, semi-synchronous callbacks. That depends on whether your list of changes gets big enough that your start swapping, for example. Just to be clear here (since there's been some discussion of a flag which would cause fine-grain notifications) -- I don't believe there's any need to describe *more* mutations. I.e. My proposal is *not* to record more than one mutation record for a call to innerHTML which affects more than one element. That case would still be a single 'ChildlistChanged' mutation. This is a key part of Jonas's proposal that we want to keep: It is (I think) optimally succinct, while still containing (nearly -- see below) all the bits of information that you need. I.e. The set of mutation records during any given event should be more or less on the order of the number of DOM *operations* -- not affected nodes. Also note that it seems like the multiple observers can share the same mutation record (just like multiple event listeners share the same event object). The question is how much data is contained in the mutation record. Here's my sense: For ChildlistChanged, the potential data to be included: -Target node* -Removed nodes* -Added nodes -one of nextSibling or previousSibling* My belief is that including the starred (*) data above would be sufficient to meet David's test of mirroring a tree *without* a ton of processing or O(N) memory. If people think it's worth while seeing example js code that implements this properly and it'll convince the group that this data is sufficient, I'll sign up for implementing it. The only bit that might be slower is what data you include in the mutation list. That's one of the things that could get slower, yes. It's not the only one. -The index of the child that changed for ChildListChanged (is this actually expensive?) It could be. In Gecko's case it's cheap right now because kids are stored in arrays, but WebKit uses doubly linked lists with a cache of some sort for indices last I checked. So for some access patterns this could be pretty expensive in WebKit. -The old value of an attribute/text node. I know this is expensive in Gecko's engine at least. This can be expensive in all engines, if they do it right. Consider having to serialize out values of the 'style' attribute (possibly twice) on every .style.foo set. Or having to serialize out path attributes as the SVG DOM is mutating paths. This is not a Gecko-specific issue. I'd be fine with excluding that information by default, but having a flag you pass at some point saying to include those. That way, only sites that need it take the performance hit. This would be a lot more palatable to me, yes. This brings us back to having ways to ask for different levels of detail in mutation notifications. -Boris
Re: Mutation events replacement
On Mon, Jul 4, 2011 at 9:57 AM, Olli Pettay olli.pet...@helsinki.fi wrote: On 07/04/2011 07:28 PM, Ojan Vafai wrote: Apologies in advance if my comment makes no sense. This is a long thread, I tried to digest it all. :) On Sat, Jul 2, 2011 at 7:07 AM, Boris Zbarsky bzbar...@mit.edu mailto:bzbar...@mit.edu wrote: That may be ok, if the use cases that incur this cost are rare and the common case can be better served by a different approach. Or put another way, if 1% of consumers want the full list because it makes them 4x faster and the other 99% don't want the full list, and the full list is 3x slower for the browser to build than just providing the information the 99% want, what's the right tradeoff? I'm not sure there really is a performance tradeoff. I believe that the proposal Rafael put forward should almost always be faster. Storing the list of changes and doing a JS callback once, for nearly all use-cases, should be faster than frequent, semi-synchronous callbacks. The only bit that might be slower is what data you include in the mutation list. I believe that all the data you'd need is cheap except for possibly the following two: -The index of the child that changed for ChildListChanged (is this actually expensive?) You may need more than just an index. element.innerHTML = null removes all the child nodes. And element.inserBefore(some_document_fragment, element.lastChild) may insert several child nodes. Depending on whether we want to get notified for each mutation or batch the mutations, simple index may or may not be enough. I think both of these can be a single ChildlistChanged mutation (not a batch of mutations). -The old value of an attribute/text node. I know this is expensive in Gecko's engine at least. Shouldn't be that slow. Mutation listener could easily implement old/new value handling itself, especially if it knows which attributes it is interested in. I'd be fine with excluding that information by default, but having a flag you pass at some point saying to include those. That way, only sites that need it take the performance hit. The numbers above are made up, of course; it would be useful to have some hard data on the actual use cases. Maybe we need both sorts of APIs: one which generates a fine-grained change list and incurs a noticeable DOM mutation performance hit and one which batches changes more but doesn't slow the browser down as much... -Boris
Re: Mutation events replacement
On Tue, Jul 5, 2011 at 2:27 PM, Boris Zbarsky bzbar...@mit.edu wrote: On 7/5/11 5:21 PM, Rafael Weinstein wrote: For ChildlistChanged, the potential data to be included: -Target node* -Removed nodes* -Added nodes -one of nextSibling or previousSibling* My belief is that including the starred (*) data above would be sufficient to meet David's test of mirroring a tree *without* a ton of processing or O(N) memory. How is that not O(N) memory? Sorry - that was imprecise. What I meant was: the application script wouldn't need to maintain more or less it's own copy of the DOM to know for certain whether a node has effectively been added, removed, or moved elsewhere in the document. -Boris
Re: Mutation events replacement
On Tue, Jul 5, 2011 at 2:29 PM, Rafael Weinstein rafa...@google.com wrote: On Tue, Jul 5, 2011 at 2:27 PM, Boris Zbarsky bzbar...@mit.edu wrote: On 7/5/11 5:21 PM, Rafael Weinstein wrote: For ChildlistChanged, the potential data to be included: -Target node* -Removed nodes* -Added nodes -one of nextSibling or previousSibling* My belief is that including the starred (*) data above would be sufficient to meet David's test of mirroring a tree *without* a ton of processing or O(N) memory. Doh! Sorry. Just to note: if you omit Added Nodes, I think you'd need AddedNodeCount. Generally speaking, to avoid application script needing to make copies of wholesale DOM structures, it needs to be given the old data and the shape of the new data E.g.: For ChildlistChanged: removedNodes + addedNodeCount next/previousSibling. For AttributeChanged: added/removed/updated + oldValue For TextChanged: oldValue. This may be an unreasonable burden for UA's to deliver all the time. If so, a give me old data flag seems worth considering. Many use-cases will be aiming to minimize expensive work (typically creating more DOM or writing to the wire) -- and it'll be tempting to guarantee that work *has* to be done. Lacking old data, the application will need to preemptively make a copy of all data that *could* change. How is that not O(N) memory? Sorry - that was imprecise. What I meant was: the application script wouldn't need to maintain more or less it's own copy of the DOM to know for certain whether a node has effectively been added, removed, or moved elsewhere in the document. -Boris
Re: Mutation events replacement
On Tue, Jul 5, 2011 at 2:38 PM, Olli Pettay olli.pet...@helsinki.fi wrote: On 07/06/2011 12:18 AM, Olli Pettay wrote: On 07/06/2011 12:06 AM, Rafael Weinstein wrote: Respond On Tue, Jul 5, 2011 at 10:44 AM, Olli Pettayolli.pet...@helsinki.fi wrote: On 07/01/2011 02:17 AM, Rafael Weinstein wrote: On Thu, Jun 30, 2011 at 4:05 AM, Olli Pettayolli.pet...@helsinki.fi wrote: On 06/30/2011 12:54 AM, Rafael Weinstein wrote: On Wed, Jun 29, 2011 at 7:13 AM, Aryeh Gregorsimetrical+...@gmail.com wrote: On Tue, Jun 28, 2011 at 5:24 PM, Jonas Sickingjo...@sicking.cc wrote: This new proposal solves both these by making all the modifications first, then firing all the events. Hence the implementation can separate implementing the mutating function from the code that sends out notifications. Conceptually, you simply queue all notifications in a queue as you're making modifications to the DOM, then right before returning from the function you insert a call like flushAllPendingNotifications(). This way you don't have to care at all about what happens when those notifications fire. So when exactly are these notifications going to be fired? In particular, I hope non-DOM Core specifications are going to have precise control over when they're fired. For instance, execCommand() will ideally want to do all its mutations at once and only then fire the notifications (which I'm told is how WebKit currently works). How will this work spec-wise? Will we have hooks to say things like remove a node but don't fire the notifications yet, and then have to add an extra line someplace saying to fire all the notifications? This could be awkward in some cases. At least personally, I often say things like call insertNode(foo) on the range in the middle of a long algorithm, and I don't want magic happening at that point just because DOM Range fires notifications before returning from insertNode. Also, even if specs have precise control, I take it the idea is authors won't, right? If a library wants to implement some fancy feature and be compatible with users of the library firing these notifications, they'd really want to be able to control when notifications are fired, just like specs want to. In practice, the only reason this isn't an issue with DOM mutation events is because they can say don't use them, and in fact people rarely do use them, but that doesn't seem ideal -- it's just saying library authors shouldn't bother to be robust. In working on Model Driven Views (http://code.google.com/p/mdv), we've run into exactly this problem, and have developed an approach we think is promising. The idea is to more or less take Jonas's proposal, but instead of firing callbacks immediately before the outer-most mutation returns, mutations are recorded for a given observer and handed to it as an in-order sequence at the end of the event. What is the advantage comparing to Jonas' proposal? You guys did the conceptual heavy lifting WRT this problem. Jonas's proposal solves the main problems with current mutation events: (1) they fire too often, (2) they are expensive because of event propagation, (3) they are crashy WRT some DOM operations. If Jonas's proposal is the ultimate solution, I think it's a good outcome and a big improvement over existing spec or tearing out mutation events. I'm asking the group to consider a few changes which I'm hoping are improvements. I'll be happy if I fail =-). --- My concern with Jonas's proposal is that its semantics depend on context (inside vs. outside of a mutation notification). I feel like this is at least a conceptual problem. That, and I kind of shudder imagining trying to explain to a webdev why and when mutation notifications are sync vs async. The place it seems likely to fall down is when someone designs an abstraction using mutation events and depends on them firing synchronously -- then they or someone else attempt to use it inside another abstraction which uses mutation events. How likely is that? I don't even have a guess, but I'm pretty surprised at the crazy things people did with current mutation events. Our proposal's semantics aren't dependent on context. Additionally, our proposal makes it clear that handling a mutation notification is an exercise in dealing with an arbitrary number of ways the DOM could have changed since you were last called. I.e. providing the list of changes. In short, I feel like our proposal is just a small tweak on Jonas's. It is more direct in its form and API about the actually difficultly of being a mutation observer. Also, I'll just note a difference in view: We view it as fundamentally a bad thing to have more than one actor operating at a time (where actor == event handler, or abstraction which observes mutations). It seems as though you guys view this as a good thing (i.e. All other problems aside, mutation events *should* be synchronous
Re: Mutation events replacement
On Tue, Jul 5, 2011 at 3:55 PM, Ryosuke Niwa rn...@webkit.org wrote: On Tue, Jul 5, 2011 at 3:24 PM, Olli Pettay olli.pet...@helsinki.fi wrote: On 07/06/2011 12:48 AM, Rafael Weinstein wrote: On Tue, Jul 5, 2011 at 2:38 PM, Olli Pettayolli.pet...@helsinki.fi wrote: What is the reason to require a new mechanism for async handling? Could listeners be handled in a task?Basically, if DOM is mutated during task A, a new task, B, is scheduled and all the mutation listeners will be called there. It's too late by then. Most importantly, visual artifacts of incomplete DOM work may have been seen by the user. If that is the reason, I don't think it really holds. The script may force a layout flush right after DOM mutation and then cause some popup to shows up which may cause repainting in the main page. Layout is different from paint at least in WebKit. But I agree with you that if any observer calls alert, showModalDialog, and other APIs that forces repaint, you can't really do anything about it. Also, UA vendors can decide to delay the repaint until all mutation observers are called in common cases even if they were completely asynchronous. It seems like these are rarified enough cases that visual artifacts are acceptable collateral damage if you do this. [Put another way, if you care enough about the visual polish of your app that you will put energy into avoiding flickr, you probably aren't using alert and showModalDialog anyway]. Also, it's up to the app when to do it, so it's entirely in its control (and thus avoid visual artifacts). Note that this is a problem with both proposals. Work done in (at least some) mutation observers is delayed. If a sync paint occurs before it, it's work won't be reflected on the screen. - Ryosuke
Re: Mutation events replacement
On Fri, Jul 1, 2011 at 12:43 PM, David Flanagan dflana...@mozilla.com wrote: On 7/1/11 12:13 PM, Boris Zbarsky wrote: On 7/1/11 3:05 PM, David Flanagan wrote: I don't think I really explained my use case on this list. See https://bugzilla.mozilla.org/show_bug.cgi?id=641821#c23 and https://bugzilla.mozilla.org/show_bug.cgi?id=641821#c25 And https://bugzilla.mozilla.org/show_bug.cgi?id=641821#c26 please Yes, that too. I agree that my use case is different than the one that Olli's proposal is addressing. But Ryosuke asked about my use case :-) Similarly, I've found it important to be able to distinguish between nodes that are being removed from a document tree and nodes that are being moved within the document tree, Interesting, given that Gecko's DOM implementation does NOT make such a distinction at the moment. Why did you find this to be important? As I see it, the test of sufficiency of set of mutation event is if you can use them to mirror a document tree. And in my case I'm trying to do that across a process boundary where I can't share nodes--I have to serialize everything to a string or something similar. If I call appendChild() on a node that is already in the tree, that removes it from its current parent and inserts it into a new parent. If that generates a remove event and then an insert event I'll end up having to completely re-serialize the node (and all of its children) to re-insert it from scratch into the mirror tree. If the appendChild() generates a move event then I can simply serialize the fact that an existing node has moved. There are probably ways I could make this work without a move event, but that's why I found it useful to make the distinction. To clarify: Are you worried that it isn't possible to detect the move and avoid serializing the non-novel node without the move information in the underlying mutationList? Or are you concerned that detecting this is work and it might be good to just provide the information and remove the need for the observer to do that work? Your point about the sufficiency test being mirroring a tree seems exactly right to me. I may be missing something, but I think move isn't strictly necessary. Implementations will presumably maintain one list of all current mutations, and then will have to filter that list to deliver only those that match the desired type and desired subtree for which a listener is registered. That's unclear. Maintaining this list (if it were done) sounds very expensive; in Gecko's case we're more likely to drop on the floor the ones which have no registered listeners. Sure, but if there were multiple listeners on different subtrees, listening for different types of events, would you built up a custom mutation list for each one as the mutations were occuring? Or build up one master list and then filter it lazily when the events are dispatched? David -Boris
Re: Mutation events replacement
On Fri, Jul 1, 2011 at 3:25 PM, David Flanagan dflana...@mozilla.com wrote: On 7/1/11 3:06 PM, Olli Pettay wrote: On 07/02/2011 12:59 AM, David Flanagan wrote: But, and I think this is an interesting but, what happens if a node is removed from the document, has its attributes or data or children changed and is then re-inserted into the document? If the node has no parent when it is changed, no mutation events will be generated, will they? Sure they are. If the node has listeners, they will get called. I'm assuming the listeners are further up the tree. To give a concrete example, to a mutation event listener (under Rafael's proposal, but maybe yours, too?) on the document, these two sequences of operations will be indistinguishable: // Generates one event for removing the title text from the head and another for // inserting it into the body. (Assume document.head.firstChild.firstChild is the text node inside // the title tag. document.body.appendChild(document.head.firstChild.firstChild); // Here we generate the same sequence of mutation events var titletext = document.head.firstChild.firstChild. titletext.parentNode.removeChild(titletext); // Generates a remove event titletext.data = foobar; // Generates a mutation event no one sees document.body.appendChild(titletext); // Generates an insert event I claim that it is useful to be able to distinguish these two cases with some sort of move event. If moves are treated as remove/insert pairs, then listeners have to assume that arbitrary changes could have taken place between the two. If you want to discover mutations to nodes while outside the tree, then having a single subtree observer isn't sufficient. You'll need an attribute observer registered on all elements reachable from the root. I believe this is the same with both proposals. David
Re: Mutation events replacement
On Thu, Jun 30, 2011 at 4:05 AM, Olli Pettay olli.pet...@helsinki.fi wrote: On 06/30/2011 12:54 AM, Rafael Weinstein wrote: On Wed, Jun 29, 2011 at 7:13 AM, Aryeh Gregorsimetrical+...@gmail.com wrote: On Tue, Jun 28, 2011 at 5:24 PM, Jonas Sickingjo...@sicking.cc wrote: This new proposal solves both these by making all the modifications first, then firing all the events. Hence the implementation can separate implementing the mutating function from the code that sends out notifications. Conceptually, you simply queue all notifications in a queue as you're making modifications to the DOM, then right before returning from the function you insert a call like flushAllPendingNotifications(). This way you don't have to care at all about what happens when those notifications fire. So when exactly are these notifications going to be fired? In particular, I hope non-DOM Core specifications are going to have precise control over when they're fired. For instance, execCommand() will ideally want to do all its mutations at once and only then fire the notifications (which I'm told is how WebKit currently works). How will this work spec-wise? Will we have hooks to say things like remove a node but don't fire the notifications yet, and then have to add an extra line someplace saying to fire all the notifications? This could be awkward in some cases. At least personally, I often say things like call insertNode(foo) on the range in the middle of a long algorithm, and I don't want magic happening at that point just because DOM Range fires notifications before returning from insertNode. Also, even if specs have precise control, I take it the idea is authors won't, right? If a library wants to implement some fancy feature and be compatible with users of the library firing these notifications, they'd really want to be able to control when notifications are fired, just like specs want to. In practice, the only reason this isn't an issue with DOM mutation events is because they can say don't use them, and in fact people rarely do use them, but that doesn't seem ideal -- it's just saying library authors shouldn't bother to be robust. In working on Model Driven Views (http://code.google.com/p/mdv), we've run into exactly this problem, and have developed an approach we think is promising. The idea is to more or less take Jonas's proposal, but instead of firing callbacks immediately before the outer-most mutation returns, mutations are recorded for a given observer and handed to it as an in-order sequence at the end of the event. What is the advantage comparing to Jonas' proposal? You guys did the conceptual heavy lifting WRT this problem. Jonas's proposal solves the main problems with current mutation events: (1) they fire too often, (2) they are expensive because of event propagation, (3) they are crashy WRT some DOM operations. If Jonas's proposal is the ultimate solution, I think it's a good outcome and a big improvement over existing spec or tearing out mutation events. I'm asking the group to consider a few changes which I'm hoping are improvements. I'll be happy if I fail =-). --- My concern with Jonas's proposal is that its semantics depend on context (inside vs. outside of a mutation notification). I feel like this is at least a conceptual problem. That, and I kind of shudder imagining trying to explain to a webdev why and when mutation notifications are sync vs async. The place it seems likely to fall down is when someone designs an abstraction using mutation events and depends on them firing synchronously -- then they or someone else attempt to use it inside another abstraction which uses mutation events. How likely is that? I don't even have a guess, but I'm pretty surprised at the crazy things people did with current mutation events. Our proposal's semantics aren't dependent on context. Additionally, our proposal makes it clear that handling a mutation notification is an exercise in dealing with an arbitrary number of ways the DOM could have changed since you were last called. I.e. providing the list of changes. In short, I feel like our proposal is just a small tweak on Jonas's. It is more direct in its form and API about the actually difficultly of being a mutation observer. Also, I'll just note a difference in view: We view it as fundamentally a bad thing to have more than one actor operating at a time (where actor == event handler, or abstraction which observes mutations). It seems as though you guys view this as a good thing (i.e. All other problems aside, mutation events *should* be synchronous). The example I keep using internally is this: an app which uses a) A constraint library which manages interactions between form values (observes data mutations, makes data mutations) b) A templating library (like MDV) which maps data to DOM (observes both DOM and data mutations, makes both DOM and data mutations) c) A widget library (like jQuery) which
Re: Mutation events replacement
On Wed, Jun 29, 2011 at 7:13 AM, Aryeh Gregor simetrical+...@gmail.com wrote: On Tue, Jun 28, 2011 at 5:24 PM, Jonas Sicking jo...@sicking.cc wrote: This new proposal solves both these by making all the modifications first, then firing all the events. Hence the implementation can separate implementing the mutating function from the code that sends out notifications. Conceptually, you simply queue all notifications in a queue as you're making modifications to the DOM, then right before returning from the function you insert a call like flushAllPendingNotifications(). This way you don't have to care at all about what happens when those notifications fire. So when exactly are these notifications going to be fired? In particular, I hope non-DOM Core specifications are going to have precise control over when they're fired. For instance, execCommand() will ideally want to do all its mutations at once and only then fire the notifications (which I'm told is how WebKit currently works). How will this work spec-wise? Will we have hooks to say things like remove a node but don't fire the notifications yet, and then have to add an extra line someplace saying to fire all the notifications? This could be awkward in some cases. At least personally, I often say things like call insertNode(foo) on the range in the middle of a long algorithm, and I don't want magic happening at that point just because DOM Range fires notifications before returning from insertNode. Also, even if specs have precise control, I take it the idea is authors won't, right? If a library wants to implement some fancy feature and be compatible with users of the library firing these notifications, they'd really want to be able to control when notifications are fired, just like specs want to. In practice, the only reason this isn't an issue with DOM mutation events is because they can say don't use them, and in fact people rarely do use them, but that doesn't seem ideal -- it's just saying library authors shouldn't bother to be robust. In working on Model Driven Views (http://code.google.com/p/mdv), we've run into exactly this problem, and have developed an approach we think is promising. The idea is to more or less take Jonas's proposal, but instead of firing callbacks immediately before the outer-most mutation returns, mutations are recorded for a given observer and handed to it as an in-order sequence at the end of the event. var observer = window.createMutationObserver(callback); document.body.addSubtreeChangedObserver(observer); document.body.addSubtreeAttributeChangedObserver(observer); ... var div = document.createElement('div'); document.body.appendChild(div); div.setAttribute('data-foo', 'bar'); div.innerHTML = 'bsomething/b isomething else/i'; div.removeChild(div.childNodes[1]); ... // mutationList is an array, all the entries added to // |observer| during the preceding script event function callback(mutationList) { // mutationList === [ // { type: 'ChildlistChanged', target: document.body, inserted: [div] }, // { type: 'AttributeChanged', target: div, attrName: 'data-foo' }, // { type: 'ChildlistChanged', target: div, inserted: [b, i] }, // { type: 'ChildlistChanged', target: div, removed: [i] } // ]; } Maybe this is a stupid question, since I'm not familiar at all with the use-cases involved, but why can't we delay firing the notifications until the event loop spins? If we're already delaying them such that there are no guarantees about what the DOM will look like by the time they fire, it seems like delaying them further shouldn't hurt the use-cases too much more. And then we don't have to put further effort into saying exactly when they fire for each method. Agreed. For context, after considering this issue, we've tentatively concluded a few things that don't seem to be widely agreed upon: 1) In terms of when to notify observers: Sync is too soon. Async (add a Task) is too late. - The same reasoning for why firing sync callbacks in the middle of DOM operations is problematic for C++ also applies to application script. Calling mutation observers synchronously can invalidate the assumptions of the code which is making the modifications. It's better to allow one bit of code to finish doing what it needs to and let mutation observers operate later over the changes. - Many uses of mutation events would actually *prefer* to not run sync because the originating code may be making multiple changes which more or less comprise a transaction. For consistency and performance, the abstraction which is watching changes would like to operate on the final state. - However, typical uses of mutation events do want to operate more or less in the same event because they are trying to create a new consistent state. They'd like to run after the application code is finished, but before paint occurs or the next scheduled event runs. 2) Because the system must allow multiple observers and allow
Re: Model-driven Views
Thanks everyone for your consideration. It sounds like the group wants to proceed by looking first at missing primitives. Maciej is right that one of them is the ability to declare inert DOM structures, but my feeling is that it's probably best to start with the central problem: -There's no way to observe mutations to JS objects. Current approaches resort to a number of hacks which create really terrible artifacts in application code. The ECMA Script Proxy mechanism may be the best starting point, but there's a related problem with timing that isn't addressed. I'll start a thread shortly on this problem detailing our best understanding, and make an attempt to loop in library authors to get their view. On Thu, Apr 28, 2011 at 2:02 AM, Maciej Stachowiak m...@apple.com wrote: On Apr 27, 2011, at 6:46 PM, Rafael Weinstein wrote: What do you think? - Is this something you'd like to be implemented in the browsers, Yes. and if yes, why? What would be the reasons to not just use script libraries (like your prototype). FAQ item also coming for this. Having heard Rafael's spiel for this previously, I believe there are some things that templating engines want to do, which are hard to do efficiently and conveniently using the existing Web platform. However, I think it would be better to add primitives to the Web platform that could be used by the many templating libraries that already exist, at least as a first step: - There is a lot of code built using many of the existing templating solutions. If we provide primitives that let those libraries become more efficient, that is a greater immediate payoff than creating a new templating system, where Web apps would have to be rewritten to take advantage. - It seems somewhat hubristic to assume that a newly invented templating library is so superior to all the already existing solutions that we should encode its particular design choices into the Web platform immediately. - This new templating library doesn't have enough real apps built on it yet to know if it is a good solution to author problems. - Creating APIs is best done incrementally. API is forever, on the Web. - Looking at the history of querySelector(), I come to the following conclusion: when there are already a lot of library-based solutions to a problem, the best approach is to provide technology that can be used inside those libraries to improve them; this is more valuable than creating an API with a primary goal of direct use. querySelector gets used a lot more via popular JavaScript libraries than directly, and should have paid more attention to that use case in the first place. Perhaps there are novel arguments that will dissuade me from this line of thinking, but these are my tentative thoughts. Regards, Maciej
Re: Model-driven Views
opaque to robots on the web. The data already canonically live in the JS heap. -Allowing declarative support for separating view model opens the way for web-automation to better understand what's going on. 9) We need to lead here and create a pit of success. The current pit is full of nasty stuff. -Creating a templating library that mostly works is easy and fun. Every framework is going to have one and everyone who creates one is going to make the same XSS mistakes (by use of innerHTML), and finally discover that it doesn't really work with dynamic applications. -The web is deeply engrained in the approach of imperative templating. It's non-obvious to typical webdevs why this approach doesn't have legs. -The web has succeeded dramatically by making complex things easy. Offering support here will raise the bar substantively for what a novice webdev can achieve. Web applications shouldn't just be the domain of web ninjas. On Thu, Apr 28, 2011 at 2:02 AM, Maciej Stachowiak m...@apple.com wrote: On Apr 27, 2011, at 6:46 PM, Rafael Weinstein wrote: What do you think? - Is this something you'd like to be implemented in the browsers, Yes. and if yes, why? What would be the reasons to not just use script libraries (like your prototype). FAQ item also coming for this. Having heard Rafael's spiel for this previously, I believe there are some things that templating engines want to do, which are hard to do efficiently and conveniently using the existing Web platform. However, I think it would be better to add primitives to the Web platform that could be used by the many templating libraries that already exist, at least as a first step: - There is a lot of code built using many of the existing templating solutions. If we provide primitives that let those libraries become more efficient, that is a greater immediate payoff than creating a new templating system, where Web apps would have to be rewritten to take advantage. - It seems somewhat hubristic to assume that a newly invented templating library is so superior to all the already existing solutions that we should encode its particular design choices into the Web platform immediately. - This new templating library doesn't have enough real apps built on it yet to know if it is a good solution to author problems. - Creating APIs is best done incrementally. API is forever, on the Web. - Looking at the history of querySelector(), I come to the following conclusion: when there are already a lot of library-based solutions to a problem, the best approach is to provide technology that can be used inside those libraries to improve them; this is more valuable than creating an API with a primary goal of direct use. querySelector gets used a lot more via popular JavaScript libraries than directly, and should have paid more attention to that use case in the first place. Perhaps there are novel arguments that will dissuade me from this line of thinking, but these are my tentative thoughts. Regards, Maciej
Re: Model-driven Views
Hi Olli, Thanks very much for taking time to read digest our design. I'm going to use this thread to start a FAQ on our project site. Some of these questions have answers that deserve more detail than is wise to put in an email =-). On Wed, Apr 27, 2011 at 8:33 AM, Olli Pettay olli.pet...@helsinki.fi wrote: HI Rafael, few random comments, or mainly just random questions :) On 04/23/2011 03:35 AM, Rafael Weinstein wrote: Myself and a few other chromium folks have been working on a design for a formalized separation between View and Model in the browser, with needs of web applications being the primary motivator. Our ideas are implemented as an experimental Javascript library: https://code.google.com/p/mdv/ and the basic design is described here: http://mdv.googlecode.com/svn/trunk/docs/design_intro.html. It's not complete and there are things we're not happy with, but it's self-consistent enough that you can start to imagine what a full design might look like. We hope to get others interested in collecting requirements/use cases and fleshing out a good solution. Would be good to know what are the use cases you had in mind. I'm never sure if I'm using the term use case correctly =-). Our primary motivator is the needs of web applications, but if we can create a good solution for more static cases in the process it'll be that much more a win. By collecting use cases I was thinking more about specific patterns that emerge in composing views for applications. One very common example is master/detail. We're starting the discussion here because a few people in this group from whom we got early feedback felt that it would be most appropriate place and, further, that this work bears some relation to XBL. Not sure why this had some relation with XBL. Unless you are planning to put the template based DOM nodes to anonymous DOM. I'm creating a FAQ question for this. Will reply again when its ready. What do you think? - Is this something you'd like to be implemented in the browsers, Yes. and if yes, why? What would be the reasons to not just use script libraries (like your prototype). FAQ item also coming for this. If the have-to-change-HTML-parser like parts could be removed, this all feels like something for JS + Proxy objects, just like what you've done in the prototype. - Is there a reason why you have chosen to create yet another datastorage like object (although your Model is just a kind of proxy)? Couldn't you reuse for example IndexedDB? XUL Templates can be bound to sqlite, XML and RDF. The goal isn't to create a storage mechanism, its to free the application from directly manipulating the DOM and allow it to operate on its data. To *say* what it wants to happen to the UI rather than to do it. If JS objects were directly observable, that would be ideal -- but it seems unlikely that runtime implementors will take the perf hit. Allowing bindings to IndexedDB is a cool idea. We should explore that more. In general, there are a number of things we should consider for sourcing data. - Model looks in many ways like JS-fied and simplified XForms model/instance. Have you investigated if there are important use cases which XForms can handle (because it has more powerful binding mechanism) but MDV can't? Are there plans to extend I've read the XForms spec, but I don't feel qualified to comment on use cases that it can better handle. It sounds like you might...? ;-) the Path language, or ideas how it could be extended? (XForms has extensions to XPath) In general I'm not too happy to see yet another selector/path language. Would be great if some existing one could be reused. Sure, some parts of the proposed language look quite a bit like JSON, but there are other parts which are something very different. The goal wasn't to create a path/selector language. The basic idea is simple JSON dot-notation. The funny syntax you see (../, ./, /) is our solution to three patterns that come up frequently in templating: -You're in an iteration, but you need a value which is just above your head (e.g. http://mdv.googlecode.com/svn/trunk/capabilities/path_reference_ancestor.html) -You're down deep in a object graph rendering you're output, but you need a global value. An example might be composing a URL for an application which is versioned. You need to grab a global static path and combine it with some local state (e.g. userId). (e.g. https://code.google.com/p/mdv/source/browse/trunk/capabilities/path_reference_root.html) -Needing to refer to *this* value. This happens all the time. (e.g. http://mdv.googlecode.com/svn/trunk/capabilities/path_reference_this.html) We considered several other options and couldn't come up with a better idea. Suggestions very welcome here (and everywhere, in fact). In general, we're not at all wedded to naming or syntax. Its the semantics were after. - It is not quite clear to me how the Model
Re: Model-driven Views
Thank, Nathan. I hadn't known of Knockout, but it looks pretty great. Conceptually, its design is very similar to MDV. Notably, the two big items: -Observable JS object properties and Arrays. -DOM-based template production (although they work with JQuery templates which are string-based). The automatic dependency tracking is interesting. We looked at some work published by Adobe/Texas AM on declarative property models (http://parasol.cs.tamu.edu/~jarvi/papers/gpce08.pdf, a very unsophisticated example in our use_cases http://mdv.googlecode.com/svn/trunk/use_cases/property_model.html). Knockout re-affirms for me that: -Dynamic web apps increasingly load one or more views as HTML but talk to their servers via a data API. Having to write lots of imperative code which shuttles data into out-of the DOM is a bummer. It's not especially interesting code and it tends to be error prone. A declarative approach can do much better. -There are basically only two approaches to templating: DOM-based (MDV, Knockout, Angular, JSTemplate) String-based (JQuery, and a ton of others). In the video, Steve explains (at about 12:40), indirectly, that DOM-based is required if you are going to dynamically update your view: performance. The other reason is DOM-stability. -In order to get this kind of approach to work, you need some way of observing when data has changed. There are four options for this that I know of: 1) Run-time support for direct observation (e.g. Adobe Flex, WPF) 2) Value-holder pattern (e.g. Knockout, Sproutcore) 3) Proxy pattern (e.g. MDV) 4) Dirty checking (e.g. Angular) The only two options available to webdevs are 2 4, and both currently require some fairly unnatural contortions. On Mon, Apr 25, 2011 at 12:26 PM, Nathan Kitchen w...@nathankitchen.com wrote: Have you heard of knockout.js? It's an MVVM pattern based on JQuery, if you're not aware of it you may be interested to see their approach. Official site: http://knockoutjs.com/ Recent MIX event: http://channel9.msdn.com/Events/MIX/MIX11/FRM08 Just FYI as it was related... On 23 April 2011 01:35, Rafael Weinstein rafa...@google.com wrote: Myself and a few other chromium folks have been working on a design for a formalized separation between View and Model in the browser, with needs of web applications being the primary motivator. Our ideas are implemented as an experimental Javascript library: https://code.google.com/p/mdv/ and the basic design is described here: http://mdv.googlecode.com/svn/trunk/docs/design_intro.html. It's not complete and there are things we're not happy with, but it's self-consistent enough that you can start to imagine what a full design might look like. We hope to get others interested in collecting requirements/use cases and fleshing out a good solution. We're starting the discussion here because a few people in this group from whom we got early feedback felt that it would be most appropriate place and, further, that this work bears some relation to XBL. What do you think?
Model-driven Views
Myself and a few other chromium folks have been working on a design for a formalized separation between View and Model in the browser, with needs of web applications being the primary motivator. Our ideas are implemented as an experimental Javascript library: https://code.google.com/p/mdv/ and the basic design is described here: http://mdv.googlecode.com/svn/trunk/docs/design_intro.html. It's not complete and there are things we're not happy with, but it's self-consistent enough that you can start to imagine what a full design might look like. We hope to get others interested in collecting requirements/use cases and fleshing out a good solution. We're starting the discussion here because a few people in this group from whom we got early feedback felt that it would be most appropriate place and, further, that this work bears some relation to XBL. What do you think?